-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add infrastructure tabs and content #2588
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { classNames } from '../utils' | ||
|
||
type ListProps<T> = { | ||
items: T[] | ||
renderItem: (item: T) => React.ReactNode | ||
onClick?: (item: T) => void | ||
className?: string | ||
} | ||
|
||
export const List = <T,>({ items, renderItem, onClick, className }: ListProps<T>) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you mean to remove this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh wow that's good to know! |
||
return ( | ||
<ul className={classNames('divide-y divide-gray-100 dark:divide-gray-700 overflow-hidden', className)}> | ||
{items.map((item, index) => ( | ||
<li | ||
key={index} | ||
className={`relative flex justify-between gap-x-6 p-4 ${onClick ? 'cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700' : ''}`} | ||
onClick={onClick ? () => onClick(item) : undefined} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to confirm, if you use this component without an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah should be ok. All the current stuff is using it without an |
||
> | ||
{renderItem(item)} | ||
</li> | ||
))} | ||
</ul> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import type React from 'react' | ||
import { classNames } from '../utils' | ||
|
||
type StatusIndicatorProps = { | ||
state: 'success' | 'error' | 'idle' | ||
text?: string | ||
} | ||
|
||
export const StatusIndicator: React.FC<StatusIndicatorProps> = ({ state, text }) => { | ||
const backgrounds = { | ||
idle: 'text-gray-500 bg-gray-500/20 dark:bg-gray-100/10', | ||
success: 'text-green-500 bg-emerald-500/20 dark:text-green-400 dark:bg-green-400/10 ', | ||
error: 'text-rose-500 bg-rose-500/20 dark:text-rose-400 dark:bg-rose-400/10', | ||
} | ||
|
||
return ( | ||
<div className='flex items-center gap-x-1.5'> | ||
<div className={classNames(backgrounds[state], 'flex-none rounded-full p-1')}> | ||
<div className='h-1.5 w-1.5 rounded-full bg-current' /> | ||
</div> | ||
{text && <p className='text-xs leading-5 text-gray-500'>{text}</p>} | ||
</div> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,29 @@ | ||
export const ControllersList = () => { | ||
return <>Controllers Content</> | ||
import { Badge } from '../../components/Badge' | ||
import { List } from '../../components/List' | ||
import type { StatusResponse_Controller } from '../../protos/xyz/block/ftl/v1/ftl_pb' | ||
|
||
export const ControllersList = ({ controllers }: { controllers: StatusResponse_Controller[] }) => { | ||
return ( | ||
<List | ||
items={controllers} | ||
renderItem={(controller) => ( | ||
<> | ||
<div className='flex min-w-0 gap-x-4'> | ||
<div className='min-w-0 flex-auto'> | ||
<p className='text-sm font-semibold leading-6'> | ||
<span className='absolute inset-x-0 -top-px bottom-0' /> | ||
{controller.key} | ||
</p> | ||
<p className='mt-1 flex text-xs leading-5 text-gray-500 dark:text-gray-400 font-roboto-mono'>{controller.endpoint}</p> | ||
</div> | ||
</div> | ||
<div className='flex shrink-0 items-center gap-x-4'> | ||
<div className='hidden sm:flex sm:flex-col sm:items-end'> | ||
<Badge name={controller.version} /> | ||
</div> | ||
</div> | ||
</> | ||
)} | ||
/> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,38 @@ | ||
export const DeploymentsList = () => { | ||
return <>Deployments Content</> | ||
import { AttributeBadge } from '../../components' | ||
import { Badge } from '../../components/Badge' | ||
import { List } from '../../components/List' | ||
import type { StatusResponse_Deployment } from '../../protos/xyz/block/ftl/v1/ftl_pb' | ||
import { classNames } from '../../utils' | ||
import { deploymentTextColor } from '../deployments/deployment.utils' | ||
import { renderValue } from './infrastructure.utils' | ||
|
||
export const DeploymentsList = ({ deployments }: { deployments: StatusResponse_Deployment[] }) => { | ||
return ( | ||
<List | ||
items={deployments} | ||
renderItem={(deployment) => ( | ||
<div className='flex w-full'> | ||
<div className='flex gap-x-4 items-center w-1/2'> | ||
<div className='whitespace-nowrap'> | ||
<div className='flex gap-x-2 items-center'> | ||
<p>{deployment.name}</p> | ||
<Badge name={deployment.language} /> | ||
</div> | ||
|
||
<p className={classNames(deploymentTextColor(deployment.key), 'text-sm font-semibold leading-6')}>{deployment.key}</p> | ||
</div> | ||
</div> | ||
<div className='flex gap-x-4 items-center w-1/2 justify-end'> | ||
<div className='flex flex-wrap gap-1'> | ||
<AttributeBadge key='replicas' name='replicas' value={deployment.replicas.toString()} /> | ||
<AttributeBadge key='min_replicas' name='min_replicas' value={deployment.minReplicas.toString()} /> | ||
{Object.entries(deployment.labels?.fields || {}).map(([key, value]) => ( | ||
<AttributeBadge key={key} name={key} value={renderValue(value)} /> | ||
))} | ||
</div> | ||
</div> | ||
</div> | ||
)} | ||
/> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,27 @@ | ||
export const RoutesList = () => { | ||
return <>Routes Content</> | ||
import { AttributeBadge } from '../../components' | ||
import { List } from '../../components/List' | ||
import type { StatusResponse_Route } from '../../protos/xyz/block/ftl/v1/ftl_pb' | ||
|
||
export const RoutesList = ({ routes }: { routes: StatusResponse_Route[] }) => { | ||
return ( | ||
<List | ||
items={routes} | ||
renderItem={(route) => ( | ||
<div className='flex w-full'> | ||
<div className='flex gap-x-4 items-center w-1/2'> | ||
<div className='whitespace-nowrap'> | ||
<div className='flex gap-x-2 items-center'>{route.module}</div> | ||
<p className='mt-1 flex text-xs leading-5 text-gray-500 dark:text-gray-400 font-roboto-mono'>{route.endpoint}</p> | ||
</div> | ||
</div> | ||
<div className='flex gap-x-4 items-center w-1/2 justify-end'> | ||
<div className='flex flex-wrap gap-1 justify-end'> | ||
<AttributeBadge name='deployment' value={route.deployment} /> | ||
<AttributeBadge name='runner' value={route.runner} /> | ||
</div> | ||
</div> | ||
</div> | ||
)} | ||
/> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,49 @@ | ||
export const RunnersList = () => { | ||
return <>Runners Content</> | ||
import { AttributeBadge } from '../../components' | ||
import { List } from '../../components/List' | ||
import { StatusIndicator } from '../../components/StatusIndicator' | ||
import { RunnerState, type StatusResponse_Runner } from '../../protos/xyz/block/ftl/v1/ftl_pb' | ||
import { classNames } from '../../utils' | ||
import { deploymentTextColor } from '../deployments/deployment.utils' | ||
import { renderValue } from './infrastructure.utils' | ||
|
||
export const RunnersList = ({ runners }: { runners: StatusResponse_Runner[] }) => { | ||
return ( | ||
<List | ||
items={runners} | ||
renderItem={(runner) => ( | ||
<> | ||
<div className='flex gap-x-4 items-center'> | ||
<div className='whitespace-nowrap'> | ||
<p className='text-sm font-semibold leading-6'>{runner.key}</p> | ||
<p className='mt-1 flex text-xs leading-5 text-gray-500 dark:text-gray-400 font-roboto-mono'>{runner.endpoint}</p> | ||
<div className='mt-1 flex gap-x-2 items-center'> | ||
{status(runner.state)} | ||
{runner.deployment && <p className={classNames(deploymentTextColor(runner.deployment), 'text-xs')}>{runner.deployment}</p>} | ||
</div> | ||
</div> | ||
</div> | ||
<div className='flex gap-x-4 items-center w-1/2'> | ||
<div className='flex flex-wrap gap-1 justify-end'> | ||
{Object.entries(runner.labels?.fields || {}).map(([key, value]) => ( | ||
<AttributeBadge key={key} name={key} value={renderValue(value)} /> | ||
))} | ||
</div> | ||
</div> | ||
</> | ||
)} | ||
/> | ||
) | ||
} | ||
|
||
const status = (state: RunnerState) => { | ||
switch (state) { | ||
case RunnerState.RUNNER_ASSIGNED: | ||
return <StatusIndicator state='success' text='Assigned' /> | ||
case RunnerState.RUNNER_RESERVED: | ||
return <StatusIndicator state='success' text='Reserved' /> | ||
case RunnerState.RUNNER_DEAD: | ||
return <StatusIndicator state='error' text='Dead' /> | ||
case RunnerState.RUNNER_IDLE: | ||
return <StatusIndicator state='idle' text='Idle' /> | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import type { Value } from '@bufbuild/protobuf' | ||
|
||
export const renderValue = (value: Value): string => { | ||
switch (value.kind?.case) { | ||
case 'numberValue': | ||
return value.kind.value.toString() | ||
case 'stringValue': | ||
return value.kind.value | ||
case 'boolValue': | ||
return value.kind.value ? 'true' : 'false' | ||
case 'structValue': | ||
return value.kind.value.toJsonString() | ||
case 'listValue': | ||
return value.kind.value.values.map(renderValue).join(', ') | ||
default: | ||
return '' | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for catching this!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You bet! I think there are going to be other similar issues after the relocating of all these files.