mirror of https://github.com/buster-so/buster.git
Dashboard filters built
This commit is contained in:
parent
5df005581f
commit
cd634843a2
|
@ -121,14 +121,9 @@ export async function getMetricDataHandler(
|
|||
// Ensure limit is within bounds
|
||||
const queryLimit = Math.min(Math.max(limit, 1), 5000);
|
||||
|
||||
console.log('Filter values received:', filterValues);
|
||||
console.log('Metric filters:', metric.content.filters);
|
||||
|
||||
// Compile SQL with user-provided filter values or defaults
|
||||
const compiledSql = compileSqlWithDefaults(metric.content, filterValues);
|
||||
|
||||
console.log('Compiled SQL:', compiledSql);
|
||||
|
||||
// Extract SQL query from metric content (for backwards compatibility if no filters)
|
||||
const sql = compiledSql || extractSqlFromMetricContent(metric.content);
|
||||
|
||||
|
|
|
@ -197,7 +197,6 @@ export async function buildMetricResponse(
|
|||
processedData: ProcessedMetricData,
|
||||
userId: string
|
||||
): Promise<GetMetricResponse> {
|
||||
console.log('buildMetricResponse called for metric:', processedData.resolvedName);
|
||||
const {
|
||||
metricFile,
|
||||
resolvedContent,
|
||||
|
@ -276,12 +275,6 @@ export async function buildMetricResponse(
|
|||
filters: resolvedContent.filters,
|
||||
};
|
||||
|
||||
console.log(`buildMetricResponse for ${resolvedName}:`, {
|
||||
hasFilters: !!resolvedContent.filters,
|
||||
filterCount: resolvedContent.filters?.length || 0,
|
||||
filters: resolvedContent.filters,
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
@ -289,7 +282,6 @@ export async function getMetricsInAncestorAssetFromMetricIds(
|
|||
metricIds: string[],
|
||||
user: User
|
||||
): Promise<Record<string, MetricWithFilters>> {
|
||||
console.log('getMetricsInAncestorAssetFromMetricIds called with', metricIds.length, 'metrics');
|
||||
const metricsObj: Record<string, MetricWithFilters> = {};
|
||||
|
||||
// Process metrics in chunks of 4 to manage concurrency
|
||||
|
|
|
@ -34,7 +34,7 @@ export const getDashboardById = async ({
|
|||
/** The version number of the dashboard */
|
||||
version_number?: number;
|
||||
}) => {
|
||||
return await mainApi
|
||||
return await mainApiV2
|
||||
.get<GetDashboardResponse>(`/dashboards/${id}`, {
|
||||
params: { password, version_number },
|
||||
})
|
||||
|
|
|
@ -179,7 +179,6 @@ export const useGetMetricData = <TData = BusterMetricDataExtended>(
|
|||
const queryFn = async () => {
|
||||
const chosenVersionNumber: number | undefined =
|
||||
versionNumberProp === 'LATEST' ? undefined : versionNumberProp;
|
||||
console.log('Fetching metric data with filter values:', filterValues);
|
||||
const result = await getMetricData({
|
||||
id,
|
||||
version_number: chosenVersionNumber || undefined,
|
||||
|
@ -187,7 +186,6 @@ export const useGetMetricData = <TData = BusterMetricDataExtended>(
|
|||
report_file_id: cacheDataId,
|
||||
filter_values: filterValues,
|
||||
});
|
||||
console.log('Received metric data:', result);
|
||||
const latestVersionNumber = getLatestMetricVersion(id);
|
||||
const isLatest =
|
||||
versionNumberProp === 'LATEST' ||
|
||||
|
|
|
@ -15,8 +15,8 @@ const dashboardGetList = (
|
|||
|
||||
const dashboardGetDashboard = (dashboardId: string, version_number: number | 'LATEST') =>
|
||||
queryOptions<GetDashboardResponse>({
|
||||
queryKey: ['dashboard', 'get', dashboardId, version_number || 'LATEST'] as const,
|
||||
staleTime: 60 * 1000,
|
||||
queryKey: ['dashboard', 'get', 'v2', dashboardId, version_number || 'LATEST'] as const, // Added 'v2' to bust cache
|
||||
staleTime: 0, // Temporarily set to 0 during filter development
|
||||
});
|
||||
|
||||
export const dashboardQueryKeys = {
|
||||
|
|
|
@ -9,7 +9,7 @@ import type { listMetrics } from '../buster_rest/metrics';
|
|||
export const metricsGetMetric = (metricId: string, version_number: number | 'LATEST') => {
|
||||
return queryOptions<BusterMetric>({
|
||||
queryKey: ['metrics', 'get', metricId, version_number || 'LATEST'] as const,
|
||||
staleTime: 60 * 1000, // 60 seconds
|
||||
staleTime: 0, // Temporarily set to 0 during filter development
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import { useMemoizedFn } from '@/hooks/useMemoizedFn';
|
|||
import { DashboardMetricItem } from '../../../../components/features/metrics/DashboardMetricItem';
|
||||
import { DashboardContentControllerProvider } from './DashboardContentControllerContext';
|
||||
import { DashboardEmptyState, DashboardNoContentReadOnly } from './DashboardEmptyState';
|
||||
import { DashboardFilterProvider } from './DashboardFilterContext';
|
||||
import { DashboardFilterProvider, useDashboardFilterValues } from './DashboardFilterContext';
|
||||
import { getCommonFilters } from './helpers/getCommonFilters';
|
||||
import { removeChildrenFromItems } from './helpers';
|
||||
|
||||
|
@ -17,7 +17,7 @@ const DEFAULT_EMPTY_ROWS: DashboardConfig['rows'] = [];
|
|||
const DEFAULT_EMPTY_METRICS: Record<string, BusterMetric> = {};
|
||||
const DEFAULT_EMPTY_CONFIG: DashboardConfig = {};
|
||||
|
||||
export const DashboardContentController: React.FC<{
|
||||
const DashboardContentControllerInner: React.FC<{
|
||||
readOnly?: boolean;
|
||||
metrics: BusterDashboardResponse['metrics'] | undefined;
|
||||
dashboard: BusterDashboardResponse['dashboard'] | undefined;
|
||||
|
@ -34,13 +34,10 @@ export const DashboardContentController: React.FC<{
|
|||
onUpdateDashboardConfig,
|
||||
}) => {
|
||||
const [draggingId, setDraggingId] = useState<string | null>(null);
|
||||
const [dashboardFilterValues, setDashboardFilterValues] = useState<Record<string, unknown>>({});
|
||||
const { setDashboardFilterValues } = useDashboardFilterValues();
|
||||
|
||||
const commonFilters = useMemo(() => {
|
||||
const filters = getCommonFilters(metrics);
|
||||
console.log('DashboardContentController - commonFilters:', filters);
|
||||
console.log('DashboardContentController - readOnly:', readOnly);
|
||||
console.log('DashboardContentController - Should show filters?', !readOnly && filters.length > 0);
|
||||
return filters;
|
||||
}, [metrics, readOnly]);
|
||||
|
||||
|
@ -120,24 +117,22 @@ export const DashboardContentController: React.FC<{
|
|||
return (
|
||||
<div className="dashboard-content-controller overflow-visible">
|
||||
{hasMetrics && !!dashboardRows.length && !!dashboard ? (
|
||||
<DashboardFilterProvider>
|
||||
<DashboardContentControllerProvider dashboard={dashboard}>
|
||||
{!readOnly && commonFilters.length > 0 && (
|
||||
<DashboardFilters
|
||||
commonFilters={commonFilters}
|
||||
onFilterValuesChange={setDashboardFilterValues}
|
||||
/>
|
||||
)}
|
||||
<BusterResizeableGrid
|
||||
rows={dashboardRows}
|
||||
readOnly={readOnly}
|
||||
onRowLayoutChange={onRowLayoutChange}
|
||||
onStartDrag={onStartDrag}
|
||||
onEndDrag={onDragEnd}
|
||||
overlayComponent={memoizedOverlayComponent}
|
||||
<DashboardContentControllerProvider dashboard={dashboard}>
|
||||
{!readOnly && commonFilters.length > 0 && (
|
||||
<DashboardFilters
|
||||
commonFilters={commonFilters}
|
||||
onFilterValuesChange={setDashboardFilterValues}
|
||||
/>
|
||||
</DashboardContentControllerProvider>
|
||||
</DashboardFilterProvider>
|
||||
)}
|
||||
<BusterResizeableGrid
|
||||
rows={dashboardRows}
|
||||
readOnly={readOnly}
|
||||
onRowLayoutChange={onRowLayoutChange}
|
||||
onStartDrag={onStartDrag}
|
||||
onEndDrag={onDragEnd}
|
||||
overlayComponent={memoizedOverlayComponent}
|
||||
/>
|
||||
</DashboardContentControllerProvider>
|
||||
) : !readOnly ? (
|
||||
<DashboardEmptyState onOpenAddContentModal={onOpenAddContentModal} />
|
||||
) : (
|
||||
|
@ -147,4 +142,19 @@ export const DashboardContentController: React.FC<{
|
|||
);
|
||||
}
|
||||
);
|
||||
DashboardContentController.displayName = 'DashboardIndividualDashboard';
|
||||
DashboardContentControllerInner.displayName = 'DashboardContentControllerInner';
|
||||
|
||||
export const DashboardContentController: React.FC<{
|
||||
readOnly?: boolean;
|
||||
metrics: BusterDashboardResponse['metrics'] | undefined;
|
||||
dashboard: BusterDashboardResponse['dashboard'] | undefined;
|
||||
onUpdateDashboardConfig: ReturnType<typeof useUpdateDashboardConfig>['mutateAsync'];
|
||||
onOpenAddContentModal: () => void;
|
||||
animate?: boolean;
|
||||
}> = (props) => {
|
||||
return (
|
||||
<DashboardFilterProvider>
|
||||
<DashboardContentControllerInner {...props} />
|
||||
</DashboardFilterProvider>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -8,20 +8,13 @@ import type { BusterMetric } from '@/api/asset_interfaces';
|
|||
export function getCommonFilters(metrics: Record<string, BusterMetric>): MetricFilter[] {
|
||||
const metricsArray = Object.values(metrics);
|
||||
|
||||
console.log('getCommonFilters - Total metrics:', metricsArray.length);
|
||||
metricsArray.forEach((m, i) => {
|
||||
console.log(` Metric ${i} (${m.name}):`, m.filters?.length || 0, 'filters', m.filters);
|
||||
});
|
||||
|
||||
if (metricsArray.length === 0) {
|
||||
console.log('No metrics, returning empty');
|
||||
return [];
|
||||
}
|
||||
|
||||
// Get filters from first metric as baseline
|
||||
const firstMetric = metricsArray[0];
|
||||
if (!firstMetric?.filters || firstMetric.filters.length === 0) {
|
||||
console.log('First metric has no filters');
|
||||
return [];
|
||||
}
|
||||
|
||||
|
@ -29,19 +22,15 @@ export function getCommonFilters(metrics: Record<string, BusterMetric>): MetricF
|
|||
const commonFilters: MetricFilter[] = [];
|
||||
|
||||
for (const filter of firstMetric.filters) {
|
||||
console.log(`\nChecking filter "${filter.key}"...`);
|
||||
|
||||
// Check if this filter exists in all other metrics
|
||||
const isInAllMetrics = metricsArray.every((metric, idx) => {
|
||||
const isInAllMetrics = metricsArray.every((metric) => {
|
||||
if (!metric.filters) {
|
||||
console.log(` ✗ Metric ${idx} has no filters`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find matching filter by key
|
||||
const matchingFilter = metric.filters.find((f) => f.key === filter.key);
|
||||
if (!matchingFilter) {
|
||||
console.log(` ✗ Metric ${idx} (${metric.name}) missing key "${filter.key}"`);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -50,23 +39,13 @@ export function getCommonFilters(metrics: Record<string, BusterMetric>): MetricF
|
|||
const modeMatch = matchingFilter.mode === filter.mode;
|
||||
const columnMatch = matchingFilter.column === filter.column;
|
||||
|
||||
if (!typeMatch || !modeMatch || !columnMatch) {
|
||||
console.log(` ✗ Metric ${idx} (${metric.name}) config mismatch:`, {
|
||||
type: typeMatch ? '✓' : `✗ ${matchingFilter.type} vs ${filter.type}`,
|
||||
mode: modeMatch ? '✓' : `✗ ${matchingFilter.mode} vs ${filter.mode}`,
|
||||
column: columnMatch ? '✓' : `✗ ${matchingFilter.column} vs ${filter.column}`,
|
||||
});
|
||||
}
|
||||
|
||||
return typeMatch && modeMatch && columnMatch;
|
||||
});
|
||||
|
||||
if (isInAllMetrics) {
|
||||
console.log(` ✓ "${filter.key}" is COMMON!`);
|
||||
commonFilters.push(filter);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\nFinal common filters:', commonFilters.length, commonFilters);
|
||||
return commonFilters;
|
||||
}
|
||||
|
|
|
@ -25,10 +25,6 @@ import {
|
|||
RESPOND_WITHOUT_ASSET_CREATION_TOOL_NAME,
|
||||
createRespondWithoutAssetCreationTool,
|
||||
} from '../../tools/communication-tools/respond-without-asset-creation/respond-without-asset-creation-tool';
|
||||
import {
|
||||
SUBMIT_THOUGHTS_TOOL_NAME,
|
||||
createSubmitThoughtsTool,
|
||||
} from '../../tools/communication-tools/submit-thoughts-tool/submit-thoughts-tool';
|
||||
import { EXECUTE_SQL_TOOL_NAME } from '../../tools/database-tools/execute-sql/execute-sql';
|
||||
import { SEQUENTIAL_THINKING_TOOL_NAME } from '../../tools/planning-thinking-tools/sequential-thinking-tool/sequential-thinking-tool';
|
||||
import { CREATE_DASHBOARDS_TOOL_NAME } from '../../tools/visualization-tools/dashboards/create-dashboards-tool/create-dashboards-tool';
|
||||
|
@ -45,7 +41,7 @@ import { getAnalystAgentSystemPrompt } from './get-analyst-agent-system-prompt';
|
|||
export const ANALYST_AGENT_NAME = 'analystAgent';
|
||||
|
||||
const STOP_CONDITIONS = [
|
||||
stepCountIs(25),
|
||||
stepCountIs(50),
|
||||
hasToolCall(DONE_TOOL_NAME),
|
||||
hasToolCall(RESPOND_WITHOUT_ASSET_CREATION_TOOL_NAME),
|
||||
hasToolCall(MESSAGE_USER_CLARIFYING_QUESTION_TOOL_NAME),
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { z } from 'zod';
|
||||
import { MetricSchema } from '../metrics';
|
||||
import { MetricSchemaWithFilters } from '../metrics';
|
||||
import { ShareConfigSchema, ShareRoleSchema } from '../share';
|
||||
import { DashboardSchema } from './dashboard.types';
|
||||
|
||||
export const GetDashboardResponseSchema = z.object({
|
||||
metrics: z.record(z.string(), MetricSchema),
|
||||
metrics: z.record(z.string(), MetricSchemaWithFilters),
|
||||
dashboard: DashboardSchema,
|
||||
collections: z.array(
|
||||
z.object({
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { z } from 'zod';
|
||||
import { AssetCollectionsSchema } from '../collections/shared-asset-collections';
|
||||
import { MetricSchema } from '../metrics';
|
||||
import { MetricSchemaWithFilters } from '../metrics';
|
||||
import { ShareConfigSchema } from '../share';
|
||||
import { VersionsSchema } from '../version-shared';
|
||||
|
||||
|
@ -31,7 +31,7 @@ export const ReportResponseSchema = z.object({
|
|||
collections: AssetCollectionsSchema,
|
||||
content: z.string(),
|
||||
...ShareConfigSchema.shape,
|
||||
metrics: z.record(z.string(), MetricSchema),
|
||||
metrics: z.record(z.string(), MetricSchemaWithFilters),
|
||||
});
|
||||
|
||||
export type ReportListItem = z.infer<typeof ReportListItemSchema>;
|
||||
|
|
Loading…
Reference in New Issue