ui: frontend api (#470) [skip-cache]

This commit is contained in:
undefined authored and GitHub committed 2022-12-12 00:53:44 +08:00
1 parent 6d69e88739
commit 96fa6cc7b9
116 files changed
+599 -629

No files matched your search

-26
View File
@@ -1,26 +0,0 @@
import request from './request';
export default async (q: string, path: string[] = []) => {
let query = q.trim();
if (!query.startsWith('query')) query = `query{${query}}`;
const res = await request.post(`/d/${UiContext.domainId}/api`, { query });
if (res.errors) throw new Error(res.errors[0].message);
let cursor = res;
for (const p of path) {
cursor = cursor[p];
if (!cursor) return undefined;
}
return cursor;
};
export const gql = (
pieces: TemplateStringsArray,
...templates: (string | number | string[] | number[])[]
) => {
let res = '';
for (let i = 0; i < pieces.length; i++) {
res += pieces[i];
if (templates[i]) res += JSON.stringify(templates[i]);
}
return res;
};
@@ -1,12 +0,0 @@
const prefixes = new Set(Object.keys(window.LANGS).filter((i) => i.includes('.')).map((i) => i.split('.')[0]));
export default function getAvailableLangs(langsList?: string[]) {
const Langs = {};
for (const key in window.LANGS) {
if (prefixes.has(key)) continue;
if (langsList && langsList.length && langsList.join('') && !langsList.includes(key)) continue;
else if (window.LANGS[key].hidden && !langsList?.includes(key)) continue;
Langs[key] = window.LANGS[key];
}
return Langs;
}
+153
View File
@@ -0,0 +1,153 @@
import $ from 'jquery';
import _ from 'lodash';
export function substitute(str: string, obj: any) {
return str.replace(/\{([^{}]+)\}/g, (match, key) => {
if (obj[key] !== undefined) return obj[key].toString();
return `{${key}}`;
});
}
export function i18n(str: string, ...params: any[]) {
if (!str) return '';
return substitute((window as any).LOCALES?.[str] || str, params);
}
export function delay(ms) {
return new Promise((resolve) => { setTimeout(resolve, ms); });
}
type Substitution = string | number | { templateRaw: true, html: string };
export function tpl(pieces: TemplateStringsArray, ...substitutions: Substitution[]) {
let result = pieces[0];
for (let i = 0; i < substitutions.length; ++i) {
const subst = substitutions[i];
let substHtml: string;
if (typeof subst === 'object' && subst.templateRaw) {
substHtml = subst.html;
} else substHtml = _.escape(String(subst));
result += substHtml + pieces[i + 1];
}
return result;
}
tpl.typoMsg = function (msg: string, raw = false) {
if (raw) return `<div class="typo"><p>${msg}</p></div>`;
const lines = msg.trim().split('\n');
return `<div class="typo">${lines.map((i) => `<p>${_.escape(i)}</p>`).join('\n')}</div>`;
};
export function rawHtml(html: string) {
return {
templateRaw: true,
html,
};
}
let zIndexCurrent = 1000;
export const zIndexManager = {
getCurrent() {
return zIndexCurrent;
},
getNext() {
return ++zIndexCurrent;
},
};
export const request = {
async ajax(options: Record<string, any>) {
return new Promise<any>((resolve, reject) => {
$
.ajax({
dataType: 'json',
headers: {
Accept: 'application/json',
},
...options,
})
.fail((jqXHR, textStatus, errorThrown: any) => {
if (textStatus === 'abort') {
const err = new Error(i18n('Aborted')) as any;
err.aborted = true;
reject(err);
} else if (jqXHR.readyState === 0) {
reject(new Error(i18n('Network error')));
} else if (typeof jqXHR.responseJSON === 'object' && jqXHR.responseJSON.error) {
const { error } = jqXHR.responseJSON;
if (error.params) {
const message = i18n(error.message, ...error.params);
const err = new Error(message === error.message && error.params.length
? `${error.message}: ${error.params.join(' ')}`
: message) as any;
err.rawMessage = error.message;
err.params = error.params;
reject(err);
} else reject(new Error(jqXHR.responseJSON.error.message));
} else if (errorThrown instanceof Error) {
reject(errorThrown);
} else {
reject(new Error(textStatus));
}
})
.done(resolve);
});
},
postFile(url: string, form: FormData, options: any = {}) {
return this.ajax({
url,
data: form,
processData: false,
contentType: false,
type: 'POST',
dataType: undefined,
...options,
});
},
post(url: string, dataOrForm: JQueryStatic | Node | string | Record<string, any> = {}, options: any = {}) {
let postData;
// @ts-ignore
if (dataOrForm instanceof $ && dataOrForm.is('form')) {
// $form
postData = (dataOrForm as any).serialize();
} else if (dataOrForm instanceof Node && $(dataOrForm).is('form')) {
// form
postData = $(dataOrForm).serialize();
} else if (typeof dataOrForm === 'string') {
// foo=bar&box=boz
postData = dataOrForm;
} else {
// {foo: 'bar'}
postData = JSON.stringify(dataOrForm);
options.contentType = 'application/json';
}
return request.ajax({
url,
method: 'post',
data: postData,
...options,
});
},
get(url: string, qs: Record<string, any> = {}, options: Record<string, any> = {}) {
return request.ajax({
url,
data: qs,
method: 'get',
...options,
});
},
};
Object.assign(window.Hydro.utils, {
i18n,
rawHtml,
substitute,
request,
tpl,
delay,
zIndexManager,
});
-5
View File
@@ -1,5 +0,0 @@
export default function delay(ms) {
return new Promise((resolve) => { setTimeout(resolve, ms); });
}
window.Hydro.utils.delay = delay;
@@ -1,20 +0,0 @@
/**
* @param {Event} ev
* @param {String} targetUrl
* @param {Boolean} alwaysOpenInNewWindow
*/
export default function emulateAnchorClick(ev, targetUrl, alwaysOpenInNewWindow = false) {
let openInNewWindow;
if (alwaysOpenInNewWindow) {
openInNewWindow = true;
} else {
openInNewWindow = (ev.ctrlKey || ev.shiftKey || ev.metaKey);
}
if (openInNewWindow) {
window.open(targetUrl);
} else {
window.location.href = targetUrl;
}
}
window.Hydro.utils.emulateAnchorClick = emulateAnchorClick;
-8
View File
@@ -1,8 +0,0 @@
import substitute from './substitute';
export default function i18n(str, ...params) {
if (!str) return '';
return substitute(window.LOCALES?.[str] || str, params);
}
window.Hydro.utils.i18n = i18n;
+118
View File
@@ -0,0 +1,118 @@
import 'streamsaver/examples/zip-stream';
import { request } from './base';
export async function api(q: string, path: string[] = []) {
let query = q.trim();
if (!query.startsWith('query')) query = `query{${query}}`;
const res = await request.post(`/d/${UiContext.domainId}/api`, { query });
if (res.errors) throw new Error(res.errors[0].message);
let cursor = res;
for (const p of path) {
cursor = cursor[p];
if (!cursor) return undefined;
}
return cursor;
}
export const gql = (
pieces: TemplateStringsArray,
...templates: (string | number | string[] | number[])[]
) => {
let res = '';
for (let i = 0; i < pieces.length; i++) {
res += pieces[i];
if (templates[i]) res += JSON.stringify(templates[i]);
}
return res;
};
export function getAvailableLangs(langsList?: string[]) {
const prefixes = new Set(Object.keys(window.LANGS).filter((i) => i.includes('.')).map((i) => i.split('.')[0]));
const Langs = {};
for (const key in window.LANGS) {
if (prefixes.has(key)) continue;
if (langsList && langsList.length && langsList.join('') && !langsList.includes(key)) continue;
else if (window.LANGS[key].hidden && !langsList?.includes(key)) continue;
Langs[key] = window.LANGS[key];
}
return Langs;
}
export const createZipStream = (window as any).ZIP;
export function createZipBlob(underlyingSource) {
return new Response(createZipStream(underlyingSource)).blob();
}
export async function pipeStream(read, write, abort) {
if (window.WritableStream && read.pipeTo) {
const abortController = new AbortController();
if (abort) abort.abort = abortController.abort.bind(abortController);
await read.pipeTo(write, abortController);
} else {
const writer = write.getWriter();
if (abort) abort.abort = writer.abort.bind(writer);
const reader = read.getReader();
// eslint-disable-next-line no-constant-condition
while (1) {
const readResult = await reader.read();
if (readResult.done) {
writer.close();
break;
} else writer.write(readResult.value);
}
}
}
// https://github.com/andrasq/node-mongoid-js/blob/master/mongoid.js
/* eslint-disable */
export function mongoId(idstring: string) {
if (typeof idstring !== 'string') idstring = String(idstring);
return {
timestamp: parseInt(idstring.slice(0, 0 + 8), 16),
machineid: parseInt(idstring.slice(8, 8 + 6), 16),
pid: parseInt(idstring.slice(14, 14 + 4), 16),
sequence: parseInt(idstring.slice(18, 18 + 6), 16),
};
}
/* eslint-enable */
const loaded = {};
export async function loadExternalModule(target: string) {
if (loaded[target]) return loaded[target];
const ele = document.createElement('script');
ele.src = target;
await new Promise((resolve, reject) => {
ele.onload = resolve;
ele.onerror = reject;
document.head.appendChild(ele);
});
loaded[target] = window.exports;
return loaded[target];
}
export function emulateAnchorClick(ev: KeyboardEvent, targetUrl: string, alwaysOpenInNewWindow = false) {
let openInNewWindow;
if (alwaysOpenInNewWindow) openInNewWindow = true;
else openInNewWindow = (ev.ctrlKey || ev.shiftKey || ev.metaKey);
if (openInNewWindow) window.open(targetUrl);
else window.location.href = targetUrl;
}
export { default as pjax } from './pjax';
export { default as base64 } from './base64';
export { default as loadReactRedux } from './loadReactRedux';
export * as mediaQuery from './mediaQuery';
export * from './slide';
export * from './base';
const zip = { createZipStream, createZipBlob };
Object.assign(window.Hydro.utils, {
zip,
pipeStream,
mongoId,
loadExternalModule,
emulateAnchorClick,
});
-14
View File
@@ -1,14 +0,0 @@
const loaded = {};
export default async function loadExternalModule(target: string) {
if (loaded[target]) return loaded[target];
const ele = document.createElement('script');
ele.src = target;
await new Promise((resolve, reject) => {
ele.onload = resolve;
ele.onerror = reject;
document.head.appendChild(ele);
});
loaded[target] = window.exports;
return loaded[target];
}
+1 -1
View File
@@ -1,4 +1,4 @@
import { Action, AnyAction, Reducer } from 'redux';
import type { Action, AnyAction, Reducer } from 'redux';
export default async function loadReactRedux<S, A extends Action = AnyAction>(storeReducer: Reducer<S, A>) {
const React = await import('react');
-16
View File
@@ -1,16 +0,0 @@
/* eslint-disable */
// https://github.com/andrasq/node-mongoid-js/blob/master/mongoid.js
export function parse(idstring) {
if (typeof idstring !== 'string') {
idstring = String(idstring);
}
return {
timestamp: parseInt(idstring.slice( 0, 0+8), 16),
machineid: parseInt(idstring.slice( 8, 8+6), 16),
pid: parseInt(idstring.slice(14, 14+4), 16),
sequence: parseInt(idstring.slice(18, 18+6), 16),
};
}
window.Hydro.utils.mongoId = parse;
-21
View File
@@ -1,21 +0,0 @@
export default async function pipeStream(read, write, abort) {
if (window.WritableStream && read.pipeTo) {
const abortController = new AbortController();
if (abort) abort.abort = abortController.abort.bind(abortController);
await read.pipeTo(write, abortController);
} else {
const writer = write.getWriter();
if (abort) abort.abort = writer.abort.bind(writer);
const reader = read.getReader();
// eslint-disable-next-line no-constant-condition
while (1) {
const readResult = await reader.read();
if (readResult.done) {
writer.close();
break;
} else writer.write(readResult.value);
}
}
}
window.Hydro.utils.pipeStream = pipeStream;
+1 -1
View File
@@ -5,7 +5,7 @@ import $ from 'jquery';
import { nanoid } from 'nanoid';
import NProgress from 'nprogress';
import Notification from 'vj/components/notification';
import request from 'vj/utils/request';
import { request } from './base';
const pjax = {};
-106
View File
@@ -1,106 +0,0 @@
import $ from 'jquery';
import i18n from './i18n';
const request = {
/**
* @param {object} options
*/
async ajax(options) {
return new Promise((resolve, reject) => {
$
.ajax({
dataType: 'json',
headers: {
Accept: 'application/json',
},
...options,
})
.fail((jqXHR, textStatus, errorThrown) => {
if (textStatus === 'abort') {
const err = new Error(i18n('Aborted'));
err.aborted = true;
reject(err);
} else if (jqXHR.readyState === 0) {
reject(new Error(i18n('Network error')));
} else if (typeof jqXHR.responseJSON === 'object' && jqXHR.responseJSON.error) {
const { error } = jqXHR.responseJSON;
if (error.params) {
const message = i18n(error.message, ...error.params);
const err = new Error(message === error.message && error.params.length ? `${error.message}: ${error.params.join(' ')}` : message);
err.rawMessage = error.message;
err.params = error.params;
reject(err);
} else reject(new Error(jqXHR.responseJSON.error.message));
} else if (errorThrown instanceof Error) {
reject(errorThrown);
} else {
reject(new Error(textStatus));
}
})
.done(resolve);
});
},
/**
* @param {string} url
* @param {FormData} FormData
* @param {object} options
*/
postFile(url, form, options = {}) {
return this.ajax({
url,
data: form,
processData: false,
contentType: false,
type: 'POST',
dataType: undefined,
...options,
});
},
/**
* @param {string} url
* @param {JQueryStatic | Node | string | object} dataOrForm
* @param {object} options
*/
post(url, dataOrForm = {}, options = {}) {
let postData;
if (dataOrForm instanceof jQuery && dataOrForm.is('form')) {
// $form
postData = dataOrForm.serialize();
} else if (dataOrForm instanceof Node && $(dataOrForm).is('form')) {
// form
postData = $(dataOrForm).serialize();
} else if (typeof dataOrForm === 'string') {
// foo=bar&box=boz
postData = dataOrForm;
} else {
// {foo: 'bar'}
postData = JSON.stringify(dataOrForm);
options.contentType = 'application/json';
}
return request.ajax({
url,
method: 'post',
data: postData,
...options,
});
},
/**
* @param {string} url
* @param {object} qs
* @param {object} options
*/
get(url, qs = {}, options = {}) {
return request.ajax({
url,
data: qs,
method: 'get',
...options,
});
},
};
export default request;
window.Hydro.utils.request = request;
File renamed without changes.
-13
View File
@@ -1,13 +0,0 @@
/**
* @param {string} str
* @param {any} obj
* @returns {string}
*/
export default function substitute(str, obj) {
return str.replace(/\{([^{}]+)\}/g, (match, key) => {
if (obj[key] !== undefined) return obj[key].toString();
return `{${key}}`;
});
}
window.Hydro.utils.substitute = substitute;
-31
View File
@@ -1,31 +0,0 @@
import _ from 'lodash';
type Substitution = string | number | { templateRaw: true, html: string };
export default function tpl(pieces: TemplateStringsArray, ...substitutions: Substitution[]) {
let result = pieces[0];
for (let i = 0; i < substitutions.length; ++i) {
const subst = substitutions[i];
let substHtml: string;
if (typeof subst === 'object' && subst.templateRaw) {
substHtml = subst.html;
} else substHtml = _.escape(String(subst));
result += substHtml + pieces[i + 1];
}
return result;
}
tpl.typoMsg = function (msg: string, raw = false) {
if (raw) return `<div class="typo"><p>${msg}</p></div>`;
const lines = msg.trim().split('\n');
return `<div class="typo">${lines.map((i) => `<p>${_.escape(i)}</p>`).join('\n')}</div>`;
};
export function rawHtml(html: string) {
return {
templateRaw: true,
html,
};
}
window.Hydro.utils.tpl = tpl;
@@ -1,13 +0,0 @@
let zIndexCurrent = 1000;
const manager = {
getCurrent() {
return zIndexCurrent;
},
getNext() {
return ++zIndexCurrent;
},
};
export default manager;
window.Hydro.utils.zIndexManager = manager;
-9
View File
@@ -1,9 +0,0 @@
import 'streamsaver/examples/zip-stream';
export const createZipStream = window.ZIP;
export async function createZipBlob(underlyingSource) {
return new Response(createZipStream(underlyingSource)).blob();
}
window.Hydro.utils.zip = { createZipStream, createZipBlob };