2.0.1 • Published 2 years ago

@psyora/psy-s3-uploader v2.0.1

Weekly downloads
-
License
-
Repository
-
Last release
2 years ago

Introduction

Psy-S3-Uploader library is created to securely upload images and files to S3 bucket from and Angular application. This library was generated with Angular CLI version 10.0.14.

This library requries a backend that generates pre-signed url for POST request using createPreSignedPost( ) method. So, bucket inforamtion, secret key and access key are provided in the backend.

Based on the response provided by the backend, the library will directly upload the file to S3 bucket.

Installation Instructions

Step 1: Install the library from npm

To install, run the following command in your angular project

npm i @psyora/psy-s3-uploader

Step 2: Import the library to Angular

To use the library in your application, import it to your angular application in your app or shared module.

import { PsyS3UploaderModule } from '@psyora/psy-s3-uploader';

@NgModule({
    imports: [
        ...,
        PsyS3UploaderModule,
        ...
    ]
})

export class AppModule { }

Step 3: Use the library in the application using the selector

selector: psy-s3-uploader

<psy-s3-uploader></psy-s3-uploader>

Step 4: Verify the image upload dropbox

image

Usage instructions

User Interaface

You can upload a file inside the application in two ways. 1. By dragging and dropping an image 1. By clicking on 'Browse File' and selecting a file to upload

By default, only jpeg, jpg or png images are allowed to be uploaded. However, other types of can be uploaded by specifiying their extensions. They will be explored later.

On successful load, a preview will be shown if an image is selected.

image

You can click on the x button to remove the file from upload.

Uploading a File

To upload the selected file to S3 bucket, you need to call the upload method from your application. This give you control to time your upload programatically.

In your parent component (ts)

import { Component, ViewChild } from '@angular/core';
import { PsyS3UploaderComponent } from 'psy-s3-uploader';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss']
})

export class AppComponent {
  
    @ViewChild(PsyS3UploaderComponent) psyS3Uploader: PsyS3UploaderComponent;

    public upload(): void {
        this.psyS3Uploader.upload();
    };
}

The library supports uploading files to S3 bucket using pre-signed url's. So you need to specify the API endpoint of a function that is able to generate a pre-signed url.

So, you need to construct a params object and provide the upload endpoint. You can import the IPsyS3UploaderConfig from the library and declare it as follows:

import { Component, ViewChild } from '@angular/core';
import { IPsyS3UploaderConfig, PsyS3UploaderComponent } from 'psy-s3-uploader';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss']
})

export class AppComponent {
  
    @ViewChild(PsyS3UploaderComponent) psyS3Uploader: PsyS3UploaderComponent;

    public params: IPsyS3UploaderConfig = {
        uploadApi: 'upload API'
    };

    public upload(): void {
        this.psyS3Uploader.upload();
    };
}

Next when the upload is in progress, two events are emitted to notify the status of upload. 1. response 1. error

Create two functions to handle these events.

import { Component, ViewChild } from '@angular/core';
import { IPsyS3UploaderConfig, PsyS3UploaderComponent } from 'psy-s3-uploader';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss']
})

export class AppComponent {
  
    @ViewChild(PsyS3UploaderComponent) psyS3Uploader: PsyS3UploaderComponent;

    public params: IPsyS3UploaderConfig = {
        uploadApi: 'upload API'
    };

    public upload(): void {
        this.psyS3Uploader.upload();
    };

    public handleResponse(res): void {
        console.log(res)
    };

    public handleError(err): void {
        console.log(err)
    };
}

Finally, in your parent component (html) update the selector with input and output operators

<psy-s3-uploader
    [params]="params"
    (response)="handleResponse($event)"
    (error)="handleError($event)"
></psy-s3-uploader>
<button (click)="upload()">Upload</button>

Now when you can click on Upload button to initiate the upload to S3.

  1. The library will reach out to the upload api end-point and get the pre-signed url, signature info, policy info, upload bucket info etc.
  2. It will then create a form object and will upload to the S3 bucket that was provided by upload api with all the details.
  3. Finally it will notify the parent component of its status

And the results will be logged by the app component.

image

Finally, verify the uploaded image in S3 bucket.

image

Uploading multiple Files

