|
@@ -34,7 +34,7 @@ import {
|
|
|
TextArea,
|
|
TextArea,
|
|
|
Typography,
|
|
Typography,
|
|
|
} from '@douyinfe/semi-ui';
|
|
} from '@douyinfe/semi-ui';
|
|
|
-import { IconDelete, IconPlus } from '@douyinfe/semi-icons';
|
|
|
|
|
|
|
+import { IconDelete, IconMenu, IconPlus } from '@douyinfe/semi-icons';
|
|
|
import { copy, showError, showSuccess, verifyJSON } from '../../../../helpers';
|
|
import { copy, showError, showSuccess, verifyJSON } from '../../../../helpers';
|
|
|
import {
|
|
import {
|
|
|
CLAUDE_CLI_HEADER_PASSTHROUGH_TEMPLATE,
|
|
CLAUDE_CLI_HEADER_PASSTHROUGH_TEMPLATE,
|
|
@@ -800,6 +800,38 @@ const normalizeOperation = (operation = {}) => ({
|
|
|
|
|
|
|
|
const createDefaultOperation = () => normalizeOperation({ mode: 'set' });
|
|
const createDefaultOperation = () => normalizeOperation({ mode: 'set' });
|
|
|
|
|
|
|
|
|
|
+const reorderOperations = (
|
|
|
|
|
+ sourceOperations = [],
|
|
|
|
|
+ sourceId,
|
|
|
|
|
+ targetId,
|
|
|
|
|
+ position = 'before',
|
|
|
|
|
+) => {
|
|
|
|
|
+ if (!sourceId || !targetId || sourceId === targetId) {
|
|
|
|
|
+ return sourceOperations;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const sourceIndex = sourceOperations.findIndex((item) => item.id === sourceId);
|
|
|
|
|
+
|
|
|
|
|
+ if (sourceIndex < 0) {
|
|
|
|
|
+ return sourceOperations;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const nextOperations = [...sourceOperations];
|
|
|
|
|
+ const [moved] = nextOperations.splice(sourceIndex, 1);
|
|
|
|
|
+ let insertIndex = nextOperations.findIndex((item) => item.id === targetId);
|
|
|
|
|
+
|
|
|
|
|
+ if (insertIndex < 0) {
|
|
|
|
|
+ return sourceOperations;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (position === 'after') {
|
|
|
|
|
+ insertIndex += 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ nextOperations.splice(insertIndex, 0, moved);
|
|
|
|
|
+ return nextOperations;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
const getOperationSummary = (operation = {}, index = 0) => {
|
|
const getOperationSummary = (operation = {}, index = 0) => {
|
|
|
const mode = operation.mode || 'set';
|
|
const mode = operation.mode || 'set';
|
|
|
const modeLabel = OPERATION_MODE_LABEL_MAP[mode] || mode;
|
|
const modeLabel = OPERATION_MODE_LABEL_MAP[mode] || mode;
|
|
@@ -1037,6 +1069,9 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
|
|
|
const [operationSearch, setOperationSearch] = useState('');
|
|
const [operationSearch, setOperationSearch] = useState('');
|
|
|
const [selectedOperationId, setSelectedOperationId] = useState('');
|
|
const [selectedOperationId, setSelectedOperationId] = useState('');
|
|
|
const [expandedConditionMap, setExpandedConditionMap] = useState({});
|
|
const [expandedConditionMap, setExpandedConditionMap] = useState({});
|
|
|
|
|
+ const [draggedOperationId, setDraggedOperationId] = useState('');
|
|
|
|
|
+ const [dragOverOperationId, setDragOverOperationId] = useState('');
|
|
|
|
|
+ const [dragOverPosition, setDragOverPosition] = useState('before');
|
|
|
const [templateGroupKey, setTemplateGroupKey] = useState('basic');
|
|
const [templateGroupKey, setTemplateGroupKey] = useState('basic');
|
|
|
const [templatePresetKey, setTemplatePresetKey] = useState('operations_default');
|
|
const [templatePresetKey, setTemplatePresetKey] = useState('operations_default');
|
|
|
const [fieldGuideVisible, setFieldGuideVisible] = useState(false);
|
|
const [fieldGuideVisible, setFieldGuideVisible] = useState(false);
|
|
@@ -1055,6 +1090,9 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
|
|
|
setOperationSearch('');
|
|
setOperationSearch('');
|
|
|
setSelectedOperationId(nextState.operations[0]?.id || '');
|
|
setSelectedOperationId(nextState.operations[0]?.id || '');
|
|
|
setExpandedConditionMap({});
|
|
setExpandedConditionMap({});
|
|
|
|
|
+ setDraggedOperationId('');
|
|
|
|
|
+ setDragOverOperationId('');
|
|
|
|
|
+ setDragOverPosition('before');
|
|
|
if (nextState.visualMode === 'legacy') {
|
|
if (nextState.visualMode === 'legacy') {
|
|
|
setTemplateGroupKey('basic');
|
|
setTemplateGroupKey('basic');
|
|
|
setTemplatePresetKey('legacy_default');
|
|
setTemplatePresetKey('legacy_default');
|
|
@@ -1583,6 +1621,67 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
|
|
|
setSelectedOperationId(created.id);
|
|
setSelectedOperationId(created.id);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+ const resetOperationDragState = useCallback(() => {
|
|
|
|
|
+ setDraggedOperationId('');
|
|
|
|
|
+ setDragOverOperationId('');
|
|
|
|
|
+ setDragOverPosition('before');
|
|
|
|
|
+ }, []);
|
|
|
|
|
+
|
|
|
|
|
+ const moveOperation = useCallback(
|
|
|
|
|
+ (sourceId, targetId, position = 'before') => {
|
|
|
|
|
+ if (!sourceId || !targetId || sourceId === targetId) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ setOperations((prev) =>
|
|
|
|
|
+ reorderOperations(prev, sourceId, targetId, position),
|
|
|
|
|
+ );
|
|
|
|
|
+ setSelectedOperationId(sourceId);
|
|
|
|
|
+ },
|
|
|
|
|
+ [],
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ const handleOperationDragStart = useCallback((event, operationId) => {
|
|
|
|
|
+ setDraggedOperationId(operationId);
|
|
|
|
|
+ setSelectedOperationId(operationId);
|
|
|
|
|
+ event.dataTransfer.effectAllowed = 'move';
|
|
|
|
|
+ event.dataTransfer.setData('text/plain', operationId);
|
|
|
|
|
+ }, []);
|
|
|
|
|
+
|
|
|
|
|
+ const handleOperationDragOver = useCallback(
|
|
|
|
|
+ (event, operationId) => {
|
|
|
|
|
+ event.preventDefault();
|
|
|
|
|
+ if (!draggedOperationId || draggedOperationId === operationId) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ const rect = event.currentTarget.getBoundingClientRect();
|
|
|
|
|
+ const position =
|
|
|
|
|
+ event.clientY - rect.top > rect.height / 2 ? 'after' : 'before';
|
|
|
|
|
+ setDragOverOperationId(operationId);
|
|
|
|
|
+ setDragOverPosition(position);
|
|
|
|
|
+ event.dataTransfer.dropEffect = 'move';
|
|
|
|
|
+ },
|
|
|
|
|
+ [draggedOperationId],
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ const handleOperationDrop = useCallback(
|
|
|
|
|
+ (event, operationId) => {
|
|
|
|
|
+ event.preventDefault();
|
|
|
|
|
+ const sourceId =
|
|
|
|
|
+ draggedOperationId || event.dataTransfer.getData('text/plain');
|
|
|
|
|
+ const position =
|
|
|
|
|
+ dragOverOperationId === operationId ? dragOverPosition : 'before';
|
|
|
|
|
+ moveOperation(sourceId, operationId, position);
|
|
|
|
|
+ resetOperationDragState();
|
|
|
|
|
+ },
|
|
|
|
|
+ [
|
|
|
|
|
+ dragOverOperationId,
|
|
|
|
|
+ dragOverPosition,
|
|
|
|
|
+ draggedOperationId,
|
|
|
|
|
+ moveOperation,
|
|
|
|
|
+ resetOperationDragState,
|
|
|
|
|
+ ],
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
const duplicateOperation = (operationId) => {
|
|
const duplicateOperation = (operationId) => {
|
|
|
let insertedId = '';
|
|
let insertedId = '';
|
|
|
setOperations((prev) => {
|
|
setOperations((prev) => {
|
|
@@ -1941,14 +2040,31 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
|
|
|
);
|
|
);
|
|
|
const isActive =
|
|
const isActive =
|
|
|
operation.id === selectedOperationId;
|
|
operation.id === selectedOperationId;
|
|
|
|
|
+ const isDragging =
|
|
|
|
|
+ operation.id === draggedOperationId;
|
|
|
|
|
+ const isDropTarget =
|
|
|
|
|
+ operation.id === dragOverOperationId &&
|
|
|
|
|
+ draggedOperationId &&
|
|
|
|
|
+ draggedOperationId !== operation.id;
|
|
|
return (
|
|
return (
|
|
|
<div
|
|
<div
|
|
|
key={operation.id}
|
|
key={operation.id}
|
|
|
role='button'
|
|
role='button'
|
|
|
tabIndex={0}
|
|
tabIndex={0}
|
|
|
|
|
+ draggable={operations.length > 1}
|
|
|
onClick={() =>
|
|
onClick={() =>
|
|
|
setSelectedOperationId(operation.id)
|
|
setSelectedOperationId(operation.id)
|
|
|
}
|
|
}
|
|
|
|
|
+ onDragStart={(event) =>
|
|
|
|
|
+ handleOperationDragStart(event, operation.id)
|
|
|
|
|
+ }
|
|
|
|
|
+ onDragOver={(event) =>
|
|
|
|
|
+ handleOperationDragOver(event, operation.id)
|
|
|
|
|
+ }
|
|
|
|
|
+ onDrop={(event) =>
|
|
|
|
|
+ handleOperationDrop(event, operation.id)
|
|
|
|
|
+ }
|
|
|
|
|
+ onDragEnd={resetOperationDragState}
|
|
|
onKeyDown={(event) => {
|
|
onKeyDown={(event) => {
|
|
|
if (
|
|
if (
|
|
|
event.key === 'Enter' ||
|
|
event.key === 'Enter' ||
|
|
@@ -1966,35 +2082,53 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
|
|
|
border: isActive
|
|
border: isActive
|
|
|
? '1px solid var(--semi-color-primary)'
|
|
? '1px solid var(--semi-color-primary)'
|
|
|
: '1px solid var(--semi-color-border)',
|
|
: '1px solid var(--semi-color-border)',
|
|
|
|
|
+ opacity: isDragging ? 0.6 : 1,
|
|
|
|
|
+ boxShadow: isDropTarget
|
|
|
|
|
+ ? dragOverPosition === 'after'
|
|
|
|
|
+ ? 'inset 0 -3px 0 var(--semi-color-primary)'
|
|
|
|
|
+ : 'inset 0 3px 0 var(--semi-color-primary)'
|
|
|
|
|
+ : 'none',
|
|
|
}}
|
|
}}
|
|
|
>
|
|
>
|
|
|
<div className='flex items-start justify-between gap-2'>
|
|
<div className='flex items-start justify-between gap-2'>
|
|
|
- <div>
|
|
|
|
|
- <Text strong>{`#${index + 1}`}</Text>
|
|
|
|
|
- <Text
|
|
|
|
|
- type='tertiary'
|
|
|
|
|
- size='small'
|
|
|
|
|
- className='block mt-1'
|
|
|
|
|
|
|
+ <div className='flex items-start gap-2 min-w-0'>
|
|
|
|
|
+ <div
|
|
|
|
|
+ className='flex-shrink-0'
|
|
|
|
|
+ style={{
|
|
|
|
|
+ color: 'var(--semi-color-text-2)',
|
|
|
|
|
+ cursor: operations.length > 1 ? 'grab' : 'default',
|
|
|
|
|
+ marginTop: 1,
|
|
|
|
|
+ }}
|
|
|
>
|
|
>
|
|
|
- {getOperationSummary(operation, index)}
|
|
|
|
|
- </Text>
|
|
|
|
|
- {String(operation.description || '').trim() ? (
|
|
|
|
|
|
|
+ <IconMenu />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div className='min-w-0'>
|
|
|
|
|
+ <Text strong>{`#${index + 1}`}</Text>
|
|
|
<Text
|
|
<Text
|
|
|
type='tertiary'
|
|
type='tertiary'
|
|
|
size='small'
|
|
size='small'
|
|
|
className='block mt-1'
|
|
className='block mt-1'
|
|
|
- style={{
|
|
|
|
|
- lineHeight: 1.5,
|
|
|
|
|
- wordBreak: 'break-word',
|
|
|
|
|
- overflow: 'hidden',
|
|
|
|
|
- display: '-webkit-box',
|
|
|
|
|
- WebkitLineClamp: 2,
|
|
|
|
|
- WebkitBoxOrient: 'vertical',
|
|
|
|
|
- }}
|
|
|
|
|
>
|
|
>
|
|
|
- {operation.description}
|
|
|
|
|
|
|
+ {getOperationSummary(operation, index)}
|
|
|
</Text>
|
|
</Text>
|
|
|
- ) : null}
|
|
|
|
|
|
|
+ {String(operation.description || '').trim() ? (
|
|
|
|
|
+ <Text
|
|
|
|
|
+ type='tertiary'
|
|
|
|
|
+ size='small'
|
|
|
|
|
+ className='block mt-1'
|
|
|
|
|
+ style={{
|
|
|
|
|
+ lineHeight: 1.5,
|
|
|
|
|
+ wordBreak: 'break-word',
|
|
|
|
|
+ overflow: 'hidden',
|
|
|
|
|
+ display: '-webkit-box',
|
|
|
|
|
+ WebkitLineClamp: 2,
|
|
|
|
|
+ WebkitBoxOrient: 'vertical',
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ {operation.description}
|
|
|
|
|
+ </Text>
|
|
|
|
|
+ ) : null}
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
<Tag size='small' color='grey'>
|
|
<Tag size='small' color='grey'>
|
|
|
{(operation.conditions || []).length}
|
|
{(operation.conditions || []).length}
|