Skip to content
Snippets Groups Projects
run-tests-button-modal.tsx 10.1 KiB
Newer Older
brunoravera's avatar
brunoravera committed
import {
  Button,
  Center,
  HStack,
  Icon,
  IconButton,
  Modal,
  ModalContent,
  Text,
  ModalHeader,
  ModalOverlay,
  ModalProps,
  useDisclosure,
  VStack,
  ModalCloseButton,
  ModalBody,
  Select,
  ModalFooter,
  Spinner,
  Box,
  Badge,
brunoravera's avatar
brunoravera committed
  Input,
brunoravera's avatar
brunoravera committed
} from '@chakra-ui/react'
import React from 'react'
import { DropzoneState } from 'react-dropzone'
import { FaPaperclip, FaTrash } from 'react-icons/fa'
import { FileWithName, Implementation, Pattern } from 'src/models'
import { match } from 'ts-pattern'
import { useRunTestsButton } from './use-run-tests-button'
import prettyBytes from 'pretty-bytes'
brunoravera's avatar
brunoravera committed
import { DownloadFileMutation } from 'src/utils/query-builder/download-file-mutation'
brunoravera's avatar
brunoravera committed

export type RunTestsButtonModalProps = {
  implementation: Implementation
  pattern: Pattern
  disclosure: ReturnType<typeof useDisclosure>
} & Partial<ModalProps>

export const RunTestsButtonModal: React.FC<RunTestsButtonModalProps> = ({
  implementation,
  pattern,
  disclosure,
  ...props
}) => {
  const {
brunoravera's avatar
brunoravera committed
    name,
    setName,
brunoravera's avatar
brunoravera committed
    formalizations,
    formalizationId,
    setFormalizationId,
    isValid,
    strategy,
    onRemoveStrategy,
    strategyDropzoneState,
    testCasesInstantiation,
    testCasesInstantiationDropzoneState,
    onRemoveTestCasesInstantiation,
    handleOnRunTestsStep1,
    handleOnRunTestsStep2,
    wrapper,
    onRemoveWrapper,
    wrapperDropzoneState,
brunoravera's avatar
brunoravera committed
    genericJUnitPath,
brunoravera's avatar
brunoravera committed
    step,
  } = useRunTestsButton({
    patternId: pattern.id,
    implementationId: implementation.id,
brunoravera's avatar
brunoravera committed
    onClose: disclosure.onClose,
brunoravera's avatar
brunoravera committed
  })

brunoravera's avatar
brunoravera committed
  const downloadFileMutation = DownloadFileMutation.useMutation({
    onSuccess: (blob) => {
      // Create a URL for the blob and trigger a download
      const url = window.URL.createObjectURL(blob)
      const link = document.createElement('a')
      link.href = url
      link.setAttribute(
        'download',
        genericJUnitPath.substring(genericJUnitPath.lastIndexOf('/') + 1)
brunoravera's avatar
brunoravera committed
      )
brunoravera's avatar
brunoravera committed
      document.body.appendChild(link)
      link.click()
      link.remove()
    },
  })
  const handleOnDownloadJUnit = () => {
    downloadFileMutation.mutate({ filePath: genericJUnitPath })
  }

brunoravera's avatar
brunoravera committed
  return (
    <>
      {disclosure.isOpen && (
brunoravera's avatar
brunoravera committed
        <Modal size="xl" {...disclosure} {...props}>
brunoravera's avatar
brunoravera committed
          <ModalOverlay />
          <ModalContent>
            {match(step)
              .with('Generating', () => (
                <>
                  <ModalHeader>
                    <Text fontSize="md">
                      Correr tests de la implementacion {implementation.name}{' '}
                      del patron {pattern.name}
                    </Text>
                  </ModalHeader>
                  <ModalCloseButton mt="-2" mr="-2" />
brunoravera's avatar
brunoravera committed
                  <ModalBody>
                    <VStack w="full">
                      <HStack
                        spacing="4"
                        w="full"
                        justifyContent="space-between"
                      >
                        <Text>Nombre:</Text>
                        <Input
                          value={name}
                          onChange={(e) => setName(e.target.value)}
                        />
                      </HStack>
                      <HStack
                        spacing="4"
                        w="full"
                        justifyContent="space-between"
                      >
brunoravera's avatar
brunoravera committed
                        <Text>Formalizacion:</Text>
                        <Select
                          name="formalizationId"
                          value={formalizationId}
                          onChange={(e) => setFormalizationId(e.target.value)}
                        >
                          {formalizations.map((formalization, index) => {
                            return (
                              <option
                                key={`formalization-${index}`}
                                value={formalization.id}
                              >
                                {formalization.name}
                              </option>
                            )
                          })}
                        </Select>
                      </HStack>
brunoravera's avatar
brunoravera committed
                    </VStack>
                    <FileSelector
                      source="Strategy"
                      fileWithName={strategy}
                      dropzoneState={strategyDropzoneState}
                      handleOnRemove={onRemoveStrategy}
                    />
brunoravera's avatar
brunoravera committed

brunoravera's avatar
brunoravera committed
                    <FileSelector
                      source="Test cases instantiation"
                      fileWithName={testCasesInstantiation}
                      dropzoneState={testCasesInstantiationDropzoneState}
                      handleOnRemove={onRemoveTestCasesInstantiation}
                    />
                  </ModalBody>
brunoravera's avatar
brunoravera committed
                  <ModalFooter bottom="0">
                    <HStack>
                      <Button variant="outline" onClick={disclosure.onClose}>
                        Cancelar
                      </Button>
                      <Button
                        onClick={handleOnRunTestsStep1}
                        variant="solid"
                        colorScheme="blue"
                        type="submit"
                        isDisabled={!isValid}
                      >
                        Correr
                      </Button>
                    </HStack>
                  </ModalFooter>
                </>
              ))
              .with('Testing', () => (
                <>
                  <ModalHeader>
                    <Text>Descargue el archivo y subalo denuevo</Text>
                  </ModalHeader>
                  <ModalBody>
                    <VStack>
brunoravera's avatar
brunoravera committed
                      <Text>{genericJUnitPath}</Text>
                      <Button onClick={handleOnDownloadJUnit}>download</Button>
brunoravera's avatar
brunoravera committed
                      <FileSelector
                        source="Wrapper completo!"
                        fileWithName={wrapper}
                        dropzoneState={wrapperDropzoneState}
                        handleOnRemove={onRemoveWrapper}
                      />
                      <Button
                        variant="solid"
                        colorScheme="blue"
                        type="submit"
                        onClick={handleOnRunTestsStep2}
                      >
                        Test
                      </Button>
                    </VStack>
                  </ModalBody>
                </>
              ))
              .with('Loading', () => (
                <Box
                  backgroundColor="gray.100"
                  borderRadius="8"
                  h="480px"
                  display="flex"
                  justifyContent="center"
                  alignItems="center"
                >
                  <Spinner size="xl" />
                </Box>
              ))
              .otherwise(() => null)}
          </ModalContent>
        </Modal>
      )}
    </>
  )
}

