style(services): apply formatter to frontend services runtime
This commit is contained in:
@@ -71,7 +71,8 @@ function Field({
|
||||
}
|
||||
|
||||
function bindingLabel(serviceId: string | null, widgetKind: string): string {
|
||||
if (serviceId === null) return BUILTIN_WIDGETS[widgetKind]?.name ?? widgetKind;
|
||||
if (serviceId === null)
|
||||
return BUILTIN_WIDGETS[widgetKind]?.name ?? widgetKind;
|
||||
return widgetKind;
|
||||
}
|
||||
|
||||
@@ -116,8 +117,11 @@ function WidgetConfigEditor({
|
||||
|
||||
const properties = binding
|
||||
? Object.entries(
|
||||
(binding.configSchema as { properties?: Record<string, unknown> } | undefined)
|
||||
?.properties ?? {},
|
||||
(
|
||||
binding.configSchema as
|
||||
| { properties?: Record<string, unknown> }
|
||||
| undefined
|
||||
)?.properties ?? {},
|
||||
)
|
||||
: [];
|
||||
|
||||
@@ -188,8 +192,9 @@ export function WidgetConfigDialog({ open, onClose }: Props) {
|
||||
}
|
||||
|
||||
function startAddService(serviceId: string, kind: string) {
|
||||
const binding = SERVICE_REGISTRY[services.find((s) => s.id === serviceId)?.service_type ?? ""]
|
||||
?.widgets.find((w) => w.kind === kind);
|
||||
const binding = SERVICE_REGISTRY[
|
||||
services.find((s) => s.id === serviceId)?.service_type ?? ""
|
||||
]?.widgets.find((w) => w.kind === kind);
|
||||
setDraft({
|
||||
serviceId,
|
||||
widgetKind: kind,
|
||||
@@ -267,19 +272,27 @@ export function WidgetConfigDialog({ open, onClose }: Props) {
|
||||
|
||||
const draftBinding = draft
|
||||
? draft.serviceId
|
||||
? SERVICE_REGISTRY[services.find((s) => s.id === draft.serviceId)?.service_type ?? ""]
|
||||
?.widgets.find((w) => w.kind === draft.widgetKind)
|
||||
? SERVICE_REGISTRY[
|
||||
services.find((s) => s.id === draft.serviceId)?.service_type ?? ""
|
||||
]?.widgets.find((w) => w.kind === draft.widgetKind)
|
||||
: BUILTIN_WIDGETS[draft.widgetKind]
|
||||
: undefined;
|
||||
const isTaskOutput =
|
||||
draft?.serviceId !== null &&
|
||||
services.find((s) => s.id === draft?.serviceId)?.service_type === "ssh_tasks";
|
||||
services.find((s) => s.id === draft?.serviceId)?.service_type ===
|
||||
"ssh_tasks";
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={handleClose}>
|
||||
<DialogContent className="sm:max-w-2xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{draft ? (draft.id ? "Edit widget" : "Add widget") : "Dashboard widgets"}</DialogTitle>
|
||||
<DialogTitle>
|
||||
{draft
|
||||
? draft.id
|
||||
? "Edit widget"
|
||||
: "Add widget"
|
||||
: "Dashboard widgets"}
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
{draft ? (
|
||||
@@ -289,7 +302,9 @@ export function WidgetConfigDialog({ open, onClose }: Props) {
|
||||
<Input
|
||||
id="widget-title"
|
||||
value={draft.title}
|
||||
onChange={(e) => setDraft({ ...draft, title: e.target.value })}
|
||||
onChange={(e) =>
|
||||
setDraft({ ...draft, title: e.target.value })
|
||||
}
|
||||
/>
|
||||
</Field>
|
||||
<Field label="Sort order" htmlFor="widget-sort-order">
|
||||
@@ -300,7 +315,8 @@ export function WidgetConfigDialog({ open, onClose }: Props) {
|
||||
onChange={(e) =>
|
||||
setDraft({
|
||||
...draft,
|
||||
sortOrder: e.target.value === "" ? 0 : Number(e.target.value),
|
||||
sortOrder:
|
||||
e.target.value === "" ? 0 : Number(e.target.value),
|
||||
})
|
||||
}
|
||||
/>
|
||||
@@ -310,7 +326,9 @@ export function WidgetConfigDialog({ open, onClose }: Props) {
|
||||
<Switch
|
||||
id="widget-enabled"
|
||||
checked={draft.enabled}
|
||||
onCheckedChange={(checked) => setDraft({ ...draft, enabled: checked })}
|
||||
onCheckedChange={(checked) =>
|
||||
setDraft({ ...draft, enabled: checked })
|
||||
}
|
||||
/>
|
||||
<Label htmlFor="widget-enabled">Enabled</Label>
|
||||
</div>
|
||||
@@ -334,7 +352,9 @@ export function WidgetConfigDialog({ open, onClose }: Props) {
|
||||
<div className="flex flex-col gap-4">
|
||||
{sortedInstances.length === 0 ? (
|
||||
<Alert>
|
||||
<AlertDescription>No widgets yet. Add one below.</AlertDescription>
|
||||
<AlertDescription>
|
||||
No widgets yet. Add one below.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
) : (
|
||||
<div className="flex flex-col gap-2">
|
||||
@@ -343,31 +363,67 @@ export function WidgetConfigDialog({ open, onClose }: Props) {
|
||||
? services.find((s) => s.id === instance.service_id)?.name
|
||||
: "Built-in";
|
||||
return (
|
||||
<div key={instance.id} className="flex items-center gap-2 rounded border p-2">
|
||||
<div
|
||||
key={instance.id}
|
||||
className="flex items-center gap-2 rounded border p-2"
|
||||
>
|
||||
<div className="flex flex-1 flex-col gap-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium">{instance.title}</span>
|
||||
<Badge variant="outline">
|
||||
{bindingLabel(instance.service_id, instance.widget_kind)}
|
||||
{bindingLabel(
|
||||
instance.service_id,
|
||||
instance.widget_kind,
|
||||
)}
|
||||
</Badge>
|
||||
{serviceName ? (
|
||||
<span className="text-xs text-muted-foreground">{serviceName}</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{serviceName}
|
||||
</span>
|
||||
) : null}
|
||||
{!instance.enabled ? (
|
||||
<Badge variant="secondary">disabled</Badge>
|
||||
) : null}
|
||||
{!instance.enabled ? <Badge variant="secondary">disabled</Badge> : null}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<Button variant="ghost" size="icon" className="h-8 w-8" disabled={index === 0} onClick={() => moveInstance(index, -1)}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8"
|
||||
disabled={index === 0}
|
||||
onClick={() => moveInstance(index, -1)}
|
||||
>
|
||||
<ChevronUp className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon" className="h-8 w-8" disabled={index === sortedInstances.length - 1} onClick={() => moveInstance(index, 1)}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8"
|
||||
disabled={index === sortedInstances.length - 1}
|
||||
onClick={() => moveInstance(index, 1)}
|
||||
>
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
</Button>
|
||||
<Switch checked={instance.enabled} onCheckedChange={() => toggleEnabled(instance)} aria-label={`Toggle ${instance.title}`} />
|
||||
<Button variant="ghost" size="icon" className="h-8 w-8" onClick={() => startEdit(instance)}>
|
||||
<Switch
|
||||
checked={instance.enabled}
|
||||
onCheckedChange={() => toggleEnabled(instance)}
|
||||
aria-label={`Toggle ${instance.title}`}
|
||||
/>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8"
|
||||
onClick={() => startEdit(instance)}
|
||||
>
|
||||
<Pencil className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon" className="h-8 w-8 text-destructive" onClick={() => removeInstance(instance)}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8 text-destructive"
|
||||
onClick={() => removeInstance(instance)}
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
@@ -381,7 +437,12 @@ export function WidgetConfigDialog({ open, onClose }: Props) {
|
||||
<p className="text-sm font-medium">Add widget</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{Object.values(BUILTIN_WIDGETS).map((b) => (
|
||||
<Button key={b.kind} variant="outline" size="sm" onClick={() => startAddBuiltIn(b.kind)}>
|
||||
<Button
|
||||
key={b.kind}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => startAddBuiltIn(b.kind)}
|
||||
>
|
||||
<Plus className="mr-1 h-3 w-3" />
|
||||
{b.name}
|
||||
</Button>
|
||||
@@ -389,21 +450,24 @@ export function WidgetConfigDialog({ open, onClose }: Props) {
|
||||
{services
|
||||
.filter((s) => s.enabled)
|
||||
.flatMap((s) =>
|
||||
(SERVICE_REGISTRY[s.service_type]?.widgets ?? []).map((w) => (
|
||||
<Button
|
||||
key={`${s.id}:${w.kind}`}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => startAddService(s.id, w.kind)}
|
||||
>
|
||||
<Plus className="mr-1 h-3 w-3" />
|
||||
{w.name} · {s.name}
|
||||
</Button>
|
||||
)),
|
||||
(SERVICE_REGISTRY[s.service_type]?.widgets ?? []).map(
|
||||
(w) => (
|
||||
<Button
|
||||
key={`${s.id}:${w.kind}`}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => startAddService(s.id, w.kind)}
|
||||
>
|
||||
<Plus className="mr-1 h-3 w-3" />
|
||||
{w.name} · {s.name}
|
||||
</Button>
|
||||
),
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Configure services on their service pages to unlock more widgets.
|
||||
Configure services on their service pages to unlock more
|
||||
widgets.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user