app-ui
created pr with
46.1
cmds
checkout latest patchset:
ssh pr.pico.sh print 46 | git am -3checkout any patchset in a patch request:
ssh pr.pico.sh print 46.[rev] | git am -3add changes to patch request:
git format-patch main --stdout | ssh pr.pico.sh pr add 46
Patchset
46.1
Install react-use-websocket
Eric Abruzzese
Update the diagnostics create form to navigate to the details page with query parameters instead of POSTing to the external service
2025-01-15T14:28:15ZEric Abruzzese
Collect events on the diagnostic details page and construct a dashboard state
2025-01-15T14:29:34ZEric Abruzzese
→ Formatting and cleanup
2025-01-15T14:30:03ZEric Abruzzese
Show dashboard messages, resources, operations, and plots
2025-01-15T14:34:02ZMichael Peterson
Support async plot annotations
2025-01-28T20:23:45ZEric Abruzzese
Fix an issue that would cause a page crash if datasets weren't perfectly aligned
2025-01-31T17:53:30ZEric Abruzzese
Add VITE_APTIBLE_AI_URL to .env.example
2025-02-03T20:19:05ZEric Abruzzese
Update VITE_APTIBLE_AI_URL references to point to Hotshot
2025-02-04T16:30:13ZEric Abruzzese
Update the analysis using PlotAnnotated events
2025-02-05T17:50:02ZEric Abruzzese
Install react-use-websocket
2025-02-05T17:51:11ZEric Abruzzese
Update the diagnostics create form to navigate to the details page with query parameters instead of POSTing to the external service
2025-01-15T14:28:15ZEric Abruzzese
Collect events on the diagnostic details page and construct a dashboard state
2025-01-15T14:29:34ZEric Abruzzese
Formatting and cleanup
2025-01-15T14:30:03ZEric Abruzzese
Show dashboard messages, resources, operations, and plots
2025-01-15T14:34:02ZMichael Peterson
Support async plot annotations
2025-01-28T20:23:45ZEric Abruzzese
Fix an issue that would cause a page crash if datasets weren't perfectly aligned
2025-01-31T17:53:30ZEric Abruzzese
Add VITE_APTIBLE_AI_URL to .env.example
2025-02-03T20:19:05ZEric Abruzzese
Update VITE_APTIBLE_AI_URL references to point to Hotshot
2025-02-04T16:30:13ZEric Abruzzese
Update the analysis using PlotAnnotated events
2025-02-05T17:50:02ZEric Abruzzese
Refactor charts
2025-02-05T17:51:11ZMichael Peterson
Refactor OperationsTimeline, chart hover state
2025-02-05T18:25:59ZMichael Peterson
Extract types into aptible-ai/index, useDashboard hook
2025-02-05T18:42:20ZMichael Peterson
Fix a linter error
2025-02-05T19:21:56ZEric Abruzzese
Fix linter errors
2025-02-05T19:40:48ZEric Abruzzese
2025-02-05T19:50:07Z
Formatting and cleanup
Eric Abruzzese
2025-01-15T14:34:02ZSemantic diff summary
0 added,
11 modified,
0 signature changed,
0 removed
across 3 analyzed files
+7
-1
src/routes/index.ts
#
| ... | ... | @@ -409,7 +409,13 @@ export const diagnosticsUrl = () => DIAGNOSTICS_URL; | |
| 409 | 409 | export const DIAGNOSTICS_CREATE_URL = "/diagnostics/create"; | |
| 410 | 410 | export const diagnosticsCreateUrl = () => DIAGNOSTICS_CREATE_URL; | |
| 411 | 411 | export const DIAGNOSTICS_DETAIL_URL = "/diagnostics/detail"; | |
| 412 | - | export const diagnosticsDetailUrl = (appId: string, symptoms: string, start: Date, end: Date) => `/diagnostics/detail?app_id=${appId}&symptom_description=${symptoms}&start_time=${start.toISOString()}&end_time=${end.toISOString()}`; | |
| 412 | + | export const diagnosticsDetailUrl = ( | |
| 413 | + | appId: string, | |
| 414 | + | symptoms: string, | |
| 415 | + | start: Date, | |
| 416 | + | end: Date, | |
| 417 | + | ) => | |
| 418 | + | `/diagnostics/detail?appId=${appId}&symptomDescription=${symptoms}&startTime=${start.toISOString()}&endTime=${end.toISOString()}`; | |
| 413 | 419 | ||
| 414 | 420 | export const SOURCES_PATH = "/sources"; | |
| 415 | 421 | export const sourcesUrl = () => SOURCES_PATH; |
+5
-5
src/ui/pages/diagnostics-create.tsx
#
| ... | ... | @@ -55,7 +55,7 @@ export const DiagnosticsCreateForm = ({ appId }: { appId: string }) => { | |
| 55 | 55 | const [timePreset, setTimePreset] = useState(timePresets[2].value); | |
| 56 | 56 | ||
| 57 | 57 | const [startDate, setStartDate] = useState<DateTime>( | |
| 58 | - | DateTime.fromISO(timePreset) | |
| 58 | + | DateTime.fromISO(timePreset), | |
| 59 | 59 | ); | |
| 60 | 60 | const onSelectStartDate = (date: Date) => { | |
| 61 | 61 | const dateTime = DateTime.fromJSDate(date); |
| ... | ... | @@ -95,7 +95,7 @@ export const DiagnosticsCreateForm = ({ appId }: { appId: string }) => { | |
| 95 | 95 | startDate !== null && | |
| 96 | 96 | endDate !== null && | |
| 97 | 97 | startDate < endDate, | |
| 98 | - | [symptoms, appId, startDate, endDate] | |
| 98 | + | [symptoms, appId, startDate, endDate], | |
| 99 | 99 | ); | |
| 100 | 100 | ||
| 101 | 101 | // Submit the form. |
| ... | ... | @@ -109,8 +109,8 @@ export const DiagnosticsCreateForm = ({ appId }: { appId: string }) => { | |
| 109 | 109 | appId, | |
| 110 | 110 | symptoms, | |
| 111 | 111 | startDate.toUTC(0, { keepLocalTime: true }).toJSDate(), | |
| 112 | - | endDate.toUTC(0, { keepLocalTime: true }).toJSDate() | |
| 113 | - | ) | |
| 112 | + | endDate.toUTC(0, { keepLocalTime: true }).toJSDate(), | |
| 113 | + | ), | |
| 114 | 114 | ); | |
| 115 | 115 | setIsLoading(false); | |
| 116 | 116 | }; |
+19
-19
src/ui/pages/diagnostics-detail.tsx
#
| ... | ... | @@ -3,10 +3,10 @@ import { useSelector } from "@app/react"; | |
| 3 | 3 | import { diagnosticsCreateUrl } from "@app/routes"; | |
| 4 | 4 | import { selectAccessToken } from "@app/token"; | |
| 5 | 5 | import { useEffect, useState } from "react"; | |
| 6 | - | import { Link, useSearchParams } from "react-router-dom"; | |
| 6 | + | import { Link, useParams, useSearchParams } from "react-router-dom"; | |
| 7 | + | import useWebSocket, { ReadyState } from "react-use-websocket"; | |
| 7 | 8 | import { AppSidebarLayout } from "../layouts"; | |
| 8 | 9 | import { Breadcrumbs, PreText } from "../shared"; | |
| 9 | - | import useWebSocket, { ReadyState } from "react-use-websocket"; | |
| 10 | 10 | ||
| 11 | 11 | type Message = { | |
| 12 | 12 | id: string; |
| ... | ... | @@ -17,13 +17,13 @@ type Message = { | |
| 17 | 17 | type Operation = { | |
| 18 | 18 | id: number; | |
| 19 | 19 | status: string; | |
| 20 | - | created_at: Date; | |
| 20 | + | created_at: string; | |
| 21 | 21 | description: string; | |
| 22 | 22 | log_lines: string[]; | |
| 23 | 23 | }; | |
| 24 | 24 | ||
| 25 | 25 | type Point = { | |
| 26 | - | timestamp: Date; | |
| 26 | + | timestamp: string; | |
| 27 | 27 | value: number; | |
| 28 | 28 | }; | |
| 29 | 29 |
| ... | ... | @@ -72,31 +72,27 @@ type Dashboard = { | |
| 72 | 72 | messages: Message[]; | |
| 73 | 73 | }; | |
| 74 | 74 | ||
| 75 | - | ||
| 76 | 75 | export const DiagnosticsDetailPage = () => { | |
| 77 | 76 | // Parse the investigation parameters from the query string. | |
| 78 | 77 | const [searchParams, setSearchParams] = useSearchParams(); | |
| 79 | 78 | const accessToken = useSelector(selectAccessToken); | |
| 80 | - | const appId = searchParams.get("app_id"); | |
| 81 | - | const symptomDescription = searchParams.get("symptom_description"); | |
| 82 | - | const startTime = searchParams.get("start_time"); | |
| 83 | - | const endTime = searchParams.get("end_time"); | |
| 79 | + | const appId = searchParams.get("appId"); | |
| 80 | + | const symptomDescription = searchParams.get("symptomDescription"); | |
| 81 | + | const startTime = searchParams.get("startTime"); | |
| 82 | + | const endTime = searchParams.get("endTime"); | |
| 84 | 83 | ||
| 85 | 84 | // If any of the parameters are missing, display an error message with a link | |
| 86 | 85 | // to the diagnostics create page. | |
| 87 | 86 | if (!appId || !symptomDescription || !startTime || !endTime) { | |
| 88 | - | return ( | |
| 89 | - | <div> | |
| 90 | - | <p>Error: Missing parameters</p> | |
| 91 | - | <Link to={diagnosticsCreateUrl()}>Go back to diagnostics page</Link> | |
| 92 | - | </div> | |
| 93 | - | ); | |
| 87 | + | throw new Error("Missing parameters"); | |
| 94 | 88 | } | |
| 95 | 89 | ||
| 96 | 90 | // Connect to the Aptible AI WebSocket. | |
| 97 | 91 | const aptibleAiUrl = useSelector(selectAptibleAiUrl); | |
| 98 | 92 | const [socketConnected, setSocketConnected] = useState(true); | |
| 99 | - | const { lastJsonMessage: event, readyState } = useWebSocket<Record<string, any>>( | |
| 93 | + | const { lastJsonMessage: event, readyState } = useWebSocket< | |
| 94 | + | Record<string, any> | |
| 95 | + | >( | |
| 100 | 96 | `${aptibleAiUrl}/troubleshoot`, | |
| 101 | 97 | { | |
| 102 | 98 | queryParams: { |
| ... | ... | @@ -105,9 +101,9 @@ export const DiagnosticsDetailPage = () => { | |
| 105 | 101 | symptom_description: symptomDescription, | |
| 106 | 102 | start_time: startTime, | |
| 107 | 103 | end_time: endTime, | |
| 108 | - | } | |
| 104 | + | }, | |
| 109 | 105 | }, | |
| 110 | - | socketConnected | |
| 106 | + | socketConnected, | |
| 111 | 107 | ); | |
| 112 | 108 | ||
| 113 | 109 | // If the socket is closed, set the socketConnected state to false (this is |
| ... | ... | @@ -204,7 +200,11 @@ export const DiagnosticsDetailPage = () => { | |
| 204 | 200 | /> | |
| 205 | 201 | ||
| 206 | 202 | <div className="flex flex-row items-center justify-center flex-1 min-h-[500px]"> | |
| 207 | - | <PreText className="max-w-7xl overflow-x-auto overflow-y-auto" text={JSON.stringify(dashboard, null, 2)} allowCopy /> | |
| 203 | + | <PreText | |
| 204 | + | className="max-w-7xl overflow-x-auto overflow-y-auto" | |
| 205 | + | text={JSON.stringify(dashboard, null, 2)} | |
| 206 | + | allowCopy | |
| 207 | + | /> | |
| 208 | 208 | </div> | |
| 209 | 209 | </AppSidebarLayout> | |
| 210 | 210 | ); |