UNPKG

@ichigo_san/graphing

Version:

A lightweight UML-style diagram editor built with React Flow and Tailwind CSS

242 lines (236 loc) 14.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireWildcard(require("react")); var _lucideReact = require("lucide-react"); var _technicalDetailsParser = require("../utils/technicalDetailsParser"); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } const TechnicalDetailsPanel = ({ selectedElement, onClose, isOpen, position }) => { var _selectedElement$data, _selectedElement$data2, _selectedElement$data3; const [isVisible, setIsVisible] = (0, _react.useState)(false); const [isDragging, setIsDragging] = (0, _react.useState)(false); const [dragOffset, setDragOffset] = (0, _react.useState)({ x: 0, y: 0 }); const [manualPosition, setManualPosition] = (0, _react.useState)(null); const panelRef = (0, _react.useRef)(null); const positionTimeoutRef = (0, _react.useRef)(null); (0, _react.useEffect)(() => { if (isOpen && selectedElement) { setIsVisible(true); setManualPosition(null); // Reset manual position on new selection } else { setIsVisible(false); } }, [isOpen, selectedElement]); // Debounced position update to reduce ResizeObserver calls (0, _react.useEffect)(() => { if (position && !manualPosition) { if (positionTimeoutRef.current) { clearTimeout(positionTimeoutRef.current); } positionTimeoutRef.current = setTimeout(() => { setManualPosition(position); }, 25); // Reduced delay for more responsive movement } return () => { if (positionTimeoutRef.current) { clearTimeout(positionTimeoutRef.current); } }; }, [position, manualPosition]); // Immediate position update for better responsiveness (0, _react.useEffect)(() => { if (position && !isDragging) { // Update position immediately if not dragging setManualPosition(position); } }, [position, isDragging]); // Dragging functionality const handleMouseDown = (0, _react.useCallback)(e => { if (e.target.closest('button')) return; // Don't drag if clicking buttons setIsDragging(true); const rect = panelRef.current.getBoundingClientRect(); setDragOffset({ x: e.clientX - rect.left, y: e.clientY - rect.top }); e.preventDefault(); }, []); const handleMouseMove = (0, _react.useCallback)(e => { if (!isDragging) return; const newX = e.clientX - dragOffset.x; const newY = e.clientY - dragOffset.y; // Keep panel within viewport bounds const maxX = window.innerWidth - 320; const maxY = window.innerHeight - 400; setManualPosition({ x: Math.max(10, Math.min(newX, maxX)), y: Math.max(10, Math.min(newY, maxY)) }); }, [isDragging, dragOffset]); const handleMouseUp = (0, _react.useCallback)(() => { setIsDragging(false); }, []); (0, _react.useEffect)(() => { if (isDragging) { document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleMouseUp); return () => { document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); }; } }, [isDragging, handleMouseMove, handleMouseUp]); if (!isOpen || !selectedElement) return null; const isNode = selectedElement.type === 'node'; const technicalDetails = isNode ? (0, _technicalDetailsParser.extractTechnicalDetails)(selectedElement) : (0, _technicalDetailsParser.extractConnectionTechnicalDetails)(selectedElement); const elementLabel = ((_selectedElement$data = selectedElement.data) === null || _selectedElement$data === void 0 ? void 0 : _selectedElement$data.label) || selectedElement.label || 'Unknown Element'; // Get icon based on element type and technical details const getElementIcon = () => { if (isNode) { if (technicalDetails.infrastructure.includes('Kubernetes')) return /*#__PURE__*/_react.default.createElement(_lucideReact.Server, { className: "w-4 h-4" }); if (technicalDetails.protocol.includes('HTTP')) return /*#__PURE__*/_react.default.createElement(_lucideReact.Network, { className: "w-4 h-4" }); if (technicalDetails.monitoring.includes('Prometheus')) return /*#__PURE__*/_react.default.createElement(_lucideReact.Activity, { className: "w-4 h-4" }); return /*#__PURE__*/_react.default.createElement(_lucideReact.Database, { className: "w-4 h-4" }); } else { return /*#__PURE__*/_react.default.createElement(_lucideReact.Network, { className: "w-4 h-4" }); } }; // Use manual position if set, otherwise use the position prop directly const panelPos = manualPosition || position || { x: 100, y: 100 }; return /*#__PURE__*/_react.default.createElement("div", { ref: panelRef, className: `fixed z-40 transition-all duration-150 ease-out ${isVisible ? 'opacity-100 scale-100' : 'opacity-0 scale-95'} ${isDragging ? 'cursor-grabbing' : 'cursor-grab'}`, style: { left: panelPos.x, top: panelPos.y, transform: isVisible ? 'translate(0, 0)' : 'translate(10px, -10px)', userSelect: isDragging ? 'none' : 'auto', willChange: 'transform, opacity' // Optimize for animations }, onMouseDown: handleMouseDown }, /*#__PURE__*/_react.default.createElement("div", { className: "w-80 bg-white/95 dark:bg-gray-900/95 backdrop-blur-md border border-gray-200/50 dark:border-gray-700/50 rounded-xl shadow-xl" }, /*#__PURE__*/_react.default.createElement("div", { className: "flex items-center justify-between p-4 border-b border-gray-100 dark:border-gray-800" }, /*#__PURE__*/_react.default.createElement("div", { className: "flex items-center gap-3" }, /*#__PURE__*/_react.default.createElement("div", { className: "p-1.5 bg-blue-100 dark:bg-blue-900/30 rounded-lg" }, getElementIcon()), /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("h3", { className: "text-sm font-semibold text-gray-900 dark:text-white" }, elementLabel), /*#__PURE__*/_react.default.createElement("p", { className: "text-xs text-gray-500 dark:text-gray-400" }, "Technical Details"))), /*#__PURE__*/_react.default.createElement("button", { onClick: onClose, className: "p-1 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg transition-colors" }, /*#__PURE__*/_react.default.createElement(_lucideReact.X, { size: 16, className: "text-gray-400" }))), /*#__PURE__*/_react.default.createElement("div", { className: "p-4 space-y-3 max-h-64 overflow-y-auto" }, technicalDetails.protocol !== 'N/A' && /*#__PURE__*/_react.default.createElement("div", { className: "flex items-center gap-2 p-2 bg-blue-50 dark:bg-blue-900/20 rounded-lg" }, /*#__PURE__*/_react.default.createElement(_lucideReact.Network, { className: "w-3 h-3 text-blue-500" }), /*#__PURE__*/_react.default.createElement("span", { className: "text-xs font-medium text-blue-700 dark:text-blue-300" }, technicalDetails.protocol)), (technicalDetails.performance.latency || technicalDetails.performance.throughput || technicalDetails.performance.timeout) && /*#__PURE__*/_react.default.createElement("div", { className: "flex items-center gap-2 p-2 bg-yellow-50 dark:bg-yellow-900/20 rounded-lg" }, /*#__PURE__*/_react.default.createElement(_lucideReact.Zap, { className: "w-3 h-3 text-yellow-500" }), /*#__PURE__*/_react.default.createElement("div", { className: "flex flex-wrap gap-1" }, technicalDetails.performance.latency && /*#__PURE__*/_react.default.createElement("span", { className: "text-xs bg-yellow-100 dark:bg-yellow-800/30 text-yellow-800 dark:text-yellow-200 px-2 py-0.5 rounded-full" }, technicalDetails.performance.latency), technicalDetails.performance.throughput && /*#__PURE__*/_react.default.createElement("span", { className: "text-xs bg-purple-100 dark:bg-purple-800/30 text-purple-800 dark:text-purple-200 px-2 py-0.5 rounded-full" }, technicalDetails.performance.throughput, " req/s"), technicalDetails.performance.timeout && /*#__PURE__*/_react.default.createElement("span", { className: "text-xs bg-orange-100 dark:bg-orange-800/30 text-orange-800 dark:text-orange-200 px-2 py-0.5 rounded-full" }, technicalDetails.performance.timeout, "s"))), technicalDetails.security !== 'N/A' && /*#__PURE__*/_react.default.createElement("div", { className: "flex items-center gap-2 p-2 bg-green-50 dark:bg-green-900/20 rounded-lg" }, /*#__PURE__*/_react.default.createElement(_lucideReact.Shield, { className: "w-3 h-3 text-green-500" }), /*#__PURE__*/_react.default.createElement("div", { className: "flex flex-wrap gap-1" }, technicalDetails.security.split(', ').map((sec, index) => /*#__PURE__*/_react.default.createElement("span", { key: index, className: "text-xs bg-green-100 dark:bg-green-800/30 text-green-800 dark:text-green-200 px-2 py-0.5 rounded-full" }, sec.trim())))), isNode && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, technicalDetails.scaling !== 'N/A' && /*#__PURE__*/_react.default.createElement("div", { className: "flex items-center gap-2 p-2 bg-indigo-50 dark:bg-indigo-900/20 rounded-lg" }, /*#__PURE__*/_react.default.createElement(_lucideReact.Activity, { className: "w-3 h-3 text-indigo-500" }), /*#__PURE__*/_react.default.createElement("div", { className: "flex flex-wrap gap-1" }, technicalDetails.scaling.split(', ').map((scale, index) => /*#__PURE__*/_react.default.createElement("span", { key: index, className: "text-xs bg-indigo-100 dark:bg-indigo-800/30 text-indigo-800 dark:text-indigo-200 px-2 py-0.5 rounded-full" }, scale.trim())))), technicalDetails.infrastructure !== 'N/A' && /*#__PURE__*/_react.default.createElement("div", { className: "flex items-center gap-2 p-2 bg-cyan-50 dark:bg-cyan-900/20 rounded-lg" }, /*#__PURE__*/_react.default.createElement(_lucideReact.Server, { className: "w-3 h-3 text-cyan-500" }), /*#__PURE__*/_react.default.createElement("div", { className: "flex flex-wrap gap-1" }, technicalDetails.infrastructure.split(', ').map((infra, index) => /*#__PURE__*/_react.default.createElement("span", { key: index, className: "text-xs bg-cyan-100 dark:bg-cyan-800/30 text-cyan-800 dark:text-cyan-200 px-2 py-0.5 rounded-full" }, infra.trim())))), technicalDetails.monitoring !== 'N/A' && /*#__PURE__*/_react.default.createElement("div", { className: "flex items-center gap-2 p-2 bg-pink-50 dark:bg-pink-900/20 rounded-lg" }, /*#__PURE__*/_react.default.createElement(_lucideReact.Activity, { className: "w-3 h-3 text-pink-500" }), /*#__PURE__*/_react.default.createElement("div", { className: "flex flex-wrap gap-1" }, technicalDetails.monitoring.split(', ').map((monitor, index) => /*#__PURE__*/_react.default.createElement("span", { key: index, className: "text-xs bg-pink-100 dark:bg-pink-800/30 text-pink-800 dark:text-pink-200 px-2 py-0.5 rounded-full" }, monitor.trim()))))), !isNode && technicalDetails.failureHandling !== 'N/A' && /*#__PURE__*/_react.default.createElement("div", { className: "flex items-center gap-2 p-2 bg-red-50 dark:bg-red-900/20 rounded-lg" }, /*#__PURE__*/_react.default.createElement(_lucideReact.AlertTriangle, { className: "w-3 h-3 text-red-500" }), /*#__PURE__*/_react.default.createElement("div", { className: "flex flex-wrap gap-1" }, technicalDetails.failureHandling.split(', ').map((failure, index) => /*#__PURE__*/_react.default.createElement("span", { key: index, className: "text-xs bg-red-100 dark:bg-red-800/30 text-red-800 dark:text-red-200 px-2 py-0.5 rounded-full" }, failure.trim())))), ((_selectedElement$data2 = selectedElement.data) === null || _selectedElement$data2 === void 0 ? void 0 : _selectedElement$data2.description) && /*#__PURE__*/_react.default.createElement("div", { className: "flex items-start gap-2 p-2 bg-gray-50 dark:bg-gray-800 rounded-lg" }, /*#__PURE__*/_react.default.createElement(_lucideReact.Info, { className: "w-3 h-3 text-gray-500 mt-0.5 flex-shrink-0" }), /*#__PURE__*/_react.default.createElement("p", { className: "text-xs text-gray-700 dark:text-gray-300 leading-relaxed" }, selectedElement.data.description)), technicalDetails.protocol === 'N/A' && technicalDetails.security === 'N/A' && !technicalDetails.performance.latency && !technicalDetails.performance.throughput && !technicalDetails.performance.timeout && technicalDetails.scaling === 'N/A' && technicalDetails.infrastructure === 'N/A' && technicalDetails.monitoring === 'N/A' && technicalDetails.failureHandling === 'N/A' && !((_selectedElement$data3 = selectedElement.data) !== null && _selectedElement$data3 !== void 0 && _selectedElement$data3.description) && /*#__PURE__*/_react.default.createElement("div", { className: "text-center py-4" }, /*#__PURE__*/_react.default.createElement("p", { className: "text-xs text-gray-500 dark:text-gray-400" }, "No technical details available")))), /*#__PURE__*/_react.default.createElement("div", { className: "absolute w-3 h-3 bg-white/95 dark:bg-gray-900/95 border-l border-t border-gray-200/50 dark:border-gray-700/50 transform rotate-45", style: { left: panelPos.x < window.innerWidth / 2 ? '-6px' : 'auto', right: panelPos.x >= window.innerWidth / 2 ? '-6px' : 'auto', top: '20px' } })); }; var _default = exports.default = TechnicalDetailsPanel;