diff --git a/web/package-lock.json b/web/package-lock.json index 468c2fd91..39ca908ea 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -77,7 +77,8 @@ "ts-jest": "^29.2.6", "use-context-selector": "^2.0.0", "utility-types": "^3.11.0", - "virtua": "^0.40.3" + "virtua": "^0.40.3", + "zustand": "^5.0.3" }, "devDependencies": { "@chromatic-com/storybook": "^3.2.6", @@ -21661,6 +21662,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zustand": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.3.tgz", + "integrity": "sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/web/package.json b/web/package.json index 556708176..31fb03d06 100644 --- a/web/package.json +++ b/web/package.json @@ -85,7 +85,8 @@ "ts-jest": "^29.2.6", "use-context-selector": "^2.0.0", "utility-types": "^3.11.0", - "virtua": "^0.40.3" + "virtua": "^0.40.3", + "zustand": "^5.0.3" }, "devDependencies": { "@chromatic-com/storybook": "^3.2.6", diff --git a/web/src/components/features/modal/AddToDashboardModal.tsx b/web/src/components/features/modal/AddToDashboardModal.tsx new file mode 100644 index 000000000..5ee7d2ea9 --- /dev/null +++ b/web/src/components/features/modal/AddToDashboardModal.tsx @@ -0,0 +1,86 @@ +import { useGetMetricsList } from '@/api/buster_rest/metrics'; +import { AppModal } from '@/components/ui/modal'; +import { useDebounceSearch } from '@/hooks'; +import React, { useState } from 'react'; +import { BusterList } from '@/components/ui/list'; +import { Input } from '@/components/ui/inputs'; + +export const AddToDashboardModal: React.FC<{ + open: boolean; + onClose: () => void; + dashboardId: string; +}> = React.memo(({ open, onClose, dashboardId }) => { + const { data: metrics, isFetched: isFetchedMetrics } = useGetMetricsList({}); + const [selectedMetrics, setSelectedMetrics] = useState([]); + + const { filteredItems, handleSearchChange } = useDebounceSearch({ + items: metrics || [], + searchPredicate: (item, searchText) => { + return item.title.toLowerCase().includes(searchText.toLowerCase()); + } + }); + + const columns = [ + { + title: 'Metric', + dataIndex: 'title', + width: 300 + } + ]; + + const rows = filteredItems.map((metric) => ({ + id: metric.id, + data: { + title: metric.title + } + })); + + const handleAddMetrics = async () => { + // TODO: Implement the API call to add metrics to dashboard + console.log('Adding metrics:', selectedMetrics); + onClose(); + }; + + return ( + +
+ handleSearchChange(e.target.value)} + /> +
+ +
+
+
+ ); +}); diff --git a/web/src/context/AppProviders.tsx b/web/src/context/AppProviders.tsx index 4f3391dcc..0283ab9dd 100644 --- a/web/src/context/AppProviders.tsx +++ b/web/src/context/AppProviders.tsx @@ -4,10 +4,10 @@ import { SupabaseContextProvider } from './Supabase/SupabaseContextProvider'; import { UseSupabaseContextType } from './Supabase/getSupabaseServerContext'; import { BusterReactQueryProvider } from './BusterReactQuery/BusterReactQueryAndApi'; import { AppLayoutProvider } from './BusterAppLayout'; -import { BusterUserConfigProvider } from './Users/UserConfigProvider'; +import { BusterUserConfigProvider } from './Users/BusterUserConfigProvider'; import { BusterAssetsProvider } from './Assets/BusterAssetsProvider'; import { BusterPosthogProvider } from './Posthog'; -import { BusterChatProvider } from './Chats'; +import { BusterNewChatProvider } from './Chats'; import { RoutePrefetcher } from './RoutePrefetcher'; import type { BusterUserResponse } from '@/api/asset_interfaces'; @@ -30,12 +30,12 @@ export const AppProviders: React.FC< - + {children} - + diff --git a/web/src/context/BusterAppLayout/AppLayoutProvider.tsx b/web/src/context/BusterAppLayout/AppLayoutProvider.tsx index edb1ea477..e3e8e8a04 100644 --- a/web/src/context/BusterAppLayout/AppLayoutProvider.tsx +++ b/web/src/context/BusterAppLayout/AppLayoutProvider.tsx @@ -57,8 +57,7 @@ export const useAppLayout = () => { currentRoute, onToggleInviteModal, openInviteModal, - onChangePage, - pathname + onChangePage }; }; diff --git a/web/src/context/Chats/BusterChatProvider.tsx b/web/src/context/Chats/BusterChatProvider.tsx deleted file mode 100644 index 9f5a8e084..000000000 --- a/web/src/context/Chats/BusterChatProvider.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import React from 'react'; -import { BusterNewChatProvider } from './NewChatProvider'; - -export const BusterChatProvider = React.memo(({ children }: { children: React.ReactNode }) => { - return {children}; -}); - -BusterChatProvider.displayName = 'ChatProvider'; diff --git a/web/src/context/Chats/NewChatProvider/NewChatProvider.tsx b/web/src/context/Chats/NewChatProvider.tsx similarity index 100% rename from web/src/context/Chats/NewChatProvider/NewChatProvider.tsx rename to web/src/context/Chats/NewChatProvider.tsx diff --git a/web/src/context/Chats/NewChatProvider/index.ts b/web/src/context/Chats/NewChatProvider/index.ts deleted file mode 100644 index 13ad697b8..000000000 --- a/web/src/context/Chats/NewChatProvider/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './NewChatProvider'; diff --git a/web/src/context/Chats/NewChatProvider/chatStreamMessageHelper.test.ts b/web/src/context/Chats/chatStreamMessageHelper.test.ts similarity index 100% rename from web/src/context/Chats/NewChatProvider/chatStreamMessageHelper.test.ts rename to web/src/context/Chats/chatStreamMessageHelper.test.ts diff --git a/web/src/context/Chats/NewChatProvider/chatStreamMessageHelper.ts b/web/src/context/Chats/chatStreamMessageHelper.ts similarity index 100% rename from web/src/context/Chats/NewChatProvider/chatStreamMessageHelper.ts rename to web/src/context/Chats/chatStreamMessageHelper.ts diff --git a/web/src/context/Chats/index.ts b/web/src/context/Chats/index.ts index febc35a3e..13ad697b8 100644 --- a/web/src/context/Chats/index.ts +++ b/web/src/context/Chats/index.ts @@ -1,5 +1 @@ -import { useBusterNewChatContextSelector } from './NewChatProvider'; - -export * from './BusterChatProvider'; - -export { useBusterNewChatContextSelector }; +export * from './NewChatProvider'; diff --git a/web/src/context/Chats/NewChatProvider/useBlackBoxMessage.ts b/web/src/context/Chats/useBlackBoxMessage.ts similarity index 100% rename from web/src/context/Chats/NewChatProvider/useBlackBoxMessage.ts rename to web/src/context/Chats/useBlackBoxMessage.ts diff --git a/web/src/context/Chats/NewChatProvider/useChatStreamMessage.ts b/web/src/context/Chats/useChatStreamMessage.ts similarity index 100% rename from web/src/context/Chats/NewChatProvider/useChatStreamMessage.ts rename to web/src/context/Chats/useChatStreamMessage.ts diff --git a/web/src/context/Chats/NewChatProvider/useChatUpdate.ts b/web/src/context/Chats/useChatUpdate.ts similarity index 100% rename from web/src/context/Chats/NewChatProvider/useChatUpdate.ts rename to web/src/context/Chats/useChatUpdate.ts diff --git a/web/src/context/Dashboards/index.ts b/web/src/context/Dashboards/index.ts new file mode 100644 index 000000000..aca5463b1 --- /dev/null +++ b/web/src/context/Dashboards/index.ts @@ -0,0 +1 @@ +export * from './useDashboardContentStore'; diff --git a/web/src/context/Dashboards/useDashboardContentStore.tsx b/web/src/context/Dashboards/useDashboardContentStore.tsx new file mode 100644 index 000000000..ef4cec726 --- /dev/null +++ b/web/src/context/Dashboards/useDashboardContentStore.tsx @@ -0,0 +1,11 @@ +import { create } from 'zustand'; + +export const useDashboardContentStore = create<{ + openAddContentModal: boolean; + onCloseAddContentModal: () => void; + onOpenAddContentModal: () => void; +}>((set) => ({ + openAddContentModal: false, + onCloseAddContentModal: () => set({ openAddContentModal: false }), + onOpenAddContentModal: () => set({ openAddContentModal: true }) +})); diff --git a/web/src/context/Users/UserConfigProvider.tsx b/web/src/context/Users/BusterUserConfigProvider.tsx similarity index 100% rename from web/src/context/Users/UserConfigProvider.tsx rename to web/src/context/Users/BusterUserConfigProvider.tsx diff --git a/web/src/context/Users/index.ts b/web/src/context/Users/index.ts index aaace6858..d71137abb 100644 --- a/web/src/context/Users/index.ts +++ b/web/src/context/Users/index.ts @@ -1 +1 @@ -export * from './UserConfigProvider'; +export * from './BusterUserConfigProvider'; diff --git a/web/src/controllers/DashboardController/DashboardController.tsx b/web/src/controllers/DashboardController/DashboardController.tsx index db5bdc801..c81213dbf 100644 --- a/web/src/controllers/DashboardController/DashboardController.tsx +++ b/web/src/controllers/DashboardController/DashboardController.tsx @@ -1,21 +1,17 @@ 'use client'; -import React, { useState } from 'react'; +import React from 'react'; import { FileIndeterminateLoader } from '@/components/features/FileIndeterminateLoader'; import { DashboardFileView, useChatLayoutContextSelector } from '@/layouts/ChatLayout'; import { DashboardViewComponents } from './config'; import { AddTypeModal } from '@/components/features/modal/AddTypeModal'; -import { useMemoizedFn } from '@/hooks'; import { useGetDashboard } from '@/api/buster_rest/dashboards'; +import { useDashboardContentStore } from '@/context/Dashboards'; export const DashboardController: React.FC<{ dashboardId: string }> = ({ dashboardId }) => { const { data: dashboardResponse, isFetched: isFetchedDashboard } = useGetDashboard(dashboardId); const selectedFileView = useChatLayoutContextSelector((x) => x.selectedFileView) || 'dashboard'; - const [openAddTypeModal, setOpenAddTypeModal] = useState(false); - - const onCloseModal = useMemoizedFn(() => { - setOpenAddTypeModal(false); - }); + const { openAddContentModal, onCloseAddContentModal } = useDashboardContentStore(); const Component = selectedFileView && isFetchedDashboard @@ -28,8 +24,8 @@ export const DashboardController: React.FC<{ dashboardId: string }> = ({ dashboa diff --git a/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardViewDashboardController.tsx b/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardViewDashboardController.tsx index a1f97530d..6e4dc1ba9 100644 --- a/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardViewDashboardController.tsx +++ b/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardViewDashboardController.tsx @@ -10,6 +10,7 @@ import { useUpdateDashboard, useUpdateDashboardConfig } from '@/api/buster_rest/dashboards'; +import { useDashboardContentStore } from '@/context/Dashboards'; export const DashboardViewDashboardController: React.FC = ({ dashboardId, @@ -18,10 +19,7 @@ export const DashboardViewDashboardController: React.FC = ({ const { data: dashboardResponse } = useGetDashboard(dashboardId); const { mutateAsync: onUpdateDashboard } = useUpdateDashboard(); const { mutateAsync: onUpdateDashboardConfig } = useUpdateDashboardConfig(); - - const onOpenAddContentModal = useMemoizedFn(() => { - console.log('open add content modal'); - }); + const onOpenAddContentModal = useDashboardContentStore((x) => x.onOpenAddContentModal); const metrics = dashboardResponse?.metrics; const dashboard = dashboardResponse?.dashboard;