🚸 (results) Add progress bar to export results modal
This commit is contained in:
@@ -39,9 +39,7 @@ test.describe('Url input block', () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
await page.click('text=Restart')
|
await page.click('text=Restart')
|
||||||
await page
|
await page.locator(`input[placeholder="Your URL..."]`).fill('test')
|
||||||
.locator(`input[placeholder="Your URL..."]`)
|
|
||||||
.fill('https://https://test')
|
|
||||||
await page.locator('button >> text="Go"').click()
|
await page.locator('button >> text="Go"').click()
|
||||||
await expect(page.locator('text=Try again bro')).toBeVisible()
|
await expect(page.locator('text=Try again bro')).toBeVisible()
|
||||||
await page
|
await page
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ test.describe('Condition block', () => {
|
|||||||
await page.click('button:has-text("Greater than")', { force: true })
|
await page.click('button:has-text("Greater than")', { force: true })
|
||||||
await page.fill('input[placeholder="Type a number..."]', '80')
|
await page.fill('input[placeholder="Type a number..."]', '80')
|
||||||
|
|
||||||
await page.click('button:has-text("Add a comparison")')
|
await page.click('button:has-text("Add comparison")')
|
||||||
|
|
||||||
await page.fill(
|
await page.fill(
|
||||||
':nth-match(input[placeholder="Search for a variable"], 2)',
|
':nth-match(input[placeholder="Search for a variable"], 2)',
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import {
|
|||||||
ModalHeader,
|
ModalHeader,
|
||||||
ModalOverlay,
|
ModalOverlay,
|
||||||
Stack,
|
Stack,
|
||||||
|
Progress,
|
||||||
|
Text,
|
||||||
} from '@chakra-ui/react'
|
} from '@chakra-ui/react'
|
||||||
import { TRPCError } from '@trpc/server'
|
import { TRPCError } from '@trpc/server'
|
||||||
import { unparse } from 'papaparse'
|
import { unparse } from 'papaparse'
|
||||||
@@ -35,9 +37,10 @@ export const ExportAllResultsModal = ({ isOpen, onClose }: Props) => {
|
|||||||
const workspaceId = typebot?.workspaceId
|
const workspaceId = typebot?.workspaceId
|
||||||
const typebotId = typebot?.id
|
const typebotId = typebot?.id
|
||||||
const { showToast } = useToast()
|
const { showToast } = useToast()
|
||||||
const { resultHeader: existingResultHeader } = useResults()
|
const { resultHeader: existingResultHeader, totalResults } = useResults()
|
||||||
const trpcContext = trpc.useContext()
|
const trpcContext = trpc.useContext()
|
||||||
const [isExportLoading, setIsExportLoading] = useState(false)
|
const [isExportLoading, setIsExportLoading] = useState(false)
|
||||||
|
const [exportProgressValue, setExportProgressValue] = useState(0)
|
||||||
|
|
||||||
const [areDeletedBlocksIncluded, setAreDeletedBlocksIncluded] =
|
const [areDeletedBlocksIncluded, setAreDeletedBlocksIncluded] =
|
||||||
useState(false)
|
useState(false)
|
||||||
@@ -55,6 +58,7 @@ export const ExportAllResultsModal = ({ isOpen, onClose }: Props) => {
|
|||||||
if (!workspaceId || !typebotId) return []
|
if (!workspaceId || !typebotId) return []
|
||||||
const allResults = []
|
const allResults = []
|
||||||
let cursor: string | undefined
|
let cursor: string | undefined
|
||||||
|
setExportProgressValue(0)
|
||||||
do {
|
do {
|
||||||
try {
|
try {
|
||||||
const { results, nextCursor } =
|
const { results, nextCursor } =
|
||||||
@@ -64,9 +68,11 @@ export const ExportAllResultsModal = ({ isOpen, onClose }: Props) => {
|
|||||||
cursor,
|
cursor,
|
||||||
})
|
})
|
||||||
allResults.push(...results)
|
allResults.push(...results)
|
||||||
|
setExportProgressValue((allResults.length / totalResults) * 100)
|
||||||
cursor = nextCursor ?? undefined
|
cursor = nextCursor ?? undefined
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showToast({ description: (error as TRPCError).message })
|
showToast({ description: (error as TRPCError).message })
|
||||||
|
return []
|
||||||
}
|
}
|
||||||
} while (cursor)
|
} while (cursor)
|
||||||
|
|
||||||
@@ -80,6 +86,8 @@ export const ExportAllResultsModal = ({ isOpen, onClose }: Props) => {
|
|||||||
|
|
||||||
const results = await getAllResults()
|
const results = await getAllResults()
|
||||||
|
|
||||||
|
if (!results.length) return setIsExportLoading(false)
|
||||||
|
|
||||||
const resultHeader = areDeletedBlocksIncluded
|
const resultHeader = areDeletedBlocksIncluded
|
||||||
? parseResultHeader(
|
? parseResultHeader(
|
||||||
publishedTypebot,
|
publishedTypebot,
|
||||||
@@ -144,7 +152,17 @@ export const ExportAllResultsModal = ({ isOpen, onClose }: Props) => {
|
|||||||
initialValue={false}
|
initialValue={false}
|
||||||
onCheckChange={setAreDeletedBlocksIncluded}
|
onCheckChange={setAreDeletedBlocksIncluded}
|
||||||
/>
|
/>
|
||||||
<AlertInfo>The export may take up to 1 minute.</AlertInfo>
|
{totalResults > 2000 ? (
|
||||||
|
<AlertInfo>The export may take a while.</AlertInfo>
|
||||||
|
) : (
|
||||||
|
<AlertInfo>The export may take up to 1 minute.</AlertInfo>
|
||||||
|
)}
|
||||||
|
{isExportLoading && (
|
||||||
|
<Stack>
|
||||||
|
<Text>Fetching all results...</Text>
|
||||||
|
<Progress value={exportProgressValue} borderRadius="md" />
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter as={HStack}>
|
<ModalFooter as={HStack}>
|
||||||
<Button onClick={onClose} variant="ghost" size="sm">
|
<Button onClick={onClose} variant="ghost" size="sm">
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ export type WorkspaceInApp = Omit<
|
|||||||
| 'chatsLimitSecondEmailSentAt'
|
| 'chatsLimitSecondEmailSentAt'
|
||||||
| 'storageLimitFirstEmailSentAt'
|
| 'storageLimitFirstEmailSentAt'
|
||||||
| 'storageLimitSecondEmailSentAt'
|
| 'storageLimitSecondEmailSentAt'
|
||||||
| 'customChatsLimit'
|
|
||||||
| 'customStorageLimit'
|
| 'customStorageLimit'
|
||||||
| 'additionalChatsIndex'
|
| 'additionalChatsIndex'
|
||||||
| 'additionalStorageIndex'
|
| 'additionalStorageIndex'
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ export const getWorkspace = authenticatedProcedure
|
|||||||
chatsLimitSecondEmailSentAt: true,
|
chatsLimitSecondEmailSentAt: true,
|
||||||
storageLimitFirstEmailSentAt: true,
|
storageLimitFirstEmailSentAt: true,
|
||||||
storageLimitSecondEmailSentAt: true,
|
storageLimitSecondEmailSentAt: true,
|
||||||
customChatsLimit: true,
|
|
||||||
customStorageLimit: true,
|
customStorageLimit: true,
|
||||||
additionalChatsIndex: true,
|
additionalChatsIndex: true,
|
||||||
additionalStorageIndex: true,
|
additionalStorageIndex: true,
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
export const validateUrl = (url: string) => {
|
const urlRegex =
|
||||||
try {
|
/^(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})$/
|
||||||
new URL(url)
|
|
||||||
return true
|
export const validateUrl = (url: string) => urlRegex.test(url)
|
||||||
} catch (_) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -14,12 +14,12 @@
|
|||||||
"db:migrate": "pnpm migrate:deploy"
|
"db:migrate": "pnpm migrate:deploy"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/client": "5.0.0"
|
"@prisma/client": "5.8.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "20.4.2",
|
"@types/node": "20.4.2",
|
||||||
"dotenv-cli": "7.2.1",
|
"dotenv-cli": "7.2.1",
|
||||||
"prisma": "5.0.0",
|
"prisma": "5.8.0",
|
||||||
"@typebot.io/tsconfig": "workspace:*",
|
"@typebot.io/tsconfig": "workspace:*",
|
||||||
"tsx": "3.12.7",
|
"tsx": "3.12.7",
|
||||||
"typescript": "5.3.2"
|
"typescript": "5.3.2"
|
||||||
|
|||||||
50
pnpm-lock.yaml
generated
50
pnpm-lock.yaml
generated
@@ -1404,8 +1404,8 @@ importers:
|
|||||||
packages/prisma:
|
packages/prisma:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@prisma/client':
|
'@prisma/client':
|
||||||
specifier: 5.0.0
|
specifier: 5.8.0
|
||||||
version: 5.0.0(prisma@5.0.0)
|
version: 5.8.0(prisma@5.8.0)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@typebot.io/tsconfig':
|
'@typebot.io/tsconfig':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
@@ -1417,8 +1417,8 @@ importers:
|
|||||||
specifier: 7.2.1
|
specifier: 7.2.1
|
||||||
version: 7.2.1
|
version: 7.2.1
|
||||||
prisma:
|
prisma:
|
||||||
specifier: 5.0.0
|
specifier: 5.8.0
|
||||||
version: 5.0.0
|
version: 5.8.0
|
||||||
tsx:
|
tsx:
|
||||||
specifier: 3.12.7
|
specifier: 3.12.7
|
||||||
version: 3.12.7
|
version: 3.12.7
|
||||||
@@ -6608,8 +6608,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
|
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@prisma/client@5.0.0(prisma@5.0.0):
|
/@prisma/client@5.8.0(prisma@5.8.0):
|
||||||
resolution: {integrity: sha512-XlO5ELNAQ7rV4cXIDJUNBEgdLwX3pjtt9Q/RHqDpGf43szpNJx2hJnggfFs7TKNx0cOFsl6KJCSfqr5duEU/bQ==}
|
resolution: {integrity: sha512-QxO6C4MaA/ysTIbC+EcAH1aX/YkpymhXtO6zPdk+FvA7+59tNibIYpd+7koPdViLg2iKES4ojsxWNUGNJaEcbA==}
|
||||||
engines: {node: '>=16.13'}
|
engines: {node: '>=16.13'}
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -6618,17 +6618,35 @@ packages:
|
|||||||
prisma:
|
prisma:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@prisma/engines-version': 4.17.0-26.6b0aef69b7cdfc787f822ecd7cdc76d5f1991584
|
prisma: 5.8.0
|
||||||
prisma: 5.0.0
|
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@prisma/engines-version@4.17.0-26.6b0aef69b7cdfc787f822ecd7cdc76d5f1991584:
|
/@prisma/debug@5.8.0:
|
||||||
resolution: {integrity: sha512-HHiUF6NixsldsP3JROq07TYBLEjXFKr6PdH8H4gK/XAoTmIplOJBCgrIUMrsRAnEuGyRoRLXKXWUb943+PFoKQ==}
|
resolution: {integrity: sha512-ZqPpkvbovu/kQJ1bvy57NO4dw97fpQGcbQSCtsqlwSE1UNKJP75R3BKxdznk8ZPMY+GJdMRetWNv4oAvSbWn8Q==}
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@prisma/engines@5.0.0:
|
/@prisma/engines-version@5.8.0-37.0a83d8541752d7582de2ebc1ece46519ce72a848:
|
||||||
resolution: {integrity: sha512-kyT/8fd0OpWmhAU5YnY7eP31brW1q1YrTGoblWrhQJDiN/1K+Z8S1kylcmtjqx5wsUGcP1HBWutayA/jtyt+sg==}
|
resolution: {integrity: sha512-cXcoVweYbnv8xRfkWq9oj8BECOdzHUazrSpYCa0ehp5TNz4l5Spa8jbq/VROCTzj3ZncH5D9Q2TmySYTOUeKlw==}
|
||||||
|
|
||||||
|
/@prisma/engines@5.8.0:
|
||||||
|
resolution: {integrity: sha512-Qhqm9WWLujNEC13AuZlUO14SQ15tNLe5puaz+tOk7UqINqJ3PtqMmuSuzomiw2diGVqZ+HYiSQzlR3+pPucVHA==}
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
|
dependencies:
|
||||||
|
'@prisma/debug': 5.8.0
|
||||||
|
'@prisma/engines-version': 5.8.0-37.0a83d8541752d7582de2ebc1ece46519ce72a848
|
||||||
|
'@prisma/fetch-engine': 5.8.0
|
||||||
|
'@prisma/get-platform': 5.8.0
|
||||||
|
|
||||||
|
/@prisma/fetch-engine@5.8.0:
|
||||||
|
resolution: {integrity: sha512-1CAuE+JoYsPNggMEn6qk0zos06Uc9bYZBJ0VBPHD6R7REL05614koAbOCmn52IaYz3nobb7f25hqW6AY7rLkIw==}
|
||||||
|
dependencies:
|
||||||
|
'@prisma/debug': 5.8.0
|
||||||
|
'@prisma/engines-version': 5.8.0-37.0a83d8541752d7582de2ebc1ece46519ce72a848
|
||||||
|
'@prisma/get-platform': 5.8.0
|
||||||
|
|
||||||
|
/@prisma/get-platform@5.8.0:
|
||||||
|
resolution: {integrity: sha512-Nk3rhTFZ1LYkFZJnpSvQcLPCaBWgJQfteHII6UEENOOkYlmP0k3FuswND54tzzEr4qs39wOdV9pbXKX9U2lv7A==}
|
||||||
|
dependencies:
|
||||||
|
'@prisma/debug': 5.8.0
|
||||||
|
|
||||||
/@radix-ui/primitive@1.0.1:
|
/@radix-ui/primitive@1.0.1:
|
||||||
resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==}
|
resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==}
|
||||||
@@ -17995,13 +18013,13 @@ packages:
|
|||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/prisma@5.0.0:
|
/prisma@5.8.0:
|
||||||
resolution: {integrity: sha512-KYWk83Fhi1FH59jSpavAYTt2eoMVW9YKgu8ci0kuUnt6Dup5Qy47pcB4/TLmiPAbhGrxxSz7gsSnJcCmkyPANA==}
|
resolution: {integrity: sha512-hDKoEqPt2qEUTH5yGO3l27CBnPtwvte0CGMKrpCr9+/A919JghfqJ3qgCGgMbOwdkXUOzdho0RH9tyUF3UhpMw==}
|
||||||
engines: {node: '>=16.13'}
|
engines: {node: '>=16.13'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@prisma/engines': 5.0.0
|
'@prisma/engines': 5.8.0
|
||||||
|
|
||||||
/prismjs@1.29.0:
|
/prismjs@1.29.0:
|
||||||
resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==}
|
resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==}
|
||||||
|
|||||||
Reference in New Issue
Block a user