Skip to content

Commit

Permalink
perf(editor): 🚸 More predictable edge management
Browse files Browse the repository at this point in the history
  • Loading branch information
baptisteArno committed Mar 25, 2022
1 parent f3c5f6b commit c507ef5
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 24 deletions.
11 changes: 9 additions & 2 deletions apps/builder/components/shared/Graph/Graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
15 changes: 12 additions & 3 deletions apps/builder/contexts/TypebotContext/actions/edges.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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)
Expand Down
37 changes: 30 additions & 7 deletions apps/builder/contexts/TypebotContext/actions/items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: (
Expand All @@ -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) => {
Expand Down
26 changes: 18 additions & 8 deletions apps/builder/contexts/TypebotContext/actions/steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: (
Expand Down Expand Up @@ -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)
})
),
Expand All @@ -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)
}

Expand Down Expand Up @@ -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 }
2 changes: 1 addition & 1 deletion apps/builder/playwright/tests/bubbles/embed.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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..."]',
Expand Down
5 changes: 4 additions & 1 deletion apps/builder/playwright/tests/editor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

3 comments on commit c507ef5

@vercel
Copy link

@vercel vercel bot commented on c507ef5 Mar 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on c507ef5 Mar 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

builder-v2 – ./apps/builder

app.typebot.io
builder-v2-typebot-io.vercel.app
builder-v2-git-main-typebot-io.vercel.app

Please sign in to comment.