Skip to content

Commit

Permalink
refactor: improve server details
Browse files Browse the repository at this point in the history
  • Loading branch information
jog1t committed Nov 13, 2024
1 parent 87600ab commit 5c12cc5
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 62 deletions.
51 changes: 30 additions & 21 deletions apps/hub/src/domains/project/components/servers/server-logs-tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Rivet } from "@rivet-gg/api";
import { Button, LogsView, WithTooltip } from "@rivet-gg/components";
import { Icon, faSave } from "@rivet-gg/icons";
import { useSuspenseQuery } from "@tanstack/react-query";
import { differenceInHours } from "date-fns";
import { saveAs } from "file-saver";
import { serverLogsQueryOptions } from "../../queries";

Expand All @@ -10,13 +11,15 @@ interface ServerLogsTabProps {
environmentId: string;
serverId: string;
logType: Rivet.servers.LogStream;
createdAt: number;
}

export function ServerLogsTab({
projectId,
environmentId,
serverId,
logType,
createdAt,
}: ServerLogsTabProps) {
const {
data: { timestamps, lines },
Expand All @@ -29,32 +32,38 @@ export function ServerLogsTab({
}),
);

const areLogsRetained = differenceInHours(Date.now(), createdAt) < 24 * 3;

return (
<LogsView
timestamps={timestamps}
lines={lines}
empty="No logs available."
empty={
areLogsRetained ? "No logs available." : "Logs are retained for 3 days."
}
sidebar={
<WithTooltip
content="Download logs"
trigger={
<Button
variant="outline"
aria-label="Download logs"
size="icon"
onClick={() =>
saveAs(
new Blob([lines.join("\n")], {
type: "text/plain;charset=utf-8",
}),
"logs.txt",
)
}
>
<Icon icon={faSave} />
</Button>
}
/>
lines.length > 0 ? (
<WithTooltip
content="Download logs"
trigger={
<Button
variant="outline"
aria-label="Download logs"
size="icon"
onClick={() =>
saveAs(
new Blob([lines.join("\n")], {
type: "text/plain;charset=utf-8",
}),
"logs.txt",
)
}
>
<Icon icon={faSave} />
</Button>
}
/>
) : null
}
/>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import type { Rivet } from "@rivet-gg/api";
import { cn } from "@rivet-gg/components";
import { ServerStatusIndicator } from "./server-status-indicator";
import { ServerStatusLabel } from "./server-status-label";

interface ServerStatusProps extends Rivet.servers.Server {}
interface ServerStatusProps extends Rivet.servers.Server {
className?: string;
}

export const ServerStatus = (props: ServerStatusProps) => {
export const ServerStatus = ({ className, ...props }: ServerStatusProps) => {
return (
<div className="flex items-center gap-x-2">
<div className={cn("flex items-center gap-x-2", className)}>
<ServerStatusIndicator {...props} />
<ServerStatusLabel {...props} />
</div>
Expand Down
61 changes: 50 additions & 11 deletions apps/hub/src/domains/project/components/servers/server-tags.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,74 @@
import { Badge, cn } from "@rivet-gg/components";
import {
CopyButton,
Slot,
Slottable,
WithTooltip,
cn,
} from "@rivet-gg/components";
import { Icon, faTag } from "@rivet-gg/icons";
import { type ReactNode, forwardRef } from "react";

const BUILT_IN_TAGS = ["current", "rivet/latest", "enabled", "rivet/enabled"];

const Tag = forwardRef<
HTMLSpanElement,
{ children: ReactNode; className?: string }
>(({ children, className, ...props }, ref) => (
<Slot ref={ref} className={className} {...props}>
<Icon className="mr-1" icon={faTag} />
<Slottable>{children}</Slottable>
</Slot>
));

interface ServerTagsProps {
tags?: unknown;
excludeBuiltIn?: boolean;
className?: string;
truncate?: boolean;
}

export function ServerTags({
tags = {},
excludeBuiltIn = false,
truncate = true,
className,
}: ServerTagsProps) {
return (
<div className={cn("flex flex-wrap gap-2 empty:hidden", className)}>
<div
className={cn(
"flex flex-wrap gap-4 gap-y-2 empty:hidden text-muted-foreground text-xs font-mono",
className,
)}
>
{tags && typeof tags === "object"
? Object.entries(tags)
.filter(([key]) =>
excludeBuiltIn ? !BUILT_IN_TAGS.includes(key) : true,
)
.sort(([a], [b]) => a.localeCompare(b))
.map(([key, value]) => (
<Badge
key={key}
variant="outline"
className="overflow-visible flex-shrink-0 text-ellipsis"
>
{key}={value}
</Badge>
))
.map(([key, value]) =>
truncate ? (
<WithTooltip
key={key}
content={`${key}=${value}`}
trigger={
<CopyButton value={`${key}=${value}`}>
<Tag className="flex-shrink-0 truncate max-w-52 cursor-pointer">
<button type="button">
{key}={value}
</button>
</Tag>
</CopyButton>
}
/>
) : (
<Tag key={key} className="flex-shrink-0">
<span>
{key}={value}
</span>
</Tag>
),
)
: null}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { Rivet } from "@rivet-gg/api";
import {
Badge,
Button,
RelativeTime,
ScrollArea,
Expand Down Expand Up @@ -99,28 +98,33 @@ function ServerRow({
<div className="w-full flex justify-center">
<ServerStatusIndicator {...server} />
</div>
<Badge variant="outline">
<SmallText className="font-semibold">
<ServerDatacenter
showLabel="abbreviated"
projectId={projectId}
environmentId={environmentId}
datacenterId={server.datacenter}
/>
</Badge>
</SmallText>
<SmallText>{server.id.split("-")[0]}</SmallText>
<WithTooltip
trigger={
<div className="relative overflow-r-gradient">
<ServerTags
className="flex-nowrap empty:block overflow-hidden"
truncate={false}
{...server}
/>
</div>
}
content={
<>
<p className="pb-2 font-bold text-xs">Tags</p>
<ServerTags className="empty:block" {...server} />
<ServerTags
className="empty:block"
truncate={false}
{...server}
/>
</>
}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function ServersListPreview({
autoSaveId="rivet-project-backend-logs"
direction={isMd ? "horizontal" : "vertical"}
>
<ResizablePanel minSize={25} maxSize={75}>
<ResizablePanel minSize={40} maxSize={75}>
<div className="h-full max-h-full overflow-hidden w-full truncate min-w-0">
<ServersListPanel
projectId={projectId}
Expand All @@ -37,7 +37,7 @@ export function ServersListPreview({
</div>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel minSize={25} maxSize={75}>
<ResizablePanel minSize={40} maxSize={75}>
<div className="h-full max-h-full overflow-hidden w-full">
<Suspense fallback={<ServersServerDetailsPanel.Skeleton />}>
<ServersServerDetailsPanel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ export function ServersServerDetailsPanel({
if (!serverId) {
return (
<Flex items="center" justify="center" className="h-full">
<Text textAlign="center">
Please select a server from the list on the left.
</Text>
<Text textAlign="center">Please select a server from the list.</Text>
</Flex>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import {
Button,
CopyButton,
ClickToCopy,
Flex,
LogsView,
Skeleton,
SmallText,
Tabs,
TabsContent,
TabsList,
Expand All @@ -12,8 +13,10 @@ import {
} from "@rivet-gg/components";
import { ErrorBoundary } from "@sentry/react";
import { useSuspenseQuery } from "@tanstack/react-query";
import { formatISO } from "date-fns";
import { Suspense } from "react";
import { serverQueryOptions, useDestroyServerMutation } from "../../queries";
import { ServerDatacenter } from "./server-datacenter";
import { ServerLogsTab } from "./server-logs-tab";
import { ServerNetworkTab } from "./server-network-tab";
import { ServerRuntimeTab } from "./server-runtime-tab";
Expand Down Expand Up @@ -57,27 +60,76 @@ export function ServersServerDetails({
</Flex>
}
>
<Flex direction="col" className="h-full w-full" pt="4">
<Flex items="start" gap="2" px="4">
<Flex gap="2">
<ServerStatus {...data} />
<CopyButton value={data.id}>
<Button variant="outline">Copy ID</Button>
</CopyButton>
<Flex direction="col" className="h-full w-full @container" pt="4">
<Flex items="start" gap="4" px="6" className="flex-col">
<Flex gap="2" justify="between" w="full">
<ServerStatus className="text-sm" {...data} />
{!data.destroyTs ? (
<Button
isLoading={isDestroying}
variant="destructive"
size="sm"
onClick={() => mutate({ projectId, environmentId, serverId })}
>
Destroy
Stop
</Button>
) : null}
</Flex>

<Flex direction="col" gap="4" className="flex-1">
<ServerTags {...data} />
</Flex>
<div className="w-full">
<Flex direction="col" gap="2" className="flex-1 min-w-0" w="full">
<ServerTags className="justify-start" {...data} />
</Flex>
</div>
<div className="flex w-full flex-wrap text-sm gap-4 border px-3 py-2 rounded-md -mx-3">
<div className="shrink-0 flex gap-2 items-center justify-center">
<p className="">Region </p>
<SmallText className="text-xs text-muted-foreground">
<ServerDatacenter
showLabel="abbreviated"
projectId={projectId}
environmentId={environmentId}
datacenterId={data.datacenter}
/>
</SmallText>
</div>
<ClickToCopy value={data.id}>
<button
type="button"
className="shrink-0 flex gap-2 items-center justify-center"
>
<p className="">ID </p>
<SmallText className="font-mono text-muted-foreground text-xs">
{data.id.split("-")[0]}
</SmallText>
</button>
</ClickToCopy>
<ClickToCopy value={formatISO(data.createdAt)}>
<button
type="button"
className="shrink-0 flex gap-2 items-center justify-center"
>
<p className=" ">Created </p>
<SmallText className=" text-xs text-muted-foreground">
{formatISO(data.createdAt)}
</SmallText>
</button>
</ClickToCopy>

<ClickToCopy
value={data.destroyTs ? formatISO(data.destroyTs) : "-"}
>
<button
type="button"
className="shrink-0 flex gap-2 items-center"
>
<p className="">Destroyed </p>
<SmallText className="text-xs text-muted-foreground ">
{data.destroyTs ? formatISO(data.destroyTs) : "-"}
</SmallText>
</button>
</ClickToCopy>
</div>
</Flex>

<Tabs
Expand All @@ -93,6 +145,7 @@ export function ServersServerDetails({
<TabsContent value="output" className="min-h-0 flex-1 mt-0 p-4">
<Suspense fallback={<ServerLogsTab.Skeleton />}>
<ServerLogsTab
createdAt={data.createdAt}
projectId={projectId}
environmentId={environmentId}
serverId={serverId}
Expand All @@ -103,6 +156,7 @@ export function ServersServerDetails({
<TabsContent value="errors" className="min-h-0 flex-1 mt-0 p-4">
<Suspense fallback={<ServerLogsTab.Skeleton />}>
<ServerLogsTab
createdAt={data.createdAt}
projectId={projectId}
environmentId={environmentId}
serverId={serverId}
Expand Down
Loading

0 comments on commit 5c12cc5

Please sign in to comment.