Skip to content

Commit

Permalink
Add Pipeline Upload filesize limit
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewballantyne committed Jun 3, 2024
1 parent 20d32e9 commit 00ba348
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ class PipelineImportModal extends Modal {
this.findUploadPipelineInput().selectFile([filePath], { force: true });
}

findUploadError() {
return this.find().findByTestId('pipeline-file-upload-error');
}

mockCreatePipelineAndVersion(params: CreatePipelineAndVersionKFData, namespace: string) {
return cy.interceptOdh(
'POST /api/service/pipelines/:namespace/:serviceName/apis/v2beta1/pipelines/create',
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const initialMockPipelineVersion = buildMockPipelineVersionV2({
pipeline_id: initialMockPipeline.pipeline_id,
});
const pipelineYamlPath = './cypress/tests/mocked/pipelines/mock-upload-pipeline.yaml';
const tooLargePipelineYAMLPath = './cypress/tests/mocked/pipelines/not-a-pipeline-2-megabytes.yaml';

describe('Pipelines', () => {
it('Empty state', () => {
Expand Down Expand Up @@ -580,6 +581,25 @@ describe('Pipelines', () => {
pipelinesTable.getRowById(uploadedMockPipeline.pipeline_id).find().should('exist');
});

it.only('fails to import a too-large file', () => {

Check failure on line 584 in frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelines.cy.ts

View workflow job for this annotation

GitHub Actions / Tests (18.x)

it.only not permitted
initIntercepts({});
pipelinesGlobal.visit(projectName);

// Open the "Import pipeline" modal
pipelinesGlobal.findImportPipelineButton().click();

// Fill out the "Import pipeline" modal and submit
pipelineImportModal.shouldBeOpen();
pipelineImportModal.fillPipelineName('New pipeline');
pipelineImportModal.findUploadError().should('not.exist');
pipelineImportModal.findSubmitButton().should('be.disabled');
pipelineImportModal.uploadPipelineYaml(tooLargePipelineYAMLPath);
pipelineImportModal.findUploadError().should('exist');
pipelineImportModal.uploadPipelineYaml(pipelineYamlPath);
pipelineImportModal.findUploadError().should('not.exist');
pipelineImportModal.findSubmitButton().should('be.enabled');
});

it('imports a new pipeline by url', () => {
initIntercepts({});
pipelinesGlobal.visit(projectName);
Expand Down
102 changes: 75 additions & 27 deletions frontend/src/concepts/pipelines/content/import/PipelineFileUpload.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,90 @@
import * as React from 'react';
import { FileUpload } from '@patternfly/react-core';
import {
Alert,
AlertActionCloseButton,
FileUpload,
Stack,
StackItem,
} from '@patternfly/react-core';

type PipelineFileUploadProps = {
fileContents: string;
onUpload: (fileContents: string) => void;
};

const MAX_SIZE_AS_MB = 1;
const MAX_SIZE = MAX_SIZE_AS_MB * 1024 * 1024; // as bytes

const PipelineFileUpload: React.FC<PipelineFileUploadProps> = ({ fileContents, onUpload }) => {
const [filename, setFilename] = React.useState('');
const [isLoading, setIsLoading] = React.useState(false);
const [dropRejectedError, setDropRejectedError] = React.useState('');

const resetSelection = () => {
setFilename('');
setDropRejectedError('');
setIsLoading(false);
onUpload('');
};

return (
<FileUpload
id="text-file-simple"
type="text"
isReadOnly
value={fileContents}
filename={filename}
filenamePlaceholder="Drag and drop a file or upload one"
onDataChange={(e, content) => onUpload(content)}
onFileInputChange={(e, file) => setFilename(file.name)}
onReadStarted={() => setIsLoading(true)}
onReadFinished={() => {
setIsLoading(false);
}}
onClearClick={() => {
setFilename('');
onUpload('');
}}
dropzoneProps={{
accept: { 'application/x-yaml': ['.yml', '.yaml'] },
}}
isLoading={isLoading}
isRequired
allowEditingUploadedText={false}
browseButtonText="Upload"
data-testid="pipeline-file-upload"
/>
<Stack hasGutter>
<StackItem>
<FileUpload
id="text-file-simple"
type="text"
isReadOnly
value={fileContents}
filename={filename}
filenamePlaceholder="Drag and drop a file or upload one"
onDataChange={(e, content) => onUpload(content)}
onFileInputChange={(e, file) => setFilename(file.name)}
onReadStarted={() => {
setDropRejectedError('');
setIsLoading(true);
}}
onReadFinished={() => {
setIsLoading(false);
}}
onClearClick={resetSelection}
dropzoneProps={{
accept: { 'application/x-yaml': ['.yml', '.yaml'] },
// TODO: consider updating this value if we change the fastify server configs
maxSize: MAX_SIZE,
onDropRejected: (rejections) => {
resetSelection();
const error = rejections[0]?.errors?.[0] ?? {};

let reason = error.message || 'Unknown reason';
// TODO: Find out from PF how to get access to ErrorCode.FileTooLarge
if (error.code === 'file-too-large') {
reason = `File size exceeds ${MAX_SIZE_AS_MB} MB`;
}

setDropRejectedError(reason);
},
}}
isLoading={isLoading}
isRequired
allowEditingUploadedText={false}
browseButtonText="Upload"
data-testid="pipeline-file-upload"
/>
</StackItem>
{dropRejectedError && (
<StackItem>
<Alert
data-testId="pipeline-file-upload-error"
isInline
title="Issue with file upload"
variant="danger"
actionClose={<AlertActionCloseButton onClose={() => setDropRejectedError('')} />}
>
{dropRejectedError}
</Alert>
</StackItem>
)}
</Stack>
);
};

Expand Down

0 comments on commit 00ba348

Please sign in to comment.