Move the remaining panel explanations into tooltips
A node setting's description comes off the backend JSON schema, so every node type's panel still printed a paragraph under each field. It moves to the field label, which is the change that makes the node panel read as a list rather than a page. Alerts, Modules and Remote access follow the same shape. A page keeps a one-line description under its h1 — a page is arrived at rather than scanned — and the rest goes behind the heading's tooltip. Verified on the running stack: the tooltip opens on tap in the phone sheet and on hover on the desktop panel. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015YrQnKV3bnQd4K342y8tKj
This commit is contained in:
@@ -49,7 +49,13 @@ import {
|
|||||||
secretsQueryOptions,
|
secretsQueryOptions,
|
||||||
useParamSuggestions,
|
useParamSuggestions,
|
||||||
} from "./queries"
|
} from "./queries"
|
||||||
import { InfoTip, PANEL_SECTION, PanelTitle, SidePanel } from "./SidePanel"
|
import {
|
||||||
|
FieldLabel,
|
||||||
|
InfoTip,
|
||||||
|
PANEL_SECTION,
|
||||||
|
PanelTitle,
|
||||||
|
SidePanel,
|
||||||
|
} from "./SidePanel"
|
||||||
|
|
||||||
const NodeEditor = lazy(() => import("./NodeEditor"))
|
const NodeEditor = lazy(() => import("./NodeEditor"))
|
||||||
|
|
||||||
@@ -782,7 +788,14 @@ function ParamsForm({
|
|||||||
const reference = (params[key] ?? null) as { $secret?: string } | null
|
const reference = (params[key] ?? null) as { $secret?: string } | null
|
||||||
return (
|
return (
|
||||||
<div key={key} className="grid gap-1.5">
|
<div key={key} className="grid gap-1.5">
|
||||||
<Label className="text-sm font-normal">{label}</Label>
|
<FieldLabel
|
||||||
|
help={
|
||||||
|
property.description ||
|
||||||
|
"Stored in the secrets store, never in the flow file."
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</FieldLabel>
|
||||||
<Select
|
<Select
|
||||||
value={reference?.$secret ?? ""}
|
value={reference?.$secret ?? ""}
|
||||||
onValueChange={(name) =>
|
onValueChange={(name) =>
|
||||||
@@ -801,12 +814,11 @@ function ParamsForm({
|
|||||||
))}
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<p className="text-xs text-muted-foreground">
|
{secrets.length ? null : (
|
||||||
{secrets.length
|
<p className="text-xs text-muted-foreground">
|
||||||
? property.description ||
|
No secrets stored yet.
|
||||||
"Stored in the secrets store, never in the flow file."
|
</p>
|
||||||
: "No secrets stored yet."}
|
)}
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -819,9 +831,9 @@ function ParamsForm({
|
|||||||
property.type === "integer" || property.type === "number"
|
property.type === "integer" || property.type === "number"
|
||||||
return (
|
return (
|
||||||
<div key={key} className="grid gap-1.5">
|
<div key={key} className="grid gap-1.5">
|
||||||
<Label htmlFor={`param-${key}`} className="text-sm font-normal">
|
<FieldLabel htmlFor={`param-${key}`} help={property.description}>
|
||||||
{label}
|
{label}
|
||||||
</Label>
|
</FieldLabel>
|
||||||
<SuggestInput
|
<SuggestInput
|
||||||
id={`param-${key}`}
|
id={`param-${key}`}
|
||||||
className="h-8 text-sm"
|
className="h-8 text-sm"
|
||||||
@@ -831,11 +843,6 @@ function ParamsForm({
|
|||||||
empty="Nothing like that in use yet."
|
empty="Nothing like that in use yet."
|
||||||
onChange={(next) => set(key, numeric ? Number(next) : next)}
|
onChange={(next) => set(key, numeric ? Number(next) : next)}
|
||||||
/>
|
/>
|
||||||
{property.description ? (
|
|
||||||
<p className="text-xs text-muted-foreground">
|
|
||||||
{property.description}
|
|
||||||
</p>
|
|
||||||
) : null}
|
|
||||||
{key === "cron" ? (
|
{key === "cron" ? (
|
||||||
<CronHelp
|
<CronHelp
|
||||||
params={params}
|
params={params}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
|
|||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
|
|
||||||
import { CloudService } from "@/client"
|
import { CloudService } from "@/client"
|
||||||
|
import { InfoTip } from "@/components/Flow/SidePanel"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
@@ -154,15 +155,25 @@ export function RemoteAccess() {
|
|||||||
|
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-medium">Remote users</h3>
|
<div className="flex items-center gap-1">
|
||||||
|
<h3 className="font-medium">Remote users</h3>
|
||||||
|
<InfoTip label="Remote users">
|
||||||
|
They get a user of their own here, not yours, and never a
|
||||||
|
superuser, so they cannot pass access on.
|
||||||
|
</InfoTip>
|
||||||
|
</div>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Let someone else reach this instance through the portal. They
|
Let someone else reach this instance through the portal.
|
||||||
get a user of their own here — not yours, and never a
|
|
||||||
superuser, so they cannot pass access on.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid gap-2">
|
<div className="grid gap-2">
|
||||||
<Label htmlFor="join-code">Code</Label>
|
<div className="flex items-center gap-1">
|
||||||
|
<Label htmlFor="join-code">Code</Label>
|
||||||
|
<InfoTip label="Code">
|
||||||
|
Added users appear under Admin → Users; deleting them there
|
||||||
|
ends their access.
|
||||||
|
</InfoTip>
|
||||||
|
</div>
|
||||||
<Input
|
<Input
|
||||||
id="join-code"
|
id="join-code"
|
||||||
value={joinCode}
|
value={joinCode}
|
||||||
@@ -174,8 +185,6 @@ export function RemoteAccess() {
|
|||||||
/>
|
/>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
They get a code at fluksio.com → Instances → Join an instance.
|
They get a code at fluksio.com → Instances → Join an instance.
|
||||||
Added users appear under Admin → Users; deleting them there
|
|
||||||
ends their access.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { Bell, BellOff, Plus, Send, Trash2 } from "lucide-react"
|
|||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
|
|
||||||
import { type AlertsConfig, AlertsService, type Channel } from "@/client"
|
import { type AlertsConfig, AlertsService, type Channel } from "@/client"
|
||||||
|
import { InfoTip } from "@/components/Flow/SidePanel"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { Checkbox } from "@/components/ui/checkbox"
|
import { Checkbox } from "@/components/ui/checkbox"
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
@@ -161,9 +162,7 @@ function Alerts() {
|
|||||||
<div className="grid gap-1">
|
<div className="grid gap-1">
|
||||||
<h1 className="text-2xl">Alerts</h1>
|
<h1 className="text-2xl">Alerts</h1>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Where the engine goes when something breaks. A channel is somewhere to
|
Where the engine goes when something breaks.
|
||||||
send to; a rule says which failures go to which channels. The same
|
|
||||||
fault repeating is held back until its cooldown passes.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{data ? <AlertsForm initial={data} /> : null}
|
{data ? <AlertsForm initial={data} /> : null}
|
||||||
@@ -229,7 +228,14 @@ function AlertsForm({ initial }: { initial: AlertsConfig }) {
|
|||||||
|
|
||||||
<section className="grid gap-3">
|
<section className="grid gap-3">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h2 className={SECTION}>Channels</h2>
|
<div className="flex items-center gap-1">
|
||||||
|
<h2 className={SECTION}>Channels</h2>
|
||||||
|
<InfoTip label="Channels">
|
||||||
|
Somewhere to send to. A setting can hold{" "}
|
||||||
|
<code className="font-mono">{`{"$secret": "name"}`}</code> instead
|
||||||
|
of the value itself, and the stored secret is used.
|
||||||
|
</InfoTip>
|
||||||
|
</div>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
@@ -359,18 +365,17 @@ function AlertsForm({ initial }: { initial: AlertsConfig }) {
|
|||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
)}
|
)}
|
||||||
{channels.length > 0 ? (
|
|
||||||
<p className="text-xs text-muted-foreground">
|
|
||||||
A setting can hold{" "}
|
|
||||||
<code className="font-mono">{`{"$secret": "name"}`}</code> instead
|
|
||||||
of the value itself, and the stored secret is used.
|
|
||||||
</p>
|
|
||||||
) : null}
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="grid gap-3">
|
<section className="grid gap-3">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h2 className={SECTION}>Rules</h2>
|
<div className="flex items-center gap-1">
|
||||||
|
<h2 className={SECTION}>Rules</h2>
|
||||||
|
<InfoTip label="Rules">
|
||||||
|
Which failures go to which channels. The same fault repeating is
|
||||||
|
held back until its cooldown passes.
|
||||||
|
</InfoTip>
|
||||||
|
</div>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { Package } from "lucide-react"
|
|||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
|
|
||||||
import { type ApiError, ModulesService } from "@/client"
|
import { type ApiError, ModulesService } from "@/client"
|
||||||
|
import { InfoTip } from "@/components/Flow/SidePanel"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import useCustomToast from "@/hooks/useCustomToast"
|
import useCustomToast from "@/hooks/useCustomToast"
|
||||||
import { handleError } from "@/utils"
|
import { handleError } from "@/utils"
|
||||||
@@ -70,11 +71,16 @@ function Modules() {
|
|||||||
return (
|
return (
|
||||||
<div className="grid gap-6">
|
<div className="grid gap-6">
|
||||||
<div className="grid gap-1">
|
<div className="grid gap-1">
|
||||||
<h1 className="text-2xl">Modules</h1>
|
<div className="flex items-center gap-1">
|
||||||
|
<h1 className="text-2xl">Modules</h1>
|
||||||
|
<InfoTip label="Modules">
|
||||||
|
{adopted
|
||||||
|
? "Fluksio was installed into an environment you already had, so that is the one your nodes run on. Change it with pip or uv rather than from here."
|
||||||
|
: "Packages install into an environment of their own, separate from the engine's, so a version pinned here is the one your code gets. The list is kept with your flows, so a rebuilt deployment installs the same set again."}
|
||||||
|
</InfoTip>
|
||||||
|
</div>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
{adopted
|
The Python packages your function nodes can import.
|
||||||
? "The Python packages your function nodes can import. Fluksio was installed into an environment you already had, so that is the one your nodes run on — and it is yours to change, with pip or uv rather than from here."
|
|
||||||
: "The Python packages your function nodes can import. They are installed into an environment of their own, separate from the engine's, so a version you pin here is the one your code gets. The list is kept with your flows, so a rebuilt deployment installs the same set again."}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -139,7 +145,7 @@ function Modules() {
|
|||||||
) : null}
|
) : null}
|
||||||
{packages.length === 0 ? (
|
{packages.length === 0 ? (
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Nothing installed yet — node code has the standard library.
|
Nothing installed yet. Node code has the standard library.
|
||||||
</p>
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<div className="grid gap-2">
|
<div className="grid gap-2">
|
||||||
|
|||||||
Reference in New Issue
Block a user