2
0

perf(editor): 🚸 More predictable edge management

This commit is contained in:
Baptiste Arnaud
2022-03-25 13:31:14 +01:00
parent f3c5f6bea2
commit c507ef55ae
7 changed files with 76 additions and 24 deletions

View File

@ -27,8 +27,14 @@ export const Graph = ({
answersCounts?: AnswersCount[]
onUnlockProPlanClick?: () => void
} & FlexProps) => {
const { draggedStepType, setDraggedStepType, draggedStep, setDraggedStep } =
useStepDnd()
const {
draggedStepType,
setDraggedStepType,
draggedStep,
setDraggedStep,
draggedItem,
setDraggedItem,
} = useStepDnd()
const graphContainerRef = useRef<HTMLDivElement | null>(null)
const editorContainerRef = useRef<HTMLDivElement | null>(null)
const { createBlock } = useTypebot()
@ -77,6 +83,7 @@ export const Graph = ({
const handleMouseUp = (e: MouseEvent) => {
if (!typebot) return
if (draggedItem) setDraggedItem(undefined)
if (!draggedStep && !draggedStepType) return
const coordinates = {
x: e.clientX - graphPosition.x - blockWidth / 3,

View File

@ -22,7 +22,7 @@ export const ItemNodesList = ({
indices: { blockIndex, stepIndex },
isReadOnly = false,
}: Props) => {
const { typebot, createItem, deleteItem } = useTypebot()
const { typebot, createItem, detachItemFromStep } = useTypebot()
const { draggedItem, setDraggedItem, mouseOverBlock } = useStepDnd()
const placeholderRefs = useRef<HTMLDivElement[]>([])
const blockId = typebot?.blocks[blockIndex].id
@ -96,7 +96,7 @@ export const ItemNodesList = ({
) => {
if (!typebot || isReadOnly) return
placeholderRefs.current.splice(itemIndex + 1, 1)
deleteItem({ blockIndex, stepIndex, itemIndex })
detachItemFromStep({ blockIndex, stepIndex, itemIndex })
setPosition(absolute)
setRelativeCoordinates(relative)
setDraggedItem(item)

View File

@ -1,4 +1,11 @@
import { Typebot, Edge, StepWithItems, StepIndices, ItemIndices } from 'models'
import {
Typebot,
Edge,
StepWithItems,
StepIndices,
ItemIndices,
Step,
} from 'models'
import { WritableDraft } from 'immer/dist/types/types-external'
import { SetTypebot } from '../TypebotContext'
import { produce } from 'immer'
@ -98,9 +105,11 @@ const deleteOutgoingEdgeIdProps = (
const fromStepIndex = typebot.blocks[fromBlockIndex].steps.findIndex(
byId(edge.from.stepId)
)
const step = typebot.blocks[fromBlockIndex].steps[fromStepIndex]
const step = typebot.blocks[fromBlockIndex].steps[fromStepIndex] as
| Step
| undefined
const fromItemIndex =
edge.from.itemId && stepHasItems(step)
edge.from.itemId && step && stepHasItems(step)
? step.items.findIndex(byId(edge.from.itemId))
: -1
if (fromStepIndex !== -1)

View File

@ -8,29 +8,44 @@ import {
import { SetTypebot } from '../TypebotContext'
import produce from 'immer'
import { cleanUpEdgeDraft } from './edges'
import { stepHasItems } from 'utils'
import { byId, stepHasItems } from 'utils'
import cuid from 'cuid'
export type ItemsActions = {
createItem: (item: Omit<ButtonItem, 'id'>, indices: ItemIndices) => void
createItem: (
item: ButtonItem | Omit<ButtonItem, 'id'>,
indices: ItemIndices
) => void
updateItem: (indices: ItemIndices, updates: Partial<Omit<Item, 'id'>>) => void
detachItemFromStep: (indices: ItemIndices) => void
deleteItem: (indices: ItemIndices) => void
}
const itemsAction = (setTypebot: SetTypebot): ItemsActions => ({
createItem: (
item: Omit<ButtonItem, 'id'>,
item: ButtonItem | Omit<ButtonItem, 'id'>,
{ blockIndex, stepIndex, itemIndex }: ItemIndices
) =>
setTypebot((typebot) =>
produce(typebot, (typebot) => {
const step = typebot.blocks[blockIndex].steps[stepIndex]
if (step.type !== InputStepType.CHOICE) return
step.items.splice(itemIndex, 0, {
const newItem = {
...item,
stepId: step.id,
id: cuid(),
id: 'id' in item ? item.id : cuid(),
}
if (item.outgoingEdgeId) {
const edgeIndex = typebot.edges.findIndex(byId(item.outgoingEdgeId))
edgeIndex !== -1
? (typebot.edges[edgeIndex].from = {
blockId: step.blockId,
stepId: step.id,
itemId: newItem.id,
})
: (newItem.outgoingEdgeId = undefined)
}
step.items.splice(itemIndex, 0, newItem)
})
),
updateItem: (
@ -49,7 +64,15 @@ const itemsAction = (setTypebot: SetTypebot): ItemsActions => ({
} as Item
})
),
detachItemFromStep: ({ blockIndex, stepIndex, itemIndex }: ItemIndices) =>
setTypebot((typebot) =>
produce(typebot, (typebot) => {
const step = typebot.blocks[blockIndex].steps[
stepIndex
] as StepWithItems
step.items.splice(itemIndex, 1)
})
),
deleteItem: ({ blockIndex, stepIndex, itemIndex }: ItemIndices) =>
setTypebot((typebot) =>
produce(typebot, (typebot) => {

View File

@ -13,6 +13,7 @@ import { SetTypebot } from '../TypebotContext'
import produce from 'immer'
import { cleanUpEdgeDraft, deleteEdgeDraft } from './edges'
import cuid from 'cuid'
import { byId } from 'utils'
export type StepsActions = {
createStep: (
@ -74,7 +75,9 @@ const stepsAction = (setTypebot: SetTypebot): StepsActions => ({
deleteStep: ({ blockIndex, stepIndex }: StepIndices) =>
setTypebot((typebot) =>
produce(typebot, (typebot) => {
const removingStep = typebot.blocks[blockIndex].steps[stepIndex]
removeStepFromBlock({ blockIndex, stepIndex })(typebot)
cleanUpEdgeDraft(typebot, removingStep.id)
removeEmptyBlocks(typebot)
})
),
@ -83,8 +86,6 @@ const stepsAction = (setTypebot: SetTypebot): StepsActions => ({
const removeStepFromBlock =
({ blockIndex, stepIndex }: StepIndices) =>
(typebot: WritableDraft<Typebot>) => {
const removingStep = typebot.blocks[blockIndex].steps[stepIndex]
cleanUpEdgeDraft(typebot, removingStep.id)
typebot.blocks[blockIndex].steps.splice(stepIndex, 1)
}
@ -122,11 +123,20 @@ const moveStepToBlock = (
step: DraggableStep,
blockId: string,
{ blockIndex, stepIndex }: StepIndices
) =>
typebot.blocks[blockIndex].steps.splice(stepIndex ?? 0, 0, {
...step,
blockId,
outgoingEdgeId: undefined,
})
) => {
const newStep = { ...step, blockId }
if (step.outgoingEdgeId) {
if (typebot.blocks[blockIndex].steps.length > stepIndex ?? 0) {
deleteEdgeDraft(typebot, step.outgoingEdgeId)
newStep.outgoingEdgeId = undefined
} else {
const edgeIndex = typebot.edges.findIndex(byId(step.outgoingEdgeId))
edgeIndex !== -1
? (typebot.edges[edgeIndex].from.blockId = blockId)
: (newStep.outgoingEdgeId = undefined)
}
}
typebot.blocks[blockIndex].steps.splice(stepIndex ?? 0, 0, newStep)
}
export { stepsAction, createStepDraft }

View File

@ -30,7 +30,7 @@ test.describe.parallel('Embed bubble step', () => {
await page.fill('input[placeholder="Paste the link or code..."]', pdfSrc)
await expect(page.locator('iframe#embed-bubble-content')).toHaveAttribute(
'src',
`https://docs.google.com/viewer?embedded=true&url=${pdfSrc}`
pdfSrc
)
await page.fill(
'input[placeholder="Paste the link or code..."]',

View File

@ -51,7 +51,10 @@ test.describe.parallel('Editor', () => {
await expect(page.locator('[data-testid="edge"] >> nth=0')).toBeVisible()
await expect(page.locator('[data-testid="edge"] >> nth=1')).toBeVisible()
await page.click('[data-testid="clickable-edge"] >> nth=0', { force: true })
await page.click('[data-testid="clickable-edge"] >> nth=0', {
force: true,
button: 'right',
})
await page.click('text=Delete')
const total = await page.locator('[data-testid="edge"]').count()
expect(total).toBe(1)