Skip to content
Merged
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
2 changes: 1 addition & 1 deletion app/components/EquivalentCliCommand.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Button } from '~/ui/lib/Button'
import { Modal } from '~/ui/lib/Modal'
import useTimeout from '~/ui/lib/use-timeout'

export default function EquivalentCliCommand({ command }: { command: string }) {
export function EquivalentCliCommand({ command }: { command: string }) {
const [isOpen, setIsOpen] = useState(false)
const [hasCopied, setHasCopied] = useState(false)

Expand Down
9 changes: 3 additions & 6 deletions app/pages/project/instances/instance/SerialConsolePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import { Link } from 'react-router-dom'
import { api } from '@oxide/api'
import { PrevArrow12Icon } from '@oxide/design-system/icons/react'

import EquivalentCliCommand from '~/components/EquivalentCliCommand'
import { EquivalentCliCommand } from '~/components/EquivalentCliCommand'
import { useInstanceSelector } from '~/hooks'
import { Badge, type BadgeColor } from '~/ui/lib/Badge'
import { Spinner } from '~/ui/lib/Spinner'
import { cliCmd } from '~/util/cli-cmd'
import { pb } from '~/util/path-builder'

const Terminal = lazy(() => import('~/components/Terminal'))
Expand Down Expand Up @@ -95,10 +96,6 @@ export function SerialConsolePage() {
}
}, [])

const command = `oxide instance serial console
--project ${project}
--instance ${instance}`

