@tachybase/plugin-database-clean 1.6.14 → 1.6.16
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
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(p,u){typeof exports=="object"&&typeof module!="undefined"?u(exports,require("@tachybase/client"),require("react/jsx-runtime"),require("react"),require("@ant-design/icons"),require("antd"),require("dayjs"),require("react-router-dom")):typeof define=="function"&&define.amd?define(["exports","@tachybase/client","react/jsx-runtime","react","@ant-design/icons","antd","dayjs","react-router-dom"],u):(p=typeof globalThis!="undefined"?globalThis:p||self,u(p["@tachybase/plugin-database-clean"]={},p["@tachybase/client"],p.jsxRuntime,p.react,p["@ant-design/icons"],p.antd,p.dayjs,p["react-router-dom"]))})(this,function(p,u,e,r,I,a,P,j){"use strict";var ut=Object.defineProperty,ht=Object.defineProperties;var pt=Object.getOwnPropertyDescriptors;var Ee=Object.getOwnPropertySymbols;var ft=Object.prototype.hasOwnProperty,gt=Object.prototype.propertyIsEnumerable;var Ne=(p,u,e)=>u in p?ut(p,u,{enumerable:!0,configurable:!0,writable:!0,value:e}):p[u]=e,v=(p,u)=>{for(var e in u||(u={}))ft.call(u,e)&&Ne(p,e,u[e]);if(Ee)for(var e of Ee(u))gt.call(u,e)&&Ne(p,e,u[e]);return p},A=(p,u)=>ht(p,pt(u));var T=(p,u,e)=>new Promise((r,I)=>{var a=M=>{try{j(e.next(M))}catch(_){I(_)}},P=M=>{try{j(e.throw(M))}catch(_){I(_)}},j=M=>M.done?r(M.value):Promise.resolve(M.value).then(a,P);j((e=e.apply(p,u)).next())});const M="database-clean";function _(){const{i18n:t}=u.useApp();return{t:(w,f={})=>t.t(w,v({ns:[M,"client"],nsMode:"fallback"},f))}}var ne=typeof globalThis!="undefined"?globalThis:typeof window!="undefined"?window:typeof global!="undefined"?global:typeof self!="undefined"?self:{},oe={exports:{}},je=oe.exports,ye;function $e(){return ye||(ye=1,function(t,y){(function(w,f){f()})(je,function(){function w(o,i){return typeof i=="undefined"?i={autoBom:!1}:typeof i!="object"&&(console.warn("Deprecated: Expected third argument to be a object"),i={autoBom:!i}),i.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(o.type)?new Blob(["\uFEFF",o],{type:o.type}):o}function f(o,i,C){var c=new XMLHttpRequest;c.open("GET",o),c.responseType="blob",c.onload=function(){L(c.response,i,C)},c.onerror=function(){console.error("could not download file")},c.send()}function Y(o){var i=new XMLHttpRequest;i.open("HEAD",o,!1);try{i.send()}catch(C){}return 200<=i.status&&299>=i.status}function b(o){try{o.dispatchEvent(new MouseEvent("click"))}catch(C){var i=document.createEvent("MouseEvents");i.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),o.dispatchEvent(i)}}var g=typeof window=="object"&&window.window===window?window:typeof self=="object"&&self.self===self?self:typeof ne=="object"&&ne.global===ne?ne:void 0,W=g.navigator&&/Macintosh/.test(navigator.userAgent)&&/AppleWebKit/.test(navigator.userAgent)&&!/Safari/.test(navigator.userAgent),L=g.saveAs||(typeof window!="object"||window!==g?function(){}:"download"in HTMLAnchorElement.prototype&&!W?function(o,i,C){var c=g.URL||g.webkitURL,k=document.createElement("a");i=i||o.name||"download",k.download=i,k.rel="noopener",typeof o=="string"?(k.href=o,k.origin===location.origin?b(k):Y(k.href)?f(o,i,C):b(k,k.target="_blank")):(k.href=c.createObjectURL(o),setTimeout(function(){c.revokeObjectURL(k.href)},4e4),setTimeout(function(){b(k)},0))}:"msSaveOrOpenBlob"in navigator?function(o,i,C){if(i=i||o.name||"download",typeof o!="string")navigator.msSaveOrOpenBlob(w(o,C),i);else if(Y(o))f(o,i,C);else{var c=document.createElement("a");c.href=o,c.target="_blank",setTimeout(function(){b(c)})}}:function(o,i,C,c){if(c=c||open("","_blank"),c&&(c.document.title=c.document.body.innerText="downloading..."),typeof o=="string")return f(o,i,C);var k=o.type==="application/octet-stream",K=/constructor/i.test(g.HTMLElement)||g.safari,h=/CriOS\/[\d]+/.test(navigator.userAgent);if((h||k&&K||W)&&typeof FileReader!="undefined"){var D=new FileReader;D.onloadend=function(){var B=D.result;B=h?B:B.replace(/^data:[^;]*;/,"data:attachment/file;"),c?c.location.href=B:location=B,c=null},D.readAsDataURL(o)}else{var O=g.URL||g.webkitURL,$=O.createObjectURL(o);c?c.location=$:location.href=$,c=null,setTimeout(function(){O.revokeObjectURL($)},4e4)}});g.saveAs=L.saveAs=L,t.exports=L})}(oe)),oe.exports}var Ve=$e();function J(t){const y={};if(t.createdAt&&t.createdAt[0]&&t.createdAt[1]){const w=P(t.createdAt[0]),f=P(t.createdAt[1]);w.isValid()&&f.isValid()&&(y.createdAt={$gte:w.startOf("day").toISOString(),$lte:f.endOf("day").toISOString()})}if(t.updatedAt&&t.updatedAt[0]&&t.updatedAt[1]){const w=P(t.updatedAt[0]),f=P(t.updatedAt[1]);w.isValid()&&f.isValid()&&(y.updatedAt={$gte:w.startOf("day").toISOString(),$lte:f.endOf("day").toISOString()})}return t.idRange&&(t.idRange[0]!==null||t.idRange[1]!==null)&&(y.id={},t.idRange[0]!==null&&(y.id.$gte=t.idRange[0]),t.idRange[1]!==null&&(y.id.$lte=t.idRange[1])),y}const qe=()=>{var Te,Be,me,Me,xe,Ie,Le,De,Oe,ze;const{t}=_(),y=u.useAPIClient(),w=j.useNavigate(),f=j.useLocation(),b=j.useParams().tableName||f.pathname.split("/").pop(),{message:g,modal:W,notification:L}=a.App.useApp(),[o,i]=r.useState(null),[C,c]=r.useState([]),[k,K]=r.useState(!1),[h,D]=r.useState(!1),[O,$]=r.useState(!1),[B,be]=r.useState(!1),[de,yt]=r.useState(!1),[Se,ue]=r.useState(null),[Ge,Q]=r.useState(!1),[He,Z]=r.useState(!1),[Xe,G]=r.useState(!1),[Je,le]=r.useState(!1),[Ye,he]=r.useState(null),[E,Qe]=r.useState({count:0,minId:null,maxId:null}),[V,we]=r.useState("none"),[se,Ze]=r.useState(10),[re,Re]=r.useState(1e4),[z,R]=r.useState(null),[ee,pe]=r.useState({current:1,pageSize:20,total:0}),[x,te]=r.useState({}),d=h||O||B||de,ae=r.useMemo(()=>y.resource("databaseClean"),[y]);r.useEffect(()=>{b&&Ce()},[b]),r.useEffect(()=>{b&&o&&ke()},[b,o,ee.current,ee.pageSize,x]);const Ce=()=>T(null,null,function*(){var n;if(b)try{const s=yield ae.get({filterByTk:b});i((n=s.data)==null?void 0:n.data)}catch(s){g.error(s.message||t("Failed to load table info")),w("/_admin/system-services/database-clean")}}),ke=()=>T(null,null,function*(){var n,s;if(b){K(!0);try{const l=J(x),m=yield ae.data({filterByTk:b,page:ee.current,pageSize:ee.pageSize,filter:Object.keys(l).length>0?l:void 0}),{data:q,meta:S}=m.data;c(Array.isArray(q)?q:[]),pe(H=>A(v({},H),{total:(S==null?void 0:S.count)||0})),Qe({count:(S==null?void 0:S.count)||0,minId:(n=S==null?void 0:S.filteredMinId)!=null?n:null,maxId:(s=S==null?void 0:S.filteredMaxId)!=null?s:null})}catch(l){g.error(l.message||t("Failed to load table data"))}finally{K(!1)}}}),ve=()=>T(null,null,function*(){yield Promise.all([Ce(),ke()])}),et=()=>T(null,null,function*(){var n,s;if(b){D(!0);try{const l=J(x),q=(s=(n=(yield ae.backup({values:{collectionName:b,filter:Object.keys(l).length>0?l:void 0}})).data)==null?void 0:n.data)==null?void 0:s.fileName;return ue(q),g.success(t("Backup Success")),q}catch(l){return g.error(l.message||t("Backup Failed")),null}finally{D(!1)}}}),tt=n=>T(null,null,function*(){const s=n||Se;if(s){$(!0);try{const l=yield y.request({url:"databaseClean:download",method:"get",params:{filterByTk:s},responseType:"blob"}),m=new Blob([l.data]);return Ve.saveAs(m,s),g.success(t("Download")+" "+t("Success")),!0}catch(l){return g.error(l.message||t("Download")+" "+t("Failed")),!1}finally{$(!1)}}}),at=()=>{Q(!0)},nt=()=>T(null,null,function*(){const n=yield et();n&&(ue(n),he(J(x)),Q(!1),Z(!0))}),ot=()=>T(null,null,function*(){(yield tt(Se))&&(Z(!1),G(!0))}),lt=()=>{Z(!1),G(!0)},st=()=>T(null,null,function*(){he(J(x)),Q(!1),G(!0)}),rt=()=>{G(!1),le(!0)},Ae=n=>T(null,null,function*(){le(!1),yield it(n)}),it=(n=!1)=>T(null,null,function*(){var s,l,m,q;if(b){be(!0),R(null);try{const S=Ye||J(x);let H=0;const{minId:ie,maxId:fe,count:Fe}=E;let U=[];if(V!=="none"&&ie!==null&&fe!==null&&Fe>0){const F=fe-ie+1;let N;V==="count"?N=se:N=Math.ceil(Fe/re),N=Math.max(1,N);const ce=Math.ceil(F/N);for(let X=0;X<N;X++){const Pe=ie+X*ce,ge=Math.min(ie+(X+1)*ce-1,fe);U.push({minId:Pe,maxId:ge})}}if(U.length>1){R({current:0,total:U.length,deletedCount:0});for(let F=0;F<U.length;F++){const N=U[F],ce=A(v({},S),{id:A(v({},S.id),{$gte:N.minId,$lte:N.maxId})}),X=F===U.length-1,ge=((l=(s=(yield ae.clean({values:{collectionName:b,filter:ce,vacuumFull:X&&n}})).data)==null?void 0:s.data)==null?void 0:l.deletedCount)||0;H+=ge,R({current:F+1,total:U.length,deletedCount:H})}}else H=((q=(m=(yield ae.clean({values:{collectionName:b,filter:Object.keys(S).length>0?S:void 0,vacuumFull:n}})).data)==null?void 0:m.data)==null?void 0:q.deletedCount)||0;g.success(t("Clean Success")+` (${H} ${t("records deleted")})`),n&&g.success(t("Space released successfully")),ue(null),he(null),R(null),we("none"),te({}),pe(F=>A(v({},F),{current:1})),yield ve()}catch(S){g.error(S.message||t("Clean Failed"))}finally{be(!1),R(null)}}}),ct=n=>{pe(s=>A(v({},s),{current:n.current,pageSize:n.pageSize}))},dt=r.useMemo(()=>{if(!C.length)return[];const n=C[0];return Object.keys(n).map(s=>({title:s,dataIndex:s,key:s,render:l=>l instanceof Date||typeof l=="string"&&l.match(/^\d{4}-\d{2}-\d{2}/)?e.jsx(u.DatePicker.ReadPretty,{value:P(l),showTime:!0}):typeof l=="object"&&l!==null?e.jsx("pre",{style:{margin:0},children:JSON.stringify(l,null,2)}):String(l)}))},[C]);return o?e.jsx("div",{children:e.jsx(a.Card,{bordered:!1,children:e.jsxs(a.Space,{direction:"vertical",style:{width:"100%"},size:"large",children:[e.jsxs("div",{children:[e.jsx("h2",{children:o.name}),e.jsxs(a.Space,{children:[e.jsxs("span",{children:[t("Origin"),": ",o.origin]}),e.jsx("span",{children:"|"}),e.jsxs("span",{children:[t("Size"),": ",Ue(o.size)]}),e.jsx("span",{children:"|"}),e.jsxs("span",{children:[t("Row Count"),": ",o.rowCount.toLocaleString()]})]})]}),e.jsx(a.Card,{size:"small",title:t("Filter"),children:e.jsxs(a.Space,{direction:"vertical",style:{width:"100%"},children:[o.hasCreatedAt&&e.jsxs("div",{children:[e.jsxs("label",{children:[t("Created At Range"),": "]}),e.jsx(u.DatePicker.RangePicker,{value:x.createdAt,onChange:n=>{te(s=>A(v({},s),{createdAt:n}))},showTime:!0,style:{width:400}})]}),o.hasUpdatedAt&&e.jsxs("div",{children:[e.jsxs("label",{children:[t("Updated At Range"),": "]}),e.jsx(u.DatePicker.RangePicker,{value:x.updatedAt,onChange:n=>{te(s=>A(v({},s),{updatedAt:n}))},showTime:!0,style:{width:400}})]}),e.jsxs("div",{children:[e.jsxs("label",{children:[t("ID Range"),": "]}),e.jsxs(a.Space,{children:[e.jsx(a.InputNumber,{placeholder:t("Min ID"),value:(Te=x.idRange)==null?void 0:Te[0],onChange:n=>{te(s=>{var m;const l=(m=s.idRange)==null?void 0:m[1];return n!==null&&l!==null&&n>l?A(v({},s),{idRange:[n,n]}):A(v({},s),{idRange:[n,l!=null?l:null]})})},style:{width:150},min:(Be=o.minId)!=null?Be:0,max:(xe=(Me=(me=x.idRange)==null?void 0:me[1])!=null?Me:o.maxId)!=null?xe:void 0}),e.jsx("span",{children:"-"}),e.jsx(a.InputNumber,{placeholder:t("Max ID"),value:(Ie=x.idRange)==null?void 0:Ie[1],onChange:n=>{te(s=>{var m;const l=(m=s.idRange)==null?void 0:m[0];return n!==null&&l!==null&&n<l?A(v({},s),{idRange:[n,n]}):A(v({},s),{idRange:[l!=null?l:null,n]})})},style:{width:150},min:(Oe=(De=(Le=x.idRange)==null?void 0:Le[0])!=null?De:o.minId)!=null?Oe:0,max:(ze=o.maxId)!=null?ze:void 0})]})]}),!o.hasCreatedAt&&!o.hasUpdatedAt&&e.jsx(a.Alert,{message:t("No time fields, use ID range filter"),type:"info",showIcon:!0})]})}),e.jsxs(a.Space,{children:[e.jsx(a.Button,{onClick:ve,icon:e.jsx(I.ReloadOutlined,{}),disabled:d,children:t("Refresh")}),e.jsx(a.Button,{danger:!0,icon:e.jsx(I.DeleteOutlined,{}),loading:B,disabled:d,onClick:at,children:B?z?`(${z.current}/${z.total}) ${t("Cleaning...")}`:t("Cleaning..."):t("Clean")})]}),e.jsx(a.Modal,{title:e.jsxs(a.Space,{children:[e.jsx(I.WarningOutlined,{style:{color:"#faad14"}}),t("Confirm Clean")]}),open:Ge,onCancel:()=>!d&&Q(!1),closable:!d,maskClosable:!d,keyboard:!d,footer:null,width:500,children:e.jsxs(a.Space,{direction:"vertical",style:{width:"100%"},size:"middle",children:[e.jsx(a.Alert,{message:t("This action cannot be undone"),description:t("Are you sure you want to clean the filtered data?"),type:"warning",showIcon:!0}),e.jsx(a.Typography.Text,{type:"secondary",children:t("It is recommended to backup before cleaning. You can also clean directly without backup.")}),e.jsxs(a.Space,{style:{width:"100%",justifyContent:"flex-end"},children:[e.jsx(a.Button,{onClick:()=>Q(!1),disabled:d,children:t("Cancel")}),e.jsx(a.Button,{icon:e.jsx(I.SaveOutlined,{}),loading:h,disabled:d,onClick:nt,children:t("Backup then Clean")}),e.jsx(a.Button,{danger:!0,icon:e.jsx(I.DeleteOutlined,{}),disabled:d,onClick:st,children:t("Clean directly")})]})]})}),e.jsx(a.Modal,{title:t("Backup Complete"),open:He,onCancel:()=>!d&&Z(!1),closable:!d,maskClosable:!d,keyboard:!d,footer:null,width:450,children:e.jsxs(a.Space,{direction:"vertical",style:{width:"100%"},size:"middle",children:[e.jsx(a.Typography.Text,{children:t("Do you want to download the backup file before cleaning?")}),e.jsxs(a.Space,{style:{width:"100%",justifyContent:"flex-end"},children:[e.jsx(a.Button,{onClick:()=>Z(!1),disabled:d,children:t("Cancel")}),e.jsx(a.Button,{onClick:lt,disabled:d,children:t("Skip download")}),e.jsx(a.Button,{type:"primary",icon:e.jsx(I.DownloadOutlined,{}),loading:O,disabled:d&&!O,onClick:ot,children:t("Download and continue")})]})]})}),e.jsx(a.Modal,{title:t("Batch Settings"),open:Xe,onCancel:()=>!d&&G(!1),closable:!d,maskClosable:!d,keyboard:!d,footer:null,width:550,children:e.jsxs(a.Space,{direction:"vertical",style:{width:"100%"},size:"middle",children:[e.jsxs(a.Typography.Text,{children:[t("Total records to clean"),": ",e.jsx("strong",{children:E.count.toLocaleString()})]}),e.jsx(a.Radio.Group,{value:V,onChange:n=>we(n.target.value),style:{width:"100%"},children:e.jsxs(a.Space,{direction:"vertical",style:{width:"100%"},children:[e.jsx(a.Radio,{value:"none",children:t("No batching")}),e.jsx(a.Radio,{value:"count",children:e.jsxs(a.Space,{children:[t("Split into"),e.jsx(a.InputNumber,{min:2,max:1e3,value:se,onChange:n=>n&&Ze(n),changeOnWheel:!0,disabled:V!=="count",style:{width:80}}),t("batches")]})}),e.jsx(a.Radio,{value:"size",children:e.jsxs(a.Space,{children:[t("Each batch"),e.jsx(a.InputNumber,{min:1e3,max:1e6,step:1e3,value:re,onChange:n=>n&&Re(n),changeOnWheel:!0,disabled:V!=="size",style:{width:100}}),t("records")]})})]})}),e.jsx(a.Alert,{type:"info",showIcon:!0,message:V==="none"?E.count>5e4?t("Will clean {{count}} records at once. Large data volume may take a long time.",{count:E.count.toLocaleString()}):t("Will clean {{count}} records at once.",{count:E.count.toLocaleString()}):V==="count"?t("Will clean {{count}} records in {{batches}} batches, {{perBatch}} records per batch.",{count:E.count.toLocaleString(),batches:se,perBatch:Math.ceil(E.count/se).toLocaleString()}):t("Will clean {{count}} records in {{batches}} batches, {{perBatch}} records per batch.",{count:E.count.toLocaleString(),batches:Math.ceil(E.count/re),perBatch:re.toLocaleString()})}),e.jsxs(a.Space,{style:{width:"100%",justifyContent:"flex-end"},children:[e.jsx(a.Button,{onClick:()=>G(!1),disabled:d,children:t("Cancel")}),e.jsx(a.Button,{type:"primary",onClick:rt,disabled:d,children:t("Next")})]})]})}),e.jsx(a.Modal,{title:e.jsxs(a.Space,{children:[e.jsx(I.WarningOutlined,{style:{color:"#faad14"}}),t("Release disk space")]}),open:Je,onCancel:()=>!d&&le(!1),closable:!d,maskClosable:!d,keyboard:!d,footer:null,width:550,children:e.jsxs(a.Space,{direction:"vertical",style:{width:"100%"},size:"middle",children:[z&&e.jsxs("div",{children:[e.jsxs(a.Typography.Text,{children:[t("Cleaning progress"),": ",z.current," / ",z.total," ",t("batches")]}),e.jsx(a.Progress,{percent:Math.round(z.current/z.total*100),status:"active"}),e.jsxs(a.Typography.Text,{type:"secondary",children:[t("Deleted"),": ",z.deletedCount.toLocaleString()," ",t("records")]})]}),!z&&e.jsxs(e.Fragment,{children:[e.jsx(a.Typography.Text,{children:t("Do you want to release disk space after cleaning?")}),e.jsx(a.Alert,{message:t("Release space warning"),description:e.jsxs(e.Fragment,{children:[t("Releasing space will lock the table and may take a long time for large tables. Other operations on this table will be blocked during the process."),V!=="none"&&e.jsxs(e.Fragment,{children:[e.jsx("br",{}),e.jsx("br",{}),t("Space will be released only after the last batch is completed.")]})]}),type:"warning",showIcon:!0}),e.jsxs(a.Space,{style:{width:"100%",justifyContent:"flex-end"},children:[e.jsx(a.Button,{onClick:()=>le(!1),disabled:d,children:t("Cancel")}),e.jsx(a.Button,{onClick:()=>Ae(!1),loading:B,disabled:d&&!B,children:t("Clean only")}),e.jsx(a.Button,{danger:!0,onClick:()=>Ae(!0),loading:B||de,disabled:d&&!(B||de),children:t("Clean and release space")})]})]})]})}),e.jsx(a.Table,{dataSource:C,loading:k,columns:dt,rowKey:(n,s)=>n.id||s,pagination:A(v({},ee),{showSizeChanger:!0,showTotal:n=>t("Total: {{total}}",{total:n})}),onChange:ct,scroll:{x:"max-content"}})]})})}):e.jsx("div",{style:{textAlign:"center",padding:50},children:e.jsx(a.Spin,{size:"large"})})};function Ue(t){if(t===0)return"0 B";const y=1024,w=["B","KB","MB","GB","TB"],f=Math.floor(Math.log(t)/Math.log(y));return Math.round(t/Math.pow(y,f)*100)/100+" "+w[f]}function _e(t){if(t===0)return"0 B";const y=1024,w=["B","KB","MB","GB","TB"],f=Math.floor(Math.log(t)/Math.log(y));return Math.round(t/Math.pow(y,f)*100)/100+" "+w[f]}const We=()=>{const{t}=_(),y=u.useAPIClient(),w=j.useNavigate(),{message:f}=a.App.useApp(),[Y,b]=r.useState([]),[g,W]=r.useState(!1),[L,o]=r.useState({current:1,pageSize:20,total:0}),i=r.useMemo(()=>y.resource("databaseClean"),[y]),C=r.useCallback(()=>T(null,null,function*(){yield c()}),[]);r.useEffect(()=>{c()},[L.current,L.pageSize]);const c=()=>T(null,null,function*(){W(!0);try{const h=yield i.list({params:{page:L.current,pageSize:L.pageSize}}),{data:D,meta:O}=h.data;b(Array.isArray(D)?D:[]),o($=>A(v({},$),{total:(O==null?void 0:O.count)||0}))}catch(h){f.error(h.message||t("Failed to load table list"))}finally{W(!1)}}),k=h=>{o(D=>A(v({},D),{current:h.current,pageSize:h.pageSize}))},K=[{title:t("Table Name"),dataIndex:"name",key:"name",render:h=>e.jsx("a",{onClick:()=>{w(`/_admin/system-services/database-clean/${h}`)},children:h})},{title:t("Origin"),dataIndex:"origin",key:"origin"},{title:t("Size"),dataIndex:"size",key:"size",render:h=>_e(h)},{title:t("Row Count"),dataIndex:"rowCount",key:"rowCount",render:h=>h.toLocaleString()},{title:t("Created At"),dataIndex:"createdAt",key:"createdAt",render:h=>h?e.jsx(u.DatePicker.ReadPretty,{value:P(h),showTime:!0}):"-"},{title:t("Updated At"),dataIndex:"updatedAt",key:"updatedAt",render:h=>h?e.jsx(u.DatePicker.ReadPretty,{value:P(h),showTime:!0}):"-"}];return e.jsx("div",{children:e.jsxs(a.Card,{bordered:!1,children:[e.jsx(a.Space,{style:{float:"right",marginBottom:16},children:e.jsx(a.Button,{onClick:C,icon:e.jsx(I.ReloadOutlined,{}),children:t("Refresh")})}),e.jsx(a.Table,{dataSource:Y,loading:g,columns:K,rowKey:"name",pagination:A(v({},L),{showSizeChanger:!0,showTotal:h=>t("Total: {{total}}",{total:h})}),onChange:k})]})})};class Ke extends u.Plugin{afterAdd(){return T(this,null,function*(){})}beforeLoad(){return T(this,null,function*(){})}load(){return T(this,null,function*(){this.app.systemSettingsManager.add("system-services."+M,{title:this.t("Database Clean"),icon:"DatabaseOutlined",Component:We,aclSnippet:"pm.database-clean.*",sort:-50}),this.app.systemSettingsManager.add("system-services."+M+"/:tableName",{title:this.t("Table Detail"),Component:qe,groupKey:"system-services."+M,aclSnippet:"pm.database-clean.*"})})}}p.default=Ke,Object.defineProperties(p,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
|
1
|
+
(function(p,c){typeof exports=="object"&&typeof module!="undefined"?c(exports,require("@tachybase/client"),require("react/jsx-runtime"),require("react"),require("@ant-design/icons"),require("antd"),require("dayjs"),require("react-router-dom")):typeof define=="function"&&define.amd?define(["exports","@tachybase/client","react/jsx-runtime","react","@ant-design/icons","antd","dayjs","react-router-dom"],c):(p=typeof globalThis!="undefined"?globalThis:p||self,c(p["@tachybase/plugin-database-clean"]={},p["@tachybase/client"],p.jsxRuntime,p.react,p["@ant-design/icons"],p.antd,p.dayjs,p["react-router-dom"]))})(this,function(p,c,e,r,I,a,P,j){"use strict";var ut=Object.defineProperty,ht=Object.defineProperties;var pt=Object.getOwnPropertyDescriptors;var Ee=Object.getOwnPropertySymbols;var ft=Object.prototype.hasOwnProperty,gt=Object.prototype.propertyIsEnumerable;var Ne=(p,c,e)=>c in p?ut(p,c,{enumerable:!0,configurable:!0,writable:!0,value:e}):p[c]=e,v=(p,c)=>{for(var e in c||(c={}))ft.call(c,e)&&Ne(p,e,c[e]);if(Ee)for(var e of Ee(c))gt.call(c,e)&&Ne(p,e,c[e]);return p},A=(p,c)=>ht(p,pt(c));var T=(p,c,e)=>new Promise((r,I)=>{var a=M=>{try{j(e.next(M))}catch(_){I(_)}},P=M=>{try{j(e.throw(M))}catch(_){I(_)}},j=M=>M.done?r(M.value):Promise.resolve(M.value).then(a,P);j((e=e.apply(p,c)).next())});const M="database-clean";function _(){const{i18n:t}=c.useApp();return{t:(w,f={})=>t.t(w,v({ns:[M,"client"],nsMode:"fallback"},f))}}var ne=typeof globalThis!="undefined"?globalThis:typeof window!="undefined"?window:typeof global!="undefined"?global:typeof self!="undefined"?self:{},oe={exports:{}},je=oe.exports,ye;function $e(){return ye||(ye=1,function(t,y){(function(w,f){f()})(je,function(){function w(o,i){return typeof i=="undefined"?i={autoBom:!1}:typeof i!="object"&&(console.warn("Deprecated: Expected third argument to be a object"),i={autoBom:!i}),i.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(o.type)?new Blob(["\uFEFF",o],{type:o.type}):o}function f(o,i,C){var d=new XMLHttpRequest;d.open("GET",o),d.responseType="blob",d.onload=function(){L(d.response,i,C)},d.onerror=function(){console.error("could not download file")},d.send()}function X(o){var i=new XMLHttpRequest;i.open("HEAD",o,!1);try{i.send()}catch(C){}return 200<=i.status&&299>=i.status}function b(o){try{o.dispatchEvent(new MouseEvent("click"))}catch(C){var i=document.createEvent("MouseEvents");i.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),o.dispatchEvent(i)}}var g=typeof window=="object"&&window.window===window?window:typeof self=="object"&&self.self===self?self:typeof ne=="object"&&ne.global===ne?ne:void 0,W=g.navigator&&/Macintosh/.test(navigator.userAgent)&&/AppleWebKit/.test(navigator.userAgent)&&!/Safari/.test(navigator.userAgent),L=g.saveAs||(typeof window!="object"||window!==g?function(){}:"download"in HTMLAnchorElement.prototype&&!W?function(o,i,C){var d=g.URL||g.webkitURL,k=document.createElement("a");i=i||o.name||"download",k.download=i,k.rel="noopener",typeof o=="string"?(k.href=o,k.origin===location.origin?b(k):X(k.href)?f(o,i,C):b(k,k.target="_blank")):(k.href=d.createObjectURL(o),setTimeout(function(){d.revokeObjectURL(k.href)},4e4),setTimeout(function(){b(k)},0))}:"msSaveOrOpenBlob"in navigator?function(o,i,C){if(i=i||o.name||"download",typeof o!="string")navigator.msSaveOrOpenBlob(w(o,C),i);else if(X(o))f(o,i,C);else{var d=document.createElement("a");d.href=o,d.target="_blank",setTimeout(function(){b(d)})}}:function(o,i,C,d){if(d=d||open("","_blank"),d&&(d.document.title=d.document.body.innerText="downloading..."),typeof o=="string")return f(o,i,C);var k=o.type==="application/octet-stream",K=/constructor/i.test(g.HTMLElement)||g.safari,h=/CriOS\/[\d]+/.test(navigator.userAgent);if((h||k&&K||W)&&typeof FileReader!="undefined"){var D=new FileReader;D.onloadend=function(){var m=D.result;m=h?m:m.replace(/^data:[^;]*;/,"data:attachment/file;"),d?d.location.href=m:location=m,d=null},D.readAsDataURL(o)}else{var O=g.URL||g.webkitURL,$=O.createObjectURL(o);d?d.location=$:location.href=$,d=null,setTimeout(function(){O.revokeObjectURL($)},4e4)}});g.saveAs=L.saveAs=L,t.exports=L})}(oe)),oe.exports}var Ve=$e();function Q(t){const y={};if(t.createdAt&&t.createdAt[0]&&t.createdAt[1]){const w=P(t.createdAt[0]),f=P(t.createdAt[1]);w.isValid()&&f.isValid()&&(y.createdAt={$gte:w.startOf("day").toISOString(),$lte:f.endOf("day").toISOString()})}if(t.updatedAt&&t.updatedAt[0]&&t.updatedAt[1]){const w=P(t.updatedAt[0]),f=P(t.updatedAt[1]);w.isValid()&&f.isValid()&&(y.updatedAt={$gte:w.startOf("day").toISOString(),$lte:f.endOf("day").toISOString()})}return t.idRange&&(t.idRange[0]!==null||t.idRange[1]!==null)&&(y.id={},t.idRange[0]!==null&&(y.id.$gte=t.idRange[0]),t.idRange[1]!==null&&(y.id.$lte=t.idRange[1])),y}const qe=()=>{var Te,me,Be,Me,xe,Ie,Le,De,Oe,ze;const{t}=_(),y=c.useAPIClient(),w=j.useNavigate(),f=j.useLocation(),b=j.useParams().tableName||f.pathname.split("/").pop(),{message:g,modal:W,notification:L}=a.App.useApp(),[o,i]=r.useState(null),[C,d]=r.useState([]),[k,K]=r.useState(!1),[h,D]=r.useState(!1),[O,$]=r.useState(!1),[m,be]=r.useState(!1),[de,yt]=r.useState(!1),[Se,ue]=r.useState(null),[Ge,Y]=r.useState(!1),[He,Z]=r.useState(!1),[Je,G]=r.useState(!1),[Qe,le]=r.useState(!1),[Xe,he]=r.useState(null),[E,Ye]=r.useState({count:0,minId:null,maxId:null}),[V,we]=r.useState("none"),[se,Ze]=r.useState(10),[re,Re]=r.useState(1e4),[z,R]=r.useState(null),[ee,pe]=r.useState({current:1,pageSize:20,total:0}),[x,te]=r.useState({}),u=h||O||m||de,ae=r.useMemo(()=>y.resource("databaseClean"),[y]);r.useEffect(()=>{b&&Ce()},[b]),r.useEffect(()=>{b&&o&&ke()},[b,o,ee.current,ee.pageSize,x]);const Ce=()=>T(null,null,function*(){var n;if(b)try{const s=yield ae.get({filterByTk:b});i((n=s.data)==null?void 0:n.data)}catch(s){g.error(s.message||t("Failed to load table info")),w("/_admin/system-services/database-clean")}}),ke=()=>T(null,null,function*(){var n,s;if(b){K(!0);try{const l=Q(x),B=yield ae.data({filterByTk:b,page:ee.current,pageSize:ee.pageSize,filter:Object.keys(l).length>0?l:void 0}),{data:q,meta:S}=B.data;d(Array.isArray(q)?q:[]),pe(H=>A(v({},H),{total:(S==null?void 0:S.count)||0})),Ye({count:(S==null?void 0:S.count)||0,minId:(n=S==null?void 0:S.filteredMinId)!=null?n:null,maxId:(s=S==null?void 0:S.filteredMaxId)!=null?s:null})}catch(l){g.error(l.message||t("Failed to load table data"))}finally{K(!1)}}}),ve=()=>T(null,null,function*(){yield Promise.all([Ce(),ke()])}),et=()=>T(null,null,function*(){var n,s;if(b){D(!0);try{const l=Q(x),q=(s=(n=(yield ae.backup({values:{collectionName:b,filter:Object.keys(l).length>0?l:void 0}})).data)==null?void 0:n.data)==null?void 0:s.fileName;return ue(q),g.success(t("Backup Success")),q}catch(l){return g.error(l.message||t("Backup Failed")),null}finally{D(!1)}}}),tt=n=>T(null,null,function*(){const s=n||Se;if(s){$(!0);try{const l=yield y.request({url:"databaseClean:download",method:"get",params:{filterByTk:s},responseType:"blob"}),B=new Blob([l.data]);return Ve.saveAs(B,s),g.success(t("Download")+" "+t("Success")),!0}catch(l){return g.error(l.message||t("Download")+" "+t("Failed")),!1}finally{$(!1)}}}),at=()=>{Y(!0)},nt=()=>T(null,null,function*(){const n=yield et();n&&(ue(n),he(Q(x)),Y(!1),Z(!0))}),ot=()=>T(null,null,function*(){(yield tt(Se))&&(Z(!1),G(!0))}),lt=()=>{Z(!1),G(!0)},st=()=>T(null,null,function*(){he(Q(x)),Y(!1),G(!0)}),rt=()=>{G(!1),le(!0)},Ae=n=>T(null,null,function*(){le(!1),yield it(n)}),it=(n=!1)=>T(null,null,function*(){var s,l,B,q;if(b){be(!0),R(null);try{const S=Xe||Q(x);let H=0;const{minId:ie,maxId:fe,count:Fe}=E;let U=[];if(V!=="none"&&ie!==null&&fe!==null&&Fe>0){const F=fe-ie+1;let N;V==="count"?N=se:N=Math.ceil(Fe/re),N=Math.max(1,N);const ce=Math.ceil(F/N);for(let J=0;J<N;J++){const Pe=ie+J*ce,ge=Math.min(ie+(J+1)*ce-1,fe);U.push({minId:Pe,maxId:ge})}}if(U.length>1){R({current:0,total:U.length,deletedCount:0});for(let F=0;F<U.length;F++){const N=U[F],ce=A(v({},S),{id:A(v({},S.id),{$gte:N.minId,$lte:N.maxId})}),J=F===U.length-1,ge=((l=(s=(yield ae.clean({values:{collectionName:b,filter:ce,vacuumFull:J&&n}})).data)==null?void 0:s.data)==null?void 0:l.deletedCount)||0;H+=ge,R({current:F+1,total:U.length,deletedCount:H})}}else H=((q=(B=(yield ae.clean({values:{collectionName:b,filter:Object.keys(S).length>0?S:void 0,vacuumFull:n}})).data)==null?void 0:B.data)==null?void 0:q.deletedCount)||0;g.success(t("Clean Success")+` (${H} ${t("records deleted")})`),n&&g.success(t("Space released successfully")),ue(null),he(null),R(null),we("none"),te({}),pe(F=>A(v({},F),{current:1})),yield ve()}catch(S){g.error(S.message||t("Clean Failed"))}finally{be(!1),R(null)}}}),ct=n=>{pe(s=>A(v({},s),{current:n.current,pageSize:n.pageSize}))},dt=r.useMemo(()=>{if(!C.length)return[];const n=C[0];return Object.keys(n).map(s=>({title:s,dataIndex:s,key:s,render:l=>l instanceof Date||typeof l=="string"&&l.match(/^\d{4}-\d{2}-\d{2}/)?e.jsx(c.DatePicker.ReadPretty,{value:P(l),showTime:!0}):typeof l=="object"&&l!==null?e.jsx("pre",{style:{margin:0},children:JSON.stringify(l,null,2)}):String(l)}))},[C]);return o?e.jsx("div",{children:e.jsx(a.Card,{bordered:!1,children:e.jsxs(a.Space,{direction:"vertical",style:{width:"100%"},size:"large",children:[e.jsxs("div",{children:[e.jsx("h2",{children:o.name}),e.jsxs(a.Space,{children:[e.jsxs("span",{children:[t("Origin"),": ",o.origin]}),e.jsx("span",{children:"|"}),e.jsxs("span",{children:[t("Size"),": ",Ue(o.size)]}),e.jsx("span",{children:"|"}),e.jsxs("span",{children:[t("Row Count"),": ",o.rowCount.toLocaleString()]})]})]}),e.jsx(a.Card,{size:"small",title:t("Filter"),children:e.jsxs(a.Space,{direction:"vertical",style:{width:"100%"},children:[o.hasCreatedAt&&e.jsxs("div",{children:[e.jsxs("label",{children:[t("Created At Range"),": "]}),e.jsx(c.DatePicker.RangePicker,{value:x.createdAt,onChange:n=>{te(s=>A(v({},s),{createdAt:n}))},showTime:!0,style:{width:400}})]}),o.hasUpdatedAt&&e.jsxs("div",{children:[e.jsxs("label",{children:[t("Updated At Range"),": "]}),e.jsx(c.DatePicker.RangePicker,{value:x.updatedAt,onChange:n=>{te(s=>A(v({},s),{updatedAt:n}))},showTime:!0,style:{width:400}})]}),e.jsxs("div",{children:[e.jsxs("label",{children:[t("ID Range"),": "]}),e.jsxs(a.Space,{children:[e.jsx(a.InputNumber,{placeholder:t("Min ID"),value:(Te=x.idRange)==null?void 0:Te[0],onChange:n=>{te(s=>{var B;const l=(B=s.idRange)==null?void 0:B[1];return n!==null&&l!==null&&n>l?A(v({},s),{idRange:[n,n]}):A(v({},s),{idRange:[n,l!=null?l:null]})})},style:{width:150},min:(me=o.minId)!=null?me:0,max:(xe=(Me=(Be=x.idRange)==null?void 0:Be[1])!=null?Me:o.maxId)!=null?xe:void 0}),e.jsx("span",{children:"-"}),e.jsx(a.InputNumber,{placeholder:t("Max ID"),value:(Ie=x.idRange)==null?void 0:Ie[1],onChange:n=>{te(s=>{var B;const l=(B=s.idRange)==null?void 0:B[0];return n!==null&&l!==null&&n<l?A(v({},s),{idRange:[n,n]}):A(v({},s),{idRange:[l!=null?l:null,n]})})},style:{width:150},min:(Oe=(De=(Le=x.idRange)==null?void 0:Le[0])!=null?De:o.minId)!=null?Oe:0,max:(ze=o.maxId)!=null?ze:void 0})]})]}),!o.hasCreatedAt&&!o.hasUpdatedAt&&e.jsx(a.Alert,{message:t("No time fields, use ID range filter"),type:"info",showIcon:!0})]})}),e.jsxs(a.Space,{children:[e.jsx(a.Button,{onClick:ve,icon:e.jsx(I.ReloadOutlined,{}),disabled:u,children:t("Refresh")}),e.jsx(a.Button,{danger:!0,icon:e.jsx(I.DeleteOutlined,{}),loading:m,disabled:u,onClick:at,children:m?z?`(${z.current}/${z.total}) ${t("Cleaning...")}`:t("Cleaning..."):t("Clean")})]}),e.jsx(a.Modal,{title:e.jsxs(a.Space,{children:[e.jsx(I.WarningOutlined,{style:{color:"#faad14"}}),t("Confirm Clean")]}),open:Ge,onCancel:()=>!u&&Y(!1),closable:!u,maskClosable:!u,keyboard:!u,footer:null,width:500,children:e.jsxs(a.Space,{direction:"vertical",style:{width:"100%"},size:"middle",children:[e.jsx(a.Alert,{message:t("This action cannot be undone"),description:t("Are you sure you want to clean the filtered data?"),type:"warning",showIcon:!0}),e.jsx(a.Typography.Text,{type:"secondary",children:t("It is recommended to backup before cleaning. You can also clean directly without backup.")}),e.jsxs(a.Space,{style:{width:"100%",justifyContent:"flex-end"},children:[e.jsx(a.Button,{onClick:()=>Y(!1),disabled:u,children:t("Cancel")}),e.jsx(a.Button,{icon:e.jsx(I.SaveOutlined,{}),loading:h,disabled:u,onClick:nt,children:t("Backup then Clean")}),e.jsx(a.Button,{danger:!0,icon:e.jsx(I.DeleteOutlined,{}),disabled:u,onClick:st,children:t("Clean directly")})]})]})}),e.jsx(a.Modal,{title:t("Backup Complete"),open:He,onCancel:()=>!u&&Z(!1),closable:!u,maskClosable:!u,keyboard:!u,footer:null,width:450,children:e.jsxs(a.Space,{direction:"vertical",style:{width:"100%"},size:"middle",children:[e.jsx(a.Typography.Text,{children:t("Do you want to download the backup file before cleaning?")}),e.jsxs(a.Space,{style:{width:"100%",justifyContent:"flex-end"},children:[e.jsx(a.Button,{onClick:()=>Z(!1),disabled:u,children:t("Cancel")}),e.jsx(a.Button,{onClick:lt,disabled:u,children:t("Skip download")}),e.jsx(a.Button,{type:"primary",icon:e.jsx(I.DownloadOutlined,{}),loading:O,disabled:u&&!O,onClick:ot,children:t("Download and continue")})]})]})}),e.jsx(a.Modal,{title:t("Batch Settings"),open:Je,onCancel:()=>!u&&G(!1),closable:!u,maskClosable:!u,keyboard:!u,footer:null,width:550,children:e.jsxs(a.Space,{direction:"vertical",style:{width:"100%"},size:"middle",children:[e.jsxs(a.Typography.Text,{children:[t("Total records to clean"),": ",e.jsx("strong",{children:E.count.toLocaleString()})]}),e.jsx(a.Radio.Group,{value:V,onChange:n=>we(n.target.value),style:{width:"100%"},children:e.jsxs(a.Space,{direction:"vertical",style:{width:"100%"},children:[e.jsx(a.Radio,{value:"none",children:t("No batching")}),e.jsx(a.Radio,{value:"count",children:e.jsxs(a.Space,{children:[t("Split into"),e.jsx(a.InputNumber,{min:2,max:1e3,value:se,onChange:n=>n&&Ze(n),changeOnWheel:!0,disabled:V!=="count",style:{width:80}}),t("batches")]})}),e.jsx(a.Radio,{value:"size",children:e.jsxs(a.Space,{children:[t("Each batch"),e.jsx(a.InputNumber,{min:1e3,max:1e6,step:1e3,value:re,onChange:n=>n&&Re(n),changeOnWheel:!0,disabled:V!=="size",style:{width:100}}),t("records")]})})]})}),e.jsx(a.Alert,{type:"info",showIcon:!0,message:V==="none"?E.count>5e4?t("Will clean {{count}} records at once. Large data volume may take a long time.",{count:E.count.toLocaleString()}):t("Will clean {{count}} records at once.",{count:E.count.toLocaleString()}):V==="count"?t("Will clean {{count}} records in {{batches}} batches, {{perBatch}} records per batch.",{count:E.count.toLocaleString(),batches:se,perBatch:Math.ceil(E.count/se).toLocaleString()}):t("Will clean {{count}} records in {{batches}} batches, {{perBatch}} records per batch.",{count:E.count.toLocaleString(),batches:Math.ceil(E.count/re),perBatch:re.toLocaleString()})}),e.jsxs(a.Space,{style:{width:"100%",justifyContent:"flex-end"},children:[e.jsx(a.Button,{onClick:()=>G(!1),disabled:u,children:t("Cancel")}),e.jsx(a.Button,{type:"primary",onClick:rt,disabled:u,children:t("Next")})]})]})}),e.jsx(a.Modal,{title:e.jsxs(a.Space,{children:[e.jsx(I.WarningOutlined,{style:{color:"#faad14"}}),t("Release disk space")]}),open:Qe,onCancel:()=>!u&&le(!1),closable:!u,maskClosable:!u,keyboard:!u,footer:null,width:550,children:e.jsxs(a.Space,{direction:"vertical",style:{width:"100%"},size:"middle",children:[z&&e.jsxs("div",{children:[e.jsxs(a.Typography.Text,{children:[t("Cleaning progress"),": ",z.current," / ",z.total," ",t("batches")]}),e.jsx(a.Progress,{percent:Math.round(z.current/z.total*100),status:"active"}),e.jsxs(a.Typography.Text,{type:"secondary",children:[t("Deleted"),": ",z.deletedCount.toLocaleString()," ",t("records")]})]}),!z&&e.jsxs(e.Fragment,{children:[e.jsx(a.Typography.Text,{children:t("Do you want to release disk space after cleaning?")}),e.jsx(a.Alert,{message:t("Release space warning"),description:e.jsxs(e.Fragment,{children:[t("Releasing space will lock the table and may take a long time for large tables. Other operations on this table will be blocked during the process."),V!=="none"&&e.jsxs(e.Fragment,{children:[e.jsx("br",{}),e.jsx("br",{}),t("Space will be released only after the last batch is completed.")]})]}),type:"warning",showIcon:!0}),e.jsxs(a.Space,{style:{width:"100%",justifyContent:"flex-end"},children:[e.jsx(a.Button,{onClick:()=>le(!1),disabled:u,children:t("Cancel")}),e.jsx(a.Button,{onClick:()=>Ae(!1),loading:m,disabled:u&&!m,children:t("Clean only")}),e.jsx(a.Button,{danger:!0,onClick:()=>Ae(!0),loading:m||de,disabled:u&&!(m||de),children:t("Clean and release space")})]})]})]})}),e.jsx(a.Table,{dataSource:C,loading:k,columns:dt,rowKey:(n,s)=>n.id||s,pagination:c.withAutoQuickJumper(A(v({},ee),{showSizeChanger:!0,showTotal:n=>t("Total: {{total}}",{total:n})})),onChange:ct,scroll:{x:"max-content"}})]})})}):e.jsx("div",{style:{textAlign:"center",padding:50},children:e.jsx(a.Spin,{size:"large"})})};function Ue(t){if(t===0)return"0 B";const y=1024,w=["B","KB","MB","GB","TB"],f=Math.floor(Math.log(t)/Math.log(y));return Math.round(t/Math.pow(y,f)*100)/100+" "+w[f]}function _e(t){if(t===0)return"0 B";const y=1024,w=["B","KB","MB","GB","TB"],f=Math.floor(Math.log(t)/Math.log(y));return Math.round(t/Math.pow(y,f)*100)/100+" "+w[f]}const We=()=>{const{t}=_(),y=c.useAPIClient(),w=j.useNavigate(),{message:f}=a.App.useApp(),[X,b]=r.useState([]),[g,W]=r.useState(!1),[L,o]=r.useState({current:1,pageSize:20,total:0}),i=r.useMemo(()=>y.resource("databaseClean"),[y]),C=r.useCallback(()=>T(null,null,function*(){yield d()}),[]);r.useEffect(()=>{d()},[L.current,L.pageSize]);const d=()=>T(null,null,function*(){W(!0);try{const h=yield i.list({params:{page:L.current,pageSize:L.pageSize}}),{data:D,meta:O}=h.data;b(Array.isArray(D)?D:[]),o($=>A(v({},$),{total:(O==null?void 0:O.count)||0}))}catch(h){f.error(h.message||t("Failed to load table list"))}finally{W(!1)}}),k=h=>{o(D=>A(v({},D),{current:h.current,pageSize:h.pageSize}))},K=[{title:t("Table Name"),dataIndex:"name",key:"name",render:h=>e.jsx("a",{onClick:()=>{w(`/_admin/system-services/database-clean/${h}`)},children:h})},{title:t("Origin"),dataIndex:"origin",key:"origin"},{title:t("Size"),dataIndex:"size",key:"size",render:h=>_e(h)},{title:t("Row Count"),dataIndex:"rowCount",key:"rowCount",render:h=>h.toLocaleString()},{title:t("Created At"),dataIndex:"createdAt",key:"createdAt",render:h=>h?e.jsx(c.DatePicker.ReadPretty,{value:P(h),showTime:!0}):"-"},{title:t("Updated At"),dataIndex:"updatedAt",key:"updatedAt",render:h=>h?e.jsx(c.DatePicker.ReadPretty,{value:P(h),showTime:!0}):"-"}];return e.jsx("div",{children:e.jsxs(a.Card,{bordered:!1,children:[e.jsx(a.Space,{style:{float:"right",marginBottom:16},children:e.jsx(a.Button,{onClick:C,icon:e.jsx(I.ReloadOutlined,{}),children:t("Refresh")})}),e.jsx(a.Table,{dataSource:X,loading:g,columns:K,rowKey:"name",pagination:c.withAutoQuickJumper(A(v({},L),{showSizeChanger:!0,showTotal:h=>t("Total: {{total}}",{total:h})})),onChange:k})]})})};class Ke extends c.Plugin{afterAdd(){return T(this,null,function*(){})}beforeLoad(){return T(this,null,function*(){})}load(){return T(this,null,function*(){this.app.systemSettingsManager.add("system-services."+M,{title:this.t("Database Clean"),icon:"DatabaseOutlined",Component:We,aclSnippet:"pm.database-clean.*",sort:-50}),this.app.systemSettingsManager.add("system-services."+M+"/:tableName",{title:this.t("Table Detail"),Component:qe,groupKey:"system-services."+M,aclSnippet:"pm.database-clean.*"})})}}p.default=Ke,Object.defineProperties(p,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
package/dist/externalVersion.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"archiver","version":"7.0.1","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":">= 14"},"scripts":{"test":"mocha --reporter dot","bench":"node benchmark/simple/pack-zip.js"},"dependencies":{"archiver-utils":"^5.0.2","async":"^3.2.4","buffer-crc32":"^1.0.0","readable-stream":"^4.0.0","readdir-glob":"^1.1.2","tar-stream":"^3.0.0","zip-stream":"^6.0.1"},"devDependencies":{"archiver-jsdoc-theme":"1.1.3","chai":"4.4.1","jsdoc":"4.0.2","mkdirp":"3.0.1","mocha":"10.3.0","rimraf":"5.0.5","stream-bench":"0.1.2","tar":"6.2.0","yauzl":"3.1.2"},"keywords":["archive","archiver","stream","zip","tar"],"publishConfig":{"registry":"https://registry.npmjs.org/"},"_lastModified":"2026-04-
|
|
1
|
+
{"name":"archiver","version":"7.0.1","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":">= 14"},"scripts":{"test":"mocha --reporter dot","bench":"node benchmark/simple/pack-zip.js"},"dependencies":{"archiver-utils":"^5.0.2","async":"^3.2.4","buffer-crc32":"^1.0.0","readable-stream":"^4.0.0","readdir-glob":"^1.1.2","tar-stream":"^3.0.0","zip-stream":"^6.0.1"},"devDependencies":{"archiver-jsdoc-theme":"1.1.3","chai":"4.4.1","jsdoc":"4.0.2","mkdirp":"3.0.1","mocha":"10.3.0","rimraf":"5.0.5","stream-bench":"0.1.2","tar":"6.2.0","yauzl":"3.1.2"},"keywords":["archive","archiver","stream","zip","tar"],"publishConfig":{"registry":"https://registry.npmjs.org/"},"_lastModified":"2026-04-27T06:03:52.575Z"}
|
|
@@ -38,6 +38,65 @@ var import_constants = require("../constants");
|
|
|
38
38
|
var import_database_service = require("../services/database-service");
|
|
39
39
|
var import_filtered_backup_service = require("../services/filtered-backup-service");
|
|
40
40
|
var import_lock = require("../utils/lock");
|
|
41
|
+
function bindDownloadDiagnostics(ctx, options) {
|
|
42
|
+
var _a, _b;
|
|
43
|
+
const logger = ctx.logger || ctx.tego.logger;
|
|
44
|
+
const startedAt = Date.now();
|
|
45
|
+
const requestId = ((_a = ctx.get) == null ? void 0 : _a.call(ctx, "x-request-id")) || ((_b = ctx.state) == null ? void 0 : _b.requestId);
|
|
46
|
+
const state = {
|
|
47
|
+
requestAborted: false
|
|
48
|
+
};
|
|
49
|
+
ctx.req.once("aborted", () => {
|
|
50
|
+
state.requestAborted = true;
|
|
51
|
+
logger == null ? void 0 : logger.warn(`${options.action} request aborted`, {
|
|
52
|
+
requestId,
|
|
53
|
+
appName: ctx.tego.name,
|
|
54
|
+
fileName: options.fileName,
|
|
55
|
+
filePath: options.filePath,
|
|
56
|
+
durationMs: Date.now() - startedAt
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
ctx.res.once("close", () => {
|
|
60
|
+
var _a2;
|
|
61
|
+
if (!ctx.res.writableEnded) {
|
|
62
|
+
logger == null ? void 0 : logger.warn(`${options.action} connection closed before stream finished`, {
|
|
63
|
+
requestId,
|
|
64
|
+
appName: ctx.tego.name,
|
|
65
|
+
fileName: options.fileName,
|
|
66
|
+
filePath: options.filePath,
|
|
67
|
+
durationMs: Date.now() - startedAt,
|
|
68
|
+
requestAborted: state.requestAborted,
|
|
69
|
+
responseFinished: ctx.res.writableFinished,
|
|
70
|
+
requestEnded: ctx.req.readableEnded,
|
|
71
|
+
socketDestroyed: (_a2 = ctx.req.socket) == null ? void 0 : _a2.destroyed
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
ctx.res.once("finish", () => {
|
|
76
|
+
logger == null ? void 0 : logger.info(`${options.action} completed`, {
|
|
77
|
+
requestId,
|
|
78
|
+
appName: ctx.tego.name,
|
|
79
|
+
fileName: options.fileName,
|
|
80
|
+
durationMs: Date.now() - startedAt
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
return (error) => {
|
|
84
|
+
logger == null ? void 0 : logger.error(`${options.action} stream error`, {
|
|
85
|
+
requestId,
|
|
86
|
+
appName: ctx.tego.name,
|
|
87
|
+
fileName: options.fileName,
|
|
88
|
+
filePath: options.filePath,
|
|
89
|
+
error: (error == null ? void 0 : error.stack) || (error == null ? void 0 : error.message) || String(error)
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function setDownloadResponse(ctx, options) {
|
|
94
|
+
ctx.set("X-Accel-Buffering", "no");
|
|
95
|
+
ctx.set("Content-Type", "application/octet-stream");
|
|
96
|
+
ctx.length = options.fileSize;
|
|
97
|
+
ctx.attachment(options.fileName);
|
|
98
|
+
ctx.body = options.stream;
|
|
99
|
+
}
|
|
41
100
|
var database_clean_default = {
|
|
42
101
|
name: "databaseClean",
|
|
43
102
|
actions: {
|
|
@@ -292,11 +351,23 @@ var database_clean_default = {
|
|
|
292
351
|
ctx.throw(403, "Invalid backup file");
|
|
293
352
|
return;
|
|
294
353
|
}
|
|
295
|
-
const stats =
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
354
|
+
const stats = await import_promises.default.stat(filePath);
|
|
355
|
+
if (!stats.isFile()) {
|
|
356
|
+
ctx.throw(404, `Backup file ${filterByTk} not found`);
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
const stream = import_node_fs.default.createReadStream(filePath);
|
|
360
|
+
const logStreamError = bindDownloadDiagnostics(ctx, {
|
|
361
|
+
action: "databaseClean:download",
|
|
362
|
+
fileName: filterByTk,
|
|
363
|
+
filePath
|
|
364
|
+
});
|
|
365
|
+
stream.once("error", logStreamError);
|
|
366
|
+
setDownloadResponse(ctx, {
|
|
367
|
+
fileName: filterByTk,
|
|
368
|
+
fileSize: stats.size,
|
|
369
|
+
stream
|
|
370
|
+
});
|
|
300
371
|
await next();
|
|
301
372
|
}
|
|
302
373
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tachybase/plugin-database-clean",
|
|
3
3
|
"displayName": "Database Cleanup Tool",
|
|
4
|
-
"version": "1.6.
|
|
4
|
+
"version": "1.6.16",
|
|
5
5
|
"description": "Clean up database.",
|
|
6
6
|
"homepage": "https://github.com/tegojs/tego-standard#readme",
|
|
7
7
|
"bugs": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"rc-field-form": "^2.7.0",
|
|
30
30
|
"react-router-dom": "6.28.1",
|
|
31
31
|
"sequelize": "^6.37.5",
|
|
32
|
-
"@tachybase/client": "1.6.
|
|
32
|
+
"@tachybase/client": "1.6.16"
|
|
33
33
|
},
|
|
34
34
|
"description.zh-CN": "数据库清理。",
|
|
35
35
|
"displayName.zh-CN": "数据库清理工具"
|