mirror of
https://github.com/siyuan-note/siyuan.git
synced 2026-01-30 04:05:16 +01:00
This commit is contained in:
parent
7bd3be0d36
commit
35eff0a3a2
9 changed files with 9 additions and 403 deletions
|
|
@ -2,12 +2,8 @@ import {confirmDialog} from "../dialog/confirmDialog";
|
|||
import {needSubscribe} from "../util/needSubscribe";
|
||||
import {fetchPost} from "../util/fetch";
|
||||
import {isMobile} from "../util/functions";
|
||||
/// #if !MOBILE
|
||||
import {exportLayout} from "../layout/util";
|
||||
/// #endif
|
||||
import {Dialog} from "../dialog";
|
||||
import {showMessage} from "../dialog/message";
|
||||
import {exitSiYuan} from "../dialog/processSystem";
|
||||
|
||||
const getCloudList = (reload = false) => {
|
||||
const listElement = repos.element.querySelector("#reposCloudSyncList");
|
||||
|
|
@ -71,57 +67,6 @@ const renderCloudBackup = () => {
|
|||
</div>
|
||||
</div>`;
|
||||
}
|
||||
let actionHTML = `<div class="fn__flex">
|
||||
<div class="fn__flex-center">${window.siyuan.languages.cloudBackup}</div>
|
||||
<span class="b3-list-item__meta fn__flex-center">${response.data.backup?.updated}</span>
|
||||
<div class="fn__flex-1"></div>
|
||||
<button class="b3-button b3-button--outline fn__flex-center fn__size200" data-type="more">
|
||||
<svg><use xlink:href="#iconMore"></use></svg>${window.siyuan.languages.more}
|
||||
</button>
|
||||
</div>
|
||||
<div class="fn__none">
|
||||
<div class="fn__hr"></div>
|
||||
<div style="margin-left: 16px">
|
||||
<div class="fn__flex${response.data.backup.size === 0 ? " fn__none" : ""}">
|
||||
<span class="fn__flex-center">${window.siyuan.languages.downloadRecover1}</span><span class="fn__space fn__flex-1"></span>
|
||||
<button class="b3-button b3-button--outline fn__flex-center fn__size200 fn__flex-shrink" data-type="cloudDownloadRecover"><svg><use xlink:href="#iconUndo"></use></svg>${window.siyuan.languages.downloadRecover}</button>
|
||||
</div><div class="fn__hr${response.data.backup.size === 0 ? " fn__none" : ""}"></div>
|
||||
<div class="fn__flex">
|
||||
<span class="fn__flex-center">${window.siyuan.languages.backupUpload1}</span><span class="fn__space fn__flex-1"></span>
|
||||
<button class="b3-button b3-button--outline fn__flex-center fn__size200" data-type="localBackupUpload"><svg><use xlink:href="#iconUpload"></use></svg>${window.siyuan.languages.backupUpload}</button>
|
||||
</div><div class="fn__hr"></div>
|
||||
<div class="fn__flex${response.data.backup.size === 0 ? " fn__none" : ""}">
|
||||
<span class="fn__flex-center">${window.siyuan.languages.deleteCloudBackup}</span><span class="fn__space fn__flex-1"></span>
|
||||
<button class="b3-button b3-button--outline fn__flex-center fn__size200" data-type="cloudRemove"><svg><use xlink:href="#iconTrashcan"></use></svg>${window.siyuan.languages.remove}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
if (isMobile()) {
|
||||
actionHTML = `<div class="fn__flex">
|
||||
<div class="fn__flex-center">${window.siyuan.languages.cloudBackup}</div>
|
||||
<span class="b3-list-item__meta fn__flex-center">${response.data.backup?.updated}</span>
|
||||
<div class="fn__flex-1"></div>
|
||||
<button class="b3-button b3-button--outline fn__flex-center" data-type="more">
|
||||
<svg><use xlink:href="#iconMore"></use></svg>${window.siyuan.languages.more}
|
||||
</button>
|
||||
</div>
|
||||
<div class="fn__none">
|
||||
<div class="fn__hr"></div>
|
||||
<div class="${response.data.backup.size === 0 ? " fn__none" : ""}">
|
||||
<button class="b3-button b3-button--outline fn__block" data-type="cloudDownloadRecover"><svg><use xlink:href="#iconUndo"></use></svg>${window.siyuan.languages.downloadRecover}</button>
|
||||
<div class="b3-label__text">${window.siyuan.languages.downloadRecover1}</div>
|
||||
</div>
|
||||
<div class="fn__hr--b${response.data.backup.size === 0 ? " fn__none" : ""}"></div>
|
||||
<button class="b3-button b3-button--outline fn__block" data-type="localBackupUpload"><svg><use xlink:href="#iconUpload"></use></svg>${window.siyuan.languages.backupUpload}</button>
|
||||
<div class="b3-label__text">${window.siyuan.languages.backupUpload1}</div>
|
||||
<div class="fn__hr--b"></div>
|
||||
<div class="${response.data.backup.size === 0 ? " fn__none" : ""}">
|
||||
<button class="b3-button b3-button--outline fn__block" data-type="cloudRemove"><svg><use xlink:href="#iconTrashcan"></use></svg>${window.siyuan.languages.remove}</button>
|
||||
<div class="b3-label__text">${window.siyuan.languages.deleteCloudBackup}</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
repos.element.querySelector("#reposBackup").innerHTML = actionHTML;
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -156,115 +101,6 @@ const addCloudName = () => {
|
|||
});
|
||||
};
|
||||
|
||||
const setE2eePassword = () => {
|
||||
const dialog = new Dialog({
|
||||
title: window.siyuan.languages.changeE2EEPasswd,
|
||||
content: `<div class="b3-dialog__content">
|
||||
<ul class="b3-list b3-list--background">
|
||||
<li class="b3-list-item b3-list-item--hide-action" data-type="default">
|
||||
<input type="radio" name="mode" class="fn__flex-center">
|
||||
<div class="fn__space"></div>
|
||||
<span class="b3-list-item__text">${window.siyuan.languages.defaultPassword}</span>
|
||||
<span class="b3-list-item__action"><svg class="svg fn__flex-center ft__on-surface"><use xlink:href="#iconRight"></use></svg></span>
|
||||
</li>
|
||||
<li class="b3-list-item b3-list-item--hide-action" data-type="custom">
|
||||
<input type="radio" name="mode" class="fn__flex-center">
|
||||
<div class="fn__space"></div>
|
||||
<span class="b3-list-item__text">${window.siyuan.languages.customPassword}</span>
|
||||
<span class="b3-list-item__action"><svg class="svg fn__flex-center ft__on-surface"><use xlink:href="#iconRight"></use></svg></span>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="fn__none ft__error" data-type="default">
|
||||
<button class="b3-button b3-button--outline"><svg><use xlink:href="#iconLeft"></use></svg>${window.siyuan.languages.back}</button>
|
||||
<div class="fn__hr"></div>
|
||||
${window.siyuan.languages.defaultPasswordTip}
|
||||
</div>
|
||||
<div class="fn__none" data-type="custom">
|
||||
<button class="b3-button b3-button--outline"><svg><use xlink:href="#iconLeft"></use></svg>${window.siyuan.languages.back}</button>
|
||||
<div class="fn__hr"></div>
|
||||
<input class="b3-text-field fn__block" placeholder="${window.siyuan.languages.customPassword}">
|
||||
<div class="fn__hr"></div>
|
||||
<div class="b3-label__text ft__error">${window.siyuan.languages.changeE2EEPasswdTip}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="b3-dialog__action">
|
||||
<button class="b3-button b3-button--cancel">${window.siyuan.languages.cancel}</button><div class="fn__space"></div>
|
||||
<button class="b3-button b3-button--text">${window.siyuan.languages.confirm}</button>
|
||||
</div>`,
|
||||
width: isMobile() ? "80vw" : "520px",
|
||||
});
|
||||
dialog.element.querySelector(".b3-dialog__content").addEventListener("click", (event) => {
|
||||
let target = event.target as HTMLElement;
|
||||
while (target && !target.classList.contains("b3-dialog__content")) {
|
||||
if (target.classList.contains("b3-list-item")) {
|
||||
target.parentElement.classList.add("fn__none");
|
||||
if (target.getAttribute("data-type") === "default") {
|
||||
target.parentElement.nextElementSibling.classList.remove("fn__none");
|
||||
} else {
|
||||
target.parentElement.nextElementSibling.nextElementSibling.classList.remove("fn__none");
|
||||
}
|
||||
break;
|
||||
} else if (target.classList.contains("b3-button--outline")) {
|
||||
target.parentElement.classList.add("fn__none");
|
||||
dialog.element.querySelector(".b3-list").classList.remove("fn__none");
|
||||
break;
|
||||
}
|
||||
target = target.parentElement;
|
||||
}
|
||||
});
|
||||
const btnsElement = dialog.element.querySelectorAll(".b3-dialog__action .b3-button");
|
||||
const inputElement = dialog.element.querySelector(".b3-text-field") as HTMLInputElement;
|
||||
inputElement.addEventListener("keydown", (event) => {
|
||||
if (event.isComposing) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
if (event.key === "Enter") {
|
||||
(btnsElement[1] as HTMLButtonElement).click();
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
} else if (event.key === "Escape") {
|
||||
dialog.destroy();
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
btnsElement[0].addEventListener("click", () => {
|
||||
dialog.destroy();
|
||||
});
|
||||
btnsElement[1].addEventListener("click", () => {
|
||||
if (!dialog.element.querySelector(".b3-list").classList.contains("fn__none")) {
|
||||
showMessage(window.siyuan.languages.plsChoose);
|
||||
return;
|
||||
}
|
||||
const mode = dialog.element.querySelector('div[data-type="default"]').classList.contains("fn__none") ? 1 : 0;
|
||||
fetchPost("/api/system/setE2EEPasswd", {
|
||||
e2eePasswd: inputElement.value,
|
||||
mode //0:内置密码; 1:自定义密码
|
||||
}, () => {
|
||||
window.siyuan.config.e2eePasswdMode = mode;
|
||||
dialog.destroy();
|
||||
const updateElement = repos.element.querySelector("#updatePassword").parentElement;
|
||||
updateElement.classList.add("fn__none");
|
||||
if (0 === window.siyuan.config.e2eePasswdMode) {
|
||||
updateElement.nextElementSibling.lastElementChild.innerHTML = window.siyuan.languages.builtinE2EEPasswdTip;
|
||||
} else {
|
||||
updateElement.nextElementSibling.lastElementChild.innerHTML = window.siyuan.languages.changeE2EEPasswdTip;
|
||||
}
|
||||
updateElement.nextElementSibling.classList.remove("fn__none");
|
||||
window.siyuan.config.e2eePasswd = "******";
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const needPassword = () => {
|
||||
if (window.siyuan.config.e2eePasswd === "" && !window.siyuan.config.sync.useDataRepo) {
|
||||
confirmDialog(window.siyuan.languages.config, window.siyuan.languages._kernel[11]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const repos = {
|
||||
element: undefined as Element,
|
||||
genHTML: () => {
|
||||
|
|
@ -292,39 +128,6 @@ export const repos = {
|
|||
<li>${window.siyuan.languages.cloudIntro11}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
let passwordHTML = `<div class="b3-label fn__flex${(window.siyuan.config.e2eePasswd !== "" || window.siyuan.config.sync.useDataRepo) ? " fn__none" : ""}">
|
||||
<div class="fn__flex-1 fn__flex-center">
|
||||
${window.siyuan.languages.e2eePasswd}
|
||||
<div class="b3-label__text ft__error">${window.siyuan.languages.e2eePasswdTip}</div>
|
||||
</div>
|
||||
<div class="fn__space"></div>
|
||||
<button id="updatePassword" class="b3-button b3-button--outline fn__size200 fn__flex-center">
|
||||
<svg><use xlink:href="#iconLock"></use></svg>
|
||||
${window.siyuan.languages.setPasswd}
|
||||
</button>
|
||||
</div>
|
||||
<div class="b3-label${(window.siyuan.config.e2eePasswd === "" || window.siyuan.config.sync.useDataRepo) ? " fn__none" : ""}">
|
||||
${window.siyuan.languages.e2eePasswd}
|
||||
<div class="b3-label__text"><i>${window.siyuan.languages.passwdSet}</i></div>
|
||||
<div class="b3-label__text ft__error">${0 === window.siyuan.config.e2eePasswdMode ? window.siyuan.languages.builtinE2EEPasswdTip : window.siyuan.languages.changeE2EEPasswdTip}</div>
|
||||
</div>`;
|
||||
if (isMobile()) {
|
||||
passwordHTML = `<div class="b3-label${(window.siyuan.config.e2eePasswd !== "" || window.siyuan.config.sync.useDataRepo) ? " fn__none" : ""}">
|
||||
${window.siyuan.languages.e2eePasswd}
|
||||
<div class="fn__hr"></div>
|
||||
<button id="updatePassword" class="b3-button b3-button--outline fn__block">
|
||||
<svg><use xlink:href="#iconLock"></use></svg>
|
||||
${window.siyuan.languages.setPasswd}
|
||||
</button>
|
||||
<div class="b3-label__text ft__error">${window.siyuan.languages.e2eePasswdTip}</div>
|
||||
</div>
|
||||
<div class="b3-label${(window.siyuan.config.e2eePasswd === "" || window.siyuan.config.sync.useDataRepo) ? " fn__none" : ""}">
|
||||
${window.siyuan.languages.e2eePasswd}
|
||||
<div class="fn__hr"></div>
|
||||
<div class="b3-label__text"><i>${window.siyuan.languages.passwdSet}</i></div>
|
||||
<div class="b3-label__text ft__error">${0 === window.siyuan.config.e2eePasswdMode ? window.siyuan.languages.builtinE2EEPasswdTip : window.siyuan.languages.changeE2EEPasswdTip}</div>
|
||||
</div>`;
|
||||
}
|
||||
return `<div><div style="position: fixed;width: 800px;height: 434px;box-sizing: border-box;text-align: center;display: flex;align-items: center;justify-content: center;z-index: 1;" id="reposLoading">
|
||||
|
|
@ -340,7 +143,6 @@ export const repos = {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
${passwordHTML}
|
||||
<label class="fn__flex b3-label">
|
||||
<div class="fn__flex-1">
|
||||
${window.siyuan.languages.openSyncTip1}
|
||||
|
|
@ -360,14 +162,6 @@ ${passwordHTML}
|
|||
<option value="2" ${window.siyuan.config.sync.mode === 2 ? "selected" : ""}>${window.siyuan.languages.syncMode2}</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="fn__flex b3-label">
|
||||
<div class="fn__flex-1">
|
||||
${window.siyuan.languages.syncDataRepo}
|
||||
<div class="b3-label__text">${window.siyuan.languages.syncDataRepoTip}</div>
|
||||
</div>
|
||||
<span class="fn__space"></span>
|
||||
<input type="checkbox" id="useDataRepo"${window.siyuan.config.sync.useDataRepo ? " checked='checked'" : ""} class="b3-switch fn__flex-center">
|
||||
</label>
|
||||
<div class="b3-label">
|
||||
<div class="fn__flex">
|
||||
<div class="fn__flex-center">${window.siyuan.languages.cloudSync}</div>
|
||||
|
|
@ -378,8 +172,7 @@ ${passwordHTML}
|
|||
</div>
|
||||
<div id="reposCloudSyncList" class="fn__none config-repos__sync"><img style="margin: 0 auto;display: block;" src="/stage/loading-pure.svg"></div>
|
||||
</div>
|
||||
<div id="reposBackup" class="b3-label${window.siyuan.config.sync.useDataRepo ? " fn__none" : ""}">${window.siyuan.languages.cloudBackup}</div>
|
||||
<div class="b3-label fn__flex${window.siyuan.config.sync.useDataRepo ? "" : " fn__none"}">
|
||||
<div class="b3-label fn__flex">
|
||||
<div class="fn__flex-center">${window.siyuan.languages.cloudBackup}</div>
|
||||
<div class="b3-list-item__meta fn__flex-center">${window.siyuan.languages.cloudBackupTip}</div>
|
||||
</div>
|
||||
|
|
@ -390,9 +183,6 @@ ${passwordHTML}
|
|||
return;
|
||||
}
|
||||
renderCloudBackup();
|
||||
repos.element.querySelector("#updatePassword").addEventListener("click", () => {
|
||||
setE2eePassword();
|
||||
});
|
||||
const switchElement = repos.element.querySelector("#reposCloudSyncSwitch") as HTMLInputElement;
|
||||
switchElement.addEventListener("change", () => {
|
||||
if (switchElement.checked && window.siyuan.config.sync.cloudName === "") {
|
||||
|
|
@ -420,36 +210,6 @@ ${passwordHTML}
|
|||
}
|
||||
});
|
||||
});
|
||||
const useDataRepoElement = repos.element.querySelector("#useDataRepo") as HTMLInputElement;
|
||||
useDataRepoElement.addEventListener("change", () => {
|
||||
fetchPost("/api/sync/setSyncUseDataRepo", {enabled: useDataRepoElement.checked}, (response) => {
|
||||
if (response.code === 1) {
|
||||
showMessage(response.msg);
|
||||
useDataRepoElement.checked = false;
|
||||
} else {
|
||||
window.siyuan.config.sync.useDataRepo = useDataRepoElement.checked;
|
||||
const reposBackupElement = repos.element.querySelector("#reposBackup") as HTMLElement;
|
||||
const reposPasswordElement = repos.element.querySelector("#updatePassword").parentElement as HTMLElement;
|
||||
if (useDataRepoElement.checked) {
|
||||
reposBackupElement.classList.add("fn__none");
|
||||
reposBackupElement.nextElementSibling.classList.remove("fn__none");
|
||||
if (window.siyuan.config.e2eePasswd === "") {
|
||||
reposPasswordElement.classList.add("fn__none");
|
||||
} else {
|
||||
reposPasswordElement.nextElementSibling.classList.add("fn__none");
|
||||
}
|
||||
} else {
|
||||
reposBackupElement.classList.remove("fn__none");
|
||||
reposBackupElement.nextElementSibling.classList.add("fn__none");
|
||||
if (window.siyuan.config.e2eePasswd === "") {
|
||||
reposPasswordElement.classList.remove("fn__none");
|
||||
} else {
|
||||
reposPasswordElement.nextElementSibling.classList.remove("fn__none");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
const loadingElement = repos.element.querySelector("#reposLoading") as HTMLElement;
|
||||
loadingElement.style.width = repos.element.clientWidth + "px";
|
||||
loadingElement.style.height = repos.element.clientHeight + "px";
|
||||
|
|
@ -460,57 +220,12 @@ ${passwordHTML}
|
|||
const type = target.getAttribute("data-type");
|
||||
if (type) {
|
||||
switch (type) {
|
||||
case "more":
|
||||
repos.element.querySelector("#reposBackup").lastElementChild.classList.toggle("fn__none");
|
||||
break;
|
||||
case "config":
|
||||
if (!needPassword()) {
|
||||
if (syncConfigElement.classList.contains("fn__none")) {
|
||||
getCloudList();
|
||||
syncConfigElement.classList.remove("fn__none");
|
||||
} else {
|
||||
syncConfigElement.classList.add("fn__none");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "cloudDownloadRecover":
|
||||
if (!needPassword()) {
|
||||
confirmDialog(window.siyuan.languages.downloadCloud, window.siyuan.languages.downloadCloudTip, () => {
|
||||
fetchPost("/api/backup/downloadCloudBackup", {}, () => {
|
||||
fetchPost("/api/backup/recoverLocalBackup", {}, () => {
|
||||
setTimeout(() => {
|
||||
/// #if !MOBILE
|
||||
exportLayout(false, () => {
|
||||
exitSiYuan();
|
||||
});
|
||||
/// #else
|
||||
window.location.reload();
|
||||
/// #endif
|
||||
}, 7000);
|
||||
return;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "cloudRemove":
|
||||
if (!needPassword()) {
|
||||
confirmDialog(window.siyuan.languages.confirm, window.siyuan.languages.confirmDelete + "?", () => {
|
||||
fetchPost("/api/backup/removeCloudBackup", {}, () => {
|
||||
renderCloudBackup();
|
||||
});
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "localBackupUpload":
|
||||
if (!needPassword()) {
|
||||
confirmDialog(window.siyuan.languages.backupUpload, window.siyuan.languages.account3Tip, () => {
|
||||
fetchPost("/api/backup/createLocalBackup", {}, () => {
|
||||
fetchPost("/api/backup/uploadLocalBackup", {}, () => {
|
||||
renderCloudBackup();
|
||||
});
|
||||
});
|
||||
});
|
||||
if (syncConfigElement.classList.contains("fn__none")) {
|
||||
getCloudList();
|
||||
syncConfigElement.classList.remove("fn__none");
|
||||
} else {
|
||||
syncConfigElement.classList.add("fn__none");
|
||||
}
|
||||
break;
|
||||
case "addCloud":
|
||||
|
|
|
|||
|
|
@ -53,9 +53,8 @@ export const initConfigSearch = (element: HTMLElement) => {
|
|||
.concat(Object.keys(Constants.SIYUAN_KEYMAP.editor.table))),
|
||||
|
||||
// 云端
|
||||
getLang(["sync", "cloudSpace", "backup", "cdn", "total", "cloudBackup", "downloadRecover", "backupUpload",
|
||||
"downloadCloud", "downloadCloudTip", "account3Tip", "updatePath", "cloudSync",
|
||||
"changeE2EEPasswd", "e2eePasswdTip", "changeE2EEPasswdTip", "e2eePasswd", "setPasswd", "syncTip", "reposTip", "openSyncTip1", "openSyncTip2", "downloadRecover1", "backupUpload1", "deleteCloudBackup", "cloudSyncDir"]),
|
||||
getLang(["sync", "cloudSpace", "backup", "cdn", "total", "cloudBackup", "updatePath", "cloudSync",
|
||||
"syncTip", "reposTip", "openSyncTip1", "openSyncTip2", "cloudSyncDir"]),
|
||||
|
||||
// 账号
|
||||
getLang(["accountTip", "accountName", "password", "captcha", "forgetPassword", "login", "register", "twoFactorCaptcha",
|
||||
|
|
|
|||
|
|
@ -410,7 +410,7 @@ export const resizeTabs = () => {
|
|||
if (item.editor && item.editor.protyle && item.element.parentElement) {
|
||||
hideElements(["gutter"], item.editor.protyle);
|
||||
setTimeout(() => {
|
||||
// .layout .fn__flex-shrink {transition: width .3s ease;} 时需要再次计算 padding
|
||||
// .layout .fn__flex-shrink {width .15s cubic-bezier(0, 0, .2, 1) 0ms} 时需要再次计算 padding
|
||||
setPadding(item.editor.protyle);
|
||||
if (typeof echarts !== "undefined") {
|
||||
item.editor.protyle.wysiwyg.element.querySelectorAll('[data-subtype="echarts"], [data-subtype="mindmap"]').forEach((chartItem: HTMLElement) => {
|
||||
|
|
|
|||
3
app/src/types/index.d.ts
vendored
3
app/src/types/index.d.ts
vendored
|
|
@ -261,8 +261,6 @@ declare interface IConfig {
|
|||
repo: {
|
||||
key: string
|
||||
},
|
||||
e2eePasswd: string
|
||||
e2eePasswdMode: number
|
||||
sync: {
|
||||
enabled: boolean
|
||||
mode: number
|
||||
|
|
@ -270,7 +268,6 @@ declare interface IConfig {
|
|||
stat: string
|
||||
interval: number
|
||||
cloudName: string
|
||||
useDataRepo: boolean
|
||||
},
|
||||
lang: string
|
||||
api: {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue