-
Notifications
You must be signed in to change notification settings - Fork 292
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pipipi #3087
Pipipi #3087
Changes from all commits
ae04eb7
97afdd5
85d3a6d
4c43237
b53ceef
5c0618d
84078ac
099bbf4
f98e082
28f4cb4
9540488
26fe125
03cb439
c6cb6d5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,30 +6,51 @@ import { useRouter } from "next/navigation"; | |
import { Suspense } from "react"; | ||
import { useHeliconeLogin } from "./../useHeliconeLogin"; | ||
import { useTestAPIKey } from "./useTestApiKey"; | ||
import { useQuery } from "@tanstack/react-query"; | ||
|
||
const jetbrainsMono = JetBrains_Mono({ subsets: ["latin"] }); | ||
|
||
const FirstPageContent = () => { | ||
const jawn = useJawnClient(); | ||
const { apiKey, sessionUUID } = useHeliconeLogin(); | ||
const { data, isLoading } = useTestAPIKey(apiKey.data ?? ""); | ||
const jawn = useJawnClient(apiKey.data ?? ""); | ||
const router = useRouter(); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: all three useQuery hooks should include enabled: !!apiKey.data to prevent unnecessary API calls when apiKey is not available |
||
if ((!data && !isLoading) || !apiKey.data) { | ||
router.push("/pi/total-requests"); | ||
const orgName = useQuery({ | ||
queryKey: ["org-name", apiKey.data], | ||
queryFn: () => jawn.POST("/v1/pi/org-name/query"), | ||
}); | ||
|
||
const totalCosts = useQuery({ | ||
queryKey: ["total-costs", apiKey.data], | ||
queryFn: () => jawn.POST("/v1/pi/total-costs"), | ||
}); | ||
|
||
const costsOverTime = useQuery({ | ||
queryKey: ["costs-over-time", apiKey.data], | ||
queryFn: () => | ||
jawn.POST("/v1/pi/costs-over-time/query", { | ||
body: { | ||
userFilter: "all", | ||
dbIncrement: "day", | ||
timeZoneDifference: new Date().getTimezoneOffset(), | ||
timeFilter: { | ||
start: new Date( | ||
Date.now() - 30 * 24 * 60 * 60 * 1000 | ||
).toISOString(), | ||
end: new Date().toISOString(), | ||
}, | ||
}, | ||
}), | ||
}); | ||
|
||
if (!data && !isLoading && !apiKey.data && !apiKey.isLoading) { | ||
router.push("/pi/setup?invalid_api_key=true"); | ||
Comment on lines
+46
to
49
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: showing Loading... while redirecting may cause UI flicker - consider removing the loading message since the redirect happens immediately |
||
return <div>Loading...</div>; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: returning an empty div after fetching data is likely unintentional - component should render fetched data or loading states |
||
|
||
return ( | ||
<div className="w-full flex flex-col justify-center items-center h-[100vh]"> | ||
<h1 | ||
className={`text-3xl font-extrabold truncate max-w-[80vw] ${jetbrainsMono.className} py-2`} | ||
> | ||
LOGGED IN! WOOOHOO | ||
</h1> | ||
{data && JSON.stringify(data).slice(0, 100)} | ||
</div> | ||
); | ||
return <div></div>; | ||
}; | ||
|
||
const PiPage = () => { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,16 +13,16 @@ const jetbrainsMono = JetBrains_Mono({ subsets: ["latin"] }); | |
|
||
const PiPageContent = () => { | ||
return ( | ||
<div className="w-full flex flex-col justify-center items-center h-[100vh]"> | ||
<h1 | ||
className={`text-3xl font-extrabold truncate max-w-[80vw] ${jetbrainsMono.className} py-2`} | ||
> | ||
<div | ||
className={`w-full flex flex-col justify-center items-center h-[100vh] ${jetbrainsMono.className}`} | ||
> | ||
<h1 className={`text-3xl font-extrabold truncate max-w-[80vw] py-2`}> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. syntax: extra space before py-2 in className string |
||
Welcome to Helicone! | ||
</h1> | ||
|
||
<div className="relative h-[80vh]"> | ||
<Image | ||
src="/static/pi/intro-image.png" | ||
src="/static/pi/intro-image.webp" | ||
alt="Helicone Logo" | ||
width={460} | ||
height={360} | ||
|
@@ -31,7 +31,7 @@ const PiPageContent = () => { | |
|
||
<Link | ||
href="/pi/setup" | ||
className=" bg-blue-500 p-5 bg-opacity-60 absolute top-1/2 left-1/2 transform translate-x-[30px] -translate-y-[110px] text-white font-bold" | ||
className="p-5 border-2 absolute top-1/2 left-1/2 transform translate-x-[16px] -translate-y-[90px] text-black font-bold h-[36.17px] px-[12.17px] py-[6.08px] origin-top-left -rotate-1 bg-white border-l-2 border-r-4 border-t-2 border-b-4 border-black flex-col justify-start items-start gap-[10.14px] inline-flex" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. syntax: extra space after border-2 in className string There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: height and padding values conflict - h-[36.17px] with p-5 will make element taller than specified height |
||
> | ||
Start | ||
</Link> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
"use client"; | ||
|
||
import { useRouter } from "next/navigation"; | ||
import { useHeliconeLogin } from "../useHeliconeLogin"; | ||
import Link from "next/link"; | ||
|
||
import { JetBrains_Mono } from "next/font/google"; | ||
import { useTestAPIKey } from "../first_page/useTestApiKey"; | ||
import { useJawnClient } from "@/lib/clients/jawnHook"; | ||
import { useQuery } from "@tanstack/react-query"; | ||
import { | ||
Bar, | ||
BarChart, | ||
CartesianGrid, | ||
ResponsiveContainer, | ||
XAxis, | ||
YAxis, | ||
} from "recharts"; | ||
const jetbrainsMono = JetBrains_Mono({ subsets: ["latin"] }); | ||
|
||
const TotalCost = () => { | ||
const { apiKey } = useHeliconeLogin(); | ||
const { data, isLoading } = useTestAPIKey(apiKey.data ?? ""); | ||
const router = useRouter(); | ||
|
||
const jawn = useJawnClient(apiKey.data ?? ""); | ||
|
||
const totalRequests = useQuery({ | ||
queryKey: ["total-requests", apiKey.data], | ||
queryFn: () => jawn.POST("/v1/pi/total_requests"), | ||
}); | ||
Comment on lines
+28
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: totalRequests is fetched but never used in the component |
||
|
||
const costsOverTime = useQuery({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: no error handling or loading state for costsOverTime query |
||
queryKey: ["costs-over-time", apiKey.data], | ||
queryFn: () => | ||
jawn.POST("/v1/pi/costs-over-time/query", { | ||
body: { | ||
userFilter: "all", | ||
dbIncrement: "day", | ||
timeZoneDifference: new Date().getTimezoneOffset(), | ||
timeFilter: { | ||
start: new Date( | ||
Date.now() - 30 * 24 * 60 * 60 * 1000 | ||
).toISOString(), | ||
end: new Date().toISOString(), | ||
}, | ||
}, | ||
}), | ||
}); | ||
const costsOverTimeData = costsOverTime.data?.data?.data; | ||
|
||
if (!data && !isLoading && !apiKey.data && !apiKey.isLoading) { | ||
router.push("/pi/setup?invalid_api_key=true"); | ||
return null; | ||
} | ||
|
||
return ( | ||
<div | ||
className={`w-full flex flex-col justify-center items-center h-[100vh] p-5 gap-4 ${jetbrainsMono.className}`} | ||
> | ||
<div className="w-full h-[360px] bg-white relative border-2 border-black"> | ||
<div className="p-2.5 bg-white border-2 border-black border-r-4 border-b-4 flex flex-col gap-[3px] absolute top-[22px] left-[18px]"> | ||
<div className="text-[14px] font-medium">Total Cost</div> | ||
<div className="text-[21px] font-extrabold"> | ||
$ | ||
{costsOverTimeData | ||
?.reduce((sum, item) => sum + item.cost, 0) | ||
?.toFixed(2) ?? "0.00"} | ||
</div> | ||
</div> | ||
<div className="px-3 py-1 bg-white border-2 border-black border-r-4 border-b-4 absolute top-[22px] right-[18px] flex gap-3 z-10 items-center"> | ||
<div className="bg-[#E5E5E5] w-[9.14px] h-[9.14px] border-2 border-black border-r-4 border-b-4"></div> | ||
<div className="text-[14px] font-medium leading-tight">costs</div> | ||
</div> | ||
<ResponsiveContainer width="100%" height="100%" className=" m-0 p-0"> | ||
<BarChart data={costsOverTimeData ?? []} className="m-0 p-0"> | ||
<CartesianGrid | ||
vertical={false} | ||
color="#000000" | ||
opacity={0.3} | ||
strokeWidth={1.52} | ||
/> | ||
<XAxis | ||
dataKey="created_at_trunc" | ||
tickFormatter={(value) => | ||
new Date(value).toLocaleDateString(undefined, { | ||
month: "numeric", | ||
day: "numeric", | ||
year: "2-digit", | ||
}) | ||
} | ||
includeHidden | ||
interval={6} | ||
tickSize={14} | ||
padding={{ left: 16, right: 16 }} | ||
tickMargin={8} | ||
fontSize={12} | ||
strokeWidth={1.52} | ||
stroke="#000000" | ||
/> | ||
{/* <YAxis fontSize={12} /> */} | ||
<Bar | ||
dataKey="cost" | ||
fill="#888888" | ||
radius={[0, 0, 0, 0]} | ||
stroke="#000000" // Add black outline | ||
strokeWidth={1.52} // Set outline thickness | ||
/> | ||
</BarChart> | ||
</ResponsiveContainer> | ||
</div> | ||
<div className="flex justify-between items-center w-full"> | ||
<Link href="/pi/total-requests"> | ||
{/* eslint-disable-next-line @next/next/no-img-element */} | ||
<img | ||
src="/static/pi/arrow-left.webp" | ||
alt="arrow-left" | ||
className="w-16 h-16" | ||
/> | ||
</Link> | ||
|
||
<Link href="/pi/total-requests"> | ||
{/* eslint-disable-next-line @next/next/no-img-element */} | ||
<img | ||
src="/static/pi/arrow-right.webp" | ||
alt="arrow-right" | ||
className="w-16 h-16" | ||
/> | ||
</Link> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default TotalCost; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: passing empty string as fallback for apiKey.data could trigger unnecessary API calls - consider adding enabled: !!apiKey.data to useTestAPIKey