Skip to content

Commit

Permalink
✨ (editor) Actions on multiple groups
Browse files Browse the repository at this point in the history
You can now select groups, move, copy, delete them easily

Closes #830, closes #1092
  • Loading branch information
baptisteArno committed Jan 23, 2024
1 parent 8ec3916 commit 2c20e96
Show file tree
Hide file tree
Showing 32 changed files with 1,043 additions and 282 deletions.
4 changes: 3 additions & 1 deletion apps/builder/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,14 @@
"slate": "0.94.1",
"slate-history": "0.93.0",
"slate-react": "0.94.2",
"sonner": "1.3.1",
"stripe": "12.13.0",
"svg-round-corners": "0.4.1",
"swr": "2.2.0",
"tinycolor2": "1.6.0",
"unsplash-js": "7.0.18",
"use-debounce": "9.0.4"
"use-debounce": "9.0.4",
"zustand": "4.5.0"
},
"devDependencies": {
"@chakra-ui/styled-system": "2.9.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { StatsCards } from './StatsCards'
import { ChangePlanModal } from '@/features/billing/components/ChangePlanModal'
import { Graph } from '@/features/graph/components/Graph'
import { GraphProvider } from '@/features/graph/providers/GraphProvider'
import { GroupsCoordinatesProvider } from '@/features/graph/providers/GroupsCoordinateProvider'
import { useTranslate } from '@tolgee/react'
import { trpc } from '@/lib/trpc'
import { isDefined } from '@typebot.io/lib'
Expand Down Expand Up @@ -51,17 +50,15 @@ export const AnalyticsGraphContainer = ({ stats }: { stats?: Stats }) => {
>
{publishedTypebot && stats ? (
<GraphProvider isReadOnly>
<GroupsCoordinatesProvider groups={publishedTypebot?.groups}>
<EventsCoordinatesProvider events={publishedTypebot?.events}>
<Graph
flex="1"
typebot={publishedTypebot}
onUnlockProPlanClick={onOpen}
totalAnswers={data?.totalAnswers}
totalVisitedEdges={edgesData?.totalVisitedEdges}
/>
</EventsCoordinatesProvider>
</GroupsCoordinatesProvider>
<EventsCoordinatesProvider events={publishedTypebot?.events}>
<Graph
flex="1"
typebot={publishedTypebot}
onUnlockProPlanClick={onOpen}
totalAnswers={data?.totalAnswers}
totalVisitedEdges={edgesData?.totalVisitedEdges}
/>
</EventsCoordinatesProvider>
</GraphProvider>
) : (
<Flex
Expand Down
18 changes: 13 additions & 5 deletions apps/builder/src/features/editor/components/BlocksSideBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { IntegrationBlockType } from '@typebot.io/schemas/features/blocks/integr
import { LogicBlockType } from '@typebot.io/schemas/features/blocks/logic/constants'
import { BlockV6 } from '@typebot.io/schemas'
import { enabledBlocks } from '@typebot.io/forge-repository'
import { useDebouncedCallback } from 'use-debounce'

// Integration blocks migrated to forged blocks
const legacyIntegrationBlocks = [
Expand All @@ -42,6 +43,8 @@ export const BlocksSideBar = () => {
const [isLocked, setIsLocked] = useState(true)
const [isExtended, setIsExtended] = useState(true)

const closeSideBar = useDebouncedCallback(() => setIsExtended(false), 200)

const handleMouseMove = (event: MouseEvent) => {
if (!draggedBlockType) return
const { clientX, clientY } = event
Expand Down Expand Up @@ -75,11 +78,14 @@ export const BlocksSideBar = () => {

const handleLockClick = () => setIsLocked(!isLocked)

const handleDockBarEnter = () => setIsExtended(true)
const handleDockBarEnter = () => {
closeSideBar.flush()
setIsExtended(true)
}

const handleMouseLeave = () => {
if (isLocked) return
setIsExtended(false)
closeSideBar()
}

return (
Expand Down Expand Up @@ -200,12 +206,14 @@ export const BlocksSideBar = () => {
<Flex
pos="absolute"
h="100%"
right="-50px"
w="50px"
right="-70px"
w="450px"
top="0"
justify="center"
justify="flex-end"
pr="10"
align="center"
onMouseEnter={handleDockBarEnter}
zIndex={-1}
>
<Flex w="5px" h="20px" bgColor="gray.400" rounded="md" />
</Flex>
Expand Down
13 changes: 5 additions & 8 deletions apps/builder/src/features/editor/components/EditorPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { TypebotHeader } from './TypebotHeader'
import { Graph } from '@/features/graph/components/Graph'
import { GraphDndProvider } from '@/features/graph/providers/GraphDndProvider'
import { GraphProvider } from '@/features/graph/providers/GraphProvider'
import { GroupsCoordinatesProvider } from '@/features/graph/providers/GroupsCoordinateProvider'
import { EventsCoordinatesProvider } from '@/features/graph/providers/EventsCoordinateProvider'
import { TypebotNotFoundPage } from './TypebotNotFoundPage'

Expand Down Expand Up @@ -50,13 +49,11 @@ export const EditorPage = () => {
currentUserMode === 'read' || currentUserMode === 'guest'
}
>
<GroupsCoordinatesProvider groups={typebot.groups}>
<EventsCoordinatesProvider events={typebot.events}>
<Graph flex="1" typebot={typebot} key={typebot.id} />
<BoardMenuButton pos="absolute" right="40px" top="20px" />
<RightPanel />
</EventsCoordinatesProvider>
</GroupsCoordinatesProvider>
<EventsCoordinatesProvider events={typebot.events}>
<Graph flex="1" typebot={typebot} key={typebot.id} />
<BoardMenuButton pos="absolute" right="40px" top="20px" />
<RightPanel />
</EventsCoordinatesProvider>
</GraphProvider>
</GraphDndProvider>
) : (
Expand Down
38 changes: 30 additions & 8 deletions apps/builder/src/features/editor/components/TypebotHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import { isDefined, isNotDefined } from '@typebot.io/lib'
import { EditableTypebotName } from './EditableTypebotName'
import Link from 'next/link'
import { EditableEmojiOrImageIcon } from '@/components/EditableEmojiOrImageIcon'
import { useUndoShortcut } from '@/hooks/useUndoShortcut'
import { useDebouncedCallback } from 'use-debounce'
import { ShareTypebotButton } from '@/features/share/components/ShareTypebotButton'
import { PublishButton } from '@/features/publish/components/PublishButton'
Expand All @@ -33,6 +32,7 @@ import { SupportBubble } from '@/components/SupportBubble'
import { isCloudProdInstance } from '@/helpers/isCloudProdInstance'
import { useTranslate } from '@tolgee/react'
import { GuestTypebotHeader } from './UnauthenticatedTypebotHeader'
import { useKeyboardShortcuts } from '@/hooks/useKeyboardShortcuts'

export const TypebotHeader = () => {
const { t } = useTranslate()
Expand Down Expand Up @@ -60,6 +60,11 @@ export const TypebotHeader = () => {
const hideUndoShortcutTooltipLater = useDebouncedCallback(() => {
setUndoShortcutTooltipOpen(false)
}, 1000)
const [isRedoShortcutTooltipOpen, setRedoShortcutTooltipOpen] =
useState(false)
const hideRedoShortcutTooltipLater = useDebouncedCallback(() => {
setRedoShortcutTooltipOpen(false)
}, 1000)
const { isOpen, onOpen } = useDisclosure()
const headerBgColor = useColorModeValue('white', 'gray.900')

Expand All @@ -76,12 +81,21 @@ export const TypebotHeader = () => {
setRightPanel(RightPanel.PREVIEW)
}

useUndoShortcut(() => {
if (!canUndo) return
hideUndoShortcutTooltipLater.flush()
setUndoShortcutTooltipOpen(true)
hideUndoShortcutTooltipLater()
undo()
useKeyboardShortcuts({
undo: () => {
if (!canUndo) return
hideUndoShortcutTooltipLater.flush()
setUndoShortcutTooltipOpen(true)
hideUndoShortcutTooltipLater()
undo()
},
redo: () => {
if (!canRedo) return
hideUndoShortcutTooltipLater.flush()
setRedoShortcutTooltipOpen(true)
hideRedoShortcutTooltipLater()
redo()
},
})

const handleHelpClick = () => {
Expand Down Expand Up @@ -229,7 +243,15 @@ export const TypebotHeader = () => {
/>
</Tooltip>

<Tooltip label={t('editor.header.redoButton.label')}>
<Tooltip
label={
isRedoShortcutTooltipOpen
? t('editor.header.undo.tooltip.label')
: t('editor.header.redoButton.label')
}
isOpen={isRedoShortcutTooltipOpen ? true : undefined}
hasArrow={isRedoShortcutTooltipOpen}
>
<IconButton
display={['none', 'flex']}
icon={<RedoIcon />}
Expand Down
14 changes: 10 additions & 4 deletions apps/builder/src/features/editor/hooks/useUndo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@ const initialState = {
future: [],
}

type Params = { isReadOnly?: boolean }
type Params<T extends { updatedAt: Date }> = {
isReadOnly?: boolean
onUndo?: (state: T) => void
onRedo?: (state: T) => void
}

export const useUndo = <T extends { updatedAt: Date }>(
initialPresent?: T,
params?: Params
params?: Params<T>
): [T | undefined, Actions<T>] => {
const [history, setHistory] = useState<History<T>>(initialState)
const presentRef = useRef<T | null>(initialPresent ?? null)
Expand All @@ -51,7 +55,8 @@ export const useUndo = <T extends { updatedAt: Date }>(
future: [present, ...future],
})
presentRef.current = newPresent
}, [history, params?.isReadOnly])
if (params?.onUndo) params.onUndo(newPresent)
}, [history, params])

const redo = useCallback(() => {
if (params?.isReadOnly) return
Expand All @@ -66,7 +71,8 @@ export const useUndo = <T extends { updatedAt: Date }>(
future: newFuture,
})
presentRef.current = next
}, [history, params?.isReadOnly])
if (params?.onRedo) params.onRedo(next)
}, [history, params])

const set = useCallback(
(newPresentArg: T | ((current: T) => T) | undefined) => {
Expand Down
17 changes: 16 additions & 1 deletion apps/builder/src/features/editor/providers/TypebotProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { isPublished as isPublishedHelper } from '@/features/publish/helpers/isP
import { convertPublicTypebotToTypebot } from '@/features/publish/helpers/convertPublicTypebotToTypebot'
import { trpc } from '@/lib/trpc'
import { EventsActions, eventsActions } from './typebotActions/events'
import { useGroupsStore } from '@/features/graph/hooks/useGroupsStore'

const autoSaveTimeout = 10000

Expand Down Expand Up @@ -87,6 +88,9 @@ export const TypebotProvider = ({
}) => {
const { showToast } = useToast()
const [is404, setIs404] = useState(false)
const setGroupsCoordinates = useGroupsStore(
(state) => state.setGroupsCoordinates
)

const {
data: typebotData,
Expand Down Expand Up @@ -168,23 +172,34 @@ export const TypebotProvider = ({
{ redo, undo, flush, canRedo, canUndo, set: setLocalTypebot },
] = useUndo<TypebotV6>(undefined, {
isReadOnly,
onUndo: (t) => {
setGroupsCoordinates(t.groups)
},
onRedo: (t) => {
setGroupsCoordinates(t.groups)
},
})

useEffect(() => {
if (!typebot && isDefined(localTypebot)) setLocalTypebot(undefined)
if (!typebot && isDefined(localTypebot)) {
setLocalTypebot(undefined)
setGroupsCoordinates(undefined)
}
if (isFetchingTypebot || !typebot) return
if (
typebot.id !== localTypebot?.id ||
new Date(typebot.updatedAt).getTime() >
new Date(localTypebot.updatedAt).getTime()
) {
setLocalTypebot({ ...typebot })
setGroupsCoordinates(typebot.groups)
flush()
}
}, [
flush,
isFetchingTypebot,
localTypebot,
setGroupsCoordinates,
setLocalTypebot,
showToast,
typebot,
Expand Down
Loading

1 comment on commit 2c20e96

@vercel
Copy link

@vercel vercel bot commented on 2c20e96 Jan 23, 2024

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

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

Please sign in to comment.