2
0

(editor) Allow empty group titles

This commit is contained in:
Baptiste Arnaud
2023-03-13 09:29:56 +01:00
parent 186328132f
commit f9aef907e3
11 changed files with 42 additions and 21 deletions

View File

@ -3,7 +3,7 @@ import { canReadTypebots } from '@/utils/api/dbRules'
import { authenticatedProcedure } from '@/utils/server/trpc' import { authenticatedProcedure } from '@/utils/server/trpc'
import { TRPCError } from '@trpc/server' import { TRPCError } from '@trpc/server'
import { Group, Typebot, Webhook, WebhookBlock } from 'models' import { Group, Typebot, Webhook, WebhookBlock } from 'models'
import { byId, isWebhookBlock } from 'utils' import { byId, isWebhookBlock, parseGroupTitle } from 'utils'
import { z } from 'zod' import { z } from 'zod'
export const listWebhookBlocksProcedure = authenticatedProcedure export const listWebhookBlocksProcedure = authenticatedProcedure
@ -55,7 +55,7 @@ export const listWebhookBlocksProcedure = authenticatedProcedure
...webhookBlocks, ...webhookBlocks,
...blocks.map((b) => ({ ...blocks.map((b) => ({
id: b.id, id: b.id,
label: `${group.title} > ${b.id}`, label: `${parseGroupTitle(group.title)} > ${b.id}`,
url: typebot?.webhooks.find(byId(b.webhookId))?.url ?? undefined, url: typebot?.webhooks.find(byId(b.webhookId))?.url ?? undefined,
})), })),
] ]

View File

