@tachybase/module-backup 0.23.48 → 1.0.6
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.
- package/dist/client/index.js +1 -1
- package/dist/externalVersion.js +6 -6
- package/dist/node_modules/@hapi/topo/package.json +1 -1
- package/dist/node_modules/archiver/package.json +1 -1
- package/dist/node_modules/mkdirp/package.json +1 -1
- package/dist/node_modules/semver/package.json +1 -1
- package/dist/node_modules/yauzl/package.json +1 -1
- package/dist/server/dumper.d.ts +8 -6
- package/dist/server/dumper.js +24 -19
- package/dist/server/resourcers/backup-files.js +9 -5
- package/dist/server/server.js +2 -1
- package/package.json +9 -9
package/dist/client/index.js
CHANGED
|
@@ -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,M,a,P){"use strict";var Z=Object.defineProperty,R=Object.defineProperties;var ee=Object.getOwnPropertyDescriptors;var z=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(z)for(var e of z(r))oe.call(r,e)&&W(p,e,r[e]);return p},D=(p,r)=>R(p,ee(r));var B=(p,r,e)=>new Promise((y,L)=>{var M=C=>{try{P(e.next(C))}catch(x){L(x)}},a=C=>{try{P(e.throw(C))}catch(x){L(x)}},P=C=>C.done?y(C.value):Promise.resolve(C.value).then(M,a);P((e=e.apply(p,r)).next())});var C=typeof globalThis!="undefined"?globalThis:typeof window!="undefined"?window:typeof global!="undefined"?global:typeof self!="undefined"?self:{},x={exports:{}};(function(l,g){(function(c,i){i()})(C,function(){function c(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 i(t,s,b){var n=new XMLHttpRequest;n.open("GET",t),n.responseType="blob",n.onload=function(){v(n.response,s,b)},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(b){}return 200<=s.status&&299>=s.status}function h(t){try{t.dispatchEvent(new MouseEvent("click"))}catch(b){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 C=="object"&&C.global===C?C: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,b){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)?i(t,s,b):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,b){if(s=s||t.name||"download",typeof t!="string")navigator.msSaveOrOpenBlob(c(t,b),s);else if(u(t))i(t,s,b);else{var n=document.createElement("a");n.href=t,n.target="_blank",setTimeout(function(){h(n)})}}:function(t,s,b,n){if(n=n||open("","_blank"),n&&(n.document.title=n.document.body.innerText="downloading..."),typeof t=="string")return i(t,s,b);var d=t.type==="application/octet-stream",m=/constructor/i.test(f.HTMLElement)||f.safari,o=/CriOS\/[\d]+/.test(navigator.userAgent);if((o||d&&m||w)&&typeof FileReader!="undefined"){var k=new FileReader;k.onloadend=function(){var T=k.result;T=o?T:T.replace(/^data:[^;]*;/,"data:attachment/file;"),n?n.location.href=T:location=T,n=null},k.readAsDataURL(t)}else{var S=f.URL||f.webkitURL,A=S.createObjectURL(t);n?n.location=A:location.href=A,n=null,setTimeout(function(){S.revokeObjectURL(A)},4e4)}});f.saveAs=v.saveAs=v,l.exports=v})})(x);var K=x.exports;const I="backup";function E(){return P.useTranslation(I,{nsMode:"fallback"})}const{Dragger:X}=a.Upload;function J(l){const g=i=>{var u;(u=l.onChange)==null||u.call(l,i)},c=r.useAPIClient();return D(q({},l),{customRequest({action:i,data:u,file:h,filename:f,headers:w,onError:v,onProgress:t,onSuccess:s,withCredentials:b}){const n=new FormData;return u&&Object.keys(u).forEach(d=>{n.append(d,u[d])}),n.append(f,h),c.axios.post(i,n,{withCredentials:b,headers:w,onUploadProgress:({total:d,loaded:m})=>{t({percent:Math.round(m/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=l=>{const{collectionsData:g}=l,{t:c}=E(),[i,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=()=>B(this,null,function*(){if(l.isBackup){const o=yield t.dumpableCollections();f(o==null?void 0:o.data),u(!0)}u(!0)}),b=()=>{u(!1)},n=()=>{u(!1)},d=[{title:c("Collection"),dataIndex:"collection",key:"collection",render:(o,k)=>{const S=v(k.title);return k.name===S?S:e.jsxs("div",{children:[k.name," ",e.jsxs("span",{style:{color:"rgba(0, 0, 0, 0.3)",fontSize:"0.9em"},children:["(",v(k.title),")"]})]})}},{title:c("Origin"),dataIndex:"origin",key:"origin",width:"50%"}],m=Object.keys(h||{}).map(o=>({key:o,label:c(`${o}.title`),children:e.jsxs(e.Fragment,{children:[e.jsx(a.Alert,{style:{marginBottom:16},message:c(`${o}.description`)}),e.jsx(a.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:c("Learn more")}),e.jsx(a.Modal,{title:c("Backup instructions"),width:"80vw",open:i,footer:null,onOk:b,onCancel:n,children:e.jsx(a.Tabs,{defaultActiveKey:"required",items:m})})]})},G=({ButtonComponent:l=a.Button,title:g,upload:c=!1,fileData:i})=>{const{t:u}=E(),[h,f]=y.useState(["required"]),[w,v]=y.useState(!1),[t,s]=y.useState(null),[b,n]=y.useState(!1),d=r.useAPIClient(),m=y.useMemo(()=>d.resource("backupFiles"),[d]),[o,k]=y.useState([]);y.useEffect(()=>{k(Object.keys((t==null?void 0:t.dumpableCollectionsGroupByGroup)||[]).map(O=>({value:O,label:u(`${O}.title`),disabled:["required","skipped"].includes(O)})))},[t]);const S=()=>B(this,null,function*(){var O,H,$;if(v(!0),!c){n(!0);const{data:F}=yield m.get({filterByTk:i.name});k(Object.keys(((H=(O=F==null?void 0:F.data)==null?void 0:O.meta)==null?void 0:H.dumpableCollectionsGroupByGroup)||[]).map(j=>({value:j,label:u(`${j}.title`),disabled:["required","skipped"].includes(j)}))),s(($=F==null?void 0:F.data)==null?void 0:$.meta),n(!1)}}),A=()=>{m.restore({values:{dataTypes:h,filterByTk:i==null?void 0:i.name,key:t==null?void 0:t.key}}),v(!1)},T=()=>{v(!1),s(null),f(["required"])};return e.jsxs(e.Fragment,{children:[e.jsx(l,{onClick:S,children:g}),e.jsx(a.Modal,{title:u("Restore"),width:800,footer:c&&!t?null:void 0,open:w,onOk:A,onCancel:T,children:e.jsxs(a.Spin,{spinning:b,children:[c&&!t&&e.jsx(V,{setRestoreData:s}),(!c||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:O=>f(O)})})},"dataType")]]})})]})},Q=({ButtonComponent:l=a.Button,refresh:g})=>{const{t:c}=E(),[i,u]=y.useState(!1),[h,f]=y.useState(["required"]),w=r.useAPIClient(),{notification:v}=a.App.useApp(),[t,s]=y.useState([]),b=()=>B(this,null,function*(){const{data:m}=yield w.resource("backupFiles").dumpableCollections();s(Object.keys(m||[]).map(o=>({value:o,label:c(`${o}.title`),disabled:["required","skipped"].includes(o)}))),u(!0)}),n=m=>{w.request({url:"backupFiles:create",method:"post",data:{dataTypes:h,method:m}}).finally(()=>{v.destroy("backup")}),v.info({key:"backup",message:e.jsxs("span",{children:[c("Processing...")," ",e.jsx(a.Spin,{indicator:e.jsx(M.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(l,{icon:e.jsx(M.PlusOutlined,{}),type:"primary",onClick:b,children:c("New backup")}),e.jsxs(a.Modal,{title:c("New backup"),width:800,open:i,onCancel:d,footer:[e.jsxs(a.Row,{gutter:16,justify:"end",align:"middle",children:[e.jsx(a.Col,{children:e.jsx(a.Button,{onClick:d,children:c("Cancel")},"cancel")}),e.jsx(a.Col,{children:e.jsx(a.Dropdown.Button,{type:"primary",onClick:()=>n("priority"),overlay:e.jsxs(a.Menu,{children:[e.jsx(a.Menu.Item,{onClick:()=>n("main"),children:c("Self backup")},"main"),e.jsx(a.Menu.Item,{onClick:()=>n("worker"),children:c("Worker backup")},"worker")]}),children:c("Backup")},"submit")})]})],children:[e.jsxs("strong",{style:{fontWeight:600,display:"block",margin:"16px 0 8px"},children:[c("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:m=>f(m),value:h})})]})]})},V=l=>{const{t:g}=E(),c={multiple:!1,action:"/backupFiles:upload",onChange(i){var h,f,w;i.fileList.length>1&&i.fileList.splice(0,i.fileList.length-1);const{status:u}=i.file;u==="done"?(a.message.success(`${i.file.name} `+g("file uploaded successfully")),l.setRestoreData(D(q({},(f=(h=i.file.response)==null?void 0:h.data)==null?void 0:f.meta),{key:(w=i.file.response)==null?void 0:w.data.key}))):u==="error"&&a.message.error(`${i.file.name} `+g("file upload failed"))},onDrop(i){console.log("Dropped files",i.dataTransfer.files)}};return e.jsxs(X,D(q({},J(c)),{children:[e.jsx("p",{className:"ant-upload-drag-icon",children:e.jsx(M.InboxOutlined,{})}),e.jsxs("p",{className:"ant-upload-text",children:[" ",g("Click or drag file to this area to upload")]})]}))},Y=()=>{const{t:l}=E(),g=r.useAPIClient(),[c,i]=y.useState([]),[u,h]=y.useState(!1),[f,w]=y.useState(!1),{modal:v,notification:t}=a.App.useApp(),s=y.useMemo(()=>g.resource("backupFiles"),[g]),b=y.useCallback(()=>B(this,null,function*(){yield n()}),[]);r.useNoticeSub("backup",o=>{(t[o.level]||t.info)({key:"backup",message:o.msg}),b()}),y.useEffect(()=>{n()},[]);const n=()=>B(this,null,function*(){h(!0);const{data:o}=yield s.list();i(o.data),h(!1)}),d=o=>B(this,null,function*(){w(o.name);const k=yield g.request({url:"backupFiles:download",method:"get",params:{filterByTk:o.name},responseType:"blob"});w(!1);const S=new Blob([k.data]);K.saveAs(S,o.name)}),m=o=>{v.confirm({title:l("Delete record",{ns:"core"}),content:l("Are you sure you want to delete it?",{ns:"core"}),onOk:()=>B(this,null,function*(){yield s.destroy({filterByTk:o.name}),yield n(),a.message.success(l("Deleted successfully"))})})};return e.jsx("div",{children:e.jsxs(a.Card,{bordered:!1,children:[e.jsxs(a.Space,{style:{float:"right",marginBottom:16},children:[e.jsx(a.Button,{onClick:b,icon:e.jsx(M.ReloadOutlined,{}),children:l("Refresh")}),e.jsx(G,{upload:!0,title:e.jsxs(e.Fragment,{children:[e.jsx(M.UploadOutlined,{})," ",l("Restore backup from local")]})}),e.jsx(Q,{refresh:b})]}),e.jsx(a.Table,{dataSource:c,loading:u,columns:[{title:l("Backup file"),dataIndex:"name",width:400,onCell:o=>o.inProgress?{colSpan:4}:{},render:(o,k)=>k.inProgress?e.jsxs("div",{style:{color:"rgba(0, 0, 0, 0.88)"},children:[o,"(",l("Backing up"),"...)"]}):e.jsx("div",{children:o})},{title:l("File size"),dataIndex:"fileSize",onCell:o=>o.inProgress?{colSpan:0}:{}},{title:l("Created at",{ns:"core"}),dataIndex:"createdAt",onCell:o=>o.inProgress?{colSpan:0}:{},render:o=>e.jsx(r.DatePicker.ReadPretty,{value:o,showTime:!0})},{title:l("Actions",{ns:"core"}),dataIndex:"actions",onCell:o=>o.inProgress?{colSpan:0}:{},render:(o,k)=>e.jsxs(a.Space,{split:e.jsx(a.Divider,{type:"vertical"}),children:[e.jsx(G,{ButtonComponent:"a",title:l("Restore"),fileData:k}),e.jsx("a",{type:"link",onClick:()=>d(k),children:l("Download")}),e.jsx("a",{onClick:()=>m(k),children:l("Delete")})]})}]})]})})},_=function(l){return e.jsx(r.SchemaComponentOptions,{children:l.children})};_.displayName="DuplicatorProvider";class N extends r.Plugin{load(){return B(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,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"}})});
|
package/dist/externalVersion.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
"react": "18.3.1",
|
|
3
|
-
"@tachybase/client": "0.
|
|
4
|
-
"@tachybase/components": "0.
|
|
3
|
+
"@tachybase/client": "1.0.6",
|
|
4
|
+
"@tachybase/components": "1.0.6",
|
|
5
5
|
"@ant-design/icons": "5.5.2",
|
|
6
6
|
"antd": "5.22.5",
|
|
7
|
-
"@tachybase/server": "0.
|
|
8
|
-
"@tachybase/utils": "0.
|
|
9
|
-
"@tachybase/database": "0.
|
|
7
|
+
"@tachybase/server": "1.0.6",
|
|
8
|
+
"@tachybase/utils": "1.0.6",
|
|
9
|
+
"@tachybase/database": "1.0.6",
|
|
10
10
|
"dayjs": "1.11.13",
|
|
11
11
|
"lodash": "4.17.21",
|
|
12
12
|
"react-i18next": "15.2.0",
|
|
13
|
-
"@tachybase/actions": "0.
|
|
13
|
+
"@tachybase/actions": "1.0.6"
|
|
14
14
|
};
|
|
@@ -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-
|
|
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-02T02:57:13.012Z"}
|
|
@@ -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-
|
|
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-02T02:57:12.820Z"}
|
|
@@ -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-
|
|
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-02T02:57:12.916Z"}
|
|
@@ -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-
|
|
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-02T02:57:13.246Z"}
|
|
@@ -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-
|
|
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-02T02:57:13.407Z"}
|
package/dist/server/dumper.d.ts
CHANGED
|
@@ -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;
|
|
@@ -40,15 +41,16 @@ export declare class Dumper extends AppMigrator {
|
|
|
40
41
|
collectionsGroupByDataTypes(): Promise<{
|
|
41
42
|
[k: string]: any[];
|
|
42
43
|
}>;
|
|
43
|
-
backUpStorageDir(): string;
|
|
44
|
+
backUpStorageDir(appName?: string): string;
|
|
44
45
|
allBackUpFilePaths(options?: {
|
|
45
46
|
includeInProgress?: boolean;
|
|
46
47
|
dir?: string;
|
|
48
|
+
appName?: string;
|
|
47
49
|
}): Promise<string[]>;
|
|
48
|
-
backUpFilePath(fileName: string): string;
|
|
49
|
-
lockFilePath(fileName: string): string;
|
|
50
|
-
writeLockFile(fileName: string): Promise<void>;
|
|
51
|
-
cleanLockFile(fileName: string): Promise<void>;
|
|
50
|
+
backUpFilePath(fileName: string, appName?: string): string;
|
|
51
|
+
lockFilePath(fileName: string, appName?: string): string;
|
|
52
|
+
writeLockFile(fileName: string, appName?: string): Promise<void>;
|
|
53
|
+
cleanLockFile(fileName: string, appName?: string): Promise<void>;
|
|
52
54
|
runDumpTask(options: Omit<DumpOptions, 'fileName'>): Promise<string>;
|
|
53
55
|
dumpableCollectionsGroupByGroup(): Promise<{
|
|
54
56
|
[x: string]: Pick<any, string>[];
|
|
@@ -63,7 +65,7 @@ export declare class Dumper extends AppMigrator {
|
|
|
63
65
|
dumpCollection(options: {
|
|
64
66
|
name: string;
|
|
65
67
|
}): Promise<void>;
|
|
66
|
-
packDumpedDir(fileName: string): Promise<{
|
|
68
|
+
packDumpedDir(fileName: string, appName?: string): Promise<{
|
|
67
69
|
filePath: string;
|
|
68
70
|
dirname: string;
|
|
69
71
|
}>;
|
package/dist/server/dumper.js
CHANGED
|
@@ -134,11 +134,14 @@ const _Dumper = class _Dumper extends import_app_migrator.AppMigrator {
|
|
|
134
134
|
const grouped = import_lodash.default.groupBy(await this.dumpableCollections(), "group");
|
|
135
135
|
return Object.fromEntries(Object.entries(grouped).map(([key, value]) => [key, value.map((item) => item.name)]));
|
|
136
136
|
}
|
|
137
|
-
backUpStorageDir() {
|
|
137
|
+
backUpStorageDir(appName) {
|
|
138
|
+
if (appName && appName !== "main") {
|
|
139
|
+
return import_path.default.resolve(process.cwd(), "storage", "backups", appName);
|
|
140
|
+
}
|
|
138
141
|
return import_path.default.resolve(process.cwd(), "storage", "backups");
|
|
139
142
|
}
|
|
140
143
|
async allBackUpFilePaths(options) {
|
|
141
|
-
const dirname = (options == null ? void 0 : options.dir) || this.backUpStorageDir();
|
|
144
|
+
const dirname = (options == null ? void 0 : options.dir) || this.backUpStorageDir(options == null ? void 0 : options.appName);
|
|
142
145
|
const includeInProgress = options == null ? void 0 : options.includeInProgress;
|
|
143
146
|
try {
|
|
144
147
|
const files = await import_promises.default.readdir(dirname);
|
|
@@ -165,34 +168,35 @@ const _Dumper = class _Dumper extends import_app_migrator.AppMigrator {
|
|
|
165
168
|
return [];
|
|
166
169
|
}
|
|
167
170
|
}
|
|
168
|
-
backUpFilePath(fileName) {
|
|
169
|
-
const dirname = this.backUpStorageDir();
|
|
171
|
+
backUpFilePath(fileName, appName) {
|
|
172
|
+
const dirname = this.backUpStorageDir(appName);
|
|
170
173
|
return import_path.default.resolve(dirname, fileName);
|
|
171
174
|
}
|
|
172
|
-
lockFilePath(fileName) {
|
|
175
|
+
lockFilePath(fileName, appName) {
|
|
173
176
|
const lockFile = fileName + ".lock";
|
|
174
|
-
const dirname = this.backUpStorageDir();
|
|
177
|
+
const dirname = this.backUpStorageDir(appName);
|
|
175
178
|
return import_path.default.resolve(dirname, lockFile);
|
|
176
179
|
}
|
|
177
|
-
async writeLockFile(fileName) {
|
|
178
|
-
const dirname = this.backUpStorageDir();
|
|
180
|
+
async writeLockFile(fileName, appName) {
|
|
181
|
+
const dirname = this.backUpStorageDir(appName);
|
|
179
182
|
await (0, import_mkdirp.default)(dirname);
|
|
180
|
-
const filePath = this.lockFilePath(fileName);
|
|
183
|
+
const filePath = this.lockFilePath(fileName, appName);
|
|
181
184
|
await import_promises.default.writeFile(filePath, "lock", "utf8");
|
|
182
185
|
}
|
|
183
|
-
async cleanLockFile(fileName) {
|
|
184
|
-
const filePath = this.lockFilePath(fileName);
|
|
186
|
+
async cleanLockFile(fileName, appName) {
|
|
187
|
+
const filePath = this.lockFilePath(fileName, appName);
|
|
185
188
|
await import_promises.default.unlink(filePath);
|
|
186
189
|
}
|
|
187
190
|
async runDumpTask(options) {
|
|
188
191
|
const backupFileName = _Dumper.generateFileName();
|
|
189
|
-
await this.writeLockFile(backupFileName);
|
|
192
|
+
await this.writeLockFile(backupFileName, options.appName);
|
|
190
193
|
if (import_worker_threads.isMainThread) {
|
|
191
194
|
const promise = this.dump({
|
|
192
195
|
groups: options.groups,
|
|
193
|
-
fileName: backupFileName
|
|
196
|
+
fileName: backupFileName,
|
|
197
|
+
appName: options.appName
|
|
194
198
|
}).finally(() => {
|
|
195
|
-
this.cleanLockFile(backupFileName);
|
|
199
|
+
this.cleanLockFile(backupFileName, options.appName);
|
|
196
200
|
_Dumper.dumpTasks.delete(backupFileName);
|
|
197
201
|
this.app.noticeManager.notify("backup", { msg: "Done" });
|
|
198
202
|
});
|
|
@@ -201,12 +205,13 @@ const _Dumper = class _Dumper extends import_app_migrator.AppMigrator {
|
|
|
201
205
|
try {
|
|
202
206
|
await this.dump({
|
|
203
207
|
groups: options.groups,
|
|
204
|
-
fileName: backupFileName
|
|
208
|
+
fileName: backupFileName,
|
|
209
|
+
appName: options.appName
|
|
205
210
|
});
|
|
206
211
|
} catch (err) {
|
|
207
212
|
throw err;
|
|
208
213
|
} finally {
|
|
209
|
-
this.cleanLockFile(backupFileName);
|
|
214
|
+
this.cleanLockFile(backupFileName, options.appName);
|
|
210
215
|
}
|
|
211
216
|
}
|
|
212
217
|
return backupFileName;
|
|
@@ -235,7 +240,7 @@ const _Dumper = class _Dumper extends import_app_migrator.AppMigrator {
|
|
|
235
240
|
});
|
|
236
241
|
await this.dumpDb(options);
|
|
237
242
|
const backupFileName = options.fileName || _Dumper.generateFileName();
|
|
238
|
-
const filePath = await this.packDumpedDir(backupFileName);
|
|
243
|
+
const filePath = await this.packDumpedDir(backupFileName, options.appName);
|
|
239
244
|
await this.clearWorkDir();
|
|
240
245
|
return filePath;
|
|
241
246
|
}
|
|
@@ -380,8 +385,8 @@ const _Dumper = class _Dumper extends import_app_migrator.AppMigrator {
|
|
|
380
385
|
}
|
|
381
386
|
await import_promises.default.writeFile(import_path.default.resolve(collectionDataDir, "meta"), JSON.stringify(meta), "utf8");
|
|
382
387
|
}
|
|
383
|
-
async packDumpedDir(fileName) {
|
|
384
|
-
const dirname = this.backUpStorageDir();
|
|
388
|
+
async packDumpedDir(fileName, appName) {
|
|
389
|
+
const dirname = this.backUpStorageDir(appName);
|
|
385
390
|
await (0, import_mkdirp.default)(dirname);
|
|
386
391
|
const filePath = import_path.default.resolve(dirname, fileName);
|
|
387
392
|
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;
|
|
@@ -153,11 +154,14 @@ var backup_files_default = {
|
|
|
153
154
|
async download(ctx, next) {
|
|
154
155
|
const { filterByTk } = ctx.action.params;
|
|
155
156
|
const dumper = new import_dumper.Dumper(ctx.app);
|
|
156
|
-
const filePath = dumper.backUpFilePath(filterByTk);
|
|
157
|
+
const filePath = dumper.backUpFilePath(filterByTk, ctx.app.name);
|
|
157
158
|
const fileState = await import_dumper.Dumper.getFileStatus(filePath);
|
|
158
159
|
if (fileState.status !== "ok") {
|
|
159
160
|
throw new Error(`Backup file ${filterByTk} not found`);
|
|
160
161
|
}
|
|
162
|
+
const stats = import_node_fs.default.statSync(filePath);
|
|
163
|
+
const fileSize = stats.size;
|
|
164
|
+
ctx.set("Content-Length", fileSize);
|
|
161
165
|
ctx.attachment(filePath);
|
|
162
166
|
ctx.body = import_node_fs.default.createReadStream(filePath);
|
|
163
167
|
await next();
|
|
@@ -171,7 +175,7 @@ var backup_files_default = {
|
|
|
171
175
|
}
|
|
172
176
|
if (filterByTk) {
|
|
173
177
|
const dumper = new import_dumper.Dumper(ctx.app);
|
|
174
|
-
return dumper.backUpFilePath(filterByTk);
|
|
178
|
+
return dumper.backUpFilePath(filterByTk, ctx.app.name);
|
|
175
179
|
}
|
|
176
180
|
})();
|
|
177
181
|
if (!filePath) {
|
|
@@ -187,7 +191,7 @@ var backup_files_default = {
|
|
|
187
191
|
async destroy(ctx, next) {
|
|
188
192
|
const { filterByTk } = ctx.action.params;
|
|
189
193
|
const dumper = new import_dumper.Dumper(ctx.app);
|
|
190
|
-
const filePath = dumper.backUpFilePath(filterByTk);
|
|
194
|
+
const filePath = dumper.backUpFilePath(filterByTk, ctx.app.name);
|
|
191
195
|
await import_promises.default.unlink(filePath);
|
|
192
196
|
ctx.body = {
|
|
193
197
|
status: "ok"
|
package/dist/server/server.js
CHANGED
|
@@ -46,7 +46,8 @@ class PluginBackupRestoreServer extends import_server.Plugin {
|
|
|
46
46
|
async workerCreateBackUp(data) {
|
|
47
47
|
const dumper = new import_dumper.Dumper(this.app);
|
|
48
48
|
return dumper.runDumpTask({
|
|
49
|
-
groups: new Set(data.dataTypes)
|
|
49
|
+
groups: new Set(data.dataTypes),
|
|
50
|
+
appName: this.app.name
|
|
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.
|
|
4
|
+
"version": "1.0.6",
|
|
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/
|
|
34
|
-
"@tachybase/
|
|
33
|
+
"@tachybase/components": "1.0.6",
|
|
34
|
+
"@tachybase/module-worker-thread": "1.0.6"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"@tachybase/
|
|
38
|
-
"@tachybase/
|
|
39
|
-
"@tachybase/
|
|
40
|
-
"@tachybase/
|
|
41
|
-
"@tachybase/
|
|
42
|
-
"@tachybase/
|
|
37
|
+
"@tachybase/actions": "1.0.6",
|
|
38
|
+
"@tachybase/client": "1.0.6",
|
|
39
|
+
"@tachybase/server": "1.0.6",
|
|
40
|
+
"@tachybase/database": "1.0.6",
|
|
41
|
+
"@tachybase/test": "1.0.6",
|
|
42
|
+
"@tachybase/utils": "1.0.6"
|
|
43
43
|
},
|
|
44
44
|
"description.zh-CN": "备份和还原应用,可用于应用的复制、迁移、升级等场景。",
|
|
45
45
|
"displayName.zh-CN": "应用的备份与还原",
|