To upload multiple files, specify the multipleFiles param and set it to true

import { Component, ViewChild } from '@angular/core';
import { IPsyS3UploaderConfig, PsyS3UploaderComponent } from 'psy-s3-uploader';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss']
})

export class AppComponent {
  
    @ViewChild(PsyS3UploaderComponent) psyS3Uploader: PsyS3UploaderComponent;

    public params: IPsyS3UploaderConfig = {
        uploadApi: 'upload API',
        multipleFiles: true
    };

    public upload(): void {
        this.psyS3Uploader.upload();
    };

    public handleResponse(res): void {
        console.log(res)
    };

    public handleError(err): void {
        console.log(err)
    };
}

Now, you can select and upload multiple files. When you can click on Upload button to initiate the upload to S3. And the results will be logged by the app component.

image

  1. The library will iterate through all the files and reach out to the upload api end-point and get the pre-signed url, signature info, policy info, upload bucket info etc.
  2. It will then create a form object for every object and will upload to the S3 bucket that was provided by upload api with all the details.
  3. Finally, once all the files are uploaded, it will notify the parent component of its status. And the results will be logged by the app component.

image

Note: Due to asynchronous nature of Javascript, the upload process will be almost simultaneous rather than sequential.

Handling a Failed Upload

On upload failure, you can

  1. retry the process by clicking on the Retry button or by calling the upload method again.
  2. remove the failied upload by clicking on 'x'

image

In case of multiple files, hitting the retry button will reinitate the upload process for only the failed files.

image

Note: A response will not be triggered by the library until all files are successfully uploaded.

In such cases, to get the upload response, the user needs to remove the failed files manually and call the upload method again.

Specifying Maximum files to upload

In cases of multiple file uploads, the library allows you to upload upto 10 files by default. You can adjust the number of files being uploaded by specifying 'maxFiles' parameter.

In case the number of files selected is greater than the maximum files specified, the library will load valid files until the max file limit is reached.

You will be notified with an alert message if you try to upload more than maximum files.

image

If/when the maximum files are uploded, the drop-area disappears.

image

To upload more files, you can remove currently selected files to free up a slot for upload.

Supported Icons

If the uploaded file is not an image. Then the library displays an icon preview.

Currently icon preview is supported for 1. PDF 1. Word 1. Excel

image

Preview Mode

Preview mode is used to render 1. 'preview of an image' by passing image URL 1. 'icon for a document' by specifying the fileType

You can pass an array of URLs to the libray using the previewArray property. Refer to the interface IFilePreview for more information.

public params: IPsyS3UploaderConfig = {
    uploadApi: "value",
    previewArray: [{
        "url": "https://images.unsplash.com/photo-1622522486900-37e2c44647cb?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1868&q=80",
        "fileType": "image/jpeg"
    }, {
        "url": "https://images.unsplash.com/photo-1624024946645-d02c208b1c4d?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1951&q=80",
        "fileType": "image/jpeg"
    }]
};

image

These files are readonly and upload activities cannot be performed on them. If you try to upload, you will get a notification that satys 'No files found'.

image

Deleting a File

A file/image can be deleted from preview mode by specifying 'canDelete' as 'true'. When specified, a delete 'icon' appears on the top right corner of the preview.

public params: IPsyS3UploaderConfig = {
    uploadApi: "value",
    previewArray: [{
        url: "https://images.unsplash.com/photo-1622522486900-37e2c44647cb?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1868&q=80",
        fileType: "image/jpeg",
        canDelete: true
    }, {
        url: "https://images.unsplash.com/photo-1624024946645-d02c208b1c4d?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1951&q=80",
        fileType: "image/jpeg"
    }]
};

image

However, just by clicking on the "🗑" icon, the delete function will not be executed. Since the library is created to delete S3 items from S3 bucket, the key of the object is a required parameter in performing the operation.

They key of the object required to delete the file can be passed to the library by specifying it in the request. It can be passed in two ways: 1. Inside the Delete URL - deleteUrl 1. Inside Query String Parameters - queryStringParameters

By default, the library uses same url that is used for uploading. DELETE method is used and a call is made. However, in case the delete URL is different from the upload URL, it can be specified per object by using deleteUrl params.

