@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
|
-
function _0x6951(_0x1d2ca7,_0x142abd){_0x1d2ca7=_0x1d2ca7-0xb4;const _0x1d77e5=_0x1d77();let _0x69516b=_0x1d77e5[_0x1d2ca7];return _0x69516b;}const _0x29892c=_0x6951;(function(_0x468f70,_0xbb9a35){const _0x567eff=_0x6951,_0x4eea51=_0x468f70();while(!![]){try{const _0x510ce3=parseInt(_0x567eff(0xb4))/0x1*(parseInt(_0x567eff(0xcc))/0x2)+parseInt(_0x567eff(0xce))/0x3*(parseInt(_0x567eff(0xc9))/0x4)+-parseInt(_0x567eff(0xca))/0x5*(-parseInt(_0x567eff(0xeb))/0x6)+parseInt(_0x567eff(0xde))/0x7*(-parseInt(_0x567eff(0xbd))/0x8)+-parseInt(_0x567eff(0xec))/0x9+-parseInt(_0x567eff(0xe3))/0xa+parseInt(_0x567eff(0xe6))/0xb;if(_0x510ce3===_0xbb9a35)break;else _0x4eea51['push'](_0x4eea51['shift']());}catch(_0x3de80d){_0x4eea51['push'](_0x4eea51['shift']());}}}(_0x1d77,0x77805));import _0x23cd8c from'@toolkit/elements/ok-icon.ok.js';import _0x5dbe35 from'@toolkit/core/ok-overlay.ok.js';import _0x111e5d from'../../../stores/events-store.js';import _0x229fab from'../../engines/parts/engine-row-item.ok.js';export default{'tag':_0x29892c(0xe1),'dependencies':[_0x5dbe35,_0x23cd8c,_0x229fab],'context':_0x301e09=>({'busy':!0x1,'engines':[],'selected':null,'_unsubs':[],'typeOrder':[_0x29892c(0xcb),_0x29892c(0xcd),_0x29892c(0xdd),_0x29892c(0xe5)],'typeLabel':{'embedder':_0x29892c(0xe8),'indexer':'Indexers','embed-worker':_0x29892c(0xea),'vector-search':_0x29892c(0xe9)},'itemLabel':{'embedder':_0x29892c(0xc1),'indexer':_0x29892c(0xb5),'embed-worker':_0x29892c(0xd7),'vector-search':_0x29892c(0xe9)},'itemColor':{'embedder':'var(--okdb-info)','indexer':'var(--okdb-purple)','embed-worker':_0x29892c(0xc8),'vector-search':_0x29892c(0xd1)},async 'load'(){const _0x59ae90=_0x29892c;this[_0x59ae90(0xb9)]=!0x0;try{const _0x1ffd12=_0x301e09['$ok']?.[_0x59ae90(0xb7)]?.['okdb']?.[_0x59ae90(0xbc)]||_0x59ae90(0xc2),[_0x29ad37,_0x4ba439]=await Promise[_0x59ae90(0xc7)]([fetch(__ENV__['API']+'/env/'+encodeURIComponent(_0x1ffd12)+_0x59ae90(0xd2))[_0x59ae90(0xc6)](_0x4510cc=>_0x4510cc[_0x59ae90(0xb6)]()),fetch(__ENV__[_0x59ae90(0xe7)]+_0x59ae90(0xe4))[_0x59ae90(0xc6)](_0x278668=>_0x278668[_0x59ae90(0xb6)]())]),_0x37b780=_0x59ae90(0xdc)===_0x29ad37[_0x59ae90(0xda)]?_0x29ad37[_0x59ae90(0xd4)]?.[_0x59ae90(0xc5)]??[]:[],_0x48133b=_0x59ae90(0xdc)===_0x4ba439['status']?_0x4ba439['value']?.['data']??[]:[];this[_0x59ae90(0xe0)]=[..._0x48133b,..._0x37b780],_0x301e09[_0x59ae90(0xdb)](_0x59ae90(0xd6),this['engines']);}catch(_0xd46520){console[_0x59ae90(0xbe)]('embed-engine-list\x20load\x20error',_0xd46520),this[_0x59ae90(0xe0)]=[];}finally{this[_0x59ae90(0xb9)]=!0x1;}},async 'refresh'(){await this['load']();},get 'grouped'(){const _0x1a6f34=_0x29892c,_0x2f3f3d={};for(const _0x4f6444 of this[_0x1a6f34(0xd8)])_0x2f3f3d[_0x4f6444]=[];for(const _0x5a7422 of this[_0x1a6f34(0xe0)])_0x2f3f3d[_0x5a7422[_0x1a6f34(0xd3)]]&&_0x2f3f3d[_0x5a7422['type']][_0x1a6f34(0xba)](_0x5a7422);return _0x2f3f3d;},'hasEngines'(_0xe75a88){const _0xf807ea=_0x29892c;return(this[_0xf807ea(0xd9)][_0xe75a88]||[])[_0xf807ea(0xd0)]>0x0;},'selectNone'(){const _0x5592b5=_0x29892c;this['selected']=null,_0x301e09[_0x5592b5(0xdb)](_0x5592b5(0xbb),null);},'openCreate'(){const _0x190e95=_0x29892c;this[_0x190e95(0xd5)]='__create__',_0x301e09[_0x190e95(0xdb)](_0x190e95(0xc4),null);},'clearSelection'(){const _0x49a6c5=_0x29892c;this[_0x49a6c5(0xd5)]=null;},'select'(_0xc2ccad){const _0x5d6e64=_0x29892c;this['selected']=_0xc2ccad?.[_0x5d6e64(0xcf)]??null,_0x301e09[_0x5d6e64(0xdb)]('select',_0xc2ccad);},'pipeline':_0x3ca966=>_0x3ca966[_0x29892c(0xe2)]?.['pipeline']??null}),async 'mount'(){const _0x17f162=_0x29892c;await this[_0x17f162(0xc3)]();const _0x48181d=()=>this[_0x17f162(0xc3)]();this[_0x17f162(0xb8)]=[_0x111e5d['on']('engine:started',_0x48181d),_0x111e5d['on'](_0x17f162(0xbf),_0x48181d),_0x111e5d['on']('engine:error',_0x48181d),_0x111e5d['on'](_0x17f162(0xc0),_0x48181d),_0x111e5d['on']('engine:uninstalled',_0x48181d),_0x111e5d['on']('embeddings:pipeline:ready',_0x48181d),_0x111e5d['on']('embeddings:indexer:ready',_0x48181d),_0x111e5d['on']('embeddings:indexer:flushed',_0x48181d)];},'unmount'(){const _0x56ee81=_0x29892c;for(const _0xd8f410 of this[_0x56ee81(0xb8)])_0xd8f410();this[_0x56ee81(0xb8)]=[];},'template':_0x29892c(0xdf),'style':'.eng-row{display:flex;align-items:center;gap:8px;padding:6px\x208px;border-radius:6px;border:1px\x20solid\x20transparent;background:0\x200;cursor:pointer;width:100%}.eng-row--on,.eng-row:hover{background:var(--okdb-app-surface);border-color:var(--okdb-app-border)}.eng-row--on{border-color:var(--okdb-accent)}.pipeline-tag{flex-shrink:0;max-width:72px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:10px;padding:1px\x205px;border-radius:999px;border:1px\x20solid\x20color-mix(in\x20srgb,var(--okdb-indigo)\x2033%,transparent);color:var(--okdb-indigo);background:color-mix(in\x20srgb,var(--okdb-indigo)\x207%,transparent);letter-spacing:.02em}'};function _0x1d77(){const _0x11df97=['API','Embedders','Search','Workers','66Prqlcz','6073416SClQAI','347mMfVqV','Indexer','json','stores','_unsubs','busy','push','select','selectedEnv','4267960KgHvaG','error','engine:stopped','engine:installed','Embedder','default','load','create','data','then','allSettled','var(--okdb-warning)','116ManIZD','381125nlIAHu','embedder','3396cCsxAS','indexer','30159AEdQXd','key','length','var(--okdb-accent)','/engines','type','value','selected','loaded','Worker','typeOrder','grouped','status','$dispatch','fulfilled','embed-worker','7sRIBrD','\x0a<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:10px;\x20height:100%;\x20min-height:0;\x22>\x0a\x0a\x20\x20<div\x20style=\x22display:flex;\x20align-items:center;\x20justify-content:space-between;\x20gap:8px;\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22font-weight:600;\x22>Engines</div>\x0a\x20\x20\x20\x20<button\x20@click=\x22load\x22\x20:disabled=\x22busy\x22\x20style=\x22opacity:.8;\x22>↻</button>\x0a\x20\x20</div>\x0a\x0a\x20\x20<if\x20:=\x22busy\x22>\x0a\x20\x20\x20\x20<ok-overlay>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22loader-center\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<ok-icon\x20name=\x22loader\x22\x20class=\x22spin\x22\x20style=\x22width:24px;height:24px;\x22></ok-icon>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</ok-overlay>\x0a\x20\x20</if>\x0a\x0a\x20\x20<!--\x20Top\x20nav:\x20Overview\x20+\x20Create\x20-->\x0a\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:2px;\x20margin-bottom:4px;\x22>\x0a\x20\x20\x20\x20<button\x0a\x20\x20\x20\x20\x20\x20:class=\x22selected\x20===\x20null\x20?\x20\x27eng-row\x20eng-row--on\x27\x20:\x20\x27eng-row\x27\x22\x0a\x20\x20\x20\x20\x20\x20@click=\x22selectNone\x22\x0a\x20\x20\x20\x20>\x0a\x20\x20\x20\x20\x20\x20<span\x20style=\x22width:14px;\x20text-align:center;\x20flex-shrink:0;\x22>⊞</span>\x0a\x20\x20\x20\x20\x20\x20<span>Overview</span>\x0a\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20<button\x0a\x20\x20\x20\x20\x20\x20:class=\x22selected\x20===\x20\x27__create__\x27\x20?\x20\x27eng-row\x20eng-row--on\x27\x20:\x20\x27eng-row\x27\x22\x0a\x20\x20\x20\x20\x20\x20@click=\x22openCreate\x22\x0a\x20\x20\x20\x20>\x0a\x20\x20\x20\x20\x20\x20<span\x20style=\x22width:14px;\x20text-align:center;\x20flex-shrink:0;\x20color:var(--okdb-accent);\x22>+</span>\x0a\x20\x20\x20\x20\x20\x20<span\x20style=\x22color:var(--okdb-accent);\x22>Create\x20Engine</span>\x0a\x20\x20\x20\x20</button>\x0a\x20\x20</div>\x0a\x0a\x20\x20<div\x20style=\x22border-top:1px\x20solid\x20var(--okdb-app-border);\x20margin:0\x200\x204px;\x22></div>\x0a\x0a\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:12px;\x20overflow:auto;\x20min-height:0;\x20padding-right:4px;\x22>\x0a\x20\x20\x20\x20<each\x20:of=\x22typeOrder\x22\x20let:item=\x22t\x22>\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22hasEngines(t)\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20text-transform:uppercase;\x20opacity:.5;\x20letter-spacing:.06em;\x20margin-bottom:4px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20typeLabel[t]\x20}}\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:flex;\x20flex-direction:column;\x20gap:2px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<each\x20:of=\x22grouped[t]\x22\x20let:item=\x22eng\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<engine-row-item\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:engine=\x22eng\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:label=\x22itemLabel[t]\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:label-color=\x22itemColor[t]\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:subtitle=\x22eng.status\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20action-label=\x22\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:selected=\x22selected\x20===\x20eng.key\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@select=\x22select($event.detail)\x22\x0a\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<if\x20:=\x22pipeline(eng)\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22pipeline-tag\x22\x20:title=\x22\x27pipeline:\x20\x27\x20+\x20pipeline(eng)\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20pipeline(eng)\x20}}\x0a\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</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</engine-row-item>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</each>\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\x20\x20\x20\x20</each>\x0a\x0a\x20\x20\x20\x20<if\x20:=\x22engines.length\x20===\x200\x20&&\x20!busy\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22opacity:.5;\x20font-size:12px;\x22>No\x20engines\x20found.</div>\x0a\x20\x20\x20\x20</if>\x0a\x20\x20</div>\x0a\x0a</div>\x0a','engines','embed-engine-list','meta','2525050rcgdeF','/embeddings/embedders','vector-search','2541913LkPGfF'];_0x1d77=function(){return _0x11df97;};return _0x1d77();}
|
|
1
|
+
import e from"@toolkit/elements/ok-icon.ok.js";import n from"@toolkit/core/ok-overlay.ok.js";import t from"../../../stores/events-store.js";import i from"../../engines/parts/engine-row-item.ok.js";export default{tag:"embed-engine-list",dependencies:[n,e,i],context:e=>({busy:!1,engines:[],selected:null,_unsubs:[],typeOrder:["embedder","indexer","embed-worker","vector-search"],typeLabel:{embedder:"Embedders",indexer:"Indexers","embed-worker":"Workers","vector-search":"Search"},itemLabel:{embedder:"Embedder",indexer:"Indexer","embed-worker":"Worker","vector-search":"Search"},itemColor:{embedder:"var(--okdb-info)",indexer:"var(--okdb-purple)","embed-worker":"var(--okdb-warning)","vector-search":"var(--okdb-accent)"},async load(){this.busy=!0;try{const n=e.$ok?.stores?.okdb?.selectedEnv||"default",[t,i]=await Promise.allSettled([fetch(`${__ENV__.API}/env/${encodeURIComponent(n)}/engines`).then(e=>e.json()),fetch(`${__ENV__.API}/embeddings/embedders`).then(e=>e.json())]),o="fulfilled"===t.status?t.value?.data??[]:[],r="fulfilled"===i.status?i.value?.data??[]:[];this.engines=[...r,...o],e.$dispatch("loaded",this.engines)}catch(e){console.error("embed-engine-list load error",e),this.engines=[]}finally{this.busy=!1}},async refresh(){await this.load()},get grouped(){const e={};for(const n of this.typeOrder)e[n]=[];for(const n of this.engines)e[n.type]&&e[n.type].push(n);return e},hasEngines(e){return(this.grouped[e]||[]).length>0},selectNone(){this.selected=null,e.$dispatch("select",null)},openCreate(){this.selected="__create__",e.$dispatch("create",null)},clearSelection(){this.selected=null},select(n){this.selected=n?.key??null,e.$dispatch("select",n)},pipeline:e=>e.meta?.pipeline??null}),async mount(){await this.load();const e=()=>this.load();this._unsubs=[t.on("engine:started",e),t.on("engine:stopped",e),t.on("engine:error",e),t.on("engine:installed",e),t.on("engine:uninstalled",e),t.on("embeddings:pipeline:ready",e),t.on("embeddings:indexer:ready",e),t.on("embeddings:indexer:flushed",e)]},unmount(){for(const e of this._unsubs)e();this._unsubs=[]},template:'\n<div style="display:flex; flex-direction:column; gap:10px; height:100%; min-height:0;">\n\n <div style="display:flex; align-items:center; justify-content:space-between; gap:8px;">\n <div style="font-weight:600;">Engines</div>\n <button @click="load" :disabled="busy" style="opacity:.8;">↻</button>\n </div>\n\n <if :="busy">\n <ok-overlay>\n <div class="loader-center">\n <ok-icon name="loader" class="spin" style="width:24px;height:24px;"></ok-icon>\n </div>\n </ok-overlay>\n </if>\n\n \x3c!-- Top nav: Overview + Create --\x3e\n <div style="display:flex; flex-direction:column; gap:2px; margin-bottom:4px;">\n <button\n :class="selected === null ? \'eng-row eng-row--on\' : \'eng-row\'"\n @click="selectNone"\n >\n <span style="width:14px; text-align:center; flex-shrink:0;">⊞</span>\n <span>Overview</span>\n </button>\n <button\n :class="selected === \'__create__\' ? \'eng-row eng-row--on\' : \'eng-row\'"\n @click="openCreate"\n >\n <span style="width:14px; text-align:center; flex-shrink:0; color:var(--okdb-accent);">+</span>\n <span style="color:var(--okdb-accent);">Create Engine</span>\n </button>\n </div>\n\n <div style="border-top:1px solid var(--okdb-app-border); margin:0 0 4px;"></div>\n\n <div style="display:flex; flex-direction:column; gap:12px; overflow:auto; min-height:0; padding-right:4px;">\n <each :of="typeOrder" let:item="t">\n <if :="hasEngines(t)">\n <div>\n <div style="font-size:11px; text-transform:uppercase; opacity:.5; letter-spacing:.06em; margin-bottom:4px;">\n {{ typeLabel[t] }}\n </div>\n <div style="display:flex; flex-direction:column; gap:2px;">\n <each :of="grouped[t]" let:item="eng">\n <engine-row-item\n :engine="eng"\n :label="itemLabel[t]"\n :label-color="itemColor[t]"\n :subtitle="eng.status"\n action-label=""\n :selected="selected === eng.key"\n @select="select($event.detail)"\n >\n <if :="pipeline(eng)">\n <span class="pipeline-tag" :title="\'pipeline: \' + pipeline(eng)">\n {{ pipeline(eng) }}\n </span>\n </if>\n </engine-row-item>\n </each>\n </div>\n </div>\n </if>\n </each>\n\n <if :="engines.length === 0 && !busy">\n <div style="opacity:.5; font-size:12px;">No engines found.</div>\n </if>\n </div>\n\n</div>\n',style:".eng-row{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:6px;border:1px solid transparent;background:0 0;cursor:pointer;width:100%}.eng-row--on,.eng-row:hover{background:var(--okdb-app-surface);border-color:var(--okdb-app-border)}.eng-row--on{border-color:var(--okdb-accent)}.pipeline-tag{flex-shrink:0;max-width:72px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:10px;padding:1px 5px;border-radius:999px;border:1px solid color-mix(in srgb,var(--okdb-indigo) 33%,transparent);color:var(--okdb-indigo);background:color-mix(in srgb,var(--okdb-indigo) 7%,transparent);letter-spacing:.02em}"};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function _0x46e0(){const _0x14476a=['docsError','flushing','storage_key','$attr','status','/retry-failed','s\x20ago','markDelete\x20failed','join','retried','docsLoadMs','10ZzYwXu','\x20doc(s)','_pipelineUrl','chunk_failed','27ZqlBgs','21liatoT','dims','/flush','Flushed','\x0a<engine-panel-shell\x0a\x20\x20:engine=\x22eng\x22\x0a\x20\x20:title=\x22name\x22\x0a\x20\x20type-label=\x22indexer\x22\x0a\x20\x20type-color=\x22var(--okdb-purple)\x22\x0a\x20\x20:badges=\x22headerBadges\x22\x0a\x20\x20show-refresh=\x22true\x22\x0a\x20\x20fill=\x22true\x22\x0a\x20\x20:refresh-busy=\x22busy\x20||\x20docsBusy\x20||\x20queueBusy\x20||\x20flushing\x22\x0a\x20\x20:on-refresh=\x22onRefresh\x22\x0a\x20\x20:on-pipeline=\x22viewPipeline\x22\x0a\x20\x20@engine-updated=\x22$dispatch(\x27engine-updated\x27,\x20$event.detail)\x22\x0a\x20\x20@refresh=\x22$dispatch(\x27refresh\x27)\x22\x0a\x20\x20@deleted=\x22$dispatch(\x27deleted\x27,\x20$event.detail)\x22\x0a>\x0a\x20\x20<if\x20:=\x22error\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22color:var(--okdb-danger);\x20font-size:13px;\x22>{{\x20error\x20}}</div>\x0a\x20\x20</if>\x0a\x0a\x0a\x20\x20<if\x20:=\x22indexer\x22>\x0a\x20\x20\x20\x20<div\x20class=\x22stack-compact\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22card\x20stack-compact\x22\x20style=\x22padding:14px;gap:12px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;flex-direction:column;gap:8px;min-width:0;flex:1;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22pill-row\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22info-pill\x22\x20title=\x22Source\x20type\x20being\x20indexed.\x22>{{\x20indexer.source_type\x20||\x20\x27—\x27\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22info-pill\x22\x20title=\x22Source\x20environment.\x22>source\x20env:\x20{{\x20sourceEnvName\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22info-pill\x22\x20title=\x22Embedder\x20used\x20to\x20create\x20vectors.\x22>embedder:\x20{{\x20embedderName\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22info-pill\x22\x20title=\x22Storage\x20key\x20for\x20the\x20vector\x20store.\x22>store:\x20{{\x20storageKey\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22info-pill\x22\x20:style=\x22\x27border-color:\x27\x20+\x20(isCaughtUp\x20?\x20\x27color-mix(in\x20srgb,\x20var(--okdb-success)\x2033%,\x20transparent)\x27\x20:\x20\x27color-mix(in\x20srgb,\x20var(--okdb-warning)\x2033%,\x20transparent)\x27)\x20+\x20\x27;color:\x27\x20+\x20(isCaughtUp\x20?\x20\x27var(--okdb-success)\x27\x20:\x20\x27var(--okdb-warning)\x27)\x20+\x20\x27;background:\x27\x20+\x20(isCaughtUp\x20?\x20\x27color-mix(in\x20srgb,\x20var(--okdb-success)\x207%,\x20transparent)\x27\x20:\x20\x27color-mix(in\x20srgb,\x20var(--okdb-warning)\x207%,\x20transparent)\x27)\x20+\x20\x27;\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20isCaughtUp\x20?\x20\x27caught\x20up\x27\x20:\x20\x27processing\x27\x20}}\x0a\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</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22story-lead\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Watches\x20<strong>{{\x20indexer.source_type\x20||\x20\x27—\x27\x20}}</strong>\x20and\x20keeps\x20vectors\x20current\x20in\x20<strong>{{\x20storageKey\x20}}</strong>.\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<div\x20class=\x22story-note\x22>Flush\x20to\x20force\x20pending\x20writes\x20through\x20now.\x20Use\x20the\x20document\x20table\x20below\x20to\x20inspect\x20failures,\x20retry\x20queue-backed\x20docs,\x20and\x20inspect\x20stored\x20vectors.</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22metric-grid\x20metric-grid--compact\x22\x20style=\x22min-width:min(100%,\x20420px);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22metric-card\x20metric-card--compact\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22metric-title\x22>Vectors</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22metric-value\x22\x20style=\x22color:var(--okdb-success);\x22>{{\x20vectorCount.toLocaleString()\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\x20\x20<div\x20class=\x22metric-card\x20metric-card--compact\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22metric-title\x22>Done</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22metric-value\x22\x20style=\x22color:var(--okdb-success);\x22>{{\x20doneDocs.toLocaleString()\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\x20\x20<div\x20class=\x22metric-card\x20metric-card--compact\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22metric-title\x22>Pending</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22metric-value\x22\x20:style=\x22\x27color:\x27\x20+\x20(pendingDocs\x20>\x200\x20?\x20\x27var(--okdb-warning)\x27\x20:\x20\x27var(--okdb-app-fg)\x27)\x22>{{\x20pendingDocs.toLocaleString()\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\x20\x20<div\x20class=\x22metric-card\x20metric-card--compact\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22metric-title\x22>Failed</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22metric-value\x22\x20:style=\x22\x27color:\x27\x20+\x20(failedDocs\x20>\x200\x20?\x20\x27var(--okdb-danger)\x27\x20:\x20\x27var(--okdb-app-fg)\x27)\x22>{{\x20failedDocs.toLocaleString()\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</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;align-items:center;gap:10px;flex-wrap:wrap;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22flush\x22\x20:disabled=\x22flushing\x20||\x20!eng.isRunning\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20flushing\x20?\x20\x27Flushing…\x27\x20:\x20\x27Flush\x27\x20}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22story-note\x22>Changelog\x20{{\x20indexer.last_seen_clock\x20??\x20\x27—\x27\x20}}\x20/\x20{{\x20indexer.head_clock\x20??\x20\x27—\x27\x20}}\x20·\x20{{\x20clockPct\x20}}%</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22search\x20&&\x20search.count\x20!=\x20null\x20&&\x20search.count\x20!==\x20indexer.vector_count\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22story-note\x22\x20style=\x22color:var(--okdb-warning);\x22\x20title=\x22In-memory\x20index\x20differs\x20from\x20storage\x20—\x20rebuild\x20may\x20be\x20needed\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20search\x20index:\x20{{\x20search.count.toLocaleString()\x20}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22background:var(--okdb-app-border);\x20border-radius:6px;\x20height:6px;\x20overflow:hidden;\x22\x20:title=\x22clockPct\x20+\x20\x27%\x20of\x20changelog\x20processed\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20:style=\x22\x27height:100%;\x20border-radius:6px;\x20transition:width\x20.3s;\x20background:\x27\x20+\x20(isCaughtUp\x20?\x20\x27var(--okdb-success)\x27\x20:\x20\x27var(--okdb-accent)\x27)\x20+\x20\x27;\x20width:\x27\x20+\x20clockPct\x20+\x20\x27%\x27\x22></div>\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<div\x20class=\x22card\x20stack-compact\x22\x20style=\x22padding:14px;gap:12px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22card-title\x22\x20style=\x22margin:0;\x22>Indexer\x20settings</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22kv-grid\x20kv-grid--compact\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22kv-key\x22>source\x20type</span><span\x20class=\x22kv-val\x22>{{\x20indexer.source_type\x20||\x20\x27—\x27\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22kv-key\x22>source\x20env</span><span\x20class=\x22kv-val\x22>{{\x20sourceEnvName\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22kv-key\x22>embedder</span><span\x20class=\x22kv-val\x22>{{\x20embedderName\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22kv-key\x22>storage\x20key</span><span\x20class=\x22kv-val\x22>{{\x20storageKey\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22kv-key\x22>mode</span><span\x20class=\x22kv-val\x22>{{\x20indexer.mode\x20||\x20\x27inline\x27\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22indexer.job_type\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22kv-key\x22>job\x20type</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22kv-val\x22\x20style=\x22font-size:11px;font-family:monospace;\x22>{{\x20indexer.job_type\x20}}</span>\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</div>\x0a\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22queueMode\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22card\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20align-items:center;\x20gap:10px;\x20margin-bottom:10px;\x20flex-wrap:wrap;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22card-title\x22\x20style=\x22margin:0;\x22>Queue</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:11px;\x20opacity:.5;\x22>job\x20type:\x20<span\x20style=\x22font-family:monospace;\x22>{{\x20indexer.job_type\x20}}</span></span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22loadQueueStats\x22\x20:disabled=\x22queueBusy\x22\x20style=\x22margin-left:auto;\x20font-size:11px;\x20padding:2px\x208px;\x20opacity:.7;\x22>↻</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22queueStats\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:grid;\x20grid-template-columns:repeat(4,1fr);\x20gap:8px;\x20text-align:center;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22stat-box\x22\x20style=\x22background:var(--okdb-app-border);\x20border-radius:6px;\x20padding:8px\x204px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:22px;\x20font-weight:600;\x20color:var(--okdb-warning);\x22>{{\x20queueStats.byStatus?.pending\x20??\x200\x20}}</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:10px;\x20opacity:.6;\x20margin-top:2px;\x22>Pending</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\x20\x20<div\x20class=\x22stat-box\x22\x20style=\x22background:var(--okdb-app-border);\x20border-radius:6px;\x20padding:8px\x204px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:22px;\x20font-weight:600;\x20color:var(--okdb-info);\x22>{{\x20queueStats.byStatus?.running\x20??\x200\x20}}</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:10px;\x20opacity:.6;\x20margin-top:2px;\x22>Running</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\x20\x20<div\x20class=\x22stat-box\x22\x20style=\x22background:var(--okdb-app-border);\x20border-radius:6px;\x20padding:8px\x204px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:22px;\x20font-weight:600;\x20color:var(--okdb-success);\x22>{{\x20queueStats.byStatus?.done\x20??\x200\x20}}</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:10px;\x20opacity:.6;\x20margin-top:2px;\x22>Done</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\x20\x20<div\x20class=\x22stat-box\x22\x20style=\x22background:var(--okdb-app-border);\x20border-radius:6px;\x20padding:8px\x204px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:22px;\x20font-weight:600;\x20color:var(--okdb-danger);\x22>{{\x20queueStats.byStatus?.failed\x20??\x200\x20}}</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:10px;\x20opacity:.6;\x20margin-top:2px;\x22>Failed</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</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22margin-top:8px;\x20font-size:11px;\x20opacity:.4;\x20font-style:italic;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Queue\x20tracks\x20individual\x20job\x20attempts.\x20Done\x20jobs\x20are\x20auto-pruned;\x20failed\x20jobs\x20persist\x20until\x20retried.\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\x20\x20<if\x20:=\x22!queueStats\x20&&\x20!queueBusy\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;\x20opacity:.4;\x20font-style:italic;\x22>No\x20queue\x20stats\x20for\x20this\x20job\x20type\x20—\x20queue\x20may\x20be\x20idle\x20or\x20feature\x20inactive.</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22queueBusy\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;\x20opacity:.4;\x22>Loading…</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<!--\x20Doc\x20status\x20table\x20-->\x0a\x20\x20<div\x20class=\x22card\x22\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:10px;\x20flex:1;\x20min-height:0;\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20align-items:center;\x20gap:8px;\x20flex-wrap:wrap;\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22card-title\x22\x20style=\x22margin:0;\x22>Documents</div>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20gap:6px;\x20flex-wrap:wrap;\x20margin-left:auto;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22setDocsStatus(null)\x22\x20\x20\x20\x20\x20\x20\x20:class=\x22docsStatus\x20==\x20null\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=\x22setDocsStatus(\x27pending\x27)\x22\x20\x20:class=\x22docsStatus\x20===\x20\x27pending\x27\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>Pending</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22setDocsStatus(\x27done\x27)\x22\x20\x20\x20\x20\x20:class=\x22docsStatus\x20===\x20\x27done\x27\x20\x20\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>Done</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22setDocsStatus(\x27failed\x27)\x22\x20\x20\x20:class=\x22docsStatus\x20===\x20\x27failed\x27\x20\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>Failed</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22setDocsStatus(\x27partial\x27)\x22\x20\x20:class=\x22docsStatus\x20===\x20\x27partial\x27\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>Partial</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22setDocsStatus(\x27deleted\x27)\x22\x20\x20:class=\x22docsStatus\x20===\x20\x27deleted\x27\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>Deleted</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22loadDocs\x22\x20:disabled=\x22docsBusy\x22\x20style=\x22opacity:.8;\x22>↻</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22indexer?.mode\x20===\x20\x27queue\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22retryFailed()\x22\x20:disabled=\x22docsBusy\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22color:var(--okdb-warning);\x20border-color:color-mix(in\x20srgb,\x20var(--okdb-warning)\x2027%,\x20transparent);\x20font-size:12px;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20title=\x22Re-enqueue\x20all\x20FAILED\x20docs\x20for\x20this\x20indexer\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20↺\x20Retry\x20Failed\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22retryStuckPending()\x22\x20:disabled=\x22docsBusy\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22color:var(--okdb-app-fg-muted);\x20border-color:color-mix(in\x20srgb,\x20var(--okdb-app-fg-muted)\x2027%,\x20transparent);\x20font-size:12px;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20title=\x22Re-enqueue\x20FAILED\x20+\x20stuck\x20PENDING\x20docs\x20(use\x20when\x20queue\x20jobs\x20were\x20purged\x20externally)\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20↺\x20Retry\x20Stuck\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20<if\x20:=\x22docsError\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22color:var(--okdb-danger);\x20font-size:13px;\x22>{{\x20docsError\x20}}</div>\x0a\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20<div\x20style=\x22position:relative;\x20flex:1;\x20min-height:0;\x20overflow:auto;\x22>\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22docsBusy\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<ok-overlay>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22loader-center\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<ok-icon\x20name=\x22loader\x22\x20class=\x22spin\x22\x20style=\x22width:28px;height:28px;\x22></ok-icon>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</ok-overlay>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20\x20\x20<ok-table\x20:data=\x22docs\x22\x20no-scroll\x20style=\x22width:100%;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<columns>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<column\x20width=\x22130px\x22\x20no-resize>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<header>Status</header>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<cell\x20let:row>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20:style=\x22\x27color:\x27\x20+\x20statusColor(row.status)\x20+\x20\x27;\x20font-size:12px;\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20row.status\x20}}\x0a\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<if\x20:=\x22chunkProgress(row)\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:11px;\x20opacity:.7;\x20margin-left:4px;\x22>{{\x20chunkProgress(row)\x20}}</span>\x0a\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</cell>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</column>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<column>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<header>Source\x20Key</header>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<cell\x20let:row>{{\x20row.source_key\x20}}</cell>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</column>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<column\x20width=\x22110px\x22\x20no-resize>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<header>Updated</header>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<cell\x20let:row>{{\x20relTime(row.updated)\x20}}</cell>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</column>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<column\x20width=\x22200px\x22\x20no-resize>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<header>Error</header>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<cell\x20let:row>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22row.error\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22color:var(--okdb-danger);\x20font-size:11px;\x20opacity:.85;\x22\x20:title=\x22row.error\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20row.error.slice(0,\x2060)\x20}}{{\x20row.error.length\x20>\x2060\x20?\x20\x27…\x27\x20:\x20\x27\x27\x20}}\x0a\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</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</cell>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</column>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<column\x20width=\x22140px\x22\x20no-resize>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<header>Actions</header>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<cell\x20let:row>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20gap:4px;\x20flex-wrap:wrap;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22(row.status\x20===\x20\x27failed\x27\x20||\x20row.status\x20===\x20\x27pending\x27)\x20&&\x20indexer?.mode\x20===\x20\x27queue\x27\x22>\x0a\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@click=\x22retryDoc(row)\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:disabled=\x22row._busy\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22font-size:11px;\x20padding:3px\x208px;\x20color:var(--okdb-warning);\x20border-color:color-mix(in\x20srgb,\x20var(--okdb-warning)\x2027%,\x20transparent);\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20title=\x22Re-enqueue\x20this\x20document\x20for\x20embedding\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20>↺\x20Retry</button>\x0a\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<if\x20:=\x22row.status\x20!==\x20\x27deleted\x27\x22>\x0a\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@click=\x22markDeleteDoc(row)\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:disabled=\x22row._busy\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22font-size:11px;\x20padding:3px\x208px;\x20color:var(--okdb-danger);\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20>Delete</button>\x0a\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</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</cell>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</column>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</columns>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20<expanded\x20let:row>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22padding:10px;\x20font-size:12px;\x20display:flex;\x20flex-direction:column;\x20gap:6px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22kv-grid\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22kv-key\x22>source_key</span>\x20\x20<span\x20class=\x22kv-val\x22>{{\x20row.source_key\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22kv-key\x22>engine_key</span>\x20\x20<span\x20class=\x22kv-val\x22>{{\x20row.engine_key\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22kv-key\x22>mode</span>\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22kv-val\x22>{{\x20row.mode\x20||\x20\x27—\x27\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22kv-key\x22>clock</span>\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22kv-val\x22>{{\x20row.clock\x20??\x20\x27—\x27\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22kv-key\x22>created</span>\x20\x20\x20\x20\x20\x20<span\x20class=\x22kv-val\x22>{{\x20relTime(row.created)\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22kv-key\x22>updated</span>\x20\x20\x20\x20\x20\x20<span\x20class=\x22kv-val\x22>{{\x20relTime(row.updated)\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22row.total_chunks\x20>\x200\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22kv-key\x22>chunks</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20class=\x22kv-val\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22color:var(--okdb-success);\x22>{{\x20row.chunk_done\x20??\x200\x20}}\x20done</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22row.chunk_failed\x20>\x200\x22><span\x20style=\x22color:var(--okdb-danger);\x22>\x20·\x20{{\x20row.chunk_failed\x20}}\x20failed</span></if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22(row.chunk_pending\x20??\x200)\x20>\x200\x22><span\x20style=\x22color:var(--okdb-warning);\x22>\x20·\x20{{\x20row.chunk_pending\x20}}\x20pending</span></if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.5;\x22>\x20/\x20{{\x20row.total_chunks\x20}}\x20total</span>\x0a\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</if>\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:=\x22row.error\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22color:var(--okdb-danger);\x20white-space:pre-wrap;\x22>{{\x20row.error\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<!--\x20Vector\x20viewer\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22row.status\x20===\x20\x27done\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20align-items:center;\x20gap:8px;\x20margin-top:4px;\x22>\x0a\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@click=\x22toggleVector(row)\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22font-size:11px;\x20padding:3px\x2010px;\x20color:var(--okdb-purple);\x20border-color:var(--okdb-purple);\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:disabled=\x22vectorCache[row.source_key]?.busy\x22\x0a\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<if\x20:=\x22vectorCache[row.source_key]?.busy\x22>…</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22!vectorCache[row.source_key]?.busy\x20&&\x20!vectorCache[row.source_key]?.vector\x20&&\x20!vectorCache[row.source_key]?.error\x22>🔍\x20View\x20Vector</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22vectorCache[row.source_key]?.vector\x20||\x20vectorCache[row.source_key]?.error\x22>✕\x20Hide\x20Vector</if>\x0a\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<if\x20:=\x22vectorCache[row.source_key]?.dims\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.5;\x20font-size:11px;\x22>{{\x20vectorCache[row.source_key].dims\x20}}\x20dims</span>\x0a\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</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22vectorCache[row.source_key]?.error\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22color:var(--okdb-danger);\x20font-size:11px;\x22>{{\x20vectorCache[row.source_key].error\x20}}</div>\x0a\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<if\x20:=\x22vectorCache[row.source_key]?.vector\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22background:var(--okdb-app-bg-deep);\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:6px;\x20padding:8px;\x20font-family:monospace;\x20font-size:11px;\x20word-break:break-all;\x20color:var(--okdb-purple);\x20max-height:80px;\x20overflow:auto;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20fmtVec(vectorCache[row.source_key].vector)\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\x20\x20</if>\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\x20\x20\x20\x20\x20\x20\x20\x20</expanded>\x0a\x20\x20\x20\x20\x20\x20</ok-table>\x0a\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22docs.length\x20===\x200\x20&&\x20!docsBusy\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22opacity:.5;\x20font-size:13px;\x20padding:12px\x200;\x22>No\x20documents\x20found.</div>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20<div\x20style=\x22font-size:12px;\x20opacity:.6;\x20display:flex;\x20gap:12px;\x20align-items:center;\x20flex-wrap:wrap;\x22>\x0a\x20\x20\x20\x20\x20\x20<span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20Showing\x20{{\x20docs.length\x20}}{{\x20docs.length\x20>=\x20docsLimit\x20?\x20\x27+\x27\x20:\x20\x27\x27\x20}}\x20{{\x20docsStatus\x20||\x20\x27\x27\x20}}\x20docs\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22docsLoadMs\x20!==\x20null\x22>\x20in\x20{{\x20docsLoadMs\x20}}ms</if>\x0a\x20\x20\x20\x20\x20\x20</span>\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22indexer?.doc_counts?.total\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.7;\x22>Total\x20tracked:\x20{{\x20indexer.doc_counts.total.toLocaleString()\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</div>\x0a</engine-panel-shell>\x0a','1112628ewzyid','now','#9ca3af','min','engine:error','791216rqjjPx','queue','docsBusy','embeddings:indexer:ready','embeddings:doc:status_change','engine:stopped','confirm','queueStats','set','message','var(--okdb-orange)','/markDelete','4784835EidoiS','108408HemAdw','toast','Re-enqueued\x20','error','length','name','vectorCache','mode','last_seen_clock','\x20deleted','application/json','2724795zwjvJy','head_clock','embeddings:indexer:doc:failed','source_env','source_key','search','doc_counts','load','inline','done','stats','data','Re-enqueued\x20\x22','chunk_done','indexer','loadDocs','$ok','/stats','engine:started','var(--okdb-info)','_busy','docsLimit','embeddings:indexer:doc:done','json','pending','_unsubs','shared','$watch','just\x20now','loadQueueStats','2PhJFGs','embed-indexer-panel','var(--okdb-warning)','\x20failed)','</b>\x22?<br><br>Use\x20this\x20when\x20jobs\x20were\x20purged\x20from\x20the\x20queue\x20but\x20docs\x20are\x20stuck\x20as\x20PENDING.','stringify','/docs/','API','round','571836aFdiAb','push','not\x20found','docCounts','deleted','all','Delete\x20\x22','flush\x20failed','POST','/docs?','modal','failed','slice','fetchVector','/retry','Retry\x20failed','var(--okdb-purple)','total_chunks','Flush\x20failed','busy','engine','info','docsStatus','docs','map','600120nrwbBc','config',',\x20…\x20+','Delete\x20failed','eng','vector','success'];_0x46e0=function(){return _0x14476a;};return _0x46e0();}function _0x33fc(_0x45aa82,_0x1e1316){_0x45aa82=_0x45aa82-0x10b;const _0x46e0f2=_0x46e0();let _0x33fcf8=_0x46e0f2[_0x45aa82];return _0x33fcf8;}const _0x1d367c=_0x33fc;(function(_0x449b7c,_0x651954){const _0x2c5b43=_0x33fc,_0x72fe8=_0x449b7c();while(!![]){try{const _0x5eb1db=-parseInt(_0x2c5b43(0x15c))/0x1*(-parseInt(_0x2c5b43(0x133))/0x2)+-parseInt(_0x2c5b43(0x121))/0x3+parseInt(_0x2c5b43(0x17e))/0x4+-parseInt(_0x2c5b43(0x13e))/0x5+-parseInt(_0x2c5b43(0x165))/0x6*(-parseInt(_0x2c5b43(0x11c))/0x7)+parseInt(_0x2c5b43(0x126))/0x8*(parseInt(_0x2c5b43(0x11b))/0x9)+parseInt(_0x2c5b43(0x117))/0xa*(parseInt(_0x2c5b43(0x132))/0xb);if(_0x5eb1db===_0x651954)break;else _0x72fe8['push'](_0x72fe8['shift']());}catch(_0x3f8b56){_0x72fe8['push'](_0x72fe8['shift']());}}}(_0x46e0,0x57f14));import _0x532db3 from'@toolkit/elements/ok-icon.ok.js';import _0x273b64 from'@toolkit/elements/ok-table.ok.js';import _0xa8b9df from'@toolkit/core/ok-overlay.ok.js';import _0x5b4fdb from'../../../stores/events-store.js';import _0x27268f from'../../engines/parts/engine-panel-shell.ok.js';import{ENGINE_PANEL_SHARED_STYLE as _0x23ade1}from'../../engines/engine-panel-shared-style.js';import{buildEmbeddingsPipelineUrl as _0x484e00,dispatchEnginePipelineSelection as _0x4694c9}from'../../engines/engine-ui-utils.js';const d=_0x23ade1+'\x0a\x20\x20.pill\x20{\x20border:1px\x20solid\x20var(--okdb-app-border);\x20background:var(--okdb-app-surface);\x20padding:3px\x2010px;\x20border-radius:999px;\x20font-size:12px;\x20cursor:pointer;\x20}\x0a\x20\x20.pill--on\x20{\x20border-color:var(--okdb-accent);\x20}\x0a';export default{'tag':_0x1d367c(0x15d),'dependencies':[_0x532db3,_0x273b64,_0xa8b9df,_0x27268f],'attr':{'name':{},'engine':{}},'context':_0x7bf357=>({'busy':!0x1,'flushing':!0x1,'stats':null,'error':null,'docsStatus':null,'docs':[],'docsBusy':!0x1,'docsError':null,'docsLimit':0x32,'docsLoadMs':null,'queueStats':null,'queueBusy':!0x1,get 'eng'(){const _0x37e5aa=_0x1d367c;return _0x7bf357[_0x37e5aa(0x10f)][_0x37e5aa(0x179)]??{};},get 'name'(){const _0x51d0d9=_0x1d367c;return _0x7bf357[_0x51d0d9(0x10f)][_0x51d0d9(0x138)];},get '_pipelineUrl'(){const _0x45d411=_0x1d367c;return _0x484e00(this[_0x45d411(0x182)],this[_0x45d411(0x138)]);},get 'indexer'(){const _0x1a0af7=_0x1d367c;return this[_0x1a0af7(0x148)]?.['indexer']??null;},get 'search'(){const _0x5e863f=_0x1d367c;return this[_0x5e863f(0x148)]?.[_0x5e863f(0x143)]??null;},get 'sourceEnvName'(){const _0x38a2f1=_0x1d367c;return this[_0x38a2f1(0x182)]?.[_0x38a2f1(0x17f)]?.[_0x38a2f1(0x141)]??'default';},get 'embedderName'(){const _0x2acb92=_0x1d367c;return this['indexer']?.['embedder']||this[_0x2acb92(0x182)]?.[_0x2acb92(0x17f)]?.['embedder']||'—';},get 'storageKey'(){const _0xf1fd49=_0x1d367c;return this[_0xf1fd49(0x14c)]?.['storage_key']||this['eng']?.[_0xf1fd49(0x17f)]?.[_0xf1fd49(0x10e)]||this[_0xf1fd49(0x138)];},get 'docCounts'(){const _0x364ae=_0x1d367c;return this[_0x364ae(0x14c)]?.[_0x364ae(0x144)]??null;},get 'queueMode'(){const _0x57c1f4=_0x1d367c;return _0x57c1f4(0x127)===(this['indexer']?.[_0x57c1f4(0x13a)]||_0x57c1f4(0x146));},get 'pendingDocs'(){const _0x7e7665=_0x1d367c;return this['docCounts']?.[_0x7e7665(0x156)]??0x0;},get 'failedDocs'(){const _0x3c7123=_0x1d367c;return this[_0x3c7123(0x168)]?.[_0x3c7123(0x170)]??0x0;},get 'doneDocs'(){const _0x1ef524=_0x1d367c;return this[_0x1ef524(0x168)]?.[_0x1ef524(0x147)]??0x0;},get 'vectorCount'(){return this['indexer']?.['vector_count']??0x0;},get 'headerBadges'(){const _0x405ca8=_0x1d367c,_0x55fdea=[];return this['indexer']?.['mode']&&_0x55fdea[_0x405ca8(0x166)]({'text':this[_0x405ca8(0x14c)][_0x405ca8(0x13a)],'color':_0x405ca8(0x175)}),_0x55fdea;},get 'clockPct'(){const _0x11a0e8=_0x1d367c,_0x4a0d8b=this[_0x11a0e8(0x14c)]?.[_0x11a0e8(0x13b)]??0x0,_0x4a0c03=this[_0x11a0e8(0x14c)]?.[_0x11a0e8(0x13f)]??0x0;return _0x4a0c03?Math[_0x11a0e8(0x124)](0x64,Math[_0x11a0e8(0x164)](_0x4a0d8b/_0x4a0c03*0x64)):0x0;},get 'isCaughtUp'(){const _0x461a3c=_0x1d367c,_0xc06cd2=this[_0x461a3c(0x14c)]?.[_0x461a3c(0x13b)]??0x0,_0x589376=this[_0x461a3c(0x14c)]?.[_0x461a3c(0x13f)]??0x0;return _0x589376>0x0&&_0xc06cd2>=_0x589376;},async 'load'(){const _0x5212dd=_0x1d367c;this[_0x5212dd(0x178)]=!0x0,this[_0x5212dd(0x136)]=null;try{const _0x2631d4=await fetch(this['_pipelineUrl']+_0x5212dd(0x14f)),_0x7cfbeb=await _0x2631d4[_0x5212dd(0x155)]();if(!_0x2631d4['ok'])throw new Error(_0x7cfbeb?.['error']?.['message']||'failed');this[_0x5212dd(0x148)]=_0x7cfbeb['data'];}catch(_0xd2c644){this[_0x5212dd(0x136)]=_0xd2c644?.['message']||String(_0xd2c644),this[_0x5212dd(0x148)]=null;}finally{this[_0x5212dd(0x178)]=!0x1;}},async 'flush'(){const _0x1c8a48=_0x1d367c;this[_0x1c8a48(0x10d)]=!0x0;try{if(!(await fetch(this[_0x1c8a48(0x119)]+_0x1c8a48(0x11e),{'method':_0x1c8a48(0x16d)}))['ok'])throw new Error(_0x1c8a48(0x16c));_0x7bf357[_0x1c8a48(0x14e)][_0x1c8a48(0x158)]?.[_0x1c8a48(0x134)]?.[_0x1c8a48(0x10b)]?.(_0x1c8a48(0x11f)),await this[_0x1c8a48(0x145)](),await this[_0x1c8a48(0x14d)]();}catch(_0x134bc1){_0x7bf357[_0x1c8a48(0x14e)][_0x1c8a48(0x158)]?.[_0x1c8a48(0x134)]?.[_0x1c8a48(0x136)]?.(_0x134bc1?.[_0x1c8a48(0x12f)]||_0x1c8a48(0x177));}finally{this[_0x1c8a48(0x10d)]=!0x1;}},async 'setDocsStatus'(_0x24ed09){const _0x3001db=_0x1d367c;this[_0x3001db(0x17b)]=_0x24ed09,await this['loadDocs']();},async 'onRefresh'(){const _0x3653cc=_0x1d367c;await Promise['all']([this['load'](),this[_0x3653cc(0x14d)]()]),_0x3653cc(0x127)===this[_0x3653cc(0x14c)]?.[_0x3653cc(0x13a)]&&await this['loadQueueStats']();},async 'loadDocs'(){const _0x1bd515=_0x1d367c;this[_0x1bd515(0x128)]=!0x0,this[_0x1bd515(0x10c)]=null;const _0xecb923=Date[_0x1bd515(0x122)]();try{const _0x5fe373=new URLSearchParams({'limit':this[_0x1bd515(0x153)]});this['docsStatus']&&_0x5fe373[_0x1bd515(0x12e)](_0x1bd515(0x110),this[_0x1bd515(0x17b)]);const _0x32c30f=await fetch(this[_0x1bd515(0x119)]+_0x1bd515(0x16e)+_0x5fe373),_0x14aa57=await _0x32c30f[_0x1bd515(0x155)]();if(!_0x32c30f['ok'])throw new Error(_0x14aa57?.[_0x1bd515(0x136)]?.[_0x1bd515(0x12f)]||_0x1bd515(0x170));this[_0x1bd515(0x17c)]=_0x14aa57['data']||[],this[_0x1bd515(0x116)]=Date[_0x1bd515(0x122)]()-_0xecb923;}catch(_0x25d51d){this[_0x1bd515(0x10c)]=_0x25d51d?.['message']||String(_0x25d51d),this[_0x1bd515(0x17c)]=[],this[_0x1bd515(0x116)]=null;}finally{this[_0x1bd515(0x128)]=!0x1;}},async 'loadQueueStats'(){const _0x1ff624=_0x1d367c;'queue'===this[_0x1ff624(0x14c)]?.[_0x1ff624(0x13a)]&&(this[_0x1ff624(0x12d)]=this['stats']?.[_0x1ff624(0x127)]??null);},async 'markDeleteDoc'(_0x20fda8){const _0x46f910=_0x1d367c;if(await _0x7bf357['$ok'][_0x46f910(0x158)][_0x46f910(0x16f)][_0x46f910(0x12c)](_0x46f910(0x16b)+_0x20fda8[_0x46f910(0x142)]+'\x22?')){_0x20fda8[_0x46f910(0x152)]=!0x0;try{if(!(await fetch(this[_0x46f910(0x119)]+'/docs/'+encodeURIComponent(_0x20fda8[_0x46f910(0x142)])+_0x46f910(0x131),{'method':_0x46f910(0x16d),'headers':{'Content-Type':_0x46f910(0x13d)},'body':JSON[_0x46f910(0x161)]({'clock':null})}))['ok'])throw new Error(_0x46f910(0x113));_0x7bf357[_0x46f910(0x14e)][_0x46f910(0x158)]?.['toast']?.[_0x46f910(0x17a)]?.('Deleted'),await this[_0x46f910(0x14d)]();}catch(_0x55ae3f){_0x7bf357[_0x46f910(0x14e)][_0x46f910(0x158)]?.['toast']?.[_0x46f910(0x136)]?.(_0x55ae3f?.[_0x46f910(0x12f)]||_0x46f910(0x181));}finally{_0x20fda8[_0x46f910(0x152)]=!0x1;}}},async 'retryDoc'(_0x56603e){const _0x1fdcde=_0x1d367c;_0x56603e[_0x1fdcde(0x152)]=!0x0;try{const _0x109a4c=await fetch(this[_0x1fdcde(0x119)]+_0x1fdcde(0x162)+encodeURIComponent(_0x56603e[_0x1fdcde(0x142)])+_0x1fdcde(0x173),{'method':'POST'}),_0x3aef2e=await _0x109a4c[_0x1fdcde(0x155)]();if(!_0x109a4c['ok'])throw new Error(_0x3aef2e?.[_0x1fdcde(0x136)]?.[_0x1fdcde(0x12f)]||'retry\x20failed');_0x7bf357['$ok']['shared']?.[_0x1fdcde(0x134)]?.[_0x1fdcde(0x10b)]?.(_0x1fdcde(0x14a)+_0x56603e['source_key']+'\x22'),await this[_0x1fdcde(0x14d)]();}catch(_0x1d39a5){_0x7bf357[_0x1fdcde(0x14e)][_0x1fdcde(0x158)]?.[_0x1fdcde(0x134)]?.[_0x1fdcde(0x136)]?.(_0x1d39a5?.['message']||_0x1fdcde(0x174));}finally{_0x56603e['_busy']=!0x1;}},async 'retryFailed'(){const _0x3dbebf=_0x1d367c;if(await _0x7bf357[_0x3dbebf(0x14e)]['shared'][_0x3dbebf(0x16f)][_0x3dbebf(0x12c)]('Re-enqueue\x20all\x20failed\x20docs\x20for\x20indexer\x20\x22'+this[_0x3dbebf(0x138)]+'\x22?')){this[_0x3dbebf(0x128)]=!0x0;try{const _0x502ecb=await fetch(this['_pipelineUrl']+_0x3dbebf(0x111),{'method':'POST','headers':{'Content-Type':_0x3dbebf(0x13d)},'body':JSON[_0x3dbebf(0x161)]({'limit':0x1388,'includeStuckPending':!0x1})}),_0x566b0a=await _0x502ecb[_0x3dbebf(0x155)]();if(!_0x502ecb['ok'])throw new Error(_0x566b0a?.[_0x3dbebf(0x136)]?.[_0x3dbebf(0x12f)]||_0x3dbebf(0x170));const _0x56dc67=_0x566b0a['data'];_0x7bf357[_0x3dbebf(0x14e)]['shared']?.[_0x3dbebf(0x134)]?.[_0x3dbebf(0x10b)]?.('Re-enqueued\x20'+_0x56dc67[_0x3dbebf(0x115)]+'\x20doc(s)'+(_0x56dc67['deleted']?',\x20cleaned\x20up\x20'+_0x56dc67[_0x3dbebf(0x169)]+_0x3dbebf(0x13c):'')),await Promise[_0x3dbebf(0x16a)]([this['load'](),this[_0x3dbebf(0x14d)]()]);}catch(_0x38838f){_0x7bf357['$ok'][_0x3dbebf(0x158)]?.[_0x3dbebf(0x134)]?.['error']?.(_0x38838f?.[_0x3dbebf(0x12f)]||_0x3dbebf(0x174));}finally{this[_0x3dbebf(0x128)]=!0x1;}}},async 'retryStuckPending'(){const _0xf77f9=_0x1d367c;if(await _0x7bf357[_0xf77f9(0x14e)]['shared'][_0xf77f9(0x16f)]['confirm']('Re-enqueue\x20ALL\x20failed\x20AND\x20stuck-pending\x20docs\x20for\x20\x22<b>'+this['name']+_0xf77f9(0x160))){this[_0xf77f9(0x128)]=!0x0;try{const _0x38fb2f=await fetch(this[_0xf77f9(0x119)]+_0xf77f9(0x111),{'method':_0xf77f9(0x16d),'headers':{'Content-Type':'application/json'},'body':JSON['stringify']({'limit':0x1388,'includeStuckPending':!0x0})}),_0x42da44=await _0x38fb2f[_0xf77f9(0x155)]();if(!_0x38fb2f['ok'])throw new Error(_0x42da44?.['error']?.[_0xf77f9(0x12f)]||'failed');const _0x27a197=_0x42da44[_0xf77f9(0x149)];_0x7bf357['$ok'][_0xf77f9(0x158)]?.[_0xf77f9(0x134)]?.['success']?.(_0xf77f9(0x135)+_0x27a197[_0xf77f9(0x115)]+_0xf77f9(0x118)+(_0x27a197[_0xf77f9(0x169)]?',\x20cleaned\x20up\x20'+_0x27a197[_0xf77f9(0x169)]+_0xf77f9(0x13c):'')),await Promise[_0xf77f9(0x16a)]([this[_0xf77f9(0x145)](),this[_0xf77f9(0x14d)]()]);}catch(_0x451608){_0x7bf357['$ok']['shared']?.[_0xf77f9(0x134)]?.['error']?.(_0x451608?.[_0xf77f9(0x12f)]||_0xf77f9(0x174));}finally{this[_0xf77f9(0x128)]=!0x1;}}},'statusColor':_0x401508=>({'done':'var(--okdb-success)','failed':'var(--okdb-danger)','deleted':_0x1d367c(0x123),'pending':_0x1d367c(0x15e),'running':_0x1d367c(0x151),'partial':_0x1d367c(0x130)}[_0x401508]||'#9ca3af'),'chunkProgress'(_0xdd8d43){const _0x10e61c=_0x1d367c;if(!(_0xdd8d43[_0x10e61c(0x176)]>0x0))return null;const _0x47b7ba=_0xdd8d43[_0x10e61c(0x14b)]??0x0,_0x38ae24=_0xdd8d43['total_chunks'],_0x3c49e7=_0xdd8d43[_0x10e61c(0x11a)]??0x0;return'partial'===_0xdd8d43[_0x10e61c(0x110)]&&_0x3c49e7>0x0?_0x47b7ba+'/'+_0x38ae24+'\x20('+_0x3c49e7+_0x10e61c(0x15f):_0x47b7ba+'/'+_0x38ae24;},'relTime'(_0x2b82cb){const _0x42d183=_0x1d367c;if(!_0x2b82cb)return'—';const _0x59d56d=Date[_0x42d183(0x122)]()-_0x2b82cb;return _0x59d56d<0x1388?_0x42d183(0x15a):_0x59d56d<0xea60?Math[_0x42d183(0x164)](_0x59d56d/0x3e8)+_0x42d183(0x112):_0x59d56d<0x36ee80?Math[_0x42d183(0x164)](_0x59d56d/0xea60)+'m\x20ago':Math[_0x42d183(0x164)](_0x59d56d/0x36ee80)+'h\x20ago';},'vectorCache':{},async 'fetchVector'(_0x4a133f){const _0x565568=_0x1d367c,_0x43e973=_0x4a133f[_0x565568(0x142)];if(!this['vectorCache'][_0x43e973]?.[_0x565568(0x183)]&&!this[_0x565568(0x139)][_0x43e973]?.[_0x565568(0x178)]){this[_0x565568(0x139)][_0x43e973]={'busy':!0x0,'error':null,'vector':null,'dims':null};try{const _0x385af6=this[_0x565568(0x14c)]?.[_0x565568(0x10e)]||this[_0x565568(0x138)],_0x49e02a=await fetch(__ENV__[_0x565568(0x163)]+'/embeddings/storage/'+encodeURIComponent(_0x385af6)+'/'+encodeURIComponent(_0x43e973)),_0x56dfb7=await _0x49e02a['json']();if(!_0x49e02a['ok'])throw new Error(_0x56dfb7?.[_0x565568(0x136)]?.['message']||_0x565568(0x167));this['vectorCache'][_0x43e973]={'busy':!0x1,'error':null,'dims':_0x56dfb7[_0x565568(0x149)][_0x565568(0x11d)],'vector':_0x56dfb7['data'][_0x565568(0x183)]};}catch(_0x4410ad){this['vectorCache'][_0x43e973]={'busy':!0x1,'error':_0x4410ad?.[_0x565568(0x12f)]||String(_0x4410ad),'vector':null,'dims':null};}}},'toggleVector'(_0xe753e4){const _0x3ea104=_0x1d367c,_0x4b2066=_0xe753e4[_0x3ea104(0x142)];this[_0x3ea104(0x139)][_0x4b2066]?.['vector']||this[_0x3ea104(0x139)][_0x4b2066]?.[_0x3ea104(0x136)]?delete this[_0x3ea104(0x139)][_0x4b2066]:this[_0x3ea104(0x172)](_0xe753e4);},'fmtVec'(_0x28af32){const _0x511f8c=_0x1d367c;if(!_0x28af32)return'';const _0x339277=_0x28af32[_0x511f8c(0x171)](0x0,0xc)[_0x511f8c(0x17d)](_0x175f73=>_0x175f73['toFixed'](0x4))[_0x511f8c(0x114)](',\x20');return _0x28af32[_0x511f8c(0x137)]>0xc?'['+_0x339277+_0x511f8c(0x180)+(_0x28af32[_0x511f8c(0x137)]-0xc)+'\x20more]':'['+_0x339277+']';},'viewPipeline'(){const _0x2d7885=_0x1d367c;_0x4694c9(_0x7bf357,this[_0x2d7885(0x182)]);},'_unsubs':[]}),async 'init'(_0x507aa6){const _0x2f983c=_0x1d367c;_0x507aa6[_0x2f983c(0x159)](()=>_0x507aa6['$attr'][_0x2f983c(0x138)],async()=>{const _0x4cc800=_0x2f983c;this[_0x4cc800(0x148)]=null,this[_0x4cc800(0x17c)]=[],this['queueStats']=null,await Promise[_0x4cc800(0x16a)]([this[_0x4cc800(0x145)](),this['loadDocs']()]),_0x4cc800(0x127)===this['indexer']?.[_0x4cc800(0x13a)]&&await this['loadQueueStats']();}),await Promise[_0x2f983c(0x16a)]([this[_0x2f983c(0x145)](),this[_0x2f983c(0x14d)]()]),'queue'===this[_0x2f983c(0x14c)]?.[_0x2f983c(0x13a)]&&await this[_0x2f983c(0x15b)]();},'mount'(){const _0x2b3523=_0x1d367c,_0x132245=()=>this[_0x2b3523(0x138)],_0x2b32cc=_0x354a2f=>{const _0x4f975b=_0x2b3523;_0x354a2f?.[_0x4f975b(0x179)]&&_0x354a2f[_0x4f975b(0x179)]!==_0x132245()||this[_0x4f975b(0x145)]();},_0x525d8d=_0x1fb29e=>{const _0x2bb63b=_0x2b3523;_0x1fb29e?.[_0x2bb63b(0x179)]&&_0x1fb29e[_0x2bb63b(0x179)]!==_0x132245()||this['loadDocs']();};this[_0x2b3523(0x157)]=[_0x5b4fdb['on'](_0x2b3523(0x129),_0x2b32cc),_0x5b4fdb['on']('embeddings:indexer:flushed',_0x2b32cc),_0x5b4fdb['on'](_0x2b3523(0x150),_0x2b32cc),_0x5b4fdb['on'](_0x2b3523(0x12b),_0x2b32cc),_0x5b4fdb['on'](_0x2b3523(0x125),_0x2b32cc),_0x5b4fdb['on'](_0x2b3523(0x154),_0x525d8d),_0x5b4fdb['on'](_0x2b3523(0x140),_0x525d8d),_0x5b4fdb['on'](_0x2b3523(0x12a),_0x525d8d)];},'unmount'(){const _0x2a1fc4=_0x1d367c;for(const _0xe12033 of this[_0x2a1fc4(0x157)])_0xe12033();this['_unsubs']=[];},'template':_0x1d367c(0x120),'style':d};
|
|
1
|
+
import e from"@toolkit/elements/ok-icon.ok.js";import n from"@toolkit/elements/ok-table.ok.js";import s from"@toolkit/core/ok-overlay.ok.js";import t from"../../../stores/events-store.js";import o from"../../engines/parts/engine-panel-shell.ok.js";import{ENGINE_PANEL_SHARED_STYLE as a}from"../../engines/engine-panel-shared-style.js";import{buildEmbeddingsPipelineUrl as i,dispatchEnginePipelineSelection as r}from"../../engines/engine-ui-utils.js";const d=a+"\n .pill { border:1px solid var(--okdb-app-border); background:var(--okdb-app-surface); padding:3px 10px; border-radius:999px; font-size:12px; cursor:pointer; }\n .pill--on { border-color:var(--okdb-accent); }\n";export default{tag:"embed-indexer-panel",dependencies:[e,n,s,o],attr:{name:{},engine:{}},context:e=>({busy:!1,flushing:!1,stats:null,error:null,docsStatus:null,docs:[],docsBusy:!1,docsError:null,docsLimit:50,docsLoadMs:null,queueStats:null,queueBusy:!1,get eng(){return e.$attr.engine??{}},get name(){return e.$attr.name},get _pipelineUrl(){return i(this.eng,this.name)},get indexer(){return this.stats?.indexer??null},get search(){return this.stats?.search??null},get sourceEnvName(){return this.eng?.config?.source_env??"default"},get embedderName(){return this.indexer?.embedder||this.eng?.config?.embedder||"—"},get storageKey(){return this.indexer?.storage_key||this.eng?.config?.storage_key||this.name},get docCounts(){return this.indexer?.doc_counts??null},get queueMode(){return"queue"===(this.indexer?.mode||"inline")},get pendingDocs(){return this.docCounts?.pending??0},get failedDocs(){return this.docCounts?.failed??0},get doneDocs(){return this.docCounts?.done??0},get vectorCount(){return this.indexer?.vector_count??0},get headerBadges(){const e=[];return this.indexer?.mode&&e.push({text:this.indexer.mode,color:"var(--okdb-purple)"}),e},get clockPct(){const e=this.indexer?.last_seen_clock??0,n=this.indexer?.head_clock??0;return n?Math.min(100,Math.round(e/n*100)):0},get isCaughtUp(){const e=this.indexer?.last_seen_clock??0,n=this.indexer?.head_clock??0;return n>0&&e>=n},async load(){this.busy=!0,this.error=null;try{const e=await fetch(`${this._pipelineUrl}/stats`),n=await e.json();if(!e.ok)throw new Error(n?.error?.message||"failed");this.stats=n.data}catch(e){this.error=e?.message||String(e),this.stats=null}finally{this.busy=!1}},async flush(){this.flushing=!0;try{if(!(await fetch(`${this._pipelineUrl}/flush`,{method:"POST"})).ok)throw new Error("flush failed");e.$ok.shared?.toast?.success?.("Flushed"),await this.load(),await this.loadDocs()}catch(n){e.$ok.shared?.toast?.error?.(n?.message||"Flush failed")}finally{this.flushing=!1}},async setDocsStatus(e){this.docsStatus=e,await this.loadDocs()},async onRefresh(){await Promise.all([this.load(),this.loadDocs()]),"queue"===this.indexer?.mode&&await this.loadQueueStats()},async loadDocs(){this.docsBusy=!0,this.docsError=null;const e=Date.now();try{const n=new URLSearchParams({limit:this.docsLimit});this.docsStatus&&n.set("status",this.docsStatus);const s=await fetch(`${this._pipelineUrl}/docs?${n}`),t=await s.json();if(!s.ok)throw new Error(t?.error?.message||"failed");this.docs=t.data||[],this.docsLoadMs=Date.now()-e}catch(e){this.docsError=e?.message||String(e),this.docs=[],this.docsLoadMs=null}finally{this.docsBusy=!1}},async loadQueueStats(){"queue"===this.indexer?.mode&&(this.queueStats=this.stats?.queue??null)},async markDeleteDoc(n){if(await e.$ok.shared.modal.confirm(`Delete "${n.source_key}"?`)){n._busy=!0;try{if(!(await fetch(`${this._pipelineUrl}/docs/${encodeURIComponent(n.source_key)}/markDelete`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({clock:null})})).ok)throw new Error("markDelete failed");e.$ok.shared?.toast?.info?.("Deleted"),await this.loadDocs()}catch(n){e.$ok.shared?.toast?.error?.(n?.message||"Delete failed")}finally{n._busy=!1}}},async retryDoc(n){n._busy=!0;try{const s=await fetch(`${this._pipelineUrl}/docs/${encodeURIComponent(n.source_key)}/retry`,{method:"POST"}),t=await s.json();if(!s.ok)throw new Error(t?.error?.message||"retry failed");e.$ok.shared?.toast?.success?.(`Re-enqueued "${n.source_key}"`),await this.loadDocs()}catch(n){e.$ok.shared?.toast?.error?.(n?.message||"Retry failed")}finally{n._busy=!1}},async retryFailed(){if(await e.$ok.shared.modal.confirm(`Re-enqueue all failed docs for indexer "${this.name}"?`)){this.docsBusy=!0;try{const n=await fetch(`${this._pipelineUrl}/retry-failed`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({limit:5e3,includeStuckPending:!1})}),s=await n.json();if(!n.ok)throw new Error(s?.error?.message||"failed");const t=s.data;e.$ok.shared?.toast?.success?.(`Re-enqueued ${t.retried} doc(s)`+(t.deleted?`, cleaned up ${t.deleted} deleted`:"")),await Promise.all([this.load(),this.loadDocs()])}catch(n){e.$ok.shared?.toast?.error?.(n?.message||"Retry failed")}finally{this.docsBusy=!1}}},async retryStuckPending(){if(await e.$ok.shared.modal.confirm(`Re-enqueue ALL failed AND stuck-pending docs for "<b>${this.name}</b>"?<br><br>Use this when jobs were purged from the queue but docs are stuck as PENDING.`)){this.docsBusy=!0;try{const n=await fetch(`${this._pipelineUrl}/retry-failed`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({limit:5e3,includeStuckPending:!0})}),s=await n.json();if(!n.ok)throw new Error(s?.error?.message||"failed");const t=s.data;e.$ok.shared?.toast?.success?.(`Re-enqueued ${t.retried} doc(s)`+(t.deleted?`, cleaned up ${t.deleted} deleted`:"")),await Promise.all([this.load(),this.loadDocs()])}catch(n){e.$ok.shared?.toast?.error?.(n?.message||"Retry failed")}finally{this.docsBusy=!1}}},statusColor:e=>({done:"var(--okdb-success)",failed:"var(--okdb-danger)",deleted:"#9ca3af",pending:"var(--okdb-warning)",running:"var(--okdb-info)",partial:"var(--okdb-orange)"}[e]||"#9ca3af"),chunkProgress(e){if(!(e.total_chunks>0))return null;const n=e.chunk_done??0,s=e.total_chunks,t=e.chunk_failed??0;return"partial"===e.status&&t>0?`${n}/${s} (${t} failed)`:`${n}/${s}`},relTime(e){if(!e)return"—";const n=Date.now()-e;return n<5e3?"just now":n<6e4?`${Math.round(n/1e3)}s ago`:n<36e5?`${Math.round(n/6e4)}m ago`:`${Math.round(n/36e5)}h ago`},vectorCache:{},async fetchVector(e){const n=e.source_key;if(!this.vectorCache[n]?.vector&&!this.vectorCache[n]?.busy){this.vectorCache[n]={busy:!0,error:null,vector:null,dims:null};try{const e=this.indexer?.storage_key||this.name,s=await fetch(`${__ENV__.API}/embeddings/storage/${encodeURIComponent(e)}/${encodeURIComponent(n)}`),t=await s.json();if(!s.ok)throw new Error(t?.error?.message||"not found");this.vectorCache[n]={busy:!1,error:null,dims:t.data.dims,vector:t.data.vector}}catch(e){this.vectorCache[n]={busy:!1,error:e?.message||String(e),vector:null,dims:null}}}},toggleVector(e){const n=e.source_key;this.vectorCache[n]?.vector||this.vectorCache[n]?.error?delete this.vectorCache[n]:this.fetchVector(e)},fmtVec(e){if(!e)return"";const n=e.slice(0,12).map(e=>e.toFixed(4)).join(", ");return e.length>12?`[${n}, … +${e.length-12} more]`:`[${n}]`},viewPipeline(){r(e,this.eng)},_unsubs:[]}),async init(e){e.$watch(()=>e.$attr.name,async()=>{this.stats=null,this.docs=[],this.queueStats=null,await Promise.all([this.load(),this.loadDocs()]),"queue"===this.indexer?.mode&&await this.loadQueueStats()}),await Promise.all([this.load(),this.loadDocs()]),"queue"===this.indexer?.mode&&await this.loadQueueStats()},mount(){const e=()=>this.name,n=n=>{n?.engine&&n.engine!==e()||this.load()},s=n=>{n?.engine&&n.engine!==e()||this.loadDocs()};this._unsubs=[t.on("embeddings:indexer:ready",n),t.on("embeddings:indexer:flushed",n),t.on("engine:started",n),t.on("engine:stopped",n),t.on("engine:error",n),t.on("embeddings:indexer:doc:done",s),t.on("embeddings:indexer:doc:failed",s),t.on("embeddings:doc:status_change",s)]},unmount(){for(const e of this._unsubs)e();this._unsubs=[]},template:'\n<engine-panel-shell\n :engine="eng"\n :title="name"\n type-label="indexer"\n type-color="var(--okdb-purple)"\n :badges="headerBadges"\n show-refresh="true"\n fill="true"\n :refresh-busy="busy || docsBusy || queueBusy || flushing"\n :on-refresh="onRefresh"\n :on-pipeline="viewPipeline"\n @engine-updated="$dispatch(\'engine-updated\', $event.detail)"\n @refresh="$dispatch(\'refresh\')"\n @deleted="$dispatch(\'deleted\', $event.detail)"\n>\n <if :="error">\n <div style="color:var(--okdb-danger); font-size:13px;">{{ error }}</div>\n </if>\n\n\n <if :="indexer">\n <div class="stack-compact">\n <div class="card stack-compact" style="padding:14px;gap:12px;">\n <div style="display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap;">\n <div style="display:flex;flex-direction:column;gap:8px;min-width:0;flex:1;">\n <div class="pill-row">\n <span class="info-pill" title="Source type being indexed.">{{ indexer.source_type || \'—\' }}</span>\n <span class="info-pill" title="Source environment.">source env: {{ sourceEnvName }}</span>\n <span class="info-pill" title="Embedder used to create vectors.">embedder: {{ embedderName }}</span>\n <span class="info-pill" title="Storage key for the vector store.">store: {{ storageKey }}</span>\n <span class="info-pill" :style="\'border-color:\' + (isCaughtUp ? \'color-mix(in srgb, var(--okdb-success) 33%, transparent)\' : \'color-mix(in srgb, var(--okdb-warning) 33%, transparent)\') + \';color:\' + (isCaughtUp ? \'var(--okdb-success)\' : \'var(--okdb-warning)\') + \';background:\' + (isCaughtUp ? \'color-mix(in srgb, var(--okdb-success) 7%, transparent)\' : \'color-mix(in srgb, var(--okdb-warning) 7%, transparent)\') + \';\'">\n {{ isCaughtUp ? \'caught up\' : \'processing\' }}\n </span>\n </div>\n <div class="story-lead">\n Watches <strong>{{ indexer.source_type || \'—\' }}</strong> and keeps vectors current in <strong>{{ storageKey }}</strong>.\n </div>\n <div class="story-note">Flush to force pending writes through now. Use the document table below to inspect failures, retry queue-backed docs, and inspect stored vectors.</div>\n </div>\n\n <div class="metric-grid metric-grid--compact" style="min-width:min(100%, 420px);">\n <div class="metric-card metric-card--compact">\n <div class="metric-title">Vectors</div>\n <div class="metric-value" style="color:var(--okdb-success);">{{ vectorCount.toLocaleString() }}</div>\n </div>\n <div class="metric-card metric-card--compact">\n <div class="metric-title">Done</div>\n <div class="metric-value" style="color:var(--okdb-success);">{{ doneDocs.toLocaleString() }}</div>\n </div>\n <div class="metric-card metric-card--compact">\n <div class="metric-title">Pending</div>\n <div class="metric-value" :style="\'color:\' + (pendingDocs > 0 ? \'var(--okdb-warning)\' : \'var(--okdb-app-fg)\')">{{ pendingDocs.toLocaleString() }}</div>\n </div>\n <div class="metric-card metric-card--compact">\n <div class="metric-title">Failed</div>\n <div class="metric-value" :style="\'color:\' + (failedDocs > 0 ? \'var(--okdb-danger)\' : \'var(--okdb-app-fg)\')">{{ failedDocs.toLocaleString() }}</div>\n </div>\n </div>\n </div>\n\n <div style="display:flex;align-items:center;gap:10px;flex-wrap:wrap;">\n <button @click="flush" :disabled="flushing || !eng.isRunning">\n {{ flushing ? \'Flushing…\' : \'Flush\' }}\n </button>\n <span class="story-note">Changelog {{ indexer.last_seen_clock ?? \'—\' }} / {{ indexer.head_clock ?? \'—\' }} · {{ clockPct }}%</span>\n <if :="search && search.count != null && search.count !== indexer.vector_count">\n <span class="story-note" style="color:var(--okdb-warning);" title="In-memory index differs from storage — rebuild may be needed">\n search index: {{ search.count.toLocaleString() }}\n </span>\n </if>\n </div>\n\n <div style="background:var(--okdb-app-border); border-radius:6px; height:6px; overflow:hidden;" :title="clockPct + \'% of changelog processed\'">\n <div :style="\'height:100%; border-radius:6px; transition:width .3s; background:\' + (isCaughtUp ? \'var(--okdb-success)\' : \'var(--okdb-accent)\') + \'; width:\' + clockPct + \'%\'"></div>\n </div>\n </div>\n\n <div class="card stack-compact" style="padding:14px;gap:12px;">\n <div class="card-title" style="margin:0;">Indexer settings</div>\n <div class="kv-grid kv-grid--compact">\n <span class="kv-key">source type</span><span class="kv-val">{{ indexer.source_type || \'—\' }}</span>\n <span class="kv-key">source env</span><span class="kv-val">{{ sourceEnvName }}</span>\n <span class="kv-key">embedder</span><span class="kv-val">{{ embedderName }}</span>\n <span class="kv-key">storage key</span><span class="kv-val">{{ storageKey }}</span>\n <span class="kv-key">mode</span><span class="kv-val">{{ indexer.mode || \'inline\' }}</span>\n <if :="indexer.job_type">\n <span class="kv-key">job type</span>\n <span class="kv-val" style="font-size:11px;font-family:monospace;">{{ indexer.job_type }}</span>\n </if>\n </div>\n </div>\n\n <if :="queueMode">\n <div class="card">\n <div style="display:flex; align-items:center; gap:10px; margin-bottom:10px; flex-wrap:wrap;">\n <div class="card-title" style="margin:0;">Queue</div>\n <span style="font-size:11px; opacity:.5;">job type: <span style="font-family:monospace;">{{ indexer.job_type }}</span></span>\n <button @click="loadQueueStats" :disabled="queueBusy" style="margin-left:auto; font-size:11px; padding:2px 8px; opacity:.7;">↻</button>\n </div>\n <if :="queueStats">\n <div style="display:grid; grid-template-columns:repeat(4,1fr); gap:8px; text-align:center;">\n <div class="stat-box" style="background:var(--okdb-app-border); border-radius:6px; padding:8px 4px;">\n <div style="font-size:22px; font-weight:600; color:var(--okdb-warning);">{{ queueStats.byStatus?.pending ?? 0 }}</div>\n <div style="font-size:10px; opacity:.6; margin-top:2px;">Pending</div>\n </div>\n <div class="stat-box" style="background:var(--okdb-app-border); border-radius:6px; padding:8px 4px;">\n <div style="font-size:22px; font-weight:600; color:var(--okdb-info);">{{ queueStats.byStatus?.running ?? 0 }}</div>\n <div style="font-size:10px; opacity:.6; margin-top:2px;">Running</div>\n </div>\n <div class="stat-box" style="background:var(--okdb-app-border); border-radius:6px; padding:8px 4px;">\n <div style="font-size:22px; font-weight:600; color:var(--okdb-success);">{{ queueStats.byStatus?.done ?? 0 }}</div>\n <div style="font-size:10px; opacity:.6; margin-top:2px;">Done</div>\n </div>\n <div class="stat-box" style="background:var(--okdb-app-border); border-radius:6px; padding:8px 4px;">\n <div style="font-size:22px; font-weight:600; color:var(--okdb-danger);">{{ queueStats.byStatus?.failed ?? 0 }}</div>\n <div style="font-size:10px; opacity:.6; margin-top:2px;">Failed</div>\n </div>\n </div>\n <div style="margin-top:8px; font-size:11px; opacity:.4; font-style:italic;">\n Queue tracks individual job attempts. Done jobs are auto-pruned; failed jobs persist until retried.\n </div>\n </if>\n <if :="!queueStats && !queueBusy">\n <div style="font-size:12px; opacity:.4; font-style:italic;">No queue stats for this job type — queue may be idle or feature inactive.</div>\n </if>\n <if :="queueBusy">\n <div style="font-size:12px; opacity:.4;">Loading…</div>\n </if>\n </div>\n </if>\n </div>\n </if>\n\n \x3c!-- Doc status table --\x3e\n <div class="card" style="display:flex; flex-direction:column; gap:10px; flex:1; min-height:0;">\n <div style="display:flex; align-items:center; gap:8px; flex-wrap:wrap;">\n <div class="card-title" style="margin:0;">Documents</div>\n <div style="display:flex; gap:6px; flex-wrap:wrap; margin-left:auto;">\n <button @click="setDocsStatus(null)" :class="docsStatus == null ? \'pill pill--on\' : \'pill\'">All</button>\n <button @click="setDocsStatus(\'pending\')" :class="docsStatus === \'pending\' ? \'pill pill--on\' : \'pill\'">Pending</button>\n <button @click="setDocsStatus(\'done\')" :class="docsStatus === \'done\' ? \'pill pill--on\' : \'pill\'">Done</button>\n <button @click="setDocsStatus(\'failed\')" :class="docsStatus === \'failed\' ? \'pill pill--on\' : \'pill\'">Failed</button>\n <button @click="setDocsStatus(\'partial\')" :class="docsStatus === \'partial\' ? \'pill pill--on\' : \'pill\'">Partial</button>\n <button @click="setDocsStatus(\'deleted\')" :class="docsStatus === \'deleted\' ? \'pill pill--on\' : \'pill\'">Deleted</button>\n <button @click="loadDocs" :disabled="docsBusy" style="opacity:.8;">↻</button>\n <if :="indexer?.mode === \'queue\'">\n <button @click="retryFailed()" :disabled="docsBusy"\n style="color:var(--okdb-warning); border-color:color-mix(in srgb, var(--okdb-warning) 27%, transparent); font-size:12px;"\n title="Re-enqueue all FAILED docs for this indexer">\n ↺ Retry Failed\n </button>\n <button @click="retryStuckPending()" :disabled="docsBusy"\n style="color:var(--okdb-app-fg-muted); border-color:color-mix(in srgb, var(--okdb-app-fg-muted) 27%, transparent); font-size:12px;"\n title="Re-enqueue FAILED + stuck PENDING docs (use when queue jobs were purged externally)">\n ↺ Retry Stuck\n </button>\n </if>\n </div>\n </div>\n\n <if :="docsError">\n <div style="color:var(--okdb-danger); font-size:13px;">{{ docsError }}</div>\n </if>\n\n <div style="position:relative; flex:1; min-height:0; overflow:auto;">\n <if :="docsBusy">\n <ok-overlay>\n <div class="loader-center">\n <ok-icon name="loader" class="spin" style="width:28px;height:28px;"></ok-icon>\n </div>\n </ok-overlay>\n </if>\n\n <ok-table :data="docs" no-scroll style="width:100%;">\n <columns>\n <column width="130px" no-resize>\n <header>Status</header>\n <cell let:row>\n <span :style="\'color:\' + statusColor(row.status) + \'; font-size:12px;\'">\n {{ row.status }}\n </span>\n <if :="chunkProgress(row)">\n <span style="font-size:11px; opacity:.7; margin-left:4px;">{{ chunkProgress(row) }}</span>\n </if>\n </cell>\n </column>\n <column>\n <header>Source Key</header>\n <cell let:row>{{ row.source_key }}</cell>\n </column>\n <column width="110px" no-resize>\n <header>Updated</header>\n <cell let:row>{{ relTime(row.updated) }}</cell>\n </column>\n <column width="200px" no-resize>\n <header>Error</header>\n <cell let:row>\n <if :="row.error">\n <span style="color:var(--okdb-danger); font-size:11px; opacity:.85;" :title="row.error">\n {{ row.error.slice(0, 60) }}{{ row.error.length > 60 ? \'…\' : \'\' }}\n </span>\n </if>\n </cell>\n </column>\n <column width="140px" no-resize>\n <header>Actions</header>\n <cell let:row>\n <div style="display:flex; gap:4px; flex-wrap:wrap;">\n <if :="(row.status === \'failed\' || row.status === \'pending\') && indexer?.mode === \'queue\'">\n <button\n @click="retryDoc(row)"\n :disabled="row._busy"\n style="font-size:11px; padding:3px 8px; color:var(--okdb-warning); border-color:color-mix(in srgb, var(--okdb-warning) 27%, transparent);"\n title="Re-enqueue this document for embedding"\n >↺ Retry</button>\n </if>\n <if :="row.status !== \'deleted\'">\n <button\n @click="markDeleteDoc(row)"\n :disabled="row._busy"\n style="font-size:11px; padding:3px 8px; color:var(--okdb-danger);"\n >Delete</button>\n </if>\n </div>\n </cell>\n </column>\n </columns>\n\n <expanded let:row>\n <div style="padding:10px; font-size:12px; display:flex; flex-direction:column; gap:6px;">\n <div class="kv-grid">\n <span class="kv-key">source_key</span> <span class="kv-val">{{ row.source_key }}</span>\n <span class="kv-key">engine_key</span> <span class="kv-val">{{ row.engine_key }}</span>\n <span class="kv-key">mode</span> <span class="kv-val">{{ row.mode || \'—\' }}</span>\n <span class="kv-key">clock</span> <span class="kv-val">{{ row.clock ?? \'—\' }}</span>\n <span class="kv-key">created</span> <span class="kv-val">{{ relTime(row.created) }}</span>\n <span class="kv-key">updated</span> <span class="kv-val">{{ relTime(row.updated) }}</span>\n <if :="row.total_chunks > 0">\n <span class="kv-key">chunks</span>\n <span class="kv-val">\n <span style="color:var(--okdb-success);">{{ row.chunk_done ?? 0 }} done</span>\n <if :="row.chunk_failed > 0"><span style="color:var(--okdb-danger);"> · {{ row.chunk_failed }} failed</span></if>\n <if :="(row.chunk_pending ?? 0) > 0"><span style="color:var(--okdb-warning);"> · {{ row.chunk_pending }} pending</span></if>\n <span style="opacity:.5;"> / {{ row.total_chunks }} total</span>\n </span>\n </if>\n </div>\n <if :="row.error">\n <div style="color:var(--okdb-danger); white-space:pre-wrap;">{{ row.error }}</div>\n </if>\n\n \x3c!-- Vector viewer --\x3e\n <if :="row.status === \'done\'">\n <div style="display:flex; align-items:center; gap:8px; margin-top:4px;">\n <button\n @click="toggleVector(row)"\n style="font-size:11px; padding:3px 10px; color:var(--okdb-purple); border-color:var(--okdb-purple);"\n :disabled="vectorCache[row.source_key]?.busy"\n >\n <if :="vectorCache[row.source_key]?.busy">…</if>\n <if :="!vectorCache[row.source_key]?.busy && !vectorCache[row.source_key]?.vector && !vectorCache[row.source_key]?.error">🔍 View Vector</if>\n <if :="vectorCache[row.source_key]?.vector || vectorCache[row.source_key]?.error">✕ Hide Vector</if>\n </button>\n <if :="vectorCache[row.source_key]?.dims">\n <span style="opacity:.5; font-size:11px;">{{ vectorCache[row.source_key].dims }} dims</span>\n </if>\n </div>\n <if :="vectorCache[row.source_key]?.error">\n <div style="color:var(--okdb-danger); font-size:11px;">{{ vectorCache[row.source_key].error }}</div>\n </if>\n <if :="vectorCache[row.source_key]?.vector">\n <div style="background:var(--okdb-app-bg-deep); border:1px solid var(--okdb-app-border); border-radius:6px; padding:8px; font-family:monospace; font-size:11px; word-break:break-all; color:var(--okdb-purple); max-height:80px; overflow:auto;">\n {{ fmtVec(vectorCache[row.source_key].vector) }}\n </div>\n </if>\n </if>\n </div>\n </expanded>\n </ok-table>\n\n <if :="docs.length === 0 && !docsBusy">\n <div style="opacity:.5; font-size:13px; padding:12px 0;">No documents found.</div>\n </if>\n </div>\n\n <div style="font-size:12px; opacity:.6; display:flex; gap:12px; align-items:center; flex-wrap:wrap;">\n <span>\n Showing {{ docs.length }}{{ docs.length >= docsLimit ? \'+\' : \'\' }} {{ docsStatus || \'\' }} docs\n <if :="docsLoadMs !== null"> in {{ docsLoadMs }}ms</if>\n </span>\n <if :="indexer?.doc_counts?.total">\n <span style="opacity:.7;">Total tracked: {{ indexer.doc_counts.total.toLocaleString() }}</span>\n </if>\n </div>\n </div>\n</engine-panel-shell>\n',style:d};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import e from"../../engines/parts/engine-lifecycle-actions.ok.js";export default{...e,tag:"embed-lifecycle-bar"};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function _0xda39(_0x38d415,_0x5cc988){_0x38d415=_0x38d415-0xe6;const _0x330cf0=_0x330c();let _0xda3994=_0x330cf0[_0x38d415];return _0xda3994;}const _0x4f2c29=_0xda39;(function(_0x4823cf,_0x55a04a){const _0x25e72d=_0xda39,_0x5737ae=_0x4823cf();while(!![]){try{const _0x5d5ad2=parseInt(_0x25e72d(0xfa))/0x1+parseInt(_0x25e72d(0xe9))/0x2+parseInt(_0x25e72d(0x112))/0x3*(-parseInt(_0x25e72d(0x101))/0x4)+parseInt(_0x25e72d(0x111))/0x5+-parseInt(_0x25e72d(0x103))/0x6*(-parseInt(_0x25e72d(0x117))/0x7)+parseInt(_0x25e72d(0xf7))/0x8*(-parseInt(_0x25e72d(0x118))/0x9)+parseInt(_0x25e72d(0x10c))/0xa;if(_0x5d5ad2===_0x55a04a)break;else _0x5737ae['push'](_0x5737ae['shift']());}catch(_0x27395a){_0x5737ae['push'](_0x5737ae['shift']());}}}(_0x330c,0x2ebe0));import _0x48277d from'../modals/register-model-modal.ok.js';function _0x330c(){const _0xefc1ab=['</b>\x22\x20from\x20catalog?','68368OdcMzM','<register-model-modal\x20:modal=\x22modal\x22\x20:initial-provider=\x22initialProvider\x22\x20:on-done=\x22onDone\x22\x20/>','model','shared','true','$ok','.pill{border:1px\x20solid\x20var(--okdb-app-border);background:var(--okdb-app-surface);padding:4px\x2010px;border-radius:999px;font-size:12px;cursor:pointer}.pill--on{border-color:var(--okdb-accent)}.td,.th{padding:8px\x2012px}.th{text-align:left;font-weight:500;font-size:11px;text-transform:uppercase;letter-spacing:.04em;opacity:.55}.td{border-top:1px\x20solid\x20#1e2932}.tr:hover\x20.td{background:#ffffff06}','24ToVHHp','data','48BNSidi','compact','Remove\x20model\x20\x22<b>','reduce','filterProvider','API','initialprovider','Failed\x20to\x20load\x20models','embed-model-catalog','1645240QLLtIb','message','provider','onchanged','models','440005ZOVcso','76233TeTZSk','modal','length','toast','info','280672xRlzkL','261YdwZOd','open','confirm','values','148256wfigyV','sort','/embeddings/models','/embeddings/models/','providers','includes','$attr','error','DELETE','load','\x0a<div\x20:style=\x22compactMode\x0a\x20\x20?\x20\x27display:flex;\x20flex-direction:column;\x20gap:14px;\x20width:min(900px,\x2078vw);\x20max-width:900px;\x27\x0a\x20\x20:\x20\x27display:flex;\x20flex-direction:column;\x20gap:16px;\x20max-width:860px;\x27\x22>\x0a\x0a\x20\x20<!--\x20Header\x20-->\x0a\x20\x20<div\x20style=\x22display:flex;\x20align-items:center;\x20gap:10px;\x20flex-wrap:wrap;\x22>\x0a\x20\x20\x20\x20<div\x20:style=\x22compactMode\x20?\x20\x27font-weight:600;\x20font-size:16px;\x27\x20:\x20\x27font-weight:600;\x20font-size:18px;\x27\x22>Model\x20Catalog</div>\x0a\x20\x20\x20\x20<span\x20style=\x22font-size:12px;\x20opacity:.55;\x22>{{totalCount}}\x20models</span>\x0a\x20\x20\x20\x20<div\x20style=\x22margin-left:auto;\x20display:flex;\x20gap:8px;\x22>\x0a\x20\x20\x20\x20\x20\x20<button\x20@click=\x22load()\x22\x20:disabled=\x22busy\x22\x20style=\x22opacity:.8;\x22>↻</button>\x0a\x20\x20\x20\x20\x20\x20<button\x20@click=\x22openAdd()\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20style=\x22background:color-mix(in\x20srgb,\x20var(--okdb-accent)\x2013%,\x20transparent);\x20border-color:var(--okdb-accent);\x20color:var(--okdb-accent);\x20font-weight:600;\x20padding:5px\x2014px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20+\x20Register\x20Model\x0a\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</div>\x0a\x0a\x20\x20<if\x20:=\x22error\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22color:var(--okdb-danger);\x20font-size:13px;\x20padding:10px;\x20border:1px\x20solid\x20var(--okdb-danger);\x20border-radius:8px;\x22>{{error}}</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<!--\x20Provider\x20filter\x20pills\x20-->\x0a\x20\x20<if\x20:=\x22providers.length\x20>\x201\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-wrap:wrap;\x20gap:6px;\x22>\x0a\x20\x20\x20\x20\x20\x20<button\x0a\x20\x20\x20\x20\x20\x20\x20\x20@click=\x22filterProvider\x20=\x20null\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20:class=\x22filterProvider\x20==\x20null\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20All\x20({{totalCount}})\x0a\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20\x20\x20<for\x20:=\x22providers\x22\x20let:p>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@click=\x22filterProvider\x20=\x20p\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:class=\x22filterProvider\x20===\x20p\x20?\x20\x27pill\x20pill--on\x27\x20:\x20\x27pill\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{p}}\x20({{(models[p]\x20||\x20[]).length}})\x0a\x20\x20\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20\x20\x20</for>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<!--\x20Table\x20-->\x0a\x20\x20<if\x20:=\x22filteredEntries.length\x20>\x200\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22background:var(--okdb-app-surface);\x20border-radius:12px;\x20overflow:hidden;\x22>\x0a\x20\x20\x20\x20\x20\x20<table\x20style=\x22width:100%;\x20border-collapse:collapse;\x20font-size:13px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<thead>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<tr\x20style=\x22border-bottom:1px\x20solid\x20var(--okdb-app-border);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<th\x20class=\x22th\x22>Provider</th>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<th\x20class=\x22th\x22>Model</th>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<th\x20class=\x22th\x22\x20style=\x22text-align:right;\x22>Dims</th>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<th\x20class=\x22th\x22>Description</th>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<th\x20class=\x22th\x22\x20style=\x22text-align:right;\x20width:80px;\x22></th>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</tr>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</thead>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<tbody>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<tr\x20as=\x22repeat\x22\x20:of=\x22filteredEntries\x22\x20let:item=\x22m\x22\x20class=\x22tr\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<td\x20class=\x22td\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22padding:2px\x208px;\x20border-radius:999px;\x20font-size:11px;\x20border:1px\x20solid\x20color-mix(in\x20srgb,\x20var(--okdb-accent)\x2033%,\x20transparent);\x20color:var(--okdb-accent);\x20background:color-mix(in\x20srgb,\x20var(--okdb-accent)\x207%,\x20transparent);\x22>{{m.provider}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</td>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<td\x20class=\x22td\x22\x20style=\x22font-family:monospace;\x22>{{m.model}}</td>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<td\x20class=\x22td\x22\x20style=\x22text-align:right;\x20font-family:monospace;\x20color:var(--okdb-warning);\x22>{{m.dims}}</td>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<td\x20class=\x22td\x22\x20style=\x22opacity:.6;\x20font-size:12px;\x22>{{m.description\x20||\x20\x27—\x27}}</td>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<td\x20class=\x22td\x22\x20style=\x22text-align:right;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22!m.builtin\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22remove(m)\x22\x20style=\x22font-size:11px;\x20padding:2px\x208px;\x20color:var(--okdb-danger);\x20opacity:.8;\x22>✕</button>\x0a\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<if\x20:=\x22m.builtin\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:10px;\x20opacity:.4;\x20font-style:italic;\x22>built-in</span>\x0a\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</td>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</tr>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</tbody>\x0a\x20\x20\x20\x20\x20\x20</table>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<if\x20:=\x22!busy\x20&&\x20filteredEntries.length\x20===\x200\x20&&\x20!error\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22opacity:.55;\x20font-size:13px;\x20line-height:1.8;\x22>\x0a\x20\x20\x20\x20\x20\x20No\x20models\x20in\x20catalog\x20for\x20the\x20selected\x20filter.<br>\x0a\x20\x20\x20\x20\x20\x20Register\x20a\x20custom\x20model\x20to\x20auto-resolve\x20its\x20dimensions\x20when\x20creating\x20engines.\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a</div>\x0a','push','Delete\x20failed','keys','102584eeWyYk','busy'];_0x330c=function(){return _0xefc1ab;};return _0x330c();}export default{'tag':_0x4f2c29(0x10b),'attr':{'initialprovider':{},'compact':{},'onchanged':{}},'dependencies':[_0x48277d],'context':_0x5a07b3=>({'busy':!0x1,'models':{},'error':null,'filterProvider':null,get 'initialProvider'(){const _0x4c52d5=_0x4f2c29;return _0x5a07b3[_0x4c52d5(0xef)][_0x4c52d5(0x109)]||null;},get 'compactMode'(){const _0x1da631=_0x4f2c29;return!0x0===_0x5a07b3[_0x1da631(0xef)]['compact']||_0x1da631(0xfe)===_0x5a07b3[_0x1da631(0xef)][_0x1da631(0x104)];},async 'load'(){const _0x40d75f=_0x4f2c29;this['busy']=!0x0,this[_0x40d75f(0xf0)]=null;try{const _0x3492fd=await fetch(__ENV__[_0x40d75f(0x108)]+_0x40d75f(0xeb)),_0x4b276e=await _0x3492fd['json']();if(!_0x3492fd['ok'])throw new Error(_0x4b276e?.[_0x40d75f(0xf0)]?.[_0x40d75f(0x10d)]||_0x40d75f(0x10a));this['models']=_0x4b276e[_0x40d75f(0x102)]??{};}catch(_0x5d36a1){this[_0x40d75f(0xf0)]=_0x5d36a1?.[_0x40d75f(0x10d)]||String(_0x5d36a1),this[_0x40d75f(0x110)]={};}finally{this[_0x40d75f(0xf8)]=!0x1;}},get 'providers'(){const _0x36fedc=_0x4f2c29;return Object[_0x36fedc(0xf6)](this[_0x36fedc(0x110)])[_0x36fedc(0xea)]();},get 'filteredEntries'(){const _0x217ef0=_0x4f2c29,_0x4c341d=this['filterProvider'];if(!_0x4c341d){const _0x477262=[];for(const _0x4bb180 of this[_0x217ef0(0xed)])for(const _0x3801fc of this[_0x217ef0(0x110)][_0x4bb180]||[])_0x477262[_0x217ef0(0xf4)]({..._0x3801fc,'provider':_0x3801fc[_0x217ef0(0x10e)]??_0x4bb180});return _0x477262;}return(this[_0x217ef0(0x110)][_0x4c341d]||[])['map'](_0x48e1e6=>({..._0x48e1e6,'provider':_0x48e1e6[_0x217ef0(0x10e)]??_0x4c341d}));},get 'totalCount'(){const _0x4b16e6=_0x4f2c29;return Object[_0x4b16e6(0xe8)](this['models'])[_0x4b16e6(0x106)]((_0x15fae8,_0x2ecd26)=>_0x15fae8+_0x2ecd26[_0x4b16e6(0x114)],0x0);},async 'openAdd'(){const _0x478026=_0x4f2c29;await _0x5a07b3[_0x478026(0xff)][_0x478026(0xfd)][_0x478026(0x113)][_0x478026(0xe6)]({'owner':_0x5a07b3,'title':'Register\x20Model','content':_0x478026(0xfb),'context':_0x5cb81c=>({'modal':_0x5cb81c,'initialProvider':this[_0x478026(0x107)]||'','onDone':async()=>{const _0x517233=_0x478026;await this[_0x517233(0xf2)](),await _0x5a07b3['$attr'][_0x517233(0x10f)]?.();}})});},async 'remove'(_0x1ac3d3){const _0x1ddb38=_0x4f2c29;if(_0x1ac3d3['builtin'])return void _0x5a07b3[_0x1ddb38(0xff)][_0x1ddb38(0xfd)]?.[_0x1ddb38(0x115)]?.[_0x1ddb38(0xf0)]?.('Built-in\x20models\x20cannot\x20be\x20deleted');const _0x8402ea=_0x1ac3d3[_0x1ddb38(0x10e)]+':'+_0x1ac3d3[_0x1ddb38(0xfc)];if(await _0x5a07b3[_0x1ddb38(0xff)][_0x1ddb38(0xfd)][_0x1ddb38(0x113)][_0x1ddb38(0xe7)](_0x1ddb38(0x105)+_0x8402ea+_0x1ddb38(0xf9)))try{const _0x11fafa=await fetch(__ENV__[_0x1ddb38(0x108)]+_0x1ddb38(0xec)+encodeURIComponent(_0x8402ea),{'method':_0x1ddb38(0xf1)});if(!_0x11fafa['ok']){const _0x37c68a=await _0x11fafa['json']();throw new Error(_0x37c68a?.[_0x1ddb38(0xf0)]?.['message']||_0x1ddb38(0xf5));}_0x5a07b3['$ok'][_0x1ddb38(0xfd)]?.['toast']?.[_0x1ddb38(0x116)]?.('Removed\x20\x22'+_0x8402ea+'\x22'),await this[_0x1ddb38(0xf2)](),await _0x5a07b3[_0x1ddb38(0xef)][_0x1ddb38(0x10f)]?.();}catch(_0x1a2af8){_0x5a07b3[_0x1ddb38(0xff)][_0x1ddb38(0xfd)]?.[_0x1ddb38(0x115)]?.[_0x1ddb38(0xf0)]?.(_0x1a2af8?.[_0x1ddb38(0x10d)]||_0x1ddb38(0xf5));}}}),async 'mount'(_0x21a3fc){const _0x562919=_0x4f2c29;await this[_0x562919(0xf2)]();const _0x11f90b=_0x21a3fc[_0x562919(0xef)][_0x562919(0x109)]||null;_0x11f90b&&this['providers'][_0x562919(0xee)](_0x11f90b)&&(this[_0x562919(0x107)]=_0x11f90b);},'template':_0x4f2c29(0xf3),'style':_0x4f2c29(0x100)};
|
|
1
|
+
import t from"../modals/register-model-modal.ok.js";export default{tag:"embed-model-catalog",attr:{initialprovider:{},compact:{},onchanged:{}},dependencies:[t],context:t=>({busy:!1,models:{},error:null,filterProvider:null,get initialProvider(){return t.$attr.initialprovider||null},get compactMode(){return!0===t.$attr.compact||"true"===t.$attr.compact},async load(){this.busy=!0,this.error=null;try{const t=await fetch(`${__ENV__.API}/embeddings/models`),e=await t.json();if(!t.ok)throw new Error(e?.error?.message||"Failed to load models");this.models=e.data??{}}catch(t){this.error=t?.message||String(t),this.models={}}finally{this.busy=!1}},get providers(){return Object.keys(this.models).sort()},get filteredEntries(){const t=this.filterProvider;if(!t){const t=[];for(const e of this.providers)for(const o of this.models[e]||[])t.push({...o,provider:o.provider??e});return t}return(this.models[t]||[]).map(e=>({...e,provider:e.provider??t}))},get totalCount(){return Object.values(this.models).reduce((t,e)=>t+e.length,0)},async openAdd(){await t.$ok.shared.modal.open({owner:t,title:"Register Model",content:'<register-model-modal :modal="modal" :initial-provider="initialProvider" :on-done="onDone" />',context:e=>({modal:e,initialProvider:this.filterProvider||"",onDone:async()=>{await this.load(),await(t.$attr.onchanged?.())}})})},async remove(e){if(e.builtin)return void t.$ok.shared?.toast?.error?.("Built-in models cannot be deleted");const o=`${e.provider}:${e.model}`;if(await t.$ok.shared.modal.confirm(`Remove model "<b>${o}</b>" from catalog?`))try{const e=await fetch(`${__ENV__.API}/embeddings/models/${encodeURIComponent(o)}`,{method:"DELETE"});if(!e.ok){const t=await e.json();throw new Error(t?.error?.message||"Delete failed")}t.$ok.shared?.toast?.info?.(`Removed "${o}"`),await this.load(),await(t.$attr.onchanged?.())}catch(e){t.$ok.shared?.toast?.error?.(e?.message||"Delete failed")}}}),async mount(t){await this.load();const e=t.$attr.initialprovider||null;e&&this.providers.includes(e)&&(this.filterProvider=e)},template:'\n<div :style="compactMode\n ? \'display:flex; flex-direction:column; gap:14px; width:min(900px, 78vw); max-width:900px;\'\n : \'display:flex; flex-direction:column; gap:16px; max-width:860px;\'">\n\n \x3c!-- Header --\x3e\n <div style="display:flex; align-items:center; gap:10px; flex-wrap:wrap;">\n <div :style="compactMode ? \'font-weight:600; font-size:16px;\' : \'font-weight:600; font-size:18px;\'">Model Catalog</div>\n <span style="font-size:12px; opacity:.55;">{{totalCount}} models</span>\n <div style="margin-left:auto; display:flex; gap:8px;">\n <button @click="load()" :disabled="busy" style="opacity:.8;">↻</button>\n <button @click="openAdd()"\n style="background:color-mix(in srgb, var(--okdb-accent) 13%, transparent); border-color:var(--okdb-accent); color:var(--okdb-accent); font-weight:600; padding:5px 14px;">\n + Register Model\n </button>\n </div>\n </div>\n\n <if :="error">\n <div style="color:var(--okdb-danger); font-size:13px; padding:10px; border:1px solid var(--okdb-danger); border-radius:8px;">{{error}}</div>\n </if>\n\n \x3c!-- Provider filter pills --\x3e\n <if :="providers.length > 1">\n <div style="display:flex; flex-wrap:wrap; gap:6px;">\n <button\n @click="filterProvider = null"\n :class="filterProvider == null ? \'pill pill--on\' : \'pill\'">\n All ({{totalCount}})\n </button>\n <for :="providers" let:p>\n <button\n @click="filterProvider = p"\n :class="filterProvider === p ? \'pill pill--on\' : \'pill\'">\n {{p}} ({{(models[p] || []).length}})\n </button>\n </for>\n </div>\n </if>\n\n \x3c!-- Table --\x3e\n <if :="filteredEntries.length > 0">\n <div style="background:var(--okdb-app-surface); border-radius:12px; overflow:hidden;">\n <table style="width:100%; border-collapse:collapse; font-size:13px;">\n <thead>\n <tr style="border-bottom:1px solid var(--okdb-app-border);">\n <th class="th">Provider</th>\n <th class="th">Model</th>\n <th class="th" style="text-align:right;">Dims</th>\n <th class="th">Description</th>\n <th class="th" style="text-align:right; width:80px;"></th>\n </tr>\n </thead>\n <tbody>\n <tr as="repeat" :of="filteredEntries" let:item="m" class="tr">\n <td class="td">\n <span style="padding:2px 8px; border-radius:999px; font-size:11px; border:1px solid color-mix(in srgb, var(--okdb-accent) 33%, transparent); color:var(--okdb-accent); background:color-mix(in srgb, var(--okdb-accent) 7%, transparent);">{{m.provider}}</span>\n </td>\n <td class="td" style="font-family:monospace;">{{m.model}}</td>\n <td class="td" style="text-align:right; font-family:monospace; color:var(--okdb-warning);">{{m.dims}}</td>\n <td class="td" style="opacity:.6; font-size:12px;">{{m.description || \'—\'}}</td>\n <td class="td" style="text-align:right;">\n <if :="!m.builtin">\n <button @click="remove(m)" style="font-size:11px; padding:2px 8px; color:var(--okdb-danger); opacity:.8;">✕</button>\n </if>\n <if :="m.builtin">\n <span style="font-size:10px; opacity:.4; font-style:italic;">built-in</span>\n </if>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </if>\n\n <if :="!busy && filteredEntries.length === 0 && !error">\n <div style="opacity:.55; font-size:13px; line-height:1.8;">\n No models in catalog for the selected filter.<br>\n Register a custom model to auto-resolve its dimensions when creating engines.\n </div>\n </if>\n\n</div>\n',style:".pill{border:1px solid var(--okdb-app-border);background:var(--okdb-app-surface);padding:4px 10px;border-radius:999px;font-size:12px;cursor:pointer}.pill--on{border-color:var(--okdb-accent)}.td,.th{padding:8px 12px}.th{text-align:left;font-weight:500;font-size:11px;text-transform:uppercase;letter-spacing:.04em;opacity:.55}.td{border-top:1px solid #1e2932}.tr:hover .td{background:#ffffff06}"};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const _0x5b8f86=_0x1ba4;(function(_0x4561eb,_0x1692ba){const _0x3d64c4=_0x1ba4,_0x1eda56=_0x4561eb();while(!![]){try{const _0x3f43c5=-parseInt(_0x3d64c4(0x1ef))/0x1+-parseInt(_0x3d64c4(0x21d))/0x2+-parseInt(_0x3d64c4(0x21a))/0x3*(parseInt(_0x3d64c4(0x204))/0x4)+parseInt(_0x3d64c4(0x22b))/0x5+parseInt(_0x3d64c4(0x228))/0x6+parseInt(_0x3d64c4(0x1e4))/0x7*(-parseInt(_0x3d64c4(0x210))/0x8)+parseInt(_0x3d64c4(0x220))/0x9;if(_0x3f43c5===_0x1692ba)break;else _0x1eda56['push'](_0x1eda56['shift']());}catch(_0x137a58){_0x1eda56['push'](_0x1eda56['shift']());}}}(_0x1b7e,0xacfe4));function _0x1ba4(_0x91fce3,_0x4271c2){_0x91fce3=_0x91fce3-0x1e0;const _0x1b7e5a=_0x1b7e();let _0x1ba414=_0x1b7e5a[_0x91fce3];return _0x1ba414;}function _0x1b7e(){const _0x473e3f=['isRunning','search','2137490CaINAk','focusPipeline','embedder','toast','sort','var(--okdb-info)','filter','pipelines','engines','get','message','6279FHlEeE','Worker','Embedder','$attr','/pipelines/','var(--okdb-warning)','has','length','name','add','success','964006RTzjDY','meta','storage_key','partially\x20running','source_type','\x22\x20stopped','default','<br>','error','join','pipeline','\x22\x20deleted','key','$ok','Stop\x20all\x20engines\x20in\x20pipeline\x20\x22','some','set','embed-overview','has\x20errors','push','confirm','432JmeUzq','<br><br>This\x20cannot\x20be\x20undone.','var(--okdb-success)','show-create','shared','replace','indexer','DELETE','Pipeline\x20\x22','$dispatch','every','pipelineBusy','816YTkzzv','var(--okdb-danger)','POST','var(--okdb-purple)','info','source_env','type','/env/','Delete\x20failed','created','1362arkHOa','status','Delete\x20the\x20entire\x20pipeline\x20\x22<b>','2042364MbaIft','values','modal','18087768sUJggi','select','var(--okdb-accent)','embed-worker','vector-search','var(--okdb-app-fg-muted)','/stop','worker','2382264bqMpTy'];_0x1b7e=function(){return _0x473e3f;};return _0x1b7e();}import _0x856df5 from'../../engines/parts/engine-row-item.ok.js';export default{'tag':_0x5b8f86(0x200),'dependencies':[_0x856df5],'attr':{'engines':{},'focusPipeline':{}},'context':_0x4ae089=>({'pipelineBusy':{},get 'allEngines'(){const _0xc94528=_0x5b8f86;return _0x4ae089[_0xc94528(0x1e7)][_0xc94528(0x1e1)]??[];},get 'focusPipeline'(){const _0x2ba2d0=_0x5b8f86;return _0x4ae089[_0x2ba2d0(0x1e7)][_0x2ba2d0(0x22c)]??null;},get 'pipelines'(){const _0x26af92=_0x5b8f86,_0x4f0d25=new Map();for(const _0x273f48 of this['allEngines']){const _0x56291c=_0x273f48[_0x26af92(0x1f0)]?.[_0x26af92(0x1f9)]??_0x273f48['name'][_0x26af92(0x209)](/-worker$/,'');_0x4f0d25[_0x26af92(0x1ea)](_0x56291c)||_0x4f0d25[_0x26af92(0x1ff)](_0x56291c,{'name':_0x56291c,'embedder':null,'indexer':null,'search':null,'worker':null});const _0x199efa=_0x4f0d25[_0x26af92(0x1e2)](_0x56291c);'embedder'===_0x273f48[_0x26af92(0x216)]?_0x199efa['embedder']=_0x273f48:_0x26af92(0x20a)===_0x273f48[_0x26af92(0x216)]?_0x199efa[_0x26af92(0x20a)]=_0x273f48:_0x26af92(0x224)===_0x273f48['type']?_0x199efa[_0x26af92(0x22a)]=_0x273f48:_0x26af92(0x223)===_0x273f48[_0x26af92(0x216)]&&(_0x199efa[_0x26af92(0x227)]=_0x273f48);}return[..._0x4f0d25[_0x26af92(0x21e)]()][_0x26af92(0x22f)]((_0x5b39a1,_0x366c75)=>_0x5b39a1[_0x26af92(0x1ec)]['localeCompare'](_0x366c75[_0x26af92(0x1ec)]));},get 'orphans'(){const _0x140ad4=_0x5b8f86,_0x20fd01=new Set();for(const _0x49775f of this[_0x140ad4(0x1e0)])for(const _0x9aedb3 of[_0x49775f[_0x140ad4(0x22d)],_0x49775f[_0x140ad4(0x20a)],_0x49775f[_0x140ad4(0x22a)],_0x49775f[_0x140ad4(0x227)]])_0x9aedb3&&_0x20fd01[_0x140ad4(0x1ed)](_0x9aedb3[_0x140ad4(0x1fb)]);const _0x49d06b=this[_0x140ad4(0x1e0)]['filter'](_0x2a427c=>0x1===[_0x2a427c[_0x140ad4(0x22d)],_0x2a427c['indexer'],_0x2a427c['search'],_0x2a427c['worker']][_0x140ad4(0x231)](Boolean)[_0x140ad4(0x1eb)]),_0x3aeb5b=[];for(const _0x1f6f10 of _0x49d06b){const _0x5733c7=_0x1f6f10['embedder']??_0x1f6f10[_0x140ad4(0x20a)]??_0x1f6f10['search']??_0x1f6f10[_0x140ad4(0x227)];_0x5733c7&&_0x3aeb5b[_0x140ad4(0x202)](_0x5733c7);}return _0x3aeb5b;},get 'groups'(){const _0x28976a=_0x5b8f86;return this[_0x28976a(0x1e0)]['filter'](_0x4c0b5d=>[_0x4c0b5d[_0x28976a(0x22d)],_0x4c0b5d[_0x28976a(0x20a)],_0x4c0b5d[_0x28976a(0x22a)],_0x4c0b5d[_0x28976a(0x227)]][_0x28976a(0x231)](Boolean)[_0x28976a(0x1eb)]>0x1);},'healthDot'(_0xb44642){const _0x56ecef=_0x5b8f86,_0x3a20f0=[_0xb44642[_0x56ecef(0x22d)],_0xb44642[_0x56ecef(0x20a)],_0xb44642[_0x56ecef(0x22a)],_0xb44642[_0x56ecef(0x227)]][_0x56ecef(0x231)](Boolean);return _0x3a20f0[_0x56ecef(0x20e)](_0x2a26e5=>_0x2a26e5[_0x56ecef(0x229)])?_0x56ecef(0x206):_0x3a20f0[_0x56ecef(0x1fe)](_0x21dc02=>_0x56ecef(0x1f7)===_0x21dc02[_0x56ecef(0x21b)])?_0x56ecef(0x211):_0x56ecef(0x1e9);},'healthTitle'(_0x432093){const _0xcb8a99=_0x5b8f86,_0x52aa41=[_0x432093['embedder'],_0x432093[_0xcb8a99(0x20a)],_0x432093[_0xcb8a99(0x22a)],_0x432093[_0xcb8a99(0x227)]][_0xcb8a99(0x231)](Boolean);return _0x52aa41[_0xcb8a99(0x20e)](_0x8095e3=>_0x8095e3['isRunning'])?'all\x20running':_0x52aa41[_0xcb8a99(0x1fe)](_0x54b7ea=>_0xcb8a99(0x1f7)===_0x54b7ea['status'])?_0xcb8a99(0x201):_0xcb8a99(0x1f2);},'typeColor':{'embedder':_0x5b8f86(0x230),'indexer':_0x5b8f86(0x213),'vector-search':_0x5b8f86(0x222),'embed-worker':_0x5b8f86(0x1e9)},'typeLabel':{'embedder':_0x5b8f86(0x1e6),'indexer':'Indexer','vector-search':'Search','embed-worker':_0x5b8f86(0x1e5)},'statusDot':_0x17c6f7=>_0x17c6f7['isRunning']?_0x5b8f86(0x206):_0x5b8f86(0x1f7)===_0x17c6f7[_0x5b8f86(0x21b)]?_0x5b8f86(0x211):_0x5b8f86(0x225),'select'(_0xe8e859){const _0x356863=_0x5b8f86;_0x4ae089[_0x356863(0x20d)](_0x356863(0x221),_0xe8e859);},'openCreate'(){const _0x2bbcb8=_0x5b8f86;_0x4ae089[_0x2bbcb8(0x20d)](_0x2bbcb8(0x207),null);},'_enginesOf':_0x47d6c0=>[_0x47d6c0[_0x5b8f86(0x22d)],_0x47d6c0['indexer'],_0x47d6c0[_0x5b8f86(0x22a)],_0x47d6c0[_0x5b8f86(0x227)]][_0x5b8f86(0x231)](Boolean),'_pipelineUrl'(_0x1f9a51){const _0x578a9c=_0x5b8f86,_0x4a0716=_0x1f9a51['indexer']??_0x1f9a51[_0x578a9c(0x22a)]??_0x1f9a51[_0x578a9c(0x227)];if(!_0x4a0716)return null;const _0x50cd30=_0x4a0716['config']??{},_0x2ef25e=encodeURIComponent(_0x50cd30[_0x578a9c(0x215)]??_0x578a9c(0x1f5)),_0x381525=encodeURIComponent(_0x50cd30[_0x578a9c(0x1f3)]??''),_0x162cc2=encodeURIComponent(_0x50cd30[_0x578a9c(0x1f1)]??_0x1f9a51[_0x578a9c(0x1ec)]);return __ENV__['API']+_0x578a9c(0x217)+_0x2ef25e+'/type/'+_0x381525+_0x578a9c(0x1e8)+_0x162cc2;},async 'stopPipeline'(_0x352926){const _0x1bfbdf=_0x5b8f86;if(await _0x4ae089[_0x1bfbdf(0x1fc)][_0x1bfbdf(0x208)][_0x1bfbdf(0x21f)][_0x1bfbdf(0x203)](_0x1bfbdf(0x1fd)+_0x352926['name']+'\x22?')){this[_0x1bfbdf(0x20f)]={...this[_0x1bfbdf(0x20f)],[_0x352926[_0x1bfbdf(0x1ec)]]:!0x0};try{const _0x2354ba=this['_pipelineUrl'](_0x352926);_0x2354ba&&await fetch(_0x2354ba+_0x1bfbdf(0x226),{'method':_0x1bfbdf(0x212)}),_0x4ae089[_0x1bfbdf(0x1fc)][_0x1bfbdf(0x208)]?.[_0x1bfbdf(0x22e)]?.[_0x1bfbdf(0x214)]?.(_0x1bfbdf(0x20c)+_0x352926[_0x1bfbdf(0x1ec)]+_0x1bfbdf(0x1f4)),_0x4ae089['$dispatch'](_0x1bfbdf(0x219),null);}catch(_0x31003f){_0x4ae089[_0x1bfbdf(0x1fc)][_0x1bfbdf(0x208)]?.[_0x1bfbdf(0x22e)]?.[_0x1bfbdf(0x1f7)]?.(_0x31003f?.[_0x1bfbdf(0x1e3)]||'Stop\x20failed');}finally{this[_0x1bfbdf(0x20f)]={...this[_0x1bfbdf(0x20f)],[_0x352926[_0x1bfbdf(0x1ec)]]:!0x1};}}},async 'deletePipeline'(_0x48520f){const _0x119d47=_0x5b8f86,_0xf9c2b5=this['_enginesOf'](_0x48520f)['map'](_0x37c68e=>'•\x20'+_0x37c68e['type']+':\x20'+_0x37c68e['name'])[_0x119d47(0x1f8)](_0x119d47(0x1f6));if(await _0x4ae089[_0x119d47(0x1fc)][_0x119d47(0x208)][_0x119d47(0x21f)][_0x119d47(0x203)](_0x119d47(0x21c)+_0x48520f[_0x119d47(0x1ec)]+'</b>\x22?<br><br>'+_0xf9c2b5+_0x119d47(0x205))){this[_0x119d47(0x20f)]={...this[_0x119d47(0x20f)],[_0x48520f['name']]:!0x0};try{const _0x53a525=this['_pipelineUrl'](_0x48520f);_0x53a525&&await fetch(_0x53a525,{'method':_0x119d47(0x20b)}),_0x4ae089[_0x119d47(0x1fc)]['shared']?.[_0x119d47(0x22e)]?.[_0x119d47(0x1ee)]?.('Pipeline\x20\x22'+_0x48520f[_0x119d47(0x1ec)]+_0x119d47(0x1fa)),_0x4ae089['$dispatch'](_0x119d47(0x219),null);}catch(_0x40b55d){_0x4ae089[_0x119d47(0x1fc)][_0x119d47(0x208)]?.[_0x119d47(0x22e)]?.[_0x119d47(0x1f7)]?.(_0x40b55d?.['message']||_0x119d47(0x218));}finally{this[_0x119d47(0x20f)]={...this[_0x119d47(0x20f)],[_0x48520f[_0x119d47(0x1ec)]]:!0x1};}}}}),'template':'\x0a<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:20px;\x20max-width:860px;\x22>\x0a\x0a\x20\x20<!--\x20Header\x20-->\x0a\x20\x20<div\x20style=\x22display:flex;\x20align-items:center;\x20gap:12px;\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22font-weight:600;\x20font-size:18px;\x22>Embeddings\x20Overview</div>\x0a\x20\x20\x20\x20<div\x20style=\x22margin-left:auto;\x22>\x0a\x20\x20\x20\x20\x20\x20<button\x0a\x20\x20\x20\x20\x20\x20\x20\x20@click=\x22openCreate()\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20style=\x22background:color-mix(in\x20srgb,\x20var(--okdb-accent)\x2013%,\x20transparent);\x20border-color:var(--okdb-accent);\x20color:var(--okdb-accent);\x20font-weight:600;\x20padding:6px\x2016px;\x22\x0a\x20\x20\x20\x20\x20\x20>\x0a\x20\x20\x20\x20\x20\x20\x20\x20+\x20Create\x0a\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</div>\x0a\x0a\x0a\x20\x20<!--\x20No\x20engines\x20at\x20all\x20-->\x0a\x20\x20<if\x20:=\x22allEngines.length\x20===\x200\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22opacity:.55;\x20font-size:14px;\x20line-height:1.8;\x22>\x0a\x20\x20\x20\x20\x20\x20No\x20engines\x20created\x20yet.<br>\x0a\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:12px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20Use\x20<b>+\x20Create</b>\x20to\x20set\x20up\x20a\x20pipeline\x20or\x20individual\x20engine.<br>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<br>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<b>Embedder</b>\x20—\x20connection\x20to\x20an\x20ML\x20service\x20(Ollama,\x20OpenAI\x20…)<br>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<b>Indexer</b>\x20—\x20watches\x20a\x20OKDB\x20type\x27s\x20change\x20log\x20and\x20creates\x20embeddings<br>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<b>Worker</b>\x20—\x20queue\x20consumer\x20for\x20queue-mode\x20indexing<br>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<b>Search</b>\x20—\x20nearest-neighbour\x20index\x20over\x20a\x20storage\x20key\x0a\x20\x20\x20\x20\x20\x20</span>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<!--\x20Pipeline\x20groups\x20-->\x0a\x20\x20<if\x20:=\x22groups.length\x20>\x200\x22>\x0a\x20\x20\x20\x20<div>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20text-transform:uppercase;\x20opacity:.45;\x20letter-spacing:.06em;\x20margin-bottom:8px;\x22>Pipelines</div>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:10px;\x22>\x0a\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<div\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:style=\x22\x27background:var(--okdb-app-surface);\x20border-radius:10px;\x20padding:14px\x2016px;\x20box-shadow:\x27\x20+\x20(focusPipeline\x20===\x20g.name\x20?\x20\x270\x200\x200\x202px\x20var(--okdb-accent),\x200\x200\x2012px\x20color-mix(in\x20srgb,\x20var(--okdb-accent)\x2020%,\x20transparent)\x27\x20:\x20\x270\x200\x205px\x20#ffffff1a\x27)\x20+\x20\x27;\x20transition:box-shadow\x20.3s;\x27\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Group\x20header\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20align-items:center;\x20gap:10px;\x20margin-bottom:10px;\x22>\x0a\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:style=\x22\x27width:8px;height:8px;border-radius:50%;flex-shrink:0;background:\x27\x20+\x20healthDot(g)\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:title=\x22healthTitle(g)\x22\x0a\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<span\x20style=\x22font-weight:600;\x20font-size:14px;\x22>{{\x20g.name\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Vector\x20store\x20summary:\x20storage_key\x20+\x20persisted\x20count\x20from\x20indexer\x20stats\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22g.indexer?.meta?.pipeline\x22>\x0a\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\x20style=\x22font-size:11px;\x20opacity:.6;\x20font-family:monospace;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20title=\x22LMDB\x20vector\x20store\x20for\x20this\x20pipeline\x22\x0a\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~emb:vec:{{\x20g.indexer.config?.storage_key\x20??\x20g.name\x20}}\x0a\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</if>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Pipeline-level\x20actions\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22margin-left:auto;\x20display:flex;\x20gap:6px;\x20align-items:center;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22[g.embedder,\x20g.indexer,\x20g.search,\x20g.worker].filter(Boolean).some(e\x20=>\x20e.isRunning)\x22>\x0a\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@click=\x22stopPipeline(g)\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:disabled=\x22pipelineBusy[g.name]\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22font-size:11px;\x20padding:3px\x2010px;\x20color:var(--okdb-warning);\x20border-color:var(--okdb-warning);\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20title=\x22Stop\x20all\x20engines\x20in\x20this\x20pipeline\x22\x0a\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{{\x20pipelineBusy[g.name]\x20?\x20\x27…\x27\x20:\x20\x27⏹\x20Stop\x27\x20}}\x0a\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</if>\x0a\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@click=\x22deletePipeline(g)\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:disabled=\x22pipelineBusy[g.name]\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22font-size:11px;\x20padding:3px\x2010px;\x20color:var(--okdb-danger);\x20border-color:var(--okdb-danger);\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20title=\x22Stop\x20and\x20permanently\x20delete\x20all\x20engines\x20in\x20this\x20pipeline\x22\x0a\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{{\x20pipelineBusy[g.name]\x20?\x20\x27…\x27\x20:\x20\x27✕\x20Delete\x27\x20}}\x0a\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</div>\x0a\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<!--\x20Engine\x20rows\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:5px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<each\x20:of=\x22[g.embedder,\x20g.indexer,\x20g.search,\x20g.worker].filter(Boolean)\x22\x20let:item=\x22eng\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<engine-row-item\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:engine=\x22eng\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:label=\x22typeLabel[eng.type]\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:label-color=\x22typeColor[eng.type]\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:subtitle=\x22eng.status\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20action-label=\x22Open\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@select=\x22select($event.detail)\x22\x0a\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<if\x20:=\x22eng.status\x20===\x20\x27error\x27\x22>\x0a\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;\x20color:var(--okdb-danger);\x20flex-shrink:0;\x22\x20:title=\x22eng.error\x20||\x20\x27error\x27\x22>⚠\x20error</span>\x0a\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</engine-row-item>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</each>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Missing\x20role\x20indicators\x20for\x20pipeline\x20completeness\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22!g.worker\x20&&\x20g.indexer?.config?.mode\x20===\x20\x27queue\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20opacity:.5;\x20padding:3px\x208px;\x20color:var(--okdb-warning);\x22>⚠\x20queue\x20mode\x20—\x20no\x20worker\x20configured</div>\x0a\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<if\x20:=\x22!g.search\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20opacity:.5;\x20padding:3px\x208px;\x20color:var(--okdb-warning);\x22>⚠\x20no\x20vector-search\x20engine</div>\x0a\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</div>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\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<!--\x20Standalone\x20engines\x20(don\x27t\x20form\x20a\x20group)\x20-->\x0a\x20\x20<if\x20:=\x22allEngines.length\x20>\x200\x20&&\x20(groups.length\x20>\x200\x20?\x20orphans.length\x20>\x200\x20:\x20true)\x22>\x0a\x20\x20\x20\x20<div>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20text-transform:uppercase;\x20opacity:.45;\x20letter-spacing:.06em;\x20margin-bottom:8px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20{{\x20groups.length\x20>\x200\x20?\x20\x27Standalone\x20Engines\x27\x20:\x20\x27Engines\x27\x20}}\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:4px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<each\x20:of=\x22groups.length\x20>\x200\x20?\x20orphans\x20:\x20allEngines\x22\x20let:item=\x22eng\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<engine-row-item\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:engine=\x22eng\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:label=\x22typeLabel[eng.type]\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:label-color=\x22typeColor[eng.type]\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:subtitle=\x22eng.status\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20action-label=\x22Open\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@select=\x22select($event.detail)\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22eng.status\x20===\x20\x27error\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:11px;\x20color:var(--okdb-danger);\x20flex-shrink:0;\x22\x20:title=\x22eng.error\x20||\x20\x27error\x27\x22>⚠\x20error</span>\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</engine-row-item>\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<!--\x20Summary\x20counts\x20-->\x0a\x20\x20<if\x20:=\x22allEngines.length\x20>\x200\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20gap:16px;\x20font-size:12px;\x20opacity:.5;\x20flex-wrap:wrap;\x22>\x0a\x20\x20\x20\x20\x20\x20<span>{{\x20allEngines.filter(e\x20=>\x20e.isRunning).length\x20}}\x20/\x20{{\x20allEngines.length\x20}}\x20running</span>\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22allEngines.filter(e\x20=>\x20e.status\x20===\x20\x27error\x27).length\x20>\x200\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22color:var(--okdb-danger);\x22>{{\x20allEngines.filter(e\x20=>\x20e.status\x20===\x20\x27error\x27).length\x20}}\x20error(s)</span>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a</div>\x0a','style':''};
|
|
1
|
+
import e from"../../engines/parts/engine-row-item.ok.js";export default{tag:"embed-overview",dependencies:[e],attr:{engines:{},focusPipeline:{}},context:e=>({pipelineBusy:{},get allEngines(){return e.$attr.engines??[]},get focusPipeline(){return e.$attr.focusPipeline??null},get pipelines(){const e=new Map;for(const n of this.allEngines){const i=n.meta?.pipeline??n.name.replace(/-worker$/,"");e.has(i)||e.set(i,{name:i,embedder:null,indexer:null,search:null,worker:null});const r=e.get(i);"embedder"===n.type?r.embedder=n:"indexer"===n.type?r.indexer=n:"vector-search"===n.type?r.search=n:"embed-worker"===n.type&&(r.worker=n)}return[...e.values()].sort((e,n)=>e.name.localeCompare(n.name))},get orphans(){const e=new Set;for(const n of this.pipelines)for(const i of[n.embedder,n.indexer,n.search,n.worker])i&&e.add(i.key);const n=this.pipelines.filter(e=>1===[e.embedder,e.indexer,e.search,e.worker].filter(Boolean).length),i=[];for(const e of n){const n=e.embedder??e.indexer??e.search??e.worker;n&&i.push(n)}return i},get groups(){return this.pipelines.filter(e=>[e.embedder,e.indexer,e.search,e.worker].filter(Boolean).length>1)},healthDot(e){const n=[e.embedder,e.indexer,e.search,e.worker].filter(Boolean);return n.every(e=>e.isRunning)?"var(--okdb-success)":n.some(e=>"error"===e.status)?"var(--okdb-danger)":"var(--okdb-warning)"},healthTitle(e){const n=[e.embedder,e.indexer,e.search,e.worker].filter(Boolean);return n.every(e=>e.isRunning)?"all running":n.some(e=>"error"===e.status)?"has errors":"partially running"},typeColor:{embedder:"var(--okdb-info)",indexer:"var(--okdb-purple)","vector-search":"var(--okdb-accent)","embed-worker":"var(--okdb-warning)"},typeLabel:{embedder:"Embedder",indexer:"Indexer","vector-search":"Search","embed-worker":"Worker"},statusDot:e=>e.isRunning?"var(--okdb-success)":"error"===e.status?"var(--okdb-danger)":"var(--okdb-app-fg-muted)",select(n){e.$dispatch("select",n)},openCreate(){e.$dispatch("show-create",null)},_enginesOf:e=>[e.embedder,e.indexer,e.search,e.worker].filter(Boolean),_pipelineUrl(e){const n=e.indexer??e.search??e.worker;if(!n)return null;const i=n.config??{},r=encodeURIComponent(i.source_env??"default"),t=encodeURIComponent(i.source_type??""),o=encodeURIComponent(i.storage_key??e.name);return`${__ENV__.API}/env/${r}/type/${t}/pipelines/${o}`},async stopPipeline(n){if(await e.$ok.shared.modal.confirm(`Stop all engines in pipeline "${n.name}"?`)){this.pipelineBusy={...this.pipelineBusy,[n.name]:!0};try{const i=this._pipelineUrl(n);i&&await fetch(`${i}/stop`,{method:"POST"}),e.$ok.shared?.toast?.info?.(`Pipeline "${n.name}" stopped`),e.$dispatch("created",null)}catch(n){e.$ok.shared?.toast?.error?.(n?.message||"Stop failed")}finally{this.pipelineBusy={...this.pipelineBusy,[n.name]:!1}}}},async deletePipeline(n){const i=this._enginesOf(n).map(e=>`• ${e.type}: ${e.name}`).join("<br>");if(await e.$ok.shared.modal.confirm(`Delete the entire pipeline "<b>${n.name}</b>"?<br><br>${i}<br><br>This cannot be undone.`)){this.pipelineBusy={...this.pipelineBusy,[n.name]:!0};try{const i=this._pipelineUrl(n);i&&await fetch(i,{method:"DELETE"}),e.$ok.shared?.toast?.success?.(`Pipeline "${n.name}" deleted`),e.$dispatch("created",null)}catch(n){e.$ok.shared?.toast?.error?.(n?.message||"Delete failed")}finally{this.pipelineBusy={...this.pipelineBusy,[n.name]:!1}}}}}),template:'\n<div style="display:flex; flex-direction:column; gap:20px; max-width:860px;">\n\n \x3c!-- Header --\x3e\n <div style="display:flex; align-items:center; gap:12px;">\n <div style="font-weight:600; font-size:18px;">Embeddings Overview</div>\n <div style="margin-left:auto;">\n <button\n @click="openCreate()"\n style="background:color-mix(in srgb, var(--okdb-accent) 13%, transparent); border-color:var(--okdb-accent); color:var(--okdb-accent); font-weight:600; padding:6px 16px;"\n >\n + Create\n </button>\n </div>\n </div>\n\n\n \x3c!-- No engines at all --\x3e\n <if :="allEngines.length === 0">\n <div style="opacity:.55; font-size:14px; line-height:1.8;">\n No engines created yet.<br>\n <span style="font-size:12px;">\n Use <b>+ Create</b> to set up a pipeline or individual engine.<br>\n <br>\n <b>Embedder</b> — connection to an ML service (Ollama, OpenAI …)<br>\n <b>Indexer</b> — watches a OKDB type\'s change log and creates embeddings<br>\n <b>Worker</b> — queue consumer for queue-mode indexing<br>\n <b>Search</b> — nearest-neighbour index over a storage key\n </span>\n </div>\n </if>\n\n \x3c!-- Pipeline groups --\x3e\n <if :="groups.length > 0">\n <div>\n <div style="font-size:11px; text-transform:uppercase; opacity:.45; letter-spacing:.06em; margin-bottom:8px;">Pipelines</div>\n <div style="display:flex; flex-direction:column; gap:10px;">\n <each :of="groups" let:item="g">\n <div\n :style="\'background:var(--okdb-app-surface); border-radius:10px; padding:14px 16px; box-shadow:\' + (focusPipeline === g.name ? \'0 0 0 2px var(--okdb-accent), 0 0 12px color-mix(in srgb, var(--okdb-accent) 20%, transparent)\' : \'0 0 5px #ffffff1a\') + \'; transition:box-shadow .3s;\'"\n >\n\n \x3c!-- Group header --\x3e\n <div style="display:flex; align-items:center; gap:10px; margin-bottom:10px;">\n <span\n :style="\'width:8px;height:8px;border-radius:50%;flex-shrink:0;background:\' + healthDot(g)"\n :title="healthTitle(g)"\n ></span>\n <span style="font-weight:600; font-size:14px;">{{ g.name }}</span>\n \x3c!-- Vector store summary: storage_key + persisted count from indexer stats --\x3e\n <if :="g.indexer?.meta?.pipeline">\n <span\n style="font-size:11px; opacity:.6; font-family:monospace;"\n title="LMDB vector store for this pipeline"\n >\n ~emb:vec:{{ g.indexer.config?.storage_key ?? g.name }}\n </span>\n </if>\n\n \x3c!-- Pipeline-level actions --\x3e\n <div style="margin-left:auto; display:flex; gap:6px; align-items:center;">\n <if :="[g.embedder, g.indexer, g.search, g.worker].filter(Boolean).some(e => e.isRunning)">\n <button\n @click="stopPipeline(g)"\n :disabled="pipelineBusy[g.name]"\n style="font-size:11px; padding:3px 10px; color:var(--okdb-warning); border-color:var(--okdb-warning);"\n title="Stop all engines in this pipeline"\n >\n {{ pipelineBusy[g.name] ? \'…\' : \'⏹ Stop\' }}\n </button>\n </if>\n <button\n @click="deletePipeline(g)"\n :disabled="pipelineBusy[g.name]"\n style="font-size:11px; padding:3px 10px; color:var(--okdb-danger); border-color:var(--okdb-danger);"\n title="Stop and permanently delete all engines in this pipeline"\n >\n {{ pipelineBusy[g.name] ? \'…\' : \'✕ Delete\' }}\n </button>\n </div>\n </div>\n\n \x3c!-- Engine rows --\x3e\n <div style="display:flex; flex-direction:column; gap:5px;">\n <each :of="[g.embedder, g.indexer, g.search, g.worker].filter(Boolean)" let:item="eng">\n <engine-row-item\n :engine="eng"\n :label="typeLabel[eng.type]"\n :label-color="typeColor[eng.type]"\n :subtitle="eng.status"\n action-label="Open"\n @select="select($event.detail)"\n >\n <if :="eng.status === \'error\'">\n <span style="font-size:11px; color:var(--okdb-danger); flex-shrink:0;" :title="eng.error || \'error\'">⚠ error</span>\n </if>\n </engine-row-item>\n </each>\n\n \x3c!-- Missing role indicators for pipeline completeness --\x3e\n <if :="!g.worker && g.indexer?.config?.mode === \'queue\'">\n <div style="font-size:11px; opacity:.5; padding:3px 8px; color:var(--okdb-warning);">⚠ queue mode — no worker configured</div>\n </if>\n <if :="!g.search">\n <div style="font-size:11px; opacity:.5; padding:3px 8px; color:var(--okdb-warning);">⚠ no vector-search engine</div>\n </if>\n </div>\n\n </div>\n </each>\n </div>\n </div>\n </if>\n\n \x3c!-- Standalone engines (don\'t form a group) --\x3e\n <if :="allEngines.length > 0 && (groups.length > 0 ? orphans.length > 0 : true)">\n <div>\n <div style="font-size:11px; text-transform:uppercase; opacity:.45; letter-spacing:.06em; margin-bottom:8px;">\n {{ groups.length > 0 ? \'Standalone Engines\' : \'Engines\' }}\n </div>\n <div style="display:flex; flex-direction:column; gap:4px;">\n <each :of="groups.length > 0 ? orphans : allEngines" let:item="eng">\n <engine-row-item\n :engine="eng"\n :label="typeLabel[eng.type]"\n :label-color="typeColor[eng.type]"\n :subtitle="eng.status"\n action-label="Open"\n @select="select($event.detail)"\n >\n <if :="eng.status === \'error\'">\n <span style="font-size:11px; color:var(--okdb-danger); flex-shrink:0;" :title="eng.error || \'error\'">⚠ error</span>\n </if>\n </engine-row-item>\n </each>\n </div>\n </div>\n </if>\n\n \x3c!-- Summary counts --\x3e\n <if :="allEngines.length > 0">\n <div style="display:flex; gap:16px; font-size:12px; opacity:.5; flex-wrap:wrap;">\n <span>{{ allEngines.filter(e => e.isRunning).length }} / {{ allEngines.length }} running</span>\n <if :="allEngines.filter(e => e.status === \'error\').length > 0">\n <span style="color:var(--okdb-danger);">{{ allEngines.filter(e => e.status === \'error\').length }} error(s)</span>\n </if>\n </div>\n </if>\n\n</div>\n',style:""};
|