diff --git a/apps/web-dashboard/package.json b/apps/web-dashboard/package.json index 939208a..8a318d0 100644 --- a/apps/web-dashboard/package.json +++ b/apps/web-dashboard/package.json @@ -12,8 +12,10 @@ "test:coverage": "jest --coverage" }, "dependencies": { + "@apollo/client": "^4.1.9", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "graphql": "^16.10.0", "lucide-react": "^1.7.0", "next": "16.2.2", "radix-ui": "^1.4.3", diff --git a/apps/web-dashboard/pnpm-lock.yaml b/apps/web-dashboard/pnpm-lock.yaml index 93d7c58..9b3dd12 100644 --- a/apps/web-dashboard/pnpm-lock.yaml +++ b/apps/web-dashboard/pnpm-lock.yaml @@ -8,12 +8,18 @@ importers: .: dependencies: + '@apollo/client': + specifier: ^4.1.9 + version: 4.1.9(graphql@16.13.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rxjs@7.8.2) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 clsx: specifier: ^2.1.1 version: 2.1.1 + graphql: + specifier: ^16.10.0 + version: 16.13.2 lucide-react: specifier: ^1.7.0 version: 1.7.0(react@19.2.4) @@ -91,6 +97,25 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@apollo/client@4.1.9': + resolution: {integrity: sha512-qfpkQD51tdU/7iAR6aLb4w9o/L7I475DluWHRb61U/3Q0AH29nNOxOBHjBbWDdf16ncPOoQuxne1sEs2NjqBFw==} + peerDependencies: + graphql: ^16.0.0 + graphql-ws: ^5.5.5 || ^6.0.3 + react: ^17.0.0 || ^18.0.0 || >=19.0.0-rc + react-dom: ^17.0.0 || ^18.0.0 || >=19.0.0-rc + rxjs: ^7.3.0 + subscriptions-transport-ws: ^0.9.0 || ^0.11.0 + peerDependenciesMeta: + graphql-ws: + optional: true + react: + optional: true + react-dom: + optional: true + subscriptions-transport-ws: + optional: true + '@babel/code-frame@7.29.0': resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} @@ -378,6 +403,11 @@ packages: '@floating-ui/utils@0.2.11': resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + '@graphql-typed-document-node/core@3.2.0': + resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==} + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + '@hono/node-server@1.19.12': resolution: {integrity: sha512-txsUW4SQ1iilgE0l9/e9VQWmELXifEFvmdA1j6WFh/aFPj99hIntrSsq/if0UWyGVkmrRPKA1wCeP+UCr1B9Uw==} engines: {node: '>=18.14.1'} @@ -1831,6 +1861,22 @@ packages: cpu: [x64] os: [win32] + '@wry/caches@1.0.1': + resolution: {integrity: sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA==} + engines: {node: '>=8'} + + '@wry/context@0.7.4': + resolution: {integrity: sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ==} + engines: {node: '>=8'} + + '@wry/equality@0.5.7': + resolution: {integrity: sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw==} + engines: {node: '>=8'} + + '@wry/trie@0.5.0': + resolution: {integrity: sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA==} + engines: {node: '>=8'} + abab@2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} deprecated: Use your platform's native atob() and btoa() methods instead @@ -2807,6 +2853,12 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + graphql-tag@2.12.6: + resolution: {integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==} + engines: {node: '>=10'} + peerDependencies: + graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + graphql@16.13.2: resolution: {integrity: sha512-5bJ+nf/UCpAjHM8i06fl7eLyVC9iuNAjm9qzkiu2ZGhM0VscSvS6WDPfAwkdkBuoXGM9FJSbKl6wylMwP9Ktig==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} @@ -3702,6 +3754,9 @@ packages: resolution: {integrity: sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==} engines: {node: '>=20'} + optimism@0.18.1: + resolution: {integrity: sha512-mLXNwWPa9dgFyDqkNi54sjDyNJ9/fTI6WGBLgnXku1vdKY/jovHfZT5r+aiVeFFLOz+foPNOm5YJ4mqgld2GBQ==} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -4021,6 +4076,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + safe-array-concat@1.1.3: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} @@ -4608,6 +4666,21 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@apollo/client@4.1.9(graphql@16.13.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rxjs@7.8.2)': + dependencies: + '@graphql-typed-document-node/core': 3.2.0(graphql@16.13.2) + '@wry/caches': 1.0.1 + '@wry/equality': 0.5.7 + '@wry/trie': 0.5.0 + graphql: 16.13.2 + graphql-tag: 2.12.6(graphql@16.13.2) + optimism: 0.18.1 + rxjs: 7.8.2 + tslib: 2.8.1 + optionalDependencies: + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -4968,6 +5041,10 @@ snapshots: '@floating-ui/utils@0.2.11': {} + '@graphql-typed-document-node/core@3.2.0(graphql@16.13.2)': + dependencies: + graphql: 16.13.2 + '@hono/node-server@1.19.12(hono@4.12.10)': dependencies: hono: 4.12.10 @@ -6515,6 +6592,22 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true + '@wry/caches@1.0.1': + dependencies: + tslib: 2.8.1 + + '@wry/context@0.7.4': + dependencies: + tslib: 2.8.1 + + '@wry/equality@0.5.7': + dependencies: + tslib: 2.8.1 + + '@wry/trie@0.5.0': + dependencies: + tslib: 2.8.1 + abab@2.0.6: {} accepts@2.0.0: @@ -7714,6 +7807,11 @@ snapshots: graceful-fs@4.2.11: {} + graphql-tag@2.12.6(graphql@16.13.2): + dependencies: + graphql: 16.13.2 + tslib: 2.8.1 + graphql@16.13.2: {} has-bigints@1.1.0: {} @@ -8771,6 +8869,13 @@ snapshots: powershell-utils: 0.1.0 wsl-utils: 0.3.1 + optimism@0.18.1: + dependencies: + '@wry/caches': 1.0.1 + '@wry/context': 0.7.4 + '@wry/trie': 0.5.0 + tslib: 2.8.1 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -9142,6 +9247,10 @@ snapshots: dependencies: queue-microtask: 1.2.3 + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + safe-array-concat@1.1.3: dependencies: call-bind: 1.0.8 diff --git a/apps/web-dashboard/src/app/layout.tsx b/apps/web-dashboard/src/app/layout.tsx index 24fb2f7..01dcac4 100644 --- a/apps/web-dashboard/src/app/layout.tsx +++ b/apps/web-dashboard/src/app/layout.tsx @@ -3,6 +3,7 @@ import { Geist, Geist_Mono, Inter } from "next/font/google"; import "./globals.css"; import { cn } from "@/lib/utils"; import { Sidebar } from "@/components/sidebar"; +import { Providers } from "./providers"; const inter = Inter({ subsets: ["latin"], variable: "--font-sans" }); @@ -32,8 +33,10 @@ export default function RootLayout({ className={cn("h-full", "antialiased", geistSans.variable, geistMono.variable, "font-sans", inter.variable)} > - -
{children}
+ + +
{children}
+
); diff --git a/apps/web-dashboard/src/app/providers.tsx b/apps/web-dashboard/src/app/providers.tsx new file mode 100644 index 0000000..43b8b3e --- /dev/null +++ b/apps/web-dashboard/src/app/providers.tsx @@ -0,0 +1,8 @@ +'use client'; + +import { ApolloProvider } from '@apollo/client'; +import { apolloClient } from '@/lib/apollo-client'; + +export function Providers({ children }: { children: React.ReactNode }) { + return {children}; +} diff --git a/apps/web-dashboard/src/lib/apollo-client.ts b/apps/web-dashboard/src/lib/apollo-client.ts new file mode 100644 index 0000000..513fa3a --- /dev/null +++ b/apps/web-dashboard/src/lib/apollo-client.ts @@ -0,0 +1,54 @@ +import { ApolloClient, InMemoryCache, createHttpLink, from } from '@apollo/client'; +import { setContext } from '@apollo/client/link/context'; + +// GraphQL API endpoint +const httpLink = createHttpLink({ + uri: process.env.NEXT_PUBLIC_API_SERVER_URL || 'http://localhost:8080/v1/graphql', +}); + +// Auth link to add authentication token to requests +const authLink = setContext((_, { headers }) => { + // Get the authentication token from local storage if it exists + const token = localStorage.getItem('auth_token'); + + return { + headers: { + ...headers, + authorization: token ? `Bearer ${token}` : '', + }, + }; +}); + +// Create Apollo Client instance +export const apolloClient = new ApolloClient({ + link: from([authLink, httpLink]), + cache: new InMemoryCache(), + defaultOptions: { + watchQuery: { + fetchPolicy: 'cache-and-network', + }, + query: { + fetchPolicy: 'network-only', + }, + mutate: { + fetchPolicy: 'network-only', + }, + }, +}); + +// GraphQL queries and mutations can be defined here +// Example: +/* +import { gql } from '@apollo/client'; + +export const GET_SERVICES = gql` + query GetServices { + services { + id + name + status + health + } + } +`; +*/