Since there are multiple files in previewMode, every file has their own individual delete URLs. They can be passed individally as follows:

In case the delete of S3 Object is done through lambda function, the lambda API can be specified in deleteUrl.

public params: IPsyS3UploaderConfig = {
    uploadApi: "value",
    previewArray: [{
        url: "https://s3.amazonaws.com/uploads.uppy-upload-svc.psyora/obj_1.jpg",
        fileType: "image/jpeg",
        deleteUrl: "https://pbi55zcp89.execute-api.us-east-1.amazonaws.com/poc/upload?key=obj_1",
        canDelete: true
    }, {
        url: "https://s3.amazonaws.com/uploads.uppy-upload-svc.psyora/obj_2.jpg",
        fileType: "image/jpeg",
        deleteUrl: "https://pbi55zcp89.execute-api.us-east-1.amazonaws.com/poc/upload?key=obj_2",
        canDelete: true
    }]
};

In case the key is a queryStringParameter, it can be passed as an Object.

public params: IPsyS3UploaderConfig = {
    uploadApi: "value",
    previewArray: [{
        url: "https://s3.amazonaws.com/uploads.uppy-upload-svc.psyora/obj_1.jpg",
        fileType: "image/jpeg",
        deleteUrl: "https://pbi55zcp89.execute-api.us-east-1.amazonaws.com/poc/upload",
        canDelete: true,
        queryStringParameters: {
            _key: "obj_1"
        },
    }, {
        url: "https://s3.amazonaws.com/uploads.uppy-upload-svc.psyora/obj_2.jpg",
        fileType: "image/jpeg",
        deleteUrl: "https://pbi55zcp89.execute-api.us-east-1.amazonaws.com/poc/upload",
        canDelete: true,
        queryStringParameters: {
            _key: "obj_2"
        }
    }]
};

Objects before deleting

The delete process for a file can be initiated by clicking on the '🗑' icon and confirming the prompt.

Objects confirmation prompt

Object during deletion

Object deleted


Note If all files are deleted, then library will switch from 'preview mode' to 'upload mode'.


Patching files through dataURL

In case only base64 string of a file/image is known, it can be provided to the library as dataURL to the library using fileData parameter.

The library converts the base64 string into a file and will treat just as normally selected file from local PC. Such files can be then be removed from the library or can be uploaded to S3 bucket in a regular manner.

The data is passed as an array using a @Input() parameter:

public fileData: IFileBase64Item[] = [{
    "dataURL": "data:image/jpeg;base64,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",
    "name": "image2.jfif",
    "type": "image/jpeg",
  }, {
    "dataURL": "data:image/png;base64,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",
    "name": "kube-pod.png",
    "type": "image/png"
}]

The interface IFileBase64Item, available from library has the following properties.

interface IFileBase64Item {
   dataURL: "string",
   name: "string",
   type: string
}

It is important to consider the role of multipleFiles property when using the fileData input params.

In case multipleFiles is false, then the first element of the array is patched into the library. If it true, then the array elements are uploaded as files until the maxFiles limit is reached.

The above base64 data, when patched, will render the following output.

Single file

Single file Patch data

Multiple files

Multiple files Patch data

API Reference (Library)

Params

You can further configure the upload behavior through following API's. You can update the params object with the following values.

These values are available in the IPsyS3UploaderConfig interface.

interface IPsyS3UploaderConfig {
    uploadApi: "string",
    uuid: boolean,
    pathPrefix: "string",
    validExtensions: string[],
    width: "string",
    height: "string",
    multipleFiles: boolean,
    maxFileSizeinMB: boolean
    maxFiles: number,
    previewArray?: IFilePreview[],
    customDeleteUrl?: "string",
}
ParamDescriptionRequired
uploadApiAPI Endpoint of the function that generates the pre-signed urlY
uuidChanges file name to a random uuid(v4)N
pathPrefixAllows you to specify a path that will creates/updates a folder in S3 to update the image. Use '/' as a delimter. Note: During input, 'path prefix' should not end with '/' Eg: "public/" (invalid) "public" (valid) )N
validExtensionsOverides the default extensions allowed for uploadN
widthSpecifes the width of the drag area. Default is 20emN
heightSpecifes the height of the drag area. Default is 20emN
multipleFilesAllows to switch between single or multiple file upload mode. Default is 'false'N
maxSizeinMBAllows you to specify the maximum file size allowed for upload in MB. Default is '1 MB'N
maxFilesSpecifies the maximum number of files. Default value is 10.N
previewArrayProvides specifications of images/files to be previewed inside dropzone. The specifications are in the form of IFilePreviewN

