From fe06d92073f8deb34cb6e141aa29b8ca69291c86 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Fri, 6 Jan 2023 17:15:27 +0400 Subject: [PATCH] Migrate RemoteStorage to TS --- src/storage_manager/config/config.ts | 59 +--------- src/storage_manager/model/IStorage.ts | 8 +- src/storage_manager/model/RemoteStorage.js | 66 ----------- src/storage_manager/model/RemoteStorage.ts | 127 +++++++++++++++++++++ 4 files changed, 134 insertions(+), 126 deletions(-) delete mode 100644 src/storage_manager/model/RemoteStorage.js create mode 100644 src/storage_manager/model/RemoteStorage.ts diff --git a/src/storage_manager/config/config.ts b/src/storage_manager/config/config.ts index a3f636b39..f1d10ca49 100644 --- a/src/storage_manager/config/config.ts +++ b/src/storage_manager/config/config.ts @@ -1,63 +1,6 @@ import Editor from '../../editor'; import { LocalStorageConfig } from '../model/LocalStorage'; - -type AnyObject = Record; - -export interface RemoteStorageConfig { - /** - * Custom headers. - * @default {} - */ - headers?: AnyObject; - - /** - * Endpoint URL where to store data project. - */ - urlStore?: string; - - /** - * Endpoint URL where to load data project. - */ - urlLoad?: string; - - /** - * Use JSON contentType. - * @default true - */ - contentTypeJson?: boolean; - - /** - * Credentials option for the fetch API. - * @default 'include' - */ - credentials?: RequestCredentials; - - /** - * Pass custom options to fetch API (remote storage) - * You can pass a simple object: { someOption: 'someValue' } - * or a function which returns and object to add: - * @example - * fetchOptions: currentOpts => { - * return currentOpts.method === 'POST' ? { method: 'PATCH' } : {}; - * }, - */ - fetchOptions?: string | ((opts: AnyObject) => object); - - /** - * The remote storage sends the project data as a body of the request. - * You can use this method to update the body before the store call in order to align - * with your API requirements. - * @default data => data - */ - onStore?: (data: AnyObject, editor: Editor) => AnyObject; - - /** - * The remote storage loads the project data directly from the request response. - * You can use this method to properly extract the project data from the response. - * @default data => data - */ - onLoad?: (data: AnyObject, editor: Editor) => AnyObject; -} +import { RemoteStorageConfig } from '../model/RemoteStorage'; export interface StorageManagerConfig { /** diff --git a/src/storage_manager/model/IStorage.ts b/src/storage_manager/model/IStorage.ts index 02d37970c..26eb10919 100644 --- a/src/storage_manager/model/IStorage.ts +++ b/src/storage_manager/model/IStorage.ts @@ -1,6 +1,10 @@ -export interface StorageOptions {} +export interface StorageOptions { + [key: string]: any; +} -export interface ProjectData {} +export interface ProjectData { + [key: string]: any; +} export default interface IStorage { load: (options?: T) => Promise; diff --git a/src/storage_manager/model/RemoteStorage.js b/src/storage_manager/model/RemoteStorage.js deleted file mode 100644 index a9fca76b0..000000000 --- a/src/storage_manager/model/RemoteStorage.js +++ /dev/null @@ -1,66 +0,0 @@ -import { isUndefined, isFunction, isString } from 'underscore'; -import fetch from '../../utils/fetch'; - -export default class RemoteStorage { - async store(data, opts = {}) { - await this.request(opts.urlStore, this.__props(opts, data), opts); - } - - async load(opts) { - return await this.request(opts.urlLoad, this.__props(opts), opts); - } - - request(url, props = {}, opts = {}) { - return fetch(url, props) - .then(res => { - const result = res.text(); - const isOk = ((res.status / 200) | 0) === 1; - return isOk ? result : result.then(Promise.reject); - }) - .then(text => { - const parsable = text && isString(text); - return opts.contentTypeJson && parsable ? JSON.parse(text) : text; - }); - } - - __props(opts = {}, data) { - const typeJson = opts.contentTypeJson; - const headers = opts.headers || {}; - const fetchOpts = opts.fetchOptions || {}; - const reqHead = 'X-Requested-With'; - const typeHead = 'Content-Type'; - let body; - - if (isUndefined(headers[reqHead])) { - headers[reqHead] = 'XMLHttpRequest'; - } - - if (isUndefined(headers[typeHead]) && typeJson) { - headers[typeHead] = 'application/json; charset=utf-8'; - } - - if (data) { - if (typeJson) { - body = JSON.stringify(data); - } else { - body = new FormData(); - - for (let key in data) { - body.append(key, data[key]); - } - } - } - - const result = { - method: body ? 'POST' : 'GET', - credentials: opts.credentials, - headers, - body, - }; - - return { - ...result, - ...(isFunction(fetchOpts) ? fetchOpts(result) : fetchOpts), - }; - } -} diff --git a/src/storage_manager/model/RemoteStorage.ts b/src/storage_manager/model/RemoteStorage.ts new file mode 100644 index 000000000..a6df65d91 --- /dev/null +++ b/src/storage_manager/model/RemoteStorage.ts @@ -0,0 +1,127 @@ +import Editor from '../../editor'; +import { isUndefined, isFunction, isString } from 'underscore'; +import fetch from '../../utils/fetch'; +import IStorage, { ProjectData } from './IStorage'; +import { ModelFetchOptions } from 'backbone'; + +type AnyObject = Record; + +export interface RemoteStorageConfig { + /** + * Custom headers. + * @default {} + */ + headers?: AnyObject; + + /** + * Endpoint URL where to store data project. + */ + urlStore?: string; + + /** + * Endpoint URL where to load data project. + */ + urlLoad?: string; + + /** + * Use JSON contentType. + * @default true + */ + contentTypeJson?: boolean; + + /** + * Credentials option for the fetch API. + * @default 'include' + */ + credentials?: RequestCredentials; + + /** + * Pass custom options to fetch API (remote storage) + * You can pass a simple object: { someOption: 'someValue' } + * or a function which returns and object to add: + * @example + * fetchOptions: currentOpts => { + * return currentOpts.method === 'POST' ? { method: 'PATCH' } : {}; + * }, + */ + fetchOptions?: string | ((opts: AnyObject) => object); + + /** + * The remote storage sends the project data as a body of the request. + * You can use this method to update the body before the store call in order to align + * with your API requirements. + * @default data => data + */ + onStore?: (data: AnyObject, editor: Editor) => AnyObject; + + /** + * The remote storage loads the project data directly from the request response. + * You can use this method to properly extract the project data from the response. + * @default data => data + */ + onLoad?: (data: AnyObject, editor: Editor) => AnyObject; +} + +export default class RemoteStorage implements IStorage { + async store(data: ProjectData, opts: RemoteStorageConfig = {}) { + await this.request(opts.urlStore!, this.__props(opts, data), opts); + } + + async load(opts: RemoteStorageConfig = {}) { + return await this.request(opts.urlLoad!, this.__props(opts), opts); + } + + request(url: string, props: RequestInit = {}, opts: RemoteStorageConfig = {}) { + return fetch(url, props) + .then((res: any) => { + const result = res.text(); + const isOk = ((res.status / 200) | 0) === 1; + return isOk ? result : result.then(Promise.reject); + }) + .then(text => { + const parsable = text && isString(text); + return opts.contentTypeJson && parsable ? JSON.parse(text) : text; + }); + } + + __props(opts: RemoteStorageConfig = {}, data?: ProjectData): RequestInit { + const typeJson = opts.contentTypeJson; + const headers = opts.headers || {}; + const fetchOpts = opts.fetchOptions || {}; + const reqHead = 'X-Requested-With'; + const typeHead = 'Content-Type'; + let body; + + if (isUndefined(headers[reqHead])) { + headers[reqHead] = 'XMLHttpRequest'; + } + + if (isUndefined(headers[typeHead]) && typeJson) { + headers[typeHead] = 'application/json; charset=utf-8'; + } + + if (data) { + if (typeJson) { + body = JSON.stringify(data); + } else { + body = new FormData(); + + for (let key in data) { + body.append(key, data[key]); + } + } + } + + const result = { + method: body ? 'POST' : 'GET', + credentials: opts.credentials, + headers, + body, + }; + + return { + ...result, + ...(isFunction(fetchOpts) ? fetchOpts(result) : fetchOpts), + }; + } +}