diff --git a/apps/console/src/App.tsx b/apps/console/src/App.tsx index 85fd53818..61098d91c 100644 --- a/apps/console/src/App.tsx +++ b/apps/console/src/App.tsx @@ -12,6 +12,7 @@ import AuthLayout from "./layouts/AuthLayout"; import { RelayEnvironment } from "./RelayEnvironment"; import { AuthProvider } from "./contexts/AuthContext"; import { ProtectedRoute } from "./components/ProtectedRoute"; +import { OrganizationProvider } from "./contexts/OrganizationContext"; posthog.init(process.env.POSTHOG_KEY!, { api_host: process.env.POSTHOG_HOST, @@ -48,55 +49,14 @@ function App() { - - {/* Authentication Routes - Accessible without login */} - - - - } - > + + + {/* Authentication Routes - Accessible without login */} - - - - - } - /> - - - - - - } - > - - - - - - } - /> - - - {/* Protected Routes - Require authentication */} - }> - - + } > @@ -105,112 +65,155 @@ function App() { element={ - + } /> - - - - - - } - /> - - - - - - } - /> - - - - - - } - /> - - - - - - } - /> - - - - - - } - /> - - - - - - } - /> - - - - - - } - /> - - - - - - } - /> - - - - - - } - /> - - - - } - /> - - + + + + + } + > + + + + + + } + /> + + + {/* Protected Routes - Require authentication */} + }> + + + + } + > + + + + + + } + /> + + + + + + } + /> + + + + + + } + /> + + + + + + } + /> + + + + + + } + /> + + + + + + } + /> + + + + + + } + /> + + + + + + } + /> + + + + + + } + /> + + + + + + } + /> + + + + } + /> + + + + diff --git a/apps/console/src/components/AppSidebar.tsx b/apps/console/src/components/AppSidebar.tsx index a67e4caac..501a02c45 100644 --- a/apps/console/src/components/AppSidebar.tsx +++ b/apps/console/src/components/AppSidebar.tsx @@ -30,7 +30,7 @@ import { SidebarMenuItem, } from "@/components/ui/sidebar"; import type { AppSidebarQuery as AppSidebarQueryType } from "./__generated__/AppSidebarQuery.graphql"; - +import { TeamSwitcher } from "@/components/TeamSwitcher"; const staticData = { user: { name: "shadcn", @@ -84,12 +84,8 @@ const AppSidebarQuery = graphql` query AppSidebarQuery { viewer { id - organization { - name - logoUrl - createdAt - updatedAt - } + ...TeamSwitcher_organizations + ...NavUser_viewer } } `; @@ -101,37 +97,18 @@ function AppSidebarContent({ queryRef: PreloadedQuery; }) { const data = usePreloadedQuery(AppSidebarQuery, queryRef); - const organization = data.viewer.organization; return ( - - - - - {organization.name} -
- - {organization.name} - - Enterprise -
-
-
-
-
+
- +
); @@ -162,7 +139,23 @@ function AppSidebarFallback(props: React.ComponentProps) { - + + + + +
+
+ +
+ + +
+ +
+
+ + + ); diff --git a/apps/console/src/components/NavUser.tsx b/apps/console/src/components/NavUser.tsx index 2019263a4..ef10f8830 100644 --- a/apps/console/src/components/NavUser.tsx +++ b/apps/console/src/components/NavUser.tsx @@ -8,6 +8,7 @@ import { LogOut, Sparkles, } from "lucide-react"; +import { graphql, useFragment } from "react-relay"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { @@ -25,17 +26,22 @@ import { SidebarMenuItem, useSidebar, } from "@/components/ui/sidebar"; +import { + NavUser_viewer$key, + NavUser_viewer$data, +} from "./__generated__/NavUser_viewer.graphql"; -export function NavUser({ - user, -}: { - user: { - name: string; - email: string; - avatar: string; - }; -}) { +export const navUserFragment = graphql` + fragment NavUser_viewer on User { + id + fullName + email + } +`; + +export function NavUser({ viewer }: { viewer: NavUser_viewer$key }) { const { isMobile } = useSidebar(); + const currentUser = useFragment(navUserFragment, viewer); return ( @@ -47,12 +53,18 @@ export function NavUser({ className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground" > - - CN + + {currentUser.fullName.substring(0, 2).toUpperCase()} + + + {currentUser.fullName.substring(0, 2).toUpperCase()} +
- {user.name} - {user.email} + + {currentUser.fullName} + + {currentUser.email}
@@ -66,12 +78,18 @@ export function NavUser({
- - CN + + {currentUser.fullName.substring(0, 2).toUpperCase()} + + + {currentUser.fullName.substring(0, 2).toUpperCase()} +
- {user.name} - {user.email} + + {currentUser.fullName} + + {currentUser.email}
diff --git a/apps/console/src/components/TeamSwitcher.tsx b/apps/console/src/components/TeamSwitcher.tsx new file mode 100644 index 000000000..7815cdb72 --- /dev/null +++ b/apps/console/src/components/TeamSwitcher.tsx @@ -0,0 +1,139 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { ChevronsUpDown, Plus } from "lucide-react"; +import { graphql, useFragment } from "react-relay"; +import { useOrganization } from "@/contexts/OrganizationContext"; + +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + useSidebar, +} from "@/components/ui/sidebar"; +import { + TeamSwitcher_organizations$key, + TeamSwitcher_organizations$data, +} from "./__generated__/TeamSwitcher_organizations.graphql"; + +export const teamSwitcherFragment = graphql` + fragment TeamSwitcher_organizations on User { + organizations { + id + name + logoUrl + } + } +`; + +// Extended type to include plan field until Relay compiler generates the types +type Organization = TeamSwitcher_organizations$data["organizations"][0] & { + plan?: string; +}; + +export function TeamSwitcher({ + organizations, +}: { + organizations: TeamSwitcher_organizations$key; +}) { + const { isMobile } = useSidebar(); + const data = useFragment(teamSwitcherFragment, organizations); + const { currentOrganization, setCurrentOrganization } = useOrganization(); + + useEffect(() => { + if ( + data.organizations && + data.organizations.length > 0 && + !currentOrganization + ) { + // Type assertion to include plan field + setCurrentOrganization(data.organizations[0] as Organization); + } + }, [data.organizations, currentOrganization, setCurrentOrganization]); + + // If no organizations or data is still loading + if (!currentOrganization) { + return null; + } + + // Convert logoUrl to a React component + const LogoComponent = ({ + org, + className, + }: { + org: Organization; + className?: string; + }) => { + if (org.logoUrl) { + return {org.name}; + } + return null; + }; + + return ( + + + + + +
+ +
+
+ + {currentOrganization.name} + + Free +
+ +
+
+ + + Organizations + + {data.organizations.map((org: Organization, index: number) => ( + setCurrentOrganization(org)} + className="gap-2 p-2" + > +
+ +
+ {org.name} + ⌘{index + 1} +
+ ))} + + +
+ +
+
+ Add organization +
+
+
+
+
+
+ ); +} diff --git a/apps/console/src/components/__generated__/AppSidebarQuery.graphql.ts b/apps/console/src/components/__generated__/AppSidebarQuery.graphql.ts index e5250010f..c2f30a8a3 100644 --- a/apps/console/src/components/__generated__/AppSidebarQuery.graphql.ts +++ b/apps/console/src/components/__generated__/AppSidebarQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<717a5c6c939c65b7e0790f84e2c41bcd>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -9,16 +9,12 @@ // @ts-nocheck import { ConcreteRequest } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; export type AppSidebarQuery$variables = Record; export type AppSidebarQuery$data = { readonly viewer: { readonly id: string; - readonly organization: { - readonly createdAt: any; - readonly logoUrl: string; - readonly name: string; - readonly updatedAt: any; - }; + readonly " $fragmentSpreads": FragmentRefs<"NavUser_viewer" | "TeamSwitcher_organizations">; }; }; export type AppSidebarQuery = { @@ -33,34 +29,6 @@ var v0 = { "kind": "ScalarField", "name": "id", "storageKey": null -}, -v1 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "name", - "storageKey": null -}, -v2 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "logoUrl", - "storageKey": null -}, -v3 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "createdAt", - "storageKey": null -}, -v4 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "updatedAt", - "storageKey": null }; return { "fragment": { @@ -79,19 +47,14 @@ return { "selections": [ (v0/*: any*/), { - "alias": null, "args": null, - "concreteType": "Organization", - "kind": "LinkedField", - "name": "organization", - "plural": false, - "selections": [ - (v1/*: any*/), - (v2/*: any*/), - (v3/*: any*/), - (v4/*: any*/) - ], - "storageKey": null + "kind": "FragmentSpread", + "name": "TeamSwitcher_organizations" + }, + { + "args": null, + "kind": "FragmentSpread", + "name": "NavUser_viewer" } ], "storageKey": null @@ -120,16 +83,40 @@ return { "args": null, "concreteType": "Organization", "kind": "LinkedField", - "name": "organization", - "plural": false, + "name": "organizations", + "plural": true, "selections": [ - (v1/*: any*/), - (v2/*: any*/), - (v3/*: any*/), - (v4/*: any*/), - (v0/*: any*/) + (v0/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "logoUrl", + "storageKey": null + } ], "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fullName", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "email", + "storageKey": null } ], "storageKey": null @@ -137,16 +124,16 @@ return { ] }, "params": { - "cacheID": "e50b9b44daf91d53b07f8912e6c2088f", + "cacheID": "48137f101a20a5ce116cbf46c2a8cd63", "id": null, "metadata": {}, "name": "AppSidebarQuery", "operationKind": "query", - "text": "query AppSidebarQuery {\n viewer {\n id\n organization {\n name\n logoUrl\n createdAt\n updatedAt\n id\n }\n }\n}\n" + "text": "query AppSidebarQuery {\n viewer {\n id\n ...TeamSwitcher_organizations\n ...NavUser_viewer\n }\n}\n\nfragment NavUser_viewer on User {\n id\n fullName\n email\n}\n\nfragment TeamSwitcher_organizations on User {\n organizations {\n id\n name\n logoUrl\n }\n}\n" } }; })(); -(node as any).hash = "d450e65862def2f7ebd6f4b8d0475be0"; +(node as any).hash = "d5e28d934b5913169dd822042f4eca07"; export default node; diff --git a/apps/console/src/components/__generated__/NavUser_viewer.graphql.ts b/apps/console/src/components/__generated__/NavUser_viewer.graphql.ts new file mode 100644 index 000000000..330b49549 --- /dev/null +++ b/apps/console/src/components/__generated__/NavUser_viewer.graphql.ts @@ -0,0 +1,58 @@ +/** + * @generated SignedSource<<0965f25c8dedb59a9316e4df4d773af6>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type NavUser_viewer$data = { + readonly email: string; + readonly fullName: string; + readonly id: string; + readonly " $fragmentType": "NavUser_viewer"; +}; +export type NavUser_viewer$key = { + readonly " $data"?: NavUser_viewer$data; + readonly " $fragmentSpreads": FragmentRefs<"NavUser_viewer">; +}; + +const node: ReaderFragment = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "NavUser_viewer", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fullName", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "email", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null +}; + +(node as any).hash = "7ee85a272f543b514c5a6a3148fd1613"; + +export default node; diff --git a/apps/console/src/components/__generated__/TeamSwitcher_organizations.graphql.ts b/apps/console/src/components/__generated__/TeamSwitcher_organizations.graphql.ts new file mode 100644 index 000000000..451419ebf --- /dev/null +++ b/apps/console/src/components/__generated__/TeamSwitcher_organizations.graphql.ts @@ -0,0 +1,71 @@ +/** + * @generated SignedSource<<8ecb9304d0a498d483d1a8c251f8c49a>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type TeamSwitcher_organizations$data = { + readonly organizations: ReadonlyArray<{ + readonly id: string; + readonly logoUrl: string; + readonly name: string; + }>; + readonly " $fragmentType": "TeamSwitcher_organizations"; +}; +export type TeamSwitcher_organizations$key = { + readonly " $data"?: TeamSwitcher_organizations$data; + readonly " $fragmentSpreads": FragmentRefs<"TeamSwitcher_organizations">; +}; + +const node: ReaderFragment = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "TeamSwitcher_organizations", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Organization", + "kind": "LinkedField", + "name": "organizations", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "logoUrl", + "storageKey": null + } + ], + "storageKey": null + } + ], + "type": "User", + "abstractKey": null +}; + +(node as any).hash = "318f68b82b5b87500ec99ffcdd2929ab"; + +export default node; diff --git a/apps/console/src/contexts/AuthContext.tsx b/apps/console/src/contexts/AuthContext.tsx index aa44880e1..65268f08e 100644 --- a/apps/console/src/contexts/AuthContext.tsx +++ b/apps/console/src/contexts/AuthContext.tsx @@ -9,6 +9,8 @@ interface AuthContextType { logout: () => Promise; } +// TODO: should be remove when backend returns proper authenticated error + const AuthContext = createContext(undefined); export function AuthProvider({ children }: { children: React.ReactNode }) { diff --git a/apps/console/src/contexts/OrganizationContext.tsx b/apps/console/src/contexts/OrganizationContext.tsx new file mode 100644 index 000000000..bb0c1fa7e --- /dev/null +++ b/apps/console/src/contexts/OrganizationContext.tsx @@ -0,0 +1,43 @@ +import React, { createContext, useContext, useState, ReactNode } from "react"; + +interface Organization { + id: string; + name: string; + logoUrl: string; +} + +interface OrganizationContextType { + currentOrganization: Organization | null; + setCurrentOrganization: (organization: Organization) => void; +} + +const OrganizationContext = createContext( + undefined +); + +export function useOrganization() { + const context = useContext(OrganizationContext); + if (context === undefined) { + throw new Error( + "useOrganization must be used within an OrganizationProvider" + ); + } + return context; +} + +interface OrganizationProviderProps { + children: ReactNode; +} + +export function OrganizationProvider({ children }: OrganizationProviderProps) { + const [currentOrganization, setCurrentOrganization] = + useState(null); + + return ( + + {children} + + ); +} diff --git a/apps/console/src/pages/CreatePeoplePage.tsx b/apps/console/src/pages/CreatePeoplePage.tsx index fe508d264..06195281b 100644 --- a/apps/console/src/pages/CreatePeoplePage.tsx +++ b/apps/console/src/pages/CreatePeoplePage.tsx @@ -24,8 +24,7 @@ const createPeoplePageQuery = graphql` query CreatePeoplePageQuery { viewer { id - - organization { + organizations { id name } diff --git a/apps/console/src/pages/FrameworkListPage.tsx b/apps/console/src/pages/FrameworkListPage.tsx index e0aa7c913..06aa40585 100644 --- a/apps/console/src/pages/FrameworkListPage.tsx +++ b/apps/console/src/pages/FrameworkListPage.tsx @@ -9,12 +9,12 @@ import { Card, CardContent } from "@/components/ui/card"; import { Link } from "react-router"; import type { FrameworkListPageQuery as FrameworkListPageQueryType } from "./__generated__/FrameworkListPageQuery.graphql"; import { Helmet } from "react-helmet-async"; +import { useOrganization } from "@/contexts/OrganizationContext"; const FrameworkListPageQuery = graphql` - query FrameworkListPageQuery { - viewer { - id - organization { + query FrameworkListPageQuery($organizationId: ID!) { + organization: node(id: $organizationId) { + ... on Organization { frameworks { edges { node { @@ -87,7 +87,7 @@ function FrameworkListPageContent({ }) { const data = usePreloadedQuery(FrameworkListPageQuery, queryRef); const frameworks = - data.viewer.organization.frameworks?.edges.map((edge) => edge?.node) ?? []; + data.organization.frameworks?.edges.map((edge) => edge?.node) ?? []; return (
@@ -164,9 +164,11 @@ export default function FrameworkListPage() { FrameworkListPageQuery ); + const { currentOrganization } = useOrganization(); + useEffect(() => { - loadQuery({}); - }, [loadQuery]); + loadQuery({ organizationId: currentOrganization!.id }); + }, [loadQuery, currentOrganization]); return ( <> diff --git a/apps/console/src/pages/HomePage.tsx b/apps/console/src/pages/HomePage.tsx index bd3e558d5..69819d0bb 100644 --- a/apps/console/src/pages/HomePage.tsx +++ b/apps/console/src/pages/HomePage.tsx @@ -12,7 +12,7 @@ export const HomePageQuery = graphql` query HomePageQuery { viewer { id - organization { + organizations { name createdAt updatedAt diff --git a/apps/console/src/pages/PeopleListPage.tsx b/apps/console/src/pages/PeopleListPage.tsx index 2da4efc33..6881dae94 100644 --- a/apps/console/src/pages/PeopleListPage.tsx +++ b/apps/console/src/pages/PeopleListPage.tsx @@ -18,28 +18,34 @@ import type { PeopleListPageQuery as PeopleListPageQueryType } from "./__generat import type { PeopleListPageDeletePeopleMutation } from "./__generated__/PeopleListPageDeletePeopleMutation.graphql"; import { PeopleListPagePaginationQuery } from "./__generated__/PeopleListPagePaginationQuery.graphql"; import { PeopleListPage_peoples$key } from "./__generated__/PeopleListPage_peoples.graphql"; +import { useOrganization } from "@/contexts/OrganizationContext"; const ITEMS_PER_PAGE = 25; const peopleListPageQuery = graphql` query PeopleListPageQuery( + $organizationId: ID! $first: Int $after: CursorKey $last: Int $before: CursorKey ) { - viewer { - id - organization { - ...PeopleListPage_peoples - } + organization: node(id: $organizationId) { + ...PeopleListPage_peoples + @arguments(first: $first, after: $after, last: $last, before: $before) } } `; const peopleListFragment = graphql` fragment PeopleListPage_peoples on Organization - @refetchable(queryName: "PeopleListPagePaginationQuery") { + @refetchable(queryName: "PeopleListPagePaginationQuery") + @argumentDefinitions( + first: { type: "Int" } + after: { type: "CursorKey" } + last: { type: "Int" } + before: { type: "CursorKey" } + ) { id peoples(first: $first, after: $after, last: $last, before: $before) @connection(key: "PeopleListPage_peoples") { @@ -147,7 +153,7 @@ function PeopleListContent({ } = usePaginationFragment< PeopleListPagePaginationQuery, PeopleListPage_peoples$key - >(peopleListFragment, data.viewer.organization); + >(peopleListFragment, data.organization); const peoples = peoplesConnection.peoples.edges.map((edge) => edge.node) ?? []; @@ -301,17 +307,20 @@ export default function PeopleListPage() { const [queryRef, loadQuery] = useQueryLoader(peopleListPageQuery); + const { currentOrganization } = useOrganization(); + useEffect(() => { const after = searchParams.get("after"); const before = searchParams.get("before"); loadQuery({ + organizationId: currentOrganization!.id, first: before ? undefined : ITEMS_PER_PAGE, after: after || undefined, last: before ? ITEMS_PER_PAGE : undefined, before: before || undefined, }); - }, [loadQuery]); + }, [loadQuery, currentOrganization]); if (!queryRef) { return ; diff --git a/apps/console/src/pages/SettingsPage.tsx b/apps/console/src/pages/SettingsPage.tsx index edf7d0d2a..048c71ef9 100644 --- a/apps/console/src/pages/SettingsPage.tsx +++ b/apps/console/src/pages/SettingsPage.tsx @@ -28,7 +28,7 @@ const settingsPageQuery = graphql` query SettingsPageQuery { viewer { id - organization { + organizations { name logoUrl } @@ -49,7 +49,7 @@ function SettingsPageContent({ queryRef: PreloadedQuery; }) { const data = usePreloadedQuery(settingsPageQuery, queryRef); - const organization = data.viewer.organization; + const organization = data.viewer.organizations[0]; const members: Member[] = []; return ( diff --git a/apps/console/src/pages/VendorListPage.tsx b/apps/console/src/pages/VendorListPage.tsx index 26eeaa95a..371140bf1 100644 --- a/apps/console/src/pages/VendorListPage.tsx +++ b/apps/console/src/pages/VendorListPage.tsx @@ -22,28 +22,35 @@ import { VendorListPageDeleteVendorMutation } from "./__generated__/VendorListPa import { toast } from "@/hooks/use-toast"; import { VendorListPagePaginationQuery } from "./__generated__/VendorListPagePaginationQuery.graphql"; import { VendorListPage_vendors$key } from "./__generated__/VendorListPage_vendors.graphql"; +import { useToast } from "@/hooks/use-toast"; +import { useOrganization } from "@/contexts/OrganizationContext"; const ITEMS_PER_PAGE = 25; const vendorListPageQuery = graphql` query VendorListPageQuery( + $organizationId: ID! $first: Int $after: CursorKey $last: Int $before: CursorKey ) { - viewer { - id - organization { - ...VendorListPage_vendors - } + organization: node(id: $organizationId) { + ...VendorListPage_vendors + @arguments(first: $first, after: $after, last: $last, before: $before) } } `; const vendorListFragment = graphql` fragment VendorListPage_vendors on Organization - @refetchable(queryName: "VendorListPagePaginationQuery") { + @refetchable(queryName: "VendorListPagePaginationQuery") + @argumentDefinitions( + first: { type: "Int" } + after: { type: "CursorKey" } + last: { type: "Int" } + before: { type: "CursorKey" } + ) { id vendors(first: $first, after: $after, last: $last, before: $before) @connection(key: "VendorListPage_vendors") { @@ -96,8 +103,15 @@ const deleteVendorMutation = graphql` } `; +// Define a proper type for the vendor items +interface VendorItem { + id: string; + name: string; + createdAt: string; +} + // TODO: Remove this once we have a real list of vendors -const vendorsList = [ +const vendorsList: VendorItem[] = [ { id: "1", name: "Amazon Web Services", createdAt: new Date().toISOString() }, { id: "2", @@ -172,6 +186,7 @@ function VendorListContent({ }: { queryRef: PreloadedQuery; }) { + const { toast } = useToast(); const data = usePreloadedQuery( vendorListPageQuery, queryRef @@ -179,7 +194,7 @@ function VendorListContent({ const [searchParams, setSearchParams] = useSearchParams(); const [isPending, startTransition] = useTransition(); const [searchTerm, setSearchTerm] = useState(""); - const [filteredVendors, setFilteredVendors] = useState>([]); + const [filteredVendors, setFilteredVendors] = useState([]); const [createVendor] = useMutation(createVendorMutation); const [deleteVendor] = @@ -196,7 +211,7 @@ function VendorListContent({ } = usePaginationFragment< VendorListPagePaginationQuery, VendorListPage_vendors$key - >(vendorListFragment, data.viewer.organization); + >(vendorListFragment, data.organization); const vendors = vendorsConnection.vendors.edges.map((edge) => edge.node) ?? []; @@ -245,7 +260,7 @@ function VendorListContent({ style={{ borderRadius: "0.3rem" }} className="absolute top-full left-0 mt-1 w-[calc(100%-100px)] max-h-48 overflow-y-auto border bg-popover shadow-md z-10" > - {filteredVendors.map((vendor) => ( + {filteredVendors.map((vendor: VendorItem) => (