mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
improvement(canvas): add multi-block select, add batch handle, enabled, and edge operations (#2738)
* improvement(canvas): add multi-block select, add batch handle, enabled, and edge operations * feat(i18n): update translations (#2732) Co-authored-by: icecrasher321 <icecrasher321@users.noreply.github.com> * don't allow flip handles for subflows * ack PR comments * more * fix missing handler * remove dead subflow-specific ops * remove unused code * fixed subflow ops * keep edges on subflow actions intact * fix subflow resizing * fix remove from subflow bulk * improvement(canvas): add multi-block select, add batch handle, enabled, and edge operations * don't allow flip handles for subflows * ack PR comments * more * fix missing handler * remove dead subflow-specific ops * remove unused code * fixed subflow ops * fix subflow resizing * keep edges on subflow actions intact * fixed copy from inside subflow * types improvement, preview fixes * fetch varible data in deploy modal * moved remove from subflow one position to the right * fix subflow issues * address greptile comment * fix test * improvement(preview): ui/ux * fix(preview): subflows * added batch add edges * removed recovery * use consolidated consts for sockets operations * more --------- Co-authored-by: icecrasher321 <icecrasher321@users.noreply.github.com> Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai> Co-authored-by: Emir Karabeg <emirkarabeg@berkeley.edu>
This commit is contained in:
@@ -120,24 +120,25 @@ export {
|
||||
} from './serialized-block.factory'
|
||||
// Undo/redo operation factories
|
||||
export {
|
||||
type AddEdgeOperation,
|
||||
type BaseOperation,
|
||||
type BatchAddBlocksOperation,
|
||||
type BatchAddEdgesOperation,
|
||||
type BatchMoveBlocksOperation,
|
||||
type BatchRemoveBlocksOperation,
|
||||
type BatchRemoveEdgesOperation,
|
||||
type BatchUpdateParentOperation,
|
||||
createAddBlockEntry,
|
||||
createAddEdgeEntry,
|
||||
createBatchRemoveEdgesEntry,
|
||||
createBatchUpdateParentEntry,
|
||||
createMoveBlockEntry,
|
||||
createRemoveBlockEntry,
|
||||
createRemoveEdgeEntry,
|
||||
createUpdateParentEntry,
|
||||
type MoveBlockOperation,
|
||||
type Operation,
|
||||
type OperationEntry,
|
||||
type OperationType,
|
||||
type RemoveEdgeOperation,
|
||||
type UpdateParentOperation,
|
||||
} from './undo-redo.factory'
|
||||
// User/workspace factories
|
||||
export {
|
||||
createUser,
|
||||
createUserWithWorkspace,
|
||||
@@ -147,7 +148,6 @@ export {
|
||||
type WorkflowObjectFactoryOptions,
|
||||
type WorkspaceFactoryOptions,
|
||||
} from './user.factory'
|
||||
// Workflow factories
|
||||
export {
|
||||
createBranchingWorkflow,
|
||||
createLinearWorkflow,
|
||||
|
||||
@@ -8,10 +8,11 @@ import { nanoid } from 'nanoid'
|
||||
export type OperationType =
|
||||
| 'batch-add-blocks'
|
||||
| 'batch-remove-blocks'
|
||||
| 'add-edge'
|
||||
| 'remove-edge'
|
||||
| 'move-block'
|
||||
| 'batch-add-edges'
|
||||
| 'batch-remove-edges'
|
||||
| 'batch-move-blocks'
|
||||
| 'update-parent'
|
||||
| 'batch-update-parent'
|
||||
|
||||
/**
|
||||
* Base operation interface.
|
||||
@@ -25,14 +26,16 @@ export interface BaseOperation {
|
||||
}
|
||||
|
||||
/**
|
||||
* Move block operation data.
|
||||
* Batch move blocks operation data.
|
||||
*/
|
||||
export interface MoveBlockOperation extends BaseOperation {
|
||||
type: 'move-block'
|
||||
export interface BatchMoveBlocksOperation extends BaseOperation {
|
||||
type: 'batch-move-blocks'
|
||||
data: {
|
||||
blockId: string
|
||||
before: { x: number; y: number; parentId?: string }
|
||||
after: { x: number; y: number; parentId?: string }
|
||||
moves: Array<{
|
||||
blockId: string
|
||||
before: { x: number; y: number; parentId?: string }
|
||||
after: { x: number; y: number; parentId?: string }
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,19 +64,19 @@ export interface BatchRemoveBlocksOperation extends BaseOperation {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add edge operation data.
|
||||
* Batch add edges operation data.
|
||||
*/
|
||||
export interface AddEdgeOperation extends BaseOperation {
|
||||
type: 'add-edge'
|
||||
data: { edgeId: string }
|
||||
export interface BatchAddEdgesOperation extends BaseOperation {
|
||||
type: 'batch-add-edges'
|
||||
data: { edgeSnapshots: any[] }
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove edge operation data.
|
||||
* Batch remove edges operation data.
|
||||
*/
|
||||
export interface RemoveEdgeOperation extends BaseOperation {
|
||||
type: 'remove-edge'
|
||||
data: { edgeId: string; edgeSnapshot: any }
|
||||
export interface BatchRemoveEdgesOperation extends BaseOperation {
|
||||
type: 'batch-remove-edges'
|
||||
data: { edgeSnapshots: any[] }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,13 +93,28 @@ export interface UpdateParentOperation extends BaseOperation {
|
||||
}
|
||||
}
|
||||
|
||||
export interface BatchUpdateParentOperation extends BaseOperation {
|
||||
type: 'batch-update-parent'
|
||||
data: {
|
||||
updates: Array<{
|
||||
blockId: string
|
||||
oldParentId?: string
|
||||
newParentId?: string
|
||||
oldPosition: { x: number; y: number }
|
||||
newPosition: { x: number; y: number }
|
||||
affectedEdges?: any[]
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export type Operation =
|
||||
| BatchAddBlocksOperation
|
||||
| BatchRemoveBlocksOperation
|
||||
| AddEdgeOperation
|
||||
| RemoveEdgeOperation
|
||||
| MoveBlockOperation
|
||||
| BatchAddEdgesOperation
|
||||
| BatchRemoveEdgesOperation
|
||||
| BatchMoveBlocksOperation
|
||||
| UpdateParentOperation
|
||||
| BatchUpdateParentOperation
|
||||
|
||||
/**
|
||||
* Operation entry with forward and inverse operations.
|
||||
@@ -208,40 +226,45 @@ export function createRemoveBlockEntry(
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mock add-edge operation entry.
|
||||
* Creates a mock batch-add-edges operation entry for a single edge.
|
||||
*/
|
||||
export function createAddEdgeEntry(edgeId: string, options: OperationEntryOptions = {}): any {
|
||||
export function createAddEdgeEntry(
|
||||
edgeId: string,
|
||||
edgeSnapshot: any = null,
|
||||
options: OperationEntryOptions = {}
|
||||
): any {
|
||||
const { id = nanoid(8), workflowId = 'wf-1', userId = 'user-1', createdAt = Date.now() } = options
|
||||
const timestamp = Date.now()
|
||||
|
||||
const snapshot = edgeSnapshot || { id: edgeId, source: 'block-1', target: 'block-2' }
|
||||
|
||||
return {
|
||||
id,
|
||||
createdAt,
|
||||
operation: {
|
||||
id: nanoid(8),
|
||||
type: 'add-edge',
|
||||
type: 'batch-add-edges',
|
||||
timestamp,
|
||||
workflowId,
|
||||
userId,
|
||||
data: { edgeId },
|
||||
data: { edgeSnapshots: [snapshot] },
|
||||
},
|
||||
inverse: {
|
||||
id: nanoid(8),
|
||||
type: 'remove-edge',
|
||||
type: 'batch-remove-edges',
|
||||
timestamp,
|
||||
workflowId,
|
||||
userId,
|
||||
data: { edgeId, edgeSnapshot: null },
|
||||
data: { edgeSnapshots: [snapshot] },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mock remove-edge operation entry.
|
||||
* Creates a mock batch-remove-edges operation entry.
|
||||
*/
|
||||
export function createRemoveEdgeEntry(
|
||||
edgeId: string,
|
||||
edgeSnapshot: any = null,
|
||||
export function createBatchRemoveEdgesEntry(
|
||||
edgeSnapshots: any[],
|
||||
options: OperationEntryOptions = {}
|
||||
): any {
|
||||
const { id = nanoid(8), workflowId = 'wf-1', userId = 'user-1', createdAt = Date.now() } = options
|
||||
@@ -252,19 +275,19 @@ export function createRemoveEdgeEntry(
|
||||
createdAt,
|
||||
operation: {
|
||||
id: nanoid(8),
|
||||
type: 'remove-edge',
|
||||
type: 'batch-remove-edges',
|
||||
timestamp,
|
||||
workflowId,
|
||||
userId,
|
||||
data: { edgeId, edgeSnapshot },
|
||||
data: { edgeSnapshots },
|
||||
},
|
||||
inverse: {
|
||||
id: nanoid(8),
|
||||
type: 'add-edge',
|
||||
type: 'batch-add-edges',
|
||||
timestamp,
|
||||
workflowId,
|
||||
userId,
|
||||
data: { edgeId },
|
||||
data: { edgeSnapshots },
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -275,7 +298,7 @@ interface MoveBlockOptions extends OperationEntryOptions {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mock move-block operation entry.
|
||||
* Creates a mock batch-move-blocks operation entry for a single block.
|
||||
*/
|
||||
export function createMoveBlockEntry(blockId: string, options: MoveBlockOptions = {}): any {
|
||||
const {
|
||||
@@ -293,19 +316,19 @@ export function createMoveBlockEntry(blockId: string, options: MoveBlockOptions
|
||||
createdAt,
|
||||
operation: {
|
||||
id: nanoid(8),
|
||||
type: 'move-block',
|
||||
type: 'batch-move-blocks',
|
||||
timestamp,
|
||||
workflowId,
|
||||
userId,
|
||||
data: { blockId, before, after },
|
||||
data: { moves: [{ blockId, before, after }] },
|
||||
},
|
||||
inverse: {
|
||||
id: nanoid(8),
|
||||
type: 'move-block',
|
||||
type: 'batch-move-blocks',
|
||||
timestamp,
|
||||
workflowId,
|
||||
userId,
|
||||
data: { blockId, before: after, after: before },
|
||||
data: { moves: [{ blockId, before: after, after: before }] },
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -361,3 +384,75 @@ export function createUpdateParentEntry(
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
interface BatchUpdateParentOptions extends OperationEntryOptions {
|
||||
updates?: Array<{
|
||||
blockId: string
|
||||
oldParentId?: string
|
||||
newParentId?: string
|
||||
oldPosition?: { x: number; y: number }
|
||||
newPosition?: { x: number; y: number }
|
||||
affectedEdges?: any[]
|
||||
}>
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mock batch-update-parent operation entry.
|
||||
*/
|
||||
export function createBatchUpdateParentEntry(options: BatchUpdateParentOptions = {}): any {
|
||||
const {
|
||||
id = nanoid(8),
|
||||
workflowId = 'wf-1',
|
||||
userId = 'user-1',
|
||||
createdAt = Date.now(),
|
||||
updates = [
|
||||
{
|
||||
blockId: 'block-1',
|
||||
oldParentId: undefined,
|
||||
newParentId: 'loop-1',
|
||||
oldPosition: { x: 0, y: 0 },
|
||||
newPosition: { x: 50, y: 50 },
|
||||
},
|
||||
],
|
||||
} = options
|
||||
const timestamp = Date.now()
|
||||
|
||||
const processedUpdates = updates.map((u) => ({
|
||||
blockId: u.blockId,
|
||||
oldParentId: u.oldParentId,
|
||||
newParentId: u.newParentId,
|
||||
oldPosition: u.oldPosition || { x: 0, y: 0 },
|
||||
newPosition: u.newPosition || { x: 50, y: 50 },
|
||||
affectedEdges: u.affectedEdges,
|
||||
}))
|
||||
|
||||
return {
|
||||
id,
|
||||
createdAt,
|
||||
operation: {
|
||||
id: nanoid(8),
|
||||
type: 'batch-update-parent',
|
||||
timestamp,
|
||||
workflowId,
|
||||
userId,
|
||||
data: { updates: processedUpdates },
|
||||
},
|
||||
inverse: {
|
||||
id: nanoid(8),
|
||||
type: 'batch-update-parent',
|
||||
timestamp,
|
||||
workflowId,
|
||||
userId,
|
||||
data: {
|
||||
updates: processedUpdates.map((u) => ({
|
||||
blockId: u.blockId,
|
||||
oldParentId: u.newParentId,
|
||||
newParentId: u.oldParentId,
|
||||
oldPosition: u.newPosition,
|
||||
newPosition: u.oldPosition,
|
||||
affectedEdges: u.affectedEdges,
|
||||
})),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user