@tachybase/module-backup 0.23.58 → 1.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- (function(p,r){typeof exports=="object"&&typeof module!="undefined"?r(exports,require("@tachybase/client"),require("react/jsx-runtime"),require("react"),require("@tachybase/components"),require("@ant-design/icons"),require("antd"),require("react-i18next")):typeof define=="function"&&define.amd?define(["exports","@tachybase/client","react/jsx-runtime","react","@tachybase/components","@ant-design/icons","antd","react-i18next"],r):(p=typeof globalThis!="undefined"?globalThis:p||self,r(p["@tachybase/module-backup"]={},p["@tachybase/client"],p.jsxRuntime,p.react,p["@tachybase/components"],p["@ant-design/icons"],p.antd,p["react-i18next"]))})(this,function(p,r,e,y,L,x,l,P){"use strict";var Z=Object.defineProperty,R=Object.defineProperties;var ee=Object.getOwnPropertyDescriptors;var $=Object.getOwnPropertySymbols;var te=Object.prototype.hasOwnProperty,oe=Object.prototype.propertyIsEnumerable;var W=(p,r,e)=>r in p?Z(p,r,{enumerable:!0,configurable:!0,writable:!0,value:e}):p[r]=e,q=(p,r)=>{for(var e in r||(r={}))te.call(r,e)&&W(p,e,r[e]);if($)for(var e of $(r))oe.call(r,e)&&W(p,e,r[e]);return p},E=(p,r)=>R(p,ee(r));var T=(p,r,e)=>new Promise((y,L)=>{var x=m=>{try{P(e.next(m))}catch(A){L(A)}},l=m=>{try{P(e.throw(m))}catch(A){L(A)}},P=m=>m.done?y(m.value):Promise.resolve(m.value).then(x,l);P((e=e.apply(p,r)).next())});var m=typeof globalThis!="undefined"?globalThis:typeof window!="undefined"?window:typeof global!="undefined"?global:typeof self!="undefined"?self:{},A={exports:{}};(function(a,g){(function(i,c){c()})(m,function(){function i(t,s){return typeof s=="undefined"?s={autoBom:!1}:typeof s!="object"&&(console.warn("Deprecated: Expected third argument to be a object"),s={autoBom:!s}),s.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(t.type)?new Blob(["\uFEFF",t],{type:t.type}):t}function c(t,s,k){var n=new XMLHttpRequest;n.open("GET",t),n.responseType="blob",n.onload=function(){v(n.response,s,k)},n.onerror=function(){console.error("could not download file")},n.send()}function u(t){var s=new XMLHttpRequest;s.open("HEAD",t,!1);try{s.send()}catch(k){}return 200<=s.status&&299>=s.status}function h(t){try{t.dispatchEvent(new MouseEvent("click"))}catch(k){var s=document.createEvent("MouseEvents");s.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),t.dispatchEvent(s)}}var f=typeof window=="object"&&window.window===window?window:typeof self=="object"&&self.self===self?self:typeof m=="object"&&m.global===m?m:void 0,w=f.navigator&&/Macintosh/.test(navigator.userAgent)&&/AppleWebKit/.test(navigator.userAgent)&&!/Safari/.test(navigator.userAgent),v=f.saveAs||(typeof window!="object"||window!==f?function(){}:"download"in HTMLAnchorElement.prototype&&!w?function(t,s,k){var n=f.URL||f.webkitURL,d=document.createElement("a");s=s||t.name||"download",d.download=s,d.rel="noopener",typeof t=="string"?(d.href=t,d.origin===location.origin?h(d):u(d.href)?c(t,s,k):h(d,d.target="_blank")):(d.href=n.createObjectURL(t),setTimeout(function(){n.revokeObjectURL(d.href)},4e4),setTimeout(function(){h(d)},0))}:"msSaveOrOpenBlob"in navigator?function(t,s,k){if(s=s||t.name||"download",typeof t!="string")navigator.msSaveOrOpenBlob(i(t,k),s);else if(u(t))c(t,s,k);else{var n=document.createElement("a");n.href=t,n.target="_blank",setTimeout(function(){h(n)})}}:function(t,s,k,n){if(n=n||open("","_blank"),n&&(n.document.title=n.document.body.innerText="downloading..."),typeof t=="string")return c(t,s,k);var d=t.type==="application/octet-stream",C=/constructor/i.test(f.HTMLElement)||f.safari,o=/CriOS\/[\d]+/.test(navigator.userAgent);if((o||d&&C||w)&&typeof FileReader!="undefined"){var b=new FileReader;b.onloadend=function(){var S=b.result;S=o?S:S.replace(/^data:[^;]*;/,"data:attachment/file;"),n?n.location.href=S:location=S,n=null},b.readAsDataURL(t)}else{var B=f.URL||f.webkitURL,O=B.createObjectURL(t);n?n.location=O:location.href=O,n=null,setTimeout(function(){B.revokeObjectURL(O)},4e4)}});f.saveAs=v.saveAs=v,a.exports=v})})(A);var K=A.exports;const I="backup";function F(){return P.useTranslation(I,{nsMode:"fallback"})}const{Dragger:X}=l.Upload;function J(a){const g=c=>{var u;(u=a.onChange)==null||u.call(a,c)},i=r.useAPIClient();return E(q({},a),{customRequest({action:c,data:u,file:h,filename:f,headers:w,onError:v,onProgress:t,onSuccess:s,withCredentials:k}){const n=new FormData;return u&&Object.keys(u).forEach(d=>{n.append(d,u[d])}),n.append(f,h),i.axios.post(c,n,{withCredentials:k,headers:w,onUploadProgress:({total:d,loaded:C})=>{t({percent:Math.round(C/d*100).toFixed(2)},h)}}).then(({data:d})=>{s(d,h)}).catch(v).finally(()=>{}),{abort(){console.log("upload progress is aborted.")}}},onChange:g})}const U=a=>{const{collectionsData:g}=a,{t:i}=F(),[c,u]=y.useState(!1),[h,f]=y.useState(g);y.useEffect(()=>{f(g)},[g]);const w=r.useAPIClient(),v=r.useCompile(),t=y.useMemo(()=>w.resource("backupFiles"),[w]),s=()=>T(this,null,function*(){if(a.isBackup){const o=yield t.dumpableCollections();f(o==null?void 0:o.data),u(!0)}u(!0)}),k=()=>{u(!1)},n=()=>{u(!1)},d=[{title:i("Collection"),dataIndex:"collection",key:"collection",render:(o,b)=>{const B=v(b.title);return b.name===B?B:e.jsxs("div",{children:[b.name," ",e.jsxs("span",{style:{color:"rgba(0, 0, 0, 0.3)",fontSize:"0.9em"},children:["(",v(b.title),")"]})]})}},{title:i("Origin"),dataIndex:"origin",key:"origin",width:"50%"}],C=Object.keys(h||{}).map(o=>({key:o,label:i(`${o}.title`),children:e.jsxs(e.Fragment,{children:[e.jsx(l.Alert,{style:{marginBottom:16},message:i(`${o}.description`)}),e.jsx(l.Table,{pagination:{pageSize:100},bordered:!0,size:"small",dataSource:h[o],columns:d,scroll:{y:400}})]})}));return e.jsxs(e.Fragment,{children:[e.jsx("a",{onClick:s,children:i("Learn more")}),e.jsx(l.Modal,{title:i("Backup instructions"),width:"80vw",open:c,footer:null,onOk:k,onCancel:n,children:e.jsx(l.Tabs,{defaultActiveKey:"required",items:C})})]})},G=({ButtonComponent:a=l.Button,title:g,upload:i=!1,fileData:c})=>{const{t:u}=F(),[h,f]=y.useState(["required"]),[w,v]=y.useState(!1),[t,s]=y.useState(null),[k,n]=y.useState(!1),d=r.useAPIClient(),C=y.useMemo(()=>d.resource("backupFiles"),[d]),[o,b]=y.useState([]);y.useEffect(()=>{b(Object.keys((t==null?void 0:t.dumpableCollectionsGroupByGroup)||[]).map(M=>({value:M,label:u(`${M}.title`),disabled:["required","skipped"].includes(M)})))},[t]);const B=()=>T(this,null,function*(){var M,z,H;if(v(!0),!i){n(!0);const{data:D}=yield C.get({filterByTk:c.name});b(Object.keys(((z=(M=D==null?void 0:D.data)==null?void 0:M.meta)==null?void 0:z.dumpableCollectionsGroupByGroup)||[]).map(j=>({value:j,label:u(`${j}.title`),disabled:["required","skipped"].includes(j)}))),s((H=D==null?void 0:D.data)==null?void 0:H.meta),n(!1)}}),O=()=>{C.restore({values:{dataTypes:h,filterByTk:c==null?void 0:c.name,key:t==null?void 0:t.key}}),v(!1)},S=()=>{v(!1),s(null),f(["required"])};return e.jsxs(e.Fragment,{children:[e.jsx(a,{onClick:B,children:g}),e.jsx(l.Modal,{title:u("Restore"),width:800,footer:i&&!t?null:void 0,open:w,onOk:O,onCancel:S,children:e.jsxs(l.Spin,{spinning:k,children:[i&&!t&&e.jsx(V,{setRestoreData:s}),(!i||t)&&[e.jsxs("strong",{style:{fontWeight:600,display:"block",margin:"16px 0 8px"},children:[u("Select the data to be restored")," (",e.jsx(U,{collectionsData:t==null?void 0:t.dumpableCollectionsGroupByGroup}),"):"]},"info"),e.jsx("div",{style:{lineHeight:2,marginBottom:8},children:e.jsx(L.FormItem,{children:e.jsx(r.Checkbox.Group,{options:o,style:{flexDirection:"column"},value:h,onChange:M=>f(M)})})},"dataType")]]})})]})},Q=({ButtonComponent:a=l.Button,refresh:g})=>{const{t:i}=F(),[c,u]=y.useState(!1),[h,f]=y.useState(["required"]),w=r.useAPIClient(),{notification:v}=l.App.useApp(),[t,s]=y.useState([]),k=()=>T(this,null,function*(){const{data:C}=yield w.resource("backupFiles").dumpableCollections();s(Object.keys(C||[]).map(o=>({value:o,label:i(`${o}.title`),disabled:["required","skipped"].includes(o)}))),u(!0)}),n=C=>{w.request({url:"backupFiles:create",method:"post",data:{dataTypes:h,method:C}}).finally(()=>{v.destroy("backup")}),v.info({key:"backup",message:e.jsxs("span",{children:[i("Processing..."),"    ",e.jsx(l.Spin,{indicator:e.jsx(x.LoadingOutlined,{style:{fontSize:24},spin:!0})})]}),duration:0}),u(!1),f(["required"]),setTimeout(()=>{g()},500)},d=()=>{u(!1),f(["required"])};return e.jsxs(e.Fragment,{children:[e.jsx(a,{icon:e.jsx(x.PlusOutlined,{}),type:"primary",onClick:k,children:i("New backup")}),e.jsxs(l.Modal,{title:i("New backup"),width:800,open:c,onCancel:d,footer:[e.jsxs(l.Row,{gutter:16,justify:"end",align:"middle",children:[e.jsx(l.Col,{children:e.jsx(l.Button,{onClick:d,children:i("Cancel")},"cancel")}),e.jsx(l.Col,{children:e.jsx(l.Dropdown.Button,{type:"primary",onClick:()=>n("priority"),overlay:e.jsxs(l.Menu,{children:[e.jsx(l.Menu.Item,{onClick:()=>n("main"),children:i("Self backup")},"main"),e.jsx(l.Menu.Item,{onClick:()=>n("worker"),children:i("Worker backup")},"worker")]}),children:i("Backup")},"submit")})]})],children:[e.jsxs("strong",{style:{fontWeight:600,display:"block",margin:"16px 0 8px"},children:[i("Select the data to be backed up")," (",e.jsx(U,{isBackup:!0}),"):"]}),e.jsx("div",{style:{lineHeight:2,marginBottom:8},children:e.jsx(r.Checkbox.Group,{options:t,style:{flexDirection:"column"},onChange:C=>f(C),value:h})})]})]})},V=a=>{const{t:g}=F(),i={multiple:!1,action:"/backupFiles:upload",onChange(c){var h,f,w;c.fileList.length>1&&c.fileList.splice(0,c.fileList.length-1);const{status:u}=c.file;u==="done"?(l.message.success(`${c.file.name} `+g("file uploaded successfully")),a.setRestoreData(E(q({},(f=(h=c.file.response)==null?void 0:h.data)==null?void 0:f.meta),{key:(w=c.file.response)==null?void 0:w.data.key}))):u==="error"&&l.message.error(`${c.file.name} `+g("file upload failed"))},onDrop(c){console.log("Dropped files",c.dataTransfer.files)}};return e.jsxs(X,E(q({},J(i)),{children:[e.jsx("p",{className:"ant-upload-drag-icon",children:e.jsx(x.InboxOutlined,{})}),e.jsxs("p",{className:"ant-upload-text",children:[" ",g("Click or drag file to this area to upload")]})]}))},Y=()=>{const{t:a}=F(),g=r.useAPIClient(),[i,c]=y.useState([]),[u,h]=y.useState(!1),[f,w]=y.useState(!1),{modal:v,notification:t}=l.App.useApp(),s=y.useMemo(()=>g.resource("backupFiles"),[g]),k=y.useCallback(()=>T(this,null,function*(){yield n()}),[]);r.useNoticeSub("backup",o=>{(t[o.level]||t.info)({key:"backup",message:o.msg}),k()}),y.useEffect(()=>{n()},[]);const n=()=>T(this,null,function*(){h(!0);const{data:o}=yield s.list();c(o.data),h(!1)}),d=o=>T(this,null,function*(){w(o.name);const b=yield g.request({url:"backupFiles:download",method:"get",params:{filterByTk:o.name},responseType:"blob",onDownloadProgress:O=>{const S=Math.round(O.loaded*100/O.total);S>=100?t.success({key:"downloadBackup",message:e.jsx("span",{children:a("Downloaded success!")}),duration:1}):t.info({key:"downloadBackup",message:e.jsxs("span",{children:[a("Downloading ")+S+"%","    ",e.jsx(l.Spin,{indicator:e.jsx(x.LoadingOutlined,{style:{fontSize:24},spin:!0})})]}),duration:0})}});w(!1);const B=new Blob([b.data]);K.saveAs(B,o.name)}),C=o=>{v.confirm({title:a("Delete record",{ns:"core"}),content:a("Are you sure you want to delete it?",{ns:"core"}),onOk:()=>T(this,null,function*(){yield s.destroy({filterByTk:o.name}),yield n(),l.message.success(a("Deleted successfully"))})})};return e.jsx("div",{children:e.jsxs(l.Card,{bordered:!1,children:[e.jsxs(l.Space,{style:{float:"right",marginBottom:16},children:[e.jsx(l.Button,{onClick:k,icon:e.jsx(x.ReloadOutlined,{}),children:a("Refresh")}),e.jsx(G,{upload:!0,title:e.jsxs(e.Fragment,{children:[e.jsx(x.UploadOutlined,{})," ",a("Restore backup from local")]})}),e.jsx(Q,{refresh:k})]}),e.jsx(l.Table,{dataSource:i,loading:u,columns:[{title:a("Backup file"),dataIndex:"name",width:400,onCell:o=>o.inProgress?{colSpan:4}:{},render:(o,b)=>b.inProgress?e.jsxs("div",{style:{color:"rgba(0, 0, 0, 0.88)"},children:[o,"(",a("Backing up"),"...)"]}):e.jsx("div",{children:o})},{title:a("File size"),dataIndex:"fileSize",onCell:o=>o.inProgress?{colSpan:0}:{}},{title:a("Created at",{ns:"core"}),dataIndex:"createdAt",onCell:o=>o.inProgress?{colSpan:0}:{},render:o=>e.jsx(r.DatePicker.ReadPretty,{value:o,showTime:!0})},{title:a("Actions",{ns:"core"}),dataIndex:"actions",onCell:o=>o.inProgress?{colSpan:0}:{},render:(o,b)=>e.jsxs(l.Space,{split:e.jsx(l.Divider,{type:"vertical"}),children:[e.jsx(G,{ButtonComponent:"a",title:a("Restore"),fileData:b}),e.jsx("a",{type:"link",onClick:()=>d(b),children:a("Download")}),e.jsx("a",{onClick:()=>C(b),children:a("Delete")})]})}]})]})})},_=function(a){return e.jsx(r.SchemaComponentOptions,{children:a.children})};_.displayName="DuplicatorProvider";class N extends r.Plugin{load(){return T(this,null,function*(){this.app.use(_),this.app.systemSettingsManager.add("system-services."+I,{title:this.t("Backup & Restore"),icon:"CloudServerOutlined",Component:Y,aclSnippet:"pm.backup.restore"})})}}p.PluginBackupRestoreClient=N,p.default=N,Object.defineProperties(p,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
1
+ (function(p,r){typeof exports=="object"&&typeof module!="undefined"?r(exports,require("@tachybase/client"),require("react/jsx-runtime"),require("react"),require("@tachybase/components"),require("@ant-design/icons"),require("antd"),require("react-i18next")):typeof define=="function"&&define.amd?define(["exports","@tachybase/client","react/jsx-runtime","react","@tachybase/components","@ant-design/icons","antd","react-i18next"],r):(p=typeof globalThis!="undefined"?globalThis:p||self,r(p["@tachybase/module-backup"]={},p["@tachybase/client"],p.jsxRuntime,p.react,p["@tachybase/components"],p["@ant-design/icons"],p.antd,p["react-i18next"]))})(this,function(p,r,e,k,L,x,l,P){"use strict";var Z=Object.defineProperty,R=Object.defineProperties;var ee=Object.getOwnPropertyDescriptors;var $=Object.getOwnPropertySymbols;var te=Object.prototype.hasOwnProperty,oe=Object.prototype.propertyIsEnumerable;var W=(p,r,e)=>r in p?Z(p,r,{enumerable:!0,configurable:!0,writable:!0,value:e}):p[r]=e,E=(p,r)=>{for(var e in r||(r={}))te.call(r,e)&&W(p,e,r[e]);if($)for(var e of $(r))oe.call(r,e)&&W(p,e,r[e]);return p},q=(p,r)=>R(p,ee(r));var T=(p,r,e)=>new Promise((k,L)=>{var x=m=>{try{P(e.next(m))}catch(A){L(A)}},l=m=>{try{P(e.throw(m))}catch(A){L(A)}},P=m=>m.done?k(m.value):Promise.resolve(m.value).then(x,l);P((e=e.apply(p,r)).next())});var m=typeof globalThis!="undefined"?globalThis:typeof window!="undefined"?window:typeof global!="undefined"?global:typeof self!="undefined"?self:{},A={exports:{}};(function(a,b){(function(i,c){c()})(m,function(){function i(t,s){return typeof s=="undefined"?s={autoBom:!1}:typeof s!="object"&&(console.warn("Deprecated: Expected third argument to be a object"),s={autoBom:!s}),s.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(t.type)?new Blob(["\uFEFF",t],{type:t.type}):t}function c(t,s,g){var n=new XMLHttpRequest;n.open("GET",t),n.responseType="blob",n.onload=function(){v(n.response,s,g)},n.onerror=function(){console.error("could not download file")},n.send()}function u(t){var s=new XMLHttpRequest;s.open("HEAD",t,!1);try{s.send()}catch(g){}return 200<=s.status&&299>=s.status}function h(t){try{t.dispatchEvent(new MouseEvent("click"))}catch(g){var s=document.createEvent("MouseEvents");s.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),t.dispatchEvent(s)}}var f=typeof window=="object"&&window.window===window?window:typeof self=="object"&&self.self===self?self:typeof m=="object"&&m.global===m?m:void 0,w=f.navigator&&/Macintosh/.test(navigator.userAgent)&&/AppleWebKit/.test(navigator.userAgent)&&!/Safari/.test(navigator.userAgent),v=f.saveAs||(typeof window!="object"||window!==f?function(){}:"download"in HTMLAnchorElement.prototype&&!w?function(t,s,g){var n=f.URL||f.webkitURL,d=document.createElement("a");s=s||t.name||"download",d.download=s,d.rel="noopener",typeof t=="string"?(d.href=t,d.origin===location.origin?h(d):u(d.href)?c(t,s,g):h(d,d.target="_blank")):(d.href=n.createObjectURL(t),setTimeout(function(){n.revokeObjectURL(d.href)},4e4),setTimeout(function(){h(d)},0))}:"msSaveOrOpenBlob"in navigator?function(t,s,g){if(s=s||t.name||"download",typeof t!="string")navigator.msSaveOrOpenBlob(i(t,g),s);else if(u(t))c(t,s,g);else{var n=document.createElement("a");n.href=t,n.target="_blank",setTimeout(function(){h(n)})}}:function(t,s,g,n){if(n=n||open("","_blank"),n&&(n.document.title=n.document.body.innerText="downloading..."),typeof t=="string")return c(t,s,g);var d=t.type==="application/octet-stream",C=/constructor/i.test(f.HTMLElement)||f.safari,o=/CriOS\/[\d]+/.test(navigator.userAgent);if((o||d&&C||w)&&typeof FileReader!="undefined"){var y=new FileReader;y.onloadend=function(){var S=y.result;S=o?S:S.replace(/^data:[^;]*;/,"data:attachment/file;"),n?n.location.href=S:location=S,n=null},y.readAsDataURL(t)}else{var B=f.URL||f.webkitURL,O=B.createObjectURL(t);n?n.location=O:location.href=O,n=null,setTimeout(function(){B.revokeObjectURL(O)},4e4)}});f.saveAs=v.saveAs=v,a.exports=v})})(A);var K=A.exports;const I="backup";function F(){return P.useTranslation(I,{nsMode:"fallback"})}const{Dragger:X}=l.Upload;function J(a){const b=c=>{var u;(u=a.onChange)==null||u.call(a,c)},i=r.useAPIClient();return q(E({},a),{customRequest({action:c,data:u,file:h,filename:f,headers:w,onError:v,onProgress:t,onSuccess:s,withCredentials:g}){const n=new FormData;return u&&Object.keys(u).forEach(d=>{n.append(d,u[d])}),n.append(f,h),i.axios.post(c,n,{withCredentials:g,headers:w,onUploadProgress:({total:d,loaded:C})=>{t({percent:Math.round(C/d*100).toFixed(2)},h)}}).then(({data:d})=>{s(d,h)}).catch(v).finally(()=>{}),{abort(){console.log("upload progress is aborted.")}}},onChange:b})}const U=a=>{const{collectionsData:b}=a,{t:i}=F(),[c,u]=k.useState(!1),[h,f]=k.useState(b);k.useEffect(()=>{f(b)},[b]);const w=r.useAPIClient(),v=r.useCompile(),t=k.useMemo(()=>w.resource("backupFiles"),[w]),s=()=>T(this,null,function*(){if(a.isBackup){const o=yield t.dumpableCollections();f(o==null?void 0:o.data),u(!0)}u(!0)}),g=()=>{u(!1)},n=()=>{u(!1)},d=[{title:i("Collection"),dataIndex:"collection",key:"collection",render:(o,y)=>{const B=v(y.title);return y.name===B?B:e.jsxs("div",{children:[y.name," ",e.jsxs("span",{style:{color:"rgba(0, 0, 0, 0.3)",fontSize:"0.9em"},children:["(",v(y.title),")"]})]})}},{title:i("Origin"),dataIndex:"origin",key:"origin",width:"50%"}],C=Object.keys(h||{}).map(o=>({key:o,label:i(`${o}.title`),children:e.jsxs(e.Fragment,{children:[e.jsx(l.Alert,{style:{marginBottom:16},message:i(`${o}.description`)}),e.jsx(l.Table,{pagination:{pageSize:100},bordered:!0,size:"small",dataSource:h[o],columns:d,scroll:{y:400}})]})}));return e.jsxs(e.Fragment,{children:[e.jsx("a",{onClick:s,children:i("Learn more")}),e.jsx(l.Modal,{title:i("Backup instructions"),width:"80vw",open:c,footer:null,onOk:g,onCancel:n,children:e.jsx(l.Tabs,{defaultActiveKey:"required",items:C})})]})},G=({ButtonComponent:a=l.Button,title:b,upload:i=!1,fileData:c})=>{const{t:u}=F(),[h,f]=k.useState(["required"]),[w,v]=k.useState(!1),[t,s]=k.useState(null),[g,n]=k.useState(!1),d=r.useAPIClient(),C=k.useMemo(()=>d.resource("backupFiles"),[d]),[o,y]=k.useState([]);k.useEffect(()=>{y(Object.keys((t==null?void 0:t.dumpableCollectionsGroupByGroup)||[]).map(M=>({value:M,label:u(`${M}.title`),disabled:["required","skipped"].includes(M)})))},[t]);const B=()=>T(this,null,function*(){var M,z,H;if(v(!0),!i){n(!0);const{data:D}=yield C.get({filterByTk:c.name});y(Object.keys(((z=(M=D==null?void 0:D.data)==null?void 0:M.meta)==null?void 0:z.dumpableCollectionsGroupByGroup)||[]).map(j=>({value:j,label:u(`${j}.title`),disabled:["required","skipped"].includes(j)}))),s((H=D==null?void 0:D.data)==null?void 0:H.meta),n(!1)}}),O=()=>{C.restore({values:{dataTypes:h,filterByTk:c==null?void 0:c.name,key:t==null?void 0:t.key}}),v(!1)},S=()=>{v(!1),s(null),f(["required"])};return e.jsxs(e.Fragment,{children:[e.jsx(a,{onClick:B,children:b}),e.jsx(l.Modal,{title:u("Restore"),width:800,footer:i&&!t?null:void 0,open:w,onOk:O,onCancel:S,children:e.jsxs(l.Spin,{spinning:g,children:[i&&!t&&e.jsx(V,{setRestoreData:s}),(!i||t)&&[e.jsxs("strong",{style:{fontWeight:600,display:"block",margin:"16px 0 8px"},children:[u("Select the data to be restored")," (",e.jsx(U,{collectionsData:t==null?void 0:t.dumpableCollectionsGroupByGroup}),"):"]},"info"),e.jsx("div",{style:{lineHeight:2,marginBottom:8},children:e.jsx(L.FormItem,{children:e.jsx(r.Checkbox.Group,{options:o,style:{flexDirection:"column"},value:h,onChange:M=>f(M)})})},"dataType")]]})})]})},Q=({ButtonComponent:a=l.Button,refresh:b})=>{const{t:i}=F(),[c,u]=k.useState(!1),[h,f]=k.useState(["required"]),w=r.useAPIClient(),{notification:v}=l.App.useApp(),[t,s]=k.useState([]),g=()=>T(this,null,function*(){const{data:C}=yield w.resource("backupFiles").dumpableCollections();s(Object.keys(C||[]).map(o=>({value:o,label:i(`${o}.title`),disabled:["required","skipped"].includes(o)}))),u(!0)}),n=C=>{w.request({url:"backupFiles:create",method:"post",data:{dataTypes:h,method:C}}),v.info({key:"backup",message:e.jsxs("span",{children:[i("Processing..."),"    ",e.jsx(l.Spin,{indicator:e.jsx(x.LoadingOutlined,{style:{fontSize:24},spin:!0})})]}),duration:0}),u(!1),f(["required"]),setTimeout(()=>{b()},500)},d=()=>{u(!1),f(["required"])};return e.jsxs(e.Fragment,{children:[e.jsx(a,{icon:e.jsx(x.PlusOutlined,{}),type:"primary",onClick:g,children:i("New backup")}),e.jsxs(l.Modal,{title:i("New backup"),width:800,open:c,onCancel:d,footer:[e.jsxs(l.Row,{gutter:16,justify:"end",align:"middle",children:[e.jsx(l.Col,{children:e.jsx(l.Button,{onClick:d,children:i("Cancel")},"cancel")}),e.jsx(l.Col,{children:e.jsx(l.Dropdown.Button,{type:"primary",onClick:()=>n("priority"),overlay:e.jsxs(l.Menu,{children:[e.jsx(l.Menu.Item,{onClick:()=>n("main"),children:i("Self backup")},"main"),e.jsx(l.Menu.Item,{onClick:()=>n("worker"),children:i("Worker backup")},"worker")]}),children:i("Backup")},"submit")})]})],children:[e.jsxs("strong",{style:{fontWeight:600,display:"block",margin:"16px 0 8px"},children:[i("Select the data to be backed up")," (",e.jsx(U,{isBackup:!0}),"):"]}),e.jsx("div",{style:{lineHeight:2,marginBottom:8},children:e.jsx(r.Checkbox.Group,{options:t,style:{flexDirection:"column"},onChange:C=>f(C),value:h})})]})]})},V=a=>{const{t:b}=F(),i={multiple:!1,action:"/backupFiles:upload",onChange(c){var h,f,w;c.fileList.length>1&&c.fileList.splice(0,c.fileList.length-1);const{status:u}=c.file;u==="done"?(l.message.success(`${c.file.name} `+b("file uploaded successfully")),a.setRestoreData(q(E({},(f=(h=c.file.response)==null?void 0:h.data)==null?void 0:f.meta),{key:(w=c.file.response)==null?void 0:w.data.key}))):u==="error"&&l.message.error(`${c.file.name} `+b("file upload failed"))},onDrop(c){console.log("Dropped files",c.dataTransfer.files)}};return e.jsxs(X,q(E({},J(i)),{children:[e.jsx("p",{className:"ant-upload-drag-icon",children:e.jsx(x.InboxOutlined,{})}),e.jsxs("p",{className:"ant-upload-text",children:[" ",b("Click or drag file to this area to upload")]})]}))},Y=()=>{const{t:a}=F(),b=r.useAPIClient(),[i,c]=k.useState([]),[u,h]=k.useState(!1),[f,w]=k.useState(!1),{modal:v,notification:t}=l.App.useApp(),s=k.useMemo(()=>b.resource("backupFiles"),[b]),g=k.useCallback(()=>T(this,null,function*(){yield n()}),[]);r.useNoticeSub("backup",o=>{(t[o.level]||t.info)({key:"backup",message:o.msg}),g()}),k.useEffect(()=>{n()},[]);const n=()=>T(this,null,function*(){h(!0);const{data:o}=yield s.list();c(o.data),h(!1)}),d=o=>T(this,null,function*(){w(o.name);const y=yield b.request({url:"backupFiles:download",method:"get",params:{filterByTk:o.name},responseType:"blob",onDownloadProgress:O=>{const S=Math.round(O.loaded*100/O.total);S>=100?t.success({key:"downloadBackup",message:e.jsx("span",{children:a("Downloaded success!")}),duration:1}):t.info({key:"downloadBackup",message:e.jsxs("span",{children:[a("Downloading ")+S+"%","    ",e.jsx(l.Spin,{indicator:e.jsx(x.LoadingOutlined,{style:{fontSize:24},spin:!0})})]}),duration:0})}});w(!1);const B=new Blob([y.data]);K.saveAs(B,o.name)}),C=o=>{v.confirm({title:a("Delete record",{ns:"core"}),content:a("Are you sure you want to delete it?",{ns:"core"}),onOk:()=>T(this,null,function*(){yield s.destroy({filterByTk:o.name}),yield n(),l.message.success(a("Deleted successfully"))})})};return e.jsx("div",{children:e.jsxs(l.Card,{bordered:!1,children:[e.jsxs(l.Space,{style:{float:"right",marginBottom:16},children:[e.jsx(l.Button,{onClick:g,icon:e.jsx(x.ReloadOutlined,{}),children:a("Refresh")}),e.jsx(G,{upload:!0,title:e.jsxs(e.Fragment,{children:[e.jsx(x.UploadOutlined,{})," ",a("Restore backup from local")]})}),e.jsx(Q,{refresh:g})]}),e.jsx(l.Table,{dataSource:i,loading:u,columns:[{title:a("Backup file"),dataIndex:"name",width:400,onCell:o=>o.inProgress?{colSpan:4}:{},render:(o,y)=>y.inProgress?e.jsxs("div",{style:{color:"rgba(0, 0, 0, 0.88)"},children:[o,"(",a("Backing up"),"...)"]}):y.status==="error"?e.jsxs("div",{style:{color:"red"},children:[o,"(",a("Error"),")"]}):e.jsx("div",{children:o})},{title:a("File size"),dataIndex:"fileSize",onCell:o=>o.inProgress?{colSpan:0}:{}},{title:a("Created at",{ns:"core"}),dataIndex:"createdAt",onCell:o=>o.inProgress?{colSpan:0}:{},render:o=>e.jsx(r.DatePicker.ReadPretty,{value:o,showTime:!0})},{title:a("Actions",{ns:"core"}),dataIndex:"actions",onCell:o=>o.inProgress?{colSpan:0}:{},render:(o,y)=>e.jsxs(l.Space,{split:e.jsx(l.Divider,{type:"vertical"}),children:[y.status!=="error"&&e.jsx(G,{ButtonComponent:"a",title:a("Restore"),fileData:y}),y.status!=="error"&&e.jsx("a",{type:"link",onClick:()=>d(y),children:a("Download")}),e.jsx("a",{onClick:()=>C(y),children:a("Delete")})]})}]})]})})},_=function(a){return e.jsx(r.SchemaComponentOptions,{children:a.children})};_.displayName="DuplicatorProvider";class N extends r.Plugin{load(){return T(this,null,function*(){this.app.use(_),this.app.systemSettingsManager.add("system-services."+I,{title:this.t("Backup & Restore"),icon:"CloudServerOutlined",Component:Y,aclSnippet:"pm.backup.restore"})})}}p.PluginBackupRestoreClient=N,p.default=N,Object.defineProperties(p,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
@@ -1,14 +1,14 @@
1
1
  module.exports = {
2
2
  "react": "18.3.1",
3
- "@tachybase/client": "0.23.58",
4
- "@tachybase/components": "0.23.58",
3
+ "@tachybase/client": "1.0.18",
4
+ "@tachybase/components": "1.0.18",
5
5
  "@ant-design/icons": "5.5.2",
6
6
  "antd": "5.22.5",
7
- "@tachybase/server": "0.23.58",
8
- "@tachybase/utils": "0.23.58",
9
- "@tachybase/database": "0.23.58",
7
+ "@tachybase/server": "1.0.18",
8
+ "@tachybase/utils": "1.0.18",
9
+ "@tachybase/database": "1.0.18",
10
10
  "dayjs": "1.11.13",
11
11
  "lodash": "4.17.21",
12
12
  "react-i18next": "15.2.0",
13
- "@tachybase/actions": "0.23.58"
13
+ "@tachybase/actions": "1.0.18"
14
14
  };
@@ -10,6 +10,7 @@
10
10
  "Configuration": "Configuration",
11
11
  "Delete": "Delete",
12
12
  "Deleted successfully": "Deleted successfully",
13
+ "Done": "Done",
13
14
  "Download": "Download",
14
15
  "File size": "File size",
15
16
  "Learn more": "Learn more",
@@ -12,6 +12,7 @@
12
12
  "Configuration": "配置",
13
13
  "Delete": "删除",
14
14
  "Deleted successfully": "删除成功",
15
+ "Done": "完成",
15
16
  "Download": "下载",
16
17
  "File size": "文件大小",
17
18
  "Learn more": "了解更多",
@@ -1 +1 @@
1
- {"name":"@hapi/topo","description":"Topological sorting with grouping support","version":"6.0.2","repository":"git://github.com/hapijs/topo","main":"lib/index.js","types":"lib/index.d.ts","files":["lib"],"keywords":["topological","sort","toposort","topsort"],"eslintConfig":{"extends":["plugin:@hapi/module"]},"dependencies":{"@hapi/hoek":"^11.0.2"},"devDependencies":{"@hapi/code":"^9.0.3","@hapi/eslint-plugin":"*","@hapi/lab":"^25.1.2","@types/node":"^17.0.31","typescript":"~4.6.4"},"scripts":{"test":"lab -a @hapi/code -t 100 -L -Y","test-cov-html":"lab -a @hapi/code -t 100 -L -r html -o coverage.html"},"license":"BSD-3-Clause","_lastModified":"2025-03-06T09:58:49.921Z"}
1
+ {"name":"@hapi/topo","description":"Topological sorting with grouping support","version":"6.0.2","repository":"git://github.com/hapijs/topo","main":"lib/index.js","types":"lib/index.d.ts","files":["lib"],"keywords":["topological","sort","toposort","topsort"],"eslintConfig":{"extends":["plugin:@hapi/module"]},"dependencies":{"@hapi/hoek":"^11.0.2"},"devDependencies":{"@hapi/code":"^9.0.3","@hapi/eslint-plugin":"*","@hapi/lab":"^25.1.2","@types/node":"^17.0.31","typescript":"~4.6.4"},"scripts":{"test":"lab -a @hapi/code -t 100 -L -Y","test-cov-html":"lab -a @hapi/code -t 100 -L -r html -o coverage.html"},"license":"BSD-3-Clause","_lastModified":"2025-04-18T20:33:17.453Z"}
@@ -1 +1 @@
1
- {"name":"archiver","version":"5.3.2","description":"a streaming interface for archive generation","homepage":"https://github.com/archiverjs/node-archiver","author":{"name":"Chris Talkington","url":"http://christalkington.com/"},"repository":{"type":"git","url":"https://github.com/archiverjs/node-archiver.git"},"bugs":{"url":"https://github.com/archiverjs/node-archiver/issues"},"license":"MIT","main":"index.js","files":["index.js","lib"],"engines":{"node":">= 10"},"scripts":{"test":"mocha --reporter dot","bench":"node benchmark/simple/pack-zip.js"},"dependencies":{"archiver-utils":"^2.1.0","async":"^3.2.4","buffer-crc32":"^0.2.1","readable-stream":"^3.6.0","readdir-glob":"^1.1.2","tar-stream":"^2.2.0","zip-stream":"^4.1.0"},"devDependencies":{"archiver-jsdoc-theme":"^1.1.3","chai":"^4.3.7","jsdoc":"^3.6.4","mkdirp":"^2.1.5","mocha":"^9.0.2","rimraf":"^4.3.1","stream-bench":"^0.1.2","tar":"^6.1.13","yauzl":"^2.9.0"},"keywords":["archive","archiver","stream","zip","tar"],"publishConfig":{"registry":"https://registry.npmjs.org/"},"_lastModified":"2025-03-06T09:58:49.736Z"}
1
+ {"name":"archiver","version":"5.3.2","description":"a streaming interface for archive generation","homepage":"https://github.com/archiverjs/node-archiver","author":{"name":"Chris Talkington","url":"http://christalkington.com/"},"repository":{"type":"git","url":"https://github.com/archiverjs/node-archiver.git"},"bugs":{"url":"https://github.com/archiverjs/node-archiver/issues"},"license":"MIT","main":"index.js","files":["index.js","lib"],"engines":{"node":">= 10"},"scripts":{"test":"mocha --reporter dot","bench":"node benchmark/simple/pack-zip.js"},"dependencies":{"archiver-utils":"^2.1.0","async":"^3.2.4","buffer-crc32":"^0.2.1","readable-stream":"^3.6.0","readdir-glob":"^1.1.2","tar-stream":"^2.2.0","zip-stream":"^4.1.0"},"devDependencies":{"archiver-jsdoc-theme":"^1.1.3","chai":"^4.3.7","jsdoc":"^3.6.4","mkdirp":"^2.1.5","mocha":"^9.0.2","rimraf":"^4.3.1","stream-bench":"^0.1.2","tar":"^6.1.13","yauzl":"^2.9.0"},"keywords":["archive","archiver","stream","zip","tar"],"publishConfig":{"registry":"https://registry.npmjs.org/"},"_lastModified":"2025-04-18T20:33:17.269Z"}
@@ -1 +1 @@
1
- {"name":"mkdirp","description":"Recursively mkdir, like `mkdir -p`","version":"1.0.4","main":"index.js","keywords":["mkdir","directory","make dir","make","dir","recursive","native"],"repository":{"type":"git","url":"https://github.com/isaacs/node-mkdirp.git"},"scripts":{"test":"tap","snap":"tap","preversion":"npm test","postversion":"npm publish","postpublish":"git push origin --follow-tags"},"tap":{"check-coverage":true,"coverage-map":"map.js"},"devDependencies":{"require-inject":"^1.4.4","tap":"^14.10.7"},"bin":"bin/cmd.js","license":"MIT","engines":{"node":">=10"},"files":["bin","lib","index.js"],"_lastModified":"2025-03-06T09:58:49.824Z"}
1
+ {"name":"mkdirp","description":"Recursively mkdir, like `mkdir -p`","version":"1.0.4","main":"index.js","keywords":["mkdir","directory","make dir","make","dir","recursive","native"],"repository":{"type":"git","url":"https://github.com/isaacs/node-mkdirp.git"},"scripts":{"test":"tap","snap":"tap","preversion":"npm test","postversion":"npm publish","postpublish":"git push origin --follow-tags"},"tap":{"check-coverage":true,"coverage-map":"map.js"},"devDependencies":{"require-inject":"^1.4.4","tap":"^14.10.7"},"bin":"bin/cmd.js","license":"MIT","engines":{"node":">=10"},"files":["bin","lib","index.js"],"_lastModified":"2025-04-18T20:33:17.357Z"}
@@ -1 +1 @@
1
- {"name":"semver","version":"7.6.3","description":"The semantic version parser used by npm.","main":"index.js","scripts":{"test":"tap","snap":"tap","lint":"eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"","postlint":"template-oss-check","lintfix":"npm run lint -- --fix","posttest":"npm run lint","template-oss-apply":"template-oss-apply --force"},"devDependencies":{"@npmcli/eslint-config":"^4.0.0","@npmcli/template-oss":"4.22.0","benchmark":"^2.1.4","tap":"^16.0.0"},"license":"ISC","repository":{"type":"git","url":"git+https://github.com/npm/node-semver.git"},"bin":{"semver":"bin/semver.js"},"files":["bin/","lib/","classes/","functions/","internal/","ranges/","index.js","preload.js","range.bnf"],"tap":{"timeout":30,"coverage-map":"map.js","nyc-arg":["--exclude","tap-snapshots/**"]},"engines":{"node":">=10"},"author":"GitHub Inc.","templateOSS":{"//@npmcli/template-oss":"This file is partially managed by @npmcli/template-oss. Edits may be overwritten.","version":"4.22.0","engines":">=10","distPaths":["classes/","functions/","internal/","ranges/","index.js","preload.js","range.bnf"],"allowPaths":["/classes/","/functions/","/internal/","/ranges/","/index.js","/preload.js","/range.bnf","/benchmarks"],"publish":"true"},"_lastModified":"2025-03-06T09:58:50.151Z"}
1
+ {"name":"semver","version":"7.6.3","description":"The semantic version parser used by npm.","main":"index.js","scripts":{"test":"tap","snap":"tap","lint":"eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"","postlint":"template-oss-check","lintfix":"npm run lint -- --fix","posttest":"npm run lint","template-oss-apply":"template-oss-apply --force"},"devDependencies":{"@npmcli/eslint-config":"^4.0.0","@npmcli/template-oss":"4.22.0","benchmark":"^2.1.4","tap":"^16.0.0"},"license":"ISC","repository":{"type":"git","url":"git+https://github.com/npm/node-semver.git"},"bin":{"semver":"bin/semver.js"},"files":["bin/","lib/","classes/","functions/","internal/","ranges/","index.js","preload.js","range.bnf"],"tap":{"timeout":30,"coverage-map":"map.js","nyc-arg":["--exclude","tap-snapshots/**"]},"engines":{"node":">=10"},"author":"GitHub Inc.","templateOSS":{"//@npmcli/template-oss":"This file is partially managed by @npmcli/template-oss. Edits may be overwritten.","version":"4.22.0","engines":">=10","distPaths":["classes/","functions/","internal/","ranges/","index.js","preload.js","range.bnf"],"allowPaths":["/classes/","/functions/","/internal/","/ranges/","/index.js","/preload.js","/range.bnf","/benchmarks"],"publish":"true"},"_lastModified":"2025-04-18T20:33:17.681Z"}
@@ -1 +1 @@
1
- {"name":"yauzl","version":"3.2.0","description":"yet another unzip library for node","engines":{"node":">=12"},"main":"index.js","scripts":{"test":"node test/test.js"},"repository":{"type":"git","url":"git+https://github.com/thejoshwolfe/yauzl.git"},"keywords":["unzip","zip","stream","archive","file"],"author":"Josh Wolfe <thejoshwolfe@gmail.com>","license":"MIT","bugs":{"url":"https://github.com/thejoshwolfe/yauzl/issues"},"homepage":"https://github.com/thejoshwolfe/yauzl","dependencies":{"buffer-crc32":"~0.2.3","pend":"~1.2.0"},"devDependencies":{"bl":"^6.0.11"},"files":["fd-slicer.js","index.js"],"_lastModified":"2025-03-06T09:58:50.309Z"}
1
+ {"name":"yauzl","version":"3.2.0","description":"yet another unzip library for node","engines":{"node":">=12"},"main":"index.js","scripts":{"test":"node test/test.js"},"repository":{"type":"git","url":"git+https://github.com/thejoshwolfe/yauzl.git"},"keywords":["unzip","zip","stream","archive","file"],"author":"Josh Wolfe <thejoshwolfe@gmail.com>","license":"MIT","bugs":{"url":"https://github.com/thejoshwolfe/yauzl/issues"},"homepage":"https://github.com/thejoshwolfe/yauzl","dependencies":{"buffer-crc32":"~0.2.3","pend":"~1.2.0"},"devDependencies":{"bl":"^6.0.11"},"files":["fd-slicer.js","index.js"],"_lastModified":"2025-04-18T20:33:17.841Z"}
@@ -3,6 +3,7 @@ import { AppMigrator } from './app-migrator';
3
3
  type DumpOptions = {
4
4
  groups: Set<DumpRulesGroupType>;
5
5
  fileName?: string;
6
+ appName?: string;
6
7
  };
7
8
  type BackUpStatusOk = {
8
9
  name: string;
@@ -15,6 +16,11 @@ type BackUpStatusDoing = {
15
16
  inProgress: true;
16
17
  status: 'in_progress';
17
18
  };
19
+ type BackUpStatusError = {
20
+ name: string;
21
+ createdAt: Date;
22
+ status: 'error';
23
+ };
18
24
  export declare class Dumper extends AppMigrator {
19
25
  static dumpTasks: Map<string, Promise<any>>;
20
26
  direction: "dump";
@@ -25,7 +31,7 @@ export declare class Dumper extends AppMigrator {
25
31
  };
26
32
  };
27
33
  static getTaskPromise(taskId: string): Promise<any> | undefined;
28
- static getFileStatus(filePath: string): Promise<BackUpStatusOk | BackUpStatusDoing>;
34
+ static getFileStatus(filePath: string): Promise<BackUpStatusOk | BackUpStatusDoing | BackUpStatusError>;
29
35
  static generateFileName(): string;
30
36
  writeSQLContent(key: string, data: {
31
37
  sql: string | string[];
@@ -40,16 +46,18 @@ export declare class Dumper extends AppMigrator {
40
46
  collectionsGroupByDataTypes(): Promise<{
41
47
  [k: string]: any[];
42
48
  }>;
43
- backUpStorageDir(): string;
49
+ backUpStorageDir(appName?: string): string;
44
50
  allBackUpFilePaths(options?: {
45
51
  includeInProgress?: boolean;
46
52
  dir?: string;
53
+ appName?: string;
47
54
  }): Promise<string[]>;
48
- backUpFilePath(fileName: string): string;
49
- lockFilePath(fileName: string): string;
50
- writeLockFile(fileName: string): Promise<void>;
51
- cleanLockFile(fileName: string): Promise<void>;
52
- runDumpTask(options: Omit<DumpOptions, 'fileName'>): Promise<string>;
55
+ backUpFilePath(fileName: string, appName?: string): string;
56
+ lockFilePath(fileName: string, appName?: string): string;
57
+ writeLockFile(fileName: string, appName?: string): Promise<void>;
58
+ cleanLockFile(fileName: string, appName: string): Promise<void>;
59
+ getLockFile(appName: string): Promise<string>;
60
+ runDumpTask(options: DumpOptions): Promise<void>;
53
61
  dumpableCollectionsGroupByGroup(): Promise<{
54
62
  [x: string]: Pick<any, string>[];
55
63
  }>;
@@ -63,7 +71,7 @@ export declare class Dumper extends AppMigrator {
63
71
  dumpCollection(options: {
64
72
  name: string;
65
73
  }): Promise<void>;
66
- packDumpedDir(fileName: string): Promise<{
74
+ packDumpedDir(fileName: string, appName?: string): Promise<{
67
75
  filePath: string;
68
76
  dirname: string;
69
77
  }>;
@@ -36,7 +36,6 @@ var import_path = __toESM(require("path"));
36
36
  var process = __toESM(require("process"));
37
37
  var import_stream = __toESM(require("stream"));
38
38
  var import_util = __toESM(require("util"));
39
- var import_worker_threads = require("worker_threads");
40
39
  var import_database = require("@tachybase/database");
41
40
  var import_archiver = __toESM(require("archiver"));
42
41
  var import_dayjs = __toESM(require("dayjs"));
@@ -60,11 +59,19 @@ const _Dumper = class _Dumper extends import_app_migrator.AppMigrator {
60
59
  const fileName = import_path.default.basename(filePath);
61
60
  return import_fs.default.promises.stat(lockFile).then((lockFileStat) => {
62
61
  if (lockFileStat.isFile()) {
63
- return {
64
- name: fileName,
65
- inProgress: true,
66
- status: "in_progress"
67
- };
62
+ if (lockFileStat.ctime.getTime() < Date.now() - 2 * 60 * 60 * 1e3) {
63
+ return {
64
+ name: fileName,
65
+ createdAt: lockFileStat.ctime,
66
+ status: "error"
67
+ };
68
+ } else {
69
+ return {
70
+ name: fileName,
71
+ inProgress: true,
72
+ status: "in_progress"
73
+ };
74
+ }
68
75
  } else {
69
76
  throw new Error("Lock file is not a file");
70
77
  }
@@ -134,11 +141,14 @@ const _Dumper = class _Dumper extends import_app_migrator.AppMigrator {
134
141
  const grouped = import_lodash.default.groupBy(await this.dumpableCollections(), "group");
135
142
  return Object.fromEntries(Object.entries(grouped).map(([key, value]) => [key, value.map((item) => item.name)]));
136
143
  }
137
- backUpStorageDir() {
144
+ backUpStorageDir(appName) {
145
+ if (appName && appName !== "main") {
146
+ return import_path.default.resolve(process.cwd(), "storage", "backups", appName);
147
+ }
138
148
  return import_path.default.resolve(process.cwd(), "storage", "backups");
139
149
  }
140
150
  async allBackUpFilePaths(options) {
141
- const dirname = (options == null ? void 0 : options.dir) || this.backUpStorageDir();
151
+ const dirname = (options == null ? void 0 : options.dir) || this.backUpStorageDir(options == null ? void 0 : options.appName);
142
152
  const includeInProgress = options == null ? void 0 : options.includeInProgress;
143
153
  try {
144
154
  const files = await import_promises.default.readdir(dirname);
@@ -165,52 +175,37 @@ const _Dumper = class _Dumper extends import_app_migrator.AppMigrator {
165
175
  return [];
166
176
  }
167
177
  }
168
- backUpFilePath(fileName) {
169
- const dirname = this.backUpStorageDir();
178
+ backUpFilePath(fileName, appName) {
179
+ const dirname = this.backUpStorageDir(appName);
170
180
  return import_path.default.resolve(dirname, fileName);
171
181
  }
172
- lockFilePath(fileName) {
182
+ lockFilePath(fileName, appName) {
173
183
  const lockFile = fileName + ".lock";
174
- const dirname = this.backUpStorageDir();
184
+ const dirname = this.backUpStorageDir(appName);
175
185
  return import_path.default.resolve(dirname, lockFile);
176
186
  }
177
- async writeLockFile(fileName) {
178
- const dirname = this.backUpStorageDir();
187
+ async writeLockFile(fileName, appName) {
188
+ const dirname = this.backUpStorageDir(appName);
179
189
  await (0, import_mkdirp.default)(dirname);
180
- const filePath = this.lockFilePath(fileName);
190
+ const filePath = this.lockFilePath(fileName, appName);
181
191
  await import_promises.default.writeFile(filePath, "lock", "utf8");
182
192
  }
183
- async cleanLockFile(fileName) {
184
- const filePath = this.lockFilePath(fileName);
193
+ async cleanLockFile(fileName, appName) {
194
+ const filePath = this.lockFilePath(fileName, appName);
185
195
  await import_promises.default.unlink(filePath);
186
196
  }
187
- async runDumpTask(options) {
197
+ async getLockFile(appName) {
188
198
  const backupFileName = _Dumper.generateFileName();
189
- await this.writeLockFile(backupFileName);
190
- if (import_worker_threads.isMainThread) {
191
- const promise = this.dump({
192
- groups: options.groups,
193
- fileName: backupFileName
194
- }).finally(() => {
195
- this.cleanLockFile(backupFileName);
196
- _Dumper.dumpTasks.delete(backupFileName);
197
- this.app.noticeManager.notify("backup", { msg: "Done" });
198
- });
199
- _Dumper.dumpTasks.set(backupFileName, promise);
200
- } else {
201
- try {
202
- await this.dump({
203
- groups: options.groups,
204
- fileName: backupFileName
205
- });
206
- } catch (err) {
207
- throw err;
208
- } finally {
209
- this.cleanLockFile(backupFileName);
210
- }
211
- }
199
+ await this.writeLockFile(backupFileName, appName);
212
200
  return backupFileName;
213
201
  }
202
+ async runDumpTask(options) {
203
+ await this.dump({
204
+ groups: options.groups,
205
+ fileName: options.fileName,
206
+ appName: options.appName
207
+ });
208
+ }
214
209
  async dumpableCollectionsGroupByGroup() {
215
210
  return (0, import_lodash.default)(await this.dumpableCollections()).map((c) => import_lodash.default.pick(c, ["name", "group", "origin", "title", "isView", "inherits"])).groupBy("group").mapValues((items) => import_lodash.default.sortBy(items, (item) => item.name)).value();
216
211
  }
@@ -235,7 +230,7 @@ const _Dumper = class _Dumper extends import_app_migrator.AppMigrator {
235
230
  });
236
231
  await this.dumpDb(options);
237
232
  const backupFileName = options.fileName || _Dumper.generateFileName();
238
- const filePath = await this.packDumpedDir(backupFileName);
233
+ const filePath = await this.packDumpedDir(backupFileName, options.appName);
239
234
  await this.clearWorkDir();
240
235
  return filePath;
241
236
  }
@@ -380,8 +375,8 @@ const _Dumper = class _Dumper extends import_app_migrator.AppMigrator {
380
375
  }
381
376
  await import_promises.default.writeFile(import_path.default.resolve(collectionDataDir, "meta"), JSON.stringify(meta), "utf8");
382
377
  }
383
- async packDumpedDir(fileName) {
384
- const dirname = this.backUpStorageDir();
378
+ async packDumpedDir(fileName, appName) {
379
+ const dirname = this.backUpStorageDir(appName);
385
380
  await (0, import_mkdirp.default)(dirname);
386
381
  const filePath = import_path.default.resolve(dirname, fileName);
387
382
  const output = import_fs.default.createWriteStream(filePath);
@@ -60,7 +60,8 @@ var backup_files_default = {
60
60
  const { page = import_actions.DEFAULT_PAGE, pageSize = import_actions.DEFAULT_PER_PAGE } = ctx.action.params;
61
61
  const dumper = new import_dumper.Dumper(ctx.app);
62
62
  const backupFiles = await dumper.allBackUpFilePaths({
63
- includeInProgress: true
63
+ includeInProgress: true,
64
+ appName: ctx.app.name
64
65
  });
65
66
  const count = backupFiles.length;
66
67
  const rows = await Promise.all(
@@ -80,7 +81,7 @@ var backup_files_default = {
80
81
  async get(ctx, next) {
81
82
  const { filterByTk } = ctx.action.params;
82
83
  const dumper = new import_dumper.Dumper(ctx.app);
83
- const filePath = dumper.backUpFilePath(filterByTk);
84
+ const filePath = dumper.backUpFilePath(filterByTk, ctx.app.name);
84
85
  async function sendError(message, status = 404) {
85
86
  ctx.body = { status: "error", message };
86
87
  ctx.status = status;
@@ -114,31 +115,45 @@ var backup_files_default = {
114
115
  async create(ctx, next) {
115
116
  var _a, _b;
116
117
  const data = ctx.request.body;
117
- let taskId;
118
118
  const app = ctx.app;
119
119
  if (data.method === "worker" && !((_a = app.worker) == null ? void 0 : _a.available)) {
120
120
  ctx.throw(500, ctx.t("No worker thread", { ns: "worker-thread" }));
121
121
  return next();
122
122
  }
123
123
  let useWorker = data.method === "worker" || data.method === "priority" && ((_b = app.worker) == null ? void 0 : _b.available);
124
+ const dumper = new import_dumper.Dumper(ctx.app);
125
+ const taskId = await dumper.getLockFile(ctx.app.name);
124
126
  if (useWorker) {
125
- try {
126
- taskId = await app.worker.callPluginMethod({
127
- plugin: import_server2.default,
128
- method: "workerCreateBackUp",
129
- params: {
130
- dataTypes: data.dataTypes
131
- },
132
- // 目前限制方法并发为1
133
- concurrency: 1
134
- });
135
- app.noticeManager.notify("backup", { level: "info", msg: ctx.t("Done") });
136
- } catch (error) {
137
- ctx.throw(500, ctx.t(error.message, { ns: "worker-thread" }));
138
- }
127
+ app.worker.callPluginMethod({
128
+ plugin: import_server2.default,
129
+ method: "workerCreateBackUp",
130
+ params: {
131
+ dataTypes: data.dataTypes,
132
+ appName: ctx.app.name,
133
+ filename: taskId
134
+ },
135
+ // 目前限制方法并发为1
136
+ concurrency: 1
137
+ }).then((res) => {
138
+ app.noticeManager.notify("backup", { level: "info", msg: ctx.t("Done", { ns: "backup" }) });
139
+ }).catch((error) => {
140
+ app.noticeManager.notify("backup", { level: "error", msg: error.message });
141
+ }).finally(() => {
142
+ dumper.cleanLockFile(taskId, ctx.app.name);
143
+ });
139
144
  } else {
140
145
  const plugin = app.pm.get(import_server2.default);
141
- taskId = await plugin.workerCreateBackUp(data);
146
+ plugin.workerCreateBackUp({
147
+ dataTypes: data.dataTypes,
148
+ appName: ctx.app.name,
149
+ filename: taskId
150
+ }).then((res) => {
151
+ app.noticeManager.notify("backup", { level: "info", msg: ctx.t("Done", { ns: "backup" }) });
152
+ }).catch((error) => {
153
+ app.noticeManager.notify("backup", { level: "error", msg: error.message });
154
+ }).finally(() => {
155
+ dumper.cleanLockFile(taskId, ctx.app.name);
156
+ });
142
157
  }
143
158
  ctx.body = {
144
159
  key: taskId
@@ -153,7 +168,7 @@ var backup_files_default = {
153
168
  async download(ctx, next) {
154
169
  const { filterByTk } = ctx.action.params;
155
170
  const dumper = new import_dumper.Dumper(ctx.app);
156
- const filePath = dumper.backUpFilePath(filterByTk);
171
+ const filePath = dumper.backUpFilePath(filterByTk, ctx.app.name);
157
172
  const fileState = await import_dumper.Dumper.getFileStatus(filePath);
158
173
  if (fileState.status !== "ok") {
159
174
  throw new Error(`Backup file ${filterByTk} not found`);
@@ -174,7 +189,7 @@ var backup_files_default = {
174
189
  }
175
190
  if (filterByTk) {
176
191
  const dumper = new import_dumper.Dumper(ctx.app);
177
- return dumper.backUpFilePath(filterByTk);
192
+ return dumper.backUpFilePath(filterByTk, ctx.app.name);
178
193
  }
179
194
  })();
180
195
  if (!filePath) {
@@ -190,7 +205,7 @@ var backup_files_default = {
190
205
  async destroy(ctx, next) {
191
206
  const { filterByTk } = ctx.action.params;
192
207
  const dumper = new import_dumper.Dumper(ctx.app);
193
- const filePath = dumper.backUpFilePath(filterByTk);
208
+ const filePath = dumper.backUpFilePath(filterByTk, ctx.app.name);
194
209
  await import_promises.default.unlink(filePath);
195
210
  ctx.body = {
196
211
  status: "ok"
@@ -4,5 +4,7 @@ export default class PluginBackupRestoreServer extends Plugin {
4
4
  load(): Promise<void>;
5
5
  workerCreateBackUp(data: {
6
6
  dataTypes: string[];
7
- }): Promise<string>;
7
+ appName: string;
8
+ filename: string;
9
+ }): Promise<void>;
8
10
  }
@@ -44,9 +44,10 @@ class PluginBackupRestoreServer extends import_server.Plugin {
44
44
  this.app.resourcer.define(import_backup_files.default);
45
45
  }
46
46
  async workerCreateBackUp(data) {
47
- const dumper = new import_dumper.Dumper(this.app);
48
- return dumper.runDumpTask({
49
- groups: new Set(data.dataTypes)
47
+ await new import_dumper.Dumper(this.app).runDumpTask({
48
+ groups: new Set(data.dataTypes),
49
+ appName: data.appName,
50
+ fileName: data.filename
50
51
  });
51
52
  }
52
53
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tachybase/module-backup",
3
3
  "displayName": "App backup & restore",
4
- "version": "0.23.58",
4
+ "version": "1.0.18",
5
5
  "description": "Backup and restore applications for scenarios such as application replication, migration, and upgrades.",
6
6
  "keywords": [
7
7
  "System management"
@@ -30,16 +30,16 @@
30
30
  "semver": "^7.6.3",
31
31
  "tar": "^6.2.1",
32
32
  "yauzl": "^3.2.0",
33
- "@tachybase/components": "0.23.58",
34
- "@tachybase/module-worker-thread": "0.23.58"
33
+ "@tachybase/components": "1.0.18",
34
+ "@tachybase/module-worker-thread": "1.0.18"
35
35
  },
36
36
  "peerDependencies": {
37
- "@tachybase/actions": "0.23.58",
38
- "@tachybase/client": "0.23.58",
39
- "@tachybase/server": "0.23.58",
40
- "@tachybase/database": "0.23.58",
41
- "@tachybase/test": "0.23.58",
42
- "@tachybase/utils": "0.23.58"
37
+ "@tachybase/actions": "1.0.18",
38
+ "@tachybase/client": "1.0.18",
39
+ "@tachybase/database": "1.0.18",
40
+ "@tachybase/test": "1.0.18",
41
+ "@tachybase/utils": "1.0.18",
42
+ "@tachybase/server": "1.0.18"
43
43
  },
44
44
  "description.zh-CN": "备份和还原应用,可用于应用的复制、迁移、升级等场景。",
45
45
  "displayName.zh-CN": "应用的备份与还原",