Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion app/components/CopyCode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,12 @@ export function EquivalentCliCommand({ project, instance }: EquivProps) {

return (
<>
<Button variant="secondary" size="sm" onClick={() => setIsOpen(true)}>
<Button
variant="secondary"
size="sm"
className="max-1000:hidden"
onClick={() => setIsOpen(true)}
>
CLI Command
</Button>
<CopyCodeModal
Expand Down
2 changes: 1 addition & 1 deletion app/components/ErrorPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export function ErrorPage({ children }: Props) {
</Link>
<SignOutButton className="mt-4 mr-6" />
</div>
<div className="bg-raise! shadow-modal max-1000:w-[calc(100%-var(--content-gutter)*2)] absolute top-1/2 left-1/2 flex w-96 -translate-x-1/2 -translate-y-1/2 flex-col items-center justify-center space-y-4 rounded-lg p-8">
<div className="bg-raise! shadow-modal max-1000:w-[calc(100%-var(--content-gutter)*2)] absolute top-1/2 left-1/2 flex max-w-96 -translate-x-1/2 -translate-y-1/2 flex-col items-center justify-center space-y-4 rounded-lg p-8">
<div className="my-2 flex h-12 w-12 items-center justify-center">
<div className="bg-destructive-inverse absolute h-10 w-10 rounded-full opacity-40 motion-safe:animate-[ping_2s_cubic-bezier(0,0,0.2,1)_infinite]" />
<Error12Icon className="text-error light:text-error-secondary relative h-8 w-8" />
Expand Down
2 changes: 1 addition & 1 deletion app/components/Pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const Tunnel = tunnel()
export function Pagination(props: UIPaginationProps) {
return (
<Tunnel.In>
<UIPagination className="gutter h-14 py-5" {...props} />
<UIPagination className="gutter py-4" {...props} />
</Tunnel.In>
)
}
Expand Down
35 changes: 26 additions & 9 deletions app/components/RouteTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,22 @@ const selectTab = (e: React.KeyboardEvent<HTMLDivElement>) => {
}
}

function RouteTabList({
className,
children,
}: {
className?: string
children: ReactNode
}) {
return (
// Keyboard nav is handled on the tablist; individual tabs take focus.
// oxlint-disable-next-line jsx-a11y/interactive-supports-focus
<div role="tablist" className={className} onKeyDown={selectTab}>
{children}
</div>
)
}

export interface RouteTabsProps {
children: ReactNode
fullWidth?: boolean
Expand All @@ -54,23 +70,24 @@ export function RouteTabs({
tabListClassName,
}: RouteTabsProps) {
/* TODO: Add aria-describedby for active tab */
const tabList = (
<RouteTabList
className={cn(sideTabs ? 'ox-side-tabs-list' : 'ox-tabs-list', tabListClassName)}
>
{children}
</RouteTabList>
)

return (
<div
className={cn(sideTabs ? 'ox-side-tabs flex' : 'ox-tabs', {
'full-width': !sideTabs && fullWidth,
})}
>
{/* eslint-disable-next-line jsx-a11y/interactive-supports-focus */}
<div
role="tablist"
className={cn(sideTabs ? 'ox-side-tabs-list' : 'ox-tabs-list', tabListClassName)}
onKeyDown={selectTab}
>
{children}
</div>
{sideTabs ? tabList : <div className="ox-tabs-list-wrap">{tabList}</div>}

<div
className={cn('ox-tabs-panel @container', { 'ml-5 grow': sideTabs })}
className={cn('ox-tabs-panel @container', { 'grow 1000:ml-5': sideTabs })}
role="tabpanel"
tabIndex={0}
>
Expand Down
2 changes: 1 addition & 1 deletion app/components/TimeSeriesChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ const MetricsMessage = ({
</div>
</div>
<div
className="bg-accent absolute inset-x-0 top-1 bottom-12"
className="bg-accent absolute inset-x-0 bottom-12"
style={{
background:
'radial-gradient(200% 100% at 50% 100%, var(--surface-default) 0%, var(--surface-secondary) 100%)',
Expand Down
4 changes: 2 additions & 2 deletions app/components/TopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ function MobileNavToggle() {
return (
// full-height cell with a right border so the toggle reads as its own
// region, mirroring the desktop home button cell
<div className="border-secondary 1000:hidden -ml-3 flex h-(--top-bar-height) shrink-0 items-center border-r px-1.5">
<div className="border-secondary 1000:hidden -ml-3 flex h-(--top-bar-height) shrink-0 items-center border-r">
<button
type="button"
onClick={toggleMobileNav}
aria-label="Toggle sidebar"
aria-expanded={isOpen}
className="hover:bg-hover flex h-10 w-10 items-center justify-center rounded-md"
className="hover:bg-hover flex h-full w-10 items-center justify-center"
>
<Icon className="text-secondary" />
</button>
Expand Down
36 changes: 17 additions & 19 deletions app/components/form/fields/DisksTableField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,25 +75,23 @@ export function DisksTableField({
emptyState={{ title: 'No disks', body: 'Add a disk to see it here' }}
/>

<div className="max-1000:flex-col flex gap-3">
<Button
size="sm"
className="max-1000:w-full"
onClick={() => setShowDiskCreate(true)}
disabled={disabled}
>
Create new disk
</Button>
<Button
variant="secondary"
size="sm"
className="max-1000:w-full"
onClick={() => setShowDiskAttach(true)}
disabled={disabled}
>
Attach existing disk
</Button>
</div>
<Button
size="sm"
className="max-1000:w-full"
onClick={() => setShowDiskCreate(true)}
disabled={disabled}
>
Create new disk
</Button>
<Button
variant="secondary"
size="sm"
className="max-1000:w-full"
onClick={() => setShowDiskAttach(true)}
disabled={disabled}
>
Attach existing disk
</Button>
</div>

{showDiskCreate && (
Expand Down
8 changes: 7 additions & 1 deletion app/components/oxql-metrics/OxqlMetric.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,13 @@ export function OxqlMetric({ title, description, unit, ...queryObj }: OxqlMetric
export const MetricHeader = ({ children }: { children: ReactNode }) => {
// If header has only one child, align it to the end of the container
const justify = Children.count(children) === 1 ? 'justify-end' : 'justify-between'
return <div className={`flex flex-wrap gap-2 ${justify}`}>{children}</div>
return (
<div
className={`max-1000:flex-col max-1000:[&>*]:w-full flex flex-wrap gap-2 ${justify}`}
>
{children}
</div>
)
}
export const MetricCollection = classed.div`mt-3 flex flex-col gap-4`

Expand Down
8 changes: 4 additions & 4 deletions app/pages/SiloUtilizationPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,21 +96,21 @@ export default function SiloUtilizationPage() {

<Divider className="my-8" />

<div className="mb-3 flex flex-wrap justify-between gap-3">
<div className="flex gap-2">
<div className="max-1000:flex-col mb-3 flex flex-wrap justify-between gap-3">
<div className="max-1000:w-full max-1000:flex-col flex gap-2">
{intervalPicker}

<Listbox
selected={filterId}
className="w-52"
className="max-1000:w-full w-52"
label="Filter by project"
hideLabel
name="filter-id"
items={projectItems}
onChange={setFilterId}
/>
</div>
<div className="flex items-center gap-2">{dateTimeRangePicker}</div>
<div className="max-1000:w-full flex items-center gap-2">{dateTimeRangePicker}</div>
</div>

<div className="mb-3 space-y-4">
Expand Down
4 changes: 2 additions & 2 deletions app/pages/project/instances/CpuMetricsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ export default function CpuMetricsTab() {
return (
<>
<MetricHeader>
<div className="flex gap-2">
<div className="max-1000:w-full flex gap-2">
<Listbox
className="w-52"
className="max-1000:w-full w-52"
aria-label="Choose state"
name="disk-name"
selected={selectedState}
Expand Down
4 changes: 2 additions & 2 deletions app/pages/project/instances/DiskMetricsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,9 @@ function DiskMetrics({ disks, instance }: { disks: Disk[]; instance: Instance })
return (
<>
<MetricHeader>
<div className="flex gap-2">
<div className="max-1000:w-full flex gap-2">
<Listbox
className="w-52"
className="max-1000:w-full w-52"
aria-label="Choose disk"
name="disk-name"
selected={selectedDisk}
Expand Down
2 changes: 1 addition & 1 deletion app/pages/project/instances/MetricsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export default function MetricsTab() {
// Find the relevant <Outlet> in RouteTabs
return (
<MetricsContext.Provider value={context}>
<RouteTabs sideTabs tabListClassName="mt-14">
<RouteTabs sideTabs tabListClassName="max-1000:mb-4 1000:mt-14">
<Tab to={pb.instanceCpuMetrics({ project, instance })}>CPU</Tab>
<Tab to={pb.instanceDiskMetrics({ project, instance })}>Disk</Tab>
<Tab to={pb.instanceNetworkMetrics({ project, instance })}>Network</Tab>
Expand Down
4 changes: 2 additions & 2 deletions app/pages/project/instances/NetworkMetricsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ function NetworkMetrics({ nics }: { nics: InstanceNetworkInterface[] }) {
return (
<>
<MetricHeader>
<div className="flex gap-2">
<div className="max-1000:w-full flex gap-2">
<Listbox
className="w-52"
className="max-1000:w-full w-52"
aria-label="Choose network interface"
name="nic-name"
selected={selectedNic}
Expand Down
34 changes: 16 additions & 18 deletions app/pages/project/instances/NetworkingTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -696,24 +696,22 @@ export default function NetworkingTab() {
<div className="space-y-5">
<CardBlock>
<CardBlock.Header title="External IPs" titleId="attached-ips-label">
<div className="flex gap-3">
<Button
size="sm"
onClick={() => setAttachEphemeralModalOpen(true)}
disabled={!!ephemeralDisabledReason}
disabledReason={ephemeralDisabledReason}
>
Attach ephemeral IP
</Button>
<Button
size="sm"
onClick={() => setAttachFloatingModalOpen(true)}
disabled={!!floatingDisabledReason}
disabledReason={floatingDisabledReason}
>
Attach floating IP
</Button>
</div>
<Button
size="sm"
onClick={() => setAttachEphemeralModalOpen(true)}
disabled={!!ephemeralDisabledReason}
disabledReason={ephemeralDisabledReason}
>
Attach ephemeral IP
</Button>
<Button
size="sm"
onClick={() => setAttachFloatingModalOpen(true)}
disabled={!!floatingDisabledReason}
disabledReason={floatingDisabledReason}
>
Attach floating IP
</Button>
</CardBlock.Header>

<CardBlock.Body>
Expand Down
8 changes: 4 additions & 4 deletions app/pages/system/UtilizationPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,21 +128,21 @@ const MetricsTab = () => {

return (
<>
<div className="mt-8 mb-3 flex flex-wrap justify-between gap-3">
<div className="flex gap-2">
<div className="max-1000:flex-col mt-8 mb-3 flex flex-wrap justify-between gap-3">
<div className="max-1000:w-full max-1000:flex-col flex gap-2">
{intervalPicker}

<Listbox
selected={filterId}
className="w-52"
className="max-1000:w-full w-52"
label="Filter by silo"
hideLabel
name="filter-id"
items={siloItems}
onChange={setFilterId}
/>
</div>
<div className="flex items-center gap-2">{dateTimeRangePicker}</div>
<div className="max-1000:w-full flex items-center gap-2">{dateTimeRangePicker}</div>
</div>
<div className="mb-4 space-y-4">
<SystemMetric
Expand Down
6 changes: 4 additions & 2 deletions app/ui/lib/CardBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,17 @@ type HeaderProps = {
}

CardBlock.Header = ({ title, description, children, titleId }: HeaderProps) => (
<header className="text-secondary flex items-start justify-between px-5 pb-4">
<header className="text-secondary max-800:flex-col flex items-start justify-between gap-4 px-5 pb-4">
<div className="flex flex-col gap-0.5">
<div className="text-sans-semi-lg text-raise" id={titleId}>
{title}
</div>
{description && <div className="text-secondary">{description}</div>}
</div>

<div className="max-1000:flex-col flex gap-2">{children}</div>
<div className="max-800:flex-col max-800:[&>.ox-button]:w-full! max-800:w-full flex gap-2">
{children}
</div>
</header>
)

Expand Down
6 changes: 3 additions & 3 deletions app/ui/lib/DateRangePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,16 @@ export function DateRangePicker(props: DateRangePickerProps) {
: 'border-default ring-accent-secondary'
)}
>
<div className="text-sans-md relative flex w-[16rem] items-center px-3">
<div className="text-sans-md max-1000:sr-only 1000:w-[16rem] relative flex items-center px-3">
<div className="truncate">{label}</div>
{state.isInvalid && (
<div className="text-error absolute top-0 right-2 bottom-0 flex items-center">
<Error12Icon className="h-3 w-3" />
</div>
)}
</div>
<div className="border-default -ml-px flex h-[calc(100%-12px)] w-10 items-center justify-center rounded-r-md border-l outline-hidden">
<Calendar16Icon className="text-secondary h-4 w-4" />
<div className="border-default max-1000:ml-0 1000:-ml-px 1000:border-l flex h-[calc(100%-12px)] w-10 items-center justify-center rounded-r-md outline-hidden">
<Calendar16Icon className="text-secondary h-4 w-4" aria-hidden />
</div>
</button>
</div>
Expand Down
13 changes: 9 additions & 4 deletions app/ui/lib/PageHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,22 @@ import type { ReactElement } from 'react'

import { classed } from '~/util/classed'

export const PageHeader = classed.header`mb-16 mt-12 flex items-center justify-between max-1000:mt-8`
import { Truncate } from './Truncate'

// Title is allowed to shrink (`min-w-0`); actions keep their intrinsic width so
// long names ellipsize instead of shoving buttons off-screen. Below 500px the
// actions stack above the title and each row can use the full width.
export const PageHeader = classed.header`mb-16 mt-12 flex w-full min-w-0 justify-between gap-4 max-500:flex-col max-500:*:last:order-0 max-500:*:first:order-1 500:items-center 500:[&>h1]:flex-1 500:[&>:not(h1)]:shrink-0 max-1000:mt-8`

interface PageTitleProps {
icon?: ReactElement
children: React.ReactNode
children: string
}
export const PageTitle = ({ children: title, icon }: PageTitleProps) => {
return (
<h1 className="text-sans-3xl text-accent-secondary light:text-accent-tertiary inline-flex items-center space-x-2">
<h1 className="text-sans-3xl text-accent-secondary light:text-accent-tertiary flex min-w-0 items-center gap-2 [&>svg]:shrink-0">
{icon}
<span className="text-accent light:text-raise">{title}</span>
<Truncate text={title} className="text-accent light:text-raise min-w-0 flex-1" />
</h1>
)
}
Loading
Loading