feat(liveview): header View link opens active design as read-only canvas
Add an authenticated GET /api/v1/liveview/config endpoint exposing the configured LIVEVIEW_KEY to logged-in admins, so the UI builds a ready-to-use share link. The header View button opens /view?key=...&design=<activeDesignId>; LiveView forwards ?design=<id> to the public endpoint, which renders that design's canvas. ha-relevant: maybe
This commit is contained in:
@@ -68,10 +68,14 @@ function LiveViewCanvas() {
|
||||
}
|
||||
|
||||
// Already handled synchronously in useState initializer
|
||||
const key = new URLSearchParams(window.location.search).get('key')
|
||||
const search = new URLSearchParams(window.location.search)
|
||||
const key = search.get('key')
|
||||
if (!key) return
|
||||
// Optional ?design=<id> selects which canvas to render; backend falls back
|
||||
// to the first design when omitted.
|
||||
const design = search.get('design') ?? undefined
|
||||
|
||||
liveviewApi.load(key)
|
||||
liveviewApi.load(key, design)
|
||||
.then((res) => {
|
||||
const { nodes: apiNodes, edges: apiEdges } = res.data
|
||||
const proxmoxMap = new Map<string, boolean>(
|
||||
|
||||
@@ -118,7 +118,15 @@ describe('LiveView (non-standalone)', () => {
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('react-flow')).toBeDefined()
|
||||
})
|
||||
expect(liveviewApi.load).toHaveBeenCalledWith('correct-key')
|
||||
expect(liveviewApi.load).toHaveBeenCalledWith('correct-key', undefined)
|
||||
})
|
||||
|
||||
it('forwards ?design=<id> to the API so a specific canvas is loaded', async () => {
|
||||
setSearch('?key=correct-key&design=elec-123')
|
||||
vi.mocked(liveviewApi.load).mockResolvedValue(canvasPayload as never)
|
||||
render(<LiveView />)
|
||||
await waitFor(() => expect(screen.getByTestId('react-flow')).toBeDefined())
|
||||
expect(liveviewApi.load).toHaveBeenCalledWith('correct-key', 'elec-123')
|
||||
})
|
||||
|
||||
it('allows zooming out to 0.25 so large infra fits (matches the editor)', async () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useRef } from 'react'
|
||||
import { Save, LayoutDashboard, Download, Palette, Undo2, Redo2, HelpCircle, Table2, FileDown, Upload } from 'lucide-react'
|
||||
import { Save, LayoutDashboard, Download, Palette, Undo2, Redo2, HelpCircle, Table2, FileDown, Upload, Eye } from 'lucide-react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Logo } from '@/components/ui/Logo'
|
||||
import { useCanvasStore } from '@/stores/canvasStore'
|
||||
@@ -15,9 +15,10 @@ interface ToolbarProps {
|
||||
onExportMd: () => void
|
||||
onExportYaml: () => void
|
||||
onImportYaml: (content: string) => void
|
||||
onViewOnly: () => void
|
||||
}
|
||||
|
||||
export function Toolbar({ onSave, onAutoLayout, onExport, onChangeStyle, onUndo, onRedo, onShortcuts, onExportMd, onExportYaml, onImportYaml }: ToolbarProps) {
|
||||
export function Toolbar({ onSave, onAutoLayout, onExport, onChangeStyle, onUndo, onRedo, onShortcuts, onExportMd, onExportYaml, onImportYaml, onViewOnly }: ToolbarProps) {
|
||||
const { hasUnsavedChanges, past, future } = useCanvasStore()
|
||||
const fileInputRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
@@ -81,6 +82,9 @@ export function Toolbar({ onSave, onAutoLayout, onExport, onChangeStyle, onUndo,
|
||||
<Button size="sm" variant="ghost" className="gap-1.5 text-muted-foreground hover:text-foreground cursor-pointer hover:bg-[#21262d]" onClick={onExportMd} title="Copy inventory as Markdown table">
|
||||
<Table2 size={14} /> MD
|
||||
</Button>
|
||||
<Button size="sm" variant="ghost" className="gap-1.5 text-muted-foreground hover:text-foreground cursor-pointer hover:bg-[#21262d]" onClick={onViewOnly} title="Open read-only live view of this canvas">
|
||||
<Eye size={14} /> View
|
||||
</Button>
|
||||
<Button size="sm" variant="ghost" className="gap-1.5 text-muted-foreground hover:text-foreground cursor-pointer hover:bg-[#21262d]" onClick={onShortcuts} title="Keyboard shortcuts (?)">
|
||||
<HelpCircle size={14} />
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user