[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
This commit is contained in:
93
components/host/HostNotesEditor.tsx
Normal file
93
components/host/HostNotesEditor.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import { FileText } from "lucide-react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useI18n } from "../../application/i18n/I18nProvider";
|
||||
import { LazyMessageResponse } from "../ai-elements/LazyMessageResponse";
|
||||
import { ScrollArea } from "../ui/scroll-area";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs";
|
||||
import { Textarea } from "../ui/textarea";
|
||||
import { cn } from "../../lib/utils";
|
||||
|
||||
const PREVIEW_PROSE_CLASS =
|
||||
"text-sm text-foreground/90 [&>*:first-child]:mt-0 [&>*:last-child]:mb-0";
|
||||
|
||||
function defaultNotesTab(notes: string, preferredTab?: "edit" | "preview"): "edit" | "preview" {
|
||||
if (preferredTab) return preferredTab;
|
||||
return notes.trim() ? "preview" : "edit";
|
||||
}
|
||||
|
||||
export interface HostNotesEditorProps {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
/** Changes when opening a different host (e.g. host id) to reset the active tab */
|
||||
panelKey?: string;
|
||||
className?: string;
|
||||
showHeader?: boolean;
|
||||
defaultTab?: "edit" | "preview";
|
||||
}
|
||||
|
||||
export const HostNotesEditor: React.FC<HostNotesEditorProps> = ({
|
||||
value,
|
||||
onChange,
|
||||
panelKey,
|
||||
className,
|
||||
showHeader = true,
|
||||
defaultTab,
|
||||
}) => {
|
||||
const { t } = useI18n();
|
||||
const [tab, setTab] = useState<"edit" | "preview">(() => defaultNotesTab(value, defaultTab));
|
||||
|
||||
useEffect(() => {
|
||||
if (panelKey === undefined) return;
|
||||
setTab(defaultNotesTab(value, defaultTab));
|
||||
// Only reset tab when opening another host, not while editing notes.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps -- value read on panelKey change
|
||||
}, [panelKey, defaultTab]);
|
||||
|
||||
const trimmed = value.trim();
|
||||
|
||||
return (
|
||||
<div className={cn("space-y-2", className)}>
|
||||
{showHeader && (
|
||||
<>
|
||||
<div className="flex items-center gap-2">
|
||||
<FileText size={14} className="text-muted-foreground shrink-0" />
|
||||
<p className="text-xs font-semibold">
|
||||
{t("hostDetails.notes.label")}
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">{t("hostDetails.notes.help")}</p>
|
||||
</>
|
||||
)}
|
||||
<Tabs value={tab} onValueChange={(v) => setTab(v as "edit" | "preview")}>
|
||||
<TabsList className="h-8 w-full">
|
||||
<TabsTrigger value="edit" className="flex-1 text-xs">
|
||||
{t("hostDetails.notes.tab.edit")}
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="preview" className="flex-1 text-xs">
|
||||
{t("hostDetails.notes.tab.preview")}
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="edit" className="mt-2">
|
||||
<Textarea
|
||||
placeholder={t("hostDetails.notes.placeholder")}
|
||||
value={value}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
className="min-h-[120px] text-sm"
|
||||
rows={5}
|
||||
/>
|
||||
</TabsContent>
|
||||
<TabsContent value="preview" className="mt-2">
|
||||
<ScrollArea className="h-[120px] rounded-md border border-border/60 bg-muted/20 p-3">
|
||||
{trimmed ? (
|
||||
<LazyMessageResponse className={PREVIEW_PROSE_CLASS}>{trimmed}</LazyMessageResponse>
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{t("hostDetails.notes.preview.empty")}
|
||||
</p>
|
||||
)}
|
||||
</ScrollArea>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user