2
0

🚸 (results) Add progress bar to export results modal

This commit is contained in:
Baptiste Arnaud
2024-01-11 10:36:48 +01:00
parent 03258e0f64
commit 5d971f7b6f
8 changed files with 62 additions and 34 deletions

View File

@ -39,9 +39,7 @@ test.describe('Url input block', () => {
)
await page.click('text=Restart')
await page
.locator(`input[placeholder="Your URL..."]`)
.fill('https://https://test')
await page.locator(`input[placeholder="Your URL..."]`).fill('test')
await page.locator('button >> text="Go"').click()
await expect(page.locator('text=Try again bro')).toBeVisible()
await page

View File

@ -25,7 +25,7 @@ test.describe('Condition block', () => {
await page.click('button:has-text("Greater than")', { force: true })
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(
':nth-match(input[placeholder="Search for a variable"], 2)',

View File

@ -14,6 +14,8 @@ import {
ModalHeader,
ModalOverlay,
Stack,
Progress,
Text,
} from '@chakra-ui/react'
import { TRPCError } from '@trpc/server'
import { unparse } from 'papaparse'
@ -35,9 +37,10 @@ export const ExportAllResultsModal = ({ isOpen, onClose }: Props) => {
const workspaceId = typebot?.workspaceId
const typebotId = typebot?.id
const { showToast } = useToast()
const { resultHeader: existingResultHeader } = useResults()
const { resultHeader: existingResultHeader, totalResults } = useResults()
const trpcContext = trpc.useContext()
const [isExportLoading, setIsExportLoading] = useState(false)
const [exportProgressValue, setExportProgressValue] = useState(0)
const [areDeletedBlocksIncluded, setAreDeletedBlocksIncluded] =
useState(false)
@ -55,6 +58,7 @@ export const ExportAllResultsModal = ({ isOpen, onClose }: Props) => {
if (!workspaceId || !typebotId) return []
const allResults = []
let cursor: string | undefined
setExportProgressValue(0)
do {
try {
const { results, nextCursor } =
@ -64,9 +68,11 @@ export const ExportAllResultsModal = ({ isOpen, onClose }: Props) => {
cursor,
})
allResults.push(...results)
setExportProgressValue((allResults.length / totalResults) * 100)
cursor = nextCursor ?? undefined
} catch (error) {
showToast({ description: (error as TRPCError).message })
return []
}
} while (cursor)
@ -80,6 +86,8 @@ export const ExportAllResultsModal = ({ isOpen, onClose }: Props) => {
const results = await getAllResults()
if (!results.length) return setIsExportLoading(false)
const resultHeader = areDeletedBlocksIncluded
? parseResultHeader(
publishedTypebot,
@ -144,7 +152,17 @@ export const ExportAllResultsModal = ({ isOpen, onClose }: Props) => {
initialValue={false}
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>
<ModalFooter as={HStack}>
<Button onClick={onClose} variant="ghost" size="sm">

View File

@ -23,7 +23,6 @@ export type WorkspaceInApp = Omit<
| 'chatsLimitSecondEmailSentAt'
| 'storageLimitFirstEmailSentAt'
| 'storageLimitSecondEmailSentAt'
| 'customChatsLimit'
| 'customStorageLimit'
| 'additionalChatsIndex'
| 'additionalStorageIndex'

View File

@ -31,7 +31,6 @@ export const getWorkspace = authenticatedProcedure
chatsLimitSecondEmailSentAt: true,
storageLimitFirstEmailSentAt: true,
storageLimitSecondEmailSentAt: true,
customChatsLimit: true,
customStorageLimit: true,
additionalChatsIndex: true,
additionalStorageIndex: true,

View File

@ -1,8 +1,4 @@
export const validateUrl = (url: string) => {
try {
new URL(url)
return true
} catch (_) {
return false
}
}
const urlRegex =
/^(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,})$/
export const validateUrl = (url: string) => urlRegex.test(url)

View File

@ -14,12 +14,12 @@
"db:migrate": "pnpm migrate:deploy"
},
"dependencies": {
"@prisma/client": "5.0.0"
"@prisma/client": "5.8.0"
},
"devDependencies": {
"@types/node": "20.4.2",
"dotenv-cli": "7.2.1",
"prisma": "5.0.0",
"prisma": "5.8.0",
"@typebot.io/tsconfig": "workspace:*",
"tsx": "3.12.7",
"typescript": "5.3.2"

50
pnpm-lock.yaml generated
View File

@ -1404,8 +1404,8 @@ importers:
packages/prisma:
dependencies:
'@prisma/client':
specifier: 5.0.0
version: 5.0.0(prisma@5.0.0)
specifier: 5.8.0
version: 5.8.0(prisma@5.8.0)
devDependencies:
'@typebot.io/tsconfig':
specifier: workspace:*
@ -1417,8 +1417,8 @@ importers:
specifier: 7.2.1
version: 7.2.1
prisma:
specifier: 5.0.0
version: 5.0.0
specifier: 5.8.0
version: 5.8.0
tsx:
specifier: 3.12.7
version: 3.12.7
@ -6608,8 +6608,8 @@ packages:
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
dev: false
/@prisma/client@5.0.0(prisma@5.0.0):
resolution: {integrity: sha512-XlO5ELNAQ7rV4cXIDJUNBEgdLwX3pjtt9Q/RHqDpGf43szpNJx2hJnggfFs7TKNx0cOFsl6KJCSfqr5duEU/bQ==}
/@prisma/client@5.8.0(prisma@5.8.0):
resolution: {integrity: sha512-QxO6C4MaA/ysTIbC+EcAH1aX/YkpymhXtO6zPdk+FvA7+59tNibIYpd+7koPdViLg2iKES4ojsxWNUGNJaEcbA==}
engines: {node: '>=16.13'}
requiresBuild: true
peerDependencies:
@ -6618,17 +6618,35 @@ packages:
prisma:
optional: true
dependencies:
'@prisma/engines-version': 4.17.0-26.6b0aef69b7cdfc787f822ecd7cdc76d5f1991584
prisma: 5.0.0
prisma: 5.8.0
dev: false
/@prisma/engines-version@4.17.0-26.6b0aef69b7cdfc787f822ecd7cdc76d5f1991584:
resolution: {integrity: sha512-HHiUF6NixsldsP3JROq07TYBLEjXFKr6PdH8H4gK/XAoTmIplOJBCgrIUMrsRAnEuGyRoRLXKXWUb943+PFoKQ==}
dev: false
/@prisma/debug@5.8.0:
resolution: {integrity: sha512-ZqPpkvbovu/kQJ1bvy57NO4dw97fpQGcbQSCtsqlwSE1UNKJP75R3BKxdznk8ZPMY+GJdMRetWNv4oAvSbWn8Q==}
/@prisma/engines@5.0.0:
resolution: {integrity: sha512-kyT/8fd0OpWmhAU5YnY7eP31brW1q1YrTGoblWrhQJDiN/1K+Z8S1kylcmtjqx5wsUGcP1HBWutayA/jtyt+sg==}
/@prisma/engines-version@5.8.0-37.0a83d8541752d7582de2ebc1ece46519ce72a848:
resolution: {integrity: sha512-cXcoVweYbnv8xRfkWq9oj8BECOdzHUazrSpYCa0ehp5TNz4l5Spa8jbq/VROCTzj3ZncH5D9Q2TmySYTOUeKlw==}
/@prisma/engines@5.8.0:
resolution: {integrity: sha512-Qhqm9WWLujNEC13AuZlUO14SQ15tNLe5puaz+tOk7UqINqJ3PtqMmuSuzomiw2diGVqZ+HYiSQzlR3+pPucVHA==}
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:
resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==}
@ -17995,13 +18013,13 @@ packages:
react: 18.2.0
dev: false
/prisma@5.0.0:
resolution: {integrity: sha512-KYWk83Fhi1FH59jSpavAYTt2eoMVW9YKgu8ci0kuUnt6Dup5Qy47pcB4/TLmiPAbhGrxxSz7gsSnJcCmkyPANA==}
/prisma@5.8.0:
resolution: {integrity: sha512-hDKoEqPt2qEUTH5yGO3l27CBnPtwvte0CGMKrpCr9+/A919JghfqJ3qgCGgMbOwdkXUOzdho0RH9tyUF3UhpMw==}
engines: {node: '>=16.13'}
hasBin: true
requiresBuild: true
dependencies:
'@prisma/engines': 5.0.0
'@prisma/engines': 5.8.0
/prismjs@1.29.0:
resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==}