diff --git a/api/server/Cargo.toml b/api/server/Cargo.toml index 5aed3ddc1..e67e0358d 100644 --- a/api/server/Cargo.toml +++ b/api/server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "buster_server" -version = "0.1.5" +version = "0.1.6" edition = "2021" default-run = "buster_server" diff --git a/cli/cli/Cargo.toml b/cli/cli/Cargo.toml index e4f54f123..5bbf41650 100644 --- a/cli/cli/Cargo.toml +++ b/cli/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "buster-cli" -version = "0.1.5" +version = "0.1.6" edition = "2021" build = "build.rs" diff --git a/tag_info.json b/tag_info.json index d5cbcf222..bd44a4250 100644 --- a/tag_info.json +++ b/tag_info.json @@ -1,7 +1,7 @@ { - "api_tag": "api/v0.1.5", "api_version": "0.1.5" + "api_tag": "api/v0.1.6", "api_version": "0.1.6" , - "web_tag": "web/v0.1.5", "web_version": "0.1.5" + "web_tag": "web/v0.1.6", "web_version": "0.1.6" , - "cli_tag": "cli/v0.1.5", "cli_version": "0.1.5" + "cli_tag": "cli/v0.1.6", "cli_version": "0.1.6" } diff --git a/web/package-lock.json b/web/package-lock.json index 00eafc07c..9f0319651 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,12 +1,12 @@ { "name": "web", - "version": "0.1.5", + "version": "0.1.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "web", - "version": "0.1.5", + "version": "0.1.6", "dependencies": { "@dnd-kit/core": "^6.3.1", "@dnd-kit/modifiers": "^9.0.0", diff --git a/web/package.json b/web/package.json index 0206fdb40..e60841750 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "web", - "version": "0.1.5", + "version": "0.1.6", "private": true, "scripts": { "dev": "next dev --turbo", diff --git a/web/src/api/buster_rest/chats/queryRequests.ts b/web/src/api/buster_rest/chats/queryRequests.ts index e0b24fb28..ec18b9de3 100644 --- a/web/src/api/buster_rest/chats/queryRequests.ts +++ b/web/src/api/buster_rest/chats/queryRequests.ts @@ -25,7 +25,7 @@ import { useMemo } from 'react'; import last from 'lodash/last'; import { prefetchGetMetricDataClient } from '../metrics/queryRequests'; import { useBusterNotifications } from '@/context/BusterNotifications'; -import { useGetUserFavorites } from '../users/queryRequests'; +import { useGetUserFavorites } from '../users/queryRequestFavorites'; import { useAddAssetToCollection, useRemoveAssetFromCollection diff --git a/web/src/api/buster_rest/collections/queryRequests.ts b/web/src/api/buster_rest/collections/queryRequests.ts index 732594410..d7a06e262 100644 --- a/web/src/api/buster_rest/collections/queryRequests.ts +++ b/web/src/api/buster_rest/collections/queryRequests.ts @@ -25,7 +25,7 @@ import { useBusterAssetsContextSelector } from '@/context/Assets/BusterAssetsPro import { create } from 'mutative'; import type { BusterCollection } from '@/api/asset_interfaces/collection'; import { RustApiError } from '../errors'; -import { isQueryStale } from '@/lib'; +import { hasOrganizationId, isQueryStale } from '@/lib'; export const useGetCollectionsList = ( filters: Omit[0], 'page_token' | 'page_size'>, @@ -51,7 +51,7 @@ export const prefetchGetCollectionsList = async ( ) => { const options = collectionQueryKeys.collectionsGetList(params); const isStale = isQueryStale(options, queryClient); - if (!isStale) return queryClient; + if (!isStale || !hasOrganizationId(queryClient)) return queryClient; const lastQueryKey = options.queryKey[options.queryKey.length - 1]; const compiledParams = lastQueryKey as Parameters[0]; diff --git a/web/src/api/buster_rest/dashboards/queryRequests.ts b/web/src/api/buster_rest/dashboards/queryRequests.ts index de91d1424..e40825820 100644 --- a/web/src/api/buster_rest/dashboards/queryRequests.ts +++ b/web/src/api/buster_rest/dashboards/queryRequests.ts @@ -43,7 +43,7 @@ import { useGetLatestMetricVersionMemoized } from '../metrics'; import { useBusterAssetsContextSelector } from '@/context/Assets/BusterAssetsProvider'; import last from 'lodash/last'; import { createDashboardFullConfirmModal } from './confirmModals'; -import { isQueryStale } from '@/lib'; +import { hasOrganizationId, isQueryStale } from '@/lib'; export const useGetDashboard = ( { @@ -751,7 +751,7 @@ export const prefetchGetDashboardsList = async ( ) => { const options = dashboardQueryKeys.dashboardGetList(params); const isStale = isQueryStale(options, queryClient); - if (!isStale) return queryClient; + if (!isStale || !hasOrganizationId(queryClient)) return queryClient; const lastQueryKey = options.queryKey[options.queryKey.length - 1]; const compiledParams = lastQueryKey as Parameters[0]; diff --git a/web/src/api/buster_rest/metrics/getMetricListQueryRequests.ts b/web/src/api/buster_rest/metrics/getMetricListQueryRequests.ts index fa529fa64..a1448d10a 100644 --- a/web/src/api/buster_rest/metrics/getMetricListQueryRequests.ts +++ b/web/src/api/buster_rest/metrics/getMetricListQueryRequests.ts @@ -4,7 +4,8 @@ import { QueryClient, useQuery, UseQueryOptions } from '@tanstack/react-query'; import { useMemoizedFn } from '@/hooks'; import { metricsQueryKeys } from '@/api/query_keys/metric'; import { RustApiError } from '../errors'; -import { isQueryStale } from '@/lib'; +import { hasOrganizationId, isQueryStale } from '@/lib'; +import { useUserConfigContextSelector } from '@/context/Users'; export const useGetMetricsList = ( params: Omit[0], 'page_token' | 'page_size'>, @@ -13,17 +14,18 @@ export const useGetMetricsList = ( 'queryKey' | 'queryFn' | 'initialData' > ) => { + const organizationId = useUserConfigContextSelector((state) => state.userOrganizations?.id); const compiledParams: Parameters[0] = useMemo( () => ({ status: [], ...params, page_token: 0, page_size: 3500 }), [params] ); - const queryFn = useMemoizedFn(() => listMetrics(compiledParams)); return useQuery({ ...metricsQueryKeys.metricsGetList(compiledParams), queryFn, select: options?.select, + enabled: !!organizationId, ...options }); }; @@ -34,7 +36,7 @@ export const prefetchGetMetricsList = async ( ) => { const options = metricsQueryKeys.metricsGetList(params); const isStale = isQueryStale(options, queryClient); - if (!isStale) return queryClient; + if (!isStale || !hasOrganizationId(queryClient)) return queryClient; const lastQueryKey = options.queryKey[options.queryKey.length - 1]; const compiledParams = lastQueryKey as Parameters[0]; diff --git a/web/src/api/buster_rest/users/index.ts b/web/src/api/buster_rest/users/index.ts index 708b987c9..8806c10f6 100644 --- a/web/src/api/buster_rest/users/index.ts +++ b/web/src/api/buster_rest/users/index.ts @@ -1,3 +1,4 @@ export * from './requests'; export * from './queryRequests'; export * from './permissions'; +export * from './queryRequestFavorites'; diff --git a/web/src/api/buster_rest/users/queryRequestFavorites.ts b/web/src/api/buster_rest/users/queryRequestFavorites.ts new file mode 100644 index 000000000..696c9f285 --- /dev/null +++ b/web/src/api/buster_rest/users/queryRequestFavorites.ts @@ -0,0 +1,79 @@ +import { useMemoizedFn } from '@/hooks/useMemoizedFn'; +import { + createUserFavorite, + deleteUserFavorite, + getUserFavorites, + getUserFavorites_server, + updateUserFavorites +} from './requests'; +import { QueryClient, useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { useUserConfigContextSelector } from '@/context/Users/BusterUserConfigProvider'; +import { userQueryKeys } from '@/api/query_keys/users'; + +export const useGetUserFavorites = () => { + const queryFn = useMemoizedFn(async () => getUserFavorites()); + const organizationId = useUserConfigContextSelector((state) => state.userOrganizations?.id); + return useQuery({ + ...userQueryKeys.favoritesGetList, + queryFn, + enabled: !!organizationId + }); +}; + +export const prefetchGetUserFavorites = async (queryClientProp?: QueryClient) => { + const queryClient = queryClientProp || new QueryClient(); + await queryClient.prefetchQuery({ + ...userQueryKeys.favoritesGetList, + queryFn: () => getUserFavorites_server() + }); + return queryClient; +}; + +export const useAddUserFavorite = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: createUserFavorite, + onMutate: (params) => { + queryClient.setQueryData(userQueryKeys.favoritesGetList.queryKey, (prev) => { + const prevIds = prev?.map((p) => p.id) || []; + const dedupedAdd = params.filter((p) => !prevIds.includes(p.id)); + return [...dedupedAdd, ...(prev || [])]; + }); + }, + onSuccess: (data) => { + queryClient.setQueryData(userQueryKeys.favoritesGetList.queryKey, data); + } + }); +}; + +export const useDeleteUserFavorite = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: deleteUserFavorite, + onMutate: (id) => { + queryClient.setQueryData(userQueryKeys.favoritesGetList.queryKey, (prev) => { + return prev?.filter((fav) => !id.includes(fav.id)); + }); + }, + onSuccess: (data) => { + queryClient.setQueryData(userQueryKeys.favoritesGetList.queryKey, data); + } + }); +}; + +export const useUpdateUserFavorites = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: updateUserFavorites, + onMutate: (params) => { + queryClient.setQueryData(userQueryKeys.favoritesGetList.queryKey, (prev) => { + return prev?.filter((fav, index) => { + const id = fav.id; + const favorite = (prev || []).find((f) => f.id === id)!; + return { ...favorite, index }; + }); + }); + } + }); +}; diff --git a/web/src/api/buster_rest/users/queryRequests.ts b/web/src/api/buster_rest/users/queryRequests.ts index 9feac8974..d6849b869 100644 --- a/web/src/api/buster_rest/users/queryRequests.ts +++ b/web/src/api/buster_rest/users/queryRequests.ts @@ -33,11 +33,9 @@ export const prefetchGetMyUserInfo = async ( queryClientProp?: QueryClient ) => { const queryClient = queryClientProp || new QueryClient(); - const initialData = await getMyUserInfo_server(params); await queryClient.prefetchQuery({ ...queryKeys.userGetUserMyself, - queryFn: () => initialData!, - initialData + queryFn: () => getMyUserInfo_server(params) }); return queryClient; }; @@ -78,72 +76,6 @@ export const prefetchGetUser = async (userId: string, queryClientProp?: QueryCli return queryClient; }; -export const useGetUserFavorites = () => { - const queryFn = useMemoizedFn(async () => getUserFavorites()); - return useQuery({ - ...queryKeys.favoritesGetList, - queryFn - }); -}; - -export const prefetchGetUserFavorites = async (queryClientProp?: QueryClient) => { - const queryClient = queryClientProp || new QueryClient(); - await queryClient.prefetchQuery({ - ...queryKeys.favoritesGetList, - queryFn: () => getUserFavorites_server() - }); - return queryClient; -}; - -export const useAddUserFavorite = () => { - const queryClient = useQueryClient(); - return useMutation({ - mutationFn: createUserFavorite, - onMutate: (params) => { - queryClient.setQueryData(queryKeys.favoritesGetList.queryKey, (prev) => { - const prevIds = prev?.map((p) => p.id) || []; - const dedupedAdd = params.filter((p) => !prevIds.includes(p.id)); - return [...dedupedAdd, ...(prev || [])]; - }); - }, - onSuccess: (data) => { - queryClient.setQueryData(queryKeys.favoritesGetList.queryKey, data); - } - }); -}; - -export const useDeleteUserFavorite = () => { - const queryClient = useQueryClient(); - return useMutation({ - mutationFn: deleteUserFavorite, - onMutate: (id) => { - queryClient.setQueryData(queryKeys.favoritesGetList.queryKey, (prev) => { - return prev?.filter((fav) => !id.includes(fav.id)); - }); - }, - onSuccess: (data) => { - queryClient.setQueryData(queryKeys.favoritesGetList.queryKey, data); - } - }); -}; - -export const useUpdateUserFavorites = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: updateUserFavorites, - onMutate: (params) => { - queryClient.setQueryData(queryKeys.favoritesGetList.queryKey, (prev) => { - return prev?.filter((fav, index) => { - const id = fav.id; - const favorite = (prev || []).find((f) => f.id === id)!; - return { ...favorite, index }; - }); - }); - } - }); -}; - export const useGetUserList = (params: Parameters[0]) => { const queryFn = useMemoizedFn(() => getUserList(params)); diff --git a/web/src/api/buster_rest/users/requests.ts b/web/src/api/buster_rest/users/requests.ts index 7f502d955..e5560e901 100644 --- a/web/src/api/buster_rest/users/requests.ts +++ b/web/src/api/buster_rest/users/requests.ts @@ -17,17 +17,12 @@ export const getMyUserInfo_server = async ({ jwtToken }: { jwtToken: string | undefined; -}): Promise => { +}): Promise => { if (!jwtToken) { - try { - //If Anonymous user, it will fail, so we catch the error and return undefined - const res = await serverFetch(`/users`, { - method: 'GET' - }); - return res; - } catch (error) { - return undefined; - } + //If Anonymous user, it will fail, so we catch the error and return undefined + return await serverFetch(`/users`, { + method: 'GET' + }); } //use fetch instead of serverFetch because... @@ -37,16 +32,17 @@ export const getMyUserInfo_server = async ({ 'Content-Type': 'application/json', Authorization: `Bearer ${jwtToken}` } - }) - .then((response) => { - if (!response.ok) { - return undefined; - } - return response.json(); - }) - .catch((error) => { - return undefined; - }); + }).then(async (response) => { + if (!response.ok) { + const errorData = await response.json().catch(() => null); + throw { + status: response.status, + statusText: response.statusText, + ...errorData + }; + } + return response.json(); + }); }; export const getUser = async ({ userId }: { userId: string }) => { diff --git a/web/src/api/query_keys/users.ts b/web/src/api/query_keys/users.ts index 22700bad4..e2d5defbb 100644 --- a/web/src/api/query_keys/users.ts +++ b/web/src/api/query_keys/users.ts @@ -19,7 +19,7 @@ const favoritesGetList = queryOptions({ initialDataUpdatedAt: 0 }); -const userGetUserMyself = queryOptions({ +const userGetUserMyself = queryOptions({ queryKey: ['myself'] as const, staleTime: 1000 * 60 * 60 // 1 hour }); diff --git a/web/src/app/app/layout.tsx b/web/src/app/app/layout.tsx index 8b851f729..5f75380af 100644 --- a/web/src/app/app/layout.tsx +++ b/web/src/app/app/layout.tsx @@ -10,6 +10,9 @@ import { AppProviders } from '@/context/AppProviders'; import { headers } from 'next/headers'; import { queryKeys } from '@/api/query_keys'; +const newUserRoute = createBusterRoute({ route: BusterRoutes.NEW_USER }); +const loginRoute = createBusterRoute({ route: BusterRoutes.AUTH_LOGIN }); + export default async function Layout({ children }: Readonly<{ @@ -32,8 +35,6 @@ export default async function Layout({ } const userInfo = queryClient.getQueryData(queryKeys.userGetUserMyself.queryKey); - const newUserRoute = createBusterRoute({ route: BusterRoutes.NEW_USER }); - const loginRoute = createBusterRoute({ route: BusterRoutes.AUTH_LOGIN }); if ( (supabaseContext.user?.is_anonymous && pathname !== loginRoute) || diff --git a/web/src/components/ui/charts/BusterChartJS/helpers/formatBarAndLineDataLabel.test.ts b/web/src/components/ui/charts/BusterChartJS/helpers/formatBarAndLineDataLabel.test.ts index 5d8471d5b..c92a26b11 100644 --- a/web/src/components/ui/charts/BusterChartJS/helpers/formatBarAndLineDataLabel.test.ts +++ b/web/src/components/ui/charts/BusterChartJS/helpers/formatBarAndLineDataLabel.test.ts @@ -102,20 +102,5 @@ describe('formatBarAndLineDataLabel', () => { // 25 out of series total (50) = 50% (since second dataset is hidden) expect(result).toBe('50%'); }); - - test('should ignore trendline datasets when counting multiple datasets', () => { - const mockContext = createMockContext([ - baseDataset, - { ...baseDataset, isTrendline: true } - ]) as Context; - - const result = formatBarAndLineDataLabel(25, mockContext, 'data-label', { - style: 'number', - columnType: 'number' - }); - - // 25 out of series total (50) = 50% (since second dataset is a trendline) - expect(result).toBe('50%'); - }); }); }); diff --git a/web/src/components/ui/charts/BusterChartJS/hooks/useBusterChartJSLegend/getLegendItems.test.ts b/web/src/components/ui/charts/BusterChartJS/hooks/useBusterChartJSLegend/getLegendItems.test.ts index 096a36afd..e900e111d 100644 --- a/web/src/components/ui/charts/BusterChartJS/hooks/useBusterChartJSLegend/getLegendItems.test.ts +++ b/web/src/components/ui/charts/BusterChartJS/hooks/useBusterChartJSLegend/getLegendItems.test.ts @@ -122,51 +122,6 @@ describe('getLegendItems', () => { expect(result[1].type).toBe(ChartType.Line); }); - it('should filter out hidden and trendline datasets', () => { - const mockChartRef = { - current: { - config: { type: ChartType.Bar }, - data: { - datasets: [ - { - label: 'Visible Data', - data: [10, 20], - yAxisKey: 'value', - hidden: false, - isTrendline: false - }, - { - label: 'Hidden Data', - data: [15, 25], - yAxisKey: 'value', - hidden: true, - isTrendline: false - }, - { - label: 'Trendline Data', - data: [12, 22], - yAxisKey: 'value', - hidden: false, - isTrendline: true - } - ] - } - } as unknown as Chart - }; - - const result = getLegendItems({ - chartRef: mockChartRef, - colors: mockColors, - inactiveDatasets: {}, - selectedChartType: ChartType.Bar, - columnLabelFormats: defaultColumnLabelFormats, - columnSettings: defaultColumnSettings - }); - - expect(result).toHaveLength(1); - expect(result[0].id).toBe('Visible Data'); - }); - it('should handle scatter plot visualization in combo charts', () => { const mockChartRef = { current: { diff --git a/web/src/components/ui/charts/BusterChartJS/hooks/useChartSpecificOptions/pieChartOptions.test.ts b/web/src/components/ui/charts/BusterChartJS/hooks/useChartSpecificOptions/pieChartOptions.test.ts index 9d1d156cd..7107515ed 100644 --- a/web/src/components/ui/charts/BusterChartJS/hooks/useChartSpecificOptions/pieChartOptions.test.ts +++ b/web/src/components/ui/charts/BusterChartJS/hooks/useChartSpecificOptions/pieChartOptions.test.ts @@ -4,9 +4,6 @@ import type { ChartSpecificOptionsProps } from './interfaces'; import type { ChartData } from 'chart.js'; jest.mock('@/lib/colors'); -jest.mock('@tanstack/react-query', () => ({ - isServer: true -})); const mockChartData: ChartData = { labels: ['Test'], diff --git a/web/src/components/ui/charts/BusterChartJS/hooks/useSeriesOptions/scatterSeriesBuilder.test.ts b/web/src/components/ui/charts/BusterChartJS/hooks/useSeriesOptions/scatterSeriesBuilder.test.ts index 58687d5a1..2daa0737b 100644 --- a/web/src/components/ui/charts/BusterChartJS/hooks/useSeriesOptions/scatterSeriesBuilder.test.ts +++ b/web/src/components/ui/charts/BusterChartJS/hooks/useSeriesOptions/scatterSeriesBuilder.test.ts @@ -61,7 +61,8 @@ describe('scatterSeriesBuilder_data', () => { barShowTotalAtTop: false, barGroupType: null, yAxisKeys: ['metric1'], - y2AxisKeys: [] + y2AxisKeys: [], + trendlines: [] }; it('should create basic scatter dataset without size options', () => { @@ -141,77 +142,8 @@ describe('scatterSeriesBuilder_labels', () => { expect(result).toBeUndefined(); }); - test('should process date labels directly when x-axis is date type', () => { - const dateString1 = '2023-01-01'; - const dateString2 = '2023-01-02'; - - const props: LabelBuilderProps = { - trendlineSeries: [{ yAxisKey: 'y1' } as any], - datasetOptions: { - ticks: [[dateString1], [dateString2]], - datasets: [{ dataKey: 'y1', data: [10, 20] } as any], - ticksKey: [{ key: 'x', value: 'X Axis' }] - } as any, - columnLabelFormats: { - x: { - columnType: 'date', - style: 'date' - } - }, - xAxisKeys: ['x'], - sizeKey: [], - columnSettings: {} - }; - - const result = scatterSeriesBuilder_labels(props); - expect(result).toEqual([ - createDayjsDate(dateString1).toDate(), - createDayjsDate(dateString2).toDate() - ]); - }); - - test('should collect all ticks without deduplication', () => { - const props: LabelBuilderProps = { - trendlineSeries: [{ yAxisKey: 'y1' } as any, { yAxisKey: 'y2' } as any], - datasetOptions: { - ticks: [], - datasets: [ - { - dataKey: 'y1', - data: [10, 20], - ticksForScatter: [ - [1, 'A'], - [2, 'B'] - ] - } as any, - { - dataKey: 'y2', - data: [30, 40, 50], - ticksForScatter: [ - [1, 'A'], - [3, 'C'], - [5, 'D'] - ] - } as any - ], - ticksKey: [{ key: 'x', value: 'X Axis' }] - } as any, - columnLabelFormats: { - x: DEFAULT_COLUMN_LABEL_FORMAT - }, - xAxisKeys: ['x'], - sizeKey: [], - columnSettings: {} - }; - - const result = scatterSeriesBuilder_labels(props); - // Should include duplicate [1, 'A'] from both datasets - expect(result).toEqual([1, 'A', 1, 'A', 2, 'B', 3, 'C', 5, 'D']); - }); - test('should return undefined when no relevant datasets are found', () => { const props: LabelBuilderProps = { - trendlineSeries: [{ yAxisKey: 'y1' } as any], datasetOptions: { ticks: [], datasets: [ diff --git a/web/src/components/ui/charts/BusterChartJS/hooks/useSeriesOptions/useSeriesOptions.ts b/web/src/components/ui/charts/BusterChartJS/hooks/useSeriesOptions/useSeriesOptions.ts index da2feea53..ed69fe09e 100644 --- a/web/src/components/ui/charts/BusterChartJS/hooks/useSeriesOptions/useSeriesOptions.ts +++ b/web/src/components/ui/charts/BusterChartJS/hooks/useSeriesOptions/useSeriesOptions.ts @@ -127,6 +127,7 @@ export type LabelBuilderProps = { xAxisKeys: ChartEncodes['x']; sizeKey: ScatterAxis['size']; columnSettings: NonNullable; + trendlineSeries?: Array<{ yAxisKey: string }>; }; const labelsBuilderRecord: Record< diff --git a/web/src/context/BusterWebSocket/BusterWebSocketProvider/useBusterWebSocket.tsx b/web/src/context/BusterWebSocket/BusterWebSocketProvider/useBusterWebSocket.tsx index 7002387da..e85d83ca0 100644 --- a/web/src/context/BusterWebSocket/BusterWebSocketProvider/useBusterWebSocket.tsx +++ b/web/src/context/BusterWebSocket/BusterWebSocketProvider/useBusterWebSocket.tsx @@ -13,6 +13,7 @@ import { useSupabaseContext } from '../../Supabase'; import { createContext, useContextSelector } from 'use-context-selector'; import { SupabaseContextReturnType } from '../../Supabase'; import { useBusterNotifications } from '@/context/BusterNotifications'; +import { useUserConfigContextSelector } from '@/context/Users'; const BUSTER_WS_URL = `${process.env.NEXT_PUBLIC_WEB_SOCKET_URL}/api/v1/ws`; @@ -36,11 +37,13 @@ interface BusterSocket { const useBusterWebSocketHook = ({ socketURL, accessToken, - checkTokenValidity + checkTokenValidity, + organizationId }: { socketURL: string; accessToken: string | undefined; checkTokenValidity: SupabaseContextReturnType['checkTokenValidity']; + organizationId: string | undefined; }) => { const { openErrorNotification } = useBusterNotifications(); @@ -77,7 +80,7 @@ const useBusterWebSocketHook = ({ const { sendJSONMessage, connectionStatus } = useWebSocket({ url: socketURL, onMessage, - canConnect: !!accessToken, + canConnect: !!accessToken && !!organizationId, checkTokenValidity }); @@ -198,11 +201,13 @@ export const BusterWebSocketProvider: React.FC<{ }> = React.memo(({ children }) => { const accessToken = useSupabaseContext((state) => state.accessToken); const checkTokenValidity = useSupabaseContext((state) => state.checkTokenValidity); + const organizationId = useUserConfigContextSelector((state) => state.userOrganizations?.id); const busterSocketHook = useBusterWebSocketHook({ socketURL: BUSTER_WS_URL, accessToken, - checkTokenValidity + checkTokenValidity, + organizationId }); return {children}; diff --git a/web/src/lib/query.ts b/web/src/lib/query.ts index ded0fb40c..0b99036d2 100644 --- a/web/src/lib/query.ts +++ b/web/src/lib/query.ts @@ -1,4 +1,5 @@ import { RustApiError } from '@/api/buster_rest/errors'; +import { userQueryKeys } from '@/api/query_keys/users'; import { QueryClient, queryOptions } from '@tanstack/react-query'; export const isQueryStale = ( @@ -15,3 +16,9 @@ export const isQueryStale = ( return isStale; }; + +export const hasOrganizationId = (queryClient: QueryClient): boolean => { + const organizationId = queryClient.getQueryData(userQueryKeys.userGetUserMyself.queryKey) + ?.organizations?.[0]?.id; + return !!organizationId; +};