diff --git a/web/package-lock.json b/web/package-lock.json index 033ba1276..4cd7a8300 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -88,6 +88,7 @@ "@storybook/react": "^8.6.4", "@storybook/test": "^8.6.4", "@tailwindcss/postcss": "4.0.12", + "@testing-library/react": "^16.2.0", "@types/canvas-confetti": "^1.9.0", "@types/js-cookie": "^3.0.6", "@types/lodash": "^4.17.16", @@ -6745,6 +6746,34 @@ "dev": true, "license": "MIT" }, + "node_modules/@testing-library/react": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.2.0.tgz", + "integrity": "sha512-2cSskAvA1QNtKc8Y9VJQRv0tm3hLVgxRGDB+KYhIaPQJ1I+RHbhIXcM+zClKXzMes/wshsMVzf4B9vS4IZpqDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@testing-library/user-event": { "version": "14.5.2", "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz", diff --git a/web/package.json b/web/package.json index 21b81371c..d20a6adb8 100644 --- a/web/package.json +++ b/web/package.json @@ -96,6 +96,7 @@ "@storybook/react": "^8.6.4", "@storybook/test": "^8.6.4", "@tailwindcss/postcss": "4.0.12", + "@testing-library/react": "^16.2.0", "@types/canvas-confetti": "^1.9.0", "@types/js-cookie": "^3.0.6", "@types/lodash": "^4.17.16", diff --git a/web/src/api/asset_interfaces/metric/metricDataInterfaces.ts b/web/src/api/asset_interfaces/metric/metricDataInterfaces.ts index 4e768d337..73796d520 100644 --- a/web/src/api/asset_interfaces/metric/metricDataInterfaces.ts +++ b/web/src/api/asset_interfaces/metric/metricDataInterfaces.ts @@ -2,8 +2,7 @@ import { DataMetadata, IDataResult } from './interfaces'; export type BusterMetricData = { data: IDataResult | null; - dataFromRerun?: IDataResult; + dataFromRerun?: IDataResult; //this is actually only used in the UI. maybe move this to ? data_metadata: DataMetadata; - code: string | null; metricId: string; }; diff --git a/web/src/api/buster_rest/metrics/queryRequests.ts b/web/src/api/buster_rest/metrics/queryRequests.ts index 7a1bc9ff6..7d463c8ff 100644 --- a/web/src/api/buster_rest/metrics/queryRequests.ts +++ b/web/src/api/buster_rest/metrics/queryRequests.ts @@ -1,7 +1,13 @@ import { useQuery } from '@tanstack/react-query'; import { QueryClient } from '@tanstack/react-query'; import { useMemoizedFn } from '@/hooks'; -import { getMetric, getMetric_server, listMetrics, listMetrics_server } from './requests'; +import { + getMetric, + getMetric_server, + getMetricData, + listMetrics, + listMetrics_server +} from './requests'; import type { GetMetricParams, ListMetricsParams } from './interfaces'; import { upgradeMetricToIMetric } from '@/lib/chat'; import { queryKeys } from '@/api/query_keys'; @@ -61,3 +67,15 @@ export const prefetchGetMetricsList = async ( return queryClient; }; + +export const useGetMetricData = (params: { id: string }) => { + const queryFn = useMemoizedFn(() => { + return getMetricData(params); + }); + + return useQuery({ + ...queryKeys.metricsGetData(params.id), + queryFn, + enabled: !!params.id + }); +}; diff --git a/web/src/api/buster_rest/metrics/requests.ts b/web/src/api/buster_rest/metrics/requests.ts index 5eccfffe5..70a7dfd71 100644 --- a/web/src/api/buster_rest/metrics/requests.ts +++ b/web/src/api/buster_rest/metrics/requests.ts @@ -1,7 +1,11 @@ import { mainApi } from '../instances'; import { serverFetch } from '@/api/createServerInstance'; import type { GetMetricParams, ListMetricsParams } from './interfaces'; -import type { BusterMetric, BusterMetricListItem } from '@/api/asset_interfaces/metric'; +import type { + BusterMetric, + BusterMetricData, + BusterMetricListItem +} from '@/api/asset_interfaces/metric'; export const getMetric = async ({ id, password }: GetMetricParams) => { return mainApi @@ -24,3 +28,7 @@ export const listMetrics = async (params: ListMetricsParams) => { export const listMetrics_server = async (params: ListMetricsParams) => { return await serverFetch('/metrics/list', { params }); }; + +export const getMetricData = async (params: { id: string }) => { + return mainApi.get(`/metrics/data`, { params }).then((res) => res.data); +}; diff --git a/web/src/api/buster_socket/metrics/eventsInterfaces.ts b/web/src/api/buster_socket/metrics/eventsInterfaces.ts deleted file mode 100644 index 7fe221ad1..000000000 --- a/web/src/api/buster_socket/metrics/eventsInterfaces.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { BusterChartConfigProps, DataMetadata, IDataResult } from '../../asset_interfaces'; -import type { EventBase } from '../base_interfaces'; - -export type MetricEvent_fetchingData = { - metric_id: string; - data: IDataResult; - data_metadata: DataMetadata; - chart_config: BusterChartConfigProps; - code: string | null; -} & EventBase; diff --git a/web/src/api/buster_socket/metrics/metricsRequests.ts b/web/src/api/buster_socket/metrics/metricsRequests.ts index 638c70eae..3e6538108 100644 --- a/web/src/api/buster_socket/metrics/metricsRequests.ts +++ b/web/src/api/buster_socket/metrics/metricsRequests.ts @@ -5,7 +5,6 @@ import { MetricSubscribeRequest, MetricUpdateRequest, MetricDeleteRequest, - MetricGetDataByMessageIdRequest, MetricSearchRequest, MetricDuplicateRequest } from '@/api/request_interfaces/metrics'; @@ -41,14 +40,6 @@ export type MetricUpdateMetric = BusterSocketRequestBase<'/metrics/update', Metr */ export type MetricDelete = BusterSocketRequestBase<'/metrics/delete', MetricDeleteRequest>; -/** - * Request payload for retrieving metric data by message ID - */ -export type MetricGetDataByMessageId = BusterSocketRequestBase< - '/metrics/data', - MetricGetDataByMessageIdRequest ->; - /** * Request payload for searching metrics */ @@ -69,5 +60,4 @@ export type MetricEmits = | MetricUpdateMetric | MetricSubscribeToMetric | MetricDelete - | MetricGetDataByMessageId | MetricSearch; diff --git a/web/src/api/buster_socket/metrics/metricsResponses.ts b/web/src/api/buster_socket/metrics/metricsResponses.ts index a3f0cf270..91283d9fd 100644 --- a/web/src/api/buster_socket/metrics/metricsResponses.ts +++ b/web/src/api/buster_socket/metrics/metricsResponses.ts @@ -1,5 +1,4 @@ import { BusterMetric, BusterMetricListItem } from '@/api/asset_interfaces/metric'; -import { MetricEvent_fetchingData } from './eventsInterfaces'; export enum MetricResponses { '/metrics/list:getMetricList' = '/metrics/list:getMetricList', @@ -29,12 +28,6 @@ export type Metric_Unsubscribe = { onError?: (d: unknown) => void; }; -export type MetricGet_fetchingData = { - route: '/metrics/get:fetchingData'; - callback: (d: MetricEvent_fetchingData) => void; - onError?: (d: unknown) => void; -}; - export type MetricList_updateMetricList = { route: '/metrics/list:updateMetricList'; callback: (d: BusterMetricListItem[]) => void; @@ -61,5 +54,4 @@ export type MetricResponseTypes = | MetricGet_updateMetricState | MetricList_updateMetricList | MetricDelete_deleteMetricState - | MetricUpdate_updateMetricState - | MetricGet_fetchingData; + | MetricUpdate_updateMetricState; diff --git a/web/src/api/query_keys/metric.ts b/web/src/api/query_keys/metric.ts index 207f388d7..e11514588 100644 --- a/web/src/api/query_keys/metric.ts +++ b/web/src/api/query_keys/metric.ts @@ -41,9 +41,16 @@ export const metricsGetDataByMessageId = (messageId: string) => staleTime: 60 * 60 * 1000 // 1 hour }); +export const metricsGetData = (id: string) => + queryOptions({ + queryKey: ['metrics', 'data', id] as const, + staleTime: 3 * 60 * 60 * 1000 // 3 hours, + }); + export const metricsQueryKeys = { metricsGetMetric, useMetricsGetMetric, metricsGetList, - metricsGetDataByMessageId + metricsGetDataByMessageId, + metricsGetData }; diff --git a/web/src/api/request_interfaces/metrics/interfaces.ts b/web/src/api/request_interfaces/metrics/interfaces.ts index 3ee3de9c3..3e7318e36 100644 --- a/web/src/api/request_interfaces/metrics/interfaces.ts +++ b/web/src/api/request_interfaces/metrics/interfaces.ts @@ -70,14 +70,6 @@ export type MetricDeleteRequest = { ids: string[]; }; -/** - * Request payload for retrieving metric data by message ID - */ -export type MetricGetDataByMessageIdRequest = { - /** Message ID to retrieve metric data for */ - id: string; -}; - /** * Request payload for searching metrics */ diff --git a/web/src/components/ui/charts/interfaces/interfaces.ts b/web/src/components/ui/charts/interfaces/interfaces.ts index ed3f2ef0c..05cb49147 100644 --- a/web/src/components/ui/charts/interfaces/interfaces.ts +++ b/web/src/components/ui/charts/interfaces/interfaces.ts @@ -1,4 +1,4 @@ -import type { ColumnMetaData } from '@/api/asset_interfaces'; +import type { ColumnMetaData } from '@/api/asset_interfaces/metric'; import type { BusterChartConfigProps } from './chartConfigProps'; export type BusterChartProps = { diff --git a/web/src/components/ui/typography/AppCodeBlock/AppCodeBlock.tsx b/web/src/components/ui/typography/AppCodeBlock/AppCodeBlock.tsx index 297ae9a12..ebd70bb5d 100644 --- a/web/src/components/ui/typography/AppCodeBlock/AppCodeBlock.tsx +++ b/web/src/components/ui/typography/AppCodeBlock/AppCodeBlock.tsx @@ -12,11 +12,11 @@ export const AppCodeBlock: React.FC<{ wrapperClassName?: string; children?: React.ReactNode; style?: React.CSSProperties; - showCopyButton?: boolean; title?: string; buttons?: React.ReactNode; -}> = React.memo(({ title, buttons, ...props }) => { + showLoader?: boolean; +}> = React.memo(({ title, buttons, showLoader, ...props }) => { const { children, className = '', diff --git a/web/src/context/MetricData/MOCK_DATA.ts b/web/src/context/MetricData/MOCK_DATA.ts index c9f7c5db1..49664df95 100644 --- a/web/src/context/MetricData/MOCK_DATA.ts +++ b/web/src/context/MetricData/MOCK_DATA.ts @@ -44,14 +44,7 @@ const MOCK_DATA: Required = { data: mockData(), metricId: faker.string.uuid(), data_metadata: dataMetadata, - dataFromRerun: null, - code: `SELECT - sales, - date, - product -FROM sales_data -WHERE date BETWEEN '2024-01-01' AND '2024-01-31' -ORDER BY date ASC` + dataFromRerun: null }; export const createMockData = (metricId: string): Required => { diff --git a/web/src/context/MetricData/useMetricDataIndividual.tsx b/web/src/context/MetricData/useMetricDataIndividual.tsx index 695c31e09..6a11a78cf 100644 --- a/web/src/context/MetricData/useMetricDataIndividual.tsx +++ b/web/src/context/MetricData/useMetricDataIndividual.tsx @@ -1,6 +1,4 @@ -import { queryKeys } from '@/api/query_keys'; -import { useSocketQueryEmitAndOnce } from '@/api/buster_socket_query'; -import type { BusterMetricData } from '@/api/asset_interfaces/metric'; +import { useGetMetricData } from '@/api/buster_rest/metrics'; export const useMetricDataIndividual = ({ metricId }: { metricId: string }) => { const { @@ -9,25 +7,7 @@ export const useMetricDataIndividual = ({ metricId }: { metricId: string }) => { refetch: refetchMetricData, dataUpdatedAt: metricDataUpdatedAt, error: metricDataError - } = useSocketQueryEmitAndOnce({ - emitEvent: { - route: '/metrics/data', - payload: { id: metricId } - }, - responseEvent: '/metrics/get:fetchingData', - options: queryKeys.chatsMessagesFetchingData(metricId), - callback: (currentData, responseData) => { - const metricId = responseData.metric_id; - const newMetricData: BusterMetricData = { - ...currentData, - metricId, - data: responseData.data ?? currentData?.data!, - data_metadata: responseData.data_metadata ?? currentData?.data_metadata!, - code: responseData.code - }; - return newMetricData; - } - }); + } = useGetMetricData({ id: metricId }); return { metricData, diff --git a/web/src/context/SQL/useSQLProvider.tsx b/web/src/context/SQL/useSQLProvider.tsx index 4982653c7..0c7a0c14c 100644 --- a/web/src/context/SQL/useSQLProvider.tsx +++ b/web/src/context/SQL/useSQLProvider.tsx @@ -51,7 +51,6 @@ export const useSQLProvider = () => { metricId, data, data_metadata, - code, isDataFromRerun }: { metricId: string; @@ -66,8 +65,7 @@ export const useSQLProvider = () => { queryClient.setQueryData(options.queryKey, { ...currentData!, [setter]: data, - data_metadata, - code + data_metadata }); }; @@ -80,7 +78,7 @@ export const useSQLProvider = () => { if (!originalConfigs.current[metricId]) { originalConfigs.current[metricId] = { chartConfig: metricMessage?.chart_config!, - code: currentMessageData?.code!, + code: metricMessage?.code!, data: currentMessageData?.data!, dataMetadata: currentMessageData?.data_metadata! }; diff --git a/web/src/context/Users/UserConfigProvider.tsx b/web/src/context/Users/UserConfigProvider.tsx index 4d32451e4..523a35188 100644 --- a/web/src/context/Users/UserConfigProvider.tsx +++ b/web/src/context/Users/UserConfigProvider.tsx @@ -6,9 +6,9 @@ import { useFavoriteProvider } from './useFavoriteProvider'; import { useGetMyUserInfo } from '@/api/buster_rest/users'; import { useSupabaseContext } from '../Supabase'; import { createContext, useContextSelector } from 'use-context-selector'; -import { checkIfUserIsAdmin } from './helpers'; import { useUserOrganization } from './useUserOrganization'; import { useInviteUser } from './useInviteUser'; +import { checkIfUserIsAdmin } from '@/lib/user'; export const useUserConfigProvider = ({ userInfo }: { userInfo: BusterUserResponse | null }) => { const isAnonymousUser = useSupabaseContext((state) => state.isAnonymousUser); diff --git a/web/src/context/Users/helpers.ts b/web/src/context/Users/helpers.ts deleted file mode 100644 index ad961182f..000000000 --- a/web/src/context/Users/helpers.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { BusterOrganizationRole } from '@/api/asset_interfaces/organizations'; -import { type BusterUserResponse } from '@/api/asset_interfaces/users'; - -export const checkIfUserIsAdmin = (userInfo?: BusterUserResponse | null): boolean => { - if (!userInfo) return false; - - const userOrganization = userInfo?.organizations?.[0]; - - if (!userOrganization) return false; - - const userRole = userOrganization.role; - - return ( - userRole === BusterOrganizationRole.DATA_ADMIN || - userRole === BusterOrganizationRole.WORKSPACE_ADMIN - ); -}; diff --git a/web/src/context/Users/index.ts b/web/src/context/Users/index.ts index 988d4add7..aaace6858 100644 --- a/web/src/context/Users/index.ts +++ b/web/src/context/Users/index.ts @@ -1,2 +1 @@ export * from './UserConfigProvider'; -export * from './helpers'; diff --git a/web/tsconfig.json b/web/tsconfig.json index b372d8049..c1a940827 100644 --- a/web/tsconfig.json +++ b/web/tsconfig.json @@ -24,5 +24,11 @@ } }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] + "exclude": [ + "node_modules", + "**/*.stories.tsx", + "**/*.stories.ts", + "**/*.test.tsx", + "**/*.test.ts" + ] }