@kedem/okdb 1.0.1 → 1.0.4
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/bin/okdb.js +1 -1
- package/keys/public.pem +3 -0
- package/okdb.js +1 -1
- package/package.json +2 -2
- package/public/admin-app.js +1 -1
- package/public/components/admin-route-host.ok.js +1 -1
- package/public/components/env-picker.ok.js +1 -1
- package/public/components/field-path-input.ok.js +1 -1
- package/public/components/field.html +154 -2
- package/public/components/geo-map.ok.js +1 -1
- package/public/components/ok-cron-input.ok.js +1 -1
- package/public/components/ok-dropzone.ok.js +1 -1
- package/public/components/ok-js-input.ok.js +1 -1
- package/public/components/ok-json-input.ok.js +1 -1
- package/public/components/ok-text-monaco-input.ok.js +1 -1
- package/public/components/theme-toggle.ok.js +1 -1
- package/public/index.html +29 -2
- package/public/layouts/_default.ok.html +1 -1
- package/public/layouts/okdb-cube.ok.html +1 -1
- package/public/login-app.js +1 -1
- package/public/login.html +205 -1
- package/public/modules/ok.js +1 -1
- package/public/sections/api/index.ok.html +1 -1
- package/public/sections/api/parts/api-endpoint.ok.js +1 -1
- package/public/sections/auth/index.ok.html +1 -1
- package/public/sections/auth/modals/create-token-modal.ok.js +1 -1
- package/public/sections/auth/modals/edit-token-modal.ok.js +1 -1
- package/public/sections/auth/modals/perm-info-popover.ok.js +1 -1
- package/public/sections/auth/parts/token-detail.ok.js +1 -1
- package/public/sections/auth/parts/token-list.ok.js +1 -1
- package/public/sections/db/index.ok.html +1 -1
- package/public/sections/db/modals/add-item-modal.ok.js +1 -1
- package/public/sections/db/modals/create-env-modal.ok.js +1 -1
- package/public/sections/db/modals/create-fts-modal.ok.js +1 -1
- package/public/sections/db/modals/create-index-modal.ok.js +1 -1
- package/public/sections/db/modals/create-pipeline-modal.ok.js +1 -1
- package/public/sections/db/modals/demo-env-modal.ok.js +1 -1
- package/public/sections/db/modals/remove-env-modal.ok.js +1 -1
- package/public/sections/db/modals/schema-edit-modal.ok.js +1 -1
- package/public/sections/db/parts/db-overview.ok.js +1 -1
- package/public/sections/db/parts/db-pipelines-panel.ok.js +1 -1
- package/public/sections/db/parts/edit-row.ok.js +1 -1
- package/public/sections/db/parts/tm-timeline.ok.js +1 -1
- package/public/sections/db/parts/type-changelog.ok.js +1 -1
- package/public/sections/db/parts/type-list.ok.js +1 -1
- package/public/sections/db/parts/type-pipelines-tab.ok.js +1 -1
- package/public/sections/db/parts/type-schema-tab.ok.js +1 -1
- package/public/sections/db/parts/type-viewer.ok.js +1 -1
- package/public/sections/db/parts/type-violations-tab.ok.js +1 -1
- package/public/sections/docs/index.ok.html +1 -1
- package/public/sections/embeddings/index.ok.html +1 -1
- package/public/sections/embeddings/modals/register-model-modal.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-create-panel.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-embedder-panel.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-engine-declaration-editor.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-engine-list.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-indexer-panel.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-lifecycle-bar.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-model-catalog.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-overview.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-search-panel.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-worker-panel.ok.js +1 -1
- package/public/sections/embeddings/parts/embeddings-engine-panel.ok.js +1 -1
- package/public/sections/embeddings/parts/engines-overview.ok.js +1 -1
- package/public/sections/embeddings/parts/pipeline-create-panel.ok.js +1 -1
- package/public/sections/engines/engine-panel-shared-style.js +1 -1
- package/public/sections/engines/engine-ui-utils.js +1 -1
- package/public/sections/engines/index.ok.html +1 -1
- package/public/sections/engines/modals/engine-modal.ok.js +1 -1
- package/public/sections/engines/parts/engine-declaration-editor.ok.js +1 -1
- package/public/sections/engines/parts/engine-lifecycle-actions.ok.js +1 -1
- package/public/sections/engines/parts/engine-panel-shell.ok.js +1 -1
- package/public/sections/engines/parts/engine-resource-card.ok.js +1 -1
- package/public/sections/engines/parts/engine-row-item.ok.js +1 -1
- package/public/sections/engines/parts/generic-engine-panel.ok.js +1 -1
- package/public/sections/files/index.ok.html +1 -1
- package/public/sections/files/parts/files-blob-status.ok.js +1 -1
- package/public/sections/files/parts/files-collection-list.ok.js +1 -1
- package/public/sections/files/parts/files-collection-panel.ok.js +1 -1
- package/public/sections/files/parts/files-file-list.ok.js +1 -1
- package/public/sections/files/parts/files-overview.ok.js +1 -1
- package/public/sections/files/parts/files-path-browser.ok.js +1 -1
- package/public/sections/files/parts/files-upload-panel.ok.js +1 -1
- package/public/sections/functions/index.ok.html +1 -1
- package/public/sections/functions/modals/function-modal.ok.js +1 -1
- package/public/sections/functions/parts/function-detail.ok.js +1 -1
- package/public/sections/functions/parts/function-logs.ok.js +1 -1
- package/public/sections/functions/parts/function-runner.ok.js +1 -1
- package/public/sections/functions/parts/functions-list.ok.js +1 -1
- package/public/sections/license/index.ok.html +1 -1
- package/public/sections/license/parts/license-panel.ok.js +1 -1
- package/public/sections/processors/index.ok.html +1 -1
- package/public/sections/queue/index.ok.html +1 -1
- package/public/sections/queue/modals/create-bucket-modal.ok.js +1 -1
- package/public/sections/queue/modals/edit-bucket-modal.ok.js +1 -1
- package/public/sections/queue/modals/edit-job-modal.ok.js +1 -1
- package/public/sections/queue/modals/enqueue-job-modal.ok.js +1 -1
- package/public/sections/queue/modals/job-type-modal.ok.js +1 -1
- package/public/sections/queue/parts/ok-job-form.ok.js +1 -1
- package/public/sections/queue/parts/queue-buckets.ok.js +1 -1
- package/public/sections/queue/parts/queue-job-types.ok.js +1 -1
- package/public/sections/queue/parts/queue-jobs.ok.js +1 -1
- package/public/sections/queue/parts/queue-types.ok.js +1 -1
- package/public/sections/queue/parts/queue-workers.ok.js +1 -1
- package/public/sections/sync/index.ok.html +1 -1
- package/public/sections/sync/parts/sync-node-detail.ok.js +1 -1
- package/public/sections/sync/parts/sync-retention.ok.js +1 -1
- package/public/sections/sync/parts/sync-topology.ok.js +1 -1
- package/public/sections/system/index.ok.html +1 -1
- package/public/sections/system/modals/data-ops-modal.ok.js +1 -1
- package/public/sections/system/parts/system-api-panel.ok.js +1 -1
- package/public/sections/system/parts/system-auth-panel.ok.js +1 -1
- package/public/sections/system/parts/system-log-history.ok.js +1 -1
- package/public/sections/system/parts/system-log.ok.js +1 -1
- package/public/sections/system/parts/system-status.ok.js +1 -1
- package/public/sections/system/parts/system-sync-panel.ok.js +1 -1
- package/public/sections/views/index.ok.html +1 -1
- package/public/sections/views/modals/create-view-modal.ok.js +1 -1
- package/public/sections/views/parts/view-detail.ok.js +1 -1
- package/public/sections/views/parts/views-list.ok.js +1 -1
- package/public/sections/views/parts/views-overview.ok.js +1 -1
- package/public/setup-app.js +1 -1
- package/public/setup.html +189 -1
- package/public/stores/auth-store.js +1 -1
- package/public/stores/events-store.js +1 -1
- package/public/stores/functions-store.js +1 -1
- package/public/stores/okdb-store.js +1 -1
- package/public/stores/theme-store.js +1 -1
- package/public/test-cron-input.html +53 -3
- package/public/test-json-input.html +182 -3
- package/public/util/permissions.js +1 -1
- package/public/util/sift-schema.js +1 -1
- package/public/vendor/okjs/ok.esm.min.js +1 -2
- package/public/view-models/type-query-vm.js +1 -1
- package/okdb-data/default/data.mdb +0 -0
- package/okdb-data/default/lock.mdb +0 -0
- package/okdb-data/~log/data.mdb +0 -0
- package/okdb-data/~log/lock.mdb +0 -0
- package/okdb-data/~system/data.mdb +0 -0
- package/okdb-data/~system/lock.mdb +0 -0
- package/public/images/logo.png +0 -0
- package/public/images/logo.svg +0 -333
|
@@ -1 +1 @@
|
|
|
1
|
-
const _0xf3506c=_0x326b;function _0x2c8c(){const _0x29f57a=['$attr','1086234mfWTio','API','96684AwrzbO','json','exportSelectedEnvNames','stringify','application/json','dataTransfer','exportSingleEnvTypes','exportIncludeChanges','change','/system/backup','set','filter','preventDefault','backupCompact','getMonth','files','1099UNOeqG','POST','split','userEnvs','canBackup','removeChild','importSelectedTypeNames','get','match','importIncludeChanges','importBusy','backupEnvNames','exportDone','exportCanRun','length','join','size','backupError','backupDlDone','typesForEnv','exportAllTypes','env','exportSelectedTypeNames','parse','createObjectURL','importEnvOverride','importFile','backupDlError','envs','find','importFileTypes','.ndjson','changes','target','name','appendChild','content-disposition','_setImportFile','server','modal','backupSelEnvs','download','10tEuBlI','importDragOver','schema','importDone','startsWith','catch','10DDVmYa','backupBusy','545612BYFpck','./okdb-backup-','exportIsSingleEnv','includeChanges','2893VVjRdl','file','importDropExisting','headers','keys','exportError','importSelTypes','createElement','/system/import?','body','backupResult','importError','revokeObjectURL','111276ghmATH','getDate','backupEnvMode','HTTP\x20','exportBusy','status','click','436276RsFOjF','padStart','getFullYear','trim','types','type','now','message','onDone','map','6301683AnZrAQ','exportInit','15CszYzL','backupDlBusy','error','header','input','exportSelEnvs','href','importBatchSize','export','true','data','slice','44776qcvlIe','/system/export?','backupDestDir','exportSelTypes','text','onchange','accept','okdb-backup-','all'];_0x2c8c=function(){return _0x29f57a;};return _0x2c8c();}function _0x326b(_0x475194,_0x3060c9){_0x475194=_0x475194-0x8a;const _0x2c8c91=_0x2c8c();let _0x326be9=_0x2c8c91[_0x475194];return _0x326be9;}(function(_0x4eb021,_0x7dc6dc){const _0x2799c5=_0x326b,_0x15e458=_0x4eb021();while(!![]){try{const _0x575b79=parseInt(_0x2799c5(0xef))/0x1+-parseInt(_0x2799c5(0xf6))/0x2*(-parseInt(_0x2799c5(0x102))/0x3)+parseInt(_0x2799c5(0xde))/0x4*(-parseInt(_0x2799c5(0xdc))/0x5)+parseInt(_0x2799c5(0x9a))/0x6+parseInt(_0x2799c5(0xac))/0x7*(parseInt(_0x2799c5(0x90))/0x8)+-parseInt(_0x2799c5(0x100))/0x9*(-parseInt(_0x2799c5(0xd6))/0xa)+parseInt(_0x2799c5(0xe2))/0xb*(-parseInt(_0x2799c5(0x9c))/0xc);if(_0x575b79===_0x7dc6dc)break;else _0x15e458['push'](_0x15e458['shift']());}catch(_0x4921ff){_0x15e458['push'](_0x15e458['shift']());}}}(_0x2c8c,0x8b30c));export default{'tag':'data-ops-modal','attr':{'modal':{},'envs':{'default':()=>[]},'onDone':{},'initialTab':{'default':_0xf3506c(0x8c)}},'context'(_0x513b88){const _0x5b21d7=_0xf3506c;function _0x9fe9cb(){const _0x178d6c=_0x326b,_0x11b76f=new Date(),_0x79d5fd=_0x21da75=>String(_0x21da75)[_0x178d6c(0xf7)](0x2,'0');return _0x11b76f[_0x178d6c(0xf8)]()+'-'+_0x79d5fd(_0x11b76f[_0x178d6c(0xaa)]()+0x1)+'-'+_0x79d5fd(_0x11b76f[_0x178d6c(0xf0)]());}return{'tab':_0x513b88[_0x5b21d7(0x99)]['initialTab']||_0x5b21d7(0x8c),'formatBytes':function(_0x5ac36f){if(null==_0x5ac36f)return'--';const _0x49ce1a=['B','KB','MB','GB','TB'];let _0x1202b6=_0x5ac36f,_0x44d7d4=0x0;for(;_0x1202b6>=0x400&&_0x44d7d4<_0x49ce1a['length']-0x1;)_0x1202b6/=0x400,_0x44d7d4++;return _0x1202b6['toFixed'](0x0===_0x44d7d4?0x0:0x2)+'\x20'+_0x49ce1a[_0x44d7d4];},get 'userEnvs'(){const _0x7bdcb4=_0x5b21d7;return(_0x513b88[_0x7bdcb4(0x99)][_0x7bdcb4(0xc8)]||[])[_0x7bdcb4(0xa7)](_0x138620=>!_0x138620[_0x7bdcb4(0xce)]['startsWith']('~'));},'typesForEnv'(_0x6ca242){const _0x4b6f63=_0x5b21d7,_0x3a50a7=(_0x513b88['$attr'][_0x4b6f63(0xc8)]||[])[_0x4b6f63(0xc9)](_0x3920ba=>_0x3920ba[_0x4b6f63(0xce)]===_0x6ca242);return(_0x3a50a7?.['types']||[])[_0x4b6f63(0xa7)](_0x2f402b=>!_0x2f402b[_0x4b6f63(0xce)][_0x4b6f63(0xda)]('~'))['map'](_0x55d0ce=>_0x55d0ce['name']);},'exportSelEnvs':{},'exportIncludeChanges':!0x1,'exportBusy':!0x1,'exportError':null,'exportDone':null,'exportSelTypes':{},'exportAllTypes':!0x0,get 'exportSelectedEnvNames'(){const _0x438c3c=_0x5b21d7;return Object[_0x438c3c(0xe6)](this[_0x438c3c(0x107)])[_0x438c3c(0xa7)](_0x57b288=>this[_0x438c3c(0x107)][_0x57b288]);},get 'exportIsSingleEnv'(){const _0x5c46f0=_0x5b21d7;return 0x1===this[_0x5c46f0(0x9e)][_0x5c46f0(0xba)];},get 'exportSingleEnvTypes'(){const _0x5c2ccf=_0x5b21d7;return this[_0x5c2ccf(0xe0)]?this[_0x5c2ccf(0xbf)](this[_0x5c2ccf(0x9e)][0x0]):[];},get 'exportSelectedTypeNames'(){const _0x16a7a8=_0x5b21d7;return!this[_0x16a7a8(0xe0)]||this[_0x16a7a8(0xc0)]?null:Object['keys'](this[_0x16a7a8(0x93)])['filter'](_0xcb5ed9=>this[_0x16a7a8(0x93)][_0xcb5ed9]);},get 'exportCanRun'(){const _0x6a2735=_0x5b21d7;return this[_0x6a2735(0x9e)]['length']>0x0&&!this['exportBusy'];},'exportToggleAllEnvs'(_0x3346c3){const _0x8243a0=_0x5b21d7,_0x1900ae={};for(const _0x5114b7 of this[_0x8243a0(0xaf)])_0x1900ae[_0x5114b7[_0x8243a0(0xce)]]=_0x3346c3;this[_0x8243a0(0x107)]=_0x1900ae;},'exportToggleAllTypes'(_0x3a0995){const _0x5f5168=_0x5b21d7,_0x46a77d={};for(const _0x53a059 of this[_0x5f5168(0xa2)])_0x46a77d[_0x53a059]=_0x3a0995;this['exportSelTypes']=_0x46a77d;},'exportInit'(){const _0x199ee0=_0x5b21d7;0x0===Object[_0x199ee0(0xe6)](this[_0x199ee0(0x107)])[_0x199ee0(0xba)]&&this[_0x199ee0(0xaf)][_0x199ee0(0xba)]&&(this[_0x199ee0(0x107)]={[this['userEnvs'][0x0]['name']]:!0x0});},async 'runExport'(){const _0x18a4ed=_0x5b21d7;if(this[_0x18a4ed(0xb9)]){this[_0x18a4ed(0xf3)]=!0x0,this[_0x18a4ed(0xe7)]=null,this[_0x18a4ed(0xb8)]=null;try{const _0x162d48=this[_0x18a4ed(0x9e)],_0x562971=_0x162d48['length']>0x1,_0x4a913d=new URLSearchParams();_0x562971?_0x4a913d[_0x18a4ed(0xa6)](_0x18a4ed(0xc8),_0x162d48[_0x18a4ed(0xbb)](',')):_0x4a913d[_0x18a4ed(0xa6)](_0x18a4ed(0xc1),_0x162d48[0x0]),this[_0x18a4ed(0xa3)]&&_0x4a913d[_0x18a4ed(0xa6)](_0x18a4ed(0xe1),_0x18a4ed(0x8d));const _0x11d864=this[_0x18a4ed(0xc2)];_0x11d864&&_0x11d864['length']&&_0x4a913d[_0x18a4ed(0xa6)](_0x18a4ed(0xfa),_0x11d864[_0x18a4ed(0xbb)](','));const _0x3537d1=await fetch(__ENV__[_0x18a4ed(0x9b)]+_0x18a4ed(0x91)+_0x4a913d);if(!_0x3537d1['ok']){const _0x162f32=await _0x3537d1[_0x18a4ed(0x9d)]()['catch'](()=>({}));throw new Error(_0x162f32?.[_0x18a4ed(0x104)]?.['message']||_0x18a4ed(0xf2)+_0x3537d1[_0x18a4ed(0xf4)]);}const _0x43e6ab=await _0x3537d1['blob'](),_0x4db149=URL[_0x18a4ed(0xc4)](_0x43e6ab),_0x48c781=document[_0x18a4ed(0xe9)]('a'),_0x104a47=_0x3537d1[_0x18a4ed(0xe5)]['get'](_0x18a4ed(0xd0))||'',_0x1053b0=_0x104a47['match'](/filename="?([^"]+)"?/)?.[0x1]||'okdb-export-'+_0x162d48[_0x18a4ed(0xbb)]('+')+'-'+Date[_0x18a4ed(0xfc)]()+_0x18a4ed(0xcb);_0x48c781['href']=_0x4db149,_0x48c781[_0x18a4ed(0xd5)]=_0x1053b0,document[_0x18a4ed(0xeb)][_0x18a4ed(0xcf)](_0x48c781),_0x48c781[_0x18a4ed(0xf5)](),document['body'][_0x18a4ed(0xb1)](_0x48c781),URL['revokeObjectURL'](_0x4db149);const _0x190a05=(await _0x43e6ab[_0x18a4ed(0x94)]())[_0x18a4ed(0xae)]('\x0a')[_0x18a4ed(0xa7)](_0x264dba=>_0x264dba[_0x18a4ed(0xf9)]())[_0x18a4ed(0xff)](_0x1c4daf=>{const _0x1f30ec=_0x18a4ed;try{return JSON[_0x1f30ec(0xc3)](_0x1c4daf);}catch{return null;}})[_0x18a4ed(0xa7)](Boolean);this[_0x18a4ed(0xb8)]={'filename':_0x1053b0,'bytes':_0x43e6ab[_0x18a4ed(0xbc)],'envCount':_0x562971?_0x162d48[_0x18a4ed(0xba)]:0x1,'types':_0x190a05[_0x18a4ed(0xa7)](_0x368b46=>_0x18a4ed(0xd8)===_0x368b46['r'])[_0x18a4ed(0xba)],'records':_0x190a05['filter'](_0x1d8360=>_0x18a4ed(0x8e)===_0x1d8360['r'])[_0x18a4ed(0xba)],'changes':_0x190a05[_0x18a4ed(0xa7)](_0x2d959f=>_0x18a4ed(0xa4)===_0x2d959f['r'])[_0x18a4ed(0xba)]};}catch(_0x2eaf1e){this[_0x18a4ed(0xe7)]=_0x2eaf1e?.[_0x18a4ed(0xfd)]||String(_0x2eaf1e);}finally{this['exportBusy']=!0x1;}}},'importFile':null,'importEnvOverride':'','importSelTypes':{},'importAllTypes':!0x0,'importDropExisting':!0x1,'importIncludeChanges':!0x1,'importBatchSize':0x1f4,'importShowAdvanced':!0x1,'importBusy':!0x1,'importError':null,'importDone':null,'importDragOver':!0x1,'importFileTypes':[],get 'importSelectedTypeNames'(){const _0x4f28a7=_0x5b21d7;return this['importAllTypes']?null:Object['keys'](this[_0x4f28a7(0xe8)])[_0x4f28a7(0xa7)](_0x3ee5f1=>this[_0x4f28a7(0xe8)][_0x3ee5f1]);},get 'canImport'(){const _0x17c751=_0x5b21d7;return!!this[_0x17c751(0xc6)]&&!this['importBusy'];},'onDrop'(_0x395971){const _0x65e5c6=_0x5b21d7;_0x395971[_0x65e5c6(0xa8)](),this[_0x65e5c6(0xd7)]=!0x1;const _0x10cdc0=_0x395971[_0x65e5c6(0xa1)]?.['files']?.[0x0];_0x10cdc0&&this[_0x65e5c6(0xd1)](_0x10cdc0);},'onDragOver'(_0x2e6d11){const _0x40e6e9=_0x5b21d7;_0x2e6d11[_0x40e6e9(0xa8)](),this[_0x40e6e9(0xd7)]=!0x0;},'onDragLeave'(){const _0x20fe46=_0x5b21d7;this[_0x20fe46(0xd7)]=!0x1;},'pickFile'(){const _0x337644=_0x5b21d7,_0x2663c3=document[_0x337644(0xe9)](_0x337644(0x106));_0x2663c3[_0x337644(0xfb)]=_0x337644(0xe3),_0x2663c3[_0x337644(0x96)]='.ndjson,.jsonl,.json,.txt',_0x2663c3[_0x337644(0x95)]=_0x2e75f8=>{const _0x52a8a2=_0x337644,_0x6fa99e=_0x2e75f8[_0x52a8a2(0xcd)][_0x52a8a2(0xab)]?.[0x0];_0x6fa99e&&this[_0x52a8a2(0xd1)](_0x6fa99e);},_0x2663c3[_0x337644(0xf5)]();},async '_setImportFile'(_0x4f960e){const _0x5910ac=_0x5b21d7;this[_0x5910ac(0xc6)]=_0x4f960e,this['importError']=null,this['importDone']=null,this[_0x5910ac(0xca)]=[];try{const _0xbbe980=(await _0x4f960e[_0x5910ac(0x8f)](0x0,0x8000)['text']())[_0x5910ac(0xae)]('\x0a')[_0x5910ac(0xa7)](_0x23b32c=>_0x23b32c['trim']()),_0xfe4926=_0xbbe980['map'](_0x239f23=>{const _0x3529b0=_0x5910ac;try{return JSON[_0x3529b0(0xc3)](_0x239f23);}catch{return null;}})[_0x5910ac(0xa7)](_0xabce0=>'schema'===_0xabce0?.['r']);this['importFileTypes']=[...new Set(_0xfe4926['map'](_0x8db22f=>_0x8db22f[_0x5910ac(0xfb)]))];const _0x27e246=_0xbbe980['map'](_0x49772a=>{try{return JSON['parse'](_0x49772a);}catch{return null;}})[_0x5910ac(0xc9)](_0x59bbaa=>_0x5910ac(0x105)===_0x59bbaa?.['r']);_0x27e246?.['envName']&&this['importEnvOverride'];}catch{}},'importToggleAllTypes'(_0x1eb333){const _0xfb5c5c=_0x5b21d7,_0x57206f={};for(const _0x3ca370 of this[_0xfb5c5c(0xca)])_0x57206f[_0x3ca370]=_0x1eb333;this['importSelTypes']=_0x57206f;},async 'runImport'(){const _0xb8acc7=_0x5b21d7;if(this[_0xb8acc7(0xc6)]){this[_0xb8acc7(0xb6)]=!0x0,this[_0xb8acc7(0xed)]=null,this[_0xb8acc7(0xd9)]=null;try{const _0x3794aa=new URLSearchParams({'dropExisting':String(this[_0xb8acc7(0xe4)]),'includeChanges':String(this[_0xb8acc7(0xb5)]),'batchSize':String(this[_0xb8acc7(0x8b)]||0x1f4)});this[_0xb8acc7(0xc5)]&&_0x3794aa['set'](_0xb8acc7(0xc1),this[_0xb8acc7(0xc5)]);const _0x51a9c2=this[_0xb8acc7(0xb2)];_0x51a9c2&&_0x51a9c2[_0xb8acc7(0xba)]&&_0x3794aa[_0xb8acc7(0xa6)]('types',_0x51a9c2[_0xb8acc7(0xbb)](','));const _0xb52d89=await fetch(__ENV__['API']+_0xb8acc7(0xea)+_0x3794aa,{'method':_0xb8acc7(0xad),'headers':{'content-type':'application/x-ndjson'},'body':this[_0xb8acc7(0xc6)]}),_0x5c7440=await _0xb52d89[_0xb8acc7(0x9d)]()[_0xb8acc7(0xdb)](()=>({}));if(!_0xb52d89['ok'])throw new Error(_0x5c7440?.[_0xb8acc7(0x104)]?.[_0xb8acc7(0xfd)]||_0xb8acc7(0xf2)+_0xb52d89['status']);const _0x4daa6c=_0x5c7440['data']??_0x5c7440;this['importDone']={'types':_0x4daa6c[_0xb8acc7(0xfa)]??0x0,'records':_0x4daa6c['records']??0x0,'changes':_0x4daa6c[_0xb8acc7(0xcc)]??0x0},_0x513b88['$attr'][_0xb8acc7(0xfe)]?.();}catch(_0x942055){this[_0xb8acc7(0xed)]=_0x942055?.[_0xb8acc7(0xfd)]||String(_0x942055);}finally{this['importBusy']=!0x1;}}},'backupMode':_0x5b21d7(0xd2),'backupDestDir':_0x5b21d7(0xdf)+_0x9fe9cb(),'backupSelEnvs':{},'backupEnvMode':_0x5b21d7(0x98),'backupCompact':!0x0,'backupBusy':!0x1,'backupError':null,'backupResult':null,'backupDlBusy':!0x1,'backupDlError':null,'backupDlDone':null,get 'backupEnvNames'(){const _0x1c2265=_0x5b21d7;return'all'===this[_0x1c2265(0xf1)]?null:Object[_0x1c2265(0xe6)](this[_0x1c2265(0xd4)])[_0x1c2265(0xa7)](_0x2ac0f0=>this[_0x1c2265(0xd4)][_0x2ac0f0]);},get 'canBackup'(){const _0x33c2c1=_0x5b21d7;return this[_0x33c2c1(0x92)][_0x33c2c1(0xf9)]()['length']>0x0&&!this['backupBusy'];},get 'canBackupDl'(){const _0x4e0cae=_0x5b21d7;return!this[_0x4e0cae(0x103)];},async 'runBackup'(){const _0x14390b=_0x5b21d7;if(this[_0x14390b(0xb0)]){this[_0x14390b(0xdd)]=!0x0,this[_0x14390b(0xbd)]=null,this[_0x14390b(0xec)]=null;try{const _0x421c4b=await fetch(__ENV__[_0x14390b(0x9b)]+_0x14390b(0xa5),{'method':_0x14390b(0xad),'headers':{'content-type':_0x14390b(0xa0)},'body':JSON[_0x14390b(0x9f)]({'destDir':this[_0x14390b(0x92)][_0x14390b(0xf9)](),'envNames':this[_0x14390b(0xb7)],'compact':this[_0x14390b(0xa9)]})}),_0x3051b2=await _0x421c4b[_0x14390b(0x9d)]()[_0x14390b(0xdb)](()=>({}));if(!_0x421c4b['ok'])throw new Error(_0x3051b2?.['error']?.[_0x14390b(0xfd)]||_0x14390b(0xf2)+_0x421c4b['status']);this[_0x14390b(0xec)]=_0x3051b2['data']??_0x3051b2;}catch(_0x30e03b){this['backupError']=_0x30e03b?.[_0x14390b(0xfd)]||String(_0x30e03b);}finally{this[_0x14390b(0xdd)]=!0x1;}}},async 'runDownloadBackup'(){const _0x49be60=_0x5b21d7;this[_0x49be60(0x103)]=!0x0,this[_0x49be60(0xc7)]=null,this['backupDlDone']=null;try{const _0x1c6a6a=this[_0x49be60(0xb7)],_0x21c096=new URLSearchParams();_0x1c6a6a?.[_0x49be60(0xba)]?_0x21c096[_0x49be60(0xa6)](_0x49be60(0xc8),_0x1c6a6a['join'](',')):_0x21c096[_0x49be60(0xa6)](_0x49be60(0xc8),this['userEnvs'][_0x49be60(0xff)](_0x5347f0=>_0x5347f0[_0x49be60(0xce)])['join'](','));const _0x44845e=await fetch(__ENV__['API']+'/system/export?'+_0x21c096);if(!_0x44845e['ok']){const _0x491c32=await _0x44845e['json']()[_0x49be60(0xdb)](()=>({}));throw new Error(_0x491c32?.['error']||_0x49be60(0xf2)+_0x44845e[_0x49be60(0xf4)]);}const _0x3c10ca=await _0x44845e['blob'](),_0x5dbe02=URL['createObjectURL'](_0x3c10ca),_0x2204fc=document[_0x49be60(0xe9)]('a'),_0x5497aa=_0x44845e[_0x49be60(0xe5)][_0x49be60(0xb3)](_0x49be60(0xd0))||'',_0x376514=_0x5497aa[_0x49be60(0xb4)](/filename="?([^"]+)"?/)?.[0x1]||_0x49be60(0x97)+_0x9fe9cb()+_0x49be60(0xcb);_0x2204fc[_0x49be60(0x8a)]=_0x5dbe02,_0x2204fc[_0x49be60(0xd5)]=_0x376514,document[_0x49be60(0xeb)][_0x49be60(0xcf)](_0x2204fc),_0x2204fc[_0x49be60(0xf5)](),document['body'][_0x49be60(0xb1)](_0x2204fc),URL[_0x49be60(0xee)](_0x5dbe02),this[_0x49be60(0xbe)]={'filename':_0x376514,'bytes':_0x3c10ca[_0x49be60(0xbc)]};}catch(_0x3d528e){this[_0x49be60(0xc7)]=_0x3d528e?.[_0x49be60(0xfd)]||String(_0x3d528e);}finally{this[_0x49be60(0x103)]=!0x1;}},'close'(){const _0x235ed4=_0x5b21d7;_0x513b88[_0x235ed4(0x99)][_0x235ed4(0xd3)]['close']();},'mount'(){const _0x4e1606=_0x5b21d7;this[_0x4e1606(0x101)]();}};},'template':'\x0a<div\x20style=\x22min-width:520px;\x20max-width:640px;\x20display:flex;\x20flex-direction:column;\x20gap:0;\x22>\x0a\x0a\x20\x20<!--\x20Tab\x20bar\x20-->\x0a\x20\x20<div\x20style=\x22display:flex;\x20gap:2px;\x20padding:3px;\x20background:var(--okdb-app-bg-deep);\x20border-radius:9px;\x20margin-bottom:22px;\x20border:1px\x20solid\x20var(--okdb-app-border);\x22>\x0a\x20\x20\x20\x20<button\x20@click=\x22tab=\x27export\x27\x22\x0a\x20\x20\x20\x20\x20\x20:style=\x22tab===\x27export\x27\x20?\x20\x27flex:1;background:var(--okdb-app-surface-2);color:var(--okdb-accent);border-color:color-mix(in\x20srgb,\x20var(--okdb-accent)\x2027%,\x20transparent);font-weight:600;\x27\x20:\x20\x27flex:1;background:transparent;border-color:transparent;opacity:.5;\x27\x22\x0a\x20\x20\x20\x20\x20\x20style=\x22padding:7px\x200;border-radius:7px;font-size:13px;transition:all\x20.15s;cursor:pointer;\x22>\x0a\x20\x20\x20\x20\x20\x20⬇\x20Export\x0a\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20<button\x20@click=\x22tab=\x27import\x27\x22\x0a\x20\x20\x20\x20\x20\x20:style=\x22tab===\x27import\x27\x20?\x20\x27flex:1;background:var(--okdb-app-surface-2);color:var(--okdb-accent);border-color:color-mix(in\x20srgb,\x20var(--okdb-accent)\x2027%,\x20transparent);font-weight:600;\x27\x20:\x20\x27flex:1;background:transparent;border-color:transparent;opacity:.5;\x27\x22\x0a\x20\x20\x20\x20\x20\x20style=\x22padding:7px\x200;border-radius:7px;font-size:13px;transition:all\x20.15s;cursor:pointer;\x22>\x0a\x20\x20\x20\x20\x20\x20⬆\x20Import\x0a\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20<button\x20@click=\x22tab=\x27backup\x27\x22\x0a\x20\x20\x20\x20\x20\x20:style=\x22tab===\x27backup\x27\x20?\x20\x27flex:1;background:var(--okdb-app-surface-2);color:var(--okdb-purple);border-color:color-mix(in\x20srgb,\x20var(--okdb-purple)\x2027%,\x20transparent);font-weight:600;\x27\x20:\x20\x27flex:1;background:transparent;border-color:transparent;opacity:.5;\x27\x22\x0a\x20\x20\x20\x20\x20\x20style=\x22padding:7px\x200;border-radius:7px;font-size:13px;transition:all\x20.15s;cursor:pointer;\x22>\x0a\x20\x20\x20\x20\x20\x20🗄\x20Backup\x0a\x20\x20\x20\x20</button>\x0a\x20\x20</div>\x0a\x0a\x20\x20<!--\x20═══\x20EXPORT\x20═══════════════════════════════════════════════════════════\x20-->\x0a\x20\x20<if\x20:=\x22tab\x20===\x20\x27export\x27\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22display:flex;flex-direction:column;gap:18px;\x22>\x0a\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;opacity:.5;line-height:1.5;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20Streaming\x20NDJSON\x20export\x20—\x20portable\x20across\x20OKDB\x20versions,\x20importable\x20into\x20any\x20instance.\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20<!--\x20Environments\x20-->\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22dops-field\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;align-items:center;gap:8px;margin-bottom:8px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<label\x20class=\x22dops-label\x22\x20style=\x22flex:1;margin:0;\x22>Environments</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22exportToggleAllEnvs(true)\x22\x20\x20class=\x22dops-micro\x22>all</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22exportToggleAllEnvs(false)\x22\x20class=\x22dops-micro\x22>none</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;flex-wrap:wrap;gap:6px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<for\x20:=\x22userEnvs\x22\x20let:e>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<label\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:style=\x22exportSelEnvs[e.name]\x20?\x20\x27background:var(--okdb-app-surface-2);border-color:color-mix(in\x20srgb,\x20var(--okdb-accent)\x2033%,\x20transparent);color:#e2eaf4;\x27\x20:\x20\x27background:var(--okdb-app-surface);border-color:var(--okdb-app-border);opacity:.55;\x27\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22display:flex;align-items:center;gap:5px;padding:5px\x2011px;border-radius:999px;font-size:12px;cursor:pointer;border:1px\x20solid;transition:all\x20.12s;user-select:none;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:checked=\x22!!exportSelEnvs[e.name]\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@change=\x22exportSelEnvs\x20=\x20{...exportSelEnvs,\x20[e.name]:\x20$el.checked}\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22display:none;\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20:style=\x22exportSelEnvs[e.name]\x20?\x20\x27color:var(--okdb-accent);font-size:10px;\x27\x20:\x20\x27display:none;\x27\x22>✓</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{e.name}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.4;font-size:10px;\x22>{{e.types\x20?\x20e.types.filter(t=>!t.name.startsWith(\x27~\x27)).length\x20:\x200}}\x20types</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</for>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20<!--\x20Types\x20(only\x20for\x20single\x20env)\x20-->\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22exportIsSingleEnv\x20&&\x20exportSingleEnvTypes.length\x20>\x200\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22dops-field\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;align-items:center;gap:8px;margin-bottom:8px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<label\x20class=\x22dops-label\x22\x20style=\x22flex:1;margin:0;\x22>Types</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<label\x20class=\x22dops-check\x22\x20style=\x22font-size:11px;gap:4px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x20:checked=\x22exportAllTypes\x22\x20@change=\x22exportAllTypes\x20=\x20$el.checked\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.6;\x22>All\x20types</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22!exportAllTypes\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;flex-direction:column;gap:0;background:var(--okdb-app-bg-deep);border:1px\x20solid\x20var(--okdb-app-border);border-radius:8px;overflow:hidden;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;align-items:center;padding:5px\x2010px;border-bottom:1px\x20solid\x20var(--okdb-app-border);gap:8px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22exportToggleAllTypes(true)\x22\x20\x20class=\x22dops-micro\x22>all</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22exportToggleAllTypes(false)\x22\x20class=\x22dops-micro\x22>none</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;flex-direction:column;max-height:140px;overflow-y:auto;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<for\x20:=\x22exportSingleEnvTypes\x22\x20let:t>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<label\x20style=\x22display:flex;align-items:center;gap:8px;padding:6px\x2010px;cursor:pointer;transition:background\x20.1s;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:style=\x22exportSelTypes[t]\x20?\x20\x27background:#1a2a1a;\x27\x20:\x20\x27\x27\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@mouseenter=\x22$el.style.background=exportSelTypes[t]?\x27#1a2a1a\x27:\x27var(--okdb-app-surface)\x27\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@mouseleave=\x22$el.style.background=exportSelTypes[t]?\x27#1a2a1a\x27:\x27\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:checked=\x22!!exportSelTypes[t]\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@change=\x22exportSelTypes\x20=\x20{...exportSelTypes,\x20[t]:\x20$el.checked}\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-family:monospace;font-size:12px;\x22>{{t}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</for>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22!exportIsSingleEnv\x20&&\x20exportSelectedEnvNames.length\x20>\x201\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;opacity:.4;font-style:italic;\x22>All\x20types\x20will\x20be\x20exported\x20from\x20each\x20selected\x20environment.</div>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20\x20\x20<!--\x20Options\x20-->\x0a\x20\x20\x20\x20\x20\x20<label\x20class=\x22dops-check\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x20:checked=\x22exportIncludeChanges\x22\x20@change=\x22exportIncludeChanges\x20=\x20$el.checked\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span>Include\x20changelog\x20<span\x20style=\x22opacity:.4;font-size:11px;\x22>(sync\x20history)</span></span>\x0a\x20\x20\x20\x20\x20\x20</label>\x0a\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22exportError\x22><div\x20class=\x22dops-error\x22>{{exportError}}</div></if>\x0a\x0a\x20\x20\x20\x20\x20\x20<!--\x20Success\x20-->\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22exportDone\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22dops-success\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;align-items:center;gap:8px;margin-bottom:8px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span>✓</span><span\x20style=\x22font-weight:600;\x22>Downloaded</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.4;font-size:11px;margin-left:auto;\x22>{{formatBytes(exportDone.bytes)}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:grid;grid-template-columns:repeat(3,1fr);gap:6px;font-size:12px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22exportDone.envCount\x20>\x201\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22dops-stat\x22><div\x20class=\x22dops-stat-n\x22>{{exportDone.envCount}}</div><div>envs</div></div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22dops-stat\x22><div\x20class=\x22dops-stat-n\x22>{{exportDone.types}}</div><div>types</div></div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22dops-stat\x22><div\x20class=\x22dops-stat-n\x22>{{exportDone.records}}</div><div>records</div></div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22dops-stat\x22><div\x20class=\x22dops-stat-n\x22>{{exportDone.changes}}</div><div>changes</div></div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:10px;opacity:.35;margin-top:6px;font-family:monospace;word-break:break-all;\x22>{{exportDone.filename}}</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;gap:8px;justify-content:flex-end;margin-top:4px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22close()\x22\x20class=\x22dops-btn-ghost\x22>Cancel</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22runExport()\x22\x20:disabled=\x22!exportCanRun\x22\x20class=\x22dops-btn-primary\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22exportBusy\x22><span\x20class=\x22dops-spinner\x22></span>\x20Exporting…</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22!exportBusy\x22>⬇\x20Download\x20NDJSON</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<!--\x20═══\x20IMPORT\x20═══════════════════════════════════════════════════════════\x20-->\x0a\x20\x20<if\x20:=\x22tab\x20===\x20\x27import\x27\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22display:flex;flex-direction:column;gap:18px;\x22>\x0a\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;opacity:.5;line-height:1.5;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20Upload\x20a\x20OKDB\x20NDJSON\x20export.\x20Types,\x20indexes,\x20and\x20records\x20are\x20restored\x20automatically.\x0a\x20\x20\x20\x20\x20\x20\x20\x20Multi-env\x20files\x20restore\x20each\x20environment\x20separately.\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20<!--\x20Drop\x20zone\x20-->\x0a\x20\x20\x20\x20\x20\x20<div\x20@click=\x22pickFile()\x22\x20@drop=\x22onDrop($event)\x22\x20@dragover=\x22onDragOver($event)\x22\x20@dragleave=\x22onDragLeave()\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20:style=\x22importDragOver\x20?\x20\x27border-color:var(--okdb-accent);background:color-mix(in\x20srgb,\x20var(--okdb-accent)\x205%,\x20transparent);\x27\x20:\x20importFile\x20?\x20\x27border-color:color-mix(in\x20srgb,\x20var(--okdb-success)\x2033%,\x20transparent);background:#0a1a10;\x27\x20:\x20\x27border-color:var(--okdb-app-border);background:var(--okdb-app-bg-deep);\x27\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20style=\x22border:2px\x20dashed;border-radius:10px;padding:24px\x2016px;text-align:center;cursor:pointer;transition:all\x20.15s;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22!importFile\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:22px;opacity:.4;margin-bottom:8px;\x22>📂</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:13px;opacity:.7;\x22>Drop\x20.ndjson\x20file\x20here\x20or\x20<span\x20style=\x22color:var(--okdb-accent);\x22>click\x20to\x20browse</span></div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;opacity:.3;margin-top:4px;\x22>.ndjson\x20·\x20.jsonl\x20·\x20.json</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22importFile\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:20px;margin-bottom:6px;\x22>📄</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:13px;font-weight:600;color:var(--okdb-success);font-family:monospace;word-break:break-all;\x22>{{importFile.name}}</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;opacity:.45;margin-top:3px;\x22>{{formatBytes(importFile.size)}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22importFileTypes.length\x22>\x20·\x20{{importFileTypes.length}}\x20type{{importFileTypes.length!==1?\x27s\x27:\x27\x27}}\x20detected</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20·\x20click\x20to\x20change</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20<!--\x20Types\x20filter\x20(from\x20file)\x20-->\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22importFileTypes.length\x20>\x200\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22dops-field\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;align-items:center;gap:8px;margin-bottom:8px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<label\x20class=\x22dops-label\x22\x20style=\x22flex:1;margin:0;\x22>Types\x20to\x20import</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<label\x20class=\x22dops-check\x22\x20style=\x22font-size:11px;gap:4px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x20:checked=\x22importAllTypes\x22\x20@change=\x22importAllTypes\x20=\x20$el.checked\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.6;\x22>All</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22!importAllTypes\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;flex-direction:column;gap:0;background:var(--okdb-app-bg-deep);border:1px\x20solid\x20var(--okdb-app-border);border-radius:8px;overflow:hidden;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;padding:5px\x2010px;border-bottom:1px\x20solid\x20var(--okdb-app-border);gap:8px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22importToggleAllTypes(true)\x22\x20\x20class=\x22dops-micro\x22>all</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22importToggleAllTypes(false)\x22\x20class=\x22dops-micro\x22>none</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;flex-direction:column;max-height:130px;overflow-y:auto;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<for\x20:=\x22importFileTypes\x22\x20let:t>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<label\x20style=\x22display:flex;align-items:center;gap:8px;padding:6px\x2010px;cursor:pointer;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:style=\x22importSelTypes[t]\x20?\x20\x27background:#1a2a1a;\x27\x20:\x20\x27\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:checked=\x22!!importSelTypes[t]\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@change=\x22importSelTypes\x20=\x20{...importSelTypes,\x20[t]:\x20$el.checked}\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-family:monospace;font-size:12px;\x22>{{t}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</for>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20\x20\x20<!--\x20Target\x20env\x20override\x20-->\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22dops-field\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<label\x20class=\x22dops-label\x22>Target\x20environment\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.35;font-size:11px;font-weight:400;\x22>(leave\x20empty\x20to\x20use\x20the\x20file\x27s\x20source\x20env)</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<select\x20:value=\x22importEnvOverride\x22\x20@change=\x22importEnvOverride\x20=\x20$el.value\x22\x20class=\x22dops-select\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<option\x20value=\x22\x22>—\x20from\x20file\x20header\x20—</option>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<for\x20:=\x22userEnvs\x22\x20let:e>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<option\x20:value=\x22e.name\x22>{{e.name}}</option>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</for>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</select>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20<!--\x20Options\x20-->\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;flex-direction:column;gap:7px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<label\x20class=\x22dops-check\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x20:checked=\x22importDropExisting\x22\x20@change=\x22importDropExisting\x20=\x20$el.checked\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span>Drop\x20&\x20recreate\x20existing\x20types\x20<span\x20style=\x22opacity:.4;font-size:11px;\x22>(replaces\x20current\x20data)</span></span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<label\x20class=\x22dops-check\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x20:checked=\x22importIncludeChanges\x22\x20@change=\x22importIncludeChanges\x20=\x20$el.checked\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span>Restore\x20changelog\x20rows</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20<!--\x20Advanced\x20-->\x0a\x20\x20\x20\x20\x20\x20<div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22importShowAdvanced=!importShowAdvanced\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22font-size:11px;opacity:.4;background:transparent;border:none;padding:0;cursor:pointer;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{importShowAdvanced?\x27▴\x20hide\x27:\x27▾\x27}}\x20advanced\x0a\x20\x20\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22importShowAdvanced\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22dops-field\x22\x20style=\x22margin-top:10px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<label\x20class=\x22dops-label\x22>Batch\x20size\x20<span\x20style=\x22opacity:.35;font-size:11px;\x22>(records\x20per\x20write-txn)</span></label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22number\x22\x20min=\x2210\x22\x20max=\x2210000\x22\x20step=\x2210\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:value=\x22importBatchSize\x22\x20@input=\x22importBatchSize=Number($el.value)||500\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20class=\x22dops-input\x22\x20style=\x22max-width:120px;\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22importError\x22><div\x20class=\x22dops-error\x22>{{importError}}</div></if>\x0a\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22importDone\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22dops-success\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;align-items:center;gap:8px;margin-bottom:8px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span>✓</span><span\x20style=\x22font-weight:600;\x22>Import\x20complete</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:grid;grid-template-columns:repeat(3,1fr);gap:6px;font-size:12px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22dops-stat\x22><div\x20class=\x22dops-stat-n\x22>{{importDone.types}}</div><div>types</div></div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22dops-stat\x22><div\x20class=\x22dops-stat-n\x22>{{importDone.records}}</div><div>records</div></div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22dops-stat\x22><div\x20class=\x22dops-stat-n\x22>{{importDone.changes}}</div><div>changes</div></div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;gap:8px;justify-content:flex-end;margin-top:4px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22close()\x22\x20class=\x22dops-btn-ghost\x22>Cancel</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22runImport()\x22\x20:disabled=\x22!canImport\x22\x20class=\x22dops-btn-primary\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22importBusy\x22><span\x20class=\x22dops-spinner\x22></span>\x20Importing…</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22!importBusy\x22>⬆\x20Import\x20File</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<!--\x20═══\x20BACKUP\x20════════════════════════════════════════════════════════════\x20-->\x0a\x20\x20<if\x20:=\x22tab\x20===\x20\x27backup\x27\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22display:flex;flex-direction:column;gap:0;\x22>\x0a\x0a\x20\x20\x20\x20\x20\x20<!--\x20Mode\x20tabs\x20-->\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;gap:0;margin-bottom:18px;border-bottom:1px\x20solid\x20var(--okdb-app-border);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22backupMode=\x27server\x27\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:style=\x22backupMode===\x27server\x27\x20?\x20\x27color:var(--okdb-purple);border-bottom:2px\x20solid\x20var(--okdb-purple);opacity:1;\x27\x20:\x20\x27border-bottom:2px\x20solid\x20transparent;opacity:.45;\x27\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22padding:6px\x2016px;background:transparent;border:none;border-radius:0;font-size:13px;cursor:pointer;transition:all\x20.15s;margin-bottom:-1px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20🗄\x20Server\x20backup\x0a\x20\x20\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22backupMode=\x27download\x27\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:style=\x22backupMode===\x27download\x27\x20?\x20\x27color:var(--okdb-purple);border-bottom:2px\x20solid\x20var(--okdb-purple);opacity:1;\x27\x20:\x20\x27border-bottom:2px\x20solid\x20transparent;opacity:.45;\x27\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22padding:6px\x2016px;background:transparent;border:none;border-radius:0;font-size:13px;cursor:pointer;transition:all\x20.15s;margin-bottom:-1px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20⬇\x20Download\x20to\x20PC\x0a\x20\x20\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20<!--\x20Server\x20backup\x20mode\x20-->\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22backupMode\x20===\x20\x27server\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;flex-direction:column;gap:16px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;opacity:.5;line-height:1.5;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Hot\x20LMDB\x20page-copy\x20backup\x20—\x20atomic,\x20exact\x20snapshot,\x20no\x20serialisation.\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Writes\x20to\x20a\x20directory\x20<em>on\x20the\x20server</em>.\x20The\x20output\x20can\x20be\x20used\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20directly\x20as\x20a\x20OKDB\x20data\x20path.\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Dest\x20dir\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22dops-field\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<label\x20class=\x22dops-label\x22>Destination\x20directory\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.35;font-size:11px;font-weight:400;\x22>(server-side\x20path)</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22text\x22\x20:value=\x22backupDestDir\x22\x20@input=\x22backupDestDir=$el.value\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20class=\x22dops-input\x22\x20style=\x22font-family:monospace;\x22\x20spellcheck=\x22false\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Env\x20selection\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22dops-field\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<label\x20class=\x22dops-label\x22\x20style=\x22margin-bottom:8px;\x22>Environments</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;gap:12px;margin-bottom:8px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<label\x20class=\x22dops-check\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22radio\x22\x20name=\x22bkEnvMode\x22\x20value=\x22all\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:checked=\x22backupEnvMode===\x27all\x27\x22\x20@change=\x22backupEnvMode=\x27all\x27\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span>All</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<label\x20class=\x22dops-check\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22radio\x22\x20name=\x22bkEnvMode\x22\x20value=\x22selected\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:checked=\x22backupEnvMode===\x27selected\x27\x22\x20@change=\x22backupEnvMode=\x27selected\x27\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span>Select…</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22backupEnvMode===\x27selected\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;flex-wrap:wrap;gap:6px;padding:10px;background:var(--okdb-app-bg-deep);border-radius:8px;border:1px\x20solid\x20var(--okdb-app-border);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<for\x20:=\x22userEnvs\x22\x20let:e>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<label\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:style=\x22backupSelEnvs[e.name]\x20?\x20\x27background:var(--okdb-app-surface);border-color:color-mix(in\x20srgb,\x20var(--okdb-purple)\x2027%,\x20transparent);color:#e2d8f4;\x27\x20:\x20\x27background:var(--okdb-app-surface);border-color:var(--okdb-app-border);opacity:.55;\x27\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22display:flex;align-items:center;gap:5px;padding:5px\x2011px;border-radius:999px;font-size:12px;cursor:pointer;border:1px\x20solid;transition:all\x20.12s;user-select:none;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:checked=\x22!!backupSelEnvs[e.name]\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@change=\x22backupSelEnvs={...backupSelEnvs,[e.name]:$el.checked}\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22display:none;\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20:style=\x22backupSelEnvs[e.name]?\x27color:var(--okdb-purple);font-size:10px;\x27:\x27display:none;\x27\x22>✓</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{e.name}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</for>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<label\x20class=\x22dops-check\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x20:checked=\x22backupCompact\x22\x20@change=\x22backupCompact=$el.checked\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span>Compact\x20while\x20copying\x20<span\x20style=\x22opacity:.4;font-size:11px;\x22>(smaller\x20files,\x20slightly\x20slower)</span></span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</label>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22backupError\x22><div\x20class=\x22dops-error\x22>{{backupError}}</div></if>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22backupResult\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22dops-success\x22\x20style=\x22border-color:color-mix(in\x20srgb,\x20var(--okdb-purple)\x2020%,\x20transparent);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;align-items:center;gap:8px;margin-bottom:10px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span>✓</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-weight:600;color:var(--okdb-app-fg);\x22>Server\x20backup\x20complete</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.4;font-size:11px;margin-left:auto;\x22>{{backupResult.durationMs}}ms</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;flex-direction:column;gap:4px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<for\x20:=\x22backupResult.envs||[]\x22\x20let:e>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22background:#1a1228;border-radius:6px;padding:7px\x2010px;font-size:12px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;gap:8px;align-items:center;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-family:monospace;font-weight:600;color:var(--okdb-purple);\x22>{{e.name}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.35;font-size:11px;\x22>{{formatBytes(e.sizeBefore)}}\x20→\x20{{formatBytes(e.sizeAfter)}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-family:monospace;font-size:10px;opacity:.4;margin-top:3px;word-break:break-all;\x22>{{e.dest}}</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</for>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;gap:8px;justify-content:flex-end;margin-top:4px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22close()\x22\x20class=\x22dops-btn-ghost\x22>Cancel</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22runBackup()\x22\x20:disabled=\x22!canBackup\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22padding:8px\x2020px;border-radius:8px;font-size:13px;font-weight:600;background:linear-gradient(135deg,#1e1530,#150f22);border:1px\x20solid\x20color-mix(in\x20srgb,\x20var(--okdb-purple)\x2033%,\x20transparent);color:var(--okdb-purple);cursor:pointer;display:flex;align-items:center;gap:6px;transition:all\x20.15s;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22backupBusy\x22><span\x20class=\x22dops-spinner\x22\x20style=\x22border-color:color-mix(in\x20srgb,\x20var(--okdb-purple)\x2027%,\x20transparent);border-top-color:var(--okdb-purple);\x22></span>\x20Backing\x20up…</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22!backupBusy\x22>🗄\x20Run\x20Server\x20Backup</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20\x20\x20<!--\x20Download\x20backup\x20mode\x20-->\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22backupMode\x20===\x20\x27download\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;flex-direction:column;gap:16px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;opacity:.5;line-height:1.5;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Export\x20all\x20environments\x20as\x20a\x20single\x20portable\x20NDJSON\x20file\x20and\x20download\x20it\x20to\x20your\x20computer.\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20This\x20file\x20can\x20be\x20imported\x20back\x20into\x20any\x20OKDB\x20instance.\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Env\x20selection\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22dops-field\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<label\x20class=\x22dops-label\x22\x20style=\x22margin-bottom:8px;\x22>Environments\x20to\x20include</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;gap:12px;margin-bottom:8px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<label\x20class=\x22dops-check\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22radio\x22\x20name=\x22dlEnvMode\x22\x20value=\x22all\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:checked=\x22backupEnvMode===\x27all\x27\x22\x20@change=\x22backupEnvMode=\x27all\x27\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span>All\x20environments</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<label\x20class=\x22dops-check\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22radio\x22\x20name=\x22dlEnvMode\x22\x20value=\x22selected\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:checked=\x22backupEnvMode===\x27selected\x27\x22\x20@change=\x22backupEnvMode=\x27selected\x27\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span>Select…</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22backupEnvMode===\x27selected\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;flex-wrap:wrap;gap:6px;padding:10px;background:var(--okdb-app-bg-deep);border-radius:8px;border:1px\x20solid\x20var(--okdb-app-border);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<for\x20:=\x22userEnvs\x22\x20let:e>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<label\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:style=\x22backupSelEnvs[e.name]\x20?\x20\x27background:var(--okdb-app-surface);border-color:color-mix(in\x20srgb,\x20var(--okdb-purple)\x2027%,\x20transparent);\x27\x20:\x20\x27background:var(--okdb-app-surface);border-color:var(--okdb-app-border);opacity:.55;\x27\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22display:flex;align-items:center;gap:5px;padding:5px\x2011px;border-radius:999px;font-size:12px;cursor:pointer;border:1px\x20solid;transition:all\x20.12s;user-select:none;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:checked=\x22!!backupSelEnvs[e.name]\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@change=\x22backupSelEnvs={...backupSelEnvs,[e.name]:$el.checked}\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22display:none;\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20:style=\x22backupSelEnvs[e.name]?\x27color:var(--okdb-purple);font-size:10px;\x27:\x27display:none;\x27\x22>✓</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{e.name}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</for>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22backupDlError\x22><div\x20class=\x22dops-error\x22>{{backupDlError}}</div></if>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22backupDlDone\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22dops-success\x22\x20style=\x22border-color:color-mix(in\x20srgb,\x20var(--okdb-purple)\x2020%,\x20transparent);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;align-items:center;gap:8px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span>✓</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-weight:600;color:var(--okdb-app-fg);\x22>Downloaded</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.4;font-size:11px;\x22>{{formatBytes(backupDlDone.bytes)}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-family:monospace;font-size:10px;opacity:.35;margin-top:5px;word-break:break-all;\x22>{{backupDlDone.filename}}</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;gap:8px;justify-content:flex-end;margin-top:4px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22close()\x22\x20class=\x22dops-btn-ghost\x22>Cancel</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22runDownloadBackup()\x22\x20:disabled=\x22!canBackupDl\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22padding:8px\x2020px;border-radius:8px;font-size:13px;font-weight:600;background:linear-gradient(135deg,#1e1530,#150f22);border:1px\x20solid\x20color-mix(in\x20srgb,\x20var(--okdb-purple)\x2033%,\x20transparent);color:var(--okdb-purple);cursor:pointer;display:flex;align-items:center;gap:6px;transition:all\x20.15s;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22backupDlBusy\x22><span\x20class=\x22dops-spinner\x22\x20style=\x22border-color:color-mix(in\x20srgb,\x20var(--okdb-purple)\x2027%,\x20transparent);border-top-color:var(--okdb-purple);\x22></span>\x20Downloading…</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22!backupDlBusy\x22>⬇\x20Download\x20Backup</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a</div>\x0a\x0a<style>\x0a\x20\x20.dops-field\x20{\x20display:flex;\x20flex-direction:column;\x20gap:5px;\x20}\x0a\x20\x20.dops-label\x20{\x20font-size:12px;\x20opacity:.6;\x20font-weight:500;\x20}\x0a\x20\x20.dops-input\x20{\x0a\x20\x20\x20\x20background:var(--okdb-app-bg-deep);\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:6px;\x0a\x20\x20\x20\x20color:inherit;\x20padding:7px\x2010px;\x20font-size:13px;\x20width:100%;\x0a\x20\x20\x20\x20box-sizing:border-box;\x20transition:border-color\x20.15s;\x0a\x20\x20}\x0a\x20\x20.dops-input:focus\x20{\x20outline:none;\x20border-color:color-mix(in\x20srgb,\x20var(--okdb-accent)\x2033%,\x20transparent);\x20}\x0a\x20\x20.dops-select\x20{\x0a\x20\x20\x20\x20background:var(--okdb-app-bg-deep);\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:6px;\x0a\x20\x20\x20\x20color:inherit;\x20padding:7px\x2010px;\x20font-size:13px;\x20width:100%;\x20box-sizing:border-box;\x20cursor:pointer;\x0a\x20\x20}\x0a\x20\x20.dops-select:focus\x20{\x20outline:none;\x20border-color:color-mix(in\x20srgb,\x20var(--okdb-accent)\x2033%,\x20transparent);\x20}\x0a\x20\x20.dops-check\x20{\x20display:flex;\x20align-items:center;\x20gap:8px;\x20font-size:13px;\x20cursor:pointer;\x20user-select:none;\x20}\x0a\x20\x20.dops-micro\x20{\x0a\x20\x20\x20\x20padding:2px\x208px;\x20border-radius:4px;\x20font-size:10px;\x20background:transparent;\x0a\x20\x20\x20\x20border:1px\x20solid\x20var(--okdb-app-border);\x20opacity:.5;\x20cursor:pointer;\x20transition:opacity\x20.1s;\x0a\x20\x20}\x0a\x20\x20.dops-micro:hover\x20{\x20opacity:.85;\x20}\x0a\x20\x20.dops-error\x20{\x0a\x20\x20\x20\x20background:#2a1010;\x20border:1px\x20solid\x20color-mix(in\x20srgb,\x20var(--okdb-danger)\x2027%,\x20transparent);\x20border-radius:8px;\x0a\x20\x20\x20\x20padding:10px\x2012px;\x20font-size:12px;\x20color:var(--okdb-danger);\x20line-height:1.5;\x0a\x20\x20}\x0a\x20\x20.dops-success\x20{\x0a\x20\x20\x20\x20background:#0d1a14;\x20border:1px\x20solid\x20color-mix(in\x20srgb,\x20var(--okdb-success)\x2020%,\x20transparent);\x20border-radius:8px;\x0a\x20\x20\x20\x20padding:12px\x2014px;\x20font-size:13px;\x20color:#d1fae5;\x0a\x20\x20}\x0a\x20\x20.dops-stat\x20{\x0a\x20\x20\x20\x20background:#071410;\x20border-radius:6px;\x20padding:8px;\x20text-align:center;\x20font-size:11px;\x20opacity:.8;\x0a\x20\x20}\x0a\x20\x20.dops-stat-n\x20{\x20font-size:18px;\x20font-weight:700;\x20color:var(--okdb-success);\x20}\x0a\x20\x20.dops-btn-primary\x20{\x0a\x20\x20\x20\x20padding:8px\x2020px;\x20border-radius:8px;\x20font-size:13px;\x20font-weight:600;\x0a\x20\x20\x20\x20background:linear-gradient(135deg,#1e4060,#1a3050);\x0a\x20\x20\x20\x20border:1px\x20solid\x20color-mix(in\x20srgb,\x20var(--okdb-accent)\x2033%,\x20transparent);\x20color:var(--okdb-accent);\x0a\x20\x20\x20\x20cursor:pointer;\x20display:flex;\x20align-items:center;\x20gap:6px;\x20transition:all\x20.15s;\x0a\x20\x20}\x0a\x20\x20.dops-btn-primary:hover:not(:disabled)\x20{\x20border-color:color-mix(in\x20srgb,\x20var(--okdb-accent)\x2053%,\x20transparent);\x20}\x0a\x20\x20.dops-btn-primary:disabled\x20{\x20opacity:.35;\x20cursor:not-allowed;\x20}\x0a\x20\x20.dops-btn-ghost\x20{\x0a\x20\x20\x20\x20padding:8px\x2016px;\x20border-radius:8px;\x20font-size:13px;\x0a\x20\x20\x20\x20background:transparent;\x20border:1px\x20solid\x20var(--okdb-app-border);\x20opacity:.55;\x20cursor:pointer;\x0a\x20\x20}\x0a\x20\x20.dops-btn-ghost:hover\x20{\x20opacity:.85;\x20}\x0a\x20\x20.dops-spinner\x20{\x0a\x20\x20\x20\x20display:inline-block;\x20width:12px;\x20height:12px;\x0a\x20\x20\x20\x20border:2px\x20solid\x20color-mix(in\x20srgb,\x20var(--okdb-accent)\x2020%,\x20transparent);\x20border-top-color:var(--okdb-accent);\x0a\x20\x20\x20\x20border-radius:50%;\x20animation:dops-spin\x20.6s\x20linear\x20infinite;\x0a\x20\x20}\x0a\x20\x20@keyframes\x20dops-spin\x20{\x20to\x20{\x20transform:rotate(360deg);\x20}\x20}\x0a</style>\x0a'};
|
|
1
|
+
export default{tag:"data-ops-modal",attr:{modal:{},envs:{default:()=>[]},onDone:{},initialTab:{default:"export"}},context(e){function n(){const e=new Date,n=e=>String(e).padStart(2,"0");return`${e.getFullYear()}-${n(e.getMonth()+1)}-${n(e.getDate())}`}return{tab:e.$attr.initialTab||"export",formatBytes:function(e){if(null==e)return"--";const n=["B","KB","MB","GB","TB"];let t=e,o=0;for(;t>=1024&&o<n.length-1;)t/=1024,o++;return t.toFixed(0===o?0:2)+" "+n[o]},get userEnvs(){return(e.$attr.envs||[]).filter(e=>!e.name.startsWith("~"))},typesForEnv(n){const t=(e.$attr.envs||[]).find(e=>e.name===n);return(t?.types||[]).filter(e=>!e.name.startsWith("~")).map(e=>e.name)},exportSelEnvs:{},exportIncludeChanges:!1,exportBusy:!1,exportError:null,exportDone:null,exportSelTypes:{},exportAllTypes:!0,get exportSelectedEnvNames(){return Object.keys(this.exportSelEnvs).filter(e=>this.exportSelEnvs[e])},get exportIsSingleEnv(){return 1===this.exportSelectedEnvNames.length},get exportSingleEnvTypes(){return this.exportIsSingleEnv?this.typesForEnv(this.exportSelectedEnvNames[0]):[]},get exportSelectedTypeNames(){return!this.exportIsSingleEnv||this.exportAllTypes?null:Object.keys(this.exportSelTypes).filter(e=>this.exportSelTypes[e])},get exportCanRun(){return this.exportSelectedEnvNames.length>0&&!this.exportBusy},exportToggleAllEnvs(e){const n={};for(const t of this.userEnvs)n[t.name]=e;this.exportSelEnvs=n},exportToggleAllTypes(e){const n={};for(const t of this.exportSingleEnvTypes)n[t]=e;this.exportSelTypes=n},exportInit(){0===Object.keys(this.exportSelEnvs).length&&this.userEnvs.length&&(this.exportSelEnvs={[this.userEnvs[0].name]:!0})},async runExport(){if(this.exportCanRun){this.exportBusy=!0,this.exportError=null,this.exportDone=null;try{const e=this.exportSelectedEnvNames,n=e.length>1,t=new URLSearchParams;n?t.set("envs",e.join(",")):t.set("env",e[0]),this.exportIncludeChanges&&t.set("includeChanges","true");const o=this.exportSelectedTypeNames;o&&o.length&&t.set("types",o.join(","));const r=await fetch(`${__ENV__.API}/system/export?${t}`);if(!r.ok){const e=await r.json().catch(()=>({}));throw new Error(e?.error?.message||`HTTP ${r.status}`)}const s=await r.blob(),a=URL.createObjectURL(s),p=document.createElement("a"),i=r.headers.get("content-disposition")||"",l=i.match(/filename="?([^"]+)"?/)?.[1]||`okdb-export-${e.join("+")}-${Date.now()}.ndjson`;p.href=a,p.download=l,document.body.appendChild(p),p.click(),document.body.removeChild(p),URL.revokeObjectURL(a);const d=(await s.text()).split("\n").filter(e=>e.trim()).map(e=>{try{return JSON.parse(e)}catch{return null}}).filter(Boolean);this.exportDone={filename:l,bytes:s.size,envCount:n?e.length:1,types:d.filter(e=>"schema"===e.r).length,records:d.filter(e=>"data"===e.r).length,changes:d.filter(e=>"change"===e.r).length}}catch(e){this.exportError=e?.message||String(e)}finally{this.exportBusy=!1}}},importFile:null,importEnvOverride:"",importSelTypes:{},importAllTypes:!0,importDropExisting:!1,importIncludeChanges:!1,importBatchSize:500,importShowAdvanced:!1,importBusy:!1,importError:null,importDone:null,importDragOver:!1,importFileTypes:[],get importSelectedTypeNames(){return this.importAllTypes?null:Object.keys(this.importSelTypes).filter(e=>this.importSelTypes[e])},get canImport(){return!!this.importFile&&!this.importBusy},onDrop(e){e.preventDefault(),this.importDragOver=!1;const n=e.dataTransfer?.files?.[0];n&&this._setImportFile(n)},onDragOver(e){e.preventDefault(),this.importDragOver=!0},onDragLeave(){this.importDragOver=!1},pickFile(){const e=document.createElement("input");e.type="file",e.accept=".ndjson,.jsonl,.json,.txt",e.onchange=e=>{const n=e.target.files?.[0];n&&this._setImportFile(n)},e.click()},async _setImportFile(e){this.importFile=e,this.importError=null,this.importDone=null,this.importFileTypes=[];try{const n=(await e.slice(0,32768).text()).split("\n").filter(e=>e.trim()),t=n.map(e=>{try{return JSON.parse(e)}catch{return null}}).filter(e=>"schema"===e?.r);this.importFileTypes=[...new Set(t.map(e=>e.type))];const o=n.map(e=>{try{return JSON.parse(e)}catch{return null}}).find(e=>"header"===e?.r);o?.envName&&this.importEnvOverride}catch{}},importToggleAllTypes(e){const n={};for(const t of this.importFileTypes)n[t]=e;this.importSelTypes=n},async runImport(){if(this.importFile){this.importBusy=!0,this.importError=null,this.importDone=null;try{const n=new URLSearchParams({dropExisting:String(this.importDropExisting),includeChanges:String(this.importIncludeChanges),batchSize:String(this.importBatchSize||500)});this.importEnvOverride&&n.set("env",this.importEnvOverride);const t=this.importSelectedTypeNames;t&&t.length&&n.set("types",t.join(","));const o=await fetch(`${__ENV__.API}/system/import?${n}`,{method:"POST",headers:{"content-type":"application/x-ndjson"},body:this.importFile}),r=await o.json().catch(()=>({}));if(!o.ok)throw new Error(r?.error?.message||`HTTP ${o.status}`);const s=r.data??r;this.importDone={types:s.types??0,records:s.records??0,changes:s.changes??0},e.$attr.onDone?.()}catch(e){this.importError=e?.message||String(e)}finally{this.importBusy=!1}}},backupMode:"server",backupDestDir:`./okdb-backup-${n()}`,backupSelEnvs:{},backupEnvMode:"all",backupCompact:!0,backupBusy:!1,backupError:null,backupResult:null,backupDlBusy:!1,backupDlError:null,backupDlDone:null,get backupEnvNames(){return"all"===this.backupEnvMode?null:Object.keys(this.backupSelEnvs).filter(e=>this.backupSelEnvs[e])},get canBackup(){return this.backupDestDir.trim().length>0&&!this.backupBusy},get canBackupDl(){return!this.backupDlBusy},async runBackup(){if(this.canBackup){this.backupBusy=!0,this.backupError=null,this.backupResult=null;try{const e=await fetch(`${__ENV__.API}/system/backup`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({destDir:this.backupDestDir.trim(),envNames:this.backupEnvNames,compact:this.backupCompact})}),n=await e.json().catch(()=>({}));if(!e.ok)throw new Error(n?.error?.message||`HTTP ${e.status}`);this.backupResult=n.data??n}catch(e){this.backupError=e?.message||String(e)}finally{this.backupBusy=!1}}},async runDownloadBackup(){this.backupDlBusy=!0,this.backupDlError=null,this.backupDlDone=null;try{const e=this.backupEnvNames,t=new URLSearchParams;e?.length?t.set("envs",e.join(",")):t.set("envs",this.userEnvs.map(e=>e.name).join(","));const o=await fetch(`${__ENV__.API}/system/export?${t}`);if(!o.ok){const e=await o.json().catch(()=>({}));throw new Error(e?.error||`HTTP ${o.status}`)}const r=await o.blob(),s=URL.createObjectURL(r),a=document.createElement("a"),p=o.headers.get("content-disposition")||"",i=p.match(/filename="?([^"]+)"?/)?.[1]||`okdb-backup-${n()}.ndjson`;a.href=s,a.download=i,document.body.appendChild(a),a.click(),document.body.removeChild(a),URL.revokeObjectURL(s),this.backupDlDone={filename:i,bytes:r.size}}catch(e){this.backupDlError=e?.message||String(e)}finally{this.backupDlBusy=!1}},close(){e.$attr.modal.close()},mount(){this.exportInit()}}},template:'\n<div style="min-width:520px; max-width:640px; display:flex; flex-direction:column; gap:0;">\n\n \x3c!-- Tab bar --\x3e\n <div style="display:flex; gap:2px; padding:3px; background:var(--okdb-app-bg-deep); border-radius:9px; margin-bottom:22px; border:1px solid var(--okdb-app-border);">\n <button @click="tab=\'export\'"\n :style="tab===\'export\' ? \'flex:1;background:var(--okdb-app-surface-2);color:var(--okdb-accent);border-color:color-mix(in srgb, var(--okdb-accent) 27%, transparent);font-weight:600;\' : \'flex:1;background:transparent;border-color:transparent;opacity:.5;\'"\n style="padding:7px 0;border-radius:7px;font-size:13px;transition:all .15s;cursor:pointer;">\n ⬇ Export\n </button>\n <button @click="tab=\'import\'"\n :style="tab===\'import\' ? \'flex:1;background:var(--okdb-app-surface-2);color:var(--okdb-accent);border-color:color-mix(in srgb, var(--okdb-accent) 27%, transparent);font-weight:600;\' : \'flex:1;background:transparent;border-color:transparent;opacity:.5;\'"\n style="padding:7px 0;border-radius:7px;font-size:13px;transition:all .15s;cursor:pointer;">\n ⬆ Import\n </button>\n <button @click="tab=\'backup\'"\n :style="tab===\'backup\' ? \'flex:1;background:var(--okdb-app-surface-2);color:var(--okdb-purple);border-color:color-mix(in srgb, var(--okdb-purple) 27%, transparent);font-weight:600;\' : \'flex:1;background:transparent;border-color:transparent;opacity:.5;\'"\n style="padding:7px 0;border-radius:7px;font-size:13px;transition:all .15s;cursor:pointer;">\n 🗄 Backup\n </button>\n </div>\n\n \x3c!-- ═══ EXPORT ═══════════════════════════════════════════════════════════ --\x3e\n <if :="tab === \'export\'">\n <div style="display:flex;flex-direction:column;gap:18px;">\n\n <div style="font-size:12px;opacity:.5;line-height:1.5;">\n Streaming NDJSON export — portable across OKDB versions, importable into any instance.\n </div>\n\n \x3c!-- Environments --\x3e\n <div class="dops-field">\n <div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;">\n <label class="dops-label" style="flex:1;margin:0;">Environments</label>\n <button @click="exportToggleAllEnvs(true)" class="dops-micro">all</button>\n <button @click="exportToggleAllEnvs(false)" class="dops-micro">none</button>\n </div>\n <div style="display:flex;flex-wrap:wrap;gap:6px;">\n <for :="userEnvs" let:e>\n <label\n :style="exportSelEnvs[e.name] ? \'background:var(--okdb-app-surface-2);border-color:color-mix(in srgb, var(--okdb-accent) 33%, transparent);color:#e2eaf4;\' : \'background:var(--okdb-app-surface);border-color:var(--okdb-app-border);opacity:.55;\'"\n style="display:flex;align-items:center;gap:5px;padding:5px 11px;border-radius:999px;font-size:12px;cursor:pointer;border:1px solid;transition:all .12s;user-select:none;">\n <input type="checkbox"\n :checked="!!exportSelEnvs[e.name]"\n @change="exportSelEnvs = {...exportSelEnvs, [e.name]: $el.checked}"\n style="display:none;" />\n <span :style="exportSelEnvs[e.name] ? \'color:var(--okdb-accent);font-size:10px;\' : \'display:none;\'">✓</span>\n {{e.name}}\n <span style="opacity:.4;font-size:10px;">{{e.types ? e.types.filter(t=>!t.name.startsWith(\'~\')).length : 0}} types</span>\n </label>\n </for>\n </div>\n </div>\n\n \x3c!-- Types (only for single env) --\x3e\n <if :="exportIsSingleEnv && exportSingleEnvTypes.length > 0">\n <div class="dops-field">\n <div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;">\n <label class="dops-label" style="flex:1;margin:0;">Types</label>\n <label class="dops-check" style="font-size:11px;gap:4px;">\n <input type="checkbox" :checked="exportAllTypes" @change="exportAllTypes = $el.checked" />\n <span style="opacity:.6;">All types</span>\n </label>\n </div>\n <if :="!exportAllTypes">\n <div style="display:flex;flex-direction:column;gap:0;background:var(--okdb-app-bg-deep);border:1px solid var(--okdb-app-border);border-radius:8px;overflow:hidden;">\n <div style="display:flex;align-items:center;padding:5px 10px;border-bottom:1px solid var(--okdb-app-border);gap:8px;">\n <button @click="exportToggleAllTypes(true)" class="dops-micro">all</button>\n <button @click="exportToggleAllTypes(false)" class="dops-micro">none</button>\n </div>\n <div style="display:flex;flex-direction:column;max-height:140px;overflow-y:auto;">\n <for :="exportSingleEnvTypes" let:t>\n <label style="display:flex;align-items:center;gap:8px;padding:6px 10px;cursor:pointer;transition:background .1s;"\n :style="exportSelTypes[t] ? \'background:#1a2a1a;\' : \'\'"\n @mouseenter="$el.style.background=exportSelTypes[t]?\'#1a2a1a\':\'var(--okdb-app-surface)\'"\n @mouseleave="$el.style.background=exportSelTypes[t]?\'#1a2a1a\':\'\'">\n <input type="checkbox"\n :checked="!!exportSelTypes[t]"\n @change="exportSelTypes = {...exportSelTypes, [t]: $el.checked}" />\n <span style="font-family:monospace;font-size:12px;">{{t}}</span>\n </label>\n </for>\n </div>\n </div>\n </if>\n </div>\n </if>\n <if :="!exportIsSingleEnv && exportSelectedEnvNames.length > 1">\n <div style="font-size:11px;opacity:.4;font-style:italic;">All types will be exported from each selected environment.</div>\n </if>\n\n \x3c!-- Options --\x3e\n <label class="dops-check">\n <input type="checkbox" :checked="exportIncludeChanges" @change="exportIncludeChanges = $el.checked" />\n <span>Include changelog <span style="opacity:.4;font-size:11px;">(sync history)</span></span>\n </label>\n\n <if :="exportError"><div class="dops-error">{{exportError}}</div></if>\n\n \x3c!-- Success --\x3e\n <if :="exportDone">\n <div class="dops-success">\n <div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;">\n <span>✓</span><span style="font-weight:600;">Downloaded</span>\n <span style="opacity:.4;font-size:11px;margin-left:auto;">{{formatBytes(exportDone.bytes)}}</span>\n </div>\n <div style="display:grid;grid-template-columns:repeat(3,1fr);gap:6px;font-size:12px;">\n <if :="exportDone.envCount > 1">\n <div class="dops-stat"><div class="dops-stat-n">{{exportDone.envCount}}</div><div>envs</div></div>\n </if>\n <div class="dops-stat"><div class="dops-stat-n">{{exportDone.types}}</div><div>types</div></div>\n <div class="dops-stat"><div class="dops-stat-n">{{exportDone.records}}</div><div>records</div></div>\n <div class="dops-stat"><div class="dops-stat-n">{{exportDone.changes}}</div><div>changes</div></div>\n </div>\n <div style="font-size:10px;opacity:.35;margin-top:6px;font-family:monospace;word-break:break-all;">{{exportDone.filename}}</div>\n </div>\n </if>\n\n <div style="display:flex;gap:8px;justify-content:flex-end;margin-top:4px;">\n <button @click="close()" class="dops-btn-ghost">Cancel</button>\n <button @click="runExport()" :disabled="!exportCanRun" class="dops-btn-primary">\n <if :="exportBusy"><span class="dops-spinner"></span> Exporting…</if>\n <if :="!exportBusy">⬇ Download NDJSON</if>\n </button>\n </div>\n </div>\n </if>\n\n \x3c!-- ═══ IMPORT ═══════════════════════════════════════════════════════════ --\x3e\n <if :="tab === \'import\'">\n <div style="display:flex;flex-direction:column;gap:18px;">\n\n <div style="font-size:12px;opacity:.5;line-height:1.5;">\n Upload a OKDB NDJSON export. Types, indexes, and records are restored automatically.\n Multi-env files restore each environment separately.\n </div>\n\n \x3c!-- Drop zone --\x3e\n <div @click="pickFile()" @drop="onDrop($event)" @dragover="onDragOver($event)" @dragleave="onDragLeave()"\n :style="importDragOver ? \'border-color:var(--okdb-accent);background:color-mix(in srgb, var(--okdb-accent) 5%, transparent);\' : importFile ? \'border-color:color-mix(in srgb, var(--okdb-success) 33%, transparent);background:#0a1a10;\' : \'border-color:var(--okdb-app-border);background:var(--okdb-app-bg-deep);\'"\n style="border:2px dashed;border-radius:10px;padding:24px 16px;text-align:center;cursor:pointer;transition:all .15s;">\n <if :="!importFile">\n <div style="font-size:22px;opacity:.4;margin-bottom:8px;">📂</div>\n <div style="font-size:13px;opacity:.7;">Drop .ndjson file here or <span style="color:var(--okdb-accent);">click to browse</span></div>\n <div style="font-size:11px;opacity:.3;margin-top:4px;">.ndjson · .jsonl · .json</div>\n </if>\n <if :="importFile">\n <div style="font-size:20px;margin-bottom:6px;">📄</div>\n <div style="font-size:13px;font-weight:600;color:var(--okdb-success);font-family:monospace;word-break:break-all;">{{importFile.name}}</div>\n <div style="font-size:11px;opacity:.45;margin-top:3px;">{{formatBytes(importFile.size)}}\n <if :="importFileTypes.length"> · {{importFileTypes.length}} type{{importFileTypes.length!==1?\'s\':\'\'}} detected</if>\n · click to change</div>\n </if>\n </div>\n\n \x3c!-- Types filter (from file) --\x3e\n <if :="importFileTypes.length > 0">\n <div class="dops-field">\n <div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;">\n <label class="dops-label" style="flex:1;margin:0;">Types to import</label>\n <label class="dops-check" style="font-size:11px;gap:4px;">\n <input type="checkbox" :checked="importAllTypes" @change="importAllTypes = $el.checked" />\n <span style="opacity:.6;">All</span>\n </label>\n </div>\n <if :="!importAllTypes">\n <div style="display:flex;flex-direction:column;gap:0;background:var(--okdb-app-bg-deep);border:1px solid var(--okdb-app-border);border-radius:8px;overflow:hidden;">\n <div style="display:flex;padding:5px 10px;border-bottom:1px solid var(--okdb-app-border);gap:8px;">\n <button @click="importToggleAllTypes(true)" class="dops-micro">all</button>\n <button @click="importToggleAllTypes(false)" class="dops-micro">none</button>\n </div>\n <div style="display:flex;flex-direction:column;max-height:130px;overflow-y:auto;">\n <for :="importFileTypes" let:t>\n <label style="display:flex;align-items:center;gap:8px;padding:6px 10px;cursor:pointer;"\n :style="importSelTypes[t] ? \'background:#1a2a1a;\' : \'\'">\n <input type="checkbox"\n :checked="!!importSelTypes[t]"\n @change="importSelTypes = {...importSelTypes, [t]: $el.checked}" />\n <span style="font-family:monospace;font-size:12px;">{{t}}</span>\n </label>\n </for>\n </div>\n </div>\n </if>\n </div>\n </if>\n\n \x3c!-- Target env override --\x3e\n <div class="dops-field">\n <label class="dops-label">Target environment\n <span style="opacity:.35;font-size:11px;font-weight:400;">(leave empty to use the file\'s source env)</span>\n </label>\n <select :value="importEnvOverride" @change="importEnvOverride = $el.value" class="dops-select">\n <option value="">— from file header —</option>\n <for :="userEnvs" let:e>\n <option :value="e.name">{{e.name}}</option>\n </for>\n </select>\n </div>\n\n \x3c!-- Options --\x3e\n <div style="display:flex;flex-direction:column;gap:7px;">\n <label class="dops-check">\n <input type="checkbox" :checked="importDropExisting" @change="importDropExisting = $el.checked" />\n <span>Drop & recreate existing types <span style="opacity:.4;font-size:11px;">(replaces current data)</span></span>\n </label>\n <label class="dops-check">\n <input type="checkbox" :checked="importIncludeChanges" @change="importIncludeChanges = $el.checked" />\n <span>Restore changelog rows</span>\n </label>\n </div>\n\n \x3c!-- Advanced --\x3e\n <div>\n <button @click="importShowAdvanced=!importShowAdvanced"\n style="font-size:11px;opacity:.4;background:transparent;border:none;padding:0;cursor:pointer;">\n {{importShowAdvanced?\'▴ hide\':\'▾\'}} advanced\n </button>\n <if :="importShowAdvanced">\n <div class="dops-field" style="margin-top:10px;">\n <label class="dops-label">Batch size <span style="opacity:.35;font-size:11px;">(records per write-txn)</span></label>\n <input type="number" min="10" max="10000" step="10"\n :value="importBatchSize" @input="importBatchSize=Number($el.value)||500"\n class="dops-input" style="max-width:120px;" />\n </div>\n </if>\n </div>\n\n <if :="importError"><div class="dops-error">{{importError}}</div></if>\n\n <if :="importDone">\n <div class="dops-success">\n <div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;">\n <span>✓</span><span style="font-weight:600;">Import complete</span>\n </div>\n <div style="display:grid;grid-template-columns:repeat(3,1fr);gap:6px;font-size:12px;">\n <div class="dops-stat"><div class="dops-stat-n">{{importDone.types}}</div><div>types</div></div>\n <div class="dops-stat"><div class="dops-stat-n">{{importDone.records}}</div><div>records</div></div>\n <div class="dops-stat"><div class="dops-stat-n">{{importDone.changes}}</div><div>changes</div></div>\n </div>\n </div>\n </if>\n\n <div style="display:flex;gap:8px;justify-content:flex-end;margin-top:4px;">\n <button @click="close()" class="dops-btn-ghost">Cancel</button>\n <button @click="runImport()" :disabled="!canImport" class="dops-btn-primary">\n <if :="importBusy"><span class="dops-spinner"></span> Importing…</if>\n <if :="!importBusy">⬆ Import File</if>\n </button>\n </div>\n </div>\n </if>\n\n \x3c!-- ═══ BACKUP ════════════════════════════════════════════════════════════ --\x3e\n <if :="tab === \'backup\'">\n <div style="display:flex;flex-direction:column;gap:0;">\n\n \x3c!-- Mode tabs --\x3e\n <div style="display:flex;gap:0;margin-bottom:18px;border-bottom:1px solid var(--okdb-app-border);">\n <button @click="backupMode=\'server\'"\n :style="backupMode===\'server\' ? \'color:var(--okdb-purple);border-bottom:2px solid var(--okdb-purple);opacity:1;\' : \'border-bottom:2px solid transparent;opacity:.45;\'"\n style="padding:6px 16px;background:transparent;border:none;border-radius:0;font-size:13px;cursor:pointer;transition:all .15s;margin-bottom:-1px;">\n 🗄 Server backup\n </button>\n <button @click="backupMode=\'download\'"\n :style="backupMode===\'download\' ? \'color:var(--okdb-purple);border-bottom:2px solid var(--okdb-purple);opacity:1;\' : \'border-bottom:2px solid transparent;opacity:.45;\'"\n style="padding:6px 16px;background:transparent;border:none;border-radius:0;font-size:13px;cursor:pointer;transition:all .15s;margin-bottom:-1px;">\n ⬇ Download to PC\n </button>\n </div>\n\n \x3c!-- Server backup mode --\x3e\n <if :="backupMode === \'server\'">\n <div style="display:flex;flex-direction:column;gap:16px;">\n <div style="font-size:12px;opacity:.5;line-height:1.5;">\n Hot LMDB page-copy backup — atomic, exact snapshot, no serialisation.\n Writes to a directory <em>on the server</em>. The output can be used\n directly as a OKDB data path.\n </div>\n\n \x3c!-- Dest dir --\x3e\n <div class="dops-field">\n <label class="dops-label">Destination directory\n <span style="opacity:.35;font-size:11px;font-weight:400;">(server-side path)</span>\n </label>\n <input type="text" :value="backupDestDir" @input="backupDestDir=$el.value"\n class="dops-input" style="font-family:monospace;" spellcheck="false" />\n </div>\n\n \x3c!-- Env selection --\x3e\n <div class="dops-field">\n <label class="dops-label" style="margin-bottom:8px;">Environments</label>\n <div style="display:flex;gap:12px;margin-bottom:8px;">\n <label class="dops-check">\n <input type="radio" name="bkEnvMode" value="all"\n :checked="backupEnvMode===\'all\'" @change="backupEnvMode=\'all\'" />\n <span>All</span>\n </label>\n <label class="dops-check">\n <input type="radio" name="bkEnvMode" value="selected"\n :checked="backupEnvMode===\'selected\'" @change="backupEnvMode=\'selected\'" />\n <span>Select…</span>\n </label>\n </div>\n <if :="backupEnvMode===\'selected\'">\n <div style="display:flex;flex-wrap:wrap;gap:6px;padding:10px;background:var(--okdb-app-bg-deep);border-radius:8px;border:1px solid var(--okdb-app-border);">\n <for :="userEnvs" let:e>\n <label\n :style="backupSelEnvs[e.name] ? \'background:var(--okdb-app-surface);border-color:color-mix(in srgb, var(--okdb-purple) 27%, transparent);color:#e2d8f4;\' : \'background:var(--okdb-app-surface);border-color:var(--okdb-app-border);opacity:.55;\'"\n style="display:flex;align-items:center;gap:5px;padding:5px 11px;border-radius:999px;font-size:12px;cursor:pointer;border:1px solid;transition:all .12s;user-select:none;">\n <input type="checkbox"\n :checked="!!backupSelEnvs[e.name]"\n @change="backupSelEnvs={...backupSelEnvs,[e.name]:$el.checked}"\n style="display:none;" />\n <span :style="backupSelEnvs[e.name]?\'color:var(--okdb-purple);font-size:10px;\':\'display:none;\'">✓</span>\n {{e.name}}\n </label>\n </for>\n </div>\n </if>\n </div>\n\n <label class="dops-check">\n <input type="checkbox" :checked="backupCompact" @change="backupCompact=$el.checked" />\n <span>Compact while copying <span style="opacity:.4;font-size:11px;">(smaller files, slightly slower)</span></span>\n </label>\n\n <if :="backupError"><div class="dops-error">{{backupError}}</div></if>\n\n <if :="backupResult">\n <div class="dops-success" style="border-color:color-mix(in srgb, var(--okdb-purple) 20%, transparent);">\n <div style="display:flex;align-items:center;gap:8px;margin-bottom:10px;">\n <span>✓</span>\n <span style="font-weight:600;color:var(--okdb-app-fg);">Server backup complete</span>\n <span style="opacity:.4;font-size:11px;margin-left:auto;">{{backupResult.durationMs}}ms</span>\n </div>\n <div style="display:flex;flex-direction:column;gap:4px;">\n <for :="backupResult.envs||[]" let:e>\n <div style="background:#1a1228;border-radius:6px;padding:7px 10px;font-size:12px;">\n <div style="display:flex;gap:8px;align-items:center;">\n <span style="font-family:monospace;font-weight:600;color:var(--okdb-purple);">{{e.name}}</span>\n <span style="opacity:.35;font-size:11px;">{{formatBytes(e.sizeBefore)}} → {{formatBytes(e.sizeAfter)}}</span>\n </div>\n <div style="font-family:monospace;font-size:10px;opacity:.4;margin-top:3px;word-break:break-all;">{{e.dest}}</div>\n </div>\n </for>\n </div>\n </div>\n </if>\n\n <div style="display:flex;gap:8px;justify-content:flex-end;margin-top:4px;">\n <button @click="close()" class="dops-btn-ghost">Cancel</button>\n <button @click="runBackup()" :disabled="!canBackup"\n style="padding:8px 20px;border-radius:8px;font-size:13px;font-weight:600;background:linear-gradient(135deg,#1e1530,#150f22);border:1px solid color-mix(in srgb, var(--okdb-purple) 33%, transparent);color:var(--okdb-purple);cursor:pointer;display:flex;align-items:center;gap:6px;transition:all .15s;">\n <if :="backupBusy"><span class="dops-spinner" style="border-color:color-mix(in srgb, var(--okdb-purple) 27%, transparent);border-top-color:var(--okdb-purple);"></span> Backing up…</if>\n <if :="!backupBusy">🗄 Run Server Backup</if>\n </button>\n </div>\n </div>\n </if>\n\n \x3c!-- Download backup mode --\x3e\n <if :="backupMode === \'download\'">\n <div style="display:flex;flex-direction:column;gap:16px;">\n <div style="font-size:12px;opacity:.5;line-height:1.5;">\n Export all environments as a single portable NDJSON file and download it to your computer.\n This file can be imported back into any OKDB instance.\n </div>\n\n \x3c!-- Env selection --\x3e\n <div class="dops-field">\n <label class="dops-label" style="margin-bottom:8px;">Environments to include</label>\n <div style="display:flex;gap:12px;margin-bottom:8px;">\n <label class="dops-check">\n <input type="radio" name="dlEnvMode" value="all"\n :checked="backupEnvMode===\'all\'" @change="backupEnvMode=\'all\'" />\n <span>All environments</span>\n </label>\n <label class="dops-check">\n <input type="radio" name="dlEnvMode" value="selected"\n :checked="backupEnvMode===\'selected\'" @change="backupEnvMode=\'selected\'" />\n <span>Select…</span>\n </label>\n </div>\n <if :="backupEnvMode===\'selected\'">\n <div style="display:flex;flex-wrap:wrap;gap:6px;padding:10px;background:var(--okdb-app-bg-deep);border-radius:8px;border:1px solid var(--okdb-app-border);">\n <for :="userEnvs" let:e>\n <label\n :style="backupSelEnvs[e.name] ? \'background:var(--okdb-app-surface);border-color:color-mix(in srgb, var(--okdb-purple) 27%, transparent);\' : \'background:var(--okdb-app-surface);border-color:var(--okdb-app-border);opacity:.55;\'"\n style="display:flex;align-items:center;gap:5px;padding:5px 11px;border-radius:999px;font-size:12px;cursor:pointer;border:1px solid;transition:all .12s;user-select:none;">\n <input type="checkbox"\n :checked="!!backupSelEnvs[e.name]"\n @change="backupSelEnvs={...backupSelEnvs,[e.name]:$el.checked}"\n style="display:none;" />\n <span :style="backupSelEnvs[e.name]?\'color:var(--okdb-purple);font-size:10px;\':\'display:none;\'">✓</span>\n {{e.name}}\n </label>\n </for>\n </div>\n </if>\n </div>\n\n <if :="backupDlError"><div class="dops-error">{{backupDlError}}</div></if>\n\n <if :="backupDlDone">\n <div class="dops-success" style="border-color:color-mix(in srgb, var(--okdb-purple) 20%, transparent);">\n <div style="display:flex;align-items:center;gap:8px;">\n <span>✓</span>\n <span style="font-weight:600;color:var(--okdb-app-fg);">Downloaded</span>\n <span style="opacity:.4;font-size:11px;">{{formatBytes(backupDlDone.bytes)}}</span>\n </div>\n <div style="font-family:monospace;font-size:10px;opacity:.35;margin-top:5px;word-break:break-all;">{{backupDlDone.filename}}</div>\n </div>\n </if>\n\n <div style="display:flex;gap:8px;justify-content:flex-end;margin-top:4px;">\n <button @click="close()" class="dops-btn-ghost">Cancel</button>\n <button @click="runDownloadBackup()" :disabled="!canBackupDl"\n style="padding:8px 20px;border-radius:8px;font-size:13px;font-weight:600;background:linear-gradient(135deg,#1e1530,#150f22);border:1px solid color-mix(in srgb, var(--okdb-purple) 33%, transparent);color:var(--okdb-purple);cursor:pointer;display:flex;align-items:center;gap:6px;transition:all .15s;">\n <if :="backupDlBusy"><span class="dops-spinner" style="border-color:color-mix(in srgb, var(--okdb-purple) 27%, transparent);border-top-color:var(--okdb-purple);"></span> Downloading…</if>\n <if :="!backupDlBusy">⬇ Download Backup</if>\n </button>\n </div>\n </div>\n </if>\n\n </div>\n </if>\n\n</div>\n\n<style>\n .dops-field { display:flex; flex-direction:column; gap:5px; }\n .dops-label { font-size:12px; opacity:.6; font-weight:500; }\n .dops-input {\n background:var(--okdb-app-bg-deep); border:1px solid var(--okdb-app-border); border-radius:6px;\n color:inherit; padding:7px 10px; font-size:13px; width:100%;\n box-sizing:border-box; transition:border-color .15s;\n }\n .dops-input:focus { outline:none; border-color:color-mix(in srgb, var(--okdb-accent) 33%, transparent); }\n .dops-select {\n background:var(--okdb-app-bg-deep); border:1px solid var(--okdb-app-border); border-radius:6px;\n color:inherit; padding:7px 10px; font-size:13px; width:100%; box-sizing:border-box; cursor:pointer;\n }\n .dops-select:focus { outline:none; border-color:color-mix(in srgb, var(--okdb-accent) 33%, transparent); }\n .dops-check { display:flex; align-items:center; gap:8px; font-size:13px; cursor:pointer; user-select:none; }\n .dops-micro {\n padding:2px 8px; border-radius:4px; font-size:10px; background:transparent;\n border:1px solid var(--okdb-app-border); opacity:.5; cursor:pointer; transition:opacity .1s;\n }\n .dops-micro:hover { opacity:.85; }\n .dops-error {\n background:#2a1010; border:1px solid color-mix(in srgb, var(--okdb-danger) 27%, transparent); border-radius:8px;\n padding:10px 12px; font-size:12px; color:var(--okdb-danger); line-height:1.5;\n }\n .dops-success {\n background:#0d1a14; border:1px solid color-mix(in srgb, var(--okdb-success) 20%, transparent); border-radius:8px;\n padding:12px 14px; font-size:13px; color:#d1fae5;\n }\n .dops-stat {\n background:#071410; border-radius:6px; padding:8px; text-align:center; font-size:11px; opacity:.8;\n }\n .dops-stat-n { font-size:18px; font-weight:700; color:var(--okdb-success); }\n .dops-btn-primary {\n padding:8px 20px; border-radius:8px; font-size:13px; font-weight:600;\n background:linear-gradient(135deg,#1e4060,#1a3050);\n border:1px solid color-mix(in srgb, var(--okdb-accent) 33%, transparent); color:var(--okdb-accent);\n cursor:pointer; display:flex; align-items:center; gap:6px; transition:all .15s;\n }\n .dops-btn-primary:hover:not(:disabled) { border-color:color-mix(in srgb, var(--okdb-accent) 53%, transparent); }\n .dops-btn-primary:disabled { opacity:.35; cursor:not-allowed; }\n .dops-btn-ghost {\n padding:8px 16px; border-radius:8px; font-size:13px;\n background:transparent; border:1px solid var(--okdb-app-border); opacity:.55; cursor:pointer;\n }\n .dops-btn-ghost:hover { opacity:.85; }\n .dops-spinner {\n display:inline-block; width:12px; height:12px;\n border:2px solid color-mix(in srgb, var(--okdb-accent) 20%, transparent); border-top-color:var(--okdb-accent);\n border-radius:50%; animation:dops-spin .6s linear infinite;\n }\n @keyframes dops-spin { to { transform:rotate(360deg); } }\n</style>\n'};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const _0x38fc0b=_0x27ff;function _0x27ff(_0x136fa6,_0xe52102){_0x136fa6=_0x136fa6-0x1bc;const _0x5d0176=_0x5d01();let _0x27ff05=_0x5d0176[_0x136fa6];return _0x27ff05;}function _0x5d01(){const _0x2dbc5c=['var(--okdb-danger)','loading','\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;flex-direction:column;height:100%;min-height:0;\x22>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20──\x20Detail\x20view\x20──\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22selected\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;flex-direction:column;height:100%;min-height:0;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Back\x20bar\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;align-items:center;gap:12px;margin-bottom:16px;flex-shrink:0;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@click=\x22back()\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22display:flex;align-items:center;gap:5px;font-size:12px;padding:5px\x2012px;color:var(--okdb-accent-muted);border-color:var(--okdb-app-border);border-radius:6px;background:transparent;cursor:pointer;transition:background\x20.12s;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20class=\x22api-back-btn\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20←\x20Routes\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:12px;font-family:monospace;opacity:.6;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20:style=\x22\x27color:\x27+methodColor(selected.method)+\x27;font-weight:700;\x27\x22>{{\x20selected.method\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20selected.path\x20}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<api-endpoint\x20:endpoint=\x22selected\x22\x20style=\x22flex:1;min-height:0;overflow:auto;\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20──\x20List\x20view\x20──\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22!selected\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;flex-direction:column;gap:14px;height:100%;min-height:0;\x22>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Search\x20bar\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;align-items:center;gap:10px;flex-shrink:0;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type=\x22text\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20placeholder=\x22Filter\x20routes…\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20!value=\x22search\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@input=\x22search\x20=\x20$el.value\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22flex:1;background:var(--okdb-app-bg-deep);border:1px\x20solid\x20var(--okdb-app-border);border-radius:7px;padding:7px\x2012px;color:var(--okdb-app-fg);font-size:12px;outline:none;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22loading\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<ok-icon\x20name=\x22loader\x22\x20class=\x22spin\x22\x20style=\x22width:18px;height:18px;opacity:.5;flex-shrink:0;\x22></ok-icon>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22routes.length\x20>\x200\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:11px;opacity:.35;white-space:nowrap;flex-shrink:0;\x22>{{\x20filtered.length\x20}}\x20/\x20{{\x20routes.length\x20}}\x20routes</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Error\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22error\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22color:var(--okdb-danger);font-size:12px;padding:8px;border:1px\x20solid\x20color-mix(in\x20srgb,\x20var(--okdb-danger)\x2020%,\x20transparent);border-radius:6px;flex-shrink:0;\x22>{{\x20error\x20}}</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Route\x20groups\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:18px;padding-bottom:12px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<each\x20:of=\x22groups\x22\x20let:item=\x22g\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:10px;text-transform:uppercase;letter-spacing:.07em;opacity:.38;margin-bottom:6px;padding:0\x204px;\x22>{{\x20g.tag\x20}}</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:grid;grid-template-columns:repeat(auto-fill,\x20minmax(260px,\x201fr));gap:2px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<each\x20:of=\x22g.routes\x22\x20let:item=\x22r\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@click=\x22select(r)\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:title=\x22r.meta?.summary\x20||\x20r.path\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20class=\x22api-route-card\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20:style=\x22\x27font-size:10px;font-weight:700;width:42px;flex-shrink:0;text-align:center;color:\x27+methodColor(r.method)+\x27;\x27\x22>{{\x20r.method\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;flex-direction:column;min-width:0;flex:1;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-family:monospace;font-size:11px;color:var(--okdb-accent-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22optionalHint(r.path)\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.3;\x22>{{\x20optionalHint(r.path)\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>{{\x20shortPath(r.path)\x20}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22r.meta?.summary\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:11px;color:var(--okdb-app-fg-faint);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:1px;\x22>{{\x20r.meta.summary\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</each>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</each>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22!loading\x20&&\x20routes.length\x20===\x200\x20&&\x20!error\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;opacity:.4;padding:8px;\x22>No\x20routes\x20loaded.</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20','summary','has','includes','sort','filtered','var(--okdb-accent)','system-api-panel','Failed\x20to\x20load\x20routes','json','3486qSpwOQ','11QWXciJ','routes','34ZQMOvJ','2471EoOqtH','queue','data','552630VBVFvI','push','method','toLowerCase','changelog','search','4303huhImz','fts','var(--okdb-indigo)','system','path','trim','25ywmobf','var(--okdb-warning)','indexes','localeCompare','var(--okdb-success)','load','tags','get','27918UBDKQM','indexOf','error','some','entries','replace','message','docs','584afepOl','selected','251504FaivlH','API','meta','3244490pVQNhj','filter','/docs','set','embeddings','sync','tagOrder','5382324wKcidc'];_0x5d01=function(){return _0x2dbc5c;};return _0x5d01();}(function(_0x5b5ba9,_0x228206){const _0x14cb29=_0x27ff,_0x7ebfc7=_0x5b5ba9();while(!![]){try{const _0x50bd5d=-parseInt(_0x14cb29(0x1cc))/0x1*(parseInt(_0x14cb29(0x1c2))/0x2)+-parseInt(_0x14cb29(0x1c6))/0x3+parseInt(_0x14cb29(0x1e4))/0x4*(parseInt(_0x14cb29(0x1d2))/0x5)+-parseInt(_0x14cb29(0x1bf))/0x6*(parseInt(_0x14cb29(0x1c3))/0x7)+-parseInt(_0x14cb29(0x1e2))/0x8*(-parseInt(_0x14cb29(0x1da))/0x9)+-parseInt(_0x14cb29(0x1e7))/0xa+-parseInt(_0x14cb29(0x1c0))/0xb*(-parseInt(_0x14cb29(0x1ee))/0xc);if(_0x50bd5d===_0x228206)break;else _0x7ebfc7['push'](_0x7ebfc7['shift']());}catch(_0x1ee640){_0x7ebfc7['push'](_0x7ebfc7['shift']());}}}(_0x5d01,0x316d2));import _0x15c568 from'../../api/parts/api-endpoint.ok.js';import _0x2de67d from'@toolkit/elements/ok-icon.ok.js';export default{'tag':_0x38fc0b(0x1bc),'unwrap':!0x0,'dependencies':[_0x15c568,_0x2de67d],'context':()=>({'routes':[],'loading':!0x1,'error':null,'selected':null,'search':'','tagOrder':[_0x38fc0b(0x1cf),'types',_0x38fc0b(0x1c5),_0x38fc0b(0x1ca),_0x38fc0b(0x1d4),_0x38fc0b(0x1cd),_0x38fc0b(0x1c4),'pipelines',_0x38fc0b(0x1ec),_0x38fc0b(0x1eb),'envs',_0x38fc0b(0x1e1)],async 'load'(){const _0x6ff82c=_0x38fc0b;this[_0x6ff82c(0x1f0)]=!0x0,this[_0x6ff82c(0x1dc)]=null;try{const _0x322c4d=await fetch(__ENV__[_0x6ff82c(0x1e5)]+_0x6ff82c(0x1e9)),_0x1f4b09=await _0x322c4d[_0x6ff82c(0x1be)]();if(!_0x322c4d['ok'])throw new Error(_0x1f4b09?.['error']?.[_0x6ff82c(0x1e0)]||_0x6ff82c(0x1bd));this[_0x6ff82c(0x1c1)]=_0x1f4b09[_0x6ff82c(0x1c5)]??[];}catch(_0xa25172){this[_0x6ff82c(0x1dc)]=_0xa25172?.['message']||String(_0xa25172);}finally{this['loading']=!0x1;}},get 'filtered'(){const _0x2811ae=_0x38fc0b,_0x3fc193=this[_0x2811ae(0x1cb)][_0x2811ae(0x1d1)]()[_0x2811ae(0x1c9)]();return _0x3fc193?this['routes'][_0x2811ae(0x1e8)](_0x43c4e6=>_0x43c4e6[_0x2811ae(0x1d0)]['toLowerCase']()[_0x2811ae(0x1f4)](_0x3fc193)||_0x43c4e6[_0x2811ae(0x1c8)][_0x2811ae(0x1c9)]()[_0x2811ae(0x1f4)](_0x3fc193)||(_0x43c4e6[_0x2811ae(0x1e6)]?.[_0x2811ae(0x1f2)]||'')[_0x2811ae(0x1c9)]()[_0x2811ae(0x1f4)](_0x3fc193)||(_0x43c4e6['meta']?.[_0x2811ae(0x1d8)]||[])[_0x2811ae(0x1dd)](_0x4044d8=>_0x4044d8[_0x2811ae(0x1f4)](_0x3fc193))):this[_0x2811ae(0x1c1)];},get 'groups'(){const _0x139061=_0x38fc0b,_0x4338ca=new Map();for(const _0x40aef4 of this[_0x139061(0x1f6)]){const _0x1a4cec=_0x40aef4[_0x139061(0x1e6)]?.[_0x139061(0x1d8)]?.[0x0]??'other';_0x4338ca[_0x139061(0x1f3)](_0x1a4cec)||_0x4338ca[_0x139061(0x1ea)](_0x1a4cec,[]),_0x4338ca[_0x139061(0x1d9)](_0x1a4cec)[_0x139061(0x1c7)](_0x40aef4);}return[..._0x4338ca[_0x139061(0x1de)]()][_0x139061(0x1f5)](([_0x15c9f0],[_0xcca43d])=>{const _0x3c94bb=_0x139061,_0x51b132=this['tagOrder'][_0x3c94bb(0x1db)](_0x15c9f0),_0x2ef496=this[_0x3c94bb(0x1ed)][_0x3c94bb(0x1db)](_0xcca43d);return-0x1===_0x51b132&&-0x1===_0x2ef496?_0x15c9f0[_0x3c94bb(0x1d5)](_0xcca43d):-0x1===_0x51b132?0x1:-0x1===_0x2ef496?-0x1:_0x51b132-_0x2ef496;})['map'](([_0x4a25d6,_0x4678e8])=>({'tag':_0x4a25d6,'routes':_0x4678e8}));},'methodColor':_0x2ddcb5=>({'GET':_0x38fc0b(0x1f7),'POST':_0x38fc0b(0x1d6),'PUT':_0x38fc0b(0x1d3),'PATCH':_0x38fc0b(0x1ce),'DELETE':_0x38fc0b(0x1ef)}[_0x2ddcb5]||'var(--okdb-app-fg-muted)'),'select'(_0x1e2bc6){const _0x5a4e86=_0x38fc0b;this[_0x5a4e86(0x1e3)]=null,setTimeout(()=>{const _0x4ad66d=_0x5a4e86;this[_0x4ad66d(0x1e3)]=_0x1e2bc6;},0x0);},'back'(){const _0x5705dd=_0x38fc0b;this[_0x5705dd(0x1e3)]=null;},'shortPath':_0x3b70a4=>_0x3b70a4[_0x38fc0b(0x1df)](/^\/api/,'')[_0x38fc0b(0x1df)](/\[[^\]]*\]/g,''),'optionalHint'(_0x99f12a){const _0x5022e9=_0x38fc0b,_0x48d4e7=_0x99f12a['match'](/\[([^\]]*)\]/);return _0x48d4e7?_0x48d4e7[0x1][_0x5022e9(0x1df)](/=\w+/g,''):null;}}),'init'(){const _0x107756=_0x38fc0b;this[_0x107756(0x1d7)]();},'template':_0x38fc0b(0x1f1),'style':'.api-back-btn:hover{background:var(--okdb-app-surface-2)!important;border-color:var(--okdb-app-border-strong)!important}.api-route-card{display:flex;align-items:center;gap:8px;padding:7px\x2010px;background:0\x200;border:1px\x20solid\x20transparent;border-radius:6px;cursor:pointer;text-align:left;min-width:0;transition:background\x20.1s,border-color\x20.1s}.api-route-card:hover{background:var(--okdb-app-bg-deep);border-color:var(--okdb-app-border)}'};
|
|
1
|
+
import e from"../../api/parts/api-endpoint.ok.js";import t from"@toolkit/elements/ok-icon.ok.js";export default{tag:"system-api-panel",unwrap:!0,dependencies:[e,t],context:()=>({routes:[],loading:!1,error:null,selected:null,search:"",tagOrder:["system","types","data","changelog","indexes","fts","queue","pipelines","sync","embeddings","envs","docs"],async load(){this.loading=!0,this.error=null;try{const e=await fetch(`${__ENV__.API}/docs`),t=await e.json();if(!e.ok)throw new Error(t?.error?.message||"Failed to load routes");this.routes=t.data??[]}catch(e){this.error=e?.message||String(e)}finally{this.loading=!1}},get filtered(){const e=this.search.trim().toLowerCase();return e?this.routes.filter(t=>t.path.toLowerCase().includes(e)||t.method.toLowerCase().includes(e)||(t.meta?.summary||"").toLowerCase().includes(e)||(t.meta?.tags||[]).some(t=>t.includes(e))):this.routes},get groups(){const e=new Map;for(const t of this.filtered){const n=t.meta?.tags?.[0]??"other";e.has(n)||e.set(n,[]),e.get(n).push(t)}return[...e.entries()].sort(([e],[t])=>{const n=this.tagOrder.indexOf(e),o=this.tagOrder.indexOf(t);return-1===n&&-1===o?e.localeCompare(t):-1===n?1:-1===o?-1:n-o}).map(([e,t])=>({tag:e,routes:t}))},methodColor:e=>({GET:"var(--okdb-accent)",POST:"var(--okdb-success)",PUT:"var(--okdb-warning)",PATCH:"var(--okdb-indigo)",DELETE:"var(--okdb-danger)"}[e]||"var(--okdb-app-fg-muted)"),select(e){this.selected=null,setTimeout(()=>{this.selected=e},0)},back(){this.selected=null},shortPath:e=>e.replace(/^\/api/,"").replace(/\[[^\]]*\]/g,""),optionalHint(e){const t=e.match(/\[([^\]]*)\]/);return t?t[1].replace(/=\w+/g,""):null}}),init(){this.load()},template:'\n <div style="display:flex;flex-direction:column;height:100%;min-height:0;">\n\n \x3c!-- ── Detail view ── --\x3e\n <if :="selected">\n <div style="display:flex;flex-direction:column;height:100%;min-height:0;">\n \x3c!-- Back bar --\x3e\n <div style="display:flex;align-items:center;gap:12px;margin-bottom:16px;flex-shrink:0;">\n <button\n @click="back()"\n style="display:flex;align-items:center;gap:5px;font-size:12px;padding:5px 12px;color:var(--okdb-accent-muted);border-color:var(--okdb-app-border);border-radius:6px;background:transparent;cursor:pointer;transition:background .12s;"\n class="api-back-btn"\n >\n ← Routes\n </button>\n <span style="font-size:12px;font-family:monospace;opacity:.6;">\n <span :style="\'color:\'+methodColor(selected.method)+\';font-weight:700;\'">{{ selected.method }}</span>\n {{ selected.path }}\n </span>\n </div>\n <api-endpoint :endpoint="selected" style="flex:1;min-height:0;overflow:auto;" />\n </div>\n </if>\n\n \x3c!-- ── List view ── --\x3e\n <if :="!selected">\n <div style="display:flex;flex-direction:column;gap:14px;height:100%;min-height:0;">\n\n \x3c!-- Search bar --\x3e\n <div style="display:flex;align-items:center;gap:10px;flex-shrink:0;">\n <input\n type="text"\n placeholder="Filter routes…"\n !value="search"\n @input="search = $el.value"\n style="flex:1;background:var(--okdb-app-bg-deep);border:1px solid var(--okdb-app-border);border-radius:7px;padding:7px 12px;color:var(--okdb-app-fg);font-size:12px;outline:none;"\n />\n <if :="loading">\n <ok-icon name="loader" class="spin" style="width:18px;height:18px;opacity:.5;flex-shrink:0;"></ok-icon>\n </if>\n <if :="routes.length > 0">\n <span style="font-size:11px;opacity:.35;white-space:nowrap;flex-shrink:0;">{{ filtered.length }} / {{ routes.length }} routes</span>\n </if>\n </div>\n\n \x3c!-- Error --\x3e\n <if :="error">\n <div style="color:var(--okdb-danger);font-size:12px;padding:8px;border:1px solid color-mix(in srgb, var(--okdb-danger) 20%, transparent);border-radius:6px;flex-shrink:0;">{{ error }}</div>\n </if>\n\n \x3c!-- Route groups --\x3e\n <div style="flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:18px;padding-bottom:12px;">\n <each :of="groups" let:item="g">\n <div>\n <div style="font-size:10px;text-transform:uppercase;letter-spacing:.07em;opacity:.38;margin-bottom:6px;padding:0 4px;">{{ g.tag }}</div>\n <div style="display:grid;grid-template-columns:repeat(auto-fill, minmax(260px, 1fr));gap:2px;">\n <each :of="g.routes" let:item="r">\n <button\n @click="select(r)"\n :title="r.meta?.summary || r.path"\n class="api-route-card"\n >\n <span :style="\'font-size:10px;font-weight:700;width:42px;flex-shrink:0;text-align:center;color:\'+methodColor(r.method)+\';\'">{{ r.method }}</span>\n <div style="display:flex;flex-direction:column;min-width:0;flex:1;">\n <span style="font-family:monospace;font-size:11px;color:var(--okdb-accent-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">\n <if :="optionalHint(r.path)">\n <span style="opacity:.3;">{{ optionalHint(r.path) }}</span>\n </if>{{ shortPath(r.path) }}\n </span>\n <if :="r.meta?.summary">\n <span style="font-size:11px;color:var(--okdb-app-fg-faint);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:1px;">{{ r.meta.summary }}</span>\n </if>\n </div>\n </button>\n </each>\n </div>\n </div>\n </each>\n <if :="!loading && routes.length === 0 && !error">\n <div style="font-size:12px;opacity:.4;padding:8px;">No routes loaded.</div>\n </if>\n </div>\n\n </div>\n </if>\n\n </div>\n ',style:".api-back-btn:hover{background:var(--okdb-app-surface-2)!important;border-color:var(--okdb-app-border-strong)!important}.api-route-card{display:flex;align-items:center;gap:8px;padding:7px 10px;background:0 0;border:1px solid transparent;border-radius:6px;cursor:pointer;text-align:left;min-width:0;transition:background .1s,border-color .1s}.api-route-card:hover{background:var(--okdb-app-bg-deep);border-color:var(--okdb-app-border)}"};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import e from"../../auth/parts/token-list.ok.js";import t from"../../auth/parts/token-detail.ok.js";import o from"../../auth/modals/create-token-modal.ok.js";import n from"../../auth/modals/edit-token-modal.ok.js";export default{tag:"system-auth-panel",unwrap:!0,dependencies:[e,t,o,n],context:e=>({selectedToken:null,tokenListEl:null,selectedTokenId:null,selectToken(e){this.selectedToken=e??null,this.selectedTokenId=e?.id??null},async openCreateModal(){await e.$ok.shared.modal.open({owner:e,title:"Create Token",content:'<create-token-modal :modal="modal" :on-done="onDone" />',context:e=>({modal:e,onDone:async e=>{if(e?.id){const t=this.tokenListEl?.$scope?.$innerContext;t&&(t._selectedId=e.id),this.selectToken(e)}await(this.tokenListEl?.$scope?.$innerContext?.load?.())}})})},async openEditModal(t){await e.$ok.shared.modal.open({owner:e,title:`Edit Token: ${t.label||"Unnamed"}`,content:'<edit-token-modal :modal="modal" :token="token" :on-done="onDone" />',context:e=>({modal:e,token:t,onDone:async()=>{await(this.tokenListEl?.$scope?.$innerContext?.load?.())}})})},async deleteToken(t){try{const o=await fetch(`${__ENV__.API}/auth/tokens/${encodeURIComponent(t)}`,{method:"DELETE"});if(!o.ok){const e=await o.json();throw new Error(e?.error?.message||"Failed to delete token")}e.$ok.shared?.toast?.success?.("Token deleted"),this.selectToken(null),await(this.tokenListEl?.$scope?.$innerContext?.load?.())}catch(t){e.$ok.shared?.toast?.error?.(t?.message||"Delete failed")}}}),template:'\n <div style="display:flex;gap:0;height:100%;min-height:0;">\n\n \x3c!-- Left: token list --\x3e\n <div style="width:240px;flex-shrink:0;border-right:1px solid var(--okdb-app-surface-2);display:flex;flex-direction:column;gap:8px;padding-right:12px;min-height:0;overflow:hidden;">\n <button\n @click="openCreateModal()"\n style="flex-shrink:0;padding:6px 10px;border:1px solid var(--okdb-app-border);border-radius:6px;background:transparent;color:var(--okdb-accent-muted);font-size:12px;font-weight:500;cursor:pointer;text-align:left;width:100%;transition:background .12s,border-color .12s,color .12s;"\n class="auth-panel-btn"\n >\n + New Token\n </button>\n <token-list\n :ref="tokenListEl = $el"\n :selected-id="selectedTokenId"\n @selected="selectToken($event.detail)"\n style="flex:1;min-height:0;"\n />\n </div>\n\n \x3c!-- Right: token detail --\x3e\n <div style="flex:1;min-width:0;padding-left:18px;overflow:auto;">\n <token-detail\n :token="selectedToken"\n @edit="openEditModal($event.detail)"\n @delete="deleteToken($event.detail)"\n />\n </div>\n\n </div>\n ',style:".auth-panel-btn:hover{background:var(--okdb-app-surface-2)!important;border-color:var(--okdb-app-border-strong)!important;color:var(--okdb-accent-muted)!important}"};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const _0x24e017=_0x259b;(function(_0x342f59,_0xcb02d4){const _0x339fb3=_0x259b,_0x3c874d=_0x342f59();while(!![]){try{const _0x2af39=-parseInt(_0x339fb3(0x224))/0x1*(-parseInt(_0x339fb3(0x218))/0x2)+parseInt(_0x339fb3(0x1fb))/0x3*(parseInt(_0x339fb3(0x215))/0x4)+parseInt(_0x339fb3(0x226))/0x5+-parseInt(_0x339fb3(0x1ff))/0x6+parseInt(_0x339fb3(0x1f4))/0x7+-parseInt(_0x339fb3(0x221))/0x8*(parseInt(_0x339fb3(0x200))/0x9)+-parseInt(_0x339fb3(0x22f))/0xa*(parseInt(_0x339fb3(0x207))/0xb);if(_0x2af39===_0xcb02d4)break;else _0x3c874d['push'](_0x3c874d['shift']());}catch(_0x39fe8a){_0x3c874d['push'](_0x3c874d['shift']());}}}(_0x191c,0x78349));function _0x259b(_0x53f175,_0x3be59c){_0x53f175=_0x53f175-0x1f3;const _0x191cc1=_0x191c();let _0x259bb3=_0x191cc1[_0x53f175];return _0x259bb3;}const e={'info':'var(--okdb-accent)','warn':_0x24e017(0x20c),'error':_0x24e017(0x22a),'debug':_0x24e017(0x202)},t={'1h':0x36ee80,'6h':0x1499700,'24h':0x5265c00,'7d':0x240c8400,'all':null};function _0x191c(){const _0x45cad9=['cursor','2032yByHSA','loading','filter','1418swGcLU','totalCount','indexOf','push','all','error','\x0a<div\x20class=\x22history\x22>\x0a\x0a\x20\x20<!--\x20Toolbar\x20row\x201:\x20filters\x20-->\x0a\x20\x20<div\x20class=\x22history__toolbar\x22>\x0a\x20\x20\x20\x20<span\x20class=\x22history__title\x22>History</span>\x0a\x0a\x20\x20\x20\x20<!--\x20Time\x20range\x20-->\x0a\x20\x20\x20\x20<div\x20class=\x22history__group\x22>\x0a\x20\x20\x20\x20\x20\x20<span\x20class=\x22history__label\x22>Time</span>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22history__pills\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22setTimeRange(\x271h\x27)\x22\x20:class=\x22timeRange===\x271h\x27\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>1h</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22setTimeRange(\x276h\x27)\x22\x20:class=\x22timeRange===\x276h\x27\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>6h</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22setTimeRange(\x2724h\x27)\x22\x20:class=\x22timeRange===\x2724h\x27\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>24h</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22setTimeRange(\x277d\x27)\x22\x20:class=\x22timeRange===\x277d\x27\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>7d</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22setTimeRange(\x27all\x27)\x22\x20:class=\x22timeRange===\x27all\x27\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>All</button>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20<div\x20class=\x22history__spacer\x22></div>\x0a\x0a\x20\x20\x20\x20<!--\x20Refresh\x20and\x20count\x20-->\x0a\x20\x20\x20\x20<button\x20@click=\x22resetAndLoad()\x22\x20:disabled=\x22loading\x22\x20class=\x22pill\x22\x20style=\x22white-space:nowrap;\x22>↻\x20Refresh</button>\x0a\x20\x20\x20\x20<span\x20class=\x22history__count\x22>{{\x20totalCount\x20}}</span>\x0a\x20\x20</div>\x0a\x0a\x20\x20<!--\x20Toolbar\x20row\x202:\x20level\x20filter\x20-->\x0a\x20\x20<div\x20class=\x22history__toolbar\x20history__toolbar--sub\x22>\x0a\x20\x20\x20\x20<span\x20class=\x22history__label\x22>Level</span>\x0a\x20\x20\x20\x20<div\x20class=\x22history__pills\x22>\x0a\x20\x20\x20\x20\x20\x20<button\x20@click=\x22clearLevels()\x22\x20:class=\x22levels.length\x20===\x200\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>All</button>\x0a\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleLevel(\x27info\x27)\x22\x20:class=\x22levels.includes(\x27info\x27)\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:var(--okdb-accent)\x22>info</button>\x0a\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleLevel(\x27warn\x27)\x22\x20:class=\x22levels.includes(\x27warn\x27)\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:var(--okdb-warning)\x22>warn</button>\x0a\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleLevel(\x27error\x27)\x22\x20:class=\x22levels.includes(\x27error\x27)\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:var(--okdb-danger)\x22>error</button>\x0a\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleLevel(\x27debug\x27)\x22\x20:class=\x22levels.includes(\x27debug\x27)\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:var(--okdb-app-fg-muted)\x22>debug</button>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</div>\x0a\x0a\x20\x20<!--\x20Toolbar\x20row\x203:\x20feature\x20dropdown\x20-->\x0a\x20\x20<if\x20:=\x22seenFeatures.length\x20>\x200\x22>\x0a\x20\x20\x20\x20<div\x20class=\x22history__toolbar\x20history__toolbar--sub\x22>\x0a\x20\x20\x20\x20\x20\x20<span\x20class=\x22history__label\x22>Feature</span>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22history__pills\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22setFeature(null)\x22\x20:class=\x22feature\x20===\x20null\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>All</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<each\x20:of=\x22seenFeatures\x22\x20let:item=\x22s\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22setFeature(s)\x22\x20:class=\x22feature\x20===\x20s\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>{{\x20s\x20}}</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</each>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<!--\x20Toolbar\x20row\x204:\x20node\x20dropdown\x20-->\x0a\x20\x20<if\x20:=\x22seenNodes.length\x20>\x200\x22>\x0a\x20\x20\x20\x20<div\x20class=\x22history__toolbar\x20history__toolbar--sub\x22>\x0a\x20\x20\x20\x20\x20\x20<span\x20class=\x22history__label\x22>Node</span>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22history__pills\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22setNode(null)\x22\x20:class=\x22node\x20===\x20null\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>All</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<each\x20:of=\x22seenNodes\x22\x20let:item=\x22n\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22setNode(n)\x22\x20:class=\x22node\x20===\x20n\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>{{\x20n\x20}}</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</each>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<!--\x20Error\x20state\x20-->\x0a\x20\x20<if\x20:=\x22error\x22>\x0a\x20\x20\x20\x20<div\x20class=\x22history__error\x22>{{\x20error\x20}}</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<!--\x20Log\x20entries\x20list\x20-->\x0a\x20\x20<div\x20class=\x22history__list\x22>\x0a\x20\x20\x20\x20<if\x20:=\x22entries.length\x20===\x200\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22history__empty\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22loading\x22>Loading…</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22!loading\x20&&\x20!error\x22>No\x20log\x20entries</if>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20<each\x20:of=\x22entries\x22\x20let:item=\x22entry\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22history__row\x22\x20@click=\x22toggleExpanded(entry.key)\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22history__ts\x22>{{\x20fmtTime(entry.ts)\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22history__level\x22\x20:style=\x22\x27color:\x27\x20+\x20levelColor(entry.level)\x22>{{\x20entry.level\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22history__feature\x22\x20v-if=\x22entry.feature\x22>{{\x20entry.feature\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22history__msg\x22>{{\x20entry.msg\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22history__node\x22\x20v-if=\x22entry.node\x22>{{\x20entry.node\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22entry.context\x20!=\x20null\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22history__has-context\x22>⊕</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20<!--\x20Expanded\x20context\x20-->\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22expandedKeys.has(entry.key)\x20&&\x20entry.context\x20!=\x20null\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22history__context\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<pre>{{\x20fmtContext(entry.context)\x20}}</pre>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20</each>\x0a\x20\x20</div>\x0a\x0a\x20\x20<!--\x20Load\x20more\x20button\x20-->\x0a\x20\x20<if\x20:=\x22hasMore\x22>\x0a\x20\x20\x20\x20<div\x20class=\x22history__footer\x22>\x0a\x20\x20\x20\x20\x20\x20<button\x20@click=\x22load()\x22\x20:disabled=\x22loading\x22\x20class=\x22history__load-more\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20{{\x20loading\x20?\x20\x27Loading…\x27\x20:\x20\x27Load\x20More\x27\x20}}\x0a\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</If>\x0a\x0a</div>\x0a','hasMore','json','470008eyNrUc','delete','.history{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--okdb-app-bg-deep);border-radius:12px;overflow:hidden;border:1px\x20solid\x20var(--okdb-app-border)}.history__toolbar{display:flex;align-items:center;gap:6px;padding:7px\x2010px;background:var(--okdb-app-surface);border-bottom:1px\x20solid\x20var(--okdb-app-border);flex-shrink:0;flex-wrap:wrap}.history__toolbar--sub{padding:5px\x2010px;background:var(--okdb-app-bg-deep);border-bottom:1px\x20solid\x20var(--okdb-app-surface)}.history__title{font-weight:600;font-size:13px;white-space:nowrap;margin-right:2px}.history__label{font-size:10px;opacity:.45;text-transform:uppercase;letter-spacing:.06em;white-space:nowrap;flex-shrink:0}.history__group{display:flex;align-items:center;gap:6px}.history__pills{display:flex;gap:3px;flex-wrap:wrap}.history__spacer{flex:1}.history__count,.pill{font-size:11px;white-space:nowrap}.history__count{opacity:.4;margin-right:4px}.pill{border:1px\x20solid\x20var(--okdb-app-border);background:0\x200;padding:2px\x209px;border-radius:999px;cursor:pointer;color:#666;transition:border-color\x20.12s,color\x20.12s,background\x20.12s}.pill:hover{border-color:var(--okdb-app-fg-muted);color:var(--okdb-app-fg-muted)}.pill:disabled{opacity:.5;cursor:not-allowed}.pill--on{border-color:var(--okdb-accent);background:var(--okdb-app-surface-2);color:var(--okdb-accent)}.history__error{color:var(--okdb-danger);font-size:12px;padding:8px\x2010px;background:var(--okdb-danger-deep-bg);border-bottom:1px\x20solid\x20var(--okdb-app-border)}.history__list{flex:1;overflow-y:auto;font-family:monospace;font-size:12px;padding:2px\x200;min-height:0}.history__row{display:flex;gap:8px;padding:2px\x2010px;border-bottom:1px\x20solid\x20var(--okdb-app-bg-deep);align-items:baseline;min-height:20px;cursor:pointer;transition:background\x20.12s}.history__row:hover{background:var(--okdb-app-surface)}.history__ts{color:var(--okdb-app-fg-muted);flex-shrink:0;font-size:11px;user-select:none;width:86px}.history__level{width:40px;flex-shrink:0;font-weight:700;font-size:10px;text-transform:uppercase;letter-spacing:.04em}.history__feature{flex-shrink:0;font-size:11px;color:var(--okdb-app-fg-muted)}.history__context\x20pre,.history__msg{white-space:pre-wrap;word-break:break-word}.history__msg{flex:1;color:var(--okdb-app-fg);min-width:0}.history__node{flex-shrink:0;font-size:11px;color:var(--okdb-app-fg-muted)}.history__has-context{flex-shrink:0;color:var(--okdb-accent);cursor:pointer;user-select:none}.history__context{background:var(--okdb-app-bg-deep);padding:6px\x2010px\x206px\x2096px;border-bottom:1px\x20solid\x20var(--okdb-app-surface);font-size:11px}.history__context\x20pre{margin:0;color:var(--okdb-app-fg-muted)}.history__empty{padding:24px\x2014px;opacity:.4;font-style:italic;font-size:12px;text-align:center}.history__footer{padding:8px\x2010px;background:var(--okdb-app-surface);border-top:1px\x20solid\x20var(--okdb-app-border);flex-shrink:0;text-align:center}.history__load-more{padding:4px\x2014px;border-radius:6px;font-size:12px;background:var(--okdb-app-surface-2);border:1px\x20solid\x20var(--okdb-app-border);color:var(--okdb-accent);cursor:pointer;transition:background\x20.12s,border-color\x20.12s}.history__load-more:hover{background:var(--okdb-app-surface-2);border-color:var(--okdb-app-fg-muted)}.history__load-more:disabled{opacity:.5;cursor:not-allowed}','71mCrnvj','/system/logs?','135340EPjPGl','string','system-log-history','length','var(--okdb-danger)','now','feature','All','message','264140ChxZcV','map','levels','splice','has','4422012YmdGlX','from','24h','getMilliseconds','resetAndLoad','clear','load','2100BEIdBZ','append','padStart','entries','649662VtssTo','63arnvxe','level','var(--okdb-app-fg-muted)','expandedKeys','seenFeatures','next_cursor','node','22buzuek','API','stringify','join','#ccc','var(--okdb-warning)','toUpperCase','sort','timeRange','toTimeString','add','seenNodes','result'];_0x191c=function(){return _0x45cad9;};return _0x191c();}export default{'tag':_0x24e017(0x228),'context':()=>({'level':null,'levels':[],'feature':null,'node':null,'timeRange':_0x24e017(0x1f6),'entries':[],'seenFeatures':[],'seenNodes':[],'totalCount':0x0,'cursor':null,'hasMore':!0x1,'loading':!0x1,'error':null,'expandedKeys':new Set(),get 'levelsPill'(){const _0xa52098=_0x24e017;return 0x0===this['levels'][_0xa52098(0x229)]?_0xa52098(0x22d):this[_0xa52098(0x231)][_0xa52098(0x229)]+'\x20selected';},get 'timeRangeLabel'(){const _0x54844f=_0x24e017;return _0x54844f(0x21c)===this['timeRange']?'All\x20time':this['timeRange'][_0x54844f(0x20d)]();},'clearLevels'(){const _0x340ca1=_0x24e017;this['levels']['splice'](0x0,this[_0x340ca1(0x231)]['length']),this['resetAndLoad']();},'toggleLevel'(_0x24f677){const _0x6130b3=_0x24e017,_0x2c0248=this[_0x6130b3(0x231)][_0x6130b3(0x21a)](_0x24f677);_0x2c0248>=0x0?this[_0x6130b3(0x231)][_0x6130b3(0x232)](_0x2c0248,0x1):this[_0x6130b3(0x231)]['push'](_0x24f677),this[_0x6130b3(0x1f8)]();},'setTimeRange'(_0x73799e){const _0x3d8f37=_0x24e017;this[_0x3d8f37(0x20f)]=_0x73799e,this[_0x3d8f37(0x1f8)]();},'setFeature'(_0x1f382f){const _0x5cda92=_0x24e017;this[_0x5cda92(0x22c)]=this[_0x5cda92(0x22c)]===_0x1f382f?null:_0x1f382f,this[_0x5cda92(0x1f8)]();},'setNode'(_0x14f8c7){const _0x4d0c13=_0x24e017;this[_0x4d0c13(0x206)]=this['node']===_0x14f8c7?null:_0x14f8c7,this[_0x4d0c13(0x1f8)]();},'toggleExpanded'(_0x561af0){const _0x457328=_0x24e017;this[_0x457328(0x203)][_0x457328(0x1f3)](_0x561af0)?this[_0x457328(0x203)][_0x457328(0x222)](_0x561af0):this[_0x457328(0x203)][_0x457328(0x211)](_0x561af0);},async 'load'(){const _0x439acd=_0x24e017;this['loading']=!0x0,this[_0x439acd(0x21d)]=null;try{const _0x13a683=Date[_0x439acd(0x22b)](),_0x11a2bd=_0x439acd(0x21c)===this[_0x439acd(0x20f)]?0x0:_0x13a683-t[this['timeRange']],_0x3ffc2f=new URLSearchParams();_0x3ffc2f['append'](_0x439acd(0x1f5),String(_0x11a2bd)),_0x3ffc2f[_0x439acd(0x1fc)]('to',String(_0x13a683)),this[_0x439acd(0x231)][_0x439acd(0x229)]>0x0&&_0x3ffc2f[_0x439acd(0x1fc)](_0x439acd(0x201),this['levels'][_0x439acd(0x20a)](',')),this[_0x439acd(0x22c)]&&_0x3ffc2f[_0x439acd(0x1fc)](_0x439acd(0x22c),this[_0x439acd(0x22c)]),this[_0x439acd(0x206)]&&_0x3ffc2f[_0x439acd(0x1fc)](_0x439acd(0x206),this[_0x439acd(0x206)]),this['cursor']&&_0x3ffc2f[_0x439acd(0x1fc)](_0x439acd(0x214),String(this[_0x439acd(0x214)]));const _0x50997=await fetch(__ENV__[_0x439acd(0x208)]+_0x439acd(0x225)+_0x3ffc2f),_0x24c78a=await _0x50997[_0x439acd(0x220)]();if(!_0x50997['ok'])throw new Error(_0x24c78a?.[_0x439acd(0x21d)]?.[_0x439acd(0x22e)]||'Failed\x20to\x20load\x20logs');const _0x5f2ba2=_0x24c78a['data']||_0x24c78a[_0x439acd(0x213)]||{},_0x8588c5=_0x5f2ba2[_0x439acd(0x1fe)]||[];this[_0x439acd(0x214)]?this[_0x439acd(0x1fe)][_0x439acd(0x21b)](..._0x8588c5):this[_0x439acd(0x1fe)]=_0x8588c5,this[_0x439acd(0x214)]=_0x5f2ba2[_0x439acd(0x205)]??null,this[_0x439acd(0x21f)]=null!==_0x5f2ba2[_0x439acd(0x205)];const _0x564c85=new Set(this[_0x439acd(0x1fe)][_0x439acd(0x230)](_0x1ae632=>_0x1ae632['feature'])['filter'](Boolean)),_0x5465e6=new Set(this[_0x439acd(0x1fe)][_0x439acd(0x230)](_0x39038c=>_0x39038c[_0x439acd(0x206)])[_0x439acd(0x217)](Boolean));this['seenFeatures']=Array[_0x439acd(0x1f5)](_0x564c85)[_0x439acd(0x20e)](),this[_0x439acd(0x212)]=Array['from'](_0x5465e6)['sort'](),this[_0x439acd(0x219)]=this[_0x439acd(0x1fe)][_0x439acd(0x229)];}catch(_0x574fc6){this['error']=_0x574fc6?.['message']||String(_0x574fc6),this['entries']=[];}this[_0x439acd(0x216)]=!0x1;},'resetAndLoad'(){const _0x545bfe=_0x24e017;this[_0x545bfe(0x214)]=null,this['entries']=[],this[_0x545bfe(0x204)]=[],this['seenNodes']=[],this[_0x545bfe(0x203)][_0x545bfe(0x1f9)](),this[_0x545bfe(0x1fa)]();},'fmtTime'(_0x13b89e){const _0x92d2d9=_0x24e017;if(!_0x13b89e)return'';const _0x4cebb6=new Date(_0x13b89e);return _0x4cebb6[_0x92d2d9(0x210)]()['slice'](0x0,0x8)+'.'+String(_0x4cebb6[_0x92d2d9(0x1f7)]())[_0x92d2d9(0x1fd)](0x3,'0');},'fmtContext'(_0x4eae32){const _0xef92dc=_0x24e017;if(null==_0x4eae32)return'';if(_0xef92dc(0x227)==typeof _0x4eae32)return _0x4eae32;try{return JSON[_0xef92dc(0x209)](_0x4eae32);}catch{return String(_0x4eae32);}},'levelColor':_0x57fb7c=>e[_0x57fb7c]??_0x24e017(0x20b)}),'mount'(){const _0x538b72=_0x24e017;this[_0x538b72(0x1fa)]();},'template':_0x24e017(0x21e),'style':_0x24e017(0x223)};
|
|
1
|
+
const e={info:"var(--okdb-accent)",warn:"var(--okdb-warning)",error:"var(--okdb-danger)",debug:"var(--okdb-app-fg-muted)"},t={"1h":36e5,"6h":216e5,"24h":864e5,"7d":6048e5,all:null};export default{tag:"system-log-history",context:()=>({level:null,levels:[],feature:null,node:null,timeRange:"24h",entries:[],seenFeatures:[],seenNodes:[],totalCount:0,cursor:null,hasMore:!1,loading:!1,error:null,expandedKeys:new Set,get levelsPill(){return 0===this.levels.length?"All":`${this.levels.length} selected`},get timeRangeLabel(){return"all"===this.timeRange?"All time":this.timeRange.toUpperCase()},clearLevels(){this.levels.splice(0,this.levels.length),this.resetAndLoad()},toggleLevel(e){const t=this.levels.indexOf(e);t>=0?this.levels.splice(t,1):this.levels.push(e),this.resetAndLoad()},setTimeRange(e){this.timeRange=e,this.resetAndLoad()},setFeature(e){this.feature=this.feature===e?null:e,this.resetAndLoad()},setNode(e){this.node=this.node===e?null:e,this.resetAndLoad()},toggleExpanded(e){this.expandedKeys.has(e)?this.expandedKeys.delete(e):this.expandedKeys.add(e)},async load(){this.loading=!0,this.error=null;try{const e=Date.now(),o="all"===this.timeRange?0:e-t[this.timeRange],n=new URLSearchParams;n.append("from",String(o)),n.append("to",String(e)),this.levels.length>0&&n.append("level",this.levels.join(",")),this.feature&&n.append("feature",this.feature),this.node&&n.append("node",this.node),this.cursor&&n.append("cursor",String(this.cursor));const r=await fetch(`${__ENV__.API}/system/logs?${n}`),s=await r.json();if(!r.ok)throw new Error(s?.error?.message||"Failed to load logs");const l=s.data||s.result||{},i=l.entries||[];this.cursor?this.entries.push(...i):this.entries=i,this.cursor=l.next_cursor??null,this.hasMore=null!==l.next_cursor;const a=new Set(this.entries.map(e=>e.feature).filter(Boolean)),d=new Set(this.entries.map(e=>e.node).filter(Boolean));this.seenFeatures=Array.from(a).sort(),this.seenNodes=Array.from(d).sort(),this.totalCount=this.entries.length}catch(e){this.error=e?.message||String(e),this.entries=[]}this.loading=!1},resetAndLoad(){this.cursor=null,this.entries=[],this.seenFeatures=[],this.seenNodes=[],this.expandedKeys.clear(),this.load()},fmtTime(e){if(!e)return"";const t=new Date(e);return t.toTimeString().slice(0,8)+"."+String(t.getMilliseconds()).padStart(3,"0")},fmtContext(e){if(null==e)return"";if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}},levelColor:t=>e[t]??"#ccc"}),mount(){this.load()},template:'\n<div class="history">\n\n \x3c!-- Toolbar row 1: filters --\x3e\n <div class="history__toolbar">\n <span class="history__title">History</span>\n\n \x3c!-- Time range --\x3e\n <div class="history__group">\n <span class="history__label">Time</span>\n <div class="history__pills">\n <button @click="setTimeRange(\'1h\')" :class="timeRange===\'1h\' ? \'pill pill--on\' : \'pill\'">1h</button>\n <button @click="setTimeRange(\'6h\')" :class="timeRange===\'6h\' ? \'pill pill--on\' : \'pill\'">6h</button>\n <button @click="setTimeRange(\'24h\')" :class="timeRange===\'24h\' ? \'pill pill--on\' : \'pill\'">24h</button>\n <button @click="setTimeRange(\'7d\')" :class="timeRange===\'7d\' ? \'pill pill--on\' : \'pill\'">7d</button>\n <button @click="setTimeRange(\'all\')" :class="timeRange===\'all\' ? \'pill pill--on\' : \'pill\'">All</button>\n </div>\n </div>\n\n <div class="history__spacer"></div>\n\n \x3c!-- Refresh and count --\x3e\n <button @click="resetAndLoad()" :disabled="loading" class="pill" style="white-space:nowrap;">↻ Refresh</button>\n <span class="history__count">{{ totalCount }}</span>\n </div>\n\n \x3c!-- Toolbar row 2: level filter --\x3e\n <div class="history__toolbar history__toolbar--sub">\n <span class="history__label">Level</span>\n <div class="history__pills">\n <button @click="clearLevels()" :class="levels.length === 0 ? \'pill pill--on\' : \'pill\'">All</button>\n <button @click="toggleLevel(\'info\')" :class="levels.includes(\'info\') ? \'pill pill--on\' : \'pill\'" style="color:var(--okdb-accent)">info</button>\n <button @click="toggleLevel(\'warn\')" :class="levels.includes(\'warn\') ? \'pill pill--on\' : \'pill\'" style="color:var(--okdb-warning)">warn</button>\n <button @click="toggleLevel(\'error\')" :class="levels.includes(\'error\') ? \'pill pill--on\' : \'pill\'" style="color:var(--okdb-danger)">error</button>\n <button @click="toggleLevel(\'debug\')" :class="levels.includes(\'debug\') ? \'pill pill--on\' : \'pill\'" style="color:var(--okdb-app-fg-muted)">debug</button>\n </div>\n </div>\n\n \x3c!-- Toolbar row 3: feature dropdown --\x3e\n <if :="seenFeatures.length > 0">\n <div class="history__toolbar history__toolbar--sub">\n <span class="history__label">Feature</span>\n <div class="history__pills">\n <button @click="setFeature(null)" :class="feature === null ? \'pill pill--on\' : \'pill\'">All</button>\n <each :of="seenFeatures" let:item="s">\n <button @click="setFeature(s)" :class="feature === s ? \'pill pill--on\' : \'pill\'">{{ s }}</button>\n </each>\n </div>\n </div>\n </if>\n\n \x3c!-- Toolbar row 4: node dropdown --\x3e\n <if :="seenNodes.length > 0">\n <div class="history__toolbar history__toolbar--sub">\n <span class="history__label">Node</span>\n <div class="history__pills">\n <button @click="setNode(null)" :class="node === null ? \'pill pill--on\' : \'pill\'">All</button>\n <each :of="seenNodes" let:item="n">\n <button @click="setNode(n)" :class="node === n ? \'pill pill--on\' : \'pill\'">{{ n }}</button>\n </each>\n </div>\n </div>\n </if>\n\n \x3c!-- Error state --\x3e\n <if :="error">\n <div class="history__error">{{ error }}</div>\n </if>\n\n \x3c!-- Log entries list --\x3e\n <div class="history__list">\n <if :="entries.length === 0">\n <div class="history__empty">\n <if :="loading">Loading…</if>\n <if :="!loading && !error">No log entries</if>\n </div>\n </if>\n\n <each :of="entries" let:item="entry">\n <div class="history__row" @click="toggleExpanded(entry.key)">\n <span class="history__ts">{{ fmtTime(entry.ts) }}</span>\n <span class="history__level" :style="\'color:\' + levelColor(entry.level)">{{ entry.level }}</span>\n <span class="history__feature" v-if="entry.feature">{{ entry.feature }}</span>\n <span class="history__msg">{{ entry.msg }}</span>\n <span class="history__node" v-if="entry.node">{{ entry.node }}</span>\n <if :="entry.context != null">\n <span class="history__has-context">⊕</span>\n </if>\n </div>\n\n \x3c!-- Expanded context --\x3e\n <if :="expandedKeys.has(entry.key) && entry.context != null">\n <div class="history__context">\n <pre>{{ fmtContext(entry.context) }}</pre>\n </div>\n </if>\n </each>\n </div>\n\n \x3c!-- Load more button --\x3e\n <if :="hasMore">\n <div class="history__footer">\n <button @click="load()" :disabled="loading" class="history__load-more">\n {{ loading ? \'Loading…\' : \'Load More\' }}\n </button>\n </div>\n </If>\n\n</div>\n',style:".history{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--okdb-app-bg-deep);border-radius:12px;overflow:hidden;border:1px solid var(--okdb-app-border)}.history__toolbar{display:flex;align-items:center;gap:6px;padding:7px 10px;background:var(--okdb-app-surface);border-bottom:1px solid var(--okdb-app-border);flex-shrink:0;flex-wrap:wrap}.history__toolbar--sub{padding:5px 10px;background:var(--okdb-app-bg-deep);border-bottom:1px solid var(--okdb-app-surface)}.history__title{font-weight:600;font-size:13px;white-space:nowrap;margin-right:2px}.history__label{font-size:10px;opacity:.45;text-transform:uppercase;letter-spacing:.06em;white-space:nowrap;flex-shrink:0}.history__group{display:flex;align-items:center;gap:6px}.history__pills{display:flex;gap:3px;flex-wrap:wrap}.history__spacer{flex:1}.history__count,.pill{font-size:11px;white-space:nowrap}.history__count{opacity:.4;margin-right:4px}.pill{border:1px solid var(--okdb-app-border);background:0 0;padding:2px 9px;border-radius:999px;cursor:pointer;color:#666;transition:border-color .12s,color .12s,background .12s}.pill:hover{border-color:var(--okdb-app-fg-muted);color:var(--okdb-app-fg-muted)}.pill:disabled{opacity:.5;cursor:not-allowed}.pill--on{border-color:var(--okdb-accent);background:var(--okdb-app-surface-2);color:var(--okdb-accent)}.history__error{color:var(--okdb-danger);font-size:12px;padding:8px 10px;background:var(--okdb-danger-deep-bg);border-bottom:1px solid var(--okdb-app-border)}.history__list{flex:1;overflow-y:auto;font-family:monospace;font-size:12px;padding:2px 0;min-height:0}.history__row{display:flex;gap:8px;padding:2px 10px;border-bottom:1px solid var(--okdb-app-bg-deep);align-items:baseline;min-height:20px;cursor:pointer;transition:background .12s}.history__row:hover{background:var(--okdb-app-surface)}.history__ts{color:var(--okdb-app-fg-muted);flex-shrink:0;font-size:11px;user-select:none;width:86px}.history__level{width:40px;flex-shrink:0;font-weight:700;font-size:10px;text-transform:uppercase;letter-spacing:.04em}.history__feature{flex-shrink:0;font-size:11px;color:var(--okdb-app-fg-muted)}.history__context pre,.history__msg{white-space:pre-wrap;word-break:break-word}.history__msg{flex:1;color:var(--okdb-app-fg);min-width:0}.history__node{flex-shrink:0;font-size:11px;color:var(--okdb-app-fg-muted)}.history__has-context{flex-shrink:0;color:var(--okdb-accent);cursor:pointer;user-select:none}.history__context{background:var(--okdb-app-bg-deep);padding:6px 10px 6px 96px;border-bottom:1px solid var(--okdb-app-surface);font-size:11px}.history__context pre{margin:0;color:var(--okdb-app-fg-muted)}.history__empty{padding:24px 14px;opacity:.4;font-style:italic;font-size:12px;text-align:center}.history__footer{padding:8px 10px;background:var(--okdb-app-surface);border-top:1px solid var(--okdb-app-border);flex-shrink:0;text-align:center}.history__load-more{padding:4px 14px;border-radius:6px;font-size:12px;background:var(--okdb-app-surface-2);border:1px solid var(--okdb-app-border);color:var(--okdb-accent);cursor:pointer;transition:background .12s,border-color .12s}.history__load-more:hover{background:var(--okdb-app-surface-2);border-color:var(--okdb-app-fg-muted)}.history__load-more:disabled{opacity:.5;cursor:not-allowed}"};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function _0xb115(_0x65b29e,_0x35fbfe){_0x65b29e=_0x65b29e-0x1e2;const _0x3338a7=_0x3338();let _0xb11583=_0x3338a7[_0x65b29e];return _0xb11583;}function _0x3338(){const _0x320a2c=['pipeline','_unsubs','autoScroll','engine','419296zDSRNn','activity','855xMhBmm','toTimeString','toLowerCase','_event','map','59507OwAifq','#2dd4bf','log','includes','var(--okdb-success)','var(--okdb-app-fg-muted)','has','length','level','all','getMilliseconds','env','string','split','9WAHGxl','system-log','join','push','scrollTop','_kind','keys','slice','var(--okdb-danger)','sort','initialSource','_payloadStr','msg','#f472b6','event','padStart','filter','startsWith','eventNs','key','702bTsuar','#ccc','_metaStr','type','object','$attr','56739OXRpjb','entries','error','var(--okdb-purple)','1205776aBhGmM','3999980fbEzpk','_ts','feature','var(--okdb-warning)','some','source','search','10zbvFSy','2161GKkRXV','meta'];_0x3338=function(){return _0x320a2c;};return _0x3338();}const _0x43ad81=_0xb115;(function(_0x532a4d,_0x56f67e){const _0x5c1ec9=_0xb115,_0x57c7bf=_0x532a4d();while(!![]){try{const _0x5f07ad=-parseInt(_0x5c1ec9(0x206))/0x1*(parseInt(_0x5c1ec9(0x205))/0x2)+-parseInt(_0x5c1ec9(0x1f9))/0x3+-parseInt(_0x5c1ec9(0x20c))/0x4+parseInt(_0x5c1ec9(0x20e))/0x5*(parseInt(_0x5c1ec9(0x1f3))/0x6)+-parseInt(_0x5c1ec9(0x213))/0x7+-parseInt(_0x5c1ec9(0x1fd))/0x8+parseInt(_0x5c1ec9(0x221))/0x9*(parseInt(_0x5c1ec9(0x1fe))/0xa);if(_0x5f07ad===_0x56f67e)break;else _0x57c7bf['push'](_0x57c7bf['shift']());}catch(_0x26599a){_0x57c7bf['push'](_0x57c7bf['shift']());}}}(_0x3338,0x1ed20));import _0x2d53d3,{ALL_EVENTS as _0x788b97}from'../../../stores/events-store.js';const t={'info':'var(--okdb-accent)','warn':'var(--okdb-warning)','error':_0x43ad81(0x1e7),'debug':'var(--okdb-app-fg-muted)'},n={'engine':'var(--okdb-accent)','type':_0x43ad81(0x1fc),'index':_0x43ad81(0x201),'embeddings':_0x43ad81(0x214),'system':_0x43ad81(0x217),'sync':'var(--okdb-orange)','queue':'var(--okdb-indigo)','processor':_0x43ad81(0x1ec),'fts':'var(--okdb-success)','env':'#67e8f9','txn':_0x43ad81(0x218),'item':'var(--okdb-app-fg)','relay':_0x43ad81(0x1e7)};Object[_0x43ad81(0x1e5)](n);export default{'tag':_0x43ad81(0x222),'attr':{'initialSource':{}},'context':_0x48cd38=>({'source':_0x48cd38[_0x43ad81(0x1f8)][_0x43ad81(0x1e9)]||_0x43ad81(0x21c),'eventNs':null,'level':null,'feature':null,'env':null,'search':'','autoScroll':!0x0,'_listRef':null,'_unsubs':[],get 'connected'(){return _0x2d53d3['connected'];},get 'streamError'(){const _0x35b2ec=_0x43ad81;return _0x2d53d3[_0x35b2ec(0x1fb)];},get 'entries'(){const _0x5ea6a1=_0x43ad81;let _0x63ca8d=_0x2d53d3['activity'];if(_0x5ea6a1(0x215)===this[_0x5ea6a1(0x203)]&&(_0x63ca8d=_0x63ca8d[_0x5ea6a1(0x1ef)](_0x269399=>_0x5ea6a1(0x215)===_0x269399[_0x5ea6a1(0x1e4)])),_0x5ea6a1(0x1ed)===this[_0x5ea6a1(0x203)]&&(_0x63ca8d=_0x63ca8d['filter'](_0x43a22f=>_0x5ea6a1(0x1ed)===_0x43a22f[_0x5ea6a1(0x1e4)])),this[_0x5ea6a1(0x1f1)]&&_0x5ea6a1(0x215)!==this[_0x5ea6a1(0x203)]&&(_0x63ca8d=_0x63ca8d[_0x5ea6a1(0x1ef)](_0x21518a=>'event'!==_0x21518a[_0x5ea6a1(0x1e4)]||(_0x21518a[_0x5ea6a1(0x211)]??'')[_0x5ea6a1(0x1f0)](this[_0x5ea6a1(0x1f1)]+':'))),this[_0x5ea6a1(0x21b)]&&_0x5ea6a1(0x1ed)!==this[_0x5ea6a1(0x203)]&&(_0x63ca8d=_0x63ca8d[_0x5ea6a1(0x1ef)](_0x395910=>_0x5ea6a1(0x215)!==_0x395910['_kind']||_0x395910[_0x5ea6a1(0x21b)]===this[_0x5ea6a1(0x21b)])),this[_0x5ea6a1(0x200)]&&_0x5ea6a1(0x1ed)!==this[_0x5ea6a1(0x203)]&&(_0x63ca8d=_0x63ca8d[_0x5ea6a1(0x1ef)](_0x9671b1=>'log'!==_0x9671b1[_0x5ea6a1(0x1e4)]||_0x9671b1[_0x5ea6a1(0x207)]?.['feature']===this[_0x5ea6a1(0x200)])),this[_0x5ea6a1(0x21e)]&&'event'!==this[_0x5ea6a1(0x203)]&&(_0x63ca8d=_0x63ca8d['filter'](_0x4787fb=>_0x5ea6a1(0x215)!==_0x4787fb[_0x5ea6a1(0x1e4)]||_0x4787fb[_0x5ea6a1(0x207)]?.[_0x5ea6a1(0x21e)]===this[_0x5ea6a1(0x21e)])),this[_0x5ea6a1(0x204)]){const _0x517b87=this[_0x5ea6a1(0x204)][_0x5ea6a1(0x210)]();_0x63ca8d=_0x63ca8d[_0x5ea6a1(0x1ef)](_0x333873=>_0x5ea6a1(0x215)===_0x333873[_0x5ea6a1(0x1e4)]?(_0x333873[_0x5ea6a1(0x1eb)]??'')['toLowerCase']()[_0x5ea6a1(0x216)](_0x517b87)||this[_0x5ea6a1(0x1f5)](_0x333873['context'])[_0x5ea6a1(0x210)]()['includes'](_0x517b87)||this[_0x5ea6a1(0x1f5)](_0x333873[_0x5ea6a1(0x207)])[_0x5ea6a1(0x210)]()[_0x5ea6a1(0x216)](_0x517b87):_0x5ea6a1(0x1ed)===_0x333873[_0x5ea6a1(0x1e4)]&&((_0x333873[_0x5ea6a1(0x211)]??'')[_0x5ea6a1(0x210)]()[_0x5ea6a1(0x216)](_0x517b87)||this[_0x5ea6a1(0x1ea)](_0x333873)['toLowerCase']()[_0x5ea6a1(0x216)](_0x517b87)));}return _0x63ca8d;},get 'totalCount'(){const _0x5bab8f=_0x43ad81;return _0x2d53d3[_0x5bab8f(0x20d)]['length'];},get 'filteredCount'(){const _0x3751e2=_0x43ad81;return this[_0x3751e2(0x1fa)][_0x3751e2(0x21a)];},get 'hasFeatures'(){const _0x2ff34c=_0x43ad81;return _0x2d53d3[_0x2ff34c(0x20d)][_0x2ff34c(0x202)](_0x56c7b5=>_0x2ff34c(0x215)===_0x56c7b5[_0x2ff34c(0x1e4)]&&_0x56c7b5[_0x2ff34c(0x207)]?.[_0x2ff34c(0x200)]);},get 'featureList'(){const _0x47ec34=_0x43ad81;return[...new Set(_0x2d53d3[_0x47ec34(0x20d)][_0x47ec34(0x1ef)](_0x37d22d=>_0x47ec34(0x215)===_0x37d22d[_0x47ec34(0x1e4)]&&_0x37d22d[_0x47ec34(0x207)]?.[_0x47ec34(0x200)])[_0x47ec34(0x212)](_0x3b67b1=>_0x3b67b1[_0x47ec34(0x207)][_0x47ec34(0x200)]))][_0x47ec34(0x1e8)]();},get 'hasEnvs'(){const _0x18e643=_0x43ad81;return _0x2d53d3[_0x18e643(0x20d)][_0x18e643(0x202)](_0x50f6a2=>_0x18e643(0x215)===_0x50f6a2[_0x18e643(0x1e4)]&&_0x50f6a2[_0x18e643(0x207)]?.[_0x18e643(0x21e)]);},get 'envList'(){const _0x5be18f=_0x43ad81;return[...new Set(_0x2d53d3[_0x5be18f(0x20d)]['filter'](_0x2a05d0=>_0x5be18f(0x215)===_0x2a05d0[_0x5be18f(0x1e4)]&&_0x2a05d0[_0x5be18f(0x207)]?.[_0x5be18f(0x21e)])[_0x5be18f(0x212)](_0x360624=>_0x360624[_0x5be18f(0x207)][_0x5be18f(0x21e)]))]['sort']();},'setSource'(_0x23fbb1){const _0x123174=_0x43ad81;this[_0x123174(0x203)]=_0x23fbb1,_0x123174(0x215)===_0x23fbb1&&(this['eventNs']=null),'event'===_0x23fbb1&&(this[_0x123174(0x21b)]=null,this['feature']=null,this[_0x123174(0x21e)]=null);},'toggleNs'(_0x1fd01d){const _0x1f2dd1=_0x43ad81;this[_0x1f2dd1(0x1f1)]=this[_0x1f2dd1(0x1f1)]===_0x1fd01d?null:_0x1fd01d;},'toggleLevel'(_0x7fadf9){const _0x5be33d=_0x43ad81;this['level']=this[_0x5be33d(0x21b)]===_0x7fadf9?null:_0x7fadf9;},'toggleFeature'(_0x2845ec){const _0x24d101=_0x43ad81;this[_0x24d101(0x200)]=this[_0x24d101(0x200)]===_0x2845ec?null:_0x2845ec;},'toggleEnv'(_0x5b27c7){const _0x3cecab=_0x43ad81;this[_0x3cecab(0x21e)]=this[_0x3cecab(0x21e)]===_0x5b27c7?null:_0x5b27c7;},'clear'(){_0x2d53d3['clearActivity']();},'scrollToBottom'(){const _0x158286=this['_listRef'];_0x158286&&requestAnimationFrame(()=>{const _0x214408=_0xb115;_0x158286[_0x214408(0x1e3)]=_0x158286['scrollHeight'];});},'levelColor':_0x24077e=>t[_0x24077e]??_0x43ad81(0x1f4),'nsColor':_0x311435=>function(_0x6e9256){const _0x22067=_0x43ad81,_0x252d7c=(_0x6e9256||'')[_0x22067(0x220)](':')[0x0];return n[_0x252d7c]??'var(--okdb-app-fg-muted)';}(_0x311435),'fmtTime'(_0x3fd1ca){const _0x28f383=_0x43ad81;if(!_0x3fd1ca)return'';const _0x27b851=new Date(_0x3fd1ca);return _0x27b851[_0x28f383(0x20f)]()[_0x28f383(0x1e6)](0x0,0x8)+'.'+String(_0x27b851[_0x28f383(0x21d)]())[_0x28f383(0x1ee)](0x3,'0');},'_metaStr'(_0x5a5336){const _0x1b9840=_0x43ad81;if(null==_0x5a5336)return'';if(_0x1b9840(0x21f)==typeof _0x5a5336)return _0x5a5336;try{return JSON['stringify'](_0x5a5336);}catch{return String(_0x5a5336);}},'fmtMeta'(_0x1061c7){return this['_metaStr'](_0x1061c7);},'_payloadStr'(_0x3055b8){const _0x41b0a2=_0x43ad81;if(_0x3055b8['engine'])return _0x3055b8[_0x41b0a2(0x20b)];if(_0x3055b8[_0x41b0a2(0x1f6)])return _0x3055b8[_0x41b0a2(0x1f6)];if(_0x3055b8[_0x41b0a2(0x208)])return _0x3055b8['pipeline'];if(_0x3055b8[_0x41b0a2(0x1f2)])return _0x3055b8[_0x41b0a2(0x1f2)];const _0x1ae49a=new Set(['_kind',_0x41b0a2(0x211),_0x41b0a2(0x1ff),'ts']),_0xc82da=[];for(const [_0x228dfe,_0x617ab1]of Object['entries'](_0x3055b8)){if(_0x1ae49a[_0x41b0a2(0x219)](_0x228dfe))continue;const _0x334a88=_0x41b0a2(0x1f7)==typeof _0x617ab1?JSON['stringify'](_0x617ab1):String(_0x617ab1);if(_0xc82da[_0x41b0a2(0x1e2)](_0x228dfe+':'+_0x334a88),_0xc82da['length']>=0x2)break;}return _0xc82da[_0x41b0a2(0x223)]('\x20\x20');},'fmtPayload'(_0xfb5f37){const _0x183540=_0x43ad81;return this[_0x183540(0x1ea)](_0xfb5f37);}}),'mount'(){const _0x3a4fad=_0x43ad81,_0x2ccd5f=['log',..._0x788b97][_0x3a4fad(0x212)](_0x429279=>_0x2d53d3['on'](_0x429279,()=>{this['autoScroll']&&this['scrollToBottom']();}));this['_unsubs']=_0x2ccd5f,this[_0x3a4fad(0x20a)]&&this['scrollToBottom']();},'unmount'(){const _0x2d1950=_0x43ad81;for(const _0x42df3d of this[_0x2d1950(0x209)])_0x42df3d();this[_0x2d1950(0x209)]=[];},'template':'\x0a<div\x20class=\x22syslog\x22>\x0a\x0a\x20\x20<!--\x20Toolbar\x20row\x201:\x20title\x20+\x20source\x20toggle\x20+\x20search\x20+\x20controls\x20-->\x0a\x20\x20<div\x20class=\x22syslog__toolbar\x22>\x0a\x20\x20\x20\x20<span\x20class=\x22syslog__title\x22>Activity</span>\x0a\x0a\x20\x20\x20\x20<!--\x20Source\x20pills\x20-->\x0a\x20\x20\x20\x20<div\x20class=\x22syslog__pills\x22>\x0a\x20\x20\x20\x20\x20\x20<button\x20@click=\x22setSource(\x27all\x27)\x22\x20\x20\x20:class=\x22source===\x27all\x27\x20\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>All</button>\x0a\x20\x20\x20\x20\x20\x20<button\x20@click=\x22setSource(\x27log\x27)\x22\x20\x20\x20:class=\x22source===\x27log\x27\x20\x20\x20?\x20\x27pill\x20pill--on\x20pill--log\x27\x20\x20\x20:\x20\x27pill\x20pill--log\x27\x22>Logs</button>\x0a\x20\x20\x20\x20\x20\x20<button\x20@click=\x22setSource(\x27event\x27)\x22\x20:class=\x22source===\x27event\x27\x20?\x20\x27pill\x20pill--on\x20pill--event\x27\x20:\x20\x27pill\x20pill--event\x27\x22>Events</button>\x0a\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20<div\x20class=\x22syslog__spacer\x22></div>\x0a\x0a\x20\x20\x20\x20<!--\x20Search\x20-->\x0a\x20\x20\x20\x20<input\x0a\x20\x20\x20\x20\x20\x20class=\x22syslog__search\x22\x0a\x20\x20\x20\x20\x20\x20type=\x22text\x22\x0a\x20\x20\x20\x20\x20\x20placeholder=\x22Filter…\x22\x0a\x20\x20\x20\x20\x20\x20:value=\x22search\x22\x0a\x20\x20\x20\x20\x20\x20@input=\x22search\x20=\x20$event.target.value\x22\x0a\x20\x20\x20\x20/>\x0a\x0a\x20\x20\x20\x20<!--\x20Auto-scroll\x20-->\x0a\x20\x20\x20\x20<button\x20@click=\x22autoScroll\x20=\x20!autoScroll\x22\x20:class=\x22autoScroll\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20title=\x22Auto-scroll\x20to\x20newest\x22>↓\x20Auto</button>\x0a\x0a\x20\x20\x20\x20<!--\x20Clear\x20-->\x0a\x20\x20\x20\x20<button\x20@click=\x22clear()\x22\x20class=\x22pill\x20syslog__clear\x22>Clear</button>\x0a\x0a\x20\x20\x20\x20<!--\x20Count\x20-->\x0a\x20\x20\x20\x20<span\x20class=\x22syslog__count\x22>\x0a\x20\x20\x20\x20\x20\x20{{\x20filteredCount\x20}}\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22filteredCount\x20!==\x20totalCount\x22>\x20/\x20{{\x20totalCount\x20}}</if>\x0a\x20\x20\x20\x20</span>\x0a\x0a\x20\x20\x20\x20<!--\x20Stream\x20dot\x20-->\x0a\x20\x20\x20\x20<span\x20:class=\x22connected\x20?\x20\x27dot\x20dot--on\x27\x20:\x20\x27dot\x20dot--off\x27\x22\x20:title=\x22connected\x20?\x20\x27Live\x27\x20:\x20(streamError\x20||\x20\x27Disconnected\x27)\x22></span>\x0a\x20\x20</div>\x0a\x0a\x20\x20<!--\x20Toolbar\x20row\x202:\x20secondary\x20filters\x20(level\x20for\x20logs,\x20namespace\x20for\x20events)\x20-->\x0a\x20\x20<if\x20:=\x22source\x20!==\x20\x27event\x27\x22>\x0a\x20\x20\x20\x20<div\x20class=\x22syslog__toolbar\x20syslog__toolbar--sub\x22>\x0a\x20\x20\x20\x20\x20\x20<span\x20class=\x22syslog__sublabel\x22>Level</span>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22syslog__pills\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleLevel(null)\x22\x20\x20\x20\x20:class=\x22level\x20==\x20null\x20\x20\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>All</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleLevel(\x27info\x27)\x22\x20\x20:class=\x22level===\x27info\x27\x20\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:var(--okdb-accent)\x22>info</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleLevel(\x27warn\x27)\x22\x20\x20:class=\x22level===\x27warn\x27\x20\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:var(--okdb-warning)\x22>warn</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleLevel(\x27error\x27)\x22\x20:class=\x22level===\x27error\x27\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:var(--okdb-danger)\x22>error</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleLevel(\x27debug\x27)\x22\x20:class=\x22level===\x27debug\x27\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:var(--okdb-app-fg-muted)\x22>debug</button>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20<if\x20:=\x22hasFeatures\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22syslog__toolbar\x20syslog__toolbar--sub\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22syslog__sublabel\x22>Feature</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22syslog__pills\x22\x20style=\x22flex-wrap:wrap;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleFeature(null)\x22\x20:class=\x22feature\x20==\x20null\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>all</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<each\x20:of=\x22featureList\x22\x20let:item=\x22s\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleFeature(s)\x22\x20:class=\x22feature\x20===\x20s\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>{{\x20s\x20}}</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</each>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20<if\x20:=\x22hasEnvs\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22syslog__toolbar\x20syslog__toolbar--sub\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22syslog__sublabel\x22>Env</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22syslog__pills\x22\x20style=\x22flex-wrap:wrap;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleEnv(null)\x22\x20:class=\x22env\x20==\x20null\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>all</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<each\x20:of=\x22envList\x22\x20let:item=\x22e\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleEnv(e)\x22\x20:class=\x22env\x20===\x20e\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>{{\x20e\x20}}</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</each>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</if>\x0a\x20\x20</if>\x0a\x0a\x20\x20<if\x20:=\x22source\x20!==\x20\x27log\x27\x22>\x0a\x20\x20\x20\x20<div\x20class=\x22syslog__toolbar\x20syslog__toolbar--sub\x22>\x0a\x20\x20\x20\x20\x20\x20<span\x20class=\x22syslog__sublabel\x22>Namespace</span>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22syslog__pills\x22\x20style=\x22flex-wrap:wrap;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleNs(null)\x22\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:class=\x22eventNs==null\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>all</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleNs(\x27engine\x27)\x22\x20\x20\x20\x20\x20\x20:class=\x22eventNs===\x27engine\x27\x20\x20\x20\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:var(--okdb-accent)\x22>engine</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleNs(\x27type\x27)\x22\x20\x20\x20\x20\x20\x20\x20\x20:class=\x22eventNs===\x27type\x27\x20\x20\x20\x20\x20\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:var(--okdb-purple)\x22>type</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleNs(\x27index\x27)\x22\x20\x20\x20\x20\x20\x20\x20:class=\x22eventNs===\x27index\x27\x20\x20\x20\x20\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:var(--okdb-warning)\x22>index</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleNs(\x27embeddings\x27)\x22\x20\x20:class=\x22eventNs===\x27embeddings\x27\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:#2dd4bf\x22>embeddings</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleNs(\x27system\x27)\x22\x20\x20\x20\x20\x20\x20:class=\x22eventNs===\x27system\x27\x20\x20\x20\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:var(--okdb-success)\x22>system</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleNs(\x27sync\x27)\x22\x20\x20\x20\x20\x20\x20\x20\x20:class=\x22eventNs===\x27sync\x27\x20\x20\x20\x20\x20\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:var(--okdb-orange)\x22>sync</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleNs(\x27queue\x27)\x22\x20\x20\x20\x20\x20\x20\x20:class=\x22eventNs===\x27queue\x27\x20\x20\x20\x20\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:var(--okdb-indigo)\x22>queue</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleNs(\x27processor\x27)\x22\x20\x20\x20:class=\x22eventNs===\x27processor\x27\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:#f472b6\x22>processor</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleNs(\x27fts\x27)\x22\x20\x20\x20\x20\x20\x20\x20\x20\x20:class=\x22eventNs===\x27fts\x27\x20\x20\x20\x20\x20\x20\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:var(--okdb-success)\x22>fts</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleNs(\x27env\x27)\x22\x20\x20\x20\x20\x20\x20\x20\x20\x20:class=\x22eventNs===\x27env\x27\x20\x20\x20\x20\x20\x20\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:#67e8f9\x22>env</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleNs(\x27txn\x27)\x22\x20\x20\x20\x20\x20\x20\x20\x20\x20:class=\x22eventNs===\x27txn\x27\x20\x20\x20\x20\x20\x20\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:var(--okdb-app-fg-muted)\x22>txn</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22toggleNs(\x27item\x27)\x22\x20\x20\x20\x20\x20\x20\x20\x20:class=\x22eventNs===\x27item\x27\x20\x20\x20\x20\x20\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22\x20style=\x22color:var(--okdb-app-fg)\x22>item</button>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<!--\x20Activity\x20list\x20-->\x0a\x20\x20<div\x20class=\x22syslog__list\x22\x20:ref=\x22_listRef\x20=\x20$el\x22>\x0a\x0a\x20\x20\x20\x20<if\x20:=\x22entries.length\x20===\x200\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22syslog__empty\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22!connected\x22>Connecting\x20to\x20event\x20stream…</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22connected\x20&&\x20totalCount\x20===\x200\x22>No\x20activity\x20yet.</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22connected\x20&&\x20totalCount\x20>\x200\x22>No\x20entries\x20match\x20the\x20current\x20filter.</if>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20<each\x20:of=\x22entries\x22\x20let:item=\x22entry\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20:class=\x22entry._kind\x20===\x20\x27event\x27\x20?\x20\x27syslog__row\x20syslog__row--event\x27\x20:\x20\x27syslog__row\x27\x22>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Timestamp\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22syslog__ts\x22>{{\x20fmtTime(entry._ts)\x20}}</span>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20LOG\x20entry\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22entry._kind\x20===\x20\x27log\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22syslog__level\x22\x20:style=\x22\x27color:\x27\x20+\x20levelColor(entry.level)\x22>{{\x20entry.level\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22syslog__msg\x22>{{\x20entry.msg\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22entry.meta?.feature\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22syslog__meta\x22\x20style=\x22opacity:.6\x22\x20:title=\x22fmtMeta(entry.meta)\x22>{{\x20entry.meta.feature\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22entry.context\x20!=\x20null\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22syslog__meta\x22\x20:title=\x22fmtMeta(entry.context)\x22>{{\x20fmtMeta(entry.context)\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20EVENT\x20entry\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22entry._kind\x20===\x20\x27event\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20class=\x22syslog__evtag\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:style=\x22\x27color:\x27\x20+\x20nsColor(entry._event)\x20+\x20\x27;\x20border-color:\x27\x20+\x20nsColor(entry._event)\x20+\x20\x2744\x27\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20>{{\x20entry._event\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22syslog__msg\x20syslog__msg--dim\x22>{{\x20fmtPayload(entry)\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</each>\x0a\x0a\x20\x20</div>\x0a\x0a</div>\x0a','style':'@keyframes\x20dot-pulse{0%,to{opacity:1}50%{opacity:.4}}.syslog{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--okdb-app-bg-deep);border-radius:12px;overflow:hidden;border:1px\x20solid\x20var(--okdb-app-border)}.syslog__toolbar{display:flex;align-items:center;gap:6px;padding:7px\x2010px;background:var(--okdb-app-surface);border-bottom:1px\x20solid\x20var(--okdb-app-border);flex-shrink:0;flex-wrap:wrap}.syslog__toolbar--sub{padding:5px\x2010px;background:var(--okdb-app-bg-deep);border-bottom:1px\x20solid\x20var(--okdb-app-surface)}.syslog__title{font-weight:600;font-size:13px;white-space:nowrap;margin-right:2px}.syslog__sublabel{font-size:10px;opacity:.45;text-transform:uppercase;letter-spacing:.06em;white-space:nowrap;width:60px;flex-shrink:0}.syslog__spacer{flex:1}.syslog__pills{display:flex;gap:3px;flex-wrap:wrap}.syslog__search{background:var(--okdb-app-border);border:1px\x20solid\x20var(--okdb-app-border-strong);border-radius:6px;color:var(--okdb-warning);padding:3px\x208px;font-size:12px;width:110px;outline:0}.syslog__search:focus{border-color:var(--okdb-accent)}.pill,.syslog__count{font-size:11px;white-space:nowrap}.syslog__count{opacity:.4}.pill{border:1px\x20solid\x20var(--okdb-app-border);background:0\x200;padding:2px\x209px;border-radius:999px;cursor:pointer;color:var(--okdb-app-fg-faint);transition:border-color\x20.12s,color\x20.12s,background\x20.12s}.pill:hover{border-color:var(--okdb-app-fg-muted);color:var(--okdb-app-fg-muted)}.pill--on{border-color:var(--okdb-accent);background:var(--okdb-app-surface-2)}.pill--log,.pill--on{color:var(--okdb-accent)}.pill--event{color:var(--okdb-purple)}.syslog__list{flex:1;overflow-y:auto;font-family:monospace;font-size:12px;padding:2px\x200;min-height:0}.syslog__row{display:flex;gap:8px;padding:2px\x2010px;border-bottom:1px\x20solid\x20var(--okdb-app-bg-deep);align-items:baseline;min-height:20px}.syslog__row--event,.syslog__row:hover{background:var(--okdb-app-surface)}.syslog__row--event:hover{background:var(--okdb-app-surface-2)}.syslog__ts{color:var(--okdb-app-fg-muted);flex-shrink:0;font-size:11px;user-select:none;width:86px}.syslog__level{width:40px;flex-shrink:0;font-weight:700;font-size:10px;text-transform:uppercase;letter-spacing:.04em}.syslog__evtag{flex-shrink:0;font-size:10px;padding:1px\x206px;border-radius:4px;border:1px\x20solid;white-space:nowrap;letter-spacing:.02em}.syslog__msg{flex:1;white-space:pre-wrap;word-break:break-word;color:var(--okdb-app-fg);min-width:0}.syslog__meta,.syslog__msg--dim{color:var(--okdb-app-fg-muted)}.syslog__meta{font-size:11px;max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0;cursor:default}.syslog__empty{padding:24px\x2014px;opacity:.4;font-style:italic;font-size:12px}.dot{width:7px;height:7px;border-radius:50%;display:inline-block;flex-shrink:0}.dot--on{background:var(--okdb-success);box-shadow:0\x200\x205px\x20color-mix(in\x20srgb,var(--okdb-success)\x2040%,transparent);animation:dot-pulse\x202s\x20ease-in-out\x20infinite}.dot--off{background:var(--okdb-danger)}'};
|
|
1
|
+
import e,{ALL_EVENTS as l}from"../../../stores/events-store.js";const t={info:"var(--okdb-accent)",warn:"var(--okdb-warning)",error:"var(--okdb-danger)",debug:"var(--okdb-app-fg-muted)"},n={engine:"var(--okdb-accent)",type:"var(--okdb-purple)",index:"var(--okdb-warning)",embeddings:"#2dd4bf",system:"var(--okdb-success)",sync:"var(--okdb-orange)",queue:"var(--okdb-indigo)",processor:"#f472b6",fts:"var(--okdb-success)",env:"#67e8f9",txn:"var(--okdb-app-fg-muted)",item:"var(--okdb-app-fg)",relay:"var(--okdb-danger)"};Object.keys(n);export default{tag:"system-log",attr:{initialSource:{}},context:l=>({source:l.$attr.initialSource||"all",eventNs:null,level:null,feature:null,env:null,search:"",autoScroll:!0,_listRef:null,_unsubs:[],get connected(){return e.connected},get streamError(){return e.error},get entries(){let l=e.activity;if("log"===this.source&&(l=l.filter(e=>"log"===e._kind)),"event"===this.source&&(l=l.filter(e=>"event"===e._kind)),this.eventNs&&"log"!==this.source&&(l=l.filter(e=>"event"!==e._kind||(e._event??"").startsWith(this.eventNs+":"))),this.level&&"event"!==this.source&&(l=l.filter(e=>"log"!==e._kind||e.level===this.level)),this.feature&&"event"!==this.source&&(l=l.filter(e=>"log"!==e._kind||e.meta?.feature===this.feature)),this.env&&"event"!==this.source&&(l=l.filter(e=>"log"!==e._kind||e.meta?.env===this.env)),this.search){const e=this.search.toLowerCase();l=l.filter(l=>"log"===l._kind?(l.msg??"").toLowerCase().includes(e)||this._metaStr(l.context).toLowerCase().includes(e)||this._metaStr(l.meta).toLowerCase().includes(e):"event"===l._kind&&((l._event??"").toLowerCase().includes(e)||this._payloadStr(l).toLowerCase().includes(e)))}return l},get totalCount(){return e.activity.length},get filteredCount(){return this.entries.length},get hasFeatures(){return e.activity.some(e=>"log"===e._kind&&e.meta?.feature)},get featureList(){return[...new Set(e.activity.filter(e=>"log"===e._kind&&e.meta?.feature).map(e=>e.meta.feature))].sort()},get hasEnvs(){return e.activity.some(e=>"log"===e._kind&&e.meta?.env)},get envList(){return[...new Set(e.activity.filter(e=>"log"===e._kind&&e.meta?.env).map(e=>e.meta.env))].sort()},setSource(e){this.source=e,"log"===e&&(this.eventNs=null),"event"===e&&(this.level=null,this.feature=null,this.env=null)},toggleNs(e){this.eventNs=this.eventNs===e?null:e},toggleLevel(e){this.level=this.level===e?null:e},toggleFeature(e){this.feature=this.feature===e?null:e},toggleEnv(e){this.env=this.env===e?null:e},clear(){e.clearActivity()},scrollToBottom(){const e=this._listRef;e&&requestAnimationFrame(()=>{e.scrollTop=e.scrollHeight})},levelColor:e=>t[e]??"#ccc",nsColor:e=>function(e){const l=(e||"").split(":")[0];return n[l]??"var(--okdb-app-fg-muted)"}(e),fmtTime(e){if(!e)return"";const l=new Date(e);return l.toTimeString().slice(0,8)+"."+String(l.getMilliseconds()).padStart(3,"0")},_metaStr(e){if(null==e)return"";if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}},fmtMeta(e){return this._metaStr(e)},_payloadStr(e){if(e.engine)return e.engine;if(e.type)return e.type;if(e.pipeline)return e.pipeline;if(e.key)return e.key;const l=new Set(["_kind","_event","_ts","ts"]),t=[];for(const[n,o]of Object.entries(e)){if(l.has(n))continue;const e="object"==typeof o?JSON.stringify(o):String(o);if(t.push(`${n}:${e}`),t.length>=2)break}return t.join(" ")},fmtPayload(e){return this._payloadStr(e)}}),mount(){const t=["log",...l].map(l=>e.on(l,()=>{this.autoScroll&&this.scrollToBottom()}));this._unsubs=t,this.autoScroll&&this.scrollToBottom()},unmount(){for(const e of this._unsubs)e();this._unsubs=[]},template:'\n<div class="syslog">\n\n \x3c!-- Toolbar row 1: title + source toggle + search + controls --\x3e\n <div class="syslog__toolbar">\n <span class="syslog__title">Activity</span>\n\n \x3c!-- Source pills --\x3e\n <div class="syslog__pills">\n <button @click="setSource(\'all\')" :class="source===\'all\' ? \'pill pill--on\' : \'pill\'">All</button>\n <button @click="setSource(\'log\')" :class="source===\'log\' ? \'pill pill--on pill--log\' : \'pill pill--log\'">Logs</button>\n <button @click="setSource(\'event\')" :class="source===\'event\' ? \'pill pill--on pill--event\' : \'pill pill--event\'">Events</button>\n </div>\n\n <div class="syslog__spacer"></div>\n\n \x3c!-- Search --\x3e\n <input\n class="syslog__search"\n type="text"\n placeholder="Filter…"\n :value="search"\n @input="search = $event.target.value"\n />\n\n \x3c!-- Auto-scroll --\x3e\n <button @click="autoScroll = !autoScroll" :class="autoScroll ? \'pill pill--on\' : \'pill\'" title="Auto-scroll to newest">↓ Auto</button>\n\n \x3c!-- Clear --\x3e\n <button @click="clear()" class="pill syslog__clear">Clear</button>\n\n \x3c!-- Count --\x3e\n <span class="syslog__count">\n {{ filteredCount }}\n <if :="filteredCount !== totalCount"> / {{ totalCount }}</if>\n </span>\n\n \x3c!-- Stream dot --\x3e\n <span :class="connected ? \'dot dot--on\' : \'dot dot--off\'" :title="connected ? \'Live\' : (streamError || \'Disconnected\')"></span>\n </div>\n\n \x3c!-- Toolbar row 2: secondary filters (level for logs, namespace for events) --\x3e\n <if :="source !== \'event\'">\n <div class="syslog__toolbar syslog__toolbar--sub">\n <span class="syslog__sublabel">Level</span>\n <div class="syslog__pills">\n <button @click="toggleLevel(null)" :class="level == null ? \'pill pill--on\' : \'pill\'">All</button>\n <button @click="toggleLevel(\'info\')" :class="level===\'info\' ? \'pill pill--on\' : \'pill\'" style="color:var(--okdb-accent)">info</button>\n <button @click="toggleLevel(\'warn\')" :class="level===\'warn\' ? \'pill pill--on\' : \'pill\'" style="color:var(--okdb-warning)">warn</button>\n <button @click="toggleLevel(\'error\')" :class="level===\'error\' ? \'pill pill--on\' : \'pill\'" style="color:var(--okdb-danger)">error</button>\n <button @click="toggleLevel(\'debug\')" :class="level===\'debug\' ? \'pill pill--on\' : \'pill\'" style="color:var(--okdb-app-fg-muted)">debug</button>\n </div>\n </div>\n <if :="hasFeatures">\n <div class="syslog__toolbar syslog__toolbar--sub">\n <span class="syslog__sublabel">Feature</span>\n <div class="syslog__pills" style="flex-wrap:wrap;">\n <button @click="toggleFeature(null)" :class="feature == null ? \'pill pill--on\' : \'pill\'">all</button>\n <each :of="featureList" let:item="s">\n <button @click="toggleFeature(s)" :class="feature === s ? \'pill pill--on\' : \'pill\'">{{ s }}</button>\n </each>\n </div>\n </div>\n </if>\n <if :="hasEnvs">\n <div class="syslog__toolbar syslog__toolbar--sub">\n <span class="syslog__sublabel">Env</span>\n <div class="syslog__pills" style="flex-wrap:wrap;">\n <button @click="toggleEnv(null)" :class="env == null ? \'pill pill--on\' : \'pill\'">all</button>\n <each :of="envList" let:item="e">\n <button @click="toggleEnv(e)" :class="env === e ? \'pill pill--on\' : \'pill\'">{{ e }}</button>\n </each>\n </div>\n </div>\n </if>\n </if>\n\n <if :="source !== \'log\'">\n <div class="syslog__toolbar syslog__toolbar--sub">\n <span class="syslog__sublabel">Namespace</span>\n <div class="syslog__pills" style="flex-wrap:wrap;">\n <button @click="toggleNs(null)" :class="eventNs==null ? \'pill pill--on\' : \'pill\'">all</button>\n <button @click="toggleNs(\'engine\')" :class="eventNs===\'engine\' ? \'pill pill--on\' : \'pill\'" style="color:var(--okdb-accent)">engine</button>\n <button @click="toggleNs(\'type\')" :class="eventNs===\'type\' ? \'pill pill--on\' : \'pill\'" style="color:var(--okdb-purple)">type</button>\n <button @click="toggleNs(\'index\')" :class="eventNs===\'index\' ? \'pill pill--on\' : \'pill\'" style="color:var(--okdb-warning)">index</button>\n <button @click="toggleNs(\'embeddings\')" :class="eventNs===\'embeddings\' ? \'pill pill--on\' : \'pill\'" style="color:#2dd4bf">embeddings</button>\n <button @click="toggleNs(\'system\')" :class="eventNs===\'system\' ? \'pill pill--on\' : \'pill\'" style="color:var(--okdb-success)">system</button>\n <button @click="toggleNs(\'sync\')" :class="eventNs===\'sync\' ? \'pill pill--on\' : \'pill\'" style="color:var(--okdb-orange)">sync</button>\n <button @click="toggleNs(\'queue\')" :class="eventNs===\'queue\' ? \'pill pill--on\' : \'pill\'" style="color:var(--okdb-indigo)">queue</button>\n <button @click="toggleNs(\'processor\')" :class="eventNs===\'processor\' ? \'pill pill--on\' : \'pill\'" style="color:#f472b6">processor</button>\n <button @click="toggleNs(\'fts\')" :class="eventNs===\'fts\' ? \'pill pill--on\' : \'pill\'" style="color:var(--okdb-success)">fts</button>\n <button @click="toggleNs(\'env\')" :class="eventNs===\'env\' ? \'pill pill--on\' : \'pill\'" style="color:#67e8f9">env</button>\n <button @click="toggleNs(\'txn\')" :class="eventNs===\'txn\' ? \'pill pill--on\' : \'pill\'" style="color:var(--okdb-app-fg-muted)">txn</button>\n <button @click="toggleNs(\'item\')" :class="eventNs===\'item\' ? \'pill pill--on\' : \'pill\'" style="color:var(--okdb-app-fg)">item</button>\n </div>\n </div>\n </if>\n\n \x3c!-- Activity list --\x3e\n <div class="syslog__list" :ref="_listRef = $el">\n\n <if :="entries.length === 0">\n <div class="syslog__empty">\n <if :="!connected">Connecting to event stream…</if>\n <if :="connected && totalCount === 0">No activity yet.</if>\n <if :="connected && totalCount > 0">No entries match the current filter.</if>\n </div>\n </if>\n\n <each :of="entries" let:item="entry">\n <div :class="entry._kind === \'event\' ? \'syslog__row syslog__row--event\' : \'syslog__row\'">\n\n \x3c!-- Timestamp --\x3e\n <span class="syslog__ts">{{ fmtTime(entry._ts) }}</span>\n\n \x3c!-- LOG entry --\x3e\n <if :="entry._kind === \'log\'">\n <span class="syslog__level" :style="\'color:\' + levelColor(entry.level)">{{ entry.level }}</span>\n <span class="syslog__msg">{{ entry.msg }}</span>\n <if :="entry.meta?.feature">\n <span class="syslog__meta" style="opacity:.6" :title="fmtMeta(entry.meta)">{{ entry.meta.feature }}</span>\n </if>\n <if :="entry.context != null">\n <span class="syslog__meta" :title="fmtMeta(entry.context)">{{ fmtMeta(entry.context) }}</span>\n </if>\n </if>\n\n \x3c!-- EVENT entry --\x3e\n <if :="entry._kind === \'event\'">\n <span\n class="syslog__evtag"\n :style="\'color:\' + nsColor(entry._event) + \'; border-color:\' + nsColor(entry._event) + \'44\'"\n >{{ entry._event }}</span>\n <span class="syslog__msg syslog__msg--dim">{{ fmtPayload(entry) }}</span>\n </if>\n\n </div>\n </each>\n\n </div>\n\n</div>\n',style:"@keyframes dot-pulse{0%,to{opacity:1}50%{opacity:.4}}.syslog{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--okdb-app-bg-deep);border-radius:12px;overflow:hidden;border:1px solid var(--okdb-app-border)}.syslog__toolbar{display:flex;align-items:center;gap:6px;padding:7px 10px;background:var(--okdb-app-surface);border-bottom:1px solid var(--okdb-app-border);flex-shrink:0;flex-wrap:wrap}.syslog__toolbar--sub{padding:5px 10px;background:var(--okdb-app-bg-deep);border-bottom:1px solid var(--okdb-app-surface)}.syslog__title{font-weight:600;font-size:13px;white-space:nowrap;margin-right:2px}.syslog__sublabel{font-size:10px;opacity:.45;text-transform:uppercase;letter-spacing:.06em;white-space:nowrap;width:60px;flex-shrink:0}.syslog__spacer{flex:1}.syslog__pills{display:flex;gap:3px;flex-wrap:wrap}.syslog__search{background:var(--okdb-app-border);border:1px solid var(--okdb-app-border-strong);border-radius:6px;color:var(--okdb-warning);padding:3px 8px;font-size:12px;width:110px;outline:0}.syslog__search:focus{border-color:var(--okdb-accent)}.pill,.syslog__count{font-size:11px;white-space:nowrap}.syslog__count{opacity:.4}.pill{border:1px solid var(--okdb-app-border);background:0 0;padding:2px 9px;border-radius:999px;cursor:pointer;color:var(--okdb-app-fg-faint);transition:border-color .12s,color .12s,background .12s}.pill:hover{border-color:var(--okdb-app-fg-muted);color:var(--okdb-app-fg-muted)}.pill--on{border-color:var(--okdb-accent);background:var(--okdb-app-surface-2)}.pill--log,.pill--on{color:var(--okdb-accent)}.pill--event{color:var(--okdb-purple)}.syslog__list{flex:1;overflow-y:auto;font-family:monospace;font-size:12px;padding:2px 0;min-height:0}.syslog__row{display:flex;gap:8px;padding:2px 10px;border-bottom:1px solid var(--okdb-app-bg-deep);align-items:baseline;min-height:20px}.syslog__row--event,.syslog__row:hover{background:var(--okdb-app-surface)}.syslog__row--event:hover{background:var(--okdb-app-surface-2)}.syslog__ts{color:var(--okdb-app-fg-muted);flex-shrink:0;font-size:11px;user-select:none;width:86px}.syslog__level{width:40px;flex-shrink:0;font-weight:700;font-size:10px;text-transform:uppercase;letter-spacing:.04em}.syslog__evtag{flex-shrink:0;font-size:10px;padding:1px 6px;border-radius:4px;border:1px solid;white-space:nowrap;letter-spacing:.02em}.syslog__msg{flex:1;white-space:pre-wrap;word-break:break-word;color:var(--okdb-app-fg);min-width:0}.syslog__meta,.syslog__msg--dim{color:var(--okdb-app-fg-muted)}.syslog__meta{font-size:11px;max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0;cursor:default}.syslog__empty{padding:24px 14px;opacity:.4;font-style:italic;font-size:12px}.dot{width:7px;height:7px;border-radius:50%;display:inline-block;flex-shrink:0}.dot--on{background:var(--okdb-success);box-shadow:0 0 5px color-mix(in srgb,var(--okdb-success) 40%,transparent);animation:dot-pulse 2s ease-in-out infinite}.dot--off{background:var(--okdb-danger)}"};
|