type FileSelectorProps = {
  source: string
  fileWithName?: FileWithName
  dropzoneState: DropzoneState
  handleOnRemove: () => void
}
const FileSelector: React.FC<FileSelectorProps> = ({
  source,
  fileWithName,
  dropzoneState,
  handleOnRemove,
}) => {
  return (
brunoravera's avatar
brunoravera committed
    <VStack pt="8">
brunoravera's avatar
brunoravera committed
      {!fileWithName && (
        <div {...dropzoneState.getRootProps()}>
          <Center w="100%">
            <input aria-label="upload" {...dropzoneState.getInputProps()} />
            <HStack>
              <Button
                aria-label="add strategy"
brunoravera's avatar
brunoravera committed
                variant="outline"
brunoravera's avatar
brunoravera committed
                justifyContent="flex-start"
                iconSpacing="2"
                display="flex"
                fontWeight="400"
                rightIcon={<Icon as={FaPaperclip} />}
              >
                Agregar {source}
              </Button>
            </HStack>
          </Center>
        </div>
      )}

      <VStack w="full">
        {fileWithName && (
          <>
            <Badge>
              {source} {fileWithName.name}
            </Badge>
            <HStack
              spacing="0"
              w="full"
              border="1px"
              borderColor="gray.200"
              borderRadius="sm"
              bg="white"
              width="full"
              height="min-content"
              mt="0"
              minW="0"
              flex="1"
              alignItems="flex-start"
              fontSize="xs"
              h="52px"
            >
              <Center bg="blue.600" borderLeftRadius="base" px="4" h="52px">
                <Text
                  fontWeight="medium"
                  variant="-1"
                  color="white"
                  textTransform="uppercase"
                >
                  {fileWithName.file.name.split('.')[1] ?? ''}
                </Text>
              </Center>
              <HStack
                h="full"
                borderColor="gray.200"
                borderWidth="px"
                borderStyle="solid"
                borderRadius="base"
                borderLeft="none"
                borderLeftRadius="none"
                ml="0"
                w="full"
                minWidth="0"
                flex="1"
                pt="2"
              >
                <VStack
                  justifyContent={
                    fileWithName.file.size ? 'center' : 'flex-start'
                  }
                  spacing="1"
                  minW="0"
                  flex="1"
                >
                  <Text
                    variant="-1"
                    isTruncated={true}
                    w="full"
                    textAlign="center"
                  >
                    {fileWithName.file.name}
                  </Text>

                  <Text variant="-2" color="gray.500">
                    {prettyBytes(fileWithName.file.size ?? 0)}
                  </Text>
                </VStack>
                <IconButton
                  aria-label="remove formalization"
                  variant="unstyled"
                  color="blue.400"
                  onClick={handleOnRemove}
                  icon={<Icon as={FaTrash} />}
                />
              </HStack>
            </HStack>
          </>
        )}
      </VStack>
    </VStack>
  )
}