release: bump version to 0.66.1
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "planet-frontend",
|
||||
"version": "0.66.0",
|
||||
"version": "0.66.1",
|
||||
"private": true,
|
||||
"packageManager": "bun@1",
|
||||
"dependencies": {
|
||||
|
||||
@@ -2495,6 +2495,7 @@ function ModuleConsole({ config }: { config: ModuleConfig }) {
|
||||
const taskId = text(payload.task_id, sourceId || source)
|
||||
const pendingKey = taskId || sourceId || source
|
||||
if (!pendingKey || completedDatasourceTasksRef.current.has(pendingKey)) return
|
||||
completedDatasourceTasksRef.current.add(pendingKey)
|
||||
const pendingEntry = pendingDatasourceTasksRef.current[pendingKey]
|
||||
? [pendingKey, pendingDatasourceTasksRef.current[pendingKey]] as const
|
||||
: Object.entries(pendingDatasourceTasksRef.current).find(([, item]) => isSameDatasourceRow({ id: item.sourceId, source: item.source }, sourceId, source))
|
||||
@@ -2512,7 +2513,6 @@ function ModuleConsole({ config }: { config: ModuleConfig }) {
|
||||
updateDatasourceRow({ ...payload, id: sourceId || pending?.sourceId, source: source || pending?.source }, { removeIfFilteredOut: true })
|
||||
}
|
||||
|
||||
completedDatasourceTasksRef.current.add(pendingKey)
|
||||
if (pending) {
|
||||
const finalStatus = datasourceStatus(finalRow)
|
||||
const titleName = pending.name || text(finalRow.name || finalRow.source, '数据源')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Check, Copy } from 'lucide-react'
|
||||
import { memo, useEffect, useId, useRef, useState } from 'react'
|
||||
import type { ReactNode } from 'react'
|
||||
import type { PointerEvent as ReactPointerEvent, ReactNode, WheelEvent as ReactWheelEvent } from 'react'
|
||||
|
||||
import Scrollbar from '../Scrollbar/Scrollbar'
|
||||
|
||||
@@ -161,6 +161,11 @@ async function copyToClipboard(text: string): Promise<void> {
|
||||
document.body.removeChild(textarea)
|
||||
}
|
||||
|
||||
function isMermaidTextTarget(target: EventTarget | null): boolean {
|
||||
if (!(target instanceof Element)) return false
|
||||
return Boolean(target.closest('text, tspan, foreignObject, .nodeLabel, .edgeLabel, .label'))
|
||||
}
|
||||
|
||||
function MarkdownCodeBlock({ code, language }: { code: string; language?: string }) {
|
||||
const [copied, setCopied] = useState(false)
|
||||
const label = language?.trim() || 'text'
|
||||
@@ -200,8 +205,18 @@ function MarkdownMermaidBlock({ code }: { code: string }) {
|
||||
const [svg, setSvg] = useState('')
|
||||
const [error, setError] = useState('')
|
||||
const [themeMode, setThemeMode] = useState<'light' | 'dark'>('light')
|
||||
const [isExpanded, setIsExpanded] = useState(false)
|
||||
const [zoom, setZoom] = useState(1)
|
||||
const [pan, setPan] = useState({ x: 0, y: 0 })
|
||||
const blockId = useId().replace(/[^a-zA-Z0-9_-]/g, '')
|
||||
const containerRef = useRef<HTMLDivElement | null>(null)
|
||||
const dragRef = useRef<{
|
||||
pointerId: number
|
||||
startX: number
|
||||
startY: number
|
||||
initialX: number
|
||||
initialY: number
|
||||
} | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const themeElement = containerRef.current?.closest('[data-theme]')
|
||||
@@ -269,31 +284,138 @@ function MarkdownMermaidBlock({ code }: { code: string }) {
|
||||
window.setTimeout(() => setCopied(false), COPY_FEEDBACK_MS)
|
||||
}
|
||||
|
||||
const openExpanded = () => {
|
||||
if (!svg) return
|
||||
setZoom(1)
|
||||
setPan({ x: 0, y: 0 })
|
||||
setIsExpanded(true)
|
||||
}
|
||||
|
||||
const closeExpanded = () => {
|
||||
dragRef.current = null
|
||||
setIsExpanded(false)
|
||||
}
|
||||
|
||||
const handleWheel = (event: ReactWheelEvent<HTMLDivElement>) => {
|
||||
event.preventDefault()
|
||||
const direction = event.deltaY > 0 ? -1 : 1
|
||||
setZoom((value) => Math.min(4, Math.max(0.35, value + direction * 0.12)))
|
||||
}
|
||||
|
||||
const handlePointerDown = (event: ReactPointerEvent<HTMLDivElement>) => {
|
||||
if (!isExpanded) return
|
||||
if (isMermaidTextTarget(event.target)) return
|
||||
event.currentTarget.setPointerCapture(event.pointerId)
|
||||
dragRef.current = {
|
||||
pointerId: event.pointerId,
|
||||
startX: event.clientX,
|
||||
startY: event.clientY,
|
||||
initialX: pan.x,
|
||||
initialY: pan.y,
|
||||
}
|
||||
}
|
||||
|
||||
const handlePointerMove = (event: ReactPointerEvent<HTMLDivElement>) => {
|
||||
const drag = dragRef.current
|
||||
if (!drag || drag.pointerId !== event.pointerId) return
|
||||
setPan({
|
||||
x: drag.initialX + event.clientX - drag.startX,
|
||||
y: drag.initialY + event.clientY - drag.startY,
|
||||
})
|
||||
}
|
||||
|
||||
const handlePointerUp = (event: ReactPointerEvent<HTMLDivElement>) => {
|
||||
if (dragRef.current?.pointerId === event.pointerId) {
|
||||
dragRef.current = null
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="markdown-renderer__mermaid-block" ref={containerRef}>
|
||||
<div className="markdown-renderer__code-toolbar markdown-renderer__mermaid-toolbar">
|
||||
<span className="markdown-renderer__code-language">mermaid</span>
|
||||
<button
|
||||
type="button"
|
||||
className="markdown-renderer__code-copy"
|
||||
onClick={handleCopy}
|
||||
aria-label={copied ? '已复制图表源码' : '复制图表源码'}
|
||||
title={copied ? '已复制' : '复制图表源码'}
|
||||
>
|
||||
{copied ? <Check size={14} /> : <Copy size={14} />}
|
||||
</button>
|
||||
</div>
|
||||
{svg ? (
|
||||
<div className="markdown-renderer__mermaid-canvas" dangerouslySetInnerHTML={{ __html: svg }} />
|
||||
) : error ? (
|
||||
<div className="markdown-renderer__mermaid-error">
|
||||
<strong>Mermaid render failed</strong>
|
||||
<span>{error}</span>
|
||||
<>
|
||||
<div className="markdown-renderer__mermaid-block" ref={containerRef}>
|
||||
<div className="markdown-renderer__code-toolbar markdown-renderer__mermaid-toolbar">
|
||||
<span className="markdown-renderer__code-language">mermaid</span>
|
||||
<button
|
||||
type="button"
|
||||
className="markdown-renderer__code-copy"
|
||||
onClick={handleCopy}
|
||||
aria-label={copied ? '已复制图表源码' : '复制图表源码'}
|
||||
title={copied ? '已复制' : '复制图表源码'}
|
||||
>
|
||||
{copied ? <Check size={14} /> : <Copy size={14} />}
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="markdown-renderer__mermaid-loading">Rendering diagram...</div>
|
||||
)}
|
||||
</div>
|
||||
{svg ? (
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className="markdown-renderer__mermaid-canvas"
|
||||
onClick={(event) => {
|
||||
if (isMermaidTextTarget(event.target)) return
|
||||
if (window.getSelection()?.toString()) return
|
||||
openExpanded()
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
event.preventDefault()
|
||||
openExpanded()
|
||||
}
|
||||
}}
|
||||
aria-label="放大查看 Mermaid 图表"
|
||||
title="点击放大查看"
|
||||
>
|
||||
<span className="markdown-renderer__mermaid-canvas-inner" dangerouslySetInnerHTML={{ __html: svg }} />
|
||||
</div>
|
||||
) : error ? (
|
||||
<div className="markdown-renderer__mermaid-error">
|
||||
<strong>Mermaid render failed</strong>
|
||||
<span>{error}</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="markdown-renderer__mermaid-loading">Rendering diagram...</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{isExpanded && svg ? (
|
||||
<div
|
||||
className="markdown-renderer__mermaid-viewer"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-label="Mermaid 图表查看器"
|
||||
onClick={closeExpanded}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="markdown-renderer__mermaid-viewer-close"
|
||||
onClick={closeExpanded}
|
||||
aria-label="关闭 Mermaid 图表查看器"
|
||||
title="关闭"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
<div
|
||||
className="markdown-renderer__mermaid-viewer-stage"
|
||||
onClick={(event) => event.stopPropagation()}
|
||||
onWheel={handleWheel}
|
||||
onPointerDown={handlePointerDown}
|
||||
onPointerMove={handlePointerMove}
|
||||
onPointerUp={handlePointerUp}
|
||||
onPointerCancel={handlePointerUp}
|
||||
>
|
||||
<div
|
||||
className="markdown-renderer__mermaid-viewer-content"
|
||||
style={{
|
||||
transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})`,
|
||||
}}
|
||||
dangerouslySetInnerHTML={{ __html: svg }}
|
||||
/>
|
||||
</div>
|
||||
<div className="markdown-renderer__mermaid-viewer-hint">
|
||||
拖拽移动 · 滚轮缩放 · 点击空白关闭
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -673,14 +673,135 @@
|
||||
.docs-markdown .markdown-renderer__mermaid-canvas {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
min-height: 180px;
|
||||
padding: 22px;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
overflow-x: auto;
|
||||
cursor: zoom-in;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.docs-markdown .markdown-renderer__mermaid-canvas svg {
|
||||
max-width: 100%;
|
||||
.docs-markdown .markdown-renderer__mermaid-canvas-inner {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.docs-markdown .markdown-renderer__mermaid-canvas-inner svg {
|
||||
width: 100%;
|
||||
max-width: min(100%, 1120px);
|
||||
height: auto;
|
||||
min-height: 160px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.docs-markdown .markdown-renderer__mermaid-canvas-inner svg text {
|
||||
user-select: text;
|
||||
-webkit-user-select: text;
|
||||
}
|
||||
|
||||
.docs-markdown .markdown-renderer__mermaid-canvas-inner svg tspan,
|
||||
.docs-markdown .markdown-renderer__mermaid-canvas-inner svg foreignObject,
|
||||
.docs-markdown .markdown-renderer__mermaid-canvas-inner svg foreignObject * {
|
||||
user-select: text;
|
||||
-webkit-user-select: text;
|
||||
}
|
||||
|
||||
.markdown-renderer__mermaid-viewer {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 10000;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 42px;
|
||||
background: rgba(3, 7, 18, 0.78);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.markdown-renderer__mermaid-viewer-stage {
|
||||
width: min(1180px, calc(100vw - 84px));
|
||||
height: min(760px, calc(100vh - 112px));
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(148, 163, 184, 0.26);
|
||||
border-radius: 8px;
|
||||
background: var(--d-mermaid-bg);
|
||||
box-shadow: 0 28px 80px rgba(0, 0, 0, 0.4);
|
||||
cursor: grab;
|
||||
touch-action: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.markdown-renderer__mermaid-viewer-stage:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.markdown-renderer__mermaid-viewer-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transform-origin: center;
|
||||
transition: transform 0.08s ease-out;
|
||||
}
|
||||
|
||||
.markdown-renderer__mermaid-viewer-content svg {
|
||||
max-width: 92%;
|
||||
max-height: 92%;
|
||||
width: auto;
|
||||
height: auto;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.markdown-renderer__mermaid-viewer-content svg text {
|
||||
user-select: text;
|
||||
-webkit-user-select: text;
|
||||
}
|
||||
|
||||
.markdown-renderer__mermaid-viewer-content svg tspan,
|
||||
.markdown-renderer__mermaid-viewer-content svg foreignObject,
|
||||
.markdown-renderer__mermaid-viewer-content svg foreignObject * {
|
||||
user-select: text;
|
||||
-webkit-user-select: text;
|
||||
}
|
||||
|
||||
.markdown-renderer__mermaid-viewer-close {
|
||||
position: fixed;
|
||||
top: 18px;
|
||||
right: 20px;
|
||||
z-index: 1;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border: 1px solid rgba(148, 163, 184, 0.34);
|
||||
border-radius: 8px;
|
||||
background: rgba(15, 23, 42, 0.78);
|
||||
color: #e5eefb;
|
||||
font-size: 26px;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.markdown-renderer__mermaid-viewer-close:hover {
|
||||
background: rgba(30, 41, 59, 0.92);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.markdown-renderer__mermaid-viewer-hint {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
bottom: 18px;
|
||||
transform: translateX(-50%);
|
||||
padding: 8px 12px;
|
||||
border: 1px solid rgba(148, 163, 184, 0.24);
|
||||
border-radius: 999px;
|
||||
background: rgba(15, 23, 42, 0.72);
|
||||
color: #cbd5e1;
|
||||
font-size: 12px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.docs-markdown .markdown-renderer__mermaid-loading,
|
||||
|
||||
Reference in New Issue
Block a user