15088: Adds invalid states and UI and improves action error handling
[arvados.git] / src / common / webdav.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 export class WebDAV {
6
7     defaults: WebDAVDefaults = {
8         baseURL: '',
9         headers: {},
10     };
11
12     constructor(config?: Partial<WebDAVDefaults>, private createRequest = () => new XMLHttpRequest()) {
13         if (config) {
14             this.defaults = { ...this.defaults, ...config };
15         }
16     }
17
18     propfind = (url: string, config: WebDAVRequestConfig = {}) =>
19         this.request({
20             ...config, url,
21             method: 'PROPFIND'
22         })
23
24     put = (url: string, data?: any, config: WebDAVRequestConfig = {}) =>
25         this.request({
26             ...config, url,
27             method: 'PUT',
28             data
29         })
30
31     upload = (url: string, files: File[], config: WebDAVRequestConfig = {}) => {
32         return Promise.all(
33             files.map(file => this.request({
34                 ...config, url,
35                 method: 'PUT',
36                 data: file
37             }))
38         );
39     }
40
41     copy = (url: string, destination: string, config: WebDAVRequestConfig = {}) =>
42         this.request({
43             ...config, url,
44             method: 'COPY',
45             headers: { ...config.headers, Destination: this.defaults.baseURL + destination }
46         })
47
48     move = (url: string, destination: string, config: WebDAVRequestConfig = {}) =>
49         this.request({
50             ...config, url,
51             method: 'MOVE',
52             headers: { ...config.headers, Destination: this.defaults.baseURL + destination }
53         })
54
55     delete = (url: string, config: WebDAVRequestConfig = {}) =>
56         this.request({
57             ...config, url,
58             method: 'DELETE'
59         })
60
61     private request = (config: RequestConfig) => {
62         return new Promise<XMLHttpRequest>((resolve, reject) => {
63             const r = this.createRequest();
64             r.open(config.method, this.defaults.baseURL + config.url);
65             const headers = { ...this.defaults.headers, ...config.headers };
66             Object
67                 .keys(headers)
68                 .forEach(key => r.setRequestHeader(key, headers[key]));
69
70             if (config.onUploadProgress) {
71                 r.upload.addEventListener('progress', config.onUploadProgress);
72             }
73
74             r.addEventListener('load', () => {
75                 if (r.status === 404) {
76                     return reject(r);
77                 } else {
78                     return resolve(r);
79                 }
80             });
81
82             r.addEventListener('error', () => {
83                 return reject(r);
84             });
85
86             r.upload.addEventListener('error', () => {
87                 return reject(r);
88             });
89
90             r.send(config.data);
91         });
92     }
93 }
94
95 export interface WebDAVRequestConfig {
96     headers?: {
97         [key: string]: string;
98     };
99     onUploadProgress?: (event: ProgressEvent) => void;
100 }
101
102 interface WebDAVDefaults {
103     baseURL: string;
104     headers: { [key: string]: string };
105 }
106
107 interface RequestConfig {
108     method: string;
109     url: string;
110     headers?: { [key: string]: string };
111     data?: any;
112     onUploadProgress?: (event: ProgressEvent) => void;
113 }