Files
windmill/frontend/src/lib/components/graph/PaneContextMenu.svelte
T
GuilhemandRuben Fiszel cfeb294308 feat(frontend): add notes to flow (#6628)
* Add note component

* save note size and position

* move add note button up

* nit

* Add markdown support

* wip

* fix add sticky note button

* fix text update

* Add sticky note to saved flow data

* add note color picker

* Introduce node multiselect

* Add group notes

* Adapt layout to group node

* create a note manager class

* clean reactivity

* clean

* improve adaptive layout to group note

* modify layout based on cached text height

* fined grained graph rendering for notes

* separate noteManager into editor and render

* separate noteManager into editor and render

* create a note change observer

* render note node from context

* simplify note state managment

* show note in flow viewer

* clean dirty changes

* clean selection manager

* fix layout check

* improve bg surface select

* Handle z-index for stacked group notes

* clean selection manager

* exclude notes from rect select

* Allow switch between selection modes with keyboard keys

* improve selection box styling

* prevent dragging note when editing

* nit

* Simplify selection using svelte flow built in feature

* handle note selection separately

* Add min size for notes

* improve selection toggle

* improve mode switch

* make size and position optional for group notes

* Improve initial viewport position

* Add context menu for the canevas

* nit

* Add node context menu

* improve note select

* use clickoutside for note deselect

* use pointerdown outside to close context menu

* nit

* fix selection issues

* make edges non selectable

* improve color palette

* fix backend

* fix backend check

* cargo lock restore

* Add toggle to display notes

* fix note selection

* nit

* account for css offset in for loop

* fix multiple selection pannel styling

* clear flow selection when creating note

* Improve placeholder and note default text

* Escape note edit mode when pressing Esc

* Allow note edition in local dev

* clean

* Handle subflow selection

* prevent group note resizing

* nit

* allow notes in flow expand

* Improve multi select panel

* Allow context menu in note mode

* Add event listenner to fix pane click deselect

* prevent zoom in text area in notes

* improve bounding box styling

* Use control for box selection for non mac users

* nit

* clean notes groups

* nit

* use portal for note actions

* handle assets node when computing note layout

* Simplify layout compute for notes

* use smart color choice for notes

* Switch display note when adding a new note

* clean code

* improve group note bound size calculation

* simplify AI tool nodes and asset handling

* nit

* nit

* improve flow centering

* create group note button

* Improve selection of nodes

* Revert "Improve selection of nodes"

This reverts commit d2c40d82b1.

* refert backend changes

* nit

* improve graph selection

* clean

* make backend work except job runs

* fix notSelectable

---------

Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2025-11-19 21:25:57 +00:00

116 lines
2.9 KiB
Svelte

<script lang="ts">
import { useSvelteFlow } from '@xyflow/svelte'
import { StickyNote } from 'lucide-svelte'
import { getNoteEditorContext } from './noteEditor.svelte'
import { DEFAULT_NOTE_COLOR } from './noteColors'
import { fly } from 'svelte/transition'
import {
getContextMenuContainerClass,
CONTEXT_MENU_ITEM_BASE_CLASS,
CONTEXT_MENU_ITEM_HOVER_CLASS
} from '../common/contextmenu/contextMenuStyles'
import { getGraphContext } from './graphContext'
interface Props {
editMode?: boolean
}
let { editMode = false }: Props = $props()
const { screenToFlowPosition } = useSvelteFlow()
const noteEditorContext = getNoteEditorContext()
const graphContext = getGraphContext()
let contextMenuVisible = $state(false)
let contextMenuPosition = $state<{ x: number; y: number }>({ x: 0, y: 0 })
let pendingFlowPosition = $state<{ x: number; y: number } | null>(null)
function handlePaneContextMenu(event: MouseEvent) {
// Only show context menu in edit mode
if (!editMode || !noteEditorContext?.noteEditor) {
return
}
event.preventDefault()
event.stopPropagation()
// Store screen coordinates for context menu positioning
contextMenuPosition = {
x: event.clientX,
y: event.clientY
}
// Convert to flow coordinates for note placement
pendingFlowPosition = screenToFlowPosition({
x: event.clientX,
y: event.clientY
})
contextMenuVisible = true
}
function handleAddStickyNote() {
if (noteEditorContext?.noteEditor && pendingFlowPosition) {
noteEditorContext.noteEditor.addNote({
text: '### Free note\nDouble click to edit me',
position: {
x: pendingFlowPosition.x,
y: pendingFlowPosition.y - (graphContext?.yOffset || 0)
},
size: { width: 300, height: 200 },
color: DEFAULT_NOTE_COLOR,
type: 'free',
locked: false
})
}
contextMenuVisible = false
}
// Export the handler to be used by parent
export function onPaneContextMenu(event: MouseEvent) {
handlePaneContextMenu(event)
}
</script>
{#if contextMenuVisible}
<!-- Context menu -->
<div
class="fixed {getContextMenuContainerClass('z-[9999]')}"
style="left: {contextMenuPosition.x}px; top: {contextMenuPosition.y}px;"
transition:fly={{ duration: 150, y: -10 }}
role="menu"
tabindex="-1"
onclick={(e) => {
e.stopPropagation()
}}
onkeydown={(e) => {
if (e.key === 'Escape') {
contextMenuVisible = false
}
}}
>
<button
class="{CONTEXT_MENU_ITEM_BASE_CLASS} {CONTEXT_MENU_ITEM_HOVER_CLASS}"
onclick={handleAddStickyNote}
type="button"
>
<StickyNote size={14} class="mr-2" />
<span>Add sticky note</span>
</button>
</div>
<!-- Invisible click catcher to close context menu -->
<div
class="fixed inset-0 z-[9998]"
role="presentation"
onclick={() => {
contextMenuVisible = false
}}
oncontextmenu={(e) => {
e.preventDefault()
contextMenuVisible = false
}}
></div>
{/if}