@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.
Files changed (142) hide show
  1. package/bin/okdb.js +1 -1
  2. package/keys/public.pem +3 -0
  3. package/okdb.js +1 -1
  4. package/package.json +2 -2
  5. package/public/admin-app.js +1 -1
  6. package/public/components/admin-route-host.ok.js +1 -1
  7. package/public/components/env-picker.ok.js +1 -1
  8. package/public/components/field-path-input.ok.js +1 -1
  9. package/public/components/field.html +154 -2
  10. package/public/components/geo-map.ok.js +1 -1
  11. package/public/components/ok-cron-input.ok.js +1 -1
  12. package/public/components/ok-dropzone.ok.js +1 -1
  13. package/public/components/ok-js-input.ok.js +1 -1
  14. package/public/components/ok-json-input.ok.js +1 -1
  15. package/public/components/ok-text-monaco-input.ok.js +1 -1
  16. package/public/components/theme-toggle.ok.js +1 -1
  17. package/public/index.html +29 -2
  18. package/public/layouts/_default.ok.html +1 -1
  19. package/public/layouts/okdb-cube.ok.html +1 -1
  20. package/public/login-app.js +1 -1
  21. package/public/login.html +205 -1
  22. package/public/modules/ok.js +1 -1
  23. package/public/sections/api/index.ok.html +1 -1
  24. package/public/sections/api/parts/api-endpoint.ok.js +1 -1
  25. package/public/sections/auth/index.ok.html +1 -1
  26. package/public/sections/auth/modals/create-token-modal.ok.js +1 -1
  27. package/public/sections/auth/modals/edit-token-modal.ok.js +1 -1
  28. package/public/sections/auth/modals/perm-info-popover.ok.js +1 -1
  29. package/public/sections/auth/parts/token-detail.ok.js +1 -1
  30. package/public/sections/auth/parts/token-list.ok.js +1 -1
  31. package/public/sections/db/index.ok.html +1 -1
  32. package/public/sections/db/modals/add-item-modal.ok.js +1 -1
  33. package/public/sections/db/modals/create-env-modal.ok.js +1 -1
  34. package/public/sections/db/modals/create-fts-modal.ok.js +1 -1
  35. package/public/sections/db/modals/create-index-modal.ok.js +1 -1
  36. package/public/sections/db/modals/create-pipeline-modal.ok.js +1 -1
  37. package/public/sections/db/modals/demo-env-modal.ok.js +1 -1
  38. package/public/sections/db/modals/remove-env-modal.ok.js +1 -1
  39. package/public/sections/db/modals/schema-edit-modal.ok.js +1 -1
  40. package/public/sections/db/parts/db-overview.ok.js +1 -1
  41. package/public/sections/db/parts/db-pipelines-panel.ok.js +1 -1
  42. package/public/sections/db/parts/edit-row.ok.js +1 -1
  43. package/public/sections/db/parts/tm-timeline.ok.js +1 -1
  44. package/public/sections/db/parts/type-changelog.ok.js +1 -1
  45. package/public/sections/db/parts/type-list.ok.js +1 -1
  46. package/public/sections/db/parts/type-pipelines-tab.ok.js +1 -1
  47. package/public/sections/db/parts/type-schema-tab.ok.js +1 -1
  48. package/public/sections/db/parts/type-viewer.ok.js +1 -1
  49. package/public/sections/db/parts/type-violations-tab.ok.js +1 -1
  50. package/public/sections/docs/index.ok.html +1 -1
  51. package/public/sections/embeddings/index.ok.html +1 -1
  52. package/public/sections/embeddings/modals/register-model-modal.ok.js +1 -1
  53. package/public/sections/embeddings/parts/embed-create-panel.ok.js +1 -1
  54. package/public/sections/embeddings/parts/embed-embedder-panel.ok.js +1 -1
  55. package/public/sections/embeddings/parts/embed-engine-declaration-editor.ok.js +1 -1
  56. package/public/sections/embeddings/parts/embed-engine-list.ok.js +1 -1
  57. package/public/sections/embeddings/parts/embed-indexer-panel.ok.js +1 -1
  58. package/public/sections/embeddings/parts/embed-lifecycle-bar.ok.js +1 -1
  59. package/public/sections/embeddings/parts/embed-model-catalog.ok.js +1 -1
  60. package/public/sections/embeddings/parts/embed-overview.ok.js +1 -1
  61. package/public/sections/embeddings/parts/embed-search-panel.ok.js +1 -1
  62. package/public/sections/embeddings/parts/embed-worker-panel.ok.js +1 -1
  63. package/public/sections/embeddings/parts/embeddings-engine-panel.ok.js +1 -1
  64. package/public/sections/embeddings/parts/engines-overview.ok.js +1 -1
  65. package/public/sections/embeddings/parts/pipeline-create-panel.ok.js +1 -1
  66. package/public/sections/engines/engine-panel-shared-style.js +1 -1
  67. package/public/sections/engines/engine-ui-utils.js +1 -1
  68. package/public/sections/engines/index.ok.html +1 -1
  69. package/public/sections/engines/modals/engine-modal.ok.js +1 -1
  70. package/public/sections/engines/parts/engine-declaration-editor.ok.js +1 -1
  71. package/public/sections/engines/parts/engine-lifecycle-actions.ok.js +1 -1
  72. package/public/sections/engines/parts/engine-panel-shell.ok.js +1 -1
  73. package/public/sections/engines/parts/engine-resource-card.ok.js +1 -1
  74. package/public/sections/engines/parts/engine-row-item.ok.js +1 -1
  75. package/public/sections/engines/parts/generic-engine-panel.ok.js +1 -1
  76. package/public/sections/files/index.ok.html +1 -1
  77. package/public/sections/files/parts/files-blob-status.ok.js +1 -1
  78. package/public/sections/files/parts/files-collection-list.ok.js +1 -1
  79. package/public/sections/files/parts/files-collection-panel.ok.js +1 -1
  80. package/public/sections/files/parts/files-file-list.ok.js +1 -1
  81. package/public/sections/files/parts/files-overview.ok.js +1 -1
  82. package/public/sections/files/parts/files-path-browser.ok.js +1 -1
  83. package/public/sections/files/parts/files-upload-panel.ok.js +1 -1
  84. package/public/sections/functions/index.ok.html +1 -1
  85. package/public/sections/functions/modals/function-modal.ok.js +1 -1
  86. package/public/sections/functions/parts/function-detail.ok.js +1 -1
  87. package/public/sections/functions/parts/function-logs.ok.js +1 -1
  88. package/public/sections/functions/parts/function-runner.ok.js +1 -1
  89. package/public/sections/functions/parts/functions-list.ok.js +1 -1
  90. package/public/sections/license/index.ok.html +1 -1
  91. package/public/sections/license/parts/license-panel.ok.js +1 -1
  92. package/public/sections/processors/index.ok.html +1 -1
  93. package/public/sections/queue/index.ok.html +1 -1
  94. package/public/sections/queue/modals/create-bucket-modal.ok.js +1 -1
  95. package/public/sections/queue/modals/edit-bucket-modal.ok.js +1 -1
  96. package/public/sections/queue/modals/edit-job-modal.ok.js +1 -1
  97. package/public/sections/queue/modals/enqueue-job-modal.ok.js +1 -1
  98. package/public/sections/queue/modals/job-type-modal.ok.js +1 -1
  99. package/public/sections/queue/parts/ok-job-form.ok.js +1 -1
  100. package/public/sections/queue/parts/queue-buckets.ok.js +1 -1
  101. package/public/sections/queue/parts/queue-job-types.ok.js +1 -1
  102. package/public/sections/queue/parts/queue-jobs.ok.js +1 -1
  103. package/public/sections/queue/parts/queue-types.ok.js +1 -1
  104. package/public/sections/queue/parts/queue-workers.ok.js +1 -1
  105. package/public/sections/sync/index.ok.html +1 -1
  106. package/public/sections/sync/parts/sync-node-detail.ok.js +1 -1
  107. package/public/sections/sync/parts/sync-retention.ok.js +1 -1
  108. package/public/sections/sync/parts/sync-topology.ok.js +1 -1
  109. package/public/sections/system/index.ok.html +1 -1
  110. package/public/sections/system/modals/data-ops-modal.ok.js +1 -1
  111. package/public/sections/system/parts/system-api-panel.ok.js +1 -1
  112. package/public/sections/system/parts/system-auth-panel.ok.js +1 -1
  113. package/public/sections/system/parts/system-log-history.ok.js +1 -1
  114. package/public/sections/system/parts/system-log.ok.js +1 -1
  115. package/public/sections/system/parts/system-status.ok.js +1 -1
  116. package/public/sections/system/parts/system-sync-panel.ok.js +1 -1
  117. package/public/sections/views/index.ok.html +1 -1
  118. package/public/sections/views/modals/create-view-modal.ok.js +1 -1
  119. package/public/sections/views/parts/view-detail.ok.js +1 -1
  120. package/public/sections/views/parts/views-list.ok.js +1 -1
  121. package/public/sections/views/parts/views-overview.ok.js +1 -1
  122. package/public/setup-app.js +1 -1
  123. package/public/setup.html +189 -1
  124. package/public/stores/auth-store.js +1 -1
  125. package/public/stores/events-store.js +1 -1
  126. package/public/stores/functions-store.js +1 -1
  127. package/public/stores/okdb-store.js +1 -1
  128. package/public/stores/theme-store.js +1 -1
  129. package/public/test-cron-input.html +53 -3
  130. package/public/test-json-input.html +182 -3
  131. package/public/util/permissions.js +1 -1
  132. package/public/util/sift-schema.js +1 -1
  133. package/public/vendor/okjs/ok.esm.min.js +1 -2
  134. package/public/view-models/type-query-vm.js +1 -1
  135. package/okdb-data/default/data.mdb +0 -0
  136. package/okdb-data/default/lock.mdb +0 -0
  137. package/okdb-data/~log/data.mdb +0 -0
  138. package/okdb-data/~log/lock.mdb +0 -0
  139. package/okdb-data/~system/data.mdb +0 -0
  140. package/okdb-data/~system/lock.mdb +0 -0
  141. package/public/images/logo.png +0 -0
  142. package/public/images/logo.svg +0 -333