@ -1,7 +1,7 @@
import React from 'react' import React from 'react'
import { Tag, Text } from '@chakra-ui/react' import { Tag, Text } from '@chakra-ui/react'
import { useTypebot } from '@/features/editor' import { useTypebot } from '@/features/editor'
import { byId, isDefined } from 'utils' import { byId, isDefined, parseGroupTitle } from 'utils'
import { JumpBlock } from 'models/features/blocks/logic/jump' import { JumpBlock } from 'models/features/blocks/logic/jump'
type Props = { type Props = {
@ -15,7 +15,8 @@ export const JumpNodeBody = ({ options }: Props) => {
if (!selectedGroup) return <Text color="gray.500">Configure...</Text> if (!selectedGroup) return <Text color="gray.500">Configure...</Text>
return ( return (
<Text> <Text>
Jump to <Tag colorScheme="blue">{selectedGroup.title}</Tag>{' '} Jump to{' '}
<Tag colorScheme="blue">{parseGroupTitle(selectedGroup.title)}</Tag>{' '}
{isDefined(blockIndex) && blockIndex >= 0 ? ( {isDefined(blockIndex) && blockIndex >= 0 ? (
<> <>
at block <Tag colorScheme="blue">{blockIndex + 1}</Tag> at block <Tag colorScheme="blue">{blockIndex + 1}</Tag>

View File

@ -3,7 +3,7 @@ import { useTypebot } from '@/features/editor'
import { Stack } from '@chakra-ui/react' import { Stack } from '@chakra-ui/react'
import { JumpBlock } from 'models/features/blocks/logic/jump' import { JumpBlock } from 'models/features/blocks/logic/jump'
import React from 'react' import React from 'react'
import { byId } from 'utils' import { byId, parseGroupTitle } from 'utils'
type Props = { type Props = {
groupId: string groupId: string
@ -32,7 +32,7 @@ export const JumpSettings = ({ groupId, options, onOptionsChange }: Props) => {
items={typebot.groups items={typebot.groups
.filter((group) => group.id !== currentGroupId) .filter((group) => group.id !== currentGroupId)
.map((group) => ({ .map((group) => ({
label: group.title, label: parseGroupTitle(group.title),
value: group.id, value: group.id,
}))} }))}
selectedItem={selectedGroup?.id} selectedItem={selectedGroup?.id}

View File

@ -1,6 +1,7 @@
import { Select } from '@/components/inputs/Select' import { Select } from '@/components/inputs/Select'
import { Input } from '@chakra-ui/react' import { Input } from '@chakra-ui/react'
import { Group } from 'models' import { Group } from 'models'
import { parseGroupTitle } from 'utils'
type Props = { type Props = {
groups: Group[] groups: Group[]
@ -22,7 +23,7 @@ export const GroupsDropdown = ({
<Select <Select
selectedItem={groupId} selectedItem={groupId}
items={(groups ?? []).map((group) => ({ items={(groups ?? []).map((group) => ({
label: group.title, label: parseGroupTitle(group.title),
value: group.id, value: group.id,
}))} }))}
onSelect={onGroupIdSelected} onSelect={onGroupIdSelected}

View File

@ -9,6 +9,7 @@ import {
WebhookCallBacks, WebhookCallBacks,
} from './blocks' } from './blocks'
import { Coordinates } from '@/features/graph' import { Coordinates } from '@/features/graph'
import { parseGroupTitle } from 'utils'
export type GroupsActions = { export type GroupsActions = {
createGroup: ( createGroup: (
@ -69,7 +70,7 @@ const groupsActions = (
const id = createId() const id = createId()
const newGroup: Group = { const newGroup: Group = {
...group, ...group,
title: `${group.title} copy`, title: `${parseGroupTitle(group.title)} copy`,
id, id,
blocks: group.blocks.map((block) => blocks: group.blocks.map((block) =>
duplicateBlockDraft(id)(block, onWebhookBlockDuplicated) duplicateBlockDraft(id)(block, onWebhookBlockDuplicated)

View File

@ -15,7 +15,7 @@ import {
useBlockDnd, useBlockDnd,
} from '../../../providers' } from '../../../providers'
import { BlockNodesList } from '../BlockNode/BlockNodesList' import { BlockNodesList } from '../BlockNode/BlockNodesList'
import { isDefined, isNotDefined } from 'utils' import { isDefined, isEmpty, isNotDefined } from 'utils'
import { useTypebot, RightPanel, useEditor } from '@/features/editor' import { useTypebot, RightPanel, useEditor } from '@/features/editor'
import { GroupNodeContextMenu } from './GroupNodeContextMenu' import { GroupNodeContextMenu } from './GroupNodeContextMenu'
import { useDebounce } from 'use-debounce' import { useDebounce } from 'use-debounce'
@ -108,6 +108,7 @@ const NonMemoizedDraggableGroupNode = ({
useEffect(() => { useEffect(() => {
setGroupTitle(group.title) setGroupTitle(group.title)
}, [group.title]) }, [group.title])
useEffect(() => { useEffect(() => {
if (!currentCoordinates || isReadOnly) return if (!currentCoordinates || isReadOnly) return
if ( if (
@ -127,7 +128,7 @@ const NonMemoizedDraggableGroupNode = ({
}, [connectingIds, group.id]) }, [connectingIds, group.id])
const handleTitleSubmit = (title: string) => const handleTitleSubmit = (title: string) =>
title.length > 0 ? updateGroup(groupIndex, { title }) : undefined updateGroup(groupIndex, { title })
const handleMouseEnter = () => { const handleMouseEnter = () => {
if (isReadOnly) return if (isReadOnly) return
@ -226,6 +227,16 @@ const NonMemoizedDraggableGroupNode = ({
}} }}
px="1" px="1"
userSelect={'none'} userSelect={'none'}
style={
isEmpty(groupTitle)
? {
display: 'block',
position: 'absolute',
top: '10px',
width: '100px',
}
: undefined
}
/> />
<EditableInput minW="0" px="1" className="prevent-group-drag" /> <EditableInput minW="0" px="1" className="prevent-group-drag" />
</Editable> </Editable>

View File

@ -43,10 +43,7 @@ export const AvatarForm = ({
useOutsideClick({ useOutsideClick({
ref: popoverContainerRef, ref: popoverContainerRef,
handler: () => { handler: onClose,
console.log('close')
onClose()
},
}) })
const isDefaultAvatar = !avatarProps?.url || avatarProps.url.includes('{{') const isDefaultAvatar = !avatarProps?.url || avatarProps.url.includes('{{')

View File

@ -2,7 +2,7 @@ import { authenticateUser } from '@/features/auth/api'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { Group, WebhookBlock } from 'models' import { Group, WebhookBlock } from 'models'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { byId, isWebhookBlock } from 'utils' import { byId, isWebhookBlock, parseGroupTitle } from 'utils'
import { methodNotAllowed } from 'utils/api' import { methodNotAllowed } from 'utils/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {
@ -27,7 +27,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
...emptyWebhookBlocks, ...emptyWebhookBlocks,
...blocks.map((b) => ({ ...blocks.map((b) => ({
blockId: b.id, blockId: b.id,
name: `${group.title} > ${b.id}`, name: `${parseGroupTitle(group.title)} > ${b.id}`,
url: typebot?.webhooks.find(byId(b.webhookId))?.url ?? undefined, url: typebot?.webhooks.find(byId(b.webhookId))?.url ?? undefined,
})), })),
] ]

View File

@ -2,7 +2,7 @@ import { authenticateUser } from '@/features/auth/api'
import prisma from '@/lib/prisma' import prisma from '@/lib/prisma'
import { Group, WebhookBlock } from 'models' import { Group, WebhookBlock } from 'models'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import { byId, isNotDefined, isWebhookBlock } from 'utils' import { byId, isNotDefined, isWebhookBlock, parseGroupTitle } from 'utils'
import { methodNotAllowed } from 'utils/api' import { methodNotAllowed } from 'utils/api'
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {
@ -32,7 +32,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
...blocks.map((s) => ({ ...blocks.map((s) => ({
id: s.id, id: s.id,
groupId: s.groupId, groupId: s.groupId,
name: `${group.title} > ${s.id}`, name: `${parseGroupTitle(group.title)} > ${s.id}`,
})), })),
] ]
}, []) }, [])

View File

@ -10,7 +10,13 @@ import {
InputBlockType, InputBlockType,
ResultInSession, ResultInSession,
} from 'models' } from 'models'
import { isInputBlock, isDefined, byId, isNotEmpty } from './utils' import {
isInputBlock,
isDefined,
byId,
isNotEmpty,
parseGroupTitle,
} from './utils'
export const parseResultHeader = ( export const parseResultHeader = (
typebot: Pick<Typebot, 'groups' | 'variables'>, typebot: Pick<Typebot, 'groups' | 'variables'>,
@ -55,7 +61,7 @@ const parseInputsResultHeader = ({
.flatMap((group) => .flatMap((group) =>
group.blocks.map((block) => ({ group.blocks.map((block) => ({
...block, ...block,
groupTitle: group.title, groupTitle: parseGroupTitle(group.title),
})) }))
) )
.filter((block) => isInputBlock(block)) as (InputBlock & { .filter((block) => isInputBlock(block)) as (InputBlock & {
@ -80,7 +86,8 @@ const parseInputsResultHeader = ({
if ( if (
existingHeader.blocks?.some( existingHeader.blocks?.some(
(block) => block.groupId === inputBlock.groupId (block) => block.groupId === inputBlock.groupId
) ) ||
existingHeader.label.includes('Untitled')
) { ) {
const totalPrevious = existingHeaders.filter((h) => const totalPrevious = existingHeaders.filter((h) =>
h.label.includes(label) h.label.includes(label)

View File

@ -305,3 +305,6 @@ export const getAtPath = <T>(obj: T, path: string): unknown => {
} }
return current return current
} }
export const parseGroupTitle = (title: string) =>
isEmpty(title) ? 'Untitled' : title