+2
-2
@@ -2,8 +2,8 @@ FROM python:3.13-slim
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Install nmap for network scanning + iputils-ping for ping-based status checks
|
# Install nmap for network scanning + iputils-ping for ping-based status checks + curl for the health check
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends nmap iputils-ping && rm -rf /var/lib/apt/lists/*
|
RUN apt-get update && apt-get install -y --no-install-recommends nmap iputils-ping curl && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
COPY backend/requirements.txt .
|
COPY backend/requirements.txt .
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||||
import { render, screen } from '@testing-library/react'
|
import { fireEvent, render, screen } from '@testing-library/react'
|
||||||
import { GroupNode } from '../nodes/GroupNode'
|
import { GroupNode } from '../nodes/GroupNode'
|
||||||
import * as canvasStore from '@/stores/canvasStore'
|
import * as canvasStore from '@/stores/canvasStore'
|
||||||
import type { Node } from '@xyflow/react'
|
import type { Node } from '@xyflow/react'
|
||||||
@@ -102,6 +102,19 @@ describe('GroupNode', () => {
|
|||||||
expect(screen.getByTestId('node-resizer').getAttribute('data-visible')).toBe('true')
|
expect(screen.getByTestId('node-resizer').getAttribute('data-visible')).toBe('true')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('allows dragging from the header while keeping rename controls nodrag', () => {
|
||||||
|
renderGroupNode({ selected: true })
|
||||||
|
|
||||||
|
expect(screen.getByText('My Group').closest('div')).not.toHaveClass('nodrag')
|
||||||
|
|
||||||
|
const renameButton = screen.getByTitle('Rename group')
|
||||||
|
expect(renameButton).toHaveClass('nodrag')
|
||||||
|
|
||||||
|
fireEvent.click(renameButton)
|
||||||
|
|
||||||
|
expect(screen.getByDisplayValue('My Group')).toHaveClass('nodrag')
|
||||||
|
})
|
||||||
|
|
||||||
it('shows online/offline status summary from children', () => {
|
it('shows online/offline status summary from children', () => {
|
||||||
const storeNodes = [
|
const storeNodes = [
|
||||||
{ id: 'c1', parentId: 'g1', data: { status: 'online' } },
|
{ id: 'c1', parentId: 'g1', data: { status: 'online' } },
|
||||||
|
|||||||
@@ -66,13 +66,13 @@ export function GroupNode({ id, data, selected }: NodeProps<Node<NodeData>>) {
|
|||||||
borderBottom: isVisible ? `1px solid ${borderColor}40` : 'none',
|
borderBottom: isVisible ? `1px solid ${borderColor}40` : 'none',
|
||||||
pointerEvents: 'auto',
|
pointerEvents: 'auto',
|
||||||
}}
|
}}
|
||||||
className="nodrag"
|
|
||||||
>
|
>
|
||||||
<Layers size={12} style={{ color: '#00d4ff', flexShrink: 0 }} />
|
<Layers size={12} style={{ color: '#00d4ff', flexShrink: 0 }} />
|
||||||
|
|
||||||
{editing ? (
|
{editing ? (
|
||||||
<input
|
<input
|
||||||
autoFocus
|
autoFocus
|
||||||
|
className="nodrag"
|
||||||
value={labelDraft}
|
value={labelDraft}
|
||||||
onChange={(e) => setLabelDraft(e.target.value)}
|
onChange={(e) => setLabelDraft(e.target.value)}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
@@ -97,11 +97,12 @@ export function GroupNode({ id, data, selected }: NodeProps<Node<NodeData>>) {
|
|||||||
|
|
||||||
{editing ? (
|
{editing ? (
|
||||||
<>
|
<>
|
||||||
<button onClick={handleRename} style={{ color: '#39d353', background: 'none', border: 'none', cursor: 'pointer', padding: 1 }}><Check size={11} /></button>
|
<button className="nodrag" onClick={handleRename} style={{ color: '#39d353', background: 'none', border: 'none', cursor: 'pointer', padding: 1 }}><Check size={11} /></button>
|
||||||
<button onClick={() => { setLabelDraft(data.label); setEditing(false) }} style={{ color: '#f85149', background: 'none', border: 'none', cursor: 'pointer', padding: 1 }}><X size={11} /></button>
|
<button className="nodrag" onClick={() => { setLabelDraft(data.label); setEditing(false) }} style={{ color: '#f85149', background: 'none', border: 'none', cursor: 'pointer', padding: 1 }}><X size={11} /></button>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<button
|
<button
|
||||||
|
className="nodrag"
|
||||||
onClick={() => { setLabelDraft(data.label); setEditing(true) }}
|
onClick={() => { setLabelDraft(data.label); setEditing(true) }}
|
||||||
style={{ color: '#8b949e', background: 'none', border: 'none', cursor: 'pointer', padding: 1, opacity: selected ? 1 : 0 }}
|
style={{ color: '#8b949e', background: 'none', border: 'none', cursor: 'pointer', padding: 1, opacity: selected ? 1 : 0 }}
|
||||||
title="Rename group"
|
title="Rename group"
|
||||||
|
|||||||
Reference in New Issue
Block a user