These values are available in the IFilePreview interface used in Preview Mode.

interface IFilePreview {
    url: "string",
    key?: "string",
    name?: "string",
    canDelete?: "boolean",
    deleteUrl?: "string",
    fileType: "string",
    queryStringParameters?: "object"
}
ParamDescriptionRequired
urlAPI Endpoint of the file. In case the file is image, preview can be shownY
fileTypeDetermines to preview the icon or display an icon from provided applicationY
keyS3 Key of the objectN
nameName of the DocumentN
canDeleteA flag that determines whether to show the delete icon which call the delete methodN
deleteUrlAPI end point that library should call on invoking the delete methodN
queryStringParametersAn object that is converted into queryStringParams while making an query to backend. Eg: ({ key: "img_key" } ) to ?key=img_keyN

Methods

By using ViewChild() decorator in Parent component, you can call following methods in the library directly.

MethodDescription
upload( )Initiates file upload process
clearAll( )Clears all the selected Files

API Response

On successful upload, the following objects are returned from library. 1. URL of the uploaded file 2. xmlResponse that is returned from the S3 bucket as text 3. response contains details of the uploaded file/files


Note: URL and xmlResponse will be depreciated in the future


interface IPsyS3UploaderResponse {
   url: string | string[],
   xmlResponse: null | string | string[],
   response: IUploadedFileInfo | IUploadedFileInfo[]
};

interface IUploadedFileInfo {
   url: "string",
   xmlResponse: "string",
   name: "string",
   size: number,
   key: "string",
   type: "string"
}
{
    "url": "uploaded url of the object",
    "xmlResponse": "the xml response provided by s3 bucket, converted as a string",
    "response": {
        "url": "<uploaded url of the object>",
        "xmlResponse": "<the xml response provided by s3 bucket, converted as a string>",
        "name": "<name of the file>",
        "size": "<size of the file in bytes>",
        "key": "<object key>",
        "type": "<file Type of the object>"
    }
}

In case of multiple file upload, the responses are converted into array

{
    "url": "array of uploaded url of the objects",
    "xmlResponse": "the array of xml responses provided by s3 bucket, converted as a string",
    "response": [{
        "url": "<uploaded url of the object>",
        "xmlResponse": "<the xml response provided by s3 bucket, converted as a string>",
        "name": "<name of the file>",
        "size": "<size of the file in bytes>",
        "key": "<object key>",
        "type": "<file Type of the object>"
    }]
}

Note: The interface is exported from library and can be used in the parent component.

Events

In preview mode, when selecting or unselecting a file, an event - fileChange is emitted.

interface IOnFileChange {
    "action": eFileChangeStates,
    "index"?: "number",
    "data": {
        "dataUrl": "string",
        "name": "string",
        "type": "string",
        "size": "number"
    }
}

enum eFileChangeStates {
    "fileSelect" = "fileSelect",
    "fileRemove" = "fileRemove"
}

For example:

Single File

{
    "action": "fileSelect",
    "data": {
        "dataURL": "string",
        "name": "string",
        "type": "string",
        "size": "number"
    }
}

Multiple Files will have an additional 'index' property and will send out the its position in the file upload data-array.

{
    "action": "fileRemove",
    "index": 0,
    "data": {
        "dataURL": "string",
        "name": "string",
        "type": "string",
        "size": "number"
    }
}
2.0.1

2 years ago

2.0.0

2 years ago

1.3.4

2 years ago

1.3.3

2 years ago

1.3.2

3 years ago

1.3.1

3 years ago

1.2.2

3 years ago

1.2.0

3 years ago

1.2.1

3 years ago

1.1.1

3 years ago

1.1.0

3 years ago

1.0.4

3 years ago

1.0.3

3 years ago

1.0.2

3 years ago

1.0.1

3 years ago

1.0.0

3 years ago

0.0.1

3 years ago