From b5290ac3c0989e24fca97749987a432355fba380 Mon Sep 17 00:00:00 2001 From: dextmorgn Date: Mon, 10 Feb 2025 23:03:03 +0100 Subject: [PATCH] feat: show labels on zoom --- src/app/dashboard/layout.tsx | 8 ++--- .../[investigation_id]/layout.tsx | 6 +--- .../[investigation_id]/loading.tsx | 10 +++++++ src/app/investigations/loading.tsx | 10 +++++++ src/components/contexts/chatbot-context.tsx | 14 ++++----- .../contexts/investigation-provider.tsx | 13 ++++++-- src/components/copy.tsx | 2 +- src/components/investigations/graph.tsx | 15 +++++++--- src/components/investigations/layout.tsx | 30 ++++++++++++------- src/components/investigations/nodes/email.tsx | 15 +++++----- .../investigations/nodes/individual.tsx | 12 ++++---- .../investigations/nodes/ip_address.tsx | 14 +++++---- src/components/investigations/nodes/phone.tsx | 14 +++++---- .../investigations/nodes/physical_address.tsx | 14 +++++---- .../investigations/nodes/social.tsx | 15 +++++----- src/components/user.tsx | 6 ++-- src/lib/utils.ts | 2 ++ 17 files changed, 126 insertions(+), 74 deletions(-) create mode 100644 src/app/investigations/[investigation_id]/loading.tsx create mode 100644 src/app/investigations/loading.tsx diff --git a/src/app/dashboard/layout.tsx b/src/app/dashboard/layout.tsx index a648d53..87c1464 100644 --- a/src/app/dashboard/layout.tsx +++ b/src/app/dashboard/layout.tsx @@ -21,13 +21,13 @@ const DashboardLayout = async ({
-
+
- +
@@ -37,8 +37,8 @@ const DashboardLayout = async ({
-
- +
+ diff --git a/src/app/investigations/[investigation_id]/layout.tsx b/src/app/investigations/[investigation_id]/layout.tsx index 3b838aa..a1745f2 100644 --- a/src/app/investigations/[investigation_id]/layout.tsx +++ b/src/app/investigations/[investigation_id]/layout.tsx @@ -1,9 +1,7 @@ import { InvestigationProvider } from '@/src/components/contexts/investigation-provider'; import InvestigationLayout from '@/src/components/investigations/layout'; -import { getInvestigation } from '@/src/lib/actions/investigations'; import Individuals from './individuals'; import { SearchProvider } from '@/src/components/contexts/search-context'; -import { notFound } from 'next/navigation'; import { createClient } from "@/src/lib/supabase/server"; import { redirect } from "next/navigation"; import { ChatProvider } from '@/src/components/contexts/chatbot-context'; @@ -21,14 +19,12 @@ const DashboardLayout = async ({ redirect('/login') } const { investigation_id } = await (params) - const { error } = await getInvestigation(investigation_id) - if (error) return notFound() return ( - }> + }> {children} diff --git a/src/app/investigations/[investigation_id]/loading.tsx b/src/app/investigations/[investigation_id]/loading.tsx new file mode 100644 index 0000000..a1452a1 --- /dev/null +++ b/src/app/investigations/[investigation_id]/loading.tsx @@ -0,0 +1,10 @@ +import { Spinner } from '@radix-ui/themes' +import React from 'react' + +const loading = () => { + return ( +
Loading nodes and edges...
+ ) +} + +export default loading \ No newline at end of file diff --git a/src/app/investigations/loading.tsx b/src/app/investigations/loading.tsx new file mode 100644 index 0000000..79604ce --- /dev/null +++ b/src/app/investigations/loading.tsx @@ -0,0 +1,10 @@ +import { Spinner } from '@radix-ui/themes' +import React from 'react' + +const loading = () => { + return ( +
Loading investigation...
+ ) +} + +export default loading \ No newline at end of file diff --git a/src/components/contexts/chatbot-context.tsx b/src/components/contexts/chatbot-context.tsx index 4eb3cee..a04e0a8 100644 --- a/src/components/contexts/chatbot-context.tsx +++ b/src/components/contexts/chatbot-context.tsx @@ -1,7 +1,7 @@ 'use client'; import { createContext, ReactNode, useContext, useState } from 'react'; -import { Avatar, Box, Card, Dialog, Flex, Spinner, Text, TextField } from '@radix-ui/themes'; +import { Avatar, Box, Card, Dialog, Flex, Spinner, Text, TextArea, TextField } from '@radix-ui/themes'; import { useChat } from '@ai-sdk/react'; import { BotIcon } from 'lucide-react'; import { cn } from '@/src/lib/utils'; @@ -100,7 +100,7 @@ export const ChatProvider: React.FC = ({ children }) => { {m.role === 'user' ? 'User' : 'Chatbot'} - + {m.content} @@ -135,11 +135,11 @@ export const ChatProvider: React.FC = ({ children }) => { }
- + + + diff --git a/src/components/contexts/investigation-provider.tsx b/src/components/contexts/investigation-provider.tsx index 2510009..1b6445f 100644 --- a/src/components/contexts/investigation-provider.tsx +++ b/src/components/contexts/investigation-provider.tsx @@ -20,7 +20,9 @@ interface InvestigationContextType { handleOpenIndividualModal: any, handleDeleteInvestigation: any, currentNode: any, - setCurrentNode: any + setCurrentNode: any, + panelOpen: boolean, + setPanelOpen: any } const InvestigationContext = createContext(undefined); @@ -33,6 +35,7 @@ export const InvestigationProvider: React.FC = ({ ch const router = useRouter() const pathname = usePathname() const searchParams = useSearchParams() + const [panelOpen, setPanelOpen] = useLocalStorage('panel_open', false) const [filters, setFilters] = useLocalStorage('filters', {}); const [currentNode, setCurrentNode] = useState(null) const { investigation, isLoading: isLoadingInvestigation } = useInvestigation(investigation_id) @@ -40,7 +43,9 @@ export const InvestigationProvider: React.FC = ({ ch const { confirm } = useConfirm() const [settings, setSettings] = useLocalStorage('settings', { showNodeLabel: true, - showEdgeLabel: true + showEdgeLabel: true, + showMiniMap: true, + showCopyIcon: true }); const createQueryString = useCallback( @@ -76,7 +81,7 @@ export const InvestigationProvider: React.FC = ({ ch
) return ( - + {children} @@ -87,6 +92,8 @@ export const InvestigationProvider: React.FC = ({ ch + +

Theme

diff --git a/src/components/copy.tsx b/src/components/copy.tsx index 812a8e8..56228e7 100644 --- a/src/components/copy.tsx +++ b/src/components/copy.tsx @@ -32,7 +32,7 @@ export function CopyButton({ content, delay = 2000 }: CopyButtonProps) { return ( - + ) diff --git a/src/components/investigations/graph.tsx b/src/components/investigations/graph.tsx index b0ae05e..e823475 100644 --- a/src/components/investigations/graph.tsx +++ b/src/components/investigations/graph.tsx @@ -29,7 +29,7 @@ import AddressNode from './nodes/physical_address' import { AlignCenterHorizontal, AlignCenterVertical, LockOpenIcon, MaximizeIcon, RotateCcwIcon, ZoomInIcon, ZoomOutIcon, LockIcon } from 'lucide-react'; import { useTheme } from 'next-themes'; import NewActions from './new-actions'; -import { IconButton, Tooltip, Spinner, Card, Flex } from '@radix-ui/themes'; +import { IconButton, Tooltip, Spinner, Card, Flex, SegmentedControl } from '@radix-ui/themes'; import { isNode, isEdge, getIncomers, getOutgoers } from "@xyflow/react"; import { EdgeBase } from '@xyflow/system'; import { useInvestigationContext } from '../contexts/investigation-provider'; @@ -72,7 +72,7 @@ const LayoutFlow = ({ initialNodes, initialEdges, theme }: { initialNodes: any, const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes); const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges); const [isLocked, setIsLocked] = useState(false) - const { currentNode, setCurrentNode } = useInvestigationContext() + const { currentNode, setCurrentNode, settings } = useInvestigationContext() const ref = useRef(null); const getAllIncomers = useCallback((node: any, nodes: any[], edges: EdgeBase[], prevIncomers = []) => { const incomers = getIncomers(node, nodes, edges); @@ -293,6 +293,13 @@ const LayoutFlow = ({ initialNodes, initialEdges, theme }: { initialNodes: any, + + + Graph + Timeline + Map + + @@ -337,9 +344,9 @@ const LayoutFlow = ({ initialNodes, initialEdges, theme }: { initialNodes: any, - + {settings.showMiniMap && } -
+
); }; diff --git a/src/components/investigations/layout.tsx b/src/components/investigations/layout.tsx index 02e17ec..7872a0e 100644 --- a/src/components/investigations/layout.tsx +++ b/src/components/investigations/layout.tsx @@ -1,30 +1,33 @@ "use client" -import { Investigation } from '@/src/types/investigation'; import React from 'react' -import { ThemeSwitch } from '../theme-switch'; import MoreMenu from './more-menu'; import CaseSelector from './case-selector'; import NewCase from '../dashboard/new-case'; import SearchModal from '../dashboard/seach-palette'; import { Flex, IconButton, ScrollArea } from '@radix-ui/themes'; import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; -import { BotMessageSquareIcon } from 'lucide-react'; +import { BotMessageSquareIcon, PanelRightIcon } from 'lucide-react'; import { useChatContext } from '../contexts/chatbot-context'; import Logo from '../logo'; +import { useInvestigationContext } from '../contexts/investigation-provider'; +import User from '../user'; const InvestigationLayout = ({ children, left, - investigation_id + investigation_id, + user }: { children: React.ReactNode; left: React.ReactNode; investigation_id: string + user: any }) => { const { setOpen: setOpenChat } = useChatContext() + const { panelOpen, setPanelOpen } = useInvestigationContext() return ( - - + + {panelOpen &&
@@ -39,14 +42,21 @@ const InvestigationLayout = ({ {left}
- + + +
-
+
} - +
- + + setPanelOpen(!panelOpen)} variant='soft' color='gray'> + + + +
{children} diff --git a/src/components/investigations/nodes/email.tsx b/src/components/investigations/nodes/email.tsx index 6b5784a..4286fa5 100644 --- a/src/components/investigations/nodes/email.tsx +++ b/src/components/investigations/nodes/email.tsx @@ -1,25 +1,26 @@ "use client" import React, { memo } from 'react'; -import { Handle, Position } from '@xyflow/react'; +import { Handle, Position, useStore } from '@xyflow/react'; import { Card, Box, Text, ContextMenu, Badge, Flex, Inset, Tooltip, Avatar } from '@radix-ui/themes'; import { NodeProvider, useNodeContext } from '../../contexts/node-context'; import { AtSignIcon, ZapIcon } from 'lucide-react'; -import { cn } from '@/src/lib/utils'; +import { cn, zoomSelector } from '@/src/lib/utils'; import { useInvestigationContext } from '../../contexts/investigation-provider'; import { CopyButton } from '../../copy'; import { useSearchContext } from '../../contexts/search-context'; function EmailNode({ data }: any) { const { handleDeleteNode, loading } = useNodeContext() - const { settings } = useInvestigationContext() + const { settings, currentNode } = useInvestigationContext() const { handleOpenSearchModal } = useSearchContext() + const showContent = useStore(zoomSelector); return ( - {settings.showNodeLabel ? - + {settings.showNodeLabel && showContent ? + @@ -29,7 +30,7 @@ function EmailNode({ data }: any) { {data.label} - + {settings.showCopyIcon && } @@ -63,7 +64,7 @@ function EmailNode({ data }: any) { Delete - + ); } diff --git a/src/components/investigations/nodes/individual.tsx b/src/components/investigations/nodes/individual.tsx index 2563d72..3594317 100644 --- a/src/components/investigations/nodes/individual.tsx +++ b/src/components/investigations/nodes/individual.tsx @@ -1,26 +1,28 @@ "use client" import React, { memo } from 'react'; -import { Handle, Position } from '@xyflow/react'; +import { Handle, Position, useStore } from '@xyflow/react'; import { useInvestigationContext } from '../../contexts/investigation-provider'; import { Avatar, Card, Box, Flex, Text, ContextMenu, Spinner, Badge, Tooltip } from '@radix-ui/themes'; import { AtSignIcon, CameraIcon, FacebookIcon, InstagramIcon, LocateIcon, MessageCircleDashedIcon, PhoneIcon, SendIcon, UserIcon, MapPinHouseIcon, ZapIcon, BotIcon } from 'lucide-react'; import { NodeProvider, useNodeContext } from '../../contexts/node-context'; import { useSearchContext } from '../../contexts/search-context'; -import { cn } from '@/src/lib/utils'; +import { cn, zoomSelector } from '@/src/lib/utils'; import { CopyButton } from '../../copy'; import { useChatContext } from '../../contexts/chatbot-context'; + function Custom(props: any) { const { settings, handleOpenIndividualModal, currentNode } = useInvestigationContext() const { setOpenAddNodeModal, handleDuplicateNode, handleDeleteNode, loading } = useNodeContext() const { handleOpenSearchModal } = useSearchContext() const { setOpen: setOpenChat } = useChatContext() + const showContent = useStore(zoomSelector); const { data } = props return ( <> { e.stopPropagation() }}> - {settings.showNodeLabel ? + {settings.showNodeLabel && showContent ? handleOpenIndividualModal(data.id)} className={cn('!py-1 border border-transparent hover:border-sky-400', currentNode === data.id && "border-sky-400")}> : data.full_name[0]} /> - {settings.showNodeLabel && + {settings.showNodeLabel && showContent && {data.full_name} - + {settings.showCopyIcon && } } : diff --git a/src/components/investigations/nodes/ip_address.tsx b/src/components/investigations/nodes/ip_address.tsx index 71b3dfc..60cd96a 100644 --- a/src/components/investigations/nodes/ip_address.tsx +++ b/src/components/investigations/nodes/ip_address.tsx @@ -1,25 +1,27 @@ "use client" import React, { memo } from 'react'; -import { Handle, Position } from '@xyflow/react'; +import { Handle, Position, useStore } from '@xyflow/react'; import { Card, Box, Text, ContextMenu, Flex, Inset, Badge, Tooltip, Avatar } from '@radix-ui/themes'; import { NodeProvider, useNodeContext } from '../../contexts/node-context'; import { LocateIcon, ZapIcon } from 'lucide-react'; -import { cn } from '@/src/lib/utils'; +import { cn, zoomSelector } from '@/src/lib/utils'; import { useInvestigationContext } from '../../contexts/investigation-provider'; import { CopyButton } from '../../copy'; import { useSearchContext } from '../../contexts/search-context'; function Custom({ data }: any) { const { handleDeleteNode, loading } = useNodeContext() - const { settings } = useInvestigationContext() + const { settings, currentNode } = useInvestigationContext() const { handleOpenSearchModal } = useSearchContext() + const showContent = useStore(zoomSelector); + return ( <> - {settings.showNodeLabel ? - + {settings.showNodeLabel && showContent ? + @@ -29,7 +31,7 @@ function Custom({ data }: any) { {data.label} - + {settings.showCopyIcon && } diff --git a/src/components/investigations/nodes/phone.tsx b/src/components/investigations/nodes/phone.tsx index 2d34b53..8bc09f6 100644 --- a/src/components/investigations/nodes/phone.tsx +++ b/src/components/investigations/nodes/phone.tsx @@ -1,25 +1,27 @@ "use client" import React, { memo } from 'react'; -import { Handle, Position } from '@xyflow/react'; +import { Handle, Position, useStore } from '@xyflow/react'; import { Card, Box, Text, ContextMenu, Flex, Inset, Badge, Tooltip, Avatar } from '@radix-ui/themes'; import { NodeProvider, useNodeContext } from '../../contexts/node-context'; import { PhoneIcon, ZapIcon } from 'lucide-react'; -import { cn } from '@/src/lib/utils'; +import { cn, zoomSelector } from '@/src/lib/utils'; import { useInvestigationContext } from '../../contexts/investigation-provider'; import { CopyButton } from '../../copy'; import { useSearchContext } from '../../contexts/search-context'; function Custom({ data }: any) { const { handleDeleteNode, loading } = useNodeContext() - const { settings } = useInvestigationContext() + const { settings, currentNode } = useInvestigationContext() const { handleOpenSearchModal } = useSearchContext() + const showContent = useStore(zoomSelector); + return ( <> - {settings.showNodeLabel ? - + {settings.showNodeLabel && showContent ? + @@ -29,7 +31,7 @@ function Custom({ data }: any) { {data.label} - + {settings.showCopyIcon && } diff --git a/src/components/investigations/nodes/physical_address.tsx b/src/components/investigations/nodes/physical_address.tsx index 2be4b0f..c734eee 100644 --- a/src/components/investigations/nodes/physical_address.tsx +++ b/src/components/investigations/nodes/physical_address.tsx @@ -1,24 +1,26 @@ "use client" import React, { memo } from 'react'; -import { Handle, Position } from '@xyflow/react'; +import { Handle, Position, useStore } from '@xyflow/react'; import { Card, Box, Text, ContextMenu, Badge, Flex, Inset, Tooltip, Avatar } from '@radix-ui/themes'; import { NodeProvider, useNodeContext } from '../../contexts/node-context'; import { MapPinHouseIcon, ZapIcon } from 'lucide-react'; -import { cn } from '@/src/lib/utils'; +import { cn, zoomSelector } from '@/src/lib/utils'; import { useInvestigationContext } from '../../contexts/investigation-provider'; import { CopyButton } from '../../copy'; import { useSearchContext } from '../../contexts/search-context'; function AddressNode({ data }: any) { const { handleDeleteNode, loading } = useNodeContext() - const { settings } = useInvestigationContext() + const { settings, currentNode } = useInvestigationContext() const { handleOpenSearchModal } = useSearchContext() + const showContent = useStore(zoomSelector); + return ( - {settings.showNodeLabel ? - + {settings.showNodeLabel && showContent ? + @@ -28,7 +30,7 @@ function AddressNode({ data }: any) { {data.label} - + {settings.showCopyIcon && } diff --git a/src/components/investigations/nodes/social.tsx b/src/components/investigations/nodes/social.tsx index 46035a6..a1f2157 100644 --- a/src/components/investigations/nodes/social.tsx +++ b/src/components/investigations/nodes/social.tsx @@ -1,9 +1,9 @@ "use client" import React, { memo } from 'react'; -import { Handle, Position } from '@xyflow/react'; +import { Handle, Position, useStore } from '@xyflow/react'; import { Card, Box, Text, ContextMenu, Flex, Inset, Badge, Tooltip, Avatar } from '@radix-ui/themes'; import { NodeProvider, useNodeContext } from '../../contexts/node-context'; -import { cn } from '@/src/lib/utils'; +import { cn, zoomSelector } from '@/src/lib/utils'; import { useInvestigationContext } from '../../contexts/investigation-provider'; import { usePlatformIcons } from '@/src/lib/hooks/use-platform-icons'; import { CopyButton } from '../../copy'; @@ -12,16 +12,18 @@ import { useSearchContext } from '../../contexts/search-context'; function Custom({ data }: any) { const { handleDeleteNode, loading } = useNodeContext() - const { settings } = useInvestigationContext() + const { settings, currentNode } = useInvestigationContext() const platformsIcons = usePlatformIcons() const { handleOpenSearchModal } = useSearchContext() + const showContent = useStore(zoomSelector); + return ( <> - {settings.showNodeLabel ? - + {settings.showNodeLabel && showContent ? + {/* @ts-ignore */} @@ -35,8 +37,7 @@ function Custom({ data }: any) { {data.username || data.profile_url} - + {settings.showCopyIcon && } diff --git a/src/components/user.tsx b/src/components/user.tsx index faff6fa..2a62f76 100644 --- a/src/components/user.tsx +++ b/src/components/user.tsx @@ -1,15 +1,15 @@ -import { Avatar, Button, DropdownMenu, Inset, Text } from '@radix-ui/themes' +import { Avatar, Button, DropdownMenu, IconButton, Inset, Text } from '@radix-ui/themes' import React from 'react' const User = ({ user }: any) => { return ( - + {user?.user_metadata?.user_name} diff --git a/src/lib/utils.ts b/src/lib/utils.ts index bd0c391..d72b3ea 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -4,3 +4,5 @@ import { twMerge } from "tailwind-merge" export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) } + +export const zoomSelector = (s: { transform: number[]; }) => s.transform[2] >= 0.6;