Conversation
…o instead of fixed
📝 WalkthroughWalkthroughAdds per-column cell styling support to virtual tables and applies it across table skeletons; introduces a full runtime-logs feature (UI, hooks, TRPC query, ClickHouse integration, and LLM-backed search); adds region flag components; and refactors deployment detail navigation/layout and related UI/formatters. Changes
Sequence DiagramssequenceDiagram
participant User
participant UI as Runtime Logs UI
participant Hooks as Filters & Query Hooks
participant TRPC as TRPC Client
participant Server as Runtime Logs Server
participant CH as ClickHouse
User->>UI: Apply filter / LLM search / open page
UI->>Hooks: updateFilters / trigger search / mount
Hooks->>TRPC: call deploy.runtimeLogs.query (filters, cursor)
TRPC->>Server: validated request
Server->>Server: transformFilters
Server->>CH: SQL queries (logs + total)
CH-->>Server: rows + total
Server-->>TRPC: response (logs, hasMore, nextCursor)
TRPC-->>Hooks: update cache
Hooks->>UI: provide logs and pagination
UI-->>User: render table, load-more, details
sequenceDiagram
participant User
participant UI as LLM Search UI
participant TRPCmut as TRPC Mutation
participant Server as Runtime Logs Server
participant OpenAI as OpenAI API
participant Schema as Filter Schema
User->>UI: Submit natural-language query
UI->>TRPCmut: deploy.runtimeLogs.llmSearch {query, timestamp}
TRPCmut->>Server: validated input
Server->>Server: build system prompt (field/operator docs)
Server->>OpenAI: chat.completions(system+user)
OpenAI-->>Server: JSON response
Server->>Schema: validate against runtimeLogsFilterOutputSchema
Schema-->>Server: validated structured filters
Server-->>TRPCmut: return structured filters
TRPCmut-->>UI: structured result
UI->>Hooks: updateFilters(structured filters)
UI-->>User: show applied filters / results
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Important Action Needed: IP Allowlist UpdateIf your organization protects your Git platform with IP whitelisting, please add the new CodeRabbit IP address to your allowlist:
Reviews will stop working after February 8, 2026 if the new IP is not added to your allowlist. Comment |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
There was a problem hiding this comment.
Actionable comments posted: 18
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (7)
web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/navigations/project-navigation.tsx (1)
118-136:⚠️ Potential issue | 🟡 MinorInconsistent height class between loading and loaded states may cause layout shift.
The loaded Navbar at Line 145 includes
className="h-[65px]", but the loading state Navbar at Line 119 does not. Since the base Navbar component usesmin-h-[65px], the loading state could have a variable height while the loaded state is fixed, potentially causing a visual jump when loading completes.🔧 Proposed fix to add consistent height to loading state
return ( - <Navbar> + <Navbar className="h-[65px]"> <Navbar.Breadcrumbs icon={<Cube />}>Also applies to: 145-145
web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/components/deployment-status-badge.tsx (1)
39-47:⚠️ Potential issue | 🟠 MajorType definition contradicts runtime behavior.
The
statusprop is typed as optional (status?: DeploymentStatus), but the component throws an error whenstatusis falsy. This creates a type/runtime mismatch—callers can legally passundefinedaccording to TypeScript, yet that causes a runtime exception.If
statusis required, remove the?to make this a compile-time error instead of a runtime one. As per coding guidelines: "Make illegal states unrepresentable."🛠️ Proposed fix
type Props = { - status?: DeploymentStatus; + status: DeploymentStatus; className?: string; }; -export const DeploymentStatusBadge = ({ status, className }: Props) => { - if (!status) { - throw new Error(`Invalid deployment status: ${status}`); - } - +export const DeploymentStatusBadge = ({ status, className }: Props) => { const config = STATUS_CONFIG[status];web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/active-deployment-card-logs/hooks/use-deployment-logs.tsx (2)
172-177:⚠️ Potential issue | 🟡 MinorAuto-expand effect may cause unwanted expansion after user collapses.
If a user manually collapses the logs panel, this effect will re-expand it whenever
logs.lengthchanges (e.g., on the next poll). Consider tracking whether the user has manually collapsed to avoid overriding their preference.Possible approach
+ const [userCollapsed, setUserCollapsed] = useState(false); // Auto-expand when logs are available useEffect(() => { - if (logs.length > 0) { + if (logs.length > 0 && !userCollapsed) { setIsExpanded(true); } - }, [logs.length]); + }, [logs.length, userCollapsed]); const setExpanded = (expanded: boolean) => { setIsExpanded(expanded); + if (!expanded) { + setUserCollapsed(true); + } if (!expanded) { setTimeout(resetScroll, SCROLL_RESET_DELAY); } };
50-52:⚠️ Potential issue | 🟠 Major
deploymentIdparameter is accepted but never used.The hook accepts
deploymentIdbut the sentinel query at lines 72-89 doesn't filter by it. ThequeryLogsendpoint doesn't support deployment-level filtering—the input schema (logsRequestSchema) lacks adeploymentIdfield and only supports workspace-level log queries. Either remove the unused parameter or extend the endpoint to support deployment filtering.web/apps/dashboard/lib/trpc/routers/deploy/network/utils.ts (1)
45-55:⚠️ Potential issue | 🟠 MajorRemove
as FlagCodeto comply with type safety guidelines.The
as constmarker on theprefixMapprovides sufficient type information for TypeScript to inferFlagCodecorrectly without an explicit type assertion. The optional chaining (?.[1]) combined with the nullish coalesce operator (?? "us") already returns the correctFlagCodeunion type.♻️ Minimal fix
export function mapRegionToFlag(region: string): FlagCode { const prefixMap = [ ["ap-southeast", "au"], ["ap-northeast", "jp"], ["ap-south", "in"], ["us-", "us"], ["eu-", "de"], ["sa-", "br"], ] as const; - return (prefixMap.find(([prefix]) => region.startsWith(prefix))?.[1] as FlagCode) ?? "us"; + const match = prefixMap.find(([prefix]) => region.startsWith(prefix)); + return match ? match[1] : "us"; }Per coding guidelines: "Never compromise type safety: No
any, no!(non-null assertion), noas Type."web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/(overview)/components/sections/deployment-info-section.tsx (2)
28-75:⚠️ Potential issue | 🟠 MajorGuard DeploymentStatusBadge against undefined status.
DeploymentStatusBadgethrows whenstatusis falsy. If the live query hasn’t resolved yet, this will crash the page. Add a null guard or fallback UI.🛠️ Proposed fix
- statusBadge={<DeploymentStatusBadge status={deploymentStatus} />} + statusBadge={ + deploymentStatus ? <DeploymentStatusBadge status={deploymentStatus} /> : null + }
16-18:⚠️ Potential issue | 🟠 MajorRemove the
as stringassertion and guard against undefined deploymentId.Line 17 uses a type assertion which violates the coding guideline: "Never compromise type safety: No
any, no!, noas Type". This can mask missing params. Use a typeduseParamscall with an explicit guard instead.Additionally,
deploymentStatusmay be undefined during data loading (line 29), which will causeDeploymentStatusBadgeto throw an error (it requires a valid status value). Ensure either the status is always defined before rendering the badge, or the badge component handles the undefined case gracefully.🛠️ Proposed fix
- const params = useParams(); - const deploymentId = params?.deploymentId as string; + const { deploymentId } = useParams<{ deploymentId: string }>(); + if (!deploymentId) { + return null; + }Also consider adding a guard before rendering
DeploymentStatusBadge:- statusBadge={<DeploymentStatusBadge status={deploymentStatus} />} + statusBadge={deploymentStatus ? <DeploymentStatusBadge status={deploymentStatus} /> : null}
🤖 Fix all issues with AI agents
In
`@web/apps/dashboard/app/`(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/(overview)/navigations/use-deployment-breadcrumb-config.ts:
- Around line 27-29: The variables workspaceSlug, projectId, and deploymentId
currently use unsafe type assertions (as string); replace these with
runtime-safe extraction from useParams() by checking each param is a string (and
not an array/undefined) or by using a small type-safe helper (e.g.,
getStringParam) inside the useDeploymentBreadcrumbConfig hook: validate typeof
param === 'string' and handle or throw a clear error/redirect when it's missing
or an array, ensuring no `as` or non-null assertions are used and preserving
explicit error handling for invalid params.
In
`@web/apps/dashboard/app/`(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/runtime-logs/components/controls/components/runtime-logs-search/index.tsx:
- Around line 11-36: The code uses ad-hoc TypeScript assertions (e.g., casting
data to typedData and casting the result of transformStructuredOutputToFilters
to typeof filters) which violates the "no `as`" rule; instead, update the
repository linting and boundary validation: add/enable the relevant
`@typescript-eslint` rules (e.g., `@typescript-eslint/no-unnecessary-type-assertion`
and/or no-explicit-any) in web/apps/dashboard/eslint.config.mjs to catch these
patterns globally, and implement a schema validation layer (use zod or
equivalent) at the LLM/output boundary that validates/parses the incoming data
into a safe typed object before usage so you can remove casts around variables
like data/typedData and the transformStructuredOutputToFilters result.
In
`@web/apps/dashboard/app/`(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/runtime-logs/components/table/hooks/use-runtime-logs-query.ts:
- Around line 18-20: Remove the "as const" assertion on the operator literal and
instead give the mapped array an explicit type; specifically, in the declaration
of severityFilters (which maps from filters), remove the "as const" and add a
type annotation such as Array<{ operator: 'is'; value: string }> (or the
equivalent generic/type alias used in this module) to the severityFilters
variable so the operator is typed as the literal "is" without using a type
assertion.
In
`@web/apps/dashboard/app/`(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/runtime-logs/components/table/runtime-log-details/runtime-log-header.tsx:
- Around line 28-29: The icon-only close Button in runtime-log-header.tsx lacks
an accessible label; update the Button (the element with props size="icon"
variant="ghost" onClick={onClose}) to include an accessible name—e.g., add
aria-label="Close" or aria-label={`Close ${something}`} (or include a
visually-hidden <span> describing the action) so screen readers can announce the
control; ensure the XMark icon remains decorative (aria-hidden) if you add an
aria-label on the Button.
In
`@web/apps/dashboard/app/`(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/runtime-logs/components/table/runtime-logs-table.tsx:
- Around line 68-86: getLogKey currently builds keys from time-region-message
which can collide; change it to include a stable sequence id (preferred) or
fallback to the row index to make keys unique. Update getLogKey to accept a
second parameter (e.g., seq or index) and include it in the returned string,
then update all uses: where logs are mapped/rendered (Component that renders
rows), where selectedLogKey is computed (RuntimeLogsTable using selectedLog ->
use the same seq/index or store the seq alongside selectedLog), and any handlers
that call setSelectedLog to set or compare the augmented key; ensure
getSelectedClassName still uses the log object but selection comparisons use the
augmented key consistent with useRuntimeLogsQuery-produced sequence IDs or the
array index.
In
`@web/apps/dashboard/app/`(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/runtime-logs/hooks/use-runtime-logs-filters.ts:
- Around line 37-45: The effect that sets a default since value uses
searchParams and setSearchParams but has an empty dependency array, which can
cause stale closures; update the dependency array to include searchParams and
setSearchParams (e.g., useEffect(() => { if (searchParams.since === null &&
searchParams.startTime === null && searchParams.endTime === null)
setSearchParams({ since: "6h" }); }, [searchParams, setSearchParams])) so the
check runs when params change, ensuring you only call setSearchParams when all
three fields are null to avoid loops and stale values; reference the existing
useEffect, searchParams, and setSearchParams identifiers when making the change.
In
`@web/apps/dashboard/app/`(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/active-deployment-card-logs/components/deployment-logs-trigger.tsx:
- Around line 13-27: The two log-type toggle buttons (the ones calling
setLogType with "sentinel" and "runtime" and reading logType) lack an
aria-pressed state for assistive tech; update both button elements in
deployment-logs-trigger.tsx so each includes aria-pressed set to a boolean
expression (e.g., aria-pressed={logType === "sentinel"} for the sentinel button
and aria-pressed={logType === "runtime"} for the runtime button) so screen
readers can announce the active toggle.
In
`@web/apps/dashboard/app/`(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/active-deployment-card-logs/components/runtime-logs-content.tsx:
- Around line 66-99: The code uses a type assertion on log.severity (as keyof
typeof SEVERITY_STYLES); replace that with a runtime type guard: derive a
normalized string (e.g. const severityRaw = String(log.severity).toUpperCase()),
then check if severityRaw is a key in SEVERITY_STYLES (if (severityRaw in
SEVERITY_STYLES) ...) and set a typed variable (e.g. severityKey = severityRaw)
or fallback to "INFO"; use that severityKey for SEVERITY_STYLES[severityKey] and
SEVERITY_ABBR[severityKey] instead of the asserted severity to preserve type
safety.
In
`@web/apps/dashboard/app/`(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/active-deployment-card-logs/hooks/use-deployment-logs.tsx:
- Line 58: The ref declaration uses an unsafe type assertion; replace the cast
with a type-safe ref by initializing useRef<HTMLDivElement | null>(null) (remove
"as React.MutableRefObject<HTMLDivElement>"), change the exported/returned type
to React.RefObject<HTMLDivElement | null>, and update usages in handleScroll and
resetScroll to use optional chaining (e.g. scrollRef.current?....) so you don't
rely on non-null assertions; this keeps type safety in use-deployment-logs.tsx
for scrollRef, handleScroll, and resetScroll.
In
`@web/apps/dashboard/app/`(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/active-deployment-card-logs/hooks/use-runtime-logs.tsx:
- Around line 25-35: The runtime logs query is passing redundant startTime and
endTime alongside the relative `since` parameter; update the trpc call in
use-runtime-logs.tsx (trpc.deploy.runtimeLogs.query.useQuery) to omit
`startTime` and `endTime` when using `RUNTIME_LOGS_SINCE`—keep `projectId`,
`deploymentId`, `limit: RUNTIME_LOGS_LIMIT`, `since: RUNTIME_LOGS_SINCE`, and
any other filters (`severity`, `message`) intact, and remove the `startTime:
timestamp` and `endTime: timestamp` entries to avoid sending conflicting
parameters.
In
`@web/apps/dashboard/app/`(app)/[workspaceSlug]/projects/[projectId]/components/region-flags.tsx:
- Around line 8-12: The container in the RegionFlags component uses the CSS
class cursor-pointer but has no click handler or accessible role; either remove
the cursor-pointer class from the div in RegionFlags to avoid suggesting
interactivity, or make the element interactive by adding an onClick handler and
appropriate accessibility attributes (e.g., role="button" and keyboard handlers)
and update RegionFlags' props to accept the callback; locate RegionFlags and the
surrounding div that renders RegionFlag instances to apply the change.
In `@web/apps/dashboard/app/`(app)/[workspaceSlug]/projects/[projectId]/page.tsx:
- Around line 55-60: The DeploymentLogsTrigger is being rendered unconditionally
which allows interaction when no live deployment exists; update the rendering so
DeploymentLogsTrigger is only rendered when project?.liveDeploymentId is truthy
(the same condition used for DeploymentLogsContent) — locate the trailingContent
and expandableContent usage around DeploymentLogsTrigger and
DeploymentLogsContent and wrap or replace the DeploymentLogsTrigger with a
conditional check (project?.liveDeploymentId ? <DeploymentLogsTrigger /> : null)
so the trigger is hidden/disabled when no liveDeploymentId is present.
In
`@web/apps/dashboard/components/navigation/sidebar/app-sidebar/hooks/use-projects-navigation.tsx`:
- Line 41: The line in use-projects-navigation.tsx uses an unnecessary type
assertion on the result of segments.at(deploymentIdIndex); update the
declaration for deploymentId (used in this hook) to remove the `as string |
undefined` assertion and rely on TypeScript's inferred `string | undefined` from
segments.at(...), ensuring no type-assertion or non-null operators are
introduced.
In `@web/apps/dashboard/components/virtual-table/index.tsx`:
- Around line 88-93: The current tableClassName computation unconditionally
applies a "!table-auto" override via the expression config.tableLayout ===
"fixed" ? "!table-fixed" : "!table-auto", which cancels the responsive
"xl:table-fixed"; update the logic so the override is only added when
config.tableLayout is explicitly provided (e.g., use a conditional that checks
config.tableLayout truthiness and then chooses "!table-fixed" or "!table-auto"),
leaving the class list empty when tableLayout is unset to preserve the default
"xl:table-fixed" behavior; modify the code that builds tableClassName (the cn
call) to reference config.tableLayout accordingly.
In `@web/apps/dashboard/lib/trpc/routers/deploy/runtime-logs/llm-search/utils.ts`:
- Around line 58-78: Remove all "as Type" assertions in the catch block and stop
logging raw userSearchMsg; instead sanitize inputs before logging (e.g., redact
or log only non-sensitive fields). Replace direct casts for error and
error.response with type-safe guards: first check if error instanceof TRPCError
and rethrow; then narrow unknown error by checking typeof error === "object" &&
error !== null and safely parse error shapes (e.g., use zod.safeParse or manual
property checks) before accessing response?.status to detect 429 and throw a
TOO_MANY_REQUESTS TRPCError; finally throw a generic INTERNAL_SERVER_ERROR
TRPCError. Apply the same change to the catch blocks in the other llm-search
utils files listed.
In `@web/apps/dashboard/lib/trpc/routers/deploy/runtime-logs/query.ts`:
- Around line 74-80: The code assumes countResult.val[0] exists when building
the RuntimeLogsResponseSchema; update the construction of total in the object
returned by the function that sets logs and nextCursor (the block using
logsResult and countResult) to guard against an empty countResult.val by
defaulting total to 0 if countResult.val is empty or missing (e.g., check
countResult.val && countResult.val.length > 0 and use
countResult.val[0].total_count, otherwise 0). Ensure you update the symbol
references in that same block where logs, hasMore, total, and nextCursor are
assembled.
In `@web/internal/clickhouse/src/runtime-logs.ts`:
- Around line 6-17: The schema runtimeLogsRequestSchema allows negative integers
for timestamps which will fail when bound to ClickHouse UInt64; update the
startTime and endTime validators to use non-negative integers and make
cursorTime a nullable non-negative integer (e.g., replace z.int() with
z.int().nonnegative() for startTime and endTime, and
z.int().nullable().nonnegative() or the equivalent for cursorTime) so the schema
enforces the UInt64 boundary at validation time.
- Around line 41-45: The nullable severity binding fails because ClickHouse
doesn't support Nullable(Array(String)); update the SQL CASE that checks
severity to use an empty-array sentinel: replace the length({severity:
Array(String)}) check with empty({severity: Array(String)}) and use the OR
short-circuit (empty({severity:Array(String)}) OR severity IN
{severity:Array(String)}), and ensure the caller binds an empty array [] when no
filter is intended; alternatively, pre-normalize the severity parameter to []
before invoking the query or add a separate nullable flag parameter (as
suggested by the message pattern) if you must distinguish null from empty.
🧹 Nitpick comments (14)
web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/components/active-deployment-card/components/skeleton.tsx (1)
58-65: Consider using skeleton placeholders or disabled buttons for consistency.This is a skeleton/loading state component, but these buttons appear interactive with real text labels. The rest of the component uses
animate-pulsedivs as placeholders. Using plain HTML<button>elements without handlers in a skeleton creates a confusing UX where buttons look clickable but do nothing.Consider either:
- Replacing with skeleton placeholders to match the pattern used elsewhere in this component, or
- Using the design system's
Buttoncomponent withdisabledstate for consistency with line 65.Option 1: Skeleton placeholders
<div className="flex items-center gap-1.5"> - <button className="text-xs text-grayA-9" type="button"> - Sentinel logs - </button> - <span className="text-grayA-6">|</span> - <button className="text-xs text-grayA-9" type="button"> - Runtime logs - </button> + <div className="h-2.5 w-16 bg-grayA-3 rounded animate-pulse" /> + <span className="text-grayA-6">|</span> + <div className="h-2.5 w-16 bg-grayA-3 rounded animate-pulse" /> <Button size="icon" variant="ghost">Option 2: Disabled design system buttons
<div className="flex items-center gap-1.5"> - <button className="text-xs text-grayA-9" type="button"> + <Button variant="ghost" size="sm" disabled className="text-xs text-grayA-9"> Sentinel logs - </button> + </Button> <span className="text-grayA-6">|</span> - <button className="text-xs text-grayA-9" type="button"> + <Button variant="ghost" size="sm" disabled className="text-xs text-grayA-9"> Runtime logs - </button> + </Button> <Button size="icon" variant="ghost">web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/custom-domains-section/add-custom-domain.tsx (1)
117-120: Empty catch block silently swallows exceptions.While
toast.promisehandles displaying errors to the user, the empty catch block obscures intent. Consider adding a comment to clarify this is intentional, or explicitly ignoring the error:♻️ Suggested clarification
try { await mutation; onSuccess(); - } catch {} + } catch { + // Error already displayed by toast.promise above + }web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/(overview)/navigations/use-deployment-breadcrumb-config.ts (1)
10-21: Consider importingBreadcrumbItemtype instead of duplicating it.This type definition is identical to the one in
use-breadcrumb-config.ts(lines 15-26 in relevant snippets). Importing from a shared location would reduce duplication and ensure consistency.web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/layout.tsx (1)
32-34: Magic number and fragile path detection.The
>= 5check relies on a specific URL structure that could break if routes change. Similar logic exists inuse-projects-navigation.tsx(lines 38-40) using segment indices, creating potential for inconsistency between the two detection approaches.Consider extracting this into a shared utility or constant to ensure both locations stay in sync:
Suggested approach
// In a shared utils file export function isDeploymentDetailPath(pathname: string | null): boolean { if (!pathname) return false; const segments = pathname.split("/").filter(Boolean); // Expected: workspace/projects/projectId/deployments/deploymentId/... const deploymentsIndex = segments.indexOf("deployments"); return deploymentsIndex !== -1 && segments.length > deploymentsIndex + 1; }web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/details/active-deployment-card-logs/hooks/use-deployment-logs.tsx (2)
6-6: Remove commented-out code instead of leaving it in.The commented-out build steps logic (lines 6, 61-70, 91-105) should be removed rather than left in the codebase. Version control preserves the history if this code needs to be restored later.
Proposed removal
- // const BUILD_STEPS_REFETCH_INTERVAL = 500; const GATEWAY_LOGS_REFETCH_INTERVAL = 2000;- // const { data: buildData, isLoading: buildLoading } = trpc.deploy.deployment.buildSteps.useQuery( - // { - // // without this check TS yells at us - // deploymentId: deploymentId ?? "", - // }, - // { - // enabled: showBuildSteps && isExpanded && Boolean(deploymentId), - // refetchInterval: BUILD_STEPS_REFETCH_INTERVAL, - // }, - // );- // // Update stored logs when build data changes - // useEffect(() => { - // if (showBuildSteps && buildData?.logs) { - // const logMap = new Map<string, LogEntry>(); - // buildData.logs.forEach((log) => { - // logMap.set(log.id, { - // type: "build", - // id: log.id, - // timestamp: log.timestamp, - // message: log.message, - // }); - // }); - // setStoredLogs(logMap); - // } - // }, [showBuildSteps, buildData]);Also applies to: 61-70, 91-105
15-21: Consider removing the hardcodedtypefield if only one type exists.Since
LogEntry.typenow only supports"sentinel", and the type is always set to"sentinel"on line 122, the field may be unnecessary. However, if you plan to reintroduce other log types later, keeping it for forward compatibility is reasonable.web/apps/dashboard/lib/utils/deployment-formatters.ts (1)
22-22: Consider clarifying the millicores format string.The format
${millicores}m vCPUcombines millicores notation (m) withvCPUwhich may be redundant or confusing. Standard notation is typically just${millicores}m(e.g., "500m") or expressed as a fraction/decimal of vCPU.💡 Suggested alternatives
- return `${millicores}m vCPU`; + return `${millicores}m`;Or convert to decimal vCPU:
- return `${millicores}m vCPU`; + return `${(millicores / 1024).toFixed(2)} vCPU`;web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/runtime-logs/components/controls/components/runtime-logs-datetime/index.tsx (1)
20-28: Avoid type assertion; type the accumulator explicitly.The
as Record<string, string | number>cast on line 27 violates the coding guideline to avoidas Type. The accumulator can be typed directly in the reduce call.♻️ Proposed fix
const timeValues = filters .filter((f) => ["startTime", "endTime", "since"].includes(f.field)) .reduce( - (acc, f) => { + (acc: Record<string, string | number>, f) => { acc[f.field] = f.value; return acc; }, - {} as Record<string, string | number>, + {}, );As per coding guidelines: "Never compromise type safety: No
any, no!(non-null assertion), noas Type"web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/runtime-logs/components/controls/components/runtime-logs-filters/runtime-logs-severity-filter.tsx (1)
32-39: Minor: Inconsistent field ordering in options array.The "info" option has
displaybeforeseverity(lines 34-35) while other options haveseveritybeforedisplay. This doesn't affect functionality but slightly reduces readability.💅 Suggested fix for consistency
{ id: 3, - display: "INFO", severity: "info", + display: "INFO", label: "Info", color: "bg-info-9", checked: false, },web/apps/dashboard/lib/trpc/routers/deploy/runtime-logs/utils.ts (1)
13-17: Consider handling potential error fromgetTimestampFromRelative.The
getTimestampFromRelativefunction throws anErrorwith message about invalid format (per the relevant snippet showing regex validation). Ifparams.sincecontains an invalid format, this will throw uncaught.Depending on where
transformFiltersis called, you may want to either:
- Validate
sinceformat upstream before calling this function- Wrap the call with error handling using the
faultlibrary per coding guidelinesExample with fault library wrapping
import { fault } from "fault"; // or appropriate import path // In transformFilters: if (hasRelativeTime) { try { startTime = getTimestampFromRelative(params.since); endTime = Date.now(); } catch (e) { throw fault("InvalidRelativeTime", { message: `Invalid relative time format: ${params.since}`, cause: e, }); } }web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/runtime-logs/context/runtime-logs-provider.tsx (1)
23-28: Consider usingfaultlibrary for the invariant error.Per coding guidelines, the
faultlibrary should be used for error handling. While this is a standard React context invariant pattern, usingfaultwould maintain consistency across the codebase.Optional: Use fault library
+import { fault } from "fault"; + export function useRuntimeLogs() { const context = useContext(RuntimeLogsContext); if (!context) { - throw new Error("useRuntimeLogs must be used within RuntimeLogsProvider"); + throw fault("ContextMisuse", { + message: "useRuntimeLogs must be used within RuntimeLogsProvider", + }); } return context; }web/apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/(overview)/deployments/[deploymentId]/runtime-logs/hooks/use-runtime-logs-filters.ts (3)
56-60: Type assertionas stringviolates coding guidelines.The
as stringassertion bypasses type safety. Consider using a type guard or narrowing the type properly.♻️ Proposed fix
metadata: { - colorClass: runtimeLogsFilterFieldConfig.severity.getColorClass?.( - severity.value as string, - ), + colorClass: + typeof severity.value === "string" + ? runtimeLogsFilterFieldConfig.severity.getColorClass?.(severity.value) + : undefined, },As per coding guidelines: Never compromise type safety: No
any, no!(non-null assertion), noas Type.
73-83: Multiple type assertions violate coding guidelines.Lines 74, 78, and 80 use
astype assertions. These can be refactored to use proper type narrowing.♻️ Proposed fix using type-safe iteration
- ["startTime", "endTime", "since"].forEach((field) => { - const value = searchParams[field as keyof RuntimeLogsQuerySearchParams]; - if (value !== null && value !== undefined) { - activeFilters.push({ - id: crypto.randomUUID(), - field: field as RuntimeLogsFilterField, - operator: "is", - value: value as string | number, - }); - } - }); + const timeFields = ["startTime", "endTime", "since"] as const; + for (const field of timeFields) { + const value = searchParams[field]; + if (value !== null && value !== undefined) { + activeFilters.push({ + id: crypto.randomUUID(), + field, + operator: "is", + value, + }); + } + }As per coding guidelines: Never compromise type safety: No
any, no!(non-null assertion), noas Type.
116-122: Type assertionsas numberandas stringviolate coding guidelines.Consider using type guards or discriminated unions to narrow types safely.
♻️ Proposed fix
case "startTime": case "endTime": - newParams[filter.field] = filter.value as number; + if (typeof filter.value === "number") { + newParams[filter.field] = filter.value; + } break; case "since": - newParams.since = filter.value as string; + if (typeof filter.value === "string") { + newParams.since = filter.value; + } break;As per coding guidelines: Never compromise type safety: No
any, no!(non-null assertion), noas Type.
...rview)/deployments/[deploymentId]/(overview)/navigations/use-deployment-breadcrumb-config.ts
Show resolved
Hide resolved
...nts/[deploymentId]/runtime-logs/components/controls/components/runtime-logs-search/index.tsx
Show resolved
Hide resolved
...ew)/deployments/[deploymentId]/runtime-logs/components/table/hooks/use-runtime-logs-query.ts
Show resolved
Hide resolved
...ents/[deploymentId]/runtime-logs/components/table/runtime-log-details/runtime-log-header.tsx
Show resolved
Hide resolved
...]/(overview)/deployments/[deploymentId]/runtime-logs/components/table/runtime-logs-table.tsx
Show resolved
Hide resolved
web/apps/dashboard/lib/trpc/routers/deploy/runtime-logs/llm-search/utils.ts
Show resolved
Hide resolved
* fix: overlapping in deployment list * chore: delete state change * feat: add actual network elements * refactor: replace rest of the regions with sentinel * chore: tidy up * feat: add RPS CH queries * feat: add proper formatting for metrics * feat: add proper foramtting * feat: add RPS chart * feat: add latency chart * refactor: fix AVG aggregation * chore: update logs querry * refactor: reorganize componetns * chore: tidy * chore: explanation line * feat: add disabled for navbar-popover * fix: type issues * feat: update sidebar nesting * feat: add tRPC for runtime-lgos * feat: add rough version of runtime-logs * chore: fmt * refactor: styling of runtime logs * refactor: use the same schema * feat: add message filter * refactor: use proper filters schema * feat: add AI search * feat: add proper resizing for smaller screens and switch to table-auto instead of fixed * chore: allow overriding table layout * refactor: improve ui * fix: ui inconsistenties * chore: improve styling of custom domains * feat: add runtime-logs to active deployment card * refactor: custom domain styless * fix: formatting * chore: improvemetns * refactor: use shared component for flags * chore: tidyup * fix: network status bar overlapping
What does this PR do?
How should this be tested?
make devgo run . dev seed localgo run . dev seed sentinel --deployment-id="d_xxxx"Screen.Recording.2026-02-03.at.19.10.43.mov