@@ -1 +1 @@
1
- const _0x3d76ad=_0x4fc1;(function(_0x320332,_0xbc08f7){const _0x33c112=_0x4fc1,_0x211220=_0x320332();while(!![]){try{const _0x352dc7=parseInt(_0x33c112(0x15b))/0x1+-parseInt(_0x33c112(0x132))/0x2+-parseInt(_0x33c112(0x13a))/0x3+parseInt(_0x33c112(0x156))/0x4+-parseInt(_0x33c112(0x15a))/0x5+parseInt(_0x33c112(0x172))/0x6*(parseInt(_0x33c112(0x141))/0x7)+parseInt(_0x33c112(0x16b))/0x8*(parseInt(_0x33c112(0x165))/0x9);if(_0x352dc7===_0xbc08f7)break;else _0x211220['push'](_0x211220['shift']());}catch(_0x1208a3){_0x211220['push'](_0x211220['shift']());}}}(_0x2dfa,0xd57ec));import _0x154ba3 from'@toolkit/elements/ok-icon.ok.js';import _0x506987 from'@toolkit/core/ok-overlay.ok.js';import _0x428b50 from'@toolkit/interaction/ok-flyover.ok.js';function _0x4fc1(_0x4a4f72,_0x1c696e){_0x4a4f72=_0x4a4f72-0x129;const _0x2dfac4=_0x2dfa();let _0x4fc1bb=_0x2dfac4[_0x4a4f72];return _0x4fc1bb;}function _0x2dfa(){const _0x3dff7f=['sort','5598110nlDzzT','25262IxEIzq','name','var(--okdb-warning)','isEnvAllSelected','Token\x20updated','isArray','description','json','token','/auth/permissions','1315404gdTVcW','read','message','onDone','grants','API','32LJQpYn','password','Environment','$ok','passwordStrength','scope','operations','6XztEJQ','shared','write','ADMIN_API','localeCompare','Failed\x20to\x20update\x20token','label','modal','data','keys','catalogLoading','filter','length','catalog','weak','trim','var(--okdb-danger)','peer','selectedPerms','indexOf','result','_fallback','gate','some','Gate','transparent','718692jEsYjp','stringify','godMode','hoveredPerm','var(--okdb-success)','error','envs','Failed','614010fWUjmi','close','strong','destructive','edit-token-modal','permissions','hoveredAnchor','10803513JRnwPY','entries','namespaces','validateForm','Token\x20label\x20is\x20required','routes','env','run','showPassword','PATCH','catalogError','map','application/json','$attr','opOrder','test','hoveredPermOp','.tf-header-fields,.tf-root,edit-token-modal{display:flex;flex-direction:column}.tf-root{gap:0;width:520px;max-width:88vw;position:relative}.tf-header-fields{gap:12px;padding-bottom:16px}.tf-field,.tf-header-row{display:flex;gap:10px}.tf-field{flex-direction:column;gap:4px;min-width:0}.tf-label{font-size:10px;color:var(--okdb-app-fg-muted);text-transform:uppercase;letter-spacing:.07em;font-weight:600}.tf-creds-section{display:flex;flex-direction:column;gap:8px;padding:10px\x2012px;border:1px\x20solid\x20var(--okdb-app-surface);border-radius:6px;background:rgba(0,0,0,.15)}.tf-creds-label{font-size:10px;color:var(--okdb-app-fg-muted);text-transform:uppercase;letter-spacing:.07em;font-weight:600}.tf-creds-hint{font-size:10px;color:var(--okdb-app-fg-subtle);line-height:1.4;margin-top:-4px}.tf-creds-row{display:flex;gap:10px}.tf-pw-wrap{position:relative;display:flex;align-items:center}.tf-pw-wrap\x20.tf-input{padding-right:30px}.tf-pw-eye{position:absolute;right:7px;background:0\x200;border:0;color:var(--okdb-app-fg-subtle);cursor:pointer;font-size:12px;padding:0;line-height:1;user-select:none}.tf-pw-eye:hover,.tf-scope-header:hover\x20.tf-scope-name{color:var(--okdb-accent-muted)}.tf-strength-bar{height:2px;border-radius:1px;background:var(--okdb-app-surface);margin-top:3px;overflow:hidden}.tf-strength-fill{height:100%;border-radius:1px;transition:width\x20.2s,background-color\x20.2s}.tf-strength-text{font-size:9px;margin-top:2px;text-transform:uppercase;letter-spacing:.05em}.tf-input{padding:6px\x208px;border:1px\x20solid\x20var(--okdb-app-surface-2);border-radius:4px;background:0\x200;color:var(--okdb-app-fg-strong);font-size:12px;font-family:monospace;width:100%;box-sizing:border-box}.tf-input:focus{outline:0;border-color:rgba(79,193,255,.4)}.tf-hint{font-size:10px;color:var(--okdb-app-fg-subtle);line-height:1.4}.tf-divider{height:1px;background:var(--okdb-app-surface);margin-bottom:12px}.tf-section{display:flex;flex-direction:column;gap:6px;margin-bottom:10px}.tf-scope-header{display:flex;align-items:center;gap:8px;cursor:pointer;user-select:none;padding:2px\x200}.tf-scope-name{font-size:10px;text-transform:uppercase;letter-spacing:.07em;color:var(--okdb-app-fg-muted);font-weight:600;transition:color\x20.1s}.tf-scope-count{font-size:10px;color:var(--okdb-accent);opacity:.8}.tf-scope-chevron{margin-left:auto;font-size:10px;color:var(--okdb-app-fg-subtle)}.tf-ns-block{display:flex;flex-direction:column;gap:4px;margin-bottom:8px}.tf-ns-row{display:flex;align-items:baseline;gap:8px}.tf-ns-label{font-size:11px;color:var(--okdb-app-fg-subtle);font-family:monospace;flex-shrink:0;cursor:pointer;user-select:none;transition:color\x20.1s;font-weight:600}.tf-ns-label:hover{color:var(--okdb-accent-muted)}.tf-ns-label--on{color:var(--okdb-accent)}.tf-ns-desc{font-size:10px;color:var(--okdb-app-fg-subtle);line-height:1.4}.tf-pills{display:flex;flex-wrap:wrap;gap:4px;padding-left:4px}.tf-pill-wrap{display:inline-flex}.tf-pill-warn{font-size:7px;color:rgba(215,150,60,.85);vertical-align:super;margin-left:1px;line-height:0}.tf-pill--destructive{border-color:rgba(200,140,60,.35)}.tf-pill--destructive:hover{border-color:rgba(200,140,60,.6)}.tf-pill{display:inline-flex;align-items:center;padding:2px\x208px;border-radius:4px;font-size:11px;font-family:monospace;border:1px\x20solid\x20var(--okdb-app-surface-2);color:var(--okdb-app-fg-subtle);cursor:pointer;user-select:none;transition:background\x20.1s,border-color\x20.1s,color\x20.1s;white-space:nowrap}.tf-pill:hover{border-color:var(--okdb-app-border);color:var(--okdb-accent-muted)}.tf-pill--on{background:rgba(79,193,255,.1);border-color:rgba(79,193,255,.35);color:var(--okdb-accent)}.tf-pill--on:hover{background:rgba(79,193,255,.15)}.tf-pill--full{border-color:rgba(251,191,36,.2);color:#5a4a20}.tf-pill--full-on,.tf-pill--full:hover{border-color:rgba(251,191,36,.4);color:var(--okdb-warning-text)}.tf-pill--full-on{background:rgba(251,191,36,.1)}.tf-pill--full-on:hover{background:rgba(251,191,36,.16)}.tf-pill--add{border-style:dashed;border-color:var(--okdb-app-surface-2);color:var(--okdb-app-fg-subtle)}.tf-pill--add:hover{border-color:var(--okdb-app-border);color:var(--okdb-accent-muted);border-style:solid}.tf-pill--wild{border-color:rgba(251,191,36,.2);color:#5a4a20;font-weight:700}.tf-pill--wild-on,.tf-pill--wild:hover{border-color:rgba(251,191,36,.4);color:var(--okdb-warning-text)}.tf-pill--wild-on{background:rgba(251,191,36,.1);font-weight:700}.tf-pill--wild-on:hover{background:rgba(251,191,36,.16)}.tf-pill--wild-inherited{border-style:dashed;border-color:rgba(251,191,36,.45);color:rgba(251,191,36,.6);background:rgba(251,191,36,.05);font-weight:700}.tf-pill--wild-inherited:hover{border-color:rgba(251,191,36,.65);color:rgba(251,191,36,.8);background:rgba(251,191,36,.09)}.tf-pill--inherited{border-style:dashed;border-color:rgba(79,193,255,.5);color:rgba(79,193,255,.65);background:rgba(79,193,255,.06)}.tf-pill--inherited:hover{border-color:rgba(79,193,255,.7);color:rgba(79,193,255,.85);background:rgba(79,193,255,.1)}.tf-env-row{display:flex;flex-direction:column;gap:6px;padding:8px\x200\x2010px;border-top:1px\x20solid\x20var(--okdb-app-bg)}.tf-env-row-header{display:flex;align-items:center;justify-content:space-between}.tf-env-name{font-size:11px;font-weight:600;color:var(--okdb-app-fg-muted);font-family:monospace}.tf-env-all,.tf-env-remove{font-size:10px;color:var(--okdb-app-fg-subtle);cursor:pointer;user-select:none;padding:1px\x204px;transition:color\x20.1s}.tf-env-remove:hover{color:var(--okdb-danger)}.tf-env-all:hover{color:var(--okdb-accent-muted)}.tf-env-all--on{color:var(--okdb-warning-text)}.tf-env-all--on:hover{color:var(--okdb-warning)}.tf-error{font-size:11px;color:var(--okdb-danger);padding:6px\x200\x200}.tf-actions{display:flex;gap:8px;justify-content:flex-end;padding-top:14px;margin-top:4px;border-top:1px\x20solid\x20var(--okdb-app-surface)}.tf-btn{padding:5px\x2012px;border-radius:5px;font-size:12px;border:1px\x20solid;background:0\x200;cursor:pointer;transition:background\x20.12s,color\x20.12s}.tf-btn:disabled{opacity:.4;cursor:not-allowed}.tf-btn--primary{border-color:var(--okdb-app-border);color:var(--okdb-accent-muted)}.tf-btn--primary:not(:disabled):hover{background:var(--okdb-app-surface);border-color:var(--okdb-app-border);color:var(--okdb-sky)}.tf-btn--secondary{border-color:var(--okdb-app-surface-2);color:var(--okdb-app-fg-subtle)}.tf-btn--secondary:hover{background:var(--okdb-app-bg)}.tf-pip{min-width:260px;max-width:460px;background:var(--okdb-app-bg-deep);border:1px\x20solid\x20var(--okdb-app-surface-2);border-radius:5px;padding:8px\x2010px;box-shadow:0\x204px\x2018px\x20rgba(0,0,0,.75);pointer-events:none;white-space:normal;font-size:11px}.tf-pip-perm{font-family:monospace;font-size:10px;color:var(--okdb-accent);margin-bottom:3px}.tf-pip-summary{color:var(--okdb-accent-muted);line-height:1.4;margin-bottom:5px}.tf-pip-routes-hd{font-size:9px;color:var(--okdb-app-fg-subtle);text-transform:uppercase;letter-spacing:.06em;margin-bottom:3px}.tf-pip-route{display:flex;align-items:baseline;gap:5px;padding:1px\x200}.tf-pip-method{font-family:monospace;font-size:9px;color:var(--okdb-accent);width:34px;flex-shrink:0}.tf-pip-path{font-family:monospace;font-size:10px;color:var(--okdb-accent-muted);word-break:break-all}.tf-pip-bd,.tf-pip-lr{font-size:8px;border-radius:2px;padding:0\x203px;flex-shrink:0}.tf-pip-bd{color:var(--okdb-danger);background:rgba(180,50,40,.15)}.tf-pip-lr{color:var(--okdb-app-fg-muted);background:rgba(100,100,100,.12)}.tf-pip-route-desc{font-size:9px;color:var(--okdb-app-fg-subtle);padding-left:39px;margin-bottom:1px}.tf-pip-gate,.tf-pip-implied{color:var(--okdb-app-fg-subtle);font-size:10px}.tf-pip-implied{margin-top:5px;font-size:9px;font-family:monospace}','toast','/auth/tokens/','expiresAt','1619476vidmWH','collapsedScopes','query'];_0x2dfa=function(){return _0x3dff7f;};return _0x2dfa();}export default{'tag':_0x3d76ad(0x13e),'dependencies':[_0x506987,_0x154ba3,_0x428b50],'attr':{'modal':{},'token':{},'onDone':{}},'context'(_0x5ba532){const _0x3cc6ba=_0x3d76ad,_0x1752d0=_0x5ba532[_0x3cc6ba(0x14e)][_0x3cc6ba(0x163)]?.[_0x3cc6ba(0x13f)]||[],_0x4319fe=_0x1752d0['includes']('*'),_0x1d3f65={};if(!_0x4319fe){for(const _0x2abb3a of _0x1752d0)_0x1d3f65[_0x2abb3a]=!0x0;}const _0xfb9b7={},_0x291817=_0x5ba532[_0x3cc6ba(0x14e)][_0x3cc6ba(0x163)]?.['grants']||{};for(const [_0x275850,_0x313722]of Object[_0x3cc6ba(0x142)](_0x291817)){_0xfb9b7[_0x275850]={};for(const _0x200afd of Array[_0x3cc6ba(0x160)](_0x313722)?_0x313722:[])_0xfb9b7[_0x275850][_0x200afd]=!0x0;}return{'busy':!0x1,'error':null,'label':_0x5ba532[_0x3cc6ba(0x14e)]['token']?.[_0x3cc6ba(0x178)]||'','name':_0x5ba532[_0x3cc6ba(0x14e)][_0x3cc6ba(0x163)]?.['name']||'','password':'','showPassword':!0x1,'expiresAt':_0x5ba532[_0x3cc6ba(0x14e)]['token']?.[_0x3cc6ba(0x155)]?new Date(_0x5ba532[_0x3cc6ba(0x14e)][_0x3cc6ba(0x163)][_0x3cc6ba(0x155)])['toISOString']()['slice'](0x0,0x10):'','catalog':null,'catalogError':!0x1,'catalogLoading':!0x1,'godMode':_0x4319fe,'selectedPerms':_0x1d3f65,'grants':_0xfb9b7,'collapsedScopes':{},'hoveredPerm':null,'hoveredPermOp':null,'hoveredAnchor':null,'setHover'(_0x1e42df,_0xc4e5a,_0x3adc92){const _0x393141=_0x3cc6ba;this['hoveredPerm']=_0xc4e5a,this[_0x393141(0x151)]=_0x3adc92,this[_0x393141(0x140)]=_0x1e42df['currentTarget'];},'clearHover'(){const _0x13d2bd=_0x3cc6ba;this[_0x13d2bd(0x135)]=null,this[_0x13d2bd(0x151)]=null,this[_0x13d2bd(0x140)]=null;},async 'loadCatalog'(){const _0x52e5e0=_0x3cc6ba;this[_0x52e5e0(0x17c)]=!0x0;try{const _0xf914f5=await fetch(__ENV__[_0x52e5e0(0x175)]+_0x52e5e0(0x164));if(!_0xf914f5['ok'])throw new Error(_0x52e5e0(0x139));const _0x425902=await _0xf914f5[_0x52e5e0(0x162)]();this[_0x52e5e0(0x17f)]=_0x425902[_0x52e5e0(0x17a)]??_0x425902[_0x52e5e0(0x12c)];}catch{this['catalogError']=!0x0;}finally{this['catalogLoading']=!0x1;}},'togglePerm'(_0xfe2012,_0x5a51e0,_0x16b2b7){const _0x38d065=_0x3cc6ba;if(this[_0x38d065(0x134)])return;const _0x1e7b41=_0xfe2012+':*';if(this[_0x38d065(0x12a)][_0x1e7b41]){const _0x98922d={...this[_0x38d065(0x12a)]};delete _0x98922d[_0x1e7b41];for(const _0x18f762 of _0x16b2b7)_0x18f762!==_0x5a51e0&&(_0x98922d[_0xfe2012+':'+_0x18f762]=!0x0);this[_0x38d065(0x12a)]=_0x98922d;}else this['selectedPerms']={...this[_0x38d065(0x12a)],[_0xfe2012+':'+_0x5a51e0]:!this[_0x38d065(0x12a)][_0xfe2012+':'+_0x5a51e0]};},'toggleNamespace'(_0x4b0cd5,_0x2602be){const _0x300a4f=_0x3cc6ba;if(this[_0x300a4f(0x134)])return;const _0x779a1=_0x4b0cd5+':*',_0x262458={...this['selectedPerms']};if(_0x262458[_0x779a1])delete _0x262458[_0x779a1];else{for(const _0x30e328 of _0x2602be)delete _0x262458[_0x4b0cd5+':'+_0x30e328];_0x262458[_0x779a1]=!0x0;}this['selectedPerms']=_0x262458;},'toggleGodMode'(){const _0x124bce=_0x3cc6ba;this[_0x124bce(0x134)]=!this['godMode'],this[_0x124bce(0x134)]&&(this[_0x124bce(0x12a)]={});},'toggleScope'(_0x2916e6){const _0x59ad28=_0x3cc6ba;this[_0x59ad28(0x157)]={...this[_0x59ad28(0x157)],[_0x2916e6]:!this['collapsedScopes'][_0x2916e6]};},'isCollapsed'(_0x310e84){const _0x41bbd0=_0x3cc6ba;return!!this[_0x41bbd0(0x157)][_0x310e84];},'scopeSelectionCount'(_0x2bc7b3){const _0x15d048=_0x3cc6ba;let _0x1bb5f4=0x0,_0x11b938=0x0;for(const _0x24d938 of _0x2bc7b3[_0x15d048(0x143)])for(const _0x501177 of _0x24d938[_0x15d048(0x171)])_0x11b938++,(this['selectedPerms'][_0x24d938['ns']+':'+_0x501177]||this[_0x15d048(0x12a)][_0x24d938['ns']+':*'])&&_0x1bb5f4++;return _0x1bb5f4>0x0?_0x1bb5f4+'/'+_0x11b938:'';},'addGrantEnv'(_0x3ab918){const _0x5a9655=_0x3cc6ba;_0x3ab918&&!this['grants'][_0x3ab918]&&(this[_0x5a9655(0x169)]={...this[_0x5a9655(0x169)],[_0x3ab918]:{}});},'removeGrantEnv'(_0x158ce3){const _0x437eb8=_0x3cc6ba,_0x2c8874={...this['grants']};delete _0x2c8874[_0x158ce3],this[_0x437eb8(0x169)]=_0x2c8874;},'availableGrantEnvs'(){const _0xbdd425=_0x3cc6ba;return this[_0xbdd425(0x17f)]?.[_0xbdd425(0x138)]?this[_0xbdd425(0x17f)][_0xbdd425(0x138)]['filter'](_0xcfdc4f=>!this['grants'][_0xcfdc4f]):[];},'getPermSections'(){const _0x439b94=_0x3cc6ba;if(!this[_0x439b94(0x17f)]?.[_0x439b94(0x143)])return[];const _0x4f104c=this['catalog'][_0x439b94(0x14f)]||['read','query',_0x439b94(0x148),_0x439b94(0x174),'work','peer'];return[{'scope':_0x439b94(0x147),'label':_0x439b94(0x16d)},{'scope':'system','label':'System'},{'scope':_0x439b94(0x12e),'label':_0x439b94(0x130)}][_0x439b94(0x14c)](_0x5a3db9=>({'scope':_0x5a3db9[_0x439b94(0x170)],'label':_0x5a3db9[_0x439b94(0x178)],'namespaces':Object[_0x439b94(0x142)](this[_0x439b94(0x17f)][_0x439b94(0x143)])[_0x439b94(0x17d)](([,_0x3477e6])=>_0x3477e6[_0x439b94(0x170)]===_0x5a3db9['scope'])[_0x439b94(0x14c)](([_0x4cecca,_0x3ad58a])=>({'ns':_0x4cecca,'nsLabel':_0x3ad58a['label'],'nsDescription':_0x3ad58a[_0x439b94(0x161)],'operations':Object[_0x439b94(0x17b)](_0x3ad58a[_0x439b94(0x171)])[_0x439b94(0x159)]((_0x340e58,_0x41193f)=>{const _0x3328a8=_0x439b94,_0x2bc1a4=_0x4f104c[_0x3328a8(0x12b)](_0x340e58),_0x28651f=_0x4f104c[_0x3328a8(0x12b)](_0x41193f);return-0x1===_0x2bc1a4&&-0x1===_0x28651f?_0x340e58[_0x3328a8(0x176)](_0x41193f):-0x1===_0x2bc1a4?0x1:-0x1===_0x28651f?-0x1:_0x2bc1a4-_0x28651f;}),'operationMeta':_0x3ad58a[_0x439b94(0x171)]}))}))[_0x439b94(0x17d)](_0x5b221a=>_0x5b221a[_0x439b94(0x143)][_0x439b94(0x17e)]>0x0);},'getPermOps'(_0x4d9007,_0x3efba4,_0x561dd4){const _0x4298d5=_0x3cc6ba;return _0x3efba4[_0x4298d5(0x14c)](_0x2afdf3=>{const _0xca2703=_0x4298d5,_0x420e06=_0x561dd4?.[_0x2afdf3]||{},_0x4e7d5d=_0x420e06[_0xca2703(0x146)]||[];return{'ns':_0x4d9007,'op':_0x2afdf3,'perm':_0x4d9007+':'+_0x2afdf3,'summary':_0x420e06['summary']||'','routes':_0x4e7d5d,'hasDestructive':_0x4e7d5d[_0xca2703(0x12f)](_0x3b699d=>_0x3b699d[_0xca2703(0x13d)]),'checked':!!this['selectedPerms'][_0x4d9007+':'+_0x2afdf3]||!!this[_0xca2703(0x12a)][_0x4d9007+':*']};});},'getImpliedBy'(_0x284dd3){const _0x5d8c15=_0x3cc6ba,_0x12d218=this[_0x5d8c15(0x17f)]?.['implies']||{};return Object[_0x5d8c15(0x142)](_0x12d218)[_0x5d8c15(0x17d)](([,_0x5798cc])=>_0x5798cc['includes'](_0x284dd3))[_0x5d8c15(0x14c)](([_0xc9b01b])=>_0xc9b01b);},'isNsAllSelected'(_0x19ecd6){const _0x31a45c=_0x3cc6ba;return!!this[_0x31a45c(0x12a)][_0x19ecd6+':*'];},'isEnvAllSelected'(_0x21362b){const _0x3e51e4=_0x3cc6ba;return!!this[_0x3e51e4(0x169)][_0x21362b]?.['*'];},'isEnvWildInherited'(_0x3c3d50){const _0x481d9e=_0x3cc6ba;return!this[_0x481d9e(0x15e)](_0x3c3d50)&&(this['godMode']||!!this['selectedPerms']['*']);},'isNsAllSelectedForGrant'(_0x3f9e1b,_0x465b1c){const _0x4e5a14=_0x3cc6ba;return!!this[_0x4e5a14(0x169)][_0x3f9e1b]?.['*']||!!this[_0x4e5a14(0x169)][_0x3f9e1b]?.[_0x465b1c+':*'];},'isNsWildInheritedForGrant'(_0x2dda9f,_0xe6c2cc){const _0x499945=_0x3cc6ba;return!this['isNsAllSelectedForGrant'](_0x2dda9f,_0xe6c2cc)&&(this['godMode']||!!this[_0x499945(0x12a)]['*']||!!this[_0x499945(0x12a)][_0xe6c2cc+':*']);},'toggleGrantPerm'(_0x4388f5,_0x3858e0,_0x55265f,_0x2052f6){const _0x5a310f=_0x3cc6ba,_0x50ee39=_0x3858e0+':'+_0x55265f,_0x2c883d=_0x3858e0+':*',_0x2a46b6={...this[_0x5a310f(0x169)][_0x4388f5]||{}};if(_0x2a46b6['*'])delete _0x2a46b6['*'];else{if(_0x2a46b6[_0x2c883d]){delete _0x2a46b6[_0x2c883d];for(const _0x1a230c of _0x2052f6)_0x1a230c!==_0x55265f&&(_0x2a46b6[_0x3858e0+':'+_0x1a230c]=!0x0);}else _0x2a46b6[_0x50ee39]=!_0x2a46b6[_0x50ee39];}this[_0x5a310f(0x169)]={...this['grants'],[_0x4388f5]:_0x2a46b6};},'toggleGrantNamespace'(_0x969c5e,_0x53b663,_0x1fa6b0){const _0x16a080=_0x53b663+':*',_0x32bdb8={...this['grants'][_0x969c5e]||{}};if(_0x32bdb8['*'])delete _0x32bdb8['*'];else{if(_0x32bdb8[_0x16a080])delete _0x32bdb8[_0x16a080];else{for(const _0x5517d5 of _0x1fa6b0)delete _0x32bdb8[_0x5517d5['perm']];_0x32bdb8[_0x16a080]=!0x0;}}this['grants']={...this['grants'],[_0x969c5e]:_0x32bdb8};},'toggleGrantAllPerms'(_0x246968){const _0xd284e7=_0x3cc6ba,_0x231f04=this[_0xd284e7(0x169)][_0x246968]||{};if(_0x231f04['*']){const _0x1c800b={..._0x231f04};delete _0x1c800b['*'],this[_0xd284e7(0x169)]={...this['grants'],[_0x246968]:_0x1c800b};}else this[_0xd284e7(0x169)]={...this[_0xd284e7(0x169)],[_0x246968]:{'*':!0x0}};},'getGrantEntries'(){const _0xbd7a19=_0x3cc6ba;if(!this[_0xbd7a19(0x17f)]?.['namespaces'])return[];const _0x31c409=this[_0xbd7a19(0x17f)][_0xbd7a19(0x14f)]||[_0xbd7a19(0x166),_0xbd7a19(0x158),_0xbd7a19(0x148),_0xbd7a19(0x174),'work',_0xbd7a19(0x129)],_0x203e1c=Object[_0xbd7a19(0x142)](this[_0xbd7a19(0x17f)]['namespaces'])[_0xbd7a19(0x17d)](([,_0x328623])=>_0xbd7a19(0x147)===_0x328623['scope'])[_0xbd7a19(0x14c)](([_0x4d5fc9,_0x4cd487])=>({'ns':_0x4d5fc9,'operations':Object[_0xbd7a19(0x17b)](_0x4cd487['operations'])[_0xbd7a19(0x159)]((_0x5e6a1b,_0x562bc1)=>{const _0x53386e=_0xbd7a19,_0x230f88=_0x31c409[_0x53386e(0x12b)](_0x5e6a1b),_0x587fc9=_0x31c409[_0x53386e(0x12b)](_0x562bc1);return-0x1===_0x230f88&&-0x1===_0x587fc9?_0x5e6a1b[_0x53386e(0x176)](_0x562bc1):-0x1===_0x230f88?0x1:-0x1===_0x587fc9?-0x1:_0x230f88-_0x587fc9;})})),_0x1e8564=this[_0xbd7a19(0x12a)],_0x508284=this['godMode'];return Object['entries'](this[_0xbd7a19(0x169)])[_0xbd7a19(0x14c)](([_0x271a7e,_0x5e392f])=>({'env':_0x271a7e,'globalCoverAll':_0x508284||!!_0x1e8564['*'],'nGroups':_0x203e1c['map'](({ns:_0x18303a,operations:_0x310706})=>({'ns':_0x18303a,'ops':_0x310706[_0xbd7a19(0x14c)](_0x109b2c=>{const _0xc92214=_0xbd7a19,_0x26081b=_0x18303a+':'+_0x109b2c,_0x339838=!!_0x5e392f[_0x26081b]||!!_0x5e392f[_0x18303a+':*']||!!_0x5e392f['*'],_0x1bb2da=!_0x339838&&(_0x508284||!!_0x1e8564['*']||!!_0x1e8564[_0x18303a+':*']||!!_0x1e8564[_0x26081b]),_0x3403a8=this[_0xc92214(0x17f)][_0xc92214(0x143)][_0x18303a]?.['operations']?.[_0x109b2c]||{};return{'perm':_0x26081b,'op':_0x109b2c,'summary':_0x3403a8['summary']||'','routes':_0x3403a8[_0xc92214(0x146)]||[],'hasDestructive':(_0x3403a8[_0xc92214(0x146)]||[])[_0xc92214(0x12f)](_0x5ca1f1=>_0x5ca1f1[_0xc92214(0x13d)]),'checked':_0x339838,'inherited':_0x1bb2da};})}))}));},'validateForm'(){const _0x431a54=_0x3cc6ba;if(!this[_0x431a54(0x178)][_0x431a54(0x181)]())throw new Error(_0x431a54(0x145));return!0x0;},async 'save'(){const _0x29fdb8=_0x3cc6ba;this['error']=null;try{this[_0x29fdb8(0x144)](),this['busy']=!0x0;const _0x3c315d={'label':this[_0x29fdb8(0x178)][_0x29fdb8(0x181)]()};if(this[_0x29fdb8(0x155)]?_0x3c315d['expiresAt']=new Date(this[_0x29fdb8(0x155)])['getTime']():_0x3c315d[_0x29fdb8(0x155)]=null,this[_0x29fdb8(0x134)])_0x3c315d[_0x29fdb8(0x13f)]=['*'];else{if(this[_0x29fdb8(0x14b)]&&void 0x0!==this[_0x29fdb8(0x12a)][_0x29fdb8(0x12d)]){const _0x2da954=String(this[_0x29fdb8(0x12a)][_0x29fdb8(0x12d)]||'')['split'](',')['map'](_0x4ad967=>_0x4ad967[_0x29fdb8(0x181)]())[_0x29fdb8(0x17d)](_0x20e00e=>_0x20e00e);_0x2da954['length']&&(_0x3c315d[_0x29fdb8(0x13f)]=_0x2da954);}else{const _0x4624ff=Object[_0x29fdb8(0x142)](this[_0x29fdb8(0x12a)])[_0x29fdb8(0x17d)](([_0x42bc0a,_0x17a9ef])=>_0x17a9ef&&_0x29fdb8(0x12d)!==_0x42bc0a)[_0x29fdb8(0x14c)](([_0x49e6e2])=>_0x49e6e2);_0x4624ff[_0x29fdb8(0x17e)]&&(_0x3c315d[_0x29fdb8(0x13f)]=_0x4624ff);}}const _0x1bb69f={};for(const [_0x112fc4,_0x5d9132]of Object[_0x29fdb8(0x142)](this[_0x29fdb8(0x169)])){const _0x449a63=Object[_0x29fdb8(0x142)](_0x5d9132)['filter'](([,_0x1f5ffa])=>_0x1f5ffa)['map'](([_0x3db89a])=>_0x3db89a);_0x449a63['length']&&(_0x1bb69f[_0x112fc4]=_0x449a63);}Object['keys'](_0x1bb69f)['length']&&(_0x3c315d['grants']=_0x1bb69f),this[_0x29fdb8(0x15c)]['trim']()&&(_0x3c315d[_0x29fdb8(0x15c)]=this[_0x29fdb8(0x15c)][_0x29fdb8(0x181)](),this[_0x29fdb8(0x16c)]&&(_0x3c315d['password']=this[_0x29fdb8(0x16c)]));const _0x251b25=await fetch(__ENV__[_0x29fdb8(0x16a)]+_0x29fdb8(0x154)+encodeURIComponent(_0x5ba532[_0x29fdb8(0x14e)]['token']['id']),{'method':_0x29fdb8(0x14a),'headers':{'Content-Type':_0x29fdb8(0x14d)},'body':JSON[_0x29fdb8(0x133)](_0x3c315d)});if(!_0x251b25['ok']){const _0x31f860=await _0x251b25[_0x29fdb8(0x162)]();throw new Error(_0x31f860?.[_0x29fdb8(0x137)]?.[_0x29fdb8(0x167)]||_0x29fdb8(0x177));}_0x5ba532[_0x29fdb8(0x16e)][_0x29fdb8(0x173)]?.[_0x29fdb8(0x153)]?.['success']?.(_0x29fdb8(0x15f)),await _0x5ba532[_0x29fdb8(0x14e)][_0x29fdb8(0x179)][_0x29fdb8(0x13b)](),await _0x5ba532['$attr'][_0x29fdb8(0x168)]?.(_0x5ba532[_0x29fdb8(0x14e)][_0x29fdb8(0x163)]['id']);}catch(_0x5e5c14){this[_0x29fdb8(0x137)]=_0x5e5c14?.[_0x29fdb8(0x167)]||String(_0x5e5c14),_0x5ba532[_0x29fdb8(0x16e)]['shared']?.[_0x29fdb8(0x153)]?.[_0x29fdb8(0x137)]?.(this[_0x29fdb8(0x137)]);}finally{this['busy']=!0x1;}},'cancel'(){const _0x3d7175=_0x3cc6ba;_0x5ba532['$attr'][_0x3d7175(0x179)][_0x3d7175(0x13b)]();},'passwordStrength'(_0x3436a3){const _0x39938e=_0x3cc6ba;if(!_0x3436a3)return 0x0;let _0x3a237c=0x0;return _0x3436a3[_0x39938e(0x17e)]>=0x8&&_0x3a237c++,_0x3436a3[_0x39938e(0x17e)]>=0xe&&_0x3a237c++,/[A-Z]/['test'](_0x3436a3)&&_0x3a237c++,/[0-9]/[_0x39938e(0x150)](_0x3436a3)&&_0x3a237c++,/[^A-Za-z0-9]/['test'](_0x3436a3)&&_0x3a237c++,_0x3a237c;},'passwordStrengthLabel'(_0x3ad2df){const _0x5577c5=_0x3cc6ba,_0x451dc0=this[_0x5577c5(0x16f)](_0x3ad2df);return _0x3ad2df?_0x451dc0<=0x1?_0x5577c5(0x180):_0x451dc0<=0x3?'fair':_0x5577c5(0x13c):'';},'passwordStrengthColor'(_0x4c2593){const _0x243960=_0x3cc6ba,_0x31a596=this[_0x243960(0x16f)](_0x4c2593);return _0x4c2593?_0x31a596<=0x1?_0x243960(0x182):_0x31a596<=0x3?_0x243960(0x15d):_0x243960(0x136):_0x243960(0x131);},'toggleShowPassword'(){const _0x7af312=_0x3cc6ba;this[_0x7af312(0x149)]=!this[_0x7af312(0x149)];}};},'mount'(_0x19d846){this['loadCatalog']();},'style':_0x3d76ad(0x152),'template':'<div\x20class=\x22tf-root\x22><if\x20:=\x22busy\x22><ok-overlay><div\x20class=\x22loader-center\x22><ok-icon\x20name=\x22loader\x22\x20class=\x22spin\x22\x20style=\x22width:28px;height:28px;\x22/></div></ok-overlay></if><div\x20class=\x22tf-header-fields\x22><div\x20class=\x22tf-header-row\x22><div\x20class=\x22tf-field\x22\x20style=\x22flex:2;\x22><span\x20class=\x22tf-label\x22>Label</span>\x20<input\x20class=\x22tf-input\x22\x20type=\x22text\x22\x20placeholder=\x22e.g.,\x20API\x20Client\x22\x20:value=\x22label\x22\x20@input=\x22label\x20=\x20$el.value\x22\x20:disabled=\x22busy\x22></div><div\x20class=\x22tf-field\x22\x20style=\x22flex:1.5;\x22><span\x20class=\x22tf-label\x22>Expires\x20<span\x20style=\x22opacity:.4;\x22>(optional)</span></span>\x20<input\x20class=\x22tf-input\x22\x20type=\x22datetime-local\x22\x20:value=\x22expiresAt\x22\x20@input=\x22expiresAt\x20=\x20$el.value\x22\x20:disabled=\x22busy\x22></div></div><div\x20class=\x22tf-creds-section\x22><div><div\x20class=\x22tf-creds-label\x22>Login\x20credentials\x20<span\x20style=\x22opacity:.4;\x20text-transform:none;\x20font-weight:400;\x20letter-spacing:0;\x22>(optional)</span></div><div\x20class=\x22tf-creds-hint\x22>If\x20set,\x20this\x20token\x20can\x20also\x20be\x20used\x20via\x20username\x20+\x20password\x20authentication.</div></div><div\x20class=\x22tf-creds-row\x22><div\x20class=\x22tf-field\x22\x20style=\x22flex:1;\x22><span\x20class=\x22tf-label\x22>Username</span>\x20<input\x20class=\x22tf-input\x22\x20type=\x22text\x22\x20placeholder=\x22leave\x20blank\x20for\x20token-only\x22\x20:value=\x22name\x22\x20@input=\x22name\x20=\x20$el.value\x22\x20:disabled=\x22busy\x22\x20autocomplete=\x22off\x22></div><div\x20class=\x22tf-field\x22\x20style=\x22flex:1;\x22><span\x20class=\x22tf-label\x22>Password\x20<span\x20style=\x22opacity:.4;\x22>(new)</span></span><div\x20class=\x22tf-pw-wrap\x22><input\x20class=\x22tf-input\x22\x20:type=\x22showPassword\x20?\x20\x27text\x27\x20:\x20\x27password\x27\x22\x20placeholder=\x22leave\x20blank\x20to\x20keep\x22\x20:value=\x22password\x22\x20@input=\x22password\x20=\x20$el.value\x22\x20:disabled=\x22busy\x20||\x20!name\x22\x20autocomplete=\x22new-password\x22>\x20<button\x20class=\x22tf-pw-eye\x22\x20@click=\x22toggleShowPassword()\x22\x20type=\x22button\x22\x20tabindex=\x22-1\x22>{{\x20showPassword\x20?\x20\x27🙈\x27\x20:\x20\x27👁\x27\x20}}</button></div><if\x20:=\x22password\x22><div\x20class=\x22tf-strength-bar\x22><div\x20class=\x22tf-strength-fill\x22\x20:style=\x22\x27width:\x27\x20+\x20(passwordStrength(password)/5*100)\x20+\x20\x27%;\x20background:\x27\x20+\x20passwordStrengthColor(password)\x22/></div><div\x20class=\x22tf-strength-text\x22\x20:style=\x22\x27color:\x27\x20+\x20passwordStrengthColor(password)\x22>{{\x20passwordStrengthLabel(password)\x20}}</div></if></div></div></div></div><div\x20class=\x22tf-divider\x22/><if\x20:=\x22catalogLoading\x22><div\x20class=\x22tf-hint\x22\x20style=\x22padding-bottom:12px;\x22>Loading\x20permissions…</div></if><if\x20:=\x22catalogError\x20&&\x20!catalogLoading\x22><div\x20class=\x22tf-section\x22><span\x20class=\x22tf-label\x22>Permissions\x20<span\x20style=\x22color:var(--okdb-danger);\x22>(fallback)</span></span>\x20<input\x20class=\x22tf-input\x22\x20type=\x22text\x22\x20placeholder=\x22data:read,\x20data:write\x22\x20:value=\x22selectedPerms._fallback\x20||\x20\x27\x27\x22\x20@input=\x22selectedPerms\x20=\x20{\x20_fallback:\x20$el.value\x20}\x22\x20:disabled=\x22busy\x22>\x20<span\x20class=\x22tf-hint\x22>Comma-separated\x20permission\x20strings</span></div></if><if\x20:=\x22catalog\x20&&\x20!catalogError\x20&&\x20!catalogLoading\x22><div\x20class=\x22tf-section\x22\x20style=\x22gap:4px;\x22><div\x20:class=\x22[\x27tf-pill\x27,\x20\x27tf-pill--full\x27,\x20godMode\x20?\x20\x27tf-pill--full-on\x27\x20:\x20\x27\x27]\x22\x20@click=\x22toggleGodMode()\x22\x20style=\x22width:fit-content;\x22>★\x20&nbsp;Full\x20access\x20—\x20all\x20permissions</div></div><if\x20:=\x22!godMode\x22><each\x20:of=\x22getPermSections()\x22\x20let:item=\x22section\x22><div\x20class=\x22tf-section\x22><div\x20class=\x22tf-scope-header\x22\x20@click=\x22toggleScope(section.scope)\x22><span\x20class=\x22tf-scope-name\x22>{{\x20section.label\x20}}</span><if\x20:=\x22scopeSelectionCount(section)\x22><span\x20class=\x22tf-scope-count\x22>{{\x20scopeSelectionCount(section)\x20}}</span></if><span\x20class=\x22tf-scope-chevron\x22>{{\x20isCollapsed(section.scope)\x20?\x20\x27▸\x27\x20:\x20\x27▾\x27\x20}}</span></div><if\x20:=\x22!isCollapsed(section.scope)\x22><each\x20:of=\x22section.namespaces\x22\x20let:item=\x22nsEntry\x22><div\x20class=\x22tf-ns-block\x22><div\x20class=\x22tf-ns-row\x22><span\x20:class=\x22[\x27tf-ns-label\x27,\x20isNsAllSelected(nsEntry.ns)\x20?\x20\x27tf-ns-label--on\x27\x20:\x20\x27\x27]\x22\x20@click=\x22toggleNamespace(nsEntry.ns,\x20nsEntry.operations)\x22\x20title=\x22Toggle\x20all\x22>{{\x20nsEntry.nsLabel\x20||\x20nsEntry.ns\x20}}</span><if\x20:=\x22nsEntry.nsDescription\x22><span\x20class=\x22tf-ns-desc\x22>{{\x20nsEntry.nsDescription\x20}}</span></if></div><div\x20class=\x22tf-pills\x22><span\x20:class=\x22[\x27tf-pill\x27,\x20\x27tf-pill--wild\x27,\x20isNsAllSelected(nsEntry.ns)\x20?\x20\x27tf-pill--wild-on\x27\x20:\x20\x27\x27]\x22\x20@click=\x22toggleNamespace(nsEntry.ns,\x20nsEntry.operations)\x22\x20title=\x22ns:*\x20—\x20toggle\x20all\x22>*</span><each\x20:of=\x22getPermOps(nsEntry.ns,\x20nsEntry.operations,\x20nsEntry.operationMeta)\x22\x20let:item=\x22permOp\x22><span\x20class=\x22tf-pill-wrap\x22\x20@mouseenter=\x22setHover($event,\x20permOp.perm,\x20permOp)\x22\x20@mouseleave=\x22clearHover()\x22><span\x20:class=\x22[\x27tf-pill\x27,\x20permOp.checked\x20?\x20\x27tf-pill--on\x27\x20:\x20\x27\x27,\x20permOp.hasDestructive\x20?\x20\x27tf-pill--destructive\x27\x20:\x20\x27\x27]\x22\x20@click=\x22togglePerm(permOp.ns,\x20permOp.op,\x20nsEntry.operations)\x22>{{\x20permOp.op\x20}}<if\x20:=\x22permOp.hasDestructive\x22><span\x20class=\x22tf-pill-warn\x22>⚠</span></if></span></span></each></div></div></each></if></div></each><if\x20:=\x22catalog.envs\x20&&\x20catalog.envs.length\x20>\x200\x22><div\x20class=\x22tf-divider\x22/><div\x20class=\x22tf-section\x22\x20style=\x22gap:8px;\x22><div\x20class=\x22tf-scope-header\x22\x20style=\x22cursor:default;\x20pointer-events:none;\x22><span\x20class=\x22tf-scope-name\x22>Per-env\x20grants</span>\x20<span\x20class=\x22tf-hint\x22\x20style=\x22margin-left:6px;\x22>extra\x20permissions\x20for\x20a\x20specific\x20environment</span></div><if\x20:=\x22availableGrantEnvs().length\x20>\x200\x22><div\x20class=\x22tf-pills\x22><each\x20:of=\x22availableGrantEnvs()\x22\x20let:item=\x22envName\x22><span\x20class=\x22tf-pill\x20tf-pill--add\x22\x20@click=\x22addGrantEnv(envName)\x22>+\x20{{\x20envName\x20}}</span></each></div></if><each\x20:of=\x22getGrantEntries()\x22\x20let:item=\x22grantEntry\x22><div\x20class=\x22tf-env-row\x22><div\x20class=\x22tf-env-row-header\x22><div\x20style=\x22display:flex;\x20align-items:center;\x20gap:6px;\x22><span\x20class=\x22tf-env-name\x22>{{\x20grantEntry.env\x20}}</span>\x20<span\x20:class=\x22[\x27tf-pill\x27,\x20\x27tf-pill--wild\x27,\x20isEnvAllSelected(grantEntry.env)\x20?\x20\x27tf-pill--wild-on\x27\x20:\x20isEnvWildInherited(grantEntry.env)\x20?\x20\x27tf-pill--wild-inherited\x27\x20:\x20\x27\x27]\x22\x20@click=\x22toggleGrantAllPerms(grantEntry.env)\x22\x20title=\x22*\x20—\x20all\x20permissions\x20for\x20this\x20env\x22\x20style=\x22font-size:11px;\x20padding:1px\x206px;\x22>*</span><if\x20:=\x22grantEntry.globalCoverAll\x22><span\x20class=\x22tf-hint\x22\x20style=\x22color:rgba(79,193,255,.35);\x22\x20title=\x22All\x20permissions\x20already\x20covered\x20by\x20global\x20*\x20or\x20god\x20mode\x22>inherited</span></if></div><span\x20class=\x22tf-env-remove\x22\x20@click=\x22removeGrantEnv(grantEntry.env)\x22>✕\x20remove</span></div><each\x20:of=\x22grantEntry.nGroups\x22\x20let:item=\x22nsGroup\x22><div\x20class=\x22tf-ns-row\x22><span\x20:class=\x22[\x27tf-ns-label\x27,\x20isNsAllSelectedForGrant(grantEntry.env,\x20nsGroup.ns)\x20?\x20\x27tf-ns-label--on\x27\x20:\x20\x27\x27]\x22\x20@click=\x22toggleGrantNamespace(grantEntry.env,\x20nsGroup.ns,\x20nsGroup.ops)\x22\x20title=\x22Toggle\x20all\x22>{{\x20nsGroup.ns\x20}}</span><div\x20class=\x22tf-pills\x22><span\x20:class=\x22[\x27tf-pill\x27,\x20\x27tf-pill--wild\x27,\x20isNsAllSelectedForGrant(grantEntry.env,\x20nsGroup.ns)\x20?\x20\x27tf-pill--wild-on\x27\x20:\x20isNsWildInheritedForGrant(grantEntry.env,\x20nsGroup.ns)\x20?\x20\x27tf-pill--wild-inherited\x27\x20:\x20\x27\x27]\x22\x20@click=\x22toggleGrantNamespace(grantEntry.env,\x20nsGroup.ns,\x20nsGroup.ops)\x22\x20title=\x22ns:*\x20—\x20toggle\x20all\x22>*</span><each\x20:of=\x22nsGroup.ops\x22\x20let:item=\x22grantPerm\x22><span\x20class=\x22tf-pill-wrap\x22\x20@mouseenter=\x22setHover($event,\x20grantPerm.perm,\x20grantPerm)\x22\x20@mouseleave=\x22clearHover()\x22><span\x20:class=\x22[\x27tf-pill\x27,\x20grantPerm.checked\x20?\x20\x27tf-pill--on\x27\x20:\x20grantPerm.inherited\x20?\x20\x27tf-pill--inherited\x27\x20:\x20\x27\x27,\x20grantPerm.hasDestructive\x20?\x20\x27tf-pill--destructive\x27\x20:\x20\x27\x27]\x22\x20@click=\x22toggleGrantPerm(grantEntry.env,\x20nsGroup.ns,\x20grantPerm.op,\x20nsGroup.ops.map(o\x20=>\x20o.op))\x22>{{\x20grantPerm.op\x20}}<if\x20:=\x22grantPerm.hasDestructive\x22><span\x20class=\x22tf-pill-warn\x22>⚠</span></if></span></span></each></div></div></each></div></each></div></if></if></if><if\x20:=\x22error\x22><div\x20class=\x22tf-error\x22>{{\x20error\x20}}</div></if><div\x20class=\x22tf-actions\x22><button\x20class=\x22tf-btn\x20tf-btn--secondary\x22\x20@click=\x22cancel()\x22\x20:disabled=\x22busy\x22>Cancel</button>\x20<button\x20class=\x22tf-btn\x20tf-btn--primary\x22\x20@click=\x22save()\x22\x20:disabled=\x22busy\x20||\x20!label.trim()\x22>Save\x20Changes</button></div><ok-flyover\x20:open=\x22hoveredPermOp\x20!=\x20null\x22\x20:anchor=\x22hoveredAnchor\x22\x20placement=\x22bottom-start\x22\x20:gap=\x224\x22\x20style=\x22--ok-flyover-bg:transparent;\x20--ok-flyover-border:none;\x20--ok-flyover-shadow:none;\x20--ok-flyover-radius:0;\x22><if\x20:=\x22hoveredPermOp\x22><div\x20class=\x22tf-pip\x22><div\x20class=\x22tf-pip-perm\x22>{{\x20hoveredPermOp.perm\x20||\x20hoveredPerm\x20}}</div><if\x20:=\x22hoveredPermOp.summary\x22><div\x20class=\x22tf-pip-summary\x22>{{\x20hoveredPermOp.summary\x20}}</div></if><if\x20:=\x22hoveredPermOp.routes\x20&&\x20hoveredPermOp.routes.length\x22><div\x20class=\x22tf-pip-routes-hd\x22>Routes\x20({{\x20hoveredPermOp.routes.length\x20}})</div><each\x20:of=\x22hoveredPermOp.routes\x22\x20let:item=\x22r\x22><div\x20class=\x22tf-pip-route\x22><span\x20class=\x22tf-pip-method\x22>{{\x20r.method\x20}}</span>\x20<span\x20class=\x22tf-pip-path\x22>{{\x20r.path\x20}}</span><if\x20:=\x22r.destructive\x22><span\x20class=\x22tf-pip-bd\x22>destructive</span></if><if\x20:=\x22r.longRunning\x22><span\x20class=\x22tf-pip-lr\x22>long</span></if></div><if\x20:=\x22r.summary\x22><div\x20class=\x22tf-pip-route-desc\x22>{{\x20r.summary\x20}}</div></if></each></if><if\x20:=\x22!(hoveredPermOp.routes\x20&&\x20hoveredPermOp.routes.length)\x22><div\x20class=\x22tf-pip-gate\x22>Gate\x20—\x20combine\x20with\x20underlying\x20namespace\x20permissions.</div></if><if\x20:=\x22getImpliedBy(hoveredPerm).length\x22><div\x20class=\x22tf-pip-implied\x22>Implied\x20by:\x20{{\x20getImpliedBy(hoveredPerm).join(\x27,\x20\x27)\x20}}</div></if></div></if></ok-flyover></div>'};
1
+ import e from"@toolkit/elements/ok-icon.ok.js";import t from"@toolkit/core/ok-overlay.ok.js";import s from"@toolkit/interaction/ok-flyover.ok.js";export default{tag:"edit-token-modal",dependencies:[t,e,s],attr:{modal:{},token:{},onDone:{}},context(e){const t=e.$attr.token?.permissions||[],s=t.includes("*"),r={};if(!s)for(const e of t)r[e]=!0;const o={},a=e.$attr.token?.grants||{};for(const[e,t]of Object.entries(a)){o[e]={};for(const s of Array.isArray(t)?t:[])o[e][s]=!0}return{busy:!1,error:null,label:e.$attr.token?.label||"",name:e.$attr.token?.name||"",password:"",showPassword:!1,expiresAt:e.$attr.token?.expiresAt?new Date(e.$attr.token.expiresAt).toISOString().slice(0,16):"",catalog:null,catalogError:!1,catalogLoading:!1,godMode:s,selectedPerms:r,grants:o,collapsedScopes:{},hoveredPerm:null,hoveredPermOp:null,hoveredAnchor:null,setHover(e,t,s){this.hoveredPerm=t,this.hoveredPermOp=s,this.hoveredAnchor=e.currentTarget},clearHover(){this.hoveredPerm=null,this.hoveredPermOp=null,this.hoveredAnchor=null},async loadCatalog(){this.catalogLoading=!0;try{const e=await fetch(`${__ENV__.ADMIN_API}/auth/permissions`);if(!e.ok)throw new Error("Failed");const t=await e.json();this.catalog=t.data??t.result}catch{this.catalogError=!0}finally{this.catalogLoading=!1}},togglePerm(e,t,s){if(this.godMode)return;const r=`${e}:*`;if(this.selectedPerms[r]){const o={...this.selectedPerms};delete o[r];for(const r of s)r!==t&&(o[`${e}:${r}`]=!0);this.selectedPerms=o}else this.selectedPerms={...this.selectedPerms,[`${e}:${t}`]:!this.selectedPerms[`${e}:${t}`]}},toggleNamespace(e,t){if(this.godMode)return;const s=`${e}:*`,r={...this.selectedPerms};if(r[s])delete r[s];else{for(const s of t)delete r[`${e}:${s}`];r[s]=!0}this.selectedPerms=r},toggleGodMode(){this.godMode=!this.godMode,this.godMode&&(this.selectedPerms={})},toggleScope(e){this.collapsedScopes={...this.collapsedScopes,[e]:!this.collapsedScopes[e]}},isCollapsed(e){return!!this.collapsedScopes[e]},scopeSelectionCount(e){let t=0,s=0;for(const r of e.namespaces)for(const e of r.operations)s++,(this.selectedPerms[`${r.ns}:${e}`]||this.selectedPerms[`${r.ns}:*`])&&t++;return t>0?`${t}/${s}`:""},addGrantEnv(e){e&&!this.grants[e]&&(this.grants={...this.grants,[e]:{}})},removeGrantEnv(e){const t={...this.grants};delete t[e],this.grants=t},availableGrantEnvs(){return this.catalog?.envs?this.catalog.envs.filter(e=>!this.grants[e]):[]},getPermSections(){if(!this.catalog?.namespaces)return[];const e=this.catalog.opOrder||["read","query","run","write","work","peer"];return[{scope:"env",label:"Environment"},{scope:"system",label:"System"},{scope:"gate",label:"Gate"}].map(t=>({scope:t.scope,label:t.label,namespaces:Object.entries(this.catalog.namespaces).filter(([,e])=>e.scope===t.scope).map(([t,s])=>({ns:t,nsLabel:s.label,nsDescription:s.description,operations:Object.keys(s.operations).sort((t,s)=>{const r=e.indexOf(t),o=e.indexOf(s);return-1===r&&-1===o?t.localeCompare(s):-1===r?1:-1===o?-1:r-o}),operationMeta:s.operations}))})).filter(e=>e.namespaces.length>0)},getPermOps(e,t,s){return t.map(t=>{const r=s?.[t]||{},o=r.routes||[];return{ns:e,op:t,perm:`${e}:${t}`,summary:r.summary||"",routes:o,hasDestructive:o.some(e=>e.destructive),checked:!!this.selectedPerms[`${e}:${t}`]||!!this.selectedPerms[`${e}:*`]}})},getImpliedBy(e){const t=this.catalog?.implies||{};return Object.entries(t).filter(([,t])=>t.includes(e)).map(([e])=>e)},isNsAllSelected(e){return!!this.selectedPerms[`${e}:*`]},isEnvAllSelected(e){return!!this.grants[e]?.["*"]},isEnvWildInherited(e){return!this.isEnvAllSelected(e)&&(this.godMode||!!this.selectedPerms["*"])},isNsAllSelectedForGrant(e,t){return!!this.grants[e]?.["*"]||!!this.grants[e]?.[`${t}:*`]},isNsWildInheritedForGrant(e,t){return!this.isNsAllSelectedForGrant(e,t)&&(this.godMode||!!this.selectedPerms["*"]||!!this.selectedPerms[`${t}:*`])},toggleGrantPerm(e,t,s,r){const o=`${t}:${s}`,a=`${t}:*`,n={...this.grants[e]||{}};if(n["*"])delete n["*"];else if(n[a]){delete n[a];for(const e of r)e!==s&&(n[`${t}:${e}`]=!0)}else n[o]=!n[o];this.grants={...this.grants,[e]:n}},toggleGrantNamespace(e,t,s){const r=`${t}:*`,o={...this.grants[e]||{}};if(o["*"])delete o["*"];else if(o[r])delete o[r];else{for(const e of s)delete o[e.perm];o[r]=!0}this.grants={...this.grants,[e]:o}},toggleGrantAllPerms(e){const t=this.grants[e]||{};if(t["*"]){const s={...t};delete s["*"],this.grants={...this.grants,[e]:s}}else this.grants={...this.grants,[e]:{"*":!0}}},getGrantEntries(){if(!this.catalog?.namespaces)return[];const e=this.catalog.opOrder||["read","query","run","write","work","peer"],t=Object.entries(this.catalog.namespaces).filter(([,e])=>"env"===e.scope).map(([t,s])=>({ns:t,operations:Object.keys(s.operations).sort((t,s)=>{const r=e.indexOf(t),o=e.indexOf(s);return-1===r&&-1===o?t.localeCompare(s):-1===r?1:-1===o?-1:r-o})})),s=this.selectedPerms,r=this.godMode;return Object.entries(this.grants).map(([e,o])=>({env:e,globalCoverAll:r||!!s["*"],nGroups:t.map(({ns:e,operations:t})=>({ns:e,ops:t.map(t=>{const a=`${e}:${t}`,n=!!o[a]||!!o[`${e}:*`]||!!o["*"],l=!n&&(r||!!s["*"]||!!s[`${e}:*`]||!!s[a]),i=this.catalog.namespaces[e]?.operations?.[t]||{};return{perm:a,op:t,summary:i.summary||"",routes:i.routes||[],hasDestructive:(i.routes||[]).some(e=>e.destructive),checked:n,inherited:l}})}))}))},validateForm(){if(!this.label.trim())throw new Error("Token label is required");return!0},async save(){this.error=null;try{this.validateForm(),this.busy=!0;const t={label:this.label.trim()};if(this.expiresAt?t.expiresAt=new Date(this.expiresAt).getTime():t.expiresAt=null,this.godMode)t.permissions=["*"];else if(this.catalogError&&void 0!==this.selectedPerms._fallback){const e=String(this.selectedPerms._fallback||"").split(",").map(e=>e.trim()).filter(e=>e);e.length&&(t.permissions=e)}else{const e=Object.entries(this.selectedPerms).filter(([e,t])=>t&&"_fallback"!==e).map(([e])=>e);e.length&&(t.permissions=e)}const s={};for(const[e,t]of Object.entries(this.grants)){const r=Object.entries(t).filter(([,e])=>e).map(([e])=>e);r.length&&(s[e]=r)}Object.keys(s).length&&(t.grants=s),this.name.trim()&&(t.name=this.name.trim(),this.password&&(t.password=this.password));const r=await fetch(`${__ENV__.API}/auth/tokens/${encodeURIComponent(e.$attr.token.id)}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!r.ok){const e=await r.json();throw new Error(e?.error?.message||"Failed to update token")}e.$ok.shared?.toast?.success?.("Token updated"),await e.$attr.modal.close(),await(e.$attr.onDone?.(e.$attr.token.id))}catch(t){this.error=t?.message||String(t),e.$ok.shared?.toast?.error?.(this.error)}finally{this.busy=!1}},cancel(){e.$attr.modal.close()},passwordStrength(e){if(!e)return 0;let t=0;return e.length>=8&&t++,e.length>=14&&t++,/[A-Z]/.test(e)&&t++,/[0-9]/.test(e)&&t++,/[^A-Za-z0-9]/.test(e)&&t++,t},passwordStrengthLabel(e){const t=this.passwordStrength(e);return e?t<=1?"weak":t<=3?"fair":"strong":""},passwordStrengthColor(e){const t=this.passwordStrength(e);return e?t<=1?"var(--okdb-danger)":t<=3?"var(--okdb-warning)":"var(--okdb-success)":"transparent"},toggleShowPassword(){this.showPassword=!this.showPassword}}},mount(e){this.loadCatalog()},style:".tf-header-fields,.tf-root,edit-token-modal{display:flex;flex-direction:column}.tf-root{gap:0;width:520px;max-width:88vw;position:relative}.tf-header-fields{gap:12px;padding-bottom:16px}.tf-field,.tf-header-row{display:flex;gap:10px}.tf-field{flex-direction:column;gap:4px;min-width:0}.tf-label{font-size:10px;color:var(--okdb-app-fg-muted);text-transform:uppercase;letter-spacing:.07em;font-weight:600}.tf-creds-section{display:flex;flex-direction:column;gap:8px;padding:10px 12px;border:1px solid var(--okdb-app-surface);border-radius:6px;background:rgba(0,0,0,.15)}.tf-creds-label{font-size:10px;color:var(--okdb-app-fg-muted);text-transform:uppercase;letter-spacing:.07em;font-weight:600}.tf-creds-hint{font-size:10px;color:var(--okdb-app-fg-subtle);line-height:1.4;margin-top:-4px}.tf-creds-row{display:flex;gap:10px}.tf-pw-wrap{position:relative;display:flex;align-items:center}.tf-pw-wrap .tf-input{padding-right:30px}.tf-pw-eye{position:absolute;right:7px;background:0 0;border:0;color:var(--okdb-app-fg-subtle);cursor:pointer;font-size:12px;padding:0;line-height:1;user-select:none}.tf-pw-eye:hover,.tf-scope-header:hover .tf-scope-name{color:var(--okdb-accent-muted)}.tf-strength-bar{height:2px;border-radius:1px;background:var(--okdb-app-surface);margin-top:3px;overflow:hidden}.tf-strength-fill{height:100%;border-radius:1px;transition:width .2s,background-color .2s}.tf-strength-text{font-size:9px;margin-top:2px;text-transform:uppercase;letter-spacing:.05em}.tf-input{padding:6px 8px;border:1px solid var(--okdb-app-surface-2);border-radius:4px;background:0 0;color:var(--okdb-app-fg-strong);font-size:12px;font-family:monospace;width:100%;box-sizing:border-box}.tf-input:focus{outline:0;border-color:rgba(79,193,255,.4)}.tf-hint{font-size:10px;color:var(--okdb-app-fg-subtle);line-height:1.4}.tf-divider{height:1px;background:var(--okdb-app-surface);margin-bottom:12px}.tf-section{display:flex;flex-direction:column;gap:6px;margin-bottom:10px}.tf-scope-header{display:flex;align-items:center;gap:8px;cursor:pointer;user-select:none;padding:2px 0}.tf-scope-name{font-size:10px;text-transform:uppercase;letter-spacing:.07em;color:var(--okdb-app-fg-muted);font-weight:600;transition:color .1s}.tf-scope-count{font-size:10px;color:var(--okdb-accent);opacity:.8}.tf-scope-chevron{margin-left:auto;font-size:10px;color:var(--okdb-app-fg-subtle)}.tf-ns-block{display:flex;flex-direction:column;gap:4px;margin-bottom:8px}.tf-ns-row{display:flex;align-items:baseline;gap:8px}.tf-ns-label{font-size:11px;color:var(--okdb-app-fg-subtle);font-family:monospace;flex-shrink:0;cursor:pointer;user-select:none;transition:color .1s;font-weight:600}.tf-ns-label:hover{color:var(--okdb-accent-muted)}.tf-ns-label--on{color:var(--okdb-accent)}.tf-ns-desc{font-size:10px;color:var(--okdb-app-fg-subtle);line-height:1.4}.tf-pills{display:flex;flex-wrap:wrap;gap:4px;padding-left:4px}.tf-pill-wrap{display:inline-flex}.tf-pill-warn{font-size:7px;color:rgba(215,150,60,.85);vertical-align:super;margin-left:1px;line-height:0}.tf-pill--destructive{border-color:rgba(200,140,60,.35)}.tf-pill--destructive:hover{border-color:rgba(200,140,60,.6)}.tf-pill{display:inline-flex;align-items:center;padding:2px 8px;border-radius:4px;font-size:11px;font-family:monospace;border:1px solid var(--okdb-app-surface-2);color:var(--okdb-app-fg-subtle);cursor:pointer;user-select:none;transition:background .1s,border-color .1s,color .1s;white-space:nowrap}.tf-pill:hover{border-color:var(--okdb-app-border);color:var(--okdb-accent-muted)}.tf-pill--on{background:rgba(79,193,255,.1);border-color:rgba(79,193,255,.35);color:var(--okdb-accent)}.tf-pill--on:hover{background:rgba(79,193,255,.15)}.tf-pill--full{border-color:rgba(251,191,36,.2);color:#5a4a20}.tf-pill--full-on,.tf-pill--full:hover{border-color:rgba(251,191,36,.4);color:var(--okdb-warning-text)}.tf-pill--full-on{background:rgba(251,191,36,.1)}.tf-pill--full-on:hover{background:rgba(251,191,36,.16)}.tf-pill--add{border-style:dashed;border-color:var(--okdb-app-surface-2);color:var(--okdb-app-fg-subtle)}.tf-pill--add:hover{border-color:var(--okdb-app-border);color:var(--okdb-accent-muted);border-style:solid}.tf-pill--wild{border-color:rgba(251,191,36,.2);color:#5a4a20;font-weight:700}.tf-pill--wild-on,.tf-pill--wild:hover{border-color:rgba(251,191,36,.4);color:var(--okdb-warning-text)}.tf-pill--wild-on{background:rgba(251,191,36,.1);font-weight:700}.tf-pill--wild-on:hover{background:rgba(251,191,36,.16)}.tf-pill--wild-inherited{border-style:dashed;border-color:rgba(251,191,36,.45);color:rgba(251,191,36,.6);background:rgba(251,191,36,.05);font-weight:700}.tf-pill--wild-inherited:hover{border-color:rgba(251,191,36,.65);color:rgba(251,191,36,.8);background:rgba(251,191,36,.09)}.tf-pill--inherited{border-style:dashed;border-color:rgba(79,193,255,.5);color:rgba(79,193,255,.65);background:rgba(79,193,255,.06)}.tf-pill--inherited:hover{border-color:rgba(79,193,255,.7);color:rgba(79,193,255,.85);background:rgba(79,193,255,.1)}.tf-env-row{display:flex;flex-direction:column;gap:6px;padding:8px 0 10px;border-top:1px solid var(--okdb-app-bg)}.tf-env-row-header{display:flex;align-items:center;justify-content:space-between}.tf-env-name{font-size:11px;font-weight:600;color:var(--okdb-app-fg-muted);font-family:monospace}.tf-env-all,.tf-env-remove{font-size:10px;color:var(--okdb-app-fg-subtle);cursor:pointer;user-select:none;padding:1px 4px;transition:color .1s}.tf-env-remove:hover{color:var(--okdb-danger)}.tf-env-all:hover{color:var(--okdb-accent-muted)}.tf-env-all--on{color:var(--okdb-warning-text)}.tf-env-all--on:hover{color:var(--okdb-warning)}.tf-error{font-size:11px;color:var(--okdb-danger);padding:6px 0 0}.tf-actions{display:flex;gap:8px;justify-content:flex-end;padding-top:14px;margin-top:4px;border-top:1px solid var(--okdb-app-surface)}.tf-btn{padding:5px 12px;border-radius:5px;font-size:12px;border:1px solid;background:0 0;cursor:pointer;transition:background .12s,color .12s}.tf-btn:disabled{opacity:.4;cursor:not-allowed}.tf-btn--primary{border-color:var(--okdb-app-border);color:var(--okdb-accent-muted)}.tf-btn--primary:not(:disabled):hover{background:var(--okdb-app-surface);border-color:var(--okdb-app-border);color:var(--okdb-sky)}.tf-btn--secondary{border-color:var(--okdb-app-surface-2);color:var(--okdb-app-fg-subtle)}.tf-btn--secondary:hover{background:var(--okdb-app-bg)}.tf-pip{min-width:260px;max-width:460px;background:var(--okdb-app-bg-deep);border:1px solid var(--okdb-app-surface-2);border-radius:5px;padding:8px 10px;box-shadow:0 4px 18px rgba(0,0,0,.75);pointer-events:none;white-space:normal;font-size:11px}.tf-pip-perm{font-family:monospace;font-size:10px;color:var(--okdb-accent);margin-bottom:3px}.tf-pip-summary{color:var(--okdb-accent-muted);line-height:1.4;margin-bottom:5px}.tf-pip-routes-hd{font-size:9px;color:var(--okdb-app-fg-subtle);text-transform:uppercase;letter-spacing:.06em;margin-bottom:3px}.tf-pip-route{display:flex;align-items:baseline;gap:5px;padding:1px 0}.tf-pip-method{font-family:monospace;font-size:9px;color:var(--okdb-accent);width:34px;flex-shrink:0}.tf-pip-path{font-family:monospace;font-size:10px;color:var(--okdb-accent-muted);word-break:break-all}.tf-pip-bd,.tf-pip-lr{font-size:8px;border-radius:2px;padding:0 3px;flex-shrink:0}.tf-pip-bd{color:var(--okdb-danger);background:rgba(180,50,40,.15)}.tf-pip-lr{color:var(--okdb-app-fg-muted);background:rgba(100,100,100,.12)}.tf-pip-route-desc{font-size:9px;color:var(--okdb-app-fg-subtle);padding-left:39px;margin-bottom:1px}.tf-pip-gate,.tf-pip-implied{color:var(--okdb-app-fg-subtle);font-size:10px}.tf-pip-implied{margin-top:5px;font-size:9px;font-family:monospace}",template:'<div class="tf-root"><if :="busy"><ok-overlay><div class="loader-center"><ok-icon name="loader" class="spin" style="width:28px;height:28px;"/></div></ok-overlay></if><div class="tf-header-fields"><div class="tf-header-row"><div class="tf-field" style="flex:2;"><span class="tf-label">Label</span> <input class="tf-input" type="text" placeholder="e.g., API Client" :value="label" @input="label = $el.value" :disabled="busy"></div><div class="tf-field" style="flex:1.5;"><span class="tf-label">Expires <span style="opacity:.4;">(optional)</span></span> <input class="tf-input" type="datetime-local" :value="expiresAt" @input="expiresAt = $el.value" :disabled="busy"></div></div><div class="tf-creds-section"><div><div class="tf-creds-label">Login credentials <span style="opacity:.4; text-transform:none; font-weight:400; letter-spacing:0;">(optional)</span></div><div class="tf-creds-hint">If set, this token can also be used via username + password authentication.</div></div><div class="tf-creds-row"><div class="tf-field" style="flex:1;"><span class="tf-label">Username</span> <input class="tf-input" type="text" placeholder="leave blank for token-only" :value="name" @input="name = $el.value" :disabled="busy" autocomplete="off"></div><div class="tf-field" style="flex:1;"><span class="tf-label">Password <span style="opacity:.4;">(new)</span></span><div class="tf-pw-wrap"><input class="tf-input" :type="showPassword ? \'text\' : \'password\'" placeholder="leave blank to keep" :value="password" @input="password = $el.value" :disabled="busy || !name" autocomplete="new-password"> <button class="tf-pw-eye" @click="toggleShowPassword()" type="button" tabindex="-1">{{ showPassword ? \'🙈\' : \'👁\' }}</button></div><if :="password"><div class="tf-strength-bar"><div class="tf-strength-fill" :style="\'width:\' + (passwordStrength(password)/5*100) + \'%; background:\' + passwordStrengthColor(password)"/></div><div class="tf-strength-text" :style="\'color:\' + passwordStrengthColor(password)">{{ passwordStrengthLabel(password) }}</div></if></div></div></div></div><div class="tf-divider"/><if :="catalogLoading"><div class="tf-hint" style="padding-bottom:12px;">Loading permissions…</div></if><if :="catalogError && !catalogLoading"><div class="tf-section"><span class="tf-label">Permissions <span style="color:var(--okdb-danger);">(fallback)</span></span> <input class="tf-input" type="text" placeholder="data:read, data:write" :value="selectedPerms._fallback || \'\'" @input="selectedPerms = { _fallback: $el.value }" :disabled="busy"> <span class="tf-hint">Comma-separated permission strings</span></div></if><if :="catalog && !catalogError && !catalogLoading"><div class="tf-section" style="gap:4px;"><div :class="[\'tf-pill\', \'tf-pill--full\', godMode ? \'tf-pill--full-on\' : \'\']" @click="toggleGodMode()" style="width:fit-content;">★ &nbsp;Full access — all permissions</div></div><if :="!godMode"><each :of="getPermSections()" let:item="section"><div class="tf-section"><div class="tf-scope-header" @click="toggleScope(section.scope)"><span class="tf-scope-name">{{ section.label }}</span><if :="scopeSelectionCount(section)"><span class="tf-scope-count">{{ scopeSelectionCount(section) }}</span></if><span class="tf-scope-chevron">{{ isCollapsed(section.scope) ? \'▸\' : \'▾\' }}</span></div><if :="!isCollapsed(section.scope)"><each :of="section.namespaces" let:item="nsEntry"><div class="tf-ns-block"><div class="tf-ns-row"><span :class="[\'tf-ns-label\', isNsAllSelected(nsEntry.ns) ? \'tf-ns-label--on\' : \'\']" @click="toggleNamespace(nsEntry.ns, nsEntry.operations)" title="Toggle all">{{ nsEntry.nsLabel || nsEntry.ns }}</span><if :="nsEntry.nsDescription"><span class="tf-ns-desc">{{ nsEntry.nsDescription }}</span></if></div><div class="tf-pills"><span :class="[\'tf-pill\', \'tf-pill--wild\', isNsAllSelected(nsEntry.ns) ? \'tf-pill--wild-on\' : \'\']" @click="toggleNamespace(nsEntry.ns, nsEntry.operations)" title="ns:* — toggle all">*</span><each :of="getPermOps(nsEntry.ns, nsEntry.operations, nsEntry.operationMeta)" let:item="permOp"><span class="tf-pill-wrap" @mouseenter="setHover($event, permOp.perm, permOp)" @mouseleave="clearHover()"><span :class="[\'tf-pill\', permOp.checked ? \'tf-pill--on\' : \'\', permOp.hasDestructive ? \'tf-pill--destructive\' : \'\']" @click="togglePerm(permOp.ns, permOp.op, nsEntry.operations)">{{ permOp.op }}<if :="permOp.hasDestructive"><span class="tf-pill-warn">⚠</span></if></span></span></each></div></div></each></if></div></each><if :="catalog.envs && catalog.envs.length > 0"><div class="tf-divider"/><div class="tf-section" style="gap:8px;"><div class="tf-scope-header" style="cursor:default; pointer-events:none;"><span class="tf-scope-name">Per-env grants</span> <span class="tf-hint" style="margin-left:6px;">extra permissions for a specific environment</span></div><if :="availableGrantEnvs().length > 0"><div class="tf-pills"><each :of="availableGrantEnvs()" let:item="envName"><span class="tf-pill tf-pill--add" @click="addGrantEnv(envName)">+ {{ envName }}</span></each></div></if><each :of="getGrantEntries()" let:item="grantEntry"><div class="tf-env-row"><div class="tf-env-row-header"><div style="display:flex; align-items:center; gap:6px;"><span class="tf-env-name">{{ grantEntry.env }}</span> <span :class="[\'tf-pill\', \'tf-pill--wild\', isEnvAllSelected(grantEntry.env) ? \'tf-pill--wild-on\' : isEnvWildInherited(grantEntry.env) ? \'tf-pill--wild-inherited\' : \'\']" @click="toggleGrantAllPerms(grantEntry.env)" title="* — all permissions for this env" style="font-size:11px; padding:1px 6px;">*</span><if :="grantEntry.globalCoverAll"><span class="tf-hint" style="color:rgba(79,193,255,.35);" title="All permissions already covered by global * or god mode">inherited</span></if></div><span class="tf-env-remove" @click="removeGrantEnv(grantEntry.env)">✕ remove</span></div><each :of="grantEntry.nGroups" let:item="nsGroup"><div class="tf-ns-row"><span :class="[\'tf-ns-label\', isNsAllSelectedForGrant(grantEntry.env, nsGroup.ns) ? \'tf-ns-label--on\' : \'\']" @click="toggleGrantNamespace(grantEntry.env, nsGroup.ns, nsGroup.ops)" title="Toggle all">{{ nsGroup.ns }}</span><div class="tf-pills"><span :class="[\'tf-pill\', \'tf-pill--wild\', isNsAllSelectedForGrant(grantEntry.env, nsGroup.ns) ? \'tf-pill--wild-on\' : isNsWildInheritedForGrant(grantEntry.env, nsGroup.ns) ? \'tf-pill--wild-inherited\' : \'\']" @click="toggleGrantNamespace(grantEntry.env, nsGroup.ns, nsGroup.ops)" title="ns:* — toggle all">*</span><each :of="nsGroup.ops" let:item="grantPerm"><span class="tf-pill-wrap" @mouseenter="setHover($event, grantPerm.perm, grantPerm)" @mouseleave="clearHover()"><span :class="[\'tf-pill\', grantPerm.checked ? \'tf-pill--on\' : grantPerm.inherited ? \'tf-pill--inherited\' : \'\', grantPerm.hasDestructive ? \'tf-pill--destructive\' : \'\']" @click="toggleGrantPerm(grantEntry.env, nsGroup.ns, grantPerm.op, nsGroup.ops.map(o => o.op))">{{ grantPerm.op }}<if :="grantPerm.hasDestructive"><span class="tf-pill-warn">⚠</span></if></span></span></each></div></div></each></div></each></div></if></if></if><if :="error"><div class="tf-error">{{ error }}</div></if><div class="tf-actions"><button class="tf-btn tf-btn--secondary" @click="cancel()" :disabled="busy">Cancel</button> <button class="tf-btn tf-btn--primary" @click="save()" :disabled="busy || !label.trim()">Save Changes</button></div><ok-flyover :open="hoveredPermOp != null" :anchor="hoveredAnchor" placement="bottom-start" :gap="4" style="--ok-flyover-bg:transparent; --ok-flyover-border:none; --ok-flyover-shadow:none; --ok-flyover-radius:0;"><if :="hoveredPermOp"><div class="tf-pip"><div class="tf-pip-perm">{{ hoveredPermOp.perm || hoveredPerm }}</div><if :="hoveredPermOp.summary"><div class="tf-pip-summary">{{ hoveredPermOp.summary }}</div></if><if :="hoveredPermOp.routes && hoveredPermOp.routes.length"><div class="tf-pip-routes-hd">Routes ({{ hoveredPermOp.routes.length }})</div><each :of="hoveredPermOp.routes" let:item="r"><div class="tf-pip-route"><span class="tf-pip-method">{{ r.method }}</span> <span class="tf-pip-path">{{ r.path }}</span><if :="r.destructive"><span class="tf-pip-bd">destructive</span></if><if :="r.longRunning"><span class="tf-pip-lr">long</span></if></div><if :="r.summary"><div class="tf-pip-route-desc">{{ r.summary }}</div></if></each></if><if :="!(hoveredPermOp.routes && hoveredPermOp.routes.length)"><div class="tf-pip-gate">Gate — combine with underlying namespace permissions.</div></if><if :="getImpliedBy(hoveredPerm).length"><div class="tf-pip-implied">Implied by: {{ getImpliedBy(hoveredPerm).join(\', \') }}</div></if></div></if></ok-flyover></div>'};
@@ -1 +1 @@
1
- function _0x1465(){var _0x165273=['11rwqpPZ','939830tlbGoG','17181820ySgwBU','24LiPrYa','perm-info-popover','1043114TJwegl','9931572VxHPCC','85684YfzDPR','4FmUYHV','1445340GayEIm','12IeMubk','2716903iGVtqZ'];_0x1465=function(){return _0x165273;};return _0x1465();}function _0x1d09(_0x242de6,_0xee5bfb){_0x242de6=_0x242de6-0xe3;var _0x146514=_0x1465();var _0x1d0998=_0x146514[_0x242de6];return _0x1d0998;}var _0x572e30=_0x1d09;(function(_0x2014bc,_0x53d571){var _0x470273=_0x1d09,_0x3cef14=_0x2014bc();while(!![]){try{var _0x4a2224=-parseInt(_0x470273(0xe5))/0x1+-parseInt(_0x470273(0xe7))/0x2*(parseInt(_0x470273(0xea))/0x3)+-parseInt(_0x470273(0xe8))/0x4*(parseInt(_0x470273(0xed))/0x5)+parseInt(_0x470273(0xe9))/0x6+-parseInt(_0x470273(0xeb))/0x7*(-parseInt(_0x470273(0xe3))/0x8)+-parseInt(_0x470273(0xe6))/0x9+parseInt(_0x470273(0xee))/0xa*(parseInt(_0x470273(0xec))/0xb);if(_0x4a2224===_0x53d571)break;else _0x3cef14['push'](_0x3cef14['shift']());}catch(_0x45b546){_0x3cef14['push'](_0x3cef14['shift']());}}}(_0x1465,0x96c1f));export default{'tag':_0x572e30(0xe4),'attr':{'permission':{},'summary':{},'routes':{},'impliedBy':{}},'template':'<style>.pip\x20{\x0a\x20\x20\x20\x20\x20\x20\x20\x20position:\x20absolute;\x0a\x20\x20\x20\x20\x20\x20\x20\x20bottom:\x20calc(100%\x20+\x206px);\x0a\x20\x20\x20\x20\x20\x20\x20\x20left:\x2050%;\x0a\x20\x20\x20\x20\x20\x20\x20\x20transform:\x20translateX(-50%);\x0a\x20\x20\x20\x20\x20\x20\x20\x20z-index:\x20200;\x0a\x20\x20\x20\x20\x20\x20\x20\x20min-width:\x20280px;\x0a\x20\x20\x20\x20\x20\x20\x20\x20max-width:\x20480px;\x0a\x20\x20\x20\x20\x20\x20\x20\x20background:\x20var(--okdb-app-bg-deep);\x0a\x20\x20\x20\x20\x20\x20\x20\x20border:\x201px\x20solid\x20var(--okdb-app-surface-2);\x0a\x20\x20\x20\x20\x20\x20\x20\x20border-radius:\x205px;\x0a\x20\x20\x20\x20\x20\x20\x20\x20padding:\x208px\x2010px;\x0a\x20\x20\x20\x20\x20\x20\x20\x20box-shadow:\x200\x204px\x2016px\x20rgba(0,0,0,.7);\x0a\x20\x20\x20\x20\x20\x20\x20\x20pointer-events:\x20none;\x0a\x20\x20\x20\x20\x20\x20\x20\x20white-space:\x20normal;\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20.pip-perm\x20\x20\x20{\x20font-family:\x20monospace;\x20font-size:\x2010px;\x20color:\x20var(--okdb-accent);\x20margin-bottom:\x203px;\x20}\x0a\x20\x20\x20\x20\x20\x20.pip-summary\x20{\x20font-size:\x2011px;\x20color:\x20var(--okdb-accent-muted);\x20line-height:\x201.4;\x20margin-bottom:\x206px;\x20}\x0a\x20\x20\x20\x20\x20\x20.pip-routes-hd\x20{\x20font-size:\x209px;\x20color:\x20var(--okdb-app-fg-subtle);\x20text-transform:\x20uppercase;\x20letter-spacing:\x20.06em;\x20margin-bottom:\x203px;\x20}\x0a\x20\x20\x20\x20\x20\x20.pip-route\x20\x20{\x20display:\x20flex;\x20align-items:\x20baseline;\x20gap:\x205px;\x20padding:\x201px\x200;\x20}\x0a\x20\x20\x20\x20\x20\x20.pip-method\x20{\x20font-family:\x20monospace;\x20font-size:\x209px;\x20color:\x20var(--okdb-accent);\x20width:\x2034px;\x20flex-shrink:\x200;\x20}\x0a\x20\x20\x20\x20\x20\x20.pip-path\x20\x20\x20{\x20font-family:\x20monospace;\x20font-size:\x2010px;\x20color:\x20var(--okdb-accent-muted);\x20word-break:\x20break-all;\x20}\x0a\x20\x20\x20\x20\x20\x20.pip-bd\x20\x20\x20\x20\x20{\x20font-size:\x208px;\x20color:\x20var(--okdb-danger);\x20background:\x20rgba(180,50,40,.15);\x20border-radius:\x202px;\x20padding:\x200\x203px;\x20flex-shrink:\x200;\x20}\x0a\x20\x20\x20\x20\x20\x20.pip-lr\x20\x20\x20\x20\x20{\x20font-size:\x208px;\x20color:\x20var(--okdb-app-fg-muted);\x20background:\x20rgba(100,100,100,.12);\x20border-radius:\x202px;\x20padding:\x200\x203px;\x20flex-shrink:\x200;\x20}\x0a\x20\x20\x20\x20\x20\x20.pip-route-desc\x20{\x20font-size:\x209px;\x20color:\x20var(--okdb-app-fg-subtle);\x20padding-left:\x2039px;\x20}\x0a\x20\x20\x20\x20\x20\x20.pip-implied\x20{\x20margin-top:\x206px;\x20font-size:\x209px;\x20color:\x20var(--okdb-app-fg-subtle);\x20}\x0a\x20\x20\x20\x20\x20\x20.pip-implied\x20code\x20{\x20font-family:\x20monospace;\x20color:\x20var(--okdb-accent-muted);\x20}\x0a\x20\x20\x20\x20\x20\x20.pip-gate\x20{\x20font-size:\x2010px;\x20color:\x20var(--okdb-app-fg-subtle);\x20}</style><div\x20class=\x22pip\x22><div\x20class=\x22pip-perm\x22>{{\x20$attr.permission\x20}}</div><if\x20:=\x22$attr.summary\x22><div\x20class=\x22pip-summary\x22>{{\x20$attr.summary\x20}}</div></if><if\x20:=\x22$attr.routes\x20&&\x20$attr.routes.length\x22><div\x20class=\x22pip-routes-hd\x22>Routes\x20({{\x20$attr.routes.length\x20}})</div><each\x20:of=\x22$attr.routes\x22\x20let:item=\x22r\x22><div\x20class=\x22pip-route\x22><span\x20class=\x22pip-method\x22>{{\x20r.method\x20}}</span>\x20<span\x20class=\x22pip-path\x22>{{\x20r.path\x20}}</span><if\x20:=\x22r.destructive\x22><span\x20class=\x22pip-bd\x22>destructive</span></if><if\x20:=\x22r.longRunning\x22><span\x20class=\x22pip-lr\x22>long</span></if></div><if\x20:=\x22r.summary\x22><div\x20class=\x22pip-route-desc\x22>{{\x20r.summary\x20}}</div></if></each></if><if\x20:=\x22!($attr.routes\x20&&\x20$attr.routes.length)\x22><div\x20class=\x22pip-gate\x22>Gate\x20—\x20not\x20tied\x20to\x20a\x20route.\x20Combine\x20with\x20underlying\x20namespace\x20permissions.</div></if><if\x20:=\x22$attr.impliedBy\x20&&\x20$attr.impliedBy.length\x22><div\x20class=\x22pip-implied\x22>Implied\x20by:<each\x20:of=\x22$attr.impliedBy\x22\x20let:item=\x22p\x22><code>{{\x20p\x20}}</code></each></div></if></div>'};
1
+ export default{tag:"perm-info-popover",attr:{permission:{},summary:{},routes:{},impliedBy:{}},template:'<style>.pip {\n position: absolute;\n bottom: calc(100% + 6px);\n left: 50%;\n transform: translateX(-50%);\n z-index: 200;\n min-width: 280px;\n max-width: 480px;\n background: var(--okdb-app-bg-deep);\n border: 1px solid var(--okdb-app-surface-2);\n border-radius: 5px;\n padding: 8px 10px;\n box-shadow: 0 4px 16px rgba(0,0,0,.7);\n pointer-events: none;\n white-space: normal;\n }\n .pip-perm { font-family: monospace; font-size: 10px; color: var(--okdb-accent); margin-bottom: 3px; }\n .pip-summary { font-size: 11px; color: var(--okdb-accent-muted); line-height: 1.4; margin-bottom: 6px; }\n .pip-routes-hd { font-size: 9px; color: var(--okdb-app-fg-subtle); text-transform: uppercase; letter-spacing: .06em; margin-bottom: 3px; }\n .pip-route { display: flex; align-items: baseline; gap: 5px; padding: 1px 0; }\n .pip-method { font-family: monospace; font-size: 9px; color: var(--okdb-accent); width: 34px; flex-shrink: 0; }\n .pip-path { font-family: monospace; font-size: 10px; color: var(--okdb-accent-muted); word-break: break-all; }\n .pip-bd { font-size: 8px; color: var(--okdb-danger); background: rgba(180,50,40,.15); border-radius: 2px; padding: 0 3px; flex-shrink: 0; }\n .pip-lr { font-size: 8px; color: var(--okdb-app-fg-muted); background: rgba(100,100,100,.12); border-radius: 2px; padding: 0 3px; flex-shrink: 0; }\n .pip-route-desc { font-size: 9px; color: var(--okdb-app-fg-subtle); padding-left: 39px; }\n .pip-implied { margin-top: 6px; font-size: 9px; color: var(--okdb-app-fg-subtle); }\n .pip-implied code { font-family: monospace; color: var(--okdb-accent-muted); }\n .pip-gate { font-size: 10px; color: var(--okdb-app-fg-subtle); }</style><div class="pip"><div class="pip-perm">{{ $attr.permission }}</div><if :="$attr.summary"><div class="pip-summary">{{ $attr.summary }}</div></if><if :="$attr.routes && $attr.routes.length"><div class="pip-routes-hd">Routes ({{ $attr.routes.length }})</div><each :of="$attr.routes" let:item="r"><div class="pip-route"><span class="pip-method">{{ r.method }}</span> <span class="pip-path">{{ r.path }}</span><if :="r.destructive"><span class="pip-bd">destructive</span></if><if :="r.longRunning"><span class="pip-lr">long</span></if></div><if :="r.summary"><div class="pip-route-desc">{{ r.summary }}</div></if></each></if><if :="!($attr.routes && $attr.routes.length)"><div class="pip-gate">Gate — not tied to a route. Combine with underlying namespace permissions.</div></if><if :="$attr.impliedBy && $attr.impliedBy.length"><div class="pip-implied">Implied by:<each :of="$attr.impliedBy" let:item="p"><code>{{ p }}</code></each></div></if></div>'};
@@ -1 +1 @@
1
- const _0x5bdda8=_0x471f;(function(_0x407dae,_0x437725){const _0x3251e7=_0x471f,_0xa547f2=_0x407dae();while(!![]){try{const _0x1fb614=-parseInt(_0x3251e7(0xa7))/0x1+parseInt(_0x3251e7(0xc1))/0x2*(parseInt(_0x3251e7(0xb7))/0x3)+parseInt(_0x3251e7(0xa6))/0x4*(parseInt(_0x3251e7(0xa8))/0x5)+-parseInt(_0x3251e7(0xb3))/0x6+-parseInt(_0x3251e7(0xb5))/0x7+-parseInt(_0x3251e7(0xb1))/0x8+parseInt(_0x3251e7(0xae))/0x9;if(_0x1fb614===_0x437725)break;else _0xa547f2['push'](_0xa547f2['shift']());}catch(_0x12087d){_0xa547f2['push'](_0xa547f2['shift']());}}}(_0x1048,0xcdd6d));function _0x471f(_0x2c307a,_0x30dbe0){_0x2c307a=_0x2c307a-0xa6;const _0x104868=_0x1048();let _0x471f6f=_0x104868[_0x2c307a];return _0x471f6f;}export default{'tag':_0x5bdda8(0xab),'attr':{'token':{}},'context':_0x3e4db9=>({get 'token'(){const _0x4ada2c=_0x5bdda8;return _0x3e4db9['$attr'][_0x4ada2c(0xc2)];},'edit'(){const _0x3f3d89=_0x5bdda8;_0x3e4db9[_0x3f3d89(0xc0)](_0x3f3d89(0xc5),_0x3e4db9[_0x3f3d89(0xba)]['token']);},'permissionTags'(){const _0x5736e9=_0x5bdda8,_0xd7f46a=_0x3e4db9[_0x5736e9(0xba)][_0x5736e9(0xc2)]?.['permissions']||[];return _0xd7f46a[_0x5736e9(0xbb)]('*')?[{'label':_0x5736e9(0xbc),'full':!0x0}]:_0xd7f46a[_0x5736e9(0xac)](_0x2be1b3=>({'label':_0x2be1b3,'full':!0x1}));},'grantEntries'(){const _0x410d05=_0x5bdda8,_0x1138ae=_0x3e4db9[_0x410d05(0xba)][_0x410d05(0xc2)]?.[_0x410d05(0xc3)]||{};return Object['entries'](_0x1138ae)[_0x410d05(0xac)](([_0xe83729,_0x138818])=>({'env':_0xe83729,'ops':Array[_0x410d05(0xc4)](_0x138818)?_0x138818:[]}));},'createdDate'(){const _0x422980=_0x5bdda8,_0x472ca2=_0x3e4db9[_0x422980(0xba)][_0x422980(0xc2)];return _0x472ca2?.[_0x422980(0xbe)]?new Date(_0x472ca2[_0x422980(0xbe)])[_0x422980(0xbd)]():null;},'lastUsedDate'(){const _0x17d22e=_0x5bdda8,_0x28050f=_0x3e4db9[_0x17d22e(0xba)][_0x17d22e(0xc2)];return _0x28050f?.['lastUsedAt']?new Date(_0x28050f['lastUsedAt'])[_0x17d22e(0xbd)]():null;},'expiryInfo'(){const _0x23d0af=_0x5bdda8,_0x5f122d=_0x3e4db9[_0x23d0af(0xba)][_0x23d0af(0xc2)];if(!_0x5f122d?.['expiresAt'])return null;const _0x3c21b4=new Date(_0x5f122d[_0x23d0af(0xbf)]),_0x3c5876=_0x5f122d[_0x23d0af(0xbf)]<Date[_0x23d0af(0xb8)]();return{'label':_0x3c21b4[_0x23d0af(0xbd)](),'expired':_0x3c5876};},'isConfig':()=>'cluster'!==_0x3e4db9['$attr'][_0x5bdda8(0xc2)]?.[_0x5bdda8(0xad)],async 'openDeleteConfirmation'(){const _0x5566bd=_0x5bdda8,_0x1bb10c=_0x3e4db9[_0x5566bd(0xba)][_0x5566bd(0xc2)];await _0x3e4db9[_0x5566bd(0xaf)]['shared'][_0x5566bd(0xb6)][_0x5566bd(0xb4)]('Delete\x20token\x20\x22'+(_0x1bb10c[_0x5566bd(0xb0)]||'Unnamed')+'\x22?',{'title':_0x5566bd(0xaa),'confirmText':_0x5566bd(0xb9),'confirmClass':_0x5566bd(0xa9)})&&_0x3e4db9[_0x5566bd(0xc0)](_0x5566bd(0xb2),_0x1bb10c['id']);}}),'style':'token-detail{height:100%;overflow-y:auto}.td-empty{display:flex;align-items:center;justify-content:center;height:100%;font-size:12px;color:var(--okdb-app-fg-muted)}.td-header,.td-wrap,token-detail{display:flex;flex-direction:column}.td-wrap{gap:20px;padding:20px\x2024px}.td-header{gap:6px}.td-title-row{display:flex;align-items:baseline;gap:10px}.td-name{font-size:15px;font-weight:600;color:var(--okdb-app-fg-strong);margin:0}.td-config-note,.td-meta{font-size:11px;color:var(--okdb-app-fg-muted)}.td-meta{display:flex;gap:12px;flex-wrap:wrap}.td-divider{height:1px;background:var(--okdb-app-surface-2)}.td-actions{display:flex;gap:6px}.td-btn{padding:5px\x2011px;border-radius:5px;font-size:12px;border:1px\x20solid;background:0\x200;cursor:pointer;transition:background\x20.12s}.td-btn--primary,.td-btn--primary:hover{border-color:var(--okdb-app-border);color:var(--okdb-accent-muted)}.td-btn--primary:hover{background:var(--okdb-app-surface);color:var(--okdb-sky)}.td-btn--danger{border-color:rgba(248,113,113,.3);color:var(--okdb-danger)}.td-btn--danger:hover{background:rgba(248,113,113,.08)}.td-section{display:flex;flex-direction:column;gap:8px}.td-section-label{font-size:10px;color:var(--okdb-app-fg-muted);text-transform:uppercase;letter-spacing:.07em;font-weight:600}.td-tags{display:flex;flex-wrap:wrap;gap:4px}.td-tag{display:inline-block;padding:2px\x207px;border-radius:3px;font-size:11px;font-family:monospace;background:rgba(79,193,255,.06);border:1px\x20solid\x20rgba(79,193,255,.15);color:#6db8d8}.td-tag--full{background:rgba(251,191,36,.08);border-color:rgba(251,191,36,.2);color:var(--okdb-warning-text)}.td-none{font-size:11px;color:var(--okdb-app-fg-muted)}.td-grant{display:flex;flex-direction:column;gap:5px;padding:8px\x2010px;border:1px\x20solid\x20var(--okdb-app-surface-2);border-radius:5px}.td-grant-env{font-size:11px;font-weight:600;color:var(--okdb-app-fg-muted)}.td-identity{font-size:12px;color:var(--okdb-app-fg-strong);font-family:monospace;padding:8px\x2010px;background:var(--okdb-app-bg-deep);border-radius:4px;border:1px\x20solid\x20var(--okdb-app-surface-2);word-break:break-all}','template':'<if\x20:=\x22!token\x22><div\x20class=\x22td-empty\x22>Select\x20a\x20token\x20to\x20view\x20details</div></if><if\x20:=\x22token\x22><div\x20class=\x22td-wrap\x22><div\x20class=\x22td-header\x22><div\x20class=\x22td-title-row\x22><h3\x20class=\x22td-name\x22>{{\x20token.label\x20||\x20\x27Unnamed\x20Token\x27\x20}}</h3><if\x20:=\x22isConfig()\x22><span\x20style=\x22font-size:10px;\x20color:var(--okdb-app-fg-muted);\x20text-transform:uppercase;\x20letter-spacing:.05em;\x22>read-only</span></if></div><div\x20class=\x22td-meta\x22><if\x20:=\x22createdDate()\x22><span>Created\x20{{\x20createdDate()\x20}}</span></if><if\x20:=\x22lastUsedDate()\x22><span>Last\x20used\x20{{\x20lastUsedDate()\x20}}</span></if><if\x20:=\x22expiryInfo()\x22><span\x20:style=\x22expiryInfo().expired\x20?\x20\x27color:var(--okdb-danger);\x27\x20:\x20\x27\x27\x22>{{\x20expiryInfo().expired\x20?\x20\x27Expired\x27\x20:\x20\x27Expires\x27\x20}}\x20{{\x20expiryInfo().label\x20}}</span></if><if\x20:=\x22!expiryInfo()\x22><span\x20style=\x22opacity:.5;\x22>No\x20expiry</span></if></div><if\x20:=\x22isConfig()\x22><div\x20class=\x22td-config-note\x22>This\x20token\x20comes\x20from\x20the\x20server\x20config\x20and\x20cannot\x20be\x20edited\x20here.</div></if></div><div\x20class=\x22td-divider\x22/><if\x20:=\x22!isConfig()\x22><div\x20class=\x22td-actions\x22><button\x20class=\x22td-btn\x20td-btn--primary\x22\x20@click=\x22edit()\x22>Edit</button>\x20<button\x20class=\x22td-btn\x20td-btn--danger\x22\x20@click=\x22openDeleteConfirmation()\x22>Delete</button></div></if><div\x20class=\x22td-section\x22><div\x20class=\x22td-section-label\x22>Permissions</div><div\x20class=\x22td-tags\x22><each\x20:of=\x22permissionTags()\x22\x20let:item=\x22tag\x22><span\x20:class=\x22[\x27td-tag\x27,\x20tag.full\x20?\x20\x27td-tag--full\x27\x20:\x20\x27\x27]\x22>{{\x20tag.label\x20}}</span></each><if\x20:=\x22permissionTags().length\x20===\x200\x22><span\x20class=\x22td-none\x22>None</span></if></div></div><if\x20:=\x22grantEntries().length\x20>\x200\x22><div\x20class=\x22td-section\x22><div\x20class=\x22td-section-label\x22>Per-env\x20Grants</div><each\x20:of=\x22grantEntries()\x22\x20let:item=\x22entry\x22><div\x20class=\x22td-grant\x22><span\x20class=\x22td-grant-env\x22>{{\x20entry.env\x20}}</span><div\x20class=\x22td-tags\x22><each\x20:of=\x22entry.ops\x22\x20let:item=\x22op\x22><span\x20class=\x22td-tag\x22>{{\x20op\x20}}</span></each></div></div></each></div></if><if\x20:=\x22token.name\x22><div\x20class=\x22td-section\x22><div\x20class=\x22td-section-label\x22>Identity</div><div\x20class=\x22td-identity\x22>{{\x20token.name\x20}}</div></div></if></div></if>'};function _0x1048(){const _0x261f6c=['Delete\x20Token','token-detail','map','source','16602993WqTEed','$ok','label','4391440fHfgWM','delete','6392700MxDXgd','confirm','847658YgZKFQ','modal','12CgjXya','now','Delete','$attr','includes','*\x20—\x20full\x20access','toLocaleString','createdAt','expiresAt','$dispatch','341564xbfGJh','token','grants','isArray','edit','4hnVfcq','393979yPoBOu','2223325qtoiFm','destructive'];_0x1048=function(){return _0x261f6c;};return _0x1048();}
1
+ export default{tag:"token-detail",attr:{token:{}},context:t=>({get token(){return t.$attr.token},edit(){t.$dispatch("edit",t.$attr.token)},permissionTags(){const e=t.$attr.token?.permissions||[];return e.includes("*")?[{label:"* — full access",full:!0}]:e.map(t=>({label:t,full:!1}))},grantEntries(){const e=t.$attr.token?.grants||{};return Object.entries(e).map(([t,e])=>({env:t,ops:Array.isArray(e)?e:[]}))},createdDate(){const e=t.$attr.token;return e?.createdAt?new Date(e.createdAt).toLocaleString():null},lastUsedDate(){const e=t.$attr.token;return e?.lastUsedAt?new Date(e.lastUsedAt).toLocaleString():null},expiryInfo(){const e=t.$attr.token;if(!e?.expiresAt)return null;const a=new Date(e.expiresAt),n=e.expiresAt<Date.now();return{label:a.toLocaleString(),expired:n}},isConfig:()=>"cluster"!==t.$attr.token?.source,async openDeleteConfirmation(){const e=t.$attr.token;await t.$ok.shared.modal.confirm(`Delete token "${e.label||"Unnamed"}"?`,{title:"Delete Token",confirmText:"Delete",confirmClass:"destructive"})&&t.$dispatch("delete",e.id)}}),style:"token-detail{height:100%;overflow-y:auto}.td-empty{display:flex;align-items:center;justify-content:center;height:100%;font-size:12px;color:var(--okdb-app-fg-muted)}.td-header,.td-wrap,token-detail{display:flex;flex-direction:column}.td-wrap{gap:20px;padding:20px 24px}.td-header{gap:6px}.td-title-row{display:flex;align-items:baseline;gap:10px}.td-name{font-size:15px;font-weight:600;color:var(--okdb-app-fg-strong);margin:0}.td-config-note,.td-meta{font-size:11px;color:var(--okdb-app-fg-muted)}.td-meta{display:flex;gap:12px;flex-wrap:wrap}.td-divider{height:1px;background:var(--okdb-app-surface-2)}.td-actions{display:flex;gap:6px}.td-btn{padding:5px 11px;border-radius:5px;font-size:12px;border:1px solid;background:0 0;cursor:pointer;transition:background .12s}.td-btn--primary,.td-btn--primary:hover{border-color:var(--okdb-app-border);color:var(--okdb-accent-muted)}.td-btn--primary:hover{background:var(--okdb-app-surface);color:var(--okdb-sky)}.td-btn--danger{border-color:rgba(248,113,113,.3);color:var(--okdb-danger)}.td-btn--danger:hover{background:rgba(248,113,113,.08)}.td-section{display:flex;flex-direction:column;gap:8px}.td-section-label{font-size:10px;color:var(--okdb-app-fg-muted);text-transform:uppercase;letter-spacing:.07em;font-weight:600}.td-tags{display:flex;flex-wrap:wrap;gap:4px}.td-tag{display:inline-block;padding:2px 7px;border-radius:3px;font-size:11px;font-family:monospace;background:rgba(79,193,255,.06);border:1px solid rgba(79,193,255,.15);color:#6db8d8}.td-tag--full{background:rgba(251,191,36,.08);border-color:rgba(251,191,36,.2);color:var(--okdb-warning-text)}.td-none{font-size:11px;color:var(--okdb-app-fg-muted)}.td-grant{display:flex;flex-direction:column;gap:5px;padding:8px 10px;border:1px solid var(--okdb-app-surface-2);border-radius:5px}.td-grant-env{font-size:11px;font-weight:600;color:var(--okdb-app-fg-muted)}.td-identity{font-size:12px;color:var(--okdb-app-fg-strong);font-family:monospace;padding:8px 10px;background:var(--okdb-app-bg-deep);border-radius:4px;border:1px solid var(--okdb-app-surface-2);word-break:break-all}",template:'<if :="!token"><div class="td-empty">Select a token to view details</div></if><if :="token"><div class="td-wrap"><div class="td-header"><div class="td-title-row"><h3 class="td-name">{{ token.label || \'Unnamed Token\' }}</h3><if :="isConfig()"><span style="font-size:10px; color:var(--okdb-app-fg-muted); text-transform:uppercase; letter-spacing:.05em;">read-only</span></if></div><div class="td-meta"><if :="createdDate()"><span>Created {{ createdDate() }}</span></if><if :="lastUsedDate()"><span>Last used {{ lastUsedDate() }}</span></if><if :="expiryInfo()"><span :style="expiryInfo().expired ? \'color:var(--okdb-danger);\' : \'\'">{{ expiryInfo().expired ? \'Expired\' : \'Expires\' }} {{ expiryInfo().label }}</span></if><if :="!expiryInfo()"><span style="opacity:.5;">No expiry</span></if></div><if :="isConfig()"><div class="td-config-note">This token comes from the server config and cannot be edited here.</div></if></div><div class="td-divider"/><if :="!isConfig()"><div class="td-actions"><button class="td-btn td-btn--primary" @click="edit()">Edit</button> <button class="td-btn td-btn--danger" @click="openDeleteConfirmation()">Delete</button></div></if><div class="td-section"><div class="td-section-label">Permissions</div><div class="td-tags"><each :of="permissionTags()" let:item="tag"><span :class="[\'td-tag\', tag.full ? \'td-tag--full\' : \'\']">{{ tag.label }}</span></each><if :="permissionTags().length === 0"><span class="td-none">None</span></if></div></div><if :="grantEntries().length > 0"><div class="td-section"><div class="td-section-label">Per-env Grants</div><each :of="grantEntries()" let:item="entry"><div class="td-grant"><span class="td-grant-env">{{ entry.env }}</span><div class="td-tags"><each :of="entry.ops" let:item="op"><span class="td-tag">{{ op }}</span></each></div></div></each></div></if><if :="token.name"><div class="td-section"><div class="td-section-label">Identity</div><div class="td-identity">{{ token.name }}</div></div></if></div></if>'};
@@ -1 +1 @@
1
- const _0x2b8d68=_0xa7d9;(function(_0x440f1f,_0x2e2b73){const _0x2f8f74=_0xa7d9,_0x362110=_0x440f1f();while(!![]){try{const _0x146fc1=parseInt(_0x2f8f74(0x192))/0x1*(parseInt(_0x2f8f74(0x181))/0x2)+parseInt(_0x2f8f74(0x194))/0x3*(parseInt(_0x2f8f74(0x183))/0x4)+-parseInt(_0x2f8f74(0x197))/0x5+-parseInt(_0x2f8f74(0x177))/0x6*(-parseInt(_0x2f8f74(0x18a))/0x7)+parseInt(_0x2f8f74(0x18c))/0x8*(-parseInt(_0x2f8f74(0x17e))/0x9)+parseInt(_0x2f8f74(0x17b))/0xa*(parseInt(_0x2f8f74(0x19d))/0xb)+parseInt(_0x2f8f74(0x18f))/0xc*(-parseInt(_0x2f8f74(0x178))/0xd);if(_0x146fc1===_0x2e2b73)break;else _0x362110['push'](_0x362110['shift']());}catch(_0x3c3f99){_0x362110['push'](_0x362110['shift']());}}}(_0x5635,0x74887));function _0xa7d9(_0x156be2,_0x4a5de3){_0x156be2=_0x156be2-0x174;const _0x5635be=_0x5635();let _0xa7d96e=_0x5635be[_0x156be2];return _0xa7d96e;}function _0x5635(){const _0xafa40d=['selected','\x20permissions','536620YAZETX','token-list','<div\x20style=\x22display:\x20flex;\x20flex-direction:\x20column;\x20gap:\x202px;\x20min-height:\x200;\x20height:\x20100%;\x22><if\x20:=\x22loading\x22><div\x20style=\x22font-size:\x2011px;\x20opacity:\x200.4;\x20padding:\x208px\x2010px;\x22>Loading…</div></if><if\x20:=\x22error\x20&&\x20!loading\x22><div\x20style=\x22font-size:\x2011px;\x20color:\x20var(--okdb-danger);\x20padding:\x208px\x2010px;\x22>{{\x20error\x20}}</div></if><div\x20style=\x22flex:\x201;\x20overflow-y:\x20auto;\x20min-height:\x200;\x22><each\x20:of=\x22tokens\x22\x20let:item=\x22t\x22><button\x20:class=\x22[\x27tl-item\x27,\x20selected?.id\x20===\x20t.id\x20?\x20\x27tl-item--selected\x27\x20:\x20\x27\x27]\x22\x20@click=\x22select(t)\x22><div\x20class=\x22tl-item__body\x22><span\x20class=\x22tl-item__label\x22>{{\x20t.label\x20||\x20\x27Unnamed\x27\x20}}</span>\x20<span\x20class=\x22tl-item__sub\x22>{{\x20permSummary(t)\x20}}</span></div><if\x20:=\x22isConfig(t)\x22><span\x20class=\x22tl-config-badge\x22>Config</span></if></button></each><if\x20:=\x22!loading\x20&&\x20tokens.length\x20===\x200\x20&&\x20!error\x22><div\x20style=\x22font-size:\x2011px;\x20opacity:\x200.4;\x20padding:\x208px\x2010px;\x22>No\x20tokens\x20yet</div></if></div></div>','full\x20access','stores','error','9493cBrdvc','permissions','cluster','length','204738alwAnZ','91ruPJkq','$dispatch','selectedEnv','9920OvrxEk','json','find','45RZTzgb','loading','_selectedId','288DLOFkX','Failed\x20to\x20load\x20tokens','4cJEwlW','$ok','source','tokens','load','/auth/tokens','$watch','126amOEZN','data','261688KEsbME','includes','$attr','2913036vYNqML','message','selectedId','3279hSjYSD','Load\x20tokens\x20error','1514949gYYjPG'];_0x5635=function(){return _0xafa40d;};return _0x5635();}export default{'tag':_0x2b8d68(0x198),'attr':{'selectedId':{}},'context':_0x165e87=>({'tokens':[],'loading':!0x1,'error':null,'selected':null,'_selectedId':null,async 'load'(){const _0x48c329=_0x2b8d68;this[_0x48c329(0x17f)]=!0x0,this[_0x48c329(0x19c)]=null;try{const _0x58a526=await fetch(__ENV__['API']+_0x48c329(0x188));if(!_0x58a526['ok'])throw new Error((await _0x58a526[_0x48c329(0x17c)]())?.[_0x48c329(0x19c)]?.[_0x48c329(0x190)]||_0x48c329(0x182));const _0x281c8b=await _0x58a526[_0x48c329(0x17c)]();this[_0x48c329(0x186)]=_0x281c8b[_0x48c329(0x18b)]??[];const _0x234609=this[_0x48c329(0x180)]||_0x165e87[_0x48c329(0x18e)][_0x48c329(0x191)];if(_0x234609){const _0x41dce3=this['tokens'][_0x48c329(0x17d)](_0x2bcdf7=>_0x2bcdf7['id']===_0x234609);_0x41dce3?(this[_0x48c329(0x195)]=_0x41dce3,this['_selectedId']=_0x41dce3['id'],_0x165e87['$dispatch'](_0x48c329(0x195),_0x41dce3)):(this[_0x48c329(0x195)]=null,this[_0x48c329(0x180)]=null,_0x165e87['$dispatch'](_0x48c329(0x195),null));}}catch(_0xa93cba){this[_0x48c329(0x19c)]=_0xa93cba?.[_0x48c329(0x190)]||String(_0xa93cba),console[_0x48c329(0x19c)](_0x48c329(0x193),_0xa93cba);}finally{this[_0x48c329(0x17f)]=!0x1;}},'select'(_0x31e002){const _0x584bd5=_0x2b8d68;this[_0x584bd5(0x195)]=_0x31e002??null,this[_0x584bd5(0x180)]=_0x31e002?.['id']??null,_0x165e87[_0x584bd5(0x179)](_0x584bd5(0x195),_0x31e002??null);},'permSummary'(_0x1b5e9a){const _0x1259c0=_0x2b8d68,_0x5991c9=_0x1b5e9a[_0x1259c0(0x174)]||[];return _0x5991c9[_0x1259c0(0x18d)]('*')?_0x1259c0(0x19a):0x0===_0x5991c9[_0x1259c0(0x176)]?'no\x20permissions':0x1===_0x5991c9[_0x1259c0(0x176)]?_0x5991c9[0x0]:_0x5991c9[_0x1259c0(0x176)]+_0x1259c0(0x196);},'isConfig':_0x24f8af=>_0x2b8d68(0x175)!==_0x24f8af[_0x2b8d68(0x185)]}),'mount'(_0x2bba59){const _0x46940a=_0x2b8d68;_0x2bba59[_0x46940a(0x189)](()=>_0x2bba59[_0x46940a(0x184)][_0x46940a(0x19b)]['okdb'][_0x46940a(0x17a)],()=>this['load']()),this[_0x46940a(0x187)]();},'style':'token-list{display:flex;flex-direction:column;gap:2px;min-height:0}.tl-item{display:flex;align-items:center;gap:6px;padding:6px\x2010px;font-size:12px;background:0\x200;border:1px\x20solid\x20transparent;border-radius:7px;color:var(--okdb-app-fg-muted);text-align:left;cursor:pointer;width:100%;transition:background\x20.1s,color\x20.1s}.tl-item:hover{background:var(--okdb-app-surface-2);border-color:var(--okdb-app-border);color:var(--okdb-app-fg-strong)}.tl-item--selected{background:var(--okdb-accent-soft-bg)!important;border-color:var(--okdb-accent-soft-border)!important;color:var(--okdb-accent)!important}.tl-item__body{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}.tl-item__label,.tl-item__sub{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tl-item__label{font-size:12px;font-weight:500}.tl-item__sub{font-size:10px;opacity:.5}.tl-config-badge{font-size:9px;padding:1px\x205px;border-radius:3px;background:rgba(160,174,192,.08);border:1px\x20solid\x20rgba(160,174,192,.2);color:var(--okdb-app-fg-muted);flex-shrink:0;white-space:nowrap;text-transform:uppercase;letter-spacing:.04em}','template':_0x2b8d68(0x199)};
1
+ export default{tag:"token-list",attr:{selectedId:{}},context:e=>({tokens:[],loading:!1,error:null,selected:null,_selectedId:null,async load(){this.loading=!0,this.error=null;try{const t=await fetch(`${__ENV__.API}/auth/tokens`);if(!t.ok)throw new Error((await t.json())?.error?.message||"Failed to load tokens");const i=await t.json();this.tokens=i.data??[];const o=this._selectedId||e.$attr.selectedId;if(o){const t=this.tokens.find(e=>e.id===o);t?(this.selected=t,this._selectedId=t.id,e.$dispatch("selected",t)):(this.selected=null,this._selectedId=null,e.$dispatch("selected",null))}}catch(e){this.error=e?.message||String(e),console.error("Load tokens error",e)}finally{this.loading=!1}},select(t){this.selected=t??null,this._selectedId=t?.id??null,e.$dispatch("selected",t??null)},permSummary(e){const t=e.permissions||[];return t.includes("*")?"full access":0===t.length?"no permissions":1===t.length?t[0]:`${t.length} permissions`},isConfig:e=>"cluster"!==e.source}),mount(e){e.$watch(()=>e.$ok.stores.okdb.selectedEnv,()=>this.load()),this.load()},style:"token-list{display:flex;flex-direction:column;gap:2px;min-height:0}.tl-item{display:flex;align-items:center;gap:6px;padding:6px 10px;font-size:12px;background:0 0;border:1px solid transparent;border-radius:7px;color:var(--okdb-app-fg-muted);text-align:left;cursor:pointer;width:100%;transition:background .1s,color .1s}.tl-item:hover{background:var(--okdb-app-surface-2);border-color:var(--okdb-app-border);color:var(--okdb-app-fg-strong)}.tl-item--selected{background:var(--okdb-accent-soft-bg)!important;border-color:var(--okdb-accent-soft-border)!important;color:var(--okdb-accent)!important}.tl-item__body{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}.tl-item__label,.tl-item__sub{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tl-item__label{font-size:12px;font-weight:500}.tl-item__sub{font-size:10px;opacity:.5}.tl-config-badge{font-size:9px;padding:1px 5px;border-radius:3px;background:rgba(160,174,192,.08);border:1px solid rgba(160,174,192,.2);color:var(--okdb-app-fg-muted);flex-shrink:0;white-space:nowrap;text-transform:uppercase;letter-spacing:.04em}",template:'<div style="display: flex; flex-direction: column; gap: 2px; min-height: 0; height: 100%;"><if :="loading"><div style="font-size: 11px; opacity: 0.4; padding: 8px 10px;">Loading…</div></if><if :="error && !loading"><div style="font-size: 11px; color: var(--okdb-danger); padding: 8px 10px;">{{ error }}</div></if><div style="flex: 1; overflow-y: auto; min-height: 0;"><each :of="tokens" let:item="t"><button :class="[\'tl-item\', selected?.id === t.id ? \'tl-item--selected\' : \'\']" @click="select(t)"><div class="tl-item__body"><span class="tl-item__label">{{ t.label || \'Unnamed\' }}</span> <span class="tl-item__sub">{{ permSummary(t) }}</span></div><if :="isConfig(t)"><span class="tl-config-badge">Config</span></if></button></each><if :="!loading && tokens.length === 0 && !error"><div style="font-size: 11px; opacity: 0.4; padding: 8px 10px;">No tokens yet</div></if></div></div>'};
@@ -1 +1 @@
1
- <script type="module">import dbOverview from"./parts/db-overview.ok.js";import typeList from"./parts/type-list.ok.js";import typeViewer from"./parts/type-viewer.ok.js";import demoEnvModal from"./modals/demo-env-modal.ok.js";export default{tag:"db-index",unwrap:!0,dependencies:[typeList,typeViewer,dbOverview,demoEnvModal],context:e=>({stats:null,selectedType:null,listEl:null,_deepLinkApplied:!1,async loadStats(){const t=await fetch(e.$ok.stores.okdb.apiBase+"/info");if(t.ok){const e=await t.json().catch(()=>({}));this.stats=e?.data??e?.result??null}},urlType:()=>e.$vars.$router?._search?.type??null,applyTypeFromSearch(t=null){const s=this.urlType();if(!s)return this._deepLinkApplied=!1,!1;const p=(Array.isArray(t)&&t.length?t:e.$ok.stores.okdb.types||[]).find(e=>e?.type===s);return!!p&&(this.selectedType?.type!==s&&this.selectType(p),this._deepLinkApplied=!0,!0)},onDropped(){this.selectedType=null;const t=e.$vars.$router;t&&delete t.search.type,this.loadStats(),this.listEl.$scope.$innerContext.load()},selectType(t){this.selectedType=t;const s=this.listEl?.$scope?.$innerContext;s&&(s.selected=t??null);const p=e.$vars.$router;p&&(t?.type?p.search.type=t.type:delete p.search.type)},onTypesLoaded(e){this._deepLinkApplied&&this.selectedType?.type===this.urlType()||this.applyTypeFromSearch(e??[])}}),init(e){this.loadStats(),e.$watch(()=>e.$ok.stores.okdb.selectedEnv,()=>{this.selectType(null),this._deepLinkApplied=!1}),e.$watch(()=>e.$vars.$router?._search?.type,()=>{const t=this.urlType();if(!t)return this._deepLinkApplied=!1,void(this.selectedType&&this.selectType(null));const s=this.selectedType?.type;s!==t&&(this._deepLinkApplied=!1,this.applyTypeFromSearch(e.$ok.stores.okdb.types||[]))})}}</script><template><component import="../../layouts/_default.ok.html"><template name="header"></template><template name="sidebar"><type-list :ref="listEl = $el" @selected="selectType($event.detail)" @loaded="onTypesLoaded($event.detail)"></type-list></template><template name="default"><if :="!selectedType"><db-overview :stats="stats" @select="selectType($event.detail)"></db-overview></if><if :="selectedType"><type-viewer :type="selectedType.type" @dropped="onDropped"></type-viewer></if></template></component></template>
1
+ <script type="module">import e from"./parts/db-overview.ok.js";import t from"./parts/type-list.ok.js";import s from"./parts/type-viewer.ok.js";import p from"./modals/demo-env-modal.ok.js";export default{tag:"db-index",unwrap:!0,dependencies:[t,s,e,p],context:e=>({stats:null,selectedType:null,listEl:null,_deepLinkApplied:!1,async loadStats(){const t=await fetch(e.$ok.stores.okdb.apiBase+"/info");if(t.ok){const e=await t.json().catch(()=>({}));this.stats=e?.data??e?.result??null}},urlType:()=>e.$vars.$router?._search?.type??null,applyTypeFromSearch(t=null){const s=this.urlType();if(!s)return this._deepLinkApplied=!1,!1;const p=(Array.isArray(t)&&t.length?t:e.$ok.stores.okdb.types||[]).find(e=>e?.type===s);return!!p&&(this.selectedType?.type!==s&&this.selectType(p),this._deepLinkApplied=!0,!0)},onDropped(){this.selectedType=null;const t=e.$vars.$router;t&&delete t.search.type,this.loadStats(),this.listEl.$scope.$innerContext.load()},selectType(t){this.selectedType=t;const s=this.listEl?.$scope?.$innerContext;s&&(s.selected=t??null);const p=e.$vars.$router;p&&(t?.type?p.search.type=t.type:delete p.search.type)},onTypesLoaded(e){this._deepLinkApplied&&this.selectedType?.type===this.urlType()||this.applyTypeFromSearch(e??[])}}),init(e){this.loadStats(),e.$watch(()=>e.$ok.stores.okdb.selectedEnv,()=>{this.selectType(null),this._deepLinkApplied=!1}),e.$watch(()=>e.$vars.$router?._search?.type,()=>{const t=this.urlType();if(!t)return this._deepLinkApplied=!1,void(this.selectedType&&this.selectType(null));const s=this.selectedType?.type;s!==t&&(this._deepLinkApplied=!1,this.applyTypeFromSearch(e.$ok.stores.okdb.types||[]))})}};</script><template><component import="../../layouts/_default.ok.html"><template name="header"></template><template name="sidebar"><type-list :ref="listEl = $el" @selected="selectType($event.detail)" @loaded="onTypesLoaded($event.detail)"></type-list></template><template name="default"><if :="!selectedType"><db-overview :stats="stats" @select="selectType($event.detail)"></db-overview></if><if :="selectedType"><type-viewer :type="selectedType.type" @dropped="onDropped"></type-viewer></if></template></component></template>
@@ -1 +1 @@
1
- const _0xe16322=_0x2d7a;(function(_0x29aaa9,_0x2f9310){const _0x22526a=_0x2d7a,_0x1437c7=_0x29aaa9();while(!![]){try{const _0x16daf8=-parseInt(_0x22526a(0xc3))/0x1+parseInt(_0x22526a(0xcd))/0x2*(-parseInt(_0x22526a(0xc4))/0x3)+parseInt(_0x22526a(0xb9))/0x4*(parseInt(_0x22526a(0xb8))/0x5)+parseInt(_0x22526a(0xc0))/0x6+-parseInt(_0x22526a(0xb6))/0x7*(-parseInt(_0x22526a(0xaf))/0x8)+parseInt(_0x22526a(0xac))/0x9+-parseInt(_0x22526a(0xb7))/0xa*(parseInt(_0x22526a(0xbb))/0xb);if(_0x16daf8===_0x2f9310)break;else _0x1437c7['push'](_0x1437c7['shift']());}catch(_0x32b028){_0x1437c7['push'](_0x1437c7['shift']());}}}(_0x4151,0x79eee));import _0x11f8c8 from'@toolkit/elements/ok-icon.ok.js';function _0x2d7a(_0xf25cf,_0x5ec23e){_0xf25cf=_0xf25cf-0xa8;const _0x415122=_0x4151();let _0x2d7a07=_0x415122[_0xf25cf];return _0x2d7a07;}import _0xf8c4e8 from'@toolkit/core/ok-overlay.ok.js';function _0x4151(){const _0x538cdd=['key','apiBase','16WezNgK','json','busy','value','$ok','error','message','1600046WDbokG','4708780aplViS','25yzKzAM','677244uEaqLa','Add\x20failed','33nxxjxi','/item/','Add\x20item\x20error','PUT','shared','1823772GynVJT','application/json','stringify','177961IIVbqv','309gNPEaY','$attr','modal','okdb','success','add-item-modal','trim','stores','onDone','582oUykuO','/type/','statusText','close','\x0a<div\x20style=\x22position:relative;\x20min-width:360px;\x20display:flex;\x20flex-direction:column;\x20gap:10px;\x22>\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:32px;height:32px;\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<input\x20type=\x22text\x22\x20placeholder=\x22Key\x22\x20:value=\x22key\x22\x20@input=\x22key\x20=\x20$el.value\x22\x20/>\x0a\x0a\x20\x20<div\x20style=\x22font-size:11px;\x20opacity:.65;\x20line-height:1.45;\x22>\x0a\x20\x20\x20\x20Value\x20may\x20be\x20any\x20JSON\x20value:\x20object,\x20array,\x20string,\x20number,\x20boolean,\x20or\x20<code>null</code>.\x0a\x20\x20\x20\x20Editing\x20in\x20the\x20data\x20view\x20replaces\x20the\x20full\x20stored\x20value.\x0a\x20\x20</div>\x0a\x0a\x20\x20<ok-json-input\x0a\x20\x20\x20\x20mode=\x22textarea\x22\x0a\x20\x20\x20\x20style=\x22height:300px;\x22\x0a\x20\x20\x20\x20:value=\x22valueInit\x22\x0a\x20\x20\x20\x20@edit=\x22value\x20=\x20$event.detail\x22\x0a\x20\x20/>\x0a\x0a\x20\x20<div\x20style=\x22display:flex;\x20gap:10px;\x20justify-content:flex-end;\x22>\x0a\x20\x20\x20\x20<button\x20@click=\x22cancel()\x22>Cancel</button>\x0a\x20\x20\x20\x20<button\x20@click=\x22save()\x22\x20:disabled=\x22!key\x20||\x20value\x20===\x20undefined\x20||\x20busy\x22>Save</button>\x0a\x20\x20</div>\x0a\x0a</div>\x0a','4610997hImIJT'];_0x4151=function(){return _0x538cdd;};return _0x4151();}import _0x3029a0 from'../../../components/ok-json-input.ok.js';export default{'tag':_0xe16322(0xc9),'dependencies':[_0x3029a0,_0xf8c4e8,_0x11f8c8],'attr':{'modal':{},'type':{},'onDone':{}},'context':_0x362dd5=>({'busy':!0x1,'key':'','valueInit':{},'value':{},async 'save'(){const _0x481728=_0xe16322,_0x655f93=String(this[_0x481728(0xad)]||'')[_0x481728(0xca)]();if(_0x655f93){this[_0x481728(0xb1)]=!0x0;try{const _0x42f1f7=await fetch(_0x362dd5[_0x481728(0xb3)][_0x481728(0xcb)][_0x481728(0xc7)][_0x481728(0xae)]+_0x481728(0xa8)+_0x362dd5[_0x481728(0xc5)]['type']+_0x481728(0xbc)+encodeURIComponent(_0x655f93),{'method':_0x481728(0xbe),'headers':{'Content-Type':_0x481728(0xc1)},'body':JSON[_0x481728(0xc2)](this[_0x481728(0xb2)])});if(!_0x42f1f7['ok'])throw new Error((await _0x42f1f7[_0x481728(0xb0)]())?.[_0x481728(0xb4)]?.[_0x481728(0xb5)]||_0x42f1f7[_0x481728(0xa9)]);await _0x362dd5['$ok'][_0x481728(0xcb)][_0x481728(0xc7)]['reloadTypes'](),_0x362dd5[_0x481728(0xb3)][_0x481728(0xbf)]?.['toast']?.[_0x481728(0xc8)]?.('Item\x20added'),await _0x362dd5[_0x481728(0xc5)][_0x481728(0xc6)][_0x481728(0xaa)](),await _0x362dd5[_0x481728(0xc5)][_0x481728(0xcc)]?.({'key':_0x655f93,'value':this[_0x481728(0xb2)]});}catch(_0x2230d1){_0x362dd5[_0x481728(0xb3)][_0x481728(0xbf)]?.['toast']?.[_0x481728(0xb4)]?.(_0x2230d1?.[_0x481728(0xb5)]||_0x481728(0xba)),console['error'](_0x481728(0xbd),_0x2230d1);}finally{this['busy']=!0x1;}}},'cancel'(){const _0x2f1586=_0xe16322;_0x362dd5[_0x2f1586(0xc5)][_0x2f1586(0xc6)]['close']();}}),'template':_0xe16322(0xab)};
1
+ import e from"@toolkit/elements/ok-icon.ok.js";import t from"@toolkit/core/ok-overlay.ok.js";import n from"../../../components/ok-json-input.ok.js";export default{tag:"add-item-modal",dependencies:[n,t,e],attr:{modal:{},type:{},onDone:{}},context:e=>({busy:!1,key:"",valueInit:{},value:{},async save(){const t=String(this.key||"").trim();if(t){this.busy=!0;try{const n=await fetch(`${e.$ok.stores.okdb.apiBase}/type/${e.$attr.type}/item/${encodeURIComponent(t)}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(this.value)});if(!n.ok)throw new Error((await n.json())?.error?.message||n.statusText);await e.$ok.stores.okdb.reloadTypes(),e.$ok.shared?.toast?.success?.("Item added"),await e.$attr.modal.close(),await(e.$attr.onDone?.({key:t,value:this.value}))}catch(t){e.$ok.shared?.toast?.error?.(t?.message||"Add failed"),console.error("Add item error",t)}finally{this.busy=!1}}},cancel(){e.$attr.modal.close()}}),template:'\n<div style="position:relative; min-width:360px; display:flex; flex-direction:column; gap:10px;">\n\n <if :="busy">\n <ok-overlay>\n <div class="loader-center">\n <ok-icon name="loader" class="spin" style="width:32px;height:32px;"></ok-icon>\n </div>\n </ok-overlay>\n </if>\n\n <input type="text" placeholder="Key" :value="key" @input="key = $el.value" />\n\n <div style="font-size:11px; opacity:.65; line-height:1.45;">\n Value may be any JSON value: object, array, string, number, boolean, or <code>null</code>.\n Editing in the data view replaces the full stored value.\n </div>\n\n <ok-json-input\n mode="textarea"\n style="height:300px;"\n :value="valueInit"\n @edit="value = $event.detail"\n />\n\n <div style="display:flex; gap:10px; justify-content:flex-end;">\n <button @click="cancel()">Cancel</button>\n <button @click="save()" :disabled="!key || value === undefined || busy">Save</button>\n </div>\n\n</div>\n'};
@@ -1 +1 @@
1
- function _0x4877(){const _0x1d918e=['onDone','54IYZtrC','5690100WHINOG','4782656pclkxW','name','Failed\x20to\x20create\x20environment','7227yyTZkf','5GwLULY','26984111JdXCkZ','busy','create-env-modal','$attr','486073kIXTpm','4336wnUYOk','13123RdIMuM','trim','statusText','4292373QAnFwc','message','modal','112aaUFPD','close','\x0a<div\x20style=\x22min-width:340px;\x20display:flex;\x20flex-direction:column;\x20gap:14px;\x22>\x0a\x0a\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:4px;\x22>\x0a\x20\x20\x20\x20<label\x20style=\x22font-size:12px;\x20opacity:.6;\x22>Environment\x20name</label>\x0a\x20\x20\x20\x20<input\x0a\x20\x20\x20\x20\x20\x20type=\x22text\x22\x0a\x20\x20\x20\x20\x20\x20placeholder=\x22e.g.\x20staging,\x20analytics,\x20archive\x22\x0a\x20\x20\x20\x20\x20\x20:value=\x22name\x22\x0a\x20\x20\x20\x20\x20\x20@input=\x22name\x20=\x20$el.value\x22\x0a\x20\x20\x20\x20\x20\x20@keydown.enter=\x22save()\x22\x0a\x20\x20\x20\x20\x20\x20autofocus\x0a\x20\x20\x20\x20\x20\x20style=\x22font-family:monospace;\x22\x0a\x20\x20\x20\x20/>\x0a\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20opacity:.45;\x20margin-top:2px;\x22>\x0a\x20\x20\x20\x20\x20\x20Use\x20letters,\x20numbers,\x20hyphens.\x20Prefix\x20with\x20<code>~</code>\x20for\x20system\x20envs.\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</div>\x0a\x0a\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:8px;\x22>\x0a\x20\x20\x20\x20<label\x20style=\x22display:flex;\x20align-items:center;\x20gap:8px;\x20cursor:pointer;\x20font-size:13px;\x20user-select:none;\x22>\x0a\x20\x20\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x20:checked=\x22sync\x22\x20@change=\x22sync\x20=\x20$event.target.checked\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20<span>Sync-enabled\x20<span\x20style=\x22opacity:.5;\x20font-size:11px;\x22>(HLC\x20clock\x20+\x20changelog)</span></span>\x0a\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20<label\x20style=\x22display:flex;\x20align-items:center;\x20gap:8px;\x20cursor:pointer;\x20font-size:13px;\x20user-select:none;\x22>\x0a\x20\x20\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x20:checked=\x22compression\x22\x20@change=\x22compression\x20=\x20$event.target.checked\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20<span>Compression\x20<span\x20style=\x22opacity:.5;\x20font-size:11px;\x22>(smaller\x20on\x20disk,\x20slight\x20CPU\x20overhead)</span></span>\x0a\x20\x20\x20\x20</label>\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:6px\x2010px;\x20background:var(--okdb-danger-deep-bg);\x20border-radius:4px;\x20border:1px\x20solid\x20color-mix(in\x20srgb,\x20var(--okdb-danger)\x2020%,\x20transparent);\x22>\x0a\x20\x20\x20\x20\x20\x20{{\x20error\x20}}\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<div\x20style=\x22display:flex;\x20gap:8px;\x20justify-content:flex-end;\x20padding-top:4px;\x20border-top:1px\x20solid\x20var(--okdb-app-border);\x22>\x0a\x20\x20\x20\x20<button\x20@click=\x22cancel()\x22>Cancel</button>\x0a\x20\x20\x20\x20<button\x20class=\x22btn-primary\x22\x20@click=\x22save()\x22\x20:disabled=\x22!canSave\x22>\x0a\x20\x20\x20\x20\x20\x20{{\x20busy\x20?\x20\x27Creating…\x27\x20:\x20\x27Create\x27\x20}}\x0a\x20\x20\x20\x20</button>\x0a\x20\x20</div>\x0a\x0a</div>','length','error'];_0x4877=function(){return _0x1d918e;};return _0x4877();}const _0x1e89d1=_0x9a35;(function(_0x1f101a,_0x50a41f){const _0x1e7919=_0x9a35,_0x1a1ede=_0x1f101a();while(!![]){try{const _0x15b566=parseInt(_0x1e7919(0x12d))/0x1*(-parseInt(_0x1e7919(0x11a))/0x2)+-parseInt(_0x1e7919(0x117))/0x3+parseInt(_0x1e7919(0x122))/0x4*(-parseInt(_0x1e7919(0x126))/0x5)+parseInt(_0x1e7919(0x120))/0x6*(parseInt(_0x1e7919(0x12b))/0x7)+-parseInt(_0x1e7919(0x12c))/0x8*(-parseInt(_0x1e7919(0x125))/0x9)+parseInt(_0x1e7919(0x121))/0xa+parseInt(_0x1e7919(0x127))/0xb;if(_0x15b566===_0x50a41f)break;else _0x1a1ede['push'](_0x1a1ede['shift']());}catch(_0x5977b9){_0x1a1ede['push'](_0x1a1ede['shift']());}}}(_0x4877,0xb0031));function _0x9a35(_0x1ef3de,_0xb9e756){_0x1ef3de=_0x1ef3de-0x116;const _0x4877be=_0x4877();let _0x9a35c7=_0x4877be[_0x1ef3de];return _0x9a35c7;}export default{'tag':_0x1e89d1(0x129),'attr':{'modal':{},'onDone':{}},'context':_0x27d38f=>({'busy':!0x1,'name':'','sync':!0x0,'compression':!0x0,'error':null,get 'canSave'(){const _0x163ef0=_0x1e89d1;return this[_0x163ef0(0x123)]['trim']()[_0x163ef0(0x11d)]>0x0&&!this[_0x163ef0(0x128)];},async 'save'(){const _0x282587=_0x1e89d1,_0x38d6d7=this['name'][_0x282587(0x12e)]();if(_0x38d6d7){this[_0x282587(0x11e)]=null,this[_0x282587(0x128)]=!0x0;try{const _0x35c364=await fetch(__ENV__['API']+'/envs',{'method':'POST','headers':{'Content-Type':'application/json'},'body':JSON['stringify']({'name':_0x38d6d7,'sync':this['sync'],'compression':this['compression']})});if(!_0x35c364['ok']){const _0x3fe26c=await _0x35c364['json']()['catch'](()=>({}));throw new Error(_0x3fe26c?.['error']?.['message']||_0x35c364[_0x282587(0x116)]);}await _0x27d38f[_0x282587(0x12a)][_0x282587(0x119)][_0x282587(0x11b)](),await _0x27d38f['$attr'][_0x282587(0x11f)]?.(_0x38d6d7);}catch(_0x996964){this[_0x282587(0x11e)]=_0x996964?.[_0x282587(0x118)]||_0x282587(0x124);}finally{this[_0x282587(0x128)]=!0x1;}}},'cancel'(){const _0x76d419=_0x1e89d1;_0x27d38f['$attr'][_0x76d419(0x119)][_0x76d419(0x11b)]();}}),'template':_0x1e89d1(0x11c)};
1
+ export default{tag:"create-env-modal",attr:{modal:{},onDone:{}},context:e=>({busy:!1,name:"",sync:!0,compression:!0,error:null,get canSave(){return this.name.trim().length>0&&!this.busy},async save(){const n=this.name.trim();if(n){this.error=null,this.busy=!0;try{const t=await fetch(`${__ENV__.API}/envs`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:n,sync:this.sync,compression:this.compression})});if(!t.ok){const e=await t.json().catch(()=>({}));throw new Error(e?.error?.message||t.statusText)}await e.$attr.modal.close(),await(e.$attr.onDone?.(n))}catch(e){this.error=e?.message||"Failed to create environment"}finally{this.busy=!1}}},cancel(){e.$attr.modal.close()}}),template:'\n<div style="min-width:340px; display:flex; flex-direction:column; gap:14px;">\n\n <div style="display:flex; flex-direction:column; gap:4px;">\n <label style="font-size:12px; opacity:.6;">Environment name</label>\n <input\n type="text"\n placeholder="e.g. staging, analytics, archive"\n :value="name"\n @input="name = $el.value"\n @keydown.enter="save()"\n autofocus\n style="font-family:monospace;"\n />\n <div style="font-size:11px; opacity:.45; margin-top:2px;">\n Use letters, numbers, hyphens. Prefix with <code>~</code> for system envs.\n </div>\n </div>\n\n <div style="display:flex; flex-direction:column; gap:8px;">\n <label style="display:flex; align-items:center; gap:8px; cursor:pointer; font-size:13px; user-select:none;">\n <input type="checkbox" :checked="sync" @change="sync = $event.target.checked" />\n <span>Sync-enabled <span style="opacity:.5; font-size:11px;">(HLC clock + changelog)</span></span>\n </label>\n <label style="display:flex; align-items:center; gap:8px; cursor:pointer; font-size:13px; user-select:none;">\n <input type="checkbox" :checked="compression" @change="compression = $event.target.checked" />\n <span>Compression <span style="opacity:.5; font-size:11px;">(smaller on disk, slight CPU overhead)</span></span>\n </label>\n </div>\n\n <if :="error">\n <div style="color:var(--okdb-danger); font-size:13px; padding:6px 10px; background:var(--okdb-danger-deep-bg); border-radius:4px; border:1px solid color-mix(in srgb, var(--okdb-danger) 20%, transparent);">\n {{ error }}\n </div>\n </if>\n\n <div style="display:flex; gap:8px; justify-content:flex-end; padding-top:4px; border-top:1px solid var(--okdb-app-border);">\n <button @click="cancel()">Cancel</button>\n <button class="btn-primary" @click="save()" :disabled="!canSave">\n {{ busy ? \'Creating…\' : \'Create\' }}\n </button>\n </div>\n\n</div>'};
@@ -1 +1 @@
1
- const _0xb79aee=_0x5e19;function _0x5e19(_0x37ac92,_0x53a219){_0x37ac92=_0x37ac92-0x155;const _0x26e571=_0x26e5();let _0x5e1923=_0x26e571[_0x37ac92];return _0x5e1923;}(function(_0x4da62f,_0x23ff1d){const _0x154a7d=_0x5e19,_0x308106=_0x4da62f();while(!![]){try{const _0x754717=parseInt(_0x154a7d(0x159))/0x1+-parseInt(_0x154a7d(0x17c))/0x2+parseInt(_0x154a7d(0x15b))/0x3*(-parseInt(_0x154a7d(0x171))/0x4)+parseInt(_0x154a7d(0x162))/0x5+parseInt(_0x154a7d(0x156))/0x6+parseInt(_0x154a7d(0x173))/0x7+parseInt(_0x154a7d(0x158))/0x8;if(_0x754717===_0x23ff1d)break;else _0x308106['push'](_0x308106['shift']());}catch(_0x20105f){_0x308106['push'](_0x308106['shift']());}}}(_0x26e5,0x87351));import _0x1c6a5c from'@toolkit/elements/ok-icon.ok.js';function _0x26e5(){const _0x1efdfe=['$attr','busy','keys','indexOf','includes','every','error','minTokenLength','derivedName','close','17944xOLGcL','API','5733273DhCYwI','filter','modal','join','\x0a<div\x20style=\x22position:relative;\x20min-width:380px;\x20display:flex;\x20flex-direction:column;\x20gap:14px;\x22>\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:32px;height:32px;\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<!--\x20Whole-document\x20shortcut\x20-->\x0a\x20\x20<label\x20style=\x22display:flex;\x20align-items:center;\x20gap:8px;\x20cursor:pointer;\x20font-size:13px;\x20user-select:none;\x22>\x0a\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x20:checked=\x22wholeDoc\x22\x20@change=\x22wholeDoc\x20=\x20$event.target.checked\x22\x20/>\x0a\x20\x20\x20\x20<span>Search\x20entire\x20document\x20<span\x20style=\x22opacity:.5;\x20font-size:11px;\x22>(indexes\x20all\x20fields\x20recursively)</span></span>\x0a\x20\x20</label>\x0a\x0a\x20\x20<!--\x20Field\x20picker\x20—\x20hidden\x20when\x20wholeDoc\x20is\x20checked\x20-->\x0a\x20\x20<if\x20:=\x22!wholeDoc\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:8px;\x22>\x0a\x0a\x20\x20\x20\x20\x20\x20<label\x20style=\x22font-size:12px;\x20opacity:.6;\x22>Fields\x20to\x20index</label>\x0a\x0a\x20\x20\x20\x20\x20\x20<!--\x20Input\x20row\x20-->\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20gap:8px;\x20align-items:center;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22flex:1;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<field-path-input\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:value=\x22selected\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:items=\x22items\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20placeholder=\x22Field\x20path,\x20e.g.\x20title\x20or\x20content.body\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@change=\x22selected\x20=\x20$event.detail\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22addField()\x22\x20:disabled=\x22!selected\x20||\x20fields.includes(selected)\x22>+</button>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20<!--\x20Selected\x20fields\x20tags\x20-->\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-wrap:wrap;\x20gap:6px;\x20min-height:24px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<each\x20:of=\x22fields\x22\x20let:item=\x22f\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22background:var(--okdb-app-border);\x20padding:3px\x208px;\x20border-radius:4px;\x20font-size:12px;\x20display:flex;\x20align-items:center;\x20gap:4px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20f\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\x20\x20\x20\x20style=\x22cursor:pointer;\x20font-weight:bold;\x20opacity:.6;\x20line-height:1;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@click=\x22removeField(f)\x22>×</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</each>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20:style=\x22fields.length\x20===\x200\x20?\x20\x27opacity:.35;\x20font-size:12px;\x27\x20:\x20\x27display:none\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(no\x20fields\x20selected)\x0a\x20\x20\x20\x20\x20\x20\x20\x20</span>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<!--\x20Whole-doc\x20summary\x20when\x20checked\x20-->\x0a\x20\x20<if\x20:=\x22wholeDoc\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22font-size:12px;\x20opacity:.5;\x20padding:4px\x200;\x22>\x0a\x20\x20\x20\x20\x20\x20All\x20scalar\x20leaf\x20values\x20(strings,\x20numbers,\x20booleans)\x20will\x20be\x20tokenized\x20and\x20indexed.\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<!--\x20Derived\x20name\x20display\x20-->\x0a\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:4px;\x22>\x0a\x20\x20\x20\x20<label\x20style=\x22font-size:12px;\x20opacity:.6;\x22>\x0a\x20\x20\x20\x20\x20\x20Index\x20name\x0a\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.55;\x20font-size:11px;\x20font-weight:normal;\x22>(auto-derived\x20from\x20fields)</span>\x0a\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20<div\x20style=\x22font-size:13px;\x20color:var(--okdb-accent);\x20font-family:monospace;\x20padding:6px\x2010px;\x20background:var(--okdb-app-bg-deep);\x20border-radius:4px;\x20border:1px\x20solid\x20var(--okdb-app-border);\x20min-height:30px;\x20display:flex;\x20align-items:center;\x22>\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22derivedName\x22>{{\x20derivedName\x20}}</if>\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22!derivedName\x22><span\x20style=\x22opacity:.3;\x20font-style:italic;\x22>select\x20fields\x20first</span></if>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</div>\x0a\x0a\x20\x20<!--\x20Optional\x20label\x20override\x20-->\x0a\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:4px;\x22>\x0a\x20\x20\x20\x20<label\x20style=\x22font-size:12px;\x20opacity:.6;\x22>\x0a\x20\x20\x20\x20\x20\x20Custom\x20label\x0a\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.45;\x20font-size:11px;\x20font-weight:normal;\x22>(optional\x20—\x20overrides\x20the\x20auto\x20name\x20above)</span>\x0a\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20<input\x0a\x20\x20\x20\x20\x20\x20type=\x22text\x22\x0a\x20\x20\x20\x20\x20\x20placeholder=\x22e.g.\x20full,\x20title-search\x22\x0a\x20\x20\x20\x20\x20\x20:value=\x22label\x22\x0a\x20\x20\x20\x20\x20\x20@input=\x22label\x20=\x20$el.value\x22\x0a\x20\x20\x20\x20/>\x0a\x20\x20</div>\x0a\x0a\x20\x20<!--\x20Tokenizer\x20options\x20accordion\x20-->\x0a\x20\x20<div>\x0a\x20\x20\x20\x20<div\x0a\x20\x20\x20\x20\x20\x20@click=\x22tokenizerOpen\x20=\x20!tokenizerOpen\x22\x0a\x20\x20\x20\x20\x20\x20style=\x22display:flex;\x20align-items:center;\x20gap:6px;\x20cursor:pointer;\x20font-size:12px;\x20opacity:.7;\x20user-select:none;\x20padding:4px\x200;\x22>\x0a\x20\x20\x20\x20\x20\x20<ok-icon\x0a\x20\x20\x20\x20\x20\x20\x20\x20:name=\x22tokenizerOpen\x20?\x20\x27chevron-down\x27\x20:\x20\x27chevron-right\x27\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20style=\x22width:12px;height:12px;\x22>\x0a\x20\x20\x20\x20\x20\x20</ok-icon>\x0a\x20\x20\x20\x20\x20\x20Tokenizer\x20options\x0a\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20<if\x20:=\x22tokenizerOpen\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:grid;\x20grid-template-columns:160px\x201fr;\x20gap:6px\x2012px;\x20font-size:13px;\x20padding:8px\x200\x200\x2016px;\x22>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.6;\x20align-self:center;\x22>Min\x20token\x20length</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<input\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type=\x22number\x22\x20min=\x221\x22\x20max=\x2220\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:value=\x22minTokenLength\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@input=\x22minTokenLength\x20=\x20+$el.value\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22width:70px;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20/>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.6;\x20align-self:center;\x22>Max\x20token\x20length</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<input\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type=\x22number\x22\x20min=\x224\x22\x20max=\x22256\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:value=\x22maxTokenLength\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@input=\x22maxTokenLength\x20=\x20+$el.value\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22width:70px;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20/>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.6;\x20align-self:center;\x22>Lowercase</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<label\x20style=\x22display:flex;\x20align-items:center;\x20gap:6px;\x20cursor:pointer;\x20user-select:none;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x20:checked=\x22toLower\x22\x20@change=\x22toLower\x20=\x20$event.target.checked\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:12px;\x20opacity:.6;\x22>convert\x20tokens\x20to\x20lowercase</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</label>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.6;\x20align-self:center;\x22>Keep\x20numbers</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<label\x20style=\x22display:flex;\x20align-items:center;\x20gap:6px;\x20cursor:pointer;\x20user-select:none;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x20:checked=\x22keepNumbers\x22\x20@change=\x22keepNumbers\x20=\x20$event.target.checked\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:12px;\x20opacity:.6;\x22>index\x20numeric\x20tokens</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</label>\x0a\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</if>\x0a\x20\x20</div>\x0a\x0a\x20\x20<!--\x20Actions\x20-->\x0a\x20\x20<div\x20style=\x22display:flex;\x20gap:8px;\x20justify-content:flex-end;\x20padding-top:4px;\x20border-top:1px\x20solid\x20var(--okdb-app-border);\x22>\x0a\x20\x20\x20\x20<button\x20@click=\x22cancel()\x22>Cancel</button>\x0a\x20\x20\x20\x20<button\x0a\x20\x20\x20\x20\x20\x20class=\x22btn-primary\x22\x0a\x20\x20\x20\x20\x20\x20@click=\x22save()\x22\x0a\x20\x20\x20\x20\x20\x20:disabled=\x22!canSave\x20||\x20busy\x22>\x0a\x20\x20\x20\x20\x20\x20Create\x0a\x20\x20\x20\x20</button>\x0a\x20\x20</div>\x0a\x0a</div>','message','deepPaths','push','effectiveFields','1538604Oelmvr','actualName','possibleFields','fields','/type/','toast','object','json','173304ftWgKt','label','5742264icrYvN','142392NuJpIt','trim','588KhvIck','onDone','application/json','maxTokenLength','toLower','Create\x20FTS\x20index\x20failed','canSave','2471345WxYGAo','length','wholeDoc','Create\x20FTS\x20error','selected'];_0x26e5=function(){return _0x1efdfe;};return _0x26e5();}import _0x19ce51 from'@toolkit/core/ok-overlay.ok.js';import _0x341f2b from'../../../components/field-path-input.ok.js';export default{'tag':'create-fts-modal','dependencies':[_0x341f2b,_0x19ce51,_0x1c6a5c],'attr':{'modal':{},'type':{},'apiBase':{},'deepPaths':{},'possibleFields':{},'onDone':{}},'context':_0x83dec9=>({'busy':!0x1,'label':'','fields':[],'selected':'','wholeDoc':!0x1,'tokenizerOpen':!0x1,'minTokenLength':0x2,'maxTokenLength':0x40,'toLower':!0x0,'keepNumbers':!0x0,get 'items'(){const _0x35a99d=_0x5e19,_0x5a48a8=_0x83dec9[_0x35a99d(0x167)][_0x35a99d(0x179)];return _0x5a48a8&&'object'==typeof _0x5a48a8&&Object[_0x35a99d(0x169)](_0x5a48a8)[_0x35a99d(0x163)]?Object['entries'](_0x5a48a8)[_0x35a99d(0x174)](([,_0x5b8981])=>!_0x5b8981[_0x35a99d(0x16c)](_0x150d5b=>_0x35a99d(0x182)===_0x150d5b||'geo'===_0x150d5b))['map'](([_0x25dc3b,_0x506dcc])=>({'path':_0x25dc3b,'types':_0x506dcc,'hint':null})):(_0x83dec9[_0x35a99d(0x167)][_0x35a99d(0x17e)]??[])['map'](_0x10e1c2=>({'path':_0x10e1c2,'types':['string'],'hint':null}));},get 'effectiveFields'(){const _0x548a36=_0x5e19;return this[_0x548a36(0x164)]?['*']:this[_0x548a36(0x17f)];},get 'derivedName'(){const _0xb1d806=_0x5e19;return this[_0xb1d806(0x164)]?'*':this['fields'][_0xb1d806(0x176)](',');},get 'actualName'(){const _0x18f4df=_0x5e19;return this[_0x18f4df(0x157)]['trim']()||this[_0x18f4df(0x16f)];},get 'canSave'(){const _0x445b0a=_0x5e19;return this['effectiveFields'][_0x445b0a(0x163)]>0x0;},'addField'(){const _0x212def=_0x5e19,_0x1b7241=String(this[_0x212def(0x166)]||'')[_0x212def(0x15a)]();_0x1b7241&&!this[_0x212def(0x17f)][_0x212def(0x16b)](_0x1b7241)&&(this['fields'][_0x212def(0x17a)](_0x1b7241),this['selected']='');},'removeField'(_0x33ec6e){const _0x59d506=_0x5e19,_0x16cfcd=this[_0x59d506(0x17f)][_0x59d506(0x16a)](_0x33ec6e);_0x16cfcd>=0x0&&this['fields']['splice'](_0x16cfcd,0x1);},async 'save'(){const _0x51a270=_0x5e19;if(this[_0x51a270(0x161)]){this[_0x51a270(0x168)]=!0x0;try{const _0x8eca91={'fields':this[_0x51a270(0x17b)],'tokenizer':{'minTokenLength':Number(this[_0x51a270(0x16e)]),'maxTokenLength':Number(this[_0x51a270(0x15e)]),'toLower':this[_0x51a270(0x15f)],'keepNumbers':this['keepNumbers']}},_0x477ddd=_0x83dec9['$attr']['apiBase']||__ENV__[_0x51a270(0x172)],_0x18ff7a=await fetch(_0x477ddd+_0x51a270(0x180)+_0x83dec9[_0x51a270(0x167)]['type']+'/fts/'+encodeURIComponent(this[_0x51a270(0x17d)]),{'method':'POST','headers':{'Content-Type':_0x51a270(0x15d)},'body':JSON['stringify'](_0x8eca91)});if(!_0x18ff7a['ok'])throw new Error((await _0x18ff7a[_0x51a270(0x155)]())?.['error']?.[_0x51a270(0x178)]||_0x18ff7a['statusText']);await _0x83dec9[_0x51a270(0x167)][_0x51a270(0x175)][_0x51a270(0x170)](),await _0x83dec9[_0x51a270(0x167)][_0x51a270(0x15c)]?.();}catch(_0x3637b5){_0x83dec9['$ok']['shared']?.[_0x51a270(0x181)]?.[_0x51a270(0x16d)]?.(_0x3637b5?.[_0x51a270(0x178)]||_0x51a270(0x160)),console[_0x51a270(0x16d)](_0x51a270(0x165),_0x3637b5);}finally{this['busy']=!0x1;}}},'cancel'(){const _0x3b4f72=_0x5e19;_0x83dec9[_0x3b4f72(0x167)][_0x3b4f72(0x175)][_0x3b4f72(0x170)]();}}),'template':_0xb79aee(0x177)};
1
+ import e from"@toolkit/elements/ok-icon.ok.js";import n from"@toolkit/core/ok-overlay.ok.js";import t from"../../../components/field-path-input.ok.js";export default{tag:"create-fts-modal",dependencies:[t,n,e],attr:{modal:{},type:{},apiBase:{},deepPaths:{},possibleFields:{},onDone:{}},context:e=>({busy:!1,label:"",fields:[],selected:"",wholeDoc:!1,tokenizerOpen:!1,minTokenLength:2,maxTokenLength:64,toLower:!0,keepNumbers:!0,get items(){const n=e.$attr.deepPaths;return n&&"object"==typeof n&&Object.keys(n).length?Object.entries(n).filter(([,e])=>!e.every(e=>"object"===e||"geo"===e)).map(([e,n])=>({path:e,types:n,hint:null})):(e.$attr.possibleFields??[]).map(e=>({path:e,types:["string"],hint:null}))},get effectiveFields(){return this.wholeDoc?["*"]:this.fields},get derivedName(){return this.wholeDoc?"*":this.fields.join(",")},get actualName(){return this.label.trim()||this.derivedName},get canSave(){return this.effectiveFields.length>0},addField(){const e=String(this.selected||"").trim();e&&!this.fields.includes(e)&&(this.fields.push(e),this.selected="")},removeField(e){const n=this.fields.indexOf(e);n>=0&&this.fields.splice(n,1)},async save(){if(this.canSave){this.busy=!0;try{const n={fields:this.effectiveFields,tokenizer:{minTokenLength:Number(this.minTokenLength),maxTokenLength:Number(this.maxTokenLength),toLower:this.toLower,keepNumbers:this.keepNumbers}},t=e.$attr.apiBase||__ENV__.API,i=await fetch(`${t}/type/${e.$attr.type}/fts/${encodeURIComponent(this.actualName)}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)});if(!i.ok)throw new Error((await i.json())?.error?.message||i.statusText);await e.$attr.modal.close(),await(e.$attr.onDone?.())}catch(n){e.$ok.shared?.toast?.error?.(n?.message||"Create FTS index failed"),console.error("Create FTS error",n)}finally{this.busy=!1}}},cancel(){e.$attr.modal.close()}}),template:'\n<div style="position:relative; min-width:380px; display:flex; flex-direction:column; gap:14px;">\n\n <if :="busy">\n <ok-overlay>\n <div class="loader-center">\n <ok-icon name="loader" class="spin" style="width:32px;height:32px;"></ok-icon>\n </div>\n </ok-overlay>\n </if>\n\n \x3c!-- Whole-document shortcut --\x3e\n <label style="display:flex; align-items:center; gap:8px; cursor:pointer; font-size:13px; user-select:none;">\n <input type="checkbox" :checked="wholeDoc" @change="wholeDoc = $event.target.checked" />\n <span>Search entire document <span style="opacity:.5; font-size:11px;">(indexes all fields recursively)</span></span>\n </label>\n\n \x3c!-- Field picker — hidden when wholeDoc is checked --\x3e\n <if :="!wholeDoc">\n <div style="display:flex; flex-direction:column; gap:8px;">\n\n <label style="font-size:12px; opacity:.6;">Fields to index</label>\n\n \x3c!-- Input row --\x3e\n <div style="display:flex; gap:8px; align-items:center;">\n <div style="flex:1;">\n <field-path-input\n :value="selected"\n :items="items"\n placeholder="Field path, e.g. title or content.body"\n @change="selected = $event.detail"\n />\n </div>\n <button @click="addField()" :disabled="!selected || fields.includes(selected)">+</button>\n </div>\n\n \x3c!-- Selected fields tags --\x3e\n <div style="display:flex; flex-wrap:wrap; gap:6px; min-height:24px;">\n <each :of="fields" let:item="f">\n <span style="background:var(--okdb-app-border); padding:3px 8px; border-radius:4px; font-size:12px; display:flex; align-items:center; gap:4px;">\n {{ f }}\n <span\n style="cursor:pointer; font-weight:bold; opacity:.6; line-height:1;"\n @click="removeField(f)">×</span>\n </span>\n </each>\n <span :style="fields.length === 0 ? \'opacity:.35; font-size:12px;\' : \'display:none\'">\n (no fields selected)\n </span>\n </div>\n\n </div>\n </if>\n\n \x3c!-- Whole-doc summary when checked --\x3e\n <if :="wholeDoc">\n <div style="font-size:12px; opacity:.5; padding:4px 0;">\n All scalar leaf values (strings, numbers, booleans) will be tokenized and indexed.\n </div>\n </if>\n\n \x3c!-- Derived name display --\x3e\n <div style="display:flex; flex-direction:column; gap:4px;">\n <label style="font-size:12px; opacity:.6;">\n Index name\n <span style="opacity:.55; font-size:11px; font-weight:normal;">(auto-derived from fields)</span>\n </label>\n <div style="font-size:13px; color:var(--okdb-accent); font-family:monospace; padding:6px 10px; background:var(--okdb-app-bg-deep); border-radius:4px; border:1px solid var(--okdb-app-border); min-height:30px; display:flex; align-items:center;">\n <if :="derivedName">{{ derivedName }}</if>\n <if :="!derivedName"><span style="opacity:.3; font-style:italic;">select fields first</span></if>\n </div>\n </div>\n\n \x3c!-- Optional label override --\x3e\n <div style="display:flex; flex-direction:column; gap:4px;">\n <label style="font-size:12px; opacity:.6;">\n Custom label\n <span style="opacity:.45; font-size:11px; font-weight:normal;">(optional — overrides the auto name above)</span>\n </label>\n <input\n type="text"\n placeholder="e.g. full, title-search"\n :value="label"\n @input="label = $el.value"\n />\n </div>\n\n \x3c!-- Tokenizer options accordion --\x3e\n <div>\n <div\n @click="tokenizerOpen = !tokenizerOpen"\n style="display:flex; align-items:center; gap:6px; cursor:pointer; font-size:12px; opacity:.7; user-select:none; padding:4px 0;">\n <ok-icon\n :name="tokenizerOpen ? \'chevron-down\' : \'chevron-right\'"\n style="width:12px;height:12px;">\n </ok-icon>\n Tokenizer options\n </div>\n\n <if :="tokenizerOpen">\n <div style="display:grid; grid-template-columns:160px 1fr; gap:6px 12px; font-size:13px; padding:8px 0 0 16px;">\n\n <span style="opacity:.6; align-self:center;">Min token length</span>\n <input\n type="number" min="1" max="20"\n :value="minTokenLength"\n @input="minTokenLength = +$el.value"\n style="width:70px;"\n />\n\n <span style="opacity:.6; align-self:center;">Max token length</span>\n <input\n type="number" min="4" max="256"\n :value="maxTokenLength"\n @input="maxTokenLength = +$el.value"\n style="width:70px;"\n />\n\n <span style="opacity:.6; align-self:center;">Lowercase</span>\n <label style="display:flex; align-items:center; gap:6px; cursor:pointer; user-select:none;">\n <input type="checkbox" :checked="toLower" @change="toLower = $event.target.checked" />\n <span style="font-size:12px; opacity:.6;">convert tokens to lowercase</span>\n </label>\n\n <span style="opacity:.6; align-self:center;">Keep numbers</span>\n <label style="display:flex; align-items:center; gap:6px; cursor:pointer; user-select:none;">\n <input type="checkbox" :checked="keepNumbers" @change="keepNumbers = $event.target.checked" />\n <span style="font-size:12px; opacity:.6;">index numeric tokens</span>\n </label>\n\n </div>\n </if>\n </div>\n\n \x3c!-- Actions --\x3e\n <div style="display:flex; gap:8px; justify-content:flex-end; padding-top:4px; border-top:1px solid var(--okdb-app-border);">\n <button @click="cancel()">Cancel</button>\n <button\n class="btn-primary"\n @click="save()"\n :disabled="!canSave || busy">\n Create\n </button>\n </div>\n\n</div>'};
@@ -1 +1 @@
1
- function _0x81fb(){const _0x308c00=['18955057qUnkmg','create-index-modal','application/json','entries','$attr','unique','splice','isGeo','busy','geoSet','geoFields','stores','possibleFields','parts','string','113074ctdXnr','/type/','geo','modal','precision','type','has','statusText','deepPaths','message','join','indexOf','trim','map','1434378Gfqhej','POST','/index/','isArray','31770NWBTDa','2862yrHKwL','Create\x20index\x20error','shared','stringify','26665wjrjiO','length','error','12zgevqI','json','keys','1316vBlctW','okdb','$ok','includes','4767590tijLfg','11200nDcmby','\x0a<div\x20style=\x22position:relative;\x20min-width:380px;\x20display:flex;\x20flex-direction:column;\x20gap:14px;\x22>\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:32px;height:32px;\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<!--\x20Field\x20picker\x20-->\x0a\x20\x20<div>\x0a\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20opacity:.5;\x20margin-bottom:6px;\x20text-transform:uppercase;\x20letter-spacing:.05em;\x22>Fields</div>\x0a\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20gap:8px;\x20align-items:center;\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22flex:1;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<field-path-input\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:value=\x22selected\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:items=\x22items\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20placeholder=\x22Field\x20path\x20(dot-notation)\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@change=\x22selected\x20=\x20$event.detail\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20/>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20<button\x20@click=\x22addPart()\x22\x20:disabled=\x22!selected\x20||\x20parts.includes(selected)\x22>+\x20Add</button>\x0a\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20<!--\x20Parts\x20chips\x20-->\x0a\x20\x20\x20\x20<div\x20style=\x22margin-top:8px;\x20min-height:28px;\x20display:flex;\x20align-items:center;\x20gap:6px;\x20flex-wrap:wrap;\x22>\x0a\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:12px;\x20opacity:.4;\x20user-select:none;\x22>Index:</span>\x0a\x20\x20\x20\x20\x20\x20<each\x20:of=\x22parts\x22\x20let:item=\x22p\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22background:var(--okdb-app-border);\x20padding:3px\x208px;\x20border-radius:4px;\x20font-size:12px;\x20display:inline-flex;\x20align-items:center;\x20gap:4px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20p\x20}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22cursor:pointer;\x20opacity:.6;\x20font-weight:bold;\x22\x20@click=\x22removePart(p)\x22>×</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</span>\x0a\x20\x20\x20\x20\x20\x20</each>\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22isGeo\x20&&\x20parts.length\x20>\x200\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:10px;\x20color:var(--okdb-success);\x20opacity:.7;\x22>◎\x20geo</span>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22isUnique\x20&&\x20!isGeo\x20&&\x20parts.length\x20>\x200\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:10px;\x20color:var(--okdb-warning);\x20opacity:.7;\x22>◆\x20unique</span>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.3;\x20font-size:12px;\x22\x20:style=\x22parts.length\x20?\x20\x27display:none\x27\x20:\x20\x27\x27\x22>(none\x20yet)</span>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</div>\x0a\x0a\x20\x20<!--\x20Index\x20type\x20options\x20-->\x0a\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:6px;\x22>\x0a\x0a\x20\x20\x20\x20<label\x20style=\x22font-size:12px;\x20display:flex;\x20align-items:center;\x20gap:6px;\x20cursor:pointer;\x20user-select:none;\x22>\x0a\x20\x20\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x20:checked=\x22isGeo\x22\x20@change=\x22onGeoToggle($event.target.checked)\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20◎\x20Geo\x20index\x0a\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.4;\x20font-size:11px;\x22>(field\x20stores\x20<code\x20style=\x22font-size:11px;\x22>{\x20lat,\x20lon\x20}</code>\x20coordinates)</span>\x0a\x20\x20\x20\x20</label>\x0a\x0a\x20\x20\x20\x20<if\x20:=\x22isGeo\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20align-items:center;\x20gap:8px;\x20padding-left:22px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:11px;\x20opacity:.5;\x22>Precision</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22range\x22\x20min=\x224\x22\x20max=\x229\x22\x20step=\x221\x22\x20:value=\x22precision\x22\x20@input=\x22precision\x20=\x20Number($event.target.value)\x22\x20style=\x22width:120px;\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:12px;\x20min-width:16px;\x22>{{\x20precision\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:11px;\x20opacity:.35;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20precision\x20<=\x206\x20?\x20\x27~\x27\x20+\x20[39,\x204.9,\x201.2][precision\x20-\x204]\x20+\x20\x27\x20km\x20cells\x27\x20:\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27~\x27\x20+\x20[153,\x2038,\x204.8][precision\x20-\x207]\x20+\x20\x27\x20m\x20cells\x27\x20}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20</span>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20<label\x20style=\x22font-size:12px;\x20display:flex;\x20align-items:center;\x20gap:6px;\x20cursor:pointer;\x20user-select:none;\x22\x20:style=\x22isGeo\x20?\x20\x27opacity:.35;\x20pointer-events:none;\x27\x20:\x20\x27\x27\x22>\x0a\x20\x20\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x20:checked=\x22isUnique\x22\x20:disabled=\x22isGeo\x22\x20@change=\x22isUnique\x20=\x20$event.target.checked\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20◆\x20Unique\x20index\x0a\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.4;\x20font-size:11px;\x22>(enforces\x20one\x20record\x20per\x20index\x20key)</span>\x0a\x20\x20\x20\x20</label>\x0a\x0a\x20\x20</div>\x0a\x0a\x20\x20<div\x20style=\x22display:flex;\x20gap:8px;\x20justify-content:flex-end;\x20padding-top:4px;\x20border-top:1px\x20solid\x20var(--okdb-app-border);\x22>\x0a\x20\x20\x20\x20<button\x20@click=\x22cancel()\x22>Cancel</button>\x0a\x20\x20\x20\x20<button\x20@click=\x22save()\x22\x20:disabled=\x22!parts.length\x20||\x20busy\x22>Create\x20Index</button>\x0a\x20\x20</div>\x0a\x0a</div>\x0a','10kvFqCb','2824IYcBpK'];_0x81fb=function(){return _0x308c00;};return _0x81fb();}function _0x969e(_0x542dc4,_0xb430c9){_0x542dc4=_0x542dc4-0x11e;const _0x81fb56=_0x81fb();let _0x969e0b=_0x81fb56[_0x542dc4];return _0x969e0b;}const _0x41f1a7=_0x969e;(function(_0x1ac050,_0xfeb985){const _0x35241e=_0x969e,_0x4a8507=_0x1ac050();while(!![]){try{const _0xe154ad=-parseInt(_0x35241e(0x14c))/0x1*(parseInt(_0x35241e(0x13b))/0x2)+-parseInt(_0x35241e(0x125))/0x3+parseInt(_0x35241e(0x134))/0x4*(parseInt(_0x35241e(0x12e))/0x5)+parseInt(_0x35241e(0x12a))/0x6*(-parseInt(_0x35241e(0x139))/0x7)+parseInt(_0x35241e(0x13c))/0x8*(-parseInt(_0x35241e(0x129))/0x9)+parseInt(_0x35241e(0x138))/0xa+-parseInt(_0x35241e(0x13d))/0xb*(-parseInt(_0x35241e(0x131))/0xc);if(_0xe154ad===_0xfeb985)break;else _0x4a8507['push'](_0x4a8507['shift']());}catch(_0x34dca9){_0x4a8507['push'](_0x4a8507['shift']());}}}(_0x81fb,0xdc255));import _0x14e8bf from'@toolkit/elements/ok-icon.ok.js';import _0x55a5a8 from'@toolkit/core/ok-overlay.ok.js';import _0x1b4800 from'../../../components/field-path-input.ok.js';export default{'tag':_0x41f1a7(0x13e),'dependencies':[_0x1b4800,_0x55a5a8,_0x14e8bf],'attr':{'modal':{},'type':{},'deepPaths':{},'geoFields':{},'onDone':{}},'context':_0x559000=>({'busy':!0x1,'parts':[],'selected':'','isGeo':!0x1,'isUnique':!0x1,'precision':0x7,get 'items'(){const _0x4e0fce=_0x41f1a7,_0x4e9418=_0x559000[_0x4e0fce(0x141)][_0x4e0fce(0x11f)];if(_0x4e9418&&'object'==typeof _0x4e9418&&Object[_0x4e0fce(0x133)](_0x4e9418)[_0x4e0fce(0x12f)])return Object[_0x4e0fce(0x140)](_0x4e9418)[_0x4e0fce(0x124)](([_0x286cb9,_0x4b68f4])=>({'path':_0x286cb9,'types':Array[_0x4e0fce(0x128)](_0x4b68f4)?_0x4b68f4:[],'hint':Array[_0x4e0fce(0x128)](_0x4b68f4)&&_0x4b68f4['includes'](_0x4e0fce(0x14e))?'geo':null}));const _0x29d43f=new Set(_0x559000[_0x4e0fce(0x141)][_0x4e0fce(0x147)]??[]);return(_0x559000[_0x4e0fce(0x141)][_0x4e0fce(0x149)]??[])[_0x4e0fce(0x124)](_0x22af7a=>({'path':_0x22af7a,'types':_0x29d43f['has'](_0x22af7a)?[_0x4e0fce(0x14e)]:[_0x4e0fce(0x14b)],'hint':_0x29d43f['has'](_0x22af7a)?'geo':null}));},get 'geoSet'(){const _0x3843e4=_0x41f1a7;return new Set(_0x559000['$attr'][_0x3843e4(0x147)]??[]);},'addPart'(){const _0x1fbb5a=_0x41f1a7,_0x55d09b=String(this['selected']||'')[_0x1fbb5a(0x123)]();_0x55d09b&&!this['parts'][_0x1fbb5a(0x137)](_0x55d09b)&&(this[_0x1fbb5a(0x14a)]['push'](_0x55d09b),this[_0x1fbb5a(0x146)][_0x1fbb5a(0x152)](_0x55d09b)&&(this[_0x1fbb5a(0x144)]=!0x0,this['isUnique']=!0x1),this['selected']='');},'removePart'(_0x21c2b7){const _0x5d486d=_0x41f1a7,_0x5cc723=this[_0x5d486d(0x14a)][_0x5d486d(0x122)](_0x21c2b7);_0x5cc723>=0x0&&this[_0x5d486d(0x14a)][_0x5d486d(0x143)](_0x5cc723,0x1);},'onGeoToggle'(_0x29fac3){const _0x21e94a=_0x41f1a7;this[_0x21e94a(0x144)]=!!_0x29fac3,this[_0x21e94a(0x144)]&&(this['isUnique']=!0x1);},async 'save'(){const _0x336d15=_0x41f1a7;if(this[_0x336d15(0x14a)][_0x336d15(0x12f)]){this['busy']=!0x0;try{const _0x4eafae={};this[_0x336d15(0x144)]&&(_0x4eafae[_0x336d15(0x151)]=_0x336d15(0x14e),_0x4eafae[_0x336d15(0x150)]=this[_0x336d15(0x150)]),this['isUnique']&&!this[_0x336d15(0x144)]&&(_0x4eafae[_0x336d15(0x142)]=!0x0);const _0x5dd6ea={'method':_0x336d15(0x126),...Object[_0x336d15(0x133)](_0x4eafae)['length']?{'headers':{'Content-Type':_0x336d15(0x13f)},'body':JSON[_0x336d15(0x12d)](_0x4eafae)}:{}},_0x187b0=await fetch(_0x559000[_0x336d15(0x136)][_0x336d15(0x148)][_0x336d15(0x135)]['apiBase']+_0x336d15(0x14d)+_0x559000[_0x336d15(0x141)][_0x336d15(0x151)]+_0x336d15(0x127)+this[_0x336d15(0x14a)][_0x336d15(0x121)]('~'),_0x5dd6ea);if(!_0x187b0['ok'])throw new Error((await _0x187b0[_0x336d15(0x132)]())?.[_0x336d15(0x130)]?.[_0x336d15(0x120)]||_0x187b0[_0x336d15(0x11e)]);await _0x559000['$attr'][_0x336d15(0x14f)]['close'](),await _0x559000[_0x336d15(0x141)]['onDone']?.();}catch(_0x2e2b66){_0x559000[_0x336d15(0x136)][_0x336d15(0x12c)]?.['toast']?.[_0x336d15(0x130)]?.(_0x2e2b66?.[_0x336d15(0x120)]||'Create\x20index\x20failed'),console[_0x336d15(0x130)](_0x336d15(0x12b),_0x2e2b66);}finally{this[_0x336d15(0x145)]=!0x1;}}},'cancel'(){const _0x2e8195=_0x41f1a7;_0x559000[_0x2e8195(0x141)][_0x2e8195(0x14f)]['close']();}}),'template':_0x41f1a7(0x13a)};
1
+ import e from"@toolkit/elements/ok-icon.ok.js";import t from"@toolkit/core/ok-overlay.ok.js";import n from"../../../components/field-path-input.ok.js";export default{tag:"create-index-modal",dependencies:[n,t,e],attr:{modal:{},type:{},deepPaths:{},geoFields:{},onDone:{}},context:e=>({busy:!1,parts:[],selected:"",isGeo:!1,isUnique:!1,precision:7,get items(){const t=e.$attr.deepPaths;if(t&&"object"==typeof t&&Object.keys(t).length)return Object.entries(t).map(([e,t])=>({path:e,types:Array.isArray(t)?t:[],hint:Array.isArray(t)&&t.includes("geo")?"geo":null}));const n=new Set(e.$attr.geoFields??[]);return(e.$attr.possibleFields??[]).map(e=>({path:e,types:n.has(e)?["geo"]:["string"],hint:n.has(e)?"geo":null}))},get geoSet(){return new Set(e.$attr.geoFields??[])},addPart(){const e=String(this.selected||"").trim();e&&!this.parts.includes(e)&&(this.parts.push(e),this.geoSet.has(e)&&(this.isGeo=!0,this.isUnique=!1),this.selected="")},removePart(e){const t=this.parts.indexOf(e);t>=0&&this.parts.splice(t,1)},onGeoToggle(e){this.isGeo=!!e,this.isGeo&&(this.isUnique=!1)},async save(){if(this.parts.length){this.busy=!0;try{const t={};this.isGeo&&(t.type="geo",t.precision=this.precision),this.isUnique&&!this.isGeo&&(t.unique=!0);const n={method:"POST",...Object.keys(t).length?{headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}:{}},i=await fetch(`${e.$ok.stores.okdb.apiBase}/type/${e.$attr.type}/index/${this.parts.join("~")}`,n);if(!i.ok)throw new Error((await i.json())?.error?.message||i.statusText);await e.$attr.modal.close(),await(e.$attr.onDone?.())}catch(t){e.$ok.shared?.toast?.error?.(t?.message||"Create index failed"),console.error("Create index error",t)}finally{this.busy=!1}}},cancel(){e.$attr.modal.close()}}),template:'\n<div style="position:relative; min-width:380px; display:flex; flex-direction:column; gap:14px;">\n\n <if :="busy">\n <ok-overlay>\n <div class="loader-center">\n <ok-icon name="loader" class="spin" style="width:32px;height:32px;"></ok-icon>\n </div>\n </ok-overlay>\n </if>\n\n \x3c!-- Field picker --\x3e\n <div>\n <div style="font-size:11px; opacity:.5; margin-bottom:6px; text-transform:uppercase; letter-spacing:.05em;">Fields</div>\n <div style="display:flex; gap:8px; align-items:center;">\n <div style="flex:1;">\n <field-path-input\n :value="selected"\n :items="items"\n placeholder="Field path (dot-notation)"\n @change="selected = $event.detail"\n />\n </div>\n <button @click="addPart()" :disabled="!selected || parts.includes(selected)">+ Add</button>\n </div>\n\n \x3c!-- Parts chips --\x3e\n <div style="margin-top:8px; min-height:28px; display:flex; align-items:center; gap:6px; flex-wrap:wrap;">\n <span style="font-size:12px; opacity:.4; user-select:none;">Index:</span>\n <each :of="parts" let:item="p">\n <span style="background:var(--okdb-app-border); padding:3px 8px; border-radius:4px; font-size:12px; display:inline-flex; align-items:center; gap:4px;">\n {{ p }}\n <span style="cursor:pointer; opacity:.6; font-weight:bold;" @click="removePart(p)">×</span>\n </span>\n </each>\n <if :="isGeo && parts.length > 0">\n <span style="font-size:10px; color:var(--okdb-success); opacity:.7;">◎ geo</span>\n </if>\n <if :="isUnique && !isGeo && parts.length > 0">\n <span style="font-size:10px; color:var(--okdb-warning); opacity:.7;">◆ unique</span>\n </if>\n <span style="opacity:.3; font-size:12px;" :style="parts.length ? \'display:none\' : \'\'">(none yet)</span>\n </div>\n </div>\n\n \x3c!-- Index type options --\x3e\n <div style="display:flex; flex-direction:column; gap:6px;">\n\n <label style="font-size:12px; display:flex; align-items:center; gap:6px; cursor:pointer; user-select:none;">\n <input type="checkbox" :checked="isGeo" @change="onGeoToggle($event.target.checked)" />\n ◎ Geo index\n <span style="opacity:.4; font-size:11px;">(field stores <code style="font-size:11px;">{ lat, lon }</code> coordinates)</span>\n </label>\n\n <if :="isGeo">\n <div style="display:flex; align-items:center; gap:8px; padding-left:22px;">\n <span style="font-size:11px; opacity:.5;">Precision</span>\n <input type="range" min="4" max="9" step="1" :value="precision" @input="precision = Number($event.target.value)" style="width:120px;" />\n <span style="font-size:12px; min-width:16px;">{{ precision }}</span>\n <span style="font-size:11px; opacity:.35;">\n {{ precision <= 6 ? \'~\' + [39, 4.9, 1.2][precision - 4] + \' km cells\' :\n \'~\' + [153, 38, 4.8][precision - 7] + \' m cells\' }}\n </span>\n </div>\n </if>\n\n <label style="font-size:12px; display:flex; align-items:center; gap:6px; cursor:pointer; user-select:none;" :style="isGeo ? \'opacity:.35; pointer-events:none;\' : \'\'">\n <input type="checkbox" :checked="isUnique" :disabled="isGeo" @change="isUnique = $event.target.checked" />\n ◆ Unique index\n <span style="opacity:.4; font-size:11px;">(enforces one record per index key)</span>\n </label>\n\n </div>\n\n <div style="display:flex; gap:8px; justify-content:flex-end; padding-top:4px; border-top:1px solid var(--okdb-app-border);">\n <button @click="cancel()">Cancel</button>\n <button @click="save()" :disabled="!parts.length || busy">Create Index</button>\n </div>\n\n</div>\n'};
@@ -1 +1 @@
1
- function _0x1027(_0x53ff35,_0x582602){_0x53ff35=_0x53ff35-0x117;var _0x2c01b8=_0x2c01();var _0x10279a=_0x2c01b8[_0x53ff35];return _0x10279a;}var _0x1e06b3=_0x1027;(function(_0x3058b8,_0x3857ca){var _0x3d6eb2=_0x1027,_0x5cd958=_0x3058b8();while(!![]){try{var _0x5ee9fc=-parseInt(_0x3d6eb2(0x118))/0x1*(parseInt(_0x3d6eb2(0x11a))/0x2)+parseInt(_0x3d6eb2(0x11c))/0x3+-parseInt(_0x3d6eb2(0x127))/0x4*(-parseInt(_0x3d6eb2(0x117))/0x5)+-parseInt(_0x3d6eb2(0x11b))/0x6*(parseInt(_0x3d6eb2(0x125))/0x7)+parseInt(_0x3d6eb2(0x11d))/0x8*(parseInt(_0x3d6eb2(0x126))/0x9)+-parseInt(_0x3d6eb2(0x128))/0xa+-parseInt(_0x3d6eb2(0x11f))/0xb*(-parseInt(_0x3d6eb2(0x119))/0xc);if(_0x5ee9fc===_0x3857ca)break;else _0x5cd958['push'](_0x5cd958['shift']());}catch(_0x357c06){_0x5cd958['push'](_0x5cd958['shift']());}}}(_0x2c01,0x39c00));import _0x1dac17 from'../../embeddings/parts/pipeline-create-panel.ok.js';function _0x2c01(){var _0x496a2d=['modal','203RUWUXQ','20457lllpDu','47868qyCGHB','3648700mDTZrM','onDone','trim','165zlYuCC','11qyHGeu','3088212Sjtnyc','59992fVJUqL','66696wUPulA','733833rdCDjg','1256vqyjGv','env','11gXvetJ','type','close','default','create-pipeline-modal'];_0x2c01=function(){return _0x496a2d;};return _0x2c01();}export default{'tag':_0x1e06b3(0x123),'dependencies':[_0x1dac17],'attr':{'modal':{},'type':{},'env':{},'onDone':{}},'context':_0x32f8f0=>({get 'typeName'(){var _0x40983d=_0x1e06b3;return String(_0x32f8f0['$attr'][_0x40983d(0x120)]||'')[_0x40983d(0x12a)]();},get 'envName'(){var _0x3b23e4=_0x1e06b3;return String(_0x32f8f0['$attr'][_0x3b23e4(0x11e)]||'')[_0x3b23e4(0x12a)]()||_0x3b23e4(0x122);},async 'onCreated'(_0xde5957){var _0xb1ca69=_0x1e06b3;await _0x32f8f0['$attr'][_0xb1ca69(0x124)]?.[_0xb1ca69(0x121)]?.(),await _0x32f8f0['$attr'][_0xb1ca69(0x129)]?.(_0xde5957);}}),'template':'\x0a<div\x20style=\x22width:min(92vw,\x20920px);\x20max-width:920px;\x20max-height:min(88vh,\x20960px);\x20overflow:auto;\x20display:flex;\x20flex-direction:column;\x20gap:12px;\x20padding-right:4px;\x22>\x0a\x20\x20<div\x20style=\x22font-size:12px;\x20opacity:.55;\x20line-height:1.6;\x22>\x0a\x20\x20\x20\x20Creating\x20a\x20pipeline\x20for\x20<b>{{\x20typeName\x20}}</b>\x20in\x20<b>{{\x20envName\x20}}</b>.\x0a\x20\x20\x20\x20The\x20source\x20type\x20stays\x20locked\x20in\x20this\x20contextual\x20DB\x20flow,\x20and\x20queue\x20workers\x20remain\x20available\x20from\x20the\x20Queue\x20section.\x0a\x20\x20</div>\x0a\x0a\x20\x20<pipeline-create-panel\x0a\x20\x20\x20\x20:locktype=\x22typeName\x22\x0a\x20\x20\x20\x20:lockenv=\x22envName\x22\x0a\x20\x20\x20\x20:locktypestrict=\x22true\x22\x0a\x20\x20\x20\x20:hidequeueworker=\x22true\x22\x0a\x20\x20\x20\x20@created=\x22onCreated($event.detail)\x22\x0a\x20\x20/>\x0a</div>'};
1
+ import e from"../../embeddings/parts/pipeline-create-panel.ok.js";export default{tag:"create-pipeline-modal",dependencies:[e],attr:{modal:{},type:{},env:{},onDone:{}},context:e=>({get typeName(){return String(e.$attr.type||"").trim()},get envName(){return String(e.$attr.env||"").trim()||"default"},async onCreated(t){await(e.$attr.modal?.close?.()),await(e.$attr.onDone?.(t))}}),template:'\n<div style="width:min(92vw, 920px); max-width:920px; max-height:min(88vh, 960px); overflow:auto; display:flex; flex-direction:column; gap:12px; padding-right:4px;">\n <div style="font-size:12px; opacity:.55; line-height:1.6;">\n Creating a pipeline for <b>{{ typeName }}</b> in <b>{{ envName }}</b>.\n The source type stays locked in this contextual DB flow, and queue workers remain available from the Queue section.\n </div>\n\n <pipeline-create-panel\n :locktype="typeName"\n :lockenv="envName"\n :locktypestrict="true"\n :hidequeueworker="true"\n @created="onCreated($event.detail)"\n />\n</div>'};