return (
<div className="!mx-0 flex h-full max-h-[calc(100vh-60px)] !w-full flex-col">
<Link
Expand All @@ -118,7 +115,7 @@ export function SerialConsolePage() {
<div className="flex-shrink-0 justify-between overflow-hidden border-t bg-default border-secondary empty:border-t-0">
<div className="gutter flex h-20 items-center justify-between">
<div>
<EquivalentCliCommand command={command} />
<EquivalentCliCommand command={cliCmd.serialConsole({ project, instance })} />
</div>

<Badge color={statusColor[connectionStatus]}>
Expand Down
27 changes: 20 additions & 7 deletions app/pages/project/instances/instance/tabs/ConnectTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,33 @@
* Copyright Oxide Computer Company
*/

import { Link } from 'react-router-dom'

import { EquivalentCliCommand } from '~/components/EquivalentCliCommand'
import { useInstanceSelector } from '~/hooks'
import { buttonStyle } from '~/ui/lib/Button'
import { SettingsGroup } from '~/ui/lib/SettingsGroup'
import { cliCmd } from '~/util/cli-cmd'
import { pb } from '~/util/path-builder'

export function ConnectTab() {
const { project, instance } = useInstanceSelector()

return (
<SettingsGroup
title="Serial Console"
cta={pb.serialConsole({ project, instance })}
ctaText="Connect"
>
Connect to your instance&rsquo;s serial console
</SettingsGroup>
<SettingsGroup.Container>
<SettingsGroup.Body>
<SettingsGroup.Title>Serial console</SettingsGroup.Title>
Connect to your instance&rsquo;s serial console
</SettingsGroup.Body>
<SettingsGroup.Footer>
<EquivalentCliCommand command={cliCmd.serialConsole({ project, instance })} />
Copy link
Collaborator

@david-crespo david-crespo Mar 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with the refactors separated out, this PR would only have required adding this one line

<Link
to={pb.serialConsole({ project, instance })}
className={buttonStyle({ size: 'sm' })}
>
Connect
</Link>
</SettingsGroup.Footer>
</SettingsGroup.Container>
)
}
47 changes: 30 additions & 17 deletions app/ui/lib/SettingsGroup.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,40 @@
*
* Copyright Oxide Computer Company
*/
import { Link } from 'react-router-dom'

import { Button, buttonStyle } from './Button'
import { SettingsGroup } from './SettingsGroup'

export const Default = () => (
<SettingsGroup
title="Serial Console"
docs={{ text: 'Serial Console', link: '/' }}
cta="/"
ctaText="Connect"
>
Connect to your instance&rsquo;s serial console
</SettingsGroup>
<SettingsGroup.Container>
<SettingsGroup.Body>
<SettingsGroup.Title>Serial console</SettingsGroup.Title>
Connect to your instance&rsquo;s serial console
</SettingsGroup.Body>
<SettingsGroup.Footer
docsLink={{ text: 'math', href: 'https://en.wikipedia.org/wiki/Mathematics' }}
>
<Link to="/" className={buttonStyle({ size: 'sm' })}>
Connect
</Link>
</SettingsGroup.Footer>
</SettingsGroup.Container>
)

export const WithoutDocs = () => (
<SettingsGroup title="Serial Console" cta="/" ctaText="Connect">
Connect to your instance&rsquo;s serial console
</SettingsGroup>
)

export const FunctionAction = () => (
<SettingsGroup title="Serial Console" cta={() => alert('hi')} ctaText="Connect">
Connect to your instance&rsquo;s serial console
</SettingsGroup>
<SettingsGroup.Container>
<SettingsGroup.Body>
<SettingsGroup.Title>Serial console</SettingsGroup.Title>
Connect to your instance&rsquo;s serial console
</SettingsGroup.Body>
<SettingsGroup.Footer>
<Link to="/" className={buttonStyle({ size: 'sm' })}>
Connect
</Link>
<Button size="sm" variant="secondary" onClick={() => {}}>
Secondary
</Button>
</SettingsGroup.Footer>
</SettingsGroup.Container>
)
68 changes: 25 additions & 43 deletions app/ui/lib/SettingsGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,55 +5,37 @@
*
* Copyright Oxide Computer Company
*/
import { Link } from 'react-router-dom'

import { OpenLink12Icon } from '@oxide/design-system/icons/react'

import { Button, buttonStyle } from '~/ui/lib/Button'
import { classed } from '~/util/classed'

type Props = {
title: string
docs?: {
text: string
link: string
}
const LearnMore = ({ href, text }: { href: string; text: React.ReactNode }) => (
<>
Learn more about{' '}
<a href={href} className="text-accent-secondary hover:text-accent">
{text}
<OpenLink12Icon className="ml-1 align-middle" />
</a>
</>
)

type FooterProps = {
/** Link text */
children: React.ReactNode
/** String action is a link */
cta: string | (() => void)
ctaText: string
docsLink?: { text: string; href: string }
}

export const SettingsGroup = ({ title, docs, children, cta, ctaText }: Props) => {
return (
<div className="w-full max-w-[660px] rounded-lg border text-sans-md text-secondary border-default">
<div className="p-6">
<div className="mb-1 text-sans-lg text-default">{title}</div>
{children}
</div>
<div className="flex items-center justify-between border-t px-6 py-3 border-default">
{/* div always present to keep the button right-aligned */}
<div className="text-tertiary">
{docs && (
<>
Learn more about{' '}
<a href={docs.link} className="text-accent-secondary hover:text-accent">
{docs.text}
<OpenLink12Icon className="ml-1 align-middle" />
</a>
</>
)}
</div>

{typeof cta === 'string' ? (
<Link to={cta} className={buttonStyle({ size: 'sm' })}>
{ctaText}
</Link>
) : (
<Button size="sm" onClick={cta}>
{ctaText}
</Button>
)}
</div>
/** Use size=sm on buttons and links! */
export const SettingsGroup = {
Container: classed.div`w-full max-w-[660px] rounded-lg border text-sans-md text-secondary border-default`,
Body: classed.div`p-6`,
Title: classed.div`mb-1 text-sans-lg text-default`,
Footer: ({ children, docsLink }: FooterProps) => (
<div className="flex items-center justify-between border-t px-6 py-3 border-default">
{/* div always present to keep the buttons right-aligned */}
<div className="text-tertiary">{docsLink && <LearnMore {...docsLink} />}</div>
<div className="flex gap-3">{children}</div>
</div>
)
),
}
12 changes: 12 additions & 0 deletions app/util/cli-cmd.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* Copyright Oxide Computer Company
*/

export const cliCmd = {
serialConsole: ({ project, instance }: { project: string; instance: string }) =>
`oxide instance serial console\n--project ${project}\n--instance ${instance}`,
}