@kedem/okdb 1.0.1 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/okdb.js +1 -1
- package/keys/public.pem +3 -0
- package/okdb.js +1 -1
- package/package.json +2 -2
- package/public/admin-app.js +1 -1
- package/public/components/admin-route-host.ok.js +1 -1
- package/public/components/env-picker.ok.js +1 -1
- package/public/components/field-path-input.ok.js +1 -1
- package/public/components/field.html +154 -2
- package/public/components/geo-map.ok.js +1 -1
- package/public/components/ok-cron-input.ok.js +1 -1
- package/public/components/ok-dropzone.ok.js +1 -1
- package/public/components/ok-js-input.ok.js +1 -1
- package/public/components/ok-json-input.ok.js +1 -1
- package/public/components/ok-text-monaco-input.ok.js +1 -1
- package/public/components/theme-toggle.ok.js +1 -1
- package/public/index.html +29 -2
- package/public/layouts/_default.ok.html +1 -1
- package/public/layouts/okdb-cube.ok.html +1 -1
- package/public/login-app.js +1 -1
- package/public/login.html +205 -1
- package/public/modules/ok.js +1 -1
- package/public/sections/api/index.ok.html +1 -1
- package/public/sections/api/parts/api-endpoint.ok.js +1 -1
- package/public/sections/auth/index.ok.html +1 -1
- package/public/sections/auth/modals/create-token-modal.ok.js +1 -1
- package/public/sections/auth/modals/edit-token-modal.ok.js +1 -1
- package/public/sections/auth/modals/perm-info-popover.ok.js +1 -1
- package/public/sections/auth/parts/token-detail.ok.js +1 -1
- package/public/sections/auth/parts/token-list.ok.js +1 -1
- package/public/sections/db/index.ok.html +1 -1
- package/public/sections/db/modals/add-item-modal.ok.js +1 -1
- package/public/sections/db/modals/create-env-modal.ok.js +1 -1
- package/public/sections/db/modals/create-fts-modal.ok.js +1 -1
- package/public/sections/db/modals/create-index-modal.ok.js +1 -1
- package/public/sections/db/modals/create-pipeline-modal.ok.js +1 -1
- package/public/sections/db/modals/demo-env-modal.ok.js +1 -1
- package/public/sections/db/modals/remove-env-modal.ok.js +1 -1
- package/public/sections/db/modals/schema-edit-modal.ok.js +1 -1
- package/public/sections/db/parts/db-overview.ok.js +1 -1
- package/public/sections/db/parts/db-pipelines-panel.ok.js +1 -1
- package/public/sections/db/parts/edit-row.ok.js +1 -1
- package/public/sections/db/parts/tm-timeline.ok.js +1 -1
- package/public/sections/db/parts/type-changelog.ok.js +1 -1
- package/public/sections/db/parts/type-list.ok.js +1 -1
- package/public/sections/db/parts/type-pipelines-tab.ok.js +1 -1
- package/public/sections/db/parts/type-schema-tab.ok.js +1 -1
- package/public/sections/db/parts/type-viewer.ok.js +1 -1
- package/public/sections/db/parts/type-violations-tab.ok.js +1 -1
- package/public/sections/docs/index.ok.html +1 -1
- package/public/sections/embeddings/index.ok.html +1 -1
- package/public/sections/embeddings/modals/register-model-modal.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-create-panel.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-embedder-panel.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-engine-declaration-editor.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-engine-list.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-indexer-panel.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-lifecycle-bar.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-model-catalog.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-overview.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-search-panel.ok.js +1 -1
- package/public/sections/embeddings/parts/embed-worker-panel.ok.js +1 -1
- package/public/sections/embeddings/parts/embeddings-engine-panel.ok.js +1 -1
- package/public/sections/embeddings/parts/engines-overview.ok.js +1 -1
- package/public/sections/embeddings/parts/pipeline-create-panel.ok.js +1 -1
- package/public/sections/engines/engine-panel-shared-style.js +1 -1
- package/public/sections/engines/engine-ui-utils.js +1 -1
- package/public/sections/engines/index.ok.html +1 -1
- package/public/sections/engines/modals/engine-modal.ok.js +1 -1
- package/public/sections/engines/parts/engine-declaration-editor.ok.js +1 -1
- package/public/sections/engines/parts/engine-lifecycle-actions.ok.js +1 -1
- package/public/sections/engines/parts/engine-panel-shell.ok.js +1 -1
- package/public/sections/engines/parts/engine-resource-card.ok.js +1 -1
- package/public/sections/engines/parts/engine-row-item.ok.js +1 -1
- package/public/sections/engines/parts/generic-engine-panel.ok.js +1 -1
- package/public/sections/files/index.ok.html +1 -1
- package/public/sections/files/parts/files-blob-status.ok.js +1 -1
- package/public/sections/files/parts/files-collection-list.ok.js +1 -1
- package/public/sections/files/parts/files-collection-panel.ok.js +1 -1
- package/public/sections/files/parts/files-file-list.ok.js +1 -1
- package/public/sections/files/parts/files-overview.ok.js +1 -1
- package/public/sections/files/parts/files-path-browser.ok.js +1 -1
- package/public/sections/files/parts/files-upload-panel.ok.js +1 -1
- package/public/sections/functions/index.ok.html +1 -1
- package/public/sections/functions/modals/function-modal.ok.js +1 -1
- package/public/sections/functions/parts/function-detail.ok.js +1 -1
- package/public/sections/functions/parts/function-logs.ok.js +1 -1
- package/public/sections/functions/parts/function-runner.ok.js +1 -1
- package/public/sections/functions/parts/functions-list.ok.js +1 -1
- package/public/sections/license/index.ok.html +1 -1
- package/public/sections/license/parts/license-panel.ok.js +1 -1
- package/public/sections/processors/index.ok.html +1 -1
- package/public/sections/queue/index.ok.html +1 -1
- package/public/sections/queue/modals/create-bucket-modal.ok.js +1 -1
- package/public/sections/queue/modals/edit-bucket-modal.ok.js +1 -1
- package/public/sections/queue/modals/edit-job-modal.ok.js +1 -1
- package/public/sections/queue/modals/enqueue-job-modal.ok.js +1 -1
- package/public/sections/queue/modals/job-type-modal.ok.js +1 -1
- package/public/sections/queue/parts/ok-job-form.ok.js +1 -1
- package/public/sections/queue/parts/queue-buckets.ok.js +1 -1
- package/public/sections/queue/parts/queue-job-types.ok.js +1 -1
- package/public/sections/queue/parts/queue-jobs.ok.js +1 -1
- package/public/sections/queue/parts/queue-types.ok.js +1 -1
- package/public/sections/queue/parts/queue-workers.ok.js +1 -1
- package/public/sections/sync/index.ok.html +1 -1
- package/public/sections/sync/parts/sync-node-detail.ok.js +1 -1
- package/public/sections/sync/parts/sync-retention.ok.js +1 -1
- package/public/sections/sync/parts/sync-topology.ok.js +1 -1
- package/public/sections/system/index.ok.html +1 -1
- package/public/sections/system/modals/data-ops-modal.ok.js +1 -1
- package/public/sections/system/parts/system-api-panel.ok.js +1 -1
- package/public/sections/system/parts/system-auth-panel.ok.js +1 -1
- package/public/sections/system/parts/system-log-history.ok.js +1 -1
- package/public/sections/system/parts/system-log.ok.js +1 -1
- package/public/sections/system/parts/system-status.ok.js +1 -1
- package/public/sections/system/parts/system-sync-panel.ok.js +1 -1
- package/public/sections/views/index.ok.html +1 -1
- package/public/sections/views/modals/create-view-modal.ok.js +1 -1
- package/public/sections/views/parts/view-detail.ok.js +1 -1
- package/public/sections/views/parts/views-list.ok.js +1 -1
- package/public/sections/views/parts/views-overview.ok.js +1 -1
- package/public/setup-app.js +1 -1
- package/public/setup.html +189 -1
- package/public/stores/auth-store.js +1 -1
- package/public/stores/events-store.js +1 -1
- package/public/stores/functions-store.js +1 -1
- package/public/stores/okdb-store.js +1 -1
- package/public/stores/theme-store.js +1 -1
- package/public/test-cron-input.html +53 -3
- package/public/test-json-input.html +182 -3
- package/public/util/permissions.js +1 -1
- package/public/util/sift-schema.js +1 -1
- package/public/vendor/okjs/ok.esm.min.js +1 -2
- package/public/view-models/type-query-vm.js +1 -1
- package/okdb-data/default/data.mdb +0 -0
- package/okdb-data/default/lock.mdb +0 -0
- package/okdb-data/~log/data.mdb +0 -0
- package/okdb-data/~log/lock.mdb +0 -0
- package/okdb-data/~system/data.mdb +0 -0
- package/okdb-data/~system/lock.mdb +0 -0
- package/public/images/logo.png +0 -0
- package/public/images/logo.svg +0 -333
|
@@ -1 +1 @@
|
|
|
1
|
-
function _0x5ca0(_0x173836,_0x169f20){_0x173836=_0x173836-0xb5;const _0x34b308=_0x34b3();let _0x5ca02c=_0x34b308[_0x173836];return _0x5ca02c;}const _0x52e649=_0x5ca0;(function(_0x419f57,_0x3cf62b){const _0x476027=_0x5ca0,_0x353ec0=_0x419f57();while(!![]){try{const _0x1d3c93=-parseInt(_0x476027(0xca))/0x1+-parseInt(_0x476027(0xe9))/0x2*(-parseInt(_0x476027(0xe2))/0x3)+-parseInt(_0x476027(0xb6))/0x4*(-parseInt(_0x476027(0xb7))/0x5)+-parseInt(_0x476027(0xb9))/0x6*(-parseInt(_0x476027(0xd0))/0x7)+-parseInt(_0x476027(0xd4))/0x8*(parseInt(_0x476027(0xe3))/0x9)+-parseInt(_0x476027(0xc8))/0xa*(-parseInt(_0x476027(0xdf))/0xb)+parseInt(_0x476027(0xe1))/0xc*(parseInt(_0x476027(0xc9))/0xd);if(_0x1d3c93===_0x3cf62b)break;else _0x353ec0['push'](_0x353ec0['shift']());}catch(_0x436173){_0x353ec0['push'](_0x353ec0['shift']());}}}(_0x34b3,0x3bcea));import _0x13db8b from'./files-upload-panel.ok.js';function _0x34b3(){const _0x4b4afc=['files','&recursive=true&limit=2000','#16a34a','audio/','18010xOqStQ','#ca8a04','catch','path','#0891b2','files:uploaded','refresh','video/','filter','\x0a<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:0;\x20height:100%;\x20min-height:0;\x22>\x0a\x0a\x20\x20<!--\x20──\x20Toolbar\x20───────────────────────────────────────────────────────\x20-->\x0a\x20\x20<div\x20style=\x22display:flex;\x20align-items:center;\x20justify-content:space-between;\x20gap:8px;\x20flex-wrap:wrap;\x20margin-bottom:10px;\x20flex-shrink:0;\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20align-items:center;\x20gap:8px;\x22>\x0a\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-family:monospace;\x20font-size:14px;\x20font-weight:700;\x20color:var(--okdb-accent);\x22>{{\x20path\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:11px;\x20opacity:.4;\x20font-family:monospace;\x22>{{\x20files.length\x20}}\x20file(s)</span>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20gap:6px;\x22>\x0a\x20\x20\x20\x20\x20\x20<button\x0a\x20\x20\x20\x20\x20\x20\x20\x20@click=\x22showUpload\x20=\x20!showUpload\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20:style=\x22showUpload\x20?\x20\x27font-size:12px;\x20background:var(--okdb-sky-soft-bg);\x20border-color:var(--okdb-sky-soft-border);\x20color:var(--okdb-sky);\x27\x20:\x20\x27font-size:12px;\x27\x22\x0a\x20\x20\x20\x20\x20\x20>{{\x20showUpload\x20?\x20\x27✕\x20Close\x20upload\x27\x20:\x20\x27↑\x20Upload\x27\x20}}</button>\x0a\x20\x20\x20\x20\x20\x20<button\x20@click=\x22load()\x22\x20:disabled=\x22busy\x22\x20style=\x22font-size:12px;\x20opacity:.7;\x22>↻</button>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</div>\x0a\x0a\x20\x20<!--\x20──\x20Upload\x20panel\x20──────────────────────────────────────────────────\x20-->\x0a\x20\x20<if\x20:=\x22showUpload\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22flex-shrink:0;\x20margin-bottom:10px;\x20padding:12px;\x20background:var(--okdb-app-bg-deep);\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:8px;\x22>\x0a\x20\x20\x20\x20\x20\x20<files-upload-panel\x0a\x20\x20\x20\x20\x20\x20\x20\x20:path=\x22path\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20@uploaded=\x22onUploaded()\x22\x0a\x20\x20\x20\x20\x20\x20/>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<!--\x20──\x20Error\x20──────────────────────────────────────────────────────────\x20-->\x0a\x20\x20<if\x20:=\x22error\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22flex-shrink:0;\x20color:var(--okdb-danger);\x20font-size:12px;\x20margin-bottom:8px;\x20padding:6px\x2010px;\x20border:1px\x20solid\x20color-mix(in\x20srgb,\x20var(--okdb-danger)\x2020%,\x20transparent);\x20border-radius:6px;\x20background:var(--okdb-danger-soft-bg);\x22>\x0a\x20\x20\x20\x20\x20\x20{{\x20error\x20}}\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<!--\x20──\x20Loading\x20────────────────────────────────────────────────────────\x20-->\x0a\x20\x20<if\x20:=\x22busy\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22flex-shrink:0;\x20font-size:12px;\x20opacity:.4;\x20padding:8px\x200;\x22>Loading…</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<!--\x20──\x20Empty\x20state\x20────────────────────────────────────────────────────\x20-->\x0a\x20\x20<if\x20:=\x22!busy\x20&&\x20files.length\x20===\x200\x20&&\x20!error\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22flex:1;\x20display:flex;\x20flex-direction:column;\x20align-items:center;\x20justify-content:center;\x20gap:12px;\x20opacity:.45;\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:32px;\x22>📂</div>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:13px;\x22>No\x20files\x20under\x20<code>{{\x20path\x20}}</code></div>\x0a\x20\x20\x20\x20\x20\x20<button\x20@click=\x22showUpload\x20=\x20true\x22\x20style=\x22font-size:12px;\x20background:var(--okdb-sky-soft-bg);\x20border-color:var(--okdb-sky-soft-border);\x20color:var(--okdb-sky);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20↑\x20Upload\x20a\x20file\x0a\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<!--\x20──\x20Table\x20──────────────────────────────────────────────────────────\x20-->\x0a\x20\x20<if\x20:=\x22files.length\x20>\x200\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22flex:1;\x20overflow:auto;\x20min-height:0;\x22>\x0a\x20\x20\x20\x20\x20\x20<table\x20style=\x22width:100%;\x20border-collapse:collapse;\x20font-size:12px;\x20white-space:nowrap;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<thead\x20style=\x22position:sticky;\x20top:0;\x20z-index:2;\x20background:var(--okdb-app-bg-deep);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<tr\x20style=\x22border-bottom:1px\x20solid\x20var(--okdb-app-border);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<th\x20style=\x22text-align:left;\x20padding:6px\x2010px;\x20font-weight:500;\x20opacity:.6;\x20font-size:11px;\x22>Path\x20/\x20Name</th>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<th\x20style=\x22text-align:left;\x20padding:6px\x208px;\x20font-weight:500;\x20opacity:.6;\x20font-size:11px;\x22>Type</th>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<th\x20style=\x22text-align:right;\x20padding:6px\x208px;\x20font-weight:500;\x20opacity:.6;\x20font-size:11px;\x22>Size</th>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<th\x20style=\x22text-align:left;\x20padding:6px\x208px;\x20font-weight:500;\x20opacity:.6;\x20font-size:11px;\x22>Hash</th>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<th\x20style=\x22text-align:left;\x20padding:6px\x208px;\x20font-weight:500;\x20opacity:.6;\x20font-size:11px;\x22>Uploaded</th>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<th\x20style=\x22text-align:center;\x20padding:6px\x208px;\x20font-weight:500;\x20opacity:.6;\x20font-size:11px;\x22>Actions</th>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</tr>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</thead>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<tbody>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<tr\x20as=\x22repeat\x22\x20:of=\x22pagedFiles\x22\x20let:item=\x22f\x22\x20class=\x22file-row\x22>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Path\x20/\x20name\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<td\x20style=\x22padding:6px\x2010px;\x20max-width:300px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20align-items:center;\x20gap:6px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:13px;\x20flex-shrink:0;\x22>{{\x20(f.mime\x20||\x20\x27\x27).startsWith(\x27image/\x27)\x20?\x20\x27🖼\x27\x20:\x20(f.mime\x20||\x20\x27\x27).startsWith(\x27video/\x27)\x20?\x20\x27🎬\x27\x20:\x20(f.mime\x20||\x20\x27\x27).startsWith(\x27audio/\x27)\x20?\x20\x27🎵\x27\x20:\x20(f.mime\x20||\x20\x27\x27).includes(\x27pdf\x27)\x20?\x20\x27📄\x27\x20:\x20\x27📎\x27\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22overflow:hidden;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22overflow:hidden;\x20text-overflow:ellipsis;\x20white-space:nowrap;\x20font-family:monospace;\x20font-size:11px;\x20color:var(--okdb-app-fg-strong);\x22\x20:title=\x22f.path\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20displayPath(f)\x20}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:10px;\x20opacity:.3;\x20font-family:monospace;\x20overflow:hidden;\x20text-overflow:ellipsis;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20f.id\x20?\x20f.id.slice(0,8)\x20:\x20\x27\x27\x20}}…\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</td>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20MIME\x20badge\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<td\x20style=\x22padding:6px\x208px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20:style=\x22\x27display:inline-block;\x20padding:2px\x207px;\x20border-radius:999px;\x20font-size:10px;\x20font-family:monospace;\x20background:\x27\x20+\x20mimeColor(f.mime)\x20+\x20\x2722;\x20color:\x27\x20+\x20mimeColor(f.mime)\x20+\x20\x27;\x20border:1px\x20solid\x20\x27\x20+\x20mimeColor(f.mime)\x20+\x20\x2744;\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20shortMime(f.mime)\x20}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</td>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Size\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<td\x20style=\x22padding:6px\x208px;\x20text-align:right;\x20font-family:monospace;\x20font-size:11px;\x20opacity:.7;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20fmtSize(f.size)\x20}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</td>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Hash\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<td\x20style=\x22padding:6px\x208px;\x20font-family:monospace;\x20font-size:10px;\x20opacity:.4;\x22\x20:title=\x22f.hash\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20hashShort(f.hash)\x20}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</td>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Date\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<td\x20style=\x22padding:6px\x208px;\x20font-size:11px;\x20opacity:.5;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20fmtDate(f.createdAt)\x20}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</td>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Actions\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<td\x20style=\x22padding:6px\x208px;\x20text-align:center;\x20white-space:nowrap;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:href=\x22downloadUrl(f)\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:download=\x22filename(f)\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22display:inline-flex;\x20align-items:center;\x20justify-content:center;\x20width:26px;\x20height:22px;\x20color:var(--okdb-sky);\x20font-size:12px;\x20text-decoration:none;\x20border:1px\x20solid\x20var(--okdb-sky-soft-border);\x20border-radius:4px;\x20margin-right:4px;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20title=\x22Download\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20>↓</a>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@click=\x22deleteFile(f)\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22width:26px;\x20height:22px;\x20font-size:11px;\x20padding:0;\x20color:var(--okdb-danger);\x20border-color:#5a1e1e44;\x20background:var(--okdb-danger-soft-bg);\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20title=\x22Delete\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20>🗑</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</td>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</tr>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</tbody>\x0a\x20\x20\x20\x20\x20\x20</table>\x0a\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20<!--\x20──\x20Pagination\x20────────────────────────────────────────────────────\x20-->\x0a\x20\x20\x20\x20<div\x20class=\x22ok-pager\x22>\x0a\x20\x20\x20\x20\x20\x20<button\x20@click=\x22page--\x22\x20:disabled=\x22!hasPrev\x22>‹\x20Prev</button>\x0a\x20\x20\x20\x20\x20\x20<span>Page\x20{{\x20page\x20+\x201\x20}}\x20/\x20{{\x20totalPages\x20}}\x20·\x20{{\x20files.length\x20}}\x20total</span>\x0a\x20\x20\x20\x20\x20\x20<button\x20@click=\x22page++\x22\x20:disabled=\x22!hasNext\x22>Next\x20›</button>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a</div>','4nZORMn','458320fWlfrj','ceil','36dqYDtx','\x20KB','var(--okdb-mime-default)','startsWith','zip','error','page','pop','#0d9488','#7c3aed','load','$attr','message','apiBase','busy','2700lkhEzT','135993fEoPot','347250BQkhYQ','toFixed','slice','2-digit','_unsubs','/files/','43169XTkbQM','xml','toLocaleDateString','Delete\x20failed','2715224iDSCSH','failed','data','files-file-list','\x0a[tag]\x20.file-row\x20{\x20border-bottom:\x201px\x20solid\x20var(--okdb-app-bg);\x20transition:\x20background\x20.1s;\x20}\x0a[tag]\x20.file-row:hover\x20{\x20background:\x20var(--okdb-app-bg-deep);\x20}\x0a','json','includes','toLocaleTimeString','filename','pageSize','/files?path=','16819EspQgE','tar','24IlIHaH','123dernDs','9lkYJbl','pdf'];_0x34b3=function(){return _0x4b4afc;};return _0x34b3();}import _0x2b896c from'../../../stores/events-store.js';import _0x1d10af from'../../../stores/okdb-store.js';export default{'tag':_0x52e649(0xd7),'props':[_0x52e649(0xec)],'dependencies':[_0x13db8b],'context':_0x5b9d9d=>({'busy':!0x1,'files':[],'error':null,'showUpload':!0x1,'page':0x0,'pageSize':0x32,'totalLoaded':0x0,'_unsubs':[],get 'path'(){const _0x3b98a3=_0x52e649;return _0x5b9d9d[_0x3b98a3(0xc4)][_0x3b98a3(0xec)]??'/';},get 'pagedFiles'(){const _0x10e6c0=_0x52e649,_0x29aba6=this[_0x10e6c0(0xbf)]*this[_0x10e6c0(0xdd)];return this[_0x10e6c0(0xe5)][_0x10e6c0(0xcc)](_0x29aba6,_0x29aba6+this[_0x10e6c0(0xdd)]);},get 'totalPages'(){const _0x5b8cec=_0x52e649;return Math['max'](0x1,Math[_0x5b8cec(0xb8)](this['files']['length']/this[_0x5b8cec(0xdd)]));},get 'hasNext'(){const _0x1c4af8=_0x52e649;return this[_0x1c4af8(0xbf)]<this['totalPages']-0x1;},get 'hasPrev'(){const _0x1fece3=_0x52e649;return this[_0x1fece3(0xbf)]>0x0;},async 'load'(){const _0x23345b=_0x52e649,_0x454e73=_0x5b9d9d[_0x23345b(0xc4)][_0x23345b(0xec)];if(null!=_0x454e73){this['busy']=!0x0,this[_0x23345b(0xbe)]=null;try{const _0x10f003=_0x1d10af[_0x23345b(0xc6)]+_0x23345b(0xde)+encodeURIComponent(_0x454e73)+_0x23345b(0xe6),_0x6fd146=await fetch(_0x10f003),_0xb041b6=await _0x6fd146[_0x23345b(0xd9)]();if(!_0x6fd146['ok'])throw new Error(_0xb041b6?.[_0x23345b(0xbe)]?.['message']||_0x23345b(0xd5));this['files']=_0xb041b6[_0x23345b(0xd6)]??[],this[_0x23345b(0xbf)]=0x0;}catch(_0x1f5053){this[_0x23345b(0xbe)]=_0x1f5053?.['message']||String(_0x1f5053),this[_0x23345b(0xe5)]=[];}finally{this[_0x23345b(0xc7)]=!0x1;}}else this[_0x23345b(0xe5)]=[];},async 'deleteFile'(_0x3a7195){const _0x2d1d79=_0x52e649,_0x7fabfd=this[_0x2d1d79(0xdc)](_0x3a7195);if(confirm('Delete\x20\x22'+_0x7fabfd+'\x22?\x0a\x0aThis\x20will\x20decrement\x20the\x20blob\x20ref-count.'))try{const _0x2d3e4a=_0x1d10af[_0x2d1d79(0xc6)],_0x137e2e=await fetch(_0x2d3e4a+_0x2d1d79(0xcf)+encodeURIComponent(_0x3a7195['id']),{'method':'DELETE'});if(!_0x137e2e['ok']){const _0x29acfa=await _0x137e2e[_0x2d1d79(0xd9)]()[_0x2d1d79(0xeb)](()=>({}));throw new Error(_0x29acfa?.[_0x2d1d79(0xbe)]?.[_0x2d1d79(0xc5)]||_0x2d1d79(0xd3));}this['files']=this[_0x2d1d79(0xe5)][_0x2d1d79(0xf1)](_0x14bf58=>_0x14bf58['id']!==_0x3a7195['id']),_0x5b9d9d['$dispatch'](_0x2d1d79(0xef));}catch(_0x4ddc38){this['error']=_0x4ddc38?.[_0x2d1d79(0xc5)]||String(_0x4ddc38);}},'downloadUrl':_0x4b8757=>_0x1d10af[_0x52e649(0xc6)]+'/files/'+encodeURIComponent(_0x4b8757['id']),'statusUrl':_0x528d44=>_0x1d10af[_0x52e649(0xc6)]+'/files/'+encodeURIComponent(_0x528d44['id'])+'/status','filename'(_0x38f216){const _0x3e8b25=_0x52e649,_0x23298e=_0x38f216['path']??'';return _0x23298e?_0x23298e['split']('/')['filter'](Boolean)[_0x3e8b25(0xc0)]():_0x38f216['id'];},'displayPath'(_0x299c13){const _0x26659d=_0x52e649,_0x40897a=_0x299c13['path']??'',_0x2a93bb=_0x5b9d9d[_0x26659d(0xc4)]['path']??'/';if('/'===_0x2a93bb)return _0x40897a||'/';const _0x32f230=_0x2a93bb['endsWith']('/')?_0x2a93bb:_0x2a93bb+'/';return _0x40897a[_0x26659d(0xbc)](_0x32f230)?_0x40897a['slice'](_0x32f230['length']):_0x40897a;},'onUploaded'(){const _0x5f28f9=_0x52e649;this[_0x5f28f9(0xc3)](),_0x5b9d9d['$dispatch'](_0x5f28f9(0xef));},'fmtSize':_0x473f32=>null==_0x473f32?'—':_0x473f32<0x400?_0x473f32+'\x20B':_0x473f32<0x100000?(_0x473f32/0x400)[_0x52e649(0xcb)](0x1)+_0x52e649(0xba):(_0x473f32/0x100000)['toFixed'](0x1)+'\x20MB','fmtDate'(_0x1f2f62){const _0x2cb84e=_0x52e649;if(!_0x1f2f62)return'—';const _0x5e13c3=new Date(_0x1f2f62);return _0x5e13c3[_0x2cb84e(0xd2)]()+'\x20'+_0x5e13c3[_0x2cb84e(0xdb)]([],{'hour':_0x2cb84e(0xcd),'minute':'2-digit'});},'mimeColor':_0x2841ef=>_0x2841ef?_0x2841ef[_0x52e649(0xbc)]('image/')?_0x52e649(0xc2):_0x2841ef[_0x52e649(0xbc)](_0x52e649(0xf0))?_0x52e649(0xed):_0x2841ef[_0x52e649(0xbc)](_0x52e649(0xe8))?_0x52e649(0xc1):_0x2841ef[_0x52e649(0xbc)]('text/')?_0x52e649(0xe7):_0x2841ef[_0x52e649(0xda)](_0x52e649(0xe4))?'#dc2626':_0x2841ef[_0x52e649(0xda)]('json')||_0x2841ef['includes'](_0x52e649(0xd1))?'#d97706':_0x2841ef[_0x52e649(0xda)](_0x52e649(0xbd))||_0x2841ef[_0x52e649(0xda)](_0x52e649(0xe0))?_0x52e649(0xea):_0x52e649(0xbb):_0x52e649(0xbb),'shortMime'(_0x4e3b79){if(!_0x4e3b79)return'—';const _0x4b2dd7=_0x4e3b79['split']('/');return _0x4b2dd7[0x1]??_0x4b2dd7[0x0];},'hashShort':_0x4047b0=>_0x4047b0?_0x4047b0[_0x52e649(0xcc)](0x0,0x8)+'…':'—'}),'watch':{'path'(){const _0x39cfe8=_0x52e649;this['showUpload']=!0x1,this[_0x39cfe8(0xbf)]=0x0,this[_0x39cfe8(0xc3)]();}},async 'mount'(){const _0x3eab70=_0x52e649;await this['load']();const _0x7ef8c7=()=>this[_0x3eab70(0xc3)]();this[_0x3eab70(0xce)]=[_0x2b896c['on'](_0x3eab70(0xee),_0x7ef8c7),_0x2b896c['on']('files:removed',_0x7ef8c7)];},'unmount'(){const _0x3d7c72=_0x52e649;for(const _0x50afd3 of this[_0x3d7c72(0xce)])_0x50afd3();this[_0x3d7c72(0xce)]=[];},'template':_0x52e649(0xb5),'style':_0x52e649(0xd8)};
|
|
1
|
+
import t from"./files-upload-panel.ok.js";import e from"../../../stores/events-store.js";import n from"../../../stores/okdb-store.js";export default{tag:"files-file-list",props:["path"],dependencies:[t],context:t=>({busy:!1,files:[],error:null,showUpload:!1,page:0,pageSize:50,totalLoaded:0,_unsubs:[],get path(){return t.$attr.path??"/"},get pagedFiles(){const t=this.page*this.pageSize;return this.files.slice(t,t+this.pageSize)},get totalPages(){return Math.max(1,Math.ceil(this.files.length/this.pageSize))},get hasNext(){return this.page<this.totalPages-1},get hasPrev(){return this.page>0},async load(){const e=t.$attr.path;if(null!=e){this.busy=!0,this.error=null;try{const t=`${n.apiBase}/files?path=${encodeURIComponent(e)}&recursive=true&limit=2000`,i=await fetch(t),o=await i.json();if(!i.ok)throw new Error(o?.error?.message||"failed");this.files=o.data??[],this.page=0}catch(t){this.error=t?.message||String(t),this.files=[]}finally{this.busy=!1}}else this.files=[]},async deleteFile(e){const i=this.filename(e);if(confirm(`Delete "${i}"?\n\nThis will decrement the blob ref-count.`))try{const i=n.apiBase,o=await fetch(`${i}/files/${encodeURIComponent(e.id)}`,{method:"DELETE"});if(!o.ok){const t=await o.json().catch(()=>({}));throw new Error(t?.error?.message||"Delete failed")}this.files=this.files.filter(t=>t.id!==e.id),t.$dispatch("refresh")}catch(t){this.error=t?.message||String(t)}},downloadUrl:t=>`${n.apiBase}/files/${encodeURIComponent(t.id)}`,statusUrl:t=>`${n.apiBase}/files/${encodeURIComponent(t.id)}/status`,filename(t){const e=t.path??"";return e?e.split("/").filter(Boolean).pop():t.id},displayPath(e){const n=e.path??"",i=t.$attr.path??"/";if("/"===i)return n||"/";const o=i.endsWith("/")?i:i+"/";return n.startsWith(o)?n.slice(o.length):n},onUploaded(){this.load(),t.$dispatch("refresh")},fmtSize:t=>null==t?"—":t<1024?t+" B":t<1048576?(t/1024).toFixed(1)+" KB":(t/1048576).toFixed(1)+" MB",fmtDate(t){if(!t)return"—";const e=new Date(t);return e.toLocaleDateString()+" "+e.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})},mimeColor:t=>t?t.startsWith("image/")?"#7c3aed":t.startsWith("video/")?"#0891b2":t.startsWith("audio/")?"#0d9488":t.startsWith("text/")?"#16a34a":t.includes("pdf")?"#dc2626":t.includes("json")||t.includes("xml")?"#d97706":t.includes("zip")||t.includes("tar")?"#ca8a04":"var(--okdb-mime-default)":"var(--okdb-mime-default)",shortMime(t){if(!t)return"—";const e=t.split("/");return e[1]??e[0]},hashShort:t=>t?t.slice(0,8)+"…":"—"}),watch:{path(){this.showUpload=!1,this.page=0,this.load()}},async mount(){await this.load();const t=()=>this.load();this._unsubs=[e.on("files:uploaded",t),e.on("files:removed",t)]},unmount(){for(const t of this._unsubs)t();this._unsubs=[]},template:'\n<div style="display:flex; flex-direction:column; gap:0; height:100%; min-height:0;">\n\n \x3c!-- ── Toolbar ─────────────────────────────────────────────────────── --\x3e\n <div style="display:flex; align-items:center; justify-content:space-between; gap:8px; flex-wrap:wrap; margin-bottom:10px; flex-shrink:0;">\n <div style="display:flex; align-items:center; gap:8px;">\n <span style="font-family:monospace; font-size:14px; font-weight:700; color:var(--okdb-accent);">{{ path }}</span>\n <span style="font-size:11px; opacity:.4; font-family:monospace;">{{ files.length }} file(s)</span>\n </div>\n <div style="display:flex; gap:6px;">\n <button\n @click="showUpload = !showUpload"\n :style="showUpload ? \'font-size:12px; background:var(--okdb-sky-soft-bg); border-color:var(--okdb-sky-soft-border); color:var(--okdb-sky);\' : \'font-size:12px;\'"\n >{{ showUpload ? \'✕ Close upload\' : \'↑ Upload\' }}</button>\n <button @click="load()" :disabled="busy" style="font-size:12px; opacity:.7;">↻</button>\n </div>\n </div>\n\n \x3c!-- ── Upload panel ────────────────────────────────────────────────── --\x3e\n <if :="showUpload">\n <div style="flex-shrink:0; margin-bottom:10px; padding:12px; background:var(--okdb-app-bg-deep); border:1px solid var(--okdb-app-border); border-radius:8px;">\n <files-upload-panel\n :path="path"\n @uploaded="onUploaded()"\n />\n </div>\n </if>\n\n \x3c!-- ── Error ────────────────────────────────────────────────────────── --\x3e\n <if :="error">\n <div style="flex-shrink:0; color:var(--okdb-danger); font-size:12px; margin-bottom:8px; padding:6px 10px; border:1px solid color-mix(in srgb, var(--okdb-danger) 20%, transparent); border-radius:6px; background:var(--okdb-danger-soft-bg);">\n {{ error }}\n </div>\n </if>\n\n \x3c!-- ── Loading ──────────────────────────────────────────────────────── --\x3e\n <if :="busy">\n <div style="flex-shrink:0; font-size:12px; opacity:.4; padding:8px 0;">Loading…</div>\n </if>\n\n \x3c!-- ── Empty state ──────────────────────────────────────────────────── --\x3e\n <if :="!busy && files.length === 0 && !error">\n <div style="flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:12px; opacity:.45;">\n <div style="font-size:32px;">📂</div>\n <div style="font-size:13px;">No files under <code>{{ path }}</code></div>\n <button @click="showUpload = true" style="font-size:12px; background:var(--okdb-sky-soft-bg); border-color:var(--okdb-sky-soft-border); color:var(--okdb-sky);">\n ↑ Upload a file\n </button>\n </div>\n </if>\n\n \x3c!-- ── Table ────────────────────────────────────────────────────────── --\x3e\n <if :="files.length > 0">\n <div style="flex:1; overflow:auto; min-height:0;">\n <table style="width:100%; border-collapse:collapse; font-size:12px; white-space:nowrap;">\n <thead style="position:sticky; top:0; z-index:2; background:var(--okdb-app-bg-deep);">\n <tr style="border-bottom:1px solid var(--okdb-app-border);">\n <th style="text-align:left; padding:6px 10px; font-weight:500; opacity:.6; font-size:11px;">Path / Name</th>\n <th style="text-align:left; padding:6px 8px; font-weight:500; opacity:.6; font-size:11px;">Type</th>\n <th style="text-align:right; padding:6px 8px; font-weight:500; opacity:.6; font-size:11px;">Size</th>\n <th style="text-align:left; padding:6px 8px; font-weight:500; opacity:.6; font-size:11px;">Hash</th>\n <th style="text-align:left; padding:6px 8px; font-weight:500; opacity:.6; font-size:11px;">Uploaded</th>\n <th style="text-align:center; padding:6px 8px; font-weight:500; opacity:.6; font-size:11px;">Actions</th>\n </tr>\n </thead>\n <tbody>\n <tr as="repeat" :of="pagedFiles" let:item="f" class="file-row">\n\n \x3c!-- Path / name --\x3e\n <td style="padding:6px 10px; max-width:300px;">\n <div style="display:flex; align-items:center; gap:6px;">\n <span style="font-size:13px; flex-shrink:0;">{{ (f.mime || \'\').startsWith(\'image/\') ? \'🖼\' : (f.mime || \'\').startsWith(\'video/\') ? \'🎬\' : (f.mime || \'\').startsWith(\'audio/\') ? \'🎵\' : (f.mime || \'\').includes(\'pdf\') ? \'📄\' : \'📎\' }}</span>\n <div style="overflow:hidden;">\n <div style="overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-family:monospace; font-size:11px; color:var(--okdb-app-fg-strong);" :title="f.path">\n {{ displayPath(f) }}\n </div>\n <div style="font-size:10px; opacity:.3; font-family:monospace; overflow:hidden; text-overflow:ellipsis;">\n {{ f.id ? f.id.slice(0,8) : \'\' }}…\n </div>\n </div>\n </div>\n </td>\n\n \x3c!-- MIME badge --\x3e\n <td style="padding:6px 8px;">\n <span :style="\'display:inline-block; padding:2px 7px; border-radius:999px; font-size:10px; font-family:monospace; background:\' + mimeColor(f.mime) + \'22; color:\' + mimeColor(f.mime) + \'; border:1px solid \' + mimeColor(f.mime) + \'44;\'">\n {{ shortMime(f.mime) }}\n </span>\n </td>\n\n \x3c!-- Size --\x3e\n <td style="padding:6px 8px; text-align:right; font-family:monospace; font-size:11px; opacity:.7;">\n {{ fmtSize(f.size) }}\n </td>\n\n \x3c!-- Hash --\x3e\n <td style="padding:6px 8px; font-family:monospace; font-size:10px; opacity:.4;" :title="f.hash">\n {{ hashShort(f.hash) }}\n </td>\n\n \x3c!-- Date --\x3e\n <td style="padding:6px 8px; font-size:11px; opacity:.5;">\n {{ fmtDate(f.createdAt) }}\n </td>\n\n \x3c!-- Actions --\x3e\n <td style="padding:6px 8px; text-align:center; white-space:nowrap;">\n <a\n :href="downloadUrl(f)"\n :download="filename(f)"\n style="display:inline-flex; align-items:center; justify-content:center; width:26px; height:22px; color:var(--okdb-sky); font-size:12px; text-decoration:none; border:1px solid var(--okdb-sky-soft-border); border-radius:4px; margin-right:4px;"\n title="Download"\n >↓</a>\n <button\n @click="deleteFile(f)"\n style="width:26px; height:22px; font-size:11px; padding:0; color:var(--okdb-danger); border-color:#5a1e1e44; background:var(--okdb-danger-soft-bg);"\n title="Delete"\n >🗑</button>\n </td>\n\n </tr>\n </tbody>\n </table>\n </div>\n\n \x3c!-- ── Pagination ──────────────────────────────────────────────────── --\x3e\n <div class="ok-pager">\n <button @click="page--" :disabled="!hasPrev">‹ Prev</button>\n <span>Page {{ page + 1 }} / {{ totalPages }} · {{ files.length }} total</span>\n <button @click="page++" :disabled="!hasNext">Next ›</button>\n </div>\n </if>\n\n</div>',style:"\n[tag] .file-row { border-bottom: 1px solid var(--okdb-app-bg); transition: background .1s; }\n[tag] .file-row:hover { background: var(--okdb-app-bg-deep); }\n"};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function _0xb947(_0x18f269,_0x1d915a){_0x18f269=_0x18f269-0x16c;const _0x51c93b=_0x51c9();let _0xb947f8=_0x51c93b[_0x18f269];return _0xb947f8;}const _0x35629b=_0xb947;(function(_0x43ee81,_0x35cf66){const _0x23962d=_0xb947,_0x297785=_0x43ee81();while(!![]){try{const _0x333f5c=parseInt(_0x23962d(0x16c))/0x1*(parseInt(_0x23962d(0x189))/0x2)+parseInt(_0x23962d(0x187))/0x3*(-parseInt(_0x23962d(0x17d))/0x4)+parseInt(_0x23962d(0x174))/0x5*(-parseInt(_0x23962d(0x17b))/0x6)+parseInt(_0x23962d(0x177))/0x7+parseInt(_0x23962d(0x183))/0x8*(-parseInt(_0x23962d(0x17a))/0x9)+parseInt(_0x23962d(0x176))/0xa+-parseInt(_0x23962d(0x188))/0xb*(-parseInt(_0x23962d(0x182))/0xc);if(_0x333f5c===_0x35cf66)break;else _0x297785['push'](_0x297785['shift']());}catch(_0x39f9ef){_0x297785['push'](_0x297785['shift']());}}}(_0x51c9,0x8a168));export default{'tag':'files-overview','props':['files'],'context':_0x1f7860=>({get 'files'(){const _0x31c8ba=_0xb947;return _0x1f7860['$attr'][_0x31c8ba(0x16e)]??[];},get 'totalFiles'(){const _0x5d1880=_0xb947;return this[_0x5d1880(0x16e)][_0x5d1880(0x178)];},get 'dirs'(){const _0xa2e3d3=_0xb947,_0x3146e6=new Set();for(const _0x4b8575 of this[_0xa2e3d3(0x16e)]){const _0x38d791=(_0x4b8575['path']??'')[_0xa2e3d3(0x171)](/^(\/[^/]+)\//);_0x38d791&&_0x3146e6['add'](_0x38d791[0x1]);}return[..._0x3146e6][_0xa2e3d3(0x17e)]();},get 'totalBytes'(){const _0x3dc497=_0xb947;return this[_0x3dc497(0x16e)][_0x3dc497(0x16f)]((_0x20ab9d,_0x3e142c)=>_0x20ab9d+(_0x3e142c[_0x3dc497(0x17c)]??0x0),0x0);},get 'mimeBreakdown'(){const _0x28d0f4=_0xb947,_0x1a1d0b={};for(const _0x509172 of this['files']){const _0x42e471=_0x509172[_0x28d0f4(0x186)]??_0x28d0f4(0x173),_0x3d5553=_0x42e471[_0x28d0f4(0x170)](_0x28d0f4(0x18d))?_0x28d0f4(0x184):_0x42e471['startsWith'](_0x28d0f4(0x179))?'video':_0x42e471[_0x28d0f4(0x170)](_0x28d0f4(0x172))?'audio':_0x42e471[_0x28d0f4(0x170)](_0x28d0f4(0x18a))?_0x28d0f4(0x18b):_0x42e471[_0x28d0f4(0x181)](_0x28d0f4(0x16d))?'pdf':_0x28d0f4(0x173);_0x1a1d0b[_0x3d5553]=(_0x1a1d0b[_0x3d5553]??0x0)+0x1;}return Object['entries'](_0x1a1d0b)[_0x28d0f4(0x17e)]((_0x3df9bf,_0x2cd6c5)=>_0x2cd6c5[0x1]-_0x3df9bf[0x1])[_0x28d0f4(0x17f)](([_0x2ef1a8,_0x43e429])=>({'cat':_0x2ef1a8,'count':_0x43e429}));},'mimeIcon':_0x16b17e=>({'image':'🖼','video':'🎬','audio':'🎵','text':'📝','pdf':'📄','other':'📎'}[_0x16b17e]??'📎'),'fmtBytes':_0x4f44a6=>_0x4f44a6<0x400?_0x4f44a6+'\x20B':_0x4f44a6<0x100000?(_0x4f44a6/0x400)[_0x35629b(0x185)](0x1)+'\x20KB':_0x4f44a6<0x40000000?(_0x4f44a6/0x100000)['toFixed'](0x1)+'\x20MB':(_0x4f44a6/0x40000000)[_0x35629b(0x185)](0x2)+_0x35629b(0x18c),'browseTo'(_0x459a1c){const _0x46c243=_0x35629b;_0x1f7860['$dispatch'](_0x46c243(0x180),_0x459a1c);}}),'template':'\x0a<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:20px;\x20max-width:680px;\x22>\x0a\x0a\x20\x20<div\x20style=\x22font-weight:700;\x20font-size:18px;\x20opacity:.9;\x22>Files</div>\x0a\x0a\x20\x20<!--\x20Stats\x20row\x20-->\x0a\x20\x20<div\x20style=\x22display:flex;\x20gap:12px;\x20flex-wrap:wrap;\x22>\x0a\x20\x20\x20\x20<div\x20class=\x22stat-card\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22stat-label\x22>Total\x20Files</div>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22stat-value\x22\x20style=\x22color:var(--okdb-info);\x22>{{\x20totalFiles\x20}}</div>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22stat-sub\x22>{{\x20fmtBytes(totalBytes)\x20}}</div>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20<div\x20class=\x22stat-card\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22stat-label\x22>Directories</div>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22stat-value\x22\x20style=\x22color:var(--okdb-accent-2);\x22>{{\x20dirs.length\x20}}</div>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22stat-sub\x22>top-level</div>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20<if\x20:=\x22mimeBreakdown.length\x20>\x200\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20class=\x22stat-card\x22\x20style=\x22flex:2;\x20min-width:180px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20class=\x22stat-label\x22>By\x20type</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-wrap:wrap;\x20gap:6px;\x20margin-top:6px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<each\x20:of=\x22mimeBreakdown\x22\x20let:item=\x22m\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:11px;\x20padding:2px\x208px;\x20border-radius:999px;\x20background:var(--okdb-app-surface);\x20border:1px\x20solid\x20var(--okdb-app-border);\x20opacity:.8;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20mimeIcon(m.cat)\x20}}\x20{{\x20m.cat\x20}}\x20<span\x20style=\x22opacity:.5;\x22>{{\x20m.count\x20}}</span>\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</each>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</if>\x0a\x20\x20</div>\x0a\x0a\x20\x20<!--\x20Directory\x20list\x20with\x20click-through\x20-->\x0a\x20\x20<if\x20:=\x22dirs.length\x20>\x200\x22>\x0a\x20\x20\x20\x20<div>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;\x20opacity:.5;\x20margin-bottom:8px;\x20text-transform:uppercase;\x20letter-spacing:.06em;\x22>Directories</div>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:3px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20class=\x22dir-btn\x22\x20@click=\x22browseTo(\x27/\x27)\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:12px;\x20opacity:.5;\x22>📁</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-family:monospace;\x20font-size:12px;\x22>/\x20(all\x20files)</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22margin-left:auto;\x20font-size:11px;\x20opacity:.4;\x20font-family:monospace;\x22>{{\x20totalFiles\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<each\x20:of=\x22dirs\x22\x20let:item=\x22dir\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20class=\x22dir-btn\x22\x20@click=\x22browseTo(dir)\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:12px;\x20opacity:.4;\x22>📂</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-family:monospace;\x20font-size:12px;\x22>{{\x20dir\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22margin-left:auto;\x20font-size:11px;\x20opacity:.4;\x20font-family:monospace;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20files.filter(f\x20=>\x20(f.path\x20||\x20\x27\x27).startsWith(dir\x20+\x20\x27/\x27)).length\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</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</each>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<!--\x20Empty\x20state\x20-->\x0a\x20\x20<if\x20:=\x22totalFiles\x20===\x200\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22padding:24px;\x20background:var(--okdb-app-bg);\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:10px;\x20display:flex;\x20flex-direction:column;\x20gap:10px;\x20align-items:center;\x20text-align:center;\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:32px;\x20opacity:.5;\x22>📂</div>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:13px;\x20font-weight:600;\x20opacity:.8;\x22>No\x20files\x20yet</div>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;\x20opacity:.55;\x20line-height:1.8;\x20max-width:340px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20Select\x20<strong\x20style=\x22color:var(--okdb-sky);\x22>/\x20(all\x20files)</strong>\x20in\x20the\x20sidebar,\x0a\x20\x20\x20\x20\x20\x20\x20\x20then\x20click\x20<strong\x20style=\x22color:var(--okdb-sky);\x22>↑\x20Upload</strong>\x20to\x20add\x20files.<br>\x0a\x20\x20\x20\x20\x20\x20\x20\x20Files\x20are\x20organised\x20by\x20path,\x20e.g.\x20<code\x20style=\x22color:#a5f3fc;\x22>/photos/cat.jpg</code>.\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20<button\x20@click=\x22browseTo(\x27/\x27)\x22\x20style=\x22font-size:12px;\x20background:var(--okdb-sky-soft-bg);\x20border-color:var(--okdb-sky-soft-border);\x20color:var(--okdb-sky);\x20margin-top:4px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20Browse\x20/\x0a\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a</div>','style':_0x35629b(0x175)};function _0x51c9(){const _0x481302=['other','25TnXysW','\x0a[tag]\x20.stat-card\x20{\x0a\x20\x20\x20\x20flex:\x201;\x0a\x20\x20\x20\x20min-width:\x20120px;\x0a\x20\x20\x20\x20padding:\x2014px\x2016px;\x0a\x20\x20\x20\x20background:\x20var(--okdb-app-surface);\x0a\x20\x20\x20\x20border:\x201px\x20solid\x20var(--okdb-app-border);\x0a\x20\x20\x20\x20border-radius:\x2010px;\x0a}\x0a[tag]\x20.stat-label\x20{\x0a\x20\x20\x20\x20font-size:\x2010px;\x0a\x20\x20\x20\x20opacity:\x20.5;\x0a\x20\x20\x20\x20text-transform:\x20uppercase;\x0a\x20\x20\x20\x20letter-spacing:\x20.06em;\x0a\x20\x20\x20\x20margin-bottom:\x206px;\x0a}\x0a[tag]\x20.stat-value\x20{\x0a\x20\x20\x20\x20font-size:\x2026px;\x0a\x20\x20\x20\x20font-weight:\x20700;\x0a}\x0a[tag]\x20.stat-sub\x20{\x0a\x20\x20\x20\x20font-size:\x2011px;\x0a\x20\x20\x20\x20opacity:\x20.4;\x0a\x20\x20\x20\x20margin-top:\x202px;\x0a}\x0a[tag]\x20.dir-btn\x20{\x0a\x20\x20\x20\x20display:\x20flex;\x0a\x20\x20\x20\x20align-items:\x20center;\x0a\x20\x20\x20\x20gap:\x208px;\x0a\x20\x20\x20\x20padding:\x206px\x2010px;\x0a\x20\x20\x20\x20border-radius:\x206px;\x0a\x20\x20\x20\x20border:\x201px\x20solid\x20transparent;\x0a\x20\x20\x20\x20background:\x20transparent;\x0a\x20\x20\x20\x20cursor:\x20pointer;\x0a\x20\x20\x20\x20width:\x20100%;\x0a\x20\x20\x20\x20transition:\x20background\x20.1s;\x0a}\x0a[tag]\x20.dir-btn:hover\x20{\x0a\x20\x20\x20\x20background:\x20var(--okdb-app-surface);\x0a\x20\x20\x20\x20border-color:\x20var(--okdb-app-border);\x0a}\x0a','10956980BrcxFD','56273GPgxRv','length','video/','63OrlUiR','811710xgMsar','size','4QAYOXF','sort','map','select','includes','13464516MTUFge','960864ZuJqTI','image','toFixed','mime','1350036DcCabO','11ByXIGa','614042EdLUee','text/','text','\x20GB','image/','1nzmAuZ','pdf','files','reduce','startsWith','match','audio/'];_0x51c9=function(){return _0x481302;};return _0x51c9();}
|
|
1
|
+
export default{tag:"files-overview",props:["files"],context:t=>({get files(){return t.$attr.files??[]},get totalFiles(){return this.files.length},get dirs(){const t=new Set;for(const n of this.files){const e=(n.path??"").match(/^(\/[^/]+)\//);e&&t.add(e[1])}return[...t].sort()},get totalBytes(){return this.files.reduce((t,n)=>t+(n.size??0),0)},get mimeBreakdown(){const t={};for(const n of this.files){const e=n.mime??"other",i=e.startsWith("image/")?"image":e.startsWith("video/")?"video":e.startsWith("audio/")?"audio":e.startsWith("text/")?"text":e.includes("pdf")?"pdf":"other";t[i]=(t[i]??0)+1}return Object.entries(t).sort((t,n)=>n[1]-t[1]).map(([t,n])=>({cat:t,count:n}))},mimeIcon:t=>({image:"🖼",video:"🎬",audio:"🎵",text:"📝",pdf:"📄",other:"📎"}[t]??"📎"),fmtBytes:t=>t<1024?t+" B":t<1048576?(t/1024).toFixed(1)+" KB":t<1073741824?(t/1048576).toFixed(1)+" MB":(t/1073741824).toFixed(2)+" GB",browseTo(n){t.$dispatch("select",n)}}),template:'\n<div style="display:flex; flex-direction:column; gap:20px; max-width:680px;">\n\n <div style="font-weight:700; font-size:18px; opacity:.9;">Files</div>\n\n \x3c!-- Stats row --\x3e\n <div style="display:flex; gap:12px; flex-wrap:wrap;">\n <div class="stat-card">\n <div class="stat-label">Total Files</div>\n <div class="stat-value" style="color:var(--okdb-info);">{{ totalFiles }}</div>\n <div class="stat-sub">{{ fmtBytes(totalBytes) }}</div>\n </div>\n <div class="stat-card">\n <div class="stat-label">Directories</div>\n <div class="stat-value" style="color:var(--okdb-accent-2);">{{ dirs.length }}</div>\n <div class="stat-sub">top-level</div>\n </div>\n <if :="mimeBreakdown.length > 0">\n <div class="stat-card" style="flex:2; min-width:180px;">\n <div class="stat-label">By type</div>\n <div style="display:flex; flex-wrap:wrap; gap:6px; margin-top:6px;">\n <each :of="mimeBreakdown" let:item="m">\n <span style="font-size:11px; padding:2px 8px; border-radius:999px; background:var(--okdb-app-surface); border:1px solid var(--okdb-app-border); opacity:.8;">\n {{ mimeIcon(m.cat) }} {{ m.cat }} <span style="opacity:.5;">{{ m.count }}</span>\n </span>\n </each>\n </div>\n </div>\n </if>\n </div>\n\n \x3c!-- Directory list with click-through --\x3e\n <if :="dirs.length > 0">\n <div>\n <div style="font-size:12px; opacity:.5; margin-bottom:8px; text-transform:uppercase; letter-spacing:.06em;">Directories</div>\n <div style="display:flex; flex-direction:column; gap:3px;">\n <button class="dir-btn" @click="browseTo(\'/\')">\n <span style="font-size:12px; opacity:.5;">📁</span>\n <span style="font-family:monospace; font-size:12px;">/ (all files)</span>\n <span style="margin-left:auto; font-size:11px; opacity:.4; font-family:monospace;">{{ totalFiles }}</span>\n </button>\n <each :of="dirs" let:item="dir">\n <button class="dir-btn" @click="browseTo(dir)">\n <span style="font-size:12px; opacity:.4;">📂</span>\n <span style="font-family:monospace; font-size:12px;">{{ dir }}</span>\n <span style="margin-left:auto; font-size:11px; opacity:.4; font-family:monospace;">\n {{ files.filter(f => (f.path || \'\').startsWith(dir + \'/\')).length }}\n </span>\n </button>\n </each>\n </div>\n </div>\n </if>\n\n \x3c!-- Empty state --\x3e\n <if :="totalFiles === 0">\n <div style="padding:24px; background:var(--okdb-app-bg); border:1px solid var(--okdb-app-border); border-radius:10px; display:flex; flex-direction:column; gap:10px; align-items:center; text-align:center;">\n <div style="font-size:32px; opacity:.5;">📂</div>\n <div style="font-size:13px; font-weight:600; opacity:.8;">No files yet</div>\n <div style="font-size:12px; opacity:.55; line-height:1.8; max-width:340px;">\n Select <strong style="color:var(--okdb-sky);">/ (all files)</strong> in the sidebar,\n then click <strong style="color:var(--okdb-sky);">↑ Upload</strong> to add files.<br>\n Files are organised by path, e.g. <code style="color:#a5f3fc;">/photos/cat.jpg</code>.\n </div>\n <button @click="browseTo(\'/\')" style="font-size:12px; background:var(--okdb-sky-soft-bg); border-color:var(--okdb-sky-soft-border); color:var(--okdb-sky); margin-top:4px;">\n Browse /\n </button>\n </div>\n </if>\n\n</div>',style:"\n[tag] .stat-card {\n flex: 1;\n min-width: 120px;\n padding: 14px 16px;\n background: var(--okdb-app-surface);\n border: 1px solid var(--okdb-app-border);\n border-radius: 10px;\n}\n[tag] .stat-label {\n font-size: 10px;\n opacity: .5;\n text-transform: uppercase;\n letter-spacing: .06em;\n margin-bottom: 6px;\n}\n[tag] .stat-value {\n font-size: 26px;\n font-weight: 700;\n}\n[tag] .stat-sub {\n font-size: 11px;\n opacity: .4;\n margin-top: 2px;\n}\n[tag] .dir-btn {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 10px;\n border-radius: 6px;\n border: 1px solid transparent;\n background: transparent;\n cursor: pointer;\n width: 100%;\n transition: background .1s;\n}\n[tag] .dir-btn:hover {\n background: var(--okdb-app-surface);\n border-color: var(--okdb-app-border);\n}\n"};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import e from"../../../stores/events-store.js";import t from"../../../stores/okdb-store.js";export default{tag:"files-path-browser",context:e=>({busy:!1,allFiles:[],selected:null,_unsubs:[],async load(){this.busy=!0;try{const n=t.apiBase,i=await fetch(`${n}/files?path=/&recursive=true&limit=5000`);if(!i.ok)throw new Error("failed");const s=await i.json();this.allFiles=s.data??[],e.$dispatch("loaded",this.allFiles)}catch(e){console.error("files-path-browser load error",e)}finally{this.busy=!1}},clearSelection(){this.selected=null},select(t){this.selected=t,e.$dispatch("select",t)},get dirs(){const e=new Map;for(const t of this.allFiles){const n=(t.path??"").match(/^(\/[^/]+)\//);if(!n)continue;const i=n[1];e.set(i,(e.get(i)??0)+1)}return[...e.entries()].sort((e,t)=>e[0].localeCompare(t[0])).map(([e,t])=>({path:e,count:t}))},get totalFiles(){return this.allFiles.length},totalBytes(){const e=this.allFiles.reduce((e,t)=>e+(t.size??0),0);return e<1024?e+" B":e<1048576?(e/1024).toFixed(1)+" KB":e<1073741824?(e/1048576).toFixed(1)+" MB":(e/1073741824).toFixed(2)+" GB"}}),async mount(n){await this.load();const i=()=>this.load();this._unsubs=[e.on("files:uploaded",i),e.on("files:removed",i)],n.$watch(()=>t.selectedEnv,()=>{this.selected=null,this.load()})},unmount(){for(const e of this._unsubs)e();this._unsubs=[]},template:'\n<div style="display:flex; flex-direction:column; gap:4px; height:100%; min-height:0; overflow:hidden;">\n\n \x3c!-- Header --\x3e\n <div style="display:flex; align-items:center; justify-content:space-between; gap:6px; margin-bottom:6px; flex-shrink:0;">\n <div style="font-weight:600; font-size:13px; opacity:.8;">Files</div>\n <button @click="load()" :disabled="busy" style="font-size:11px; opacity:.6;" title="Refresh">↻</button>\n </div>\n\n \x3c!-- Summary --\x3e\n <div style="font-size:11px; opacity:.4; margin-bottom:4px; flex-shrink:0;">\n {{ totalFiles }} file(s) · {{ totalBytes() }}\n </div>\n\n <if :="busy && allFiles.length === 0">\n <div style="font-size:11px; opacity:.4; padding:4px 0;">Loading…</div>\n </if>\n\n \x3c!-- Scrollable dir list --\x3e\n <div style="flex:1; overflow-y:auto; overflow-x:hidden; display:flex; flex-direction:column; gap:2px; min-height:0;">\n\n \x3c!-- All Files row --\x3e\n <button\n :class="selected === \'/\' ? \'dir-row dir-row--on\' : \'dir-row\'"\n @click="select(\'/\')"\n >\n <span style="flex-shrink:0; font-size:11px; opacity:.5;">📁</span>\n <span style="flex:1; text-align:left; font-size:12px; font-family:monospace;">/</span>\n <span style="font-size:10px; opacity:.35; flex-shrink:0; font-family:monospace;">{{ totalFiles }}</span>\n </button>\n\n <if :="dirs.length > 0">\n <div style="border-top:1px solid var(--okdb-app-surface-2); margin:4px 2px;"></div>\n </if>\n\n \x3c!-- Per-dir rows --\x3e\n <each :of="dirs" let:item="dir">\n <button\n :class="selected === dir.path ? \'dir-row dir-row--on\' : \'dir-row\'"\n @click="select(dir.path)"\n :title="dir.path"\n >\n <span style="flex-shrink:0; font-size:11px; opacity:.4;">📂</span>\n <span style="flex:1; text-align:left; font-size:12px; font-family:monospace; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">\n {{ dir.path }}\n </span>\n <span style="font-size:10px; opacity:.35; flex-shrink:0; font-family:monospace;">{{ dir.count }}</span>\n </button>\n </each>\n\n <if :="allFiles.length === 0 && !busy">\n <div style="font-size:12px; opacity:.3; padding:12px 0; text-align:center; line-height:1.7;">\n No files yet.<br>\n <span style="font-size:11px;">Select / and upload.</span>\n </div>\n </if>\n\n </div>\n\n</div>',style:"\n[tag] .dir-row {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 5px 8px;\n border-radius: 6px;\n border: 1px solid transparent;\n background: transparent;\n cursor: pointer;\n width: 100%;\n text-align: left;\n transition: background .1s;\n}\n[tag] .dir-row:hover { background: var(--okdb-app-surface); border-color: var(--okdb-app-border); }\n[tag] .dir-row--on { background: var(--okdb-accent-soft-bg); border-color: var(--okdb-accent-soft-border); color: var(--okdb-accent); }\n"};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const _0x49f344=_0x528c;function _0x528c(_0x4f889c,_0x45d7b8){_0x4f889c=_0x4f889c-0x19b;const _0x259ccc=_0x259c();let _0x528c4b=_0x259ccc[_0x4f889c];return _0x528c4b;}(function(_0x4fcd06,_0x3356f6){const _0x3156e6=_0x528c,_0x17624e=_0x4fcd06();while(!![]){try{const _0x3e2abb=-parseInt(_0x3156e6(0x1c3))/0x1*(-parseInt(_0x3156e6(0x1b4))/0x2)+parseInt(_0x3156e6(0x1a1))/0x3*(-parseInt(_0x3156e6(0x1a9))/0x4)+-parseInt(_0x3156e6(0x1be))/0x5*(parseInt(_0x3156e6(0x1b2))/0x6)+parseInt(_0x3156e6(0x1c4))/0x7*(parseInt(_0x3156e6(0x1a3))/0x8)+-parseInt(_0x3156e6(0x1c6))/0x9+parseInt(_0x3156e6(0x1b3))/0xa*(parseInt(_0x3156e6(0x1c5))/0xb)+parseInt(_0x3156e6(0x1c8))/0xc;if(_0x3e2abb===_0x3356f6)break;else _0x17624e['push'](_0x17624e['shift']());}catch(_0x753c3d){_0x17624e['push'](_0x17624e['shift']());}}}(_0x259c,0x549cd));function _0x259c(){const _0x4447ed=['$attr','12HAZsat','830CllDEC','1570VuYzMb','uploading','name','click','size','json','push','application/octet-stream','status','multiple','187345Bpbacl','\x20KB','filter','type','toFixed','569kubggf','119VYntaZ','37631hawmqq','1271016HnUSMX','splice','5299992ZiUAZV','\x0a@keyframes\x20spin\x20{\x20to\x20{\x20transform:\x20rotate(360deg);\x20}\x20}\x0a','POST','error','\x20MB','$dispatch','apiBase','find','length','createElement','6vKOLyV','done','18632GVNWpx','_uploading','uploaded','file','queue','files-upload-panel','1298264gYrhiX','onchange','pending','path','input','Upload\x20failed','message','_flush'];_0x259c=function(){return _0x4447ed;};return _0x259c();}import _0x1863a7 from'../../../components/ok-dropzone.ok.js';import _0x1ca71c from'../../../stores/okdb-store.js';export default{'tag':_0x49f344(0x1a8),'props':[_0x49f344(0x1ac)],'dependencies':[_0x1863a7],'context':_0x21993e=>({'queue':[],get 'path'(){const _0x3e5d15=_0x49f344;return _0x21993e[_0x3e5d15(0x1b1)]['path']||'/';},'onFilesDropped'(_0x3a7d44){const _0x94acf1=_0x49f344,{files:_0x2419e8}=_0x3a7d44['detail'];for(const _0x36d0dc of _0x2419e8)this['queue'][_0x94acf1(0x1ba)]({'file':_0x36d0dc,'relativePath':_0x36d0dc['relativePath']||_0x36d0dc[_0x94acf1(0x1b6)],'status':_0x94acf1(0x1ab),'error':null,'record':null});this[_0x94acf1(0x1b0)]();},'onBrowse'(){const _0xba30d0=_0x49f344,_0x43245e=document[_0xba30d0(0x1a0)](_0xba30d0(0x1ad));_0x43245e[_0xba30d0(0x1c1)]='file',_0x43245e[_0xba30d0(0x1bd)]=!0x0,_0x43245e[_0xba30d0(0x1aa)]=()=>{const _0xdb63ae=_0xba30d0;for(const _0x59c632 of Array['from'](_0x43245e['files']))this[_0xdb63ae(0x1a7)]['push']({'file':_0x59c632,'relativePath':_0x59c632['name'],'status':_0xdb63ae(0x1ab),'error':null,'record':null});this[_0xdb63ae(0x1b0)]();},_0x43245e[_0xba30d0(0x1b7)]();},'_uploading':!0x1,async '_flush'(){const _0x1502d7=_0x49f344;if(!this[_0x1502d7(0x1a4)]){this[_0x1502d7(0x1a4)]=!0x0;try{let _0x3f9792;for(;_0x3f9792=this['queue'][_0x1502d7(0x19e)](_0x44eafa=>'pending'===_0x44eafa[_0x1502d7(0x1bc)]);)await this['_uploadOne'](_0x3f9792);}finally{this['_uploading']=!0x1;}}},async '_uploadOne'(_0x337b5f){const _0x8c506c=_0x49f344;_0x337b5f[_0x8c506c(0x1bc)]=_0x8c506c(0x1b5);const _0x38b3e4=_0x21993e['$attr'][_0x8c506c(0x1ac)]||'/';try{const _0x48d70d=(_0x337b5f['relativePath']||_0x337b5f['file'][_0x8c506c(0x1b6)])['replace'](/^\//,''),_0x127ff9=(_0x38b3e4['endsWith']('/')?_0x38b3e4:_0x38b3e4+'/')+_0x48d70d,_0x1c655c=await fetch(_0x1ca71c[_0x8c506c(0x19d)]+'/files?path='+encodeURIComponent(_0x127ff9),{'method':_0x8c506c(0x1ca),'headers':{'content-type':_0x337b5f[_0x8c506c(0x1a6)][_0x8c506c(0x1c1)]||_0x8c506c(0x1bb),'content-length':String(_0x337b5f[_0x8c506c(0x1a6)][_0x8c506c(0x1b8)])},'body':_0x337b5f[_0x8c506c(0x1a6)]}),_0x3e0945=await _0x1c655c[_0x8c506c(0x1b9)]();if(!_0x1c655c['ok'])throw new Error(_0x3e0945?.[_0x8c506c(0x1cb)]?.['message']||_0x8c506c(0x1ae));_0x337b5f['record']=_0x3e0945['data'],_0x337b5f['status']='done',_0x21993e[_0x8c506c(0x19c)](_0x8c506c(0x1a5),_0x337b5f['record']);}catch(_0x26793d){_0x337b5f[_0x8c506c(0x1cb)]=_0x26793d?.[_0x8c506c(0x1af)]||String(_0x26793d),_0x337b5f[_0x8c506c(0x1bc)]=_0x8c506c(0x1cb);}},'retryItem'(_0x1f4b94){const _0x599c9e=_0x49f344;_0x1f4b94[_0x599c9e(0x1bc)]=_0x599c9e(0x1ab),_0x1f4b94['error']=null,this['_flush']();},'removeItem'(_0x51a2b0){const _0x360833=_0x49f344,_0xeec292=this[_0x360833(0x1a7)]['indexOf'](_0x51a2b0);-0x1!==_0xeec292&&this['queue'][_0x360833(0x1c7)](_0xeec292,0x1);},'clearDone'(){const _0x173559=_0x49f344;this['queue']=this[_0x173559(0x1a7)][_0x173559(0x1c0)](_0x4b6f9c=>_0x173559(0x1a2)!==_0x4b6f9c['status']);},'fmtSize':_0x5a11af=>null==_0x5a11af?'—':_0x5a11af<0x400?_0x5a11af+'\x20B':_0x5a11af<0x100000?(_0x5a11af/0x400)[_0x49f344(0x1c2)](0x1)+_0x49f344(0x1bf):(_0x5a11af/0x100000)[_0x49f344(0x1c2)](0x1)+_0x49f344(0x19b),get 'pendingCount'(){const _0x24b6cf=_0x49f344;return this[_0x24b6cf(0x1a7)][_0x24b6cf(0x1c0)](_0x119c06=>_0x24b6cf(0x1ab)===_0x119c06[_0x24b6cf(0x1bc)])['length'];},get 'uploadingCount'(){const _0x8ebdda=_0x49f344;return this[_0x8ebdda(0x1a7)][_0x8ebdda(0x1c0)](_0x4ac7ad=>_0x8ebdda(0x1b5)===_0x4ac7ad[_0x8ebdda(0x1bc)])[_0x8ebdda(0x19f)];},get 'doneCount'(){const _0x4058b8=_0x49f344;return this[_0x4058b8(0x1a7)]['filter'](_0x2da49e=>_0x4058b8(0x1a2)===_0x2da49e['status'])[_0x4058b8(0x19f)];},get 'errorCount'(){const _0x4a14df=_0x49f344;return this[_0x4a14df(0x1a7)][_0x4a14df(0x1c0)](_0x354053=>'error'===_0x354053[_0x4a14df(0x1bc)])[_0x4a14df(0x19f)];}}),'template':'\x0a<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:10px;\x22>\x0a\x0a\x20\x20<!--\x20Drop\x20zone\x20-->\x0a\x20\x20<ok-dropzone\x0a\x20\x20\x20\x20@files-drop=\x22onFilesDropped($event)\x22\x0a\x20\x20\x20\x20style=\x22border:2px\x20dashed\x20var(--okdb-app-border);\x20border-radius:8px;\x20padding:24px\x2012px;\x20text-align:center;\x20cursor:pointer;\x20transition:border-color\x20.15s;\x22\x0a\x20\x20\x20\x20@click=\x22onBrowse()\x22\x0a\x20\x20>\x0a\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20align-items:center;\x20gap:6px;\x20pointer-events:none;\x22>\x0a\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:28px;\x20opacity:.6;\x22>📁</span>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:13px;\x20opacity:.7;\x22>Drop\x20files\x20or\x20folders\x20here,\x20or\x20<span\x20style=\x22color:var(--okdb-accent);\x20text-decoration:underline;\x22>browse</span></div>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20opacity:.4;\x22>Uploading\x20to\x20<strong>{{\x20path\x20}}</strong></div>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</ok-dropzone>\x0a\x0a\x20\x20<!--\x20Summary\x20bar\x20-->\x0a\x20\x20<if\x20:=\x22queue.length\x20>\x200\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20align-items:center;\x20gap:8px;\x20font-size:12px;\x22>\x0a\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.5;\x22>{{\x20queue.length\x20}}\x20file(s)</span>\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22uploadingCount\x20>\x200\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22color:var(--okdb-accent);\x22>↑\x20{{\x20uploadingCount\x20}}\x20uploading</span>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22doneCount\x20>\x200\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22color:var(--okdb-success);\x22>✓\x20{{\x20doneCount\x20}}\x20done</span>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22errorCount\x20>\x200\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22color:var(--okdb-danger);\x22>✗\x20{{\x20errorCount\x20}}\x20failed</span>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20<span\x20style=\x22flex:1;\x22></span>\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22doneCount\x20>\x200\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22clearDone()\x22\x20style=\x22font-size:11px;\x20padding:2px\x208px;\x22>Clear\x20done</button>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20<!--\x20File\x20list\x20-->\x0a\x20\x20\x20\x20<div\x20style=\x22max-height:220px;\x20overflow-y:auto;\x20display:flex;\x20flex-direction:column;\x20gap:2px;\x22>\x0a\x20\x20\x20\x20\x20\x20<each\x20:of=\x22queue\x22\x20let:item=\x22item\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20align-items:center;\x20gap:8px;\x20padding:5px\x208px;\x20border-radius:6px;\x20background:var(--okdb-app-surface);\x20font-size:12px;\x22>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Status\x20dot\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20:style=\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x27width:7px;height:7px;border-radius:50%;flex-shrink:0;background:\x27\x20+\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(item.status\x20===\x20\x27done\x27\x20?\x20\x27var(--okdb-success)\x27\x20:\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20item.status\x20===\x20\x27error\x27\x20?\x20\x27var(--okdb-danger)\x27\x20:\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20item.status\x20===\x20\x27uploading\x27\x20?\x20\x27var(--okdb-accent)\x27\x20:\x20\x27var(--okdb-method-default)\x27)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22></span>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Name\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22flex:1;\x20overflow:hidden;\x20text-overflow:ellipsis;\x20white-space:nowrap;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:title=\x22item.relativePath\x22>{{\x20item.relativePath\x20}}</span>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Size\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22opacity:.5;\x20font-family:monospace;\x20font-size:11px;\x20flex-shrink:0;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20fmtSize(item.file.size)\x20}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</span>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Error\x20message\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22item.status\x20===\x20\x27error\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22color:var(--okdb-danger);\x20font-size:11px;\x20max-width:120px;\x20overflow:hidden;\x20text-overflow:ellipsis;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:title=\x22item.error\x22>{{\x20item.error\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22retryItem(item)\x22\x20style=\x22font-size:10px;\x20padding:1px\x206px;\x22>↻</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Spinner\x20for\x20uploading\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22item.status\x20===\x20\x27uploading\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22color:var(--okdb-accent);\x20font-size:11px;\x20animation:spin\x201s\x20linear\x20infinite;\x22>⟳</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<!--\x20Remove\x20button\x20-->\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22item.status\x20!==\x20\x27uploading\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22removeItem(item)\x22\x20style=\x22font-size:10px;\x20padding:1px\x206px;\x20opacity:.5;\x22>✕</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</each>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a</div>','style':_0x49f344(0x1c9)};
|
|
1
|
+
import e from"../../../components/ok-dropzone.ok.js";import n from"../../../stores/okdb-store.js";export default{tag:"files-upload-panel",props:["path"],dependencies:[e],context:e=>({queue:[],get path(){return e.$attr.path||"/"},onFilesDropped(e){const{files:n}=e.detail;for(const e of n)this.queue.push({file:e,relativePath:e.relativePath||e.name,status:"pending",error:null,record:null});this._flush()},onBrowse(){const e=document.createElement("input");e.type="file",e.multiple=!0,e.onchange=()=>{for(const n of Array.from(e.files))this.queue.push({file:n,relativePath:n.name,status:"pending",error:null,record:null});this._flush()},e.click()},_uploading:!1,async _flush(){if(!this._uploading){this._uploading=!0;try{let e;for(;e=this.queue.find(e=>"pending"===e.status);)await this._uploadOne(e)}finally{this._uploading=!1}}},async _uploadOne(t){t.status="uploading";const o=e.$attr.path||"/";try{const i=(t.relativePath||t.file.name).replace(/^\//,""),s=(o.endsWith("/")?o:o+"/")+i,r=await fetch(`${n.apiBase}/files?path=${encodeURIComponent(s)}`,{method:"POST",headers:{"content-type":t.file.type||"application/octet-stream","content-length":String(t.file.size)},body:t.file}),a=await r.json();if(!r.ok)throw new Error(a?.error?.message||"Upload failed");t.record=a.data,t.status="done",e.$dispatch("uploaded",t.record)}catch(e){t.error=e?.message||String(e),t.status="error"}},retryItem(e){e.status="pending",e.error=null,this._flush()},removeItem(e){const n=this.queue.indexOf(e);-1!==n&&this.queue.splice(n,1)},clearDone(){this.queue=this.queue.filter(e=>"done"!==e.status)},fmtSize:e=>null==e?"—":e<1024?e+" B":e<1048576?(e/1024).toFixed(1)+" KB":(e/1048576).toFixed(1)+" MB",get pendingCount(){return this.queue.filter(e=>"pending"===e.status).length},get uploadingCount(){return this.queue.filter(e=>"uploading"===e.status).length},get doneCount(){return this.queue.filter(e=>"done"===e.status).length},get errorCount(){return this.queue.filter(e=>"error"===e.status).length}}),template:'\n<div style="display:flex; flex-direction:column; gap:10px;">\n\n \x3c!-- Drop zone --\x3e\n <ok-dropzone\n @files-drop="onFilesDropped($event)"\n style="border:2px dashed var(--okdb-app-border); border-radius:8px; padding:24px 12px; text-align:center; cursor:pointer; transition:border-color .15s;"\n @click="onBrowse()"\n >\n <div style="display:flex; flex-direction:column; align-items:center; gap:6px; pointer-events:none;">\n <span style="font-size:28px; opacity:.6;">📁</span>\n <div style="font-size:13px; opacity:.7;">Drop files or folders here, or <span style="color:var(--okdb-accent); text-decoration:underline;">browse</span></div>\n <div style="font-size:11px; opacity:.4;">Uploading to <strong>{{ path }}</strong></div>\n </div>\n </ok-dropzone>\n\n \x3c!-- Summary bar --\x3e\n <if :="queue.length > 0">\n <div style="display:flex; align-items:center; gap:8px; font-size:12px;">\n <span style="opacity:.5;">{{ queue.length }} file(s)</span>\n <if :="uploadingCount > 0">\n <span style="color:var(--okdb-accent);">↑ {{ uploadingCount }} uploading</span>\n </if>\n <if :="doneCount > 0">\n <span style="color:var(--okdb-success);">✓ {{ doneCount }} done</span>\n </if>\n <if :="errorCount > 0">\n <span style="color:var(--okdb-danger);">✗ {{ errorCount }} failed</span>\n </if>\n <span style="flex:1;"></span>\n <if :="doneCount > 0">\n <button @click="clearDone()" style="font-size:11px; padding:2px 8px;">Clear done</button>\n </if>\n </div>\n\n \x3c!-- File list --\x3e\n <div style="max-height:220px; overflow-y:auto; display:flex; flex-direction:column; gap:2px;">\n <each :of="queue" let:item="item">\n <div style="display:flex; align-items:center; gap:8px; padding:5px 8px; border-radius:6px; background:var(--okdb-app-surface); font-size:12px;">\n\n \x3c!-- Status dot --\x3e\n <span :style="\n \'width:7px;height:7px;border-radius:50%;flex-shrink:0;background:\' +\n (item.status === \'done\' ? \'var(--okdb-success)\' :\n item.status === \'error\' ? \'var(--okdb-danger)\' :\n item.status === \'uploading\' ? \'var(--okdb-accent)\' : \'var(--okdb-method-default)\')\n "></span>\n\n \x3c!-- Name --\x3e\n <span style="flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;"\n :title="item.relativePath">{{ item.relativePath }}</span>\n\n \x3c!-- Size --\x3e\n <span style="opacity:.5; font-family:monospace; font-size:11px; flex-shrink:0;">\n {{ fmtSize(item.file.size) }}\n </span>\n\n \x3c!-- Error message --\x3e\n <if :="item.status === \'error\'">\n <span style="color:var(--okdb-danger); font-size:11px; max-width:120px; overflow:hidden; text-overflow:ellipsis;"\n :title="item.error">{{ item.error }}</span>\n <button @click="retryItem(item)" style="font-size:10px; padding:1px 6px;">↻</button>\n </if>\n\n \x3c!-- Spinner for uploading --\x3e\n <if :="item.status === \'uploading\'">\n <span style="color:var(--okdb-accent); font-size:11px; animation:spin 1s linear infinite;">⟳</span>\n </if>\n\n \x3c!-- Remove button --\x3e\n <if :="item.status !== \'uploading\'">\n <button @click="removeItem(item)" style="font-size:10px; padding:1px 6px; opacity:.5;">✕</button>\n </if>\n\n </div>\n </each>\n </div>\n </if>\n\n</div>',style:"\n@keyframes spin { to { transform: rotate(360deg); } }\n"};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<script type="module">import functionDetail from"./parts/function-detail.ok.js";import functionLogs from"./parts/function-logs.ok.js";import functionRunner from"./parts/function-runner.ok.js";import functionModal from"./modals/function-modal.ok.js";import functionsList from"./parts/functions-list.ok.js";export default{tag:"functions-index",unwrap:!0,dependencies:[functionsList,functionDetail,functionRunner,functionLogs,functionModal],context:n=>({get functions(){return n.$ok.stores.functions},get isGlobal(){return this.functions.isGlobalScope},get envName(){return this.functions.envName},get canManage(){return this.functions.canOpenModal},get isDetailView(){return"detail"===this.functions.currentView&&this.functions.hasSelected},get isOverviewView(){return!this.isDetailView},get selectedName(){return this.functions.selectedName},get totalFunctions(){return this.functions.functionsOverview.length},get enabledCount(){return this.functions.functionsOverview.filter(n=>!1!==n.value?.enabled).length},get disabledCount(){return this.functions.functionsOverview.filter(n=>!1===n.value?.enabled).length},get neverRunCount(){return this.functions.functionsOverview.filter(n=>!n.latestRun).length},get recentSuccessCount(){return this.functions.overviewRuns.filter(n=>"success"===n.value?.status).length},get recentErrorCount(){return this.functions.overviewRuns.filter(n=>["error","timeout","killed"].includes(n.value?.status)).length},fmt:n=>Number(n||0).toLocaleString(),relTime(n){if(!n)return"—";const t=Date.now()-n;return t<5e3?"just now":t<6e4?`${Math.round(t/1e3)}s ago`:t<36e5?`${Math.round(t/6e4)}m ago`:t<864e5?`${Math.round(t/36e5)}h ago`:new Date(n).toLocaleDateString()},latestLogLine(n){const t=n?.latestRun?.id||n?.latestRun?.runId;if(!t)return null;const e=this.functions.logsForRun(t);return e.length?e[e.length-1]?.msg:null},getRouteFunctionName(){try{const n=globalThis.location?.hash||"",t=n.includes("?")?n.split("?")[1]:"";return new URLSearchParams(t).get("name")}catch{return null}},goOverview(){const t=n.$ok.stores.functions;t.setView("overview"),t.select(null),n.$vars.$router?.push?.("/functions")},async openFunction(t){t&&(await n.$ok.stores.functions.select(t),n.$vars.$router?.push?.("/functions?name="+encodeURIComponent(t)))},async openCreateModal(){const t=n.$ok.stores.functions;t.canOpenModal&&(t.beginCreateDraft(),await n.$ok.shared.modal.open({owner:n,title:"Create Function",canDrag:!0,content:'<function-modal :modal="modal" mode="create" :on-done="onDone" />',context:e=>({modal:e,onDone:async e=>{await t.hydrateOverview(),e?.name&&await n.openFunction(e.name)}})}))},async openEditModal(){const t=n.$ok.stores.functions;t.hasSelected&&(t.beginEditDraft(),await n.$ok.shared.modal.open({owner:n,title:`Edit Function · ${t.selectedName}`,canDrag:!0,content:'<function-modal :modal="modal" mode="edit" :on-done="onDone" />',context:n=>({modal:n,onDone:async()=>{await t.select(t.selectedName),await t.loadOverviewRuns()}})}))}}),init(n){const t=async()=>{const t=this.getRouteFunctionName();t?await n.$ok.stores.functions.select(t):n.$ok.stores.functions.setView("overview")};n.$watch(()=>n.$ok.stores.okdb.selectedEnv,()=>n.$ok.stores.functions.onEnvChanged()),n.$watch(()=>globalThis.location?.hash,()=>t()),this.functions.onEnvChanged(),t()}}</script><template><component import="../../layouts/_default.ok.html"><template name="header"><div style="display:flex;align-items:center;justify-content:space-between;gap:16px;width:100%"><div><div style="font-size:22px;font-weight:700;color:var(--okdb-app-fg)">Functions</div><div style="margin-top:4px;font-size:12px;color:var(--okdb-app-fg-muted)"><if :="envName">{{ envName }}</if><if :="!envName">No environment selected</if></div><if :="isDetailView"><div style="margin-top:8px;font-size:13px;color:#a7c0d1">Viewing <strong>{{ selectedName }}</strong></div></if></div><div style="font-size:11px;color:var(--okdb-app-fg-muted);text-transform:uppercase;letter-spacing:.08em"><div>{{ envName || '—' }}</div></div></div></template><template name="sidebar"><functions-list @create="openCreateModal()" @overview="goOverview()" @open="openFunction($event.detail)"></functions-list></template><template name="default"><if :="isOverviewView"><div style="display:flex;flex-direction:column;gap:20px;max-width:980px"><div style="display:flex;align-items:center;gap:10px"><div style="font-weight:600;font-size:18px">Functions Overview</div><div style="margin-left:auto"><button @click="openCreateModal()" :disabled="!canManage" style="font-size:12px;padding:5px 12px;opacity:.85">+ New function</button></div></div><div class="fn-ov-stat-row"><div class="fn-ov-stat-card"><div class="fn-ov-stat-label">Functions</div><div class="fn-ov-stat-value" style="color:var(--okdb-accent)">{{ fmt(totalFunctions) }}</div></div><div class="fn-ov-stat-card"><div class="fn-ov-stat-label">Enabled</div><div class="fn-ov-stat-value" style="color:#4ade80">{{ fmt(enabledCount) }}</div></div><div class="fn-ov-stat-card"><div class="fn-ov-stat-label">Recent Success</div><div class="fn-ov-stat-value" style="color:var(--okdb-success)">{{ fmt(recentSuccessCount) }}</div></div><div class="fn-ov-stat-card"><div class="fn-ov-stat-label">Recent Failures</div><div class="fn-ov-stat-value" style="color:var(--okdb-danger)">{{ fmt(recentErrorCount) }}</div></div></div><if :="functions.functionsOverview.length === 0"><div class="fn-ov-empty"><div style="font-size:30px;margin-bottom:12px">ƒ</div><div style="font-weight:600;font-size:15px;margin-bottom:5px">No functions registered yet</div><div style="font-size:13px;opacity:.6;line-height:1.7">Create your first function from the sidebar and use the draft runner to validate it before saving.</div></div></if><if :="functions.functionsOverview.length > 0"><div class="fn-ov-card"><div class="fn-ov-card-head"><span style="font-weight:600;font-size:14px">Functions</span> <span style="font-size:12px;opacity:.45;margin-left:auto">{{ totalFunctions }} total · {{ neverRunCount }} never run</span></div><table class="fn-ov-table"><thead><tr><th>Name</th><th>Status</th><th style="text-align:right">Runs</th><th style="text-align:right">Latest</th><th></th></tr></thead><tbody><tr as="repeat" :of="functions.functionsOverview" let:item="fn" class="fn-ov-row" @click="openFunction(fn.key)"><td><div style="display:flex;flex-direction:column;gap:4px"><span style="font-family:monospace;font-size:13px;color:var(--okdb-app-fg)">{{ fn.key }}</span> <span style="font-size:11px;color:var(--okdb-app-fg-muted);max-width:360px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">{{ fn.value?.metadata?.description || 'No description yet.' }}</span><if :="latestLogLine(fn)"><span style="font-size:11px;color:#8db1c8;max-width:360px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">log: {{ latestLogLine(fn) }}</span></if></div></td><td><span :style="fn.value?.enabled === false ? 'font-size:10px; color:var(--okdb-danger); text-transform:uppercase;' : 'font-size:10px; color:var(--okdb-success); text-transform:uppercase;'">{{ fn.value?.enabled === false ? 'disabled' : (fn.latestRun?.status || 'ready') }}</span></td><td style="text-align:right;color:var(--okdb-accent);font-weight:600">{{ fmt(functions.overviewRuns.filter(row => row.value?.functionName === fn.key).length) }}</td><td style="text-align:right;opacity:.55;font-size:12px">{{ relTime(fn.latestRun?.execution?.finishedAt ?? fn.latestRun?.request?.requestedAt) }}</td><td style="text-align:right;opacity:.3;font-size:11px;padding-right:16px">→</td></tr></tbody></table></div><div class="fn-ov-card"><div class="fn-ov-card-head"><span style="font-weight:600;font-size:14px">Recent Executions</span> <span style="font-size:12px;opacity:.4;margin-left:auto">last {{ functions.overviewRuns.length }}</span></div><table style="width:100%;border-collapse:collapse;font-size:12px"><tbody><tr as="repeat" :of="functions.overviewRuns" let:item="row" class="fn-ov-row fn-ov-row--sm" @click="openFunction(row.value?.functionName)"><td class="fn-ov-td" style="font-family:monospace;font-size:11px;color:var(--okdb-app-fg);padding-left:16px">{{ row.value?.functionName || row.key }}</td><td class="fn-ov-td"><span :style="row.value?.status === 'success' ? 'font-size:10px; color:var(--okdb-success);' : 'font-size:10px; color:var(--okdb-danger);'">{{ row.value?.status || '—' }}</span></td><td class="fn-ov-td" style="font-family:monospace;font-size:11px;opacity:.45;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">{{ row.value?.id || row.key }}</td><td class="fn-ov-td" style="text-align:right;opacity:.35;white-space:nowrap;font-size:11px;padding-right:16px">{{ relTime(row.value?.execution?.finishedAt ?? row.value?.request?.requestedAt) }}</td></tr></tbody></table></div><function-logs title="Live function logs" empty="Run a function to see logs here."></function-logs></if></div></if><if :="isDetailView"><div style="display:grid;grid-template-columns:minmax(0,1.45fr) minmax(360px,.95fr);gap:16px;height:100%;min-height:0"><div style="display:grid;grid-template-rows:minmax(0,1fr) minmax(260px,.85fr);gap:16px;min-height:0"><div style="min-height:0;overflow:auto"><function-detail :on-edit="openEditModal"></function-detail></div><div style="min-height:0;overflow:auto"><function-logs :run-id="functions.selectedRun?.id || functions.selectedRun?.runId" :entries="functions.selectedLogEntries" title="Selected function live logs" empty="No logs captured for the selected run yet."></function-logs></div></div><div style="min-height:0;overflow:auto"><function-runner></function-runner></div></div></if></template></component></template><style>.fn-ov-stat-row{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px}.fn-ov-card,.fn-ov-stat-card{border:1px solid var(--okdb-app-border);border-radius:12px;background:var(--okdb-app-bg-deep)}.fn-ov-stat-card{padding:14px}.fn-ov-stat-label{font-size:11px;text-transform:uppercase;color:var(--okdb-app-fg-muted);margin-bottom:6px}.fn-ov-stat-value{font-size:24px;font-weight:700;color:var(--okdb-app-fg)}.fn-ov-empty{border:1px dashed var(--okdb-app-border);border-radius:12px;padding:24px;text-align:center;color:var(--okdb-app-fg-muted);background:var(--okdb-app-bg-deep)}.fn-ov-card-head{display:flex;align-items:center;gap:10px;padding:14px 16px;border-bottom:1px solid var(--okdb-app-border)}.fn-ov-table{width:100%;border-collapse:collapse;font-size:12px}.fn-ov-table thead th{text-align:left;padding:10px 16px;color:var(--okdb-app-fg-muted);font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;border-bottom:1px solid var(--okdb-app-border)}.fn-ov-row{cursor:pointer}.fn-ov-row:hover{background:var(--okdb-app-bg-deep)}.fn-ov-row td,.fn-ov-td{padding:12px 16px;border-bottom:1px solid var(--okdb-app-border)}.fn-ov-row--sm .fn-ov-td,.fn-ov-row--sm td{padding-top:10px;padding-bottom:10px}</style>
|
|
1
|
+
<script type="module">import e from"./parts/function-detail.ok.js";import t from"./parts/function-logs.ok.js";import n from"./parts/function-runner.ok.js";import o from"./modals/function-modal.ok.js";import s from"./parts/functions-list.ok.js";export default{tag:"functions-index",unwrap:!0,dependencies:[s,e,n,t,o],context:e=>({get functions(){return e.$ok.stores.functions},get isGlobal(){return this.functions.isGlobalScope},get envName(){return this.functions.envName},get canManage(){return this.functions.canOpenModal},get isDetailView(){return"detail"===this.functions.currentView&&this.functions.hasSelected},get isOverviewView(){return!this.isDetailView},get selectedName(){return this.functions.selectedName},get totalFunctions(){return this.functions.functionsOverview.length},get enabledCount(){return this.functions.functionsOverview.filter(e=>!1!==e.value?.enabled).length},get disabledCount(){return this.functions.functionsOverview.filter(e=>!1===e.value?.enabled).length},get neverRunCount(){return this.functions.functionsOverview.filter(e=>!e.latestRun).length},get recentSuccessCount(){return this.functions.overviewRuns.filter(e=>"success"===e.value?.status).length},get recentErrorCount(){return this.functions.overviewRuns.filter(e=>["error","timeout","killed"].includes(e.value?.status)).length},fmt:e=>Number(e||0).toLocaleString(),relTime(e){if(!e)return"—";const t=Date.now()-e;return t<5e3?"just now":t<6e4?`${Math.round(t/1e3)}s ago`:t<36e5?`${Math.round(t/6e4)}m ago`:t<864e5?`${Math.round(t/36e5)}h ago`:new Date(e).toLocaleDateString()},latestLogLine(e){const t=e?.latestRun?.id||e?.latestRun?.runId;if(!t)return null;const n=this.functions.logsForRun(t);return n.length?n[n.length-1]?.msg:null},getRouteFunctionName(){try{const e=globalThis.location?.hash||"",t=e.includes("?")?e.split("?")[1]:"";return new URLSearchParams(t).get("name")}catch{return null}},goOverview(){const t=e.$ok.stores.functions;t.setView("overview"),t.select(null),e.$vars.$router?.push?.("/functions")},async openFunction(t){t&&(await e.$ok.stores.functions.select(t),e.$vars.$router?.push?.("/functions?name="+encodeURIComponent(t)))},async openCreateModal(){const t=e.$ok.stores.functions;t.canOpenModal&&(t.beginCreateDraft(),await e.$ok.shared.modal.open({owner:e,title:"Create Function",canDrag:!0,content:'<function-modal :modal="modal" mode="create" :on-done="onDone" />',context:n=>({modal:n,onDone:async n=>{await t.hydrateOverview(),n?.name&&await e.openFunction(n.name)}})}))},async openEditModal(){const t=e.$ok.stores.functions;t.hasSelected&&(t.beginEditDraft(),await e.$ok.shared.modal.open({owner:e,title:`Edit Function · ${t.selectedName}`,canDrag:!0,content:'<function-modal :modal="modal" mode="edit" :on-done="onDone" />',context:e=>({modal:e,onDone:async()=>{await t.select(t.selectedName),await t.loadOverviewRuns()}})}))}}),init(e){const t=async()=>{const t=this.getRouteFunctionName();t?await e.$ok.stores.functions.select(t):e.$ok.stores.functions.setView("overview")};e.$watch(()=>e.$ok.stores.okdb.selectedEnv,()=>e.$ok.stores.functions.onEnvChanged()),e.$watch(()=>globalThis.location?.hash,()=>t()),this.functions.onEnvChanged(),t()}};</script><template><component import="../../layouts/_default.ok.html"><template name="header"><div style="display:flex;align-items:center;justify-content:space-between;gap:16px;width:100%"><div><div style="font-size:22px;font-weight:700;color:var(--okdb-app-fg)">Functions</div><div style="margin-top:4px;font-size:12px;color:var(--okdb-app-fg-muted)"><if :="envName">{{ envName }}</if><if :="!envName">No environment selected</if></div><if :="isDetailView"><div style="margin-top:8px;font-size:13px;color:#a7c0d1">Viewing <strong>{{ selectedName }}</strong></div></if></div><div style="font-size:11px;color:var(--okdb-app-fg-muted);text-transform:uppercase;letter-spacing:.08em"><div>{{ envName || '—' }}</div></div></div></template><template name="sidebar"><functions-list @create="openCreateModal()" @overview="goOverview()" @open="openFunction($event.detail)"></functions-list></template><template name="default"><if :="isOverviewView"><div style="display:flex;flex-direction:column;gap:20px;max-width:980px"><div style="display:flex;align-items:center;gap:10px"><div style="font-weight:600;font-size:18px">Functions Overview</div><div style="margin-left:auto"><button @click="openCreateModal()" :disabled="!canManage" style="font-size:12px;padding:5px 12px;opacity:.85">+ New function</button></div></div><div class="fn-ov-stat-row"><div class="fn-ov-stat-card"><div class="fn-ov-stat-label">Functions</div><div class="fn-ov-stat-value" style="color:var(--okdb-accent)">{{ fmt(totalFunctions) }}</div></div><div class="fn-ov-stat-card"><div class="fn-ov-stat-label">Enabled</div><div class="fn-ov-stat-value" style="color:#4ade80">{{ fmt(enabledCount) }}</div></div><div class="fn-ov-stat-card"><div class="fn-ov-stat-label">Recent Success</div><div class="fn-ov-stat-value" style="color:var(--okdb-success)">{{ fmt(recentSuccessCount) }}</div></div><div class="fn-ov-stat-card"><div class="fn-ov-stat-label">Recent Failures</div><div class="fn-ov-stat-value" style="color:var(--okdb-danger)">{{ fmt(recentErrorCount) }}</div></div></div><if :="functions.functionsOverview.length === 0"><div class="fn-ov-empty"><div style="font-size:30px;margin-bottom:12px">ƒ</div><div style="font-weight:600;font-size:15px;margin-bottom:5px">No functions registered yet</div><div style="font-size:13px;opacity:.6;line-height:1.7">Create your first function from the sidebar and use the draft runner to validate it before saving.</div></div></if><if :="functions.functionsOverview.length > 0"><div class="fn-ov-card"><div class="fn-ov-card-head"><span style="font-weight:600;font-size:14px">Functions</span> <span style="font-size:12px;opacity:.45;margin-left:auto">{{ totalFunctions }} total · {{ neverRunCount }} never run</span></div><table class="fn-ov-table"><thead><tr><th>Name</th><th>Status</th><th style="text-align:right">Runs</th><th style="text-align:right">Latest</th><th></th></tr></thead><tbody><tr as="repeat" :of="functions.functionsOverview" let:item="fn" class="fn-ov-row" @click="openFunction(fn.key)"><td><div style="display:flex;flex-direction:column;gap:4px"><span style="font-family:monospace;font-size:13px;color:var(--okdb-app-fg)">{{ fn.key }}</span> <span style="font-size:11px;color:var(--okdb-app-fg-muted);max-width:360px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">{{ fn.value?.metadata?.description || 'No description yet.' }}</span><if :="latestLogLine(fn)"><span style="font-size:11px;color:#8db1c8;max-width:360px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">log: {{ latestLogLine(fn) }}</span></if></div></td><td><span :style="fn.value?.enabled === false ? 'font-size:10px; color:var(--okdb-danger); text-transform:uppercase;' : 'font-size:10px; color:var(--okdb-success); text-transform:uppercase;'">{{ fn.value?.enabled === false ? 'disabled' : (fn.latestRun?.status || 'ready') }}</span></td><td style="text-align:right;color:var(--okdb-accent);font-weight:600">{{ fmt(functions.overviewRuns.filter(row => row.value?.functionName === fn.key).length) }}</td><td style="text-align:right;opacity:.55;font-size:12px">{{ relTime(fn.latestRun?.execution?.finishedAt ?? fn.latestRun?.request?.requestedAt) }}</td><td style="text-align:right;opacity:.3;font-size:11px;padding-right:16px">→</td></tr></tbody></table></div><div class="fn-ov-card"><div class="fn-ov-card-head"><span style="font-weight:600;font-size:14px">Recent Executions</span> <span style="font-size:12px;opacity:.4;margin-left:auto">last {{ functions.overviewRuns.length }}</span></div><table style="width:100%;border-collapse:collapse;font-size:12px"><tbody><tr as="repeat" :of="functions.overviewRuns" let:item="row" class="fn-ov-row fn-ov-row--sm" @click="openFunction(row.value?.functionName)"><td class="fn-ov-td" style="font-family:monospace;font-size:11px;color:var(--okdb-app-fg);padding-left:16px">{{ row.value?.functionName || row.key }}</td><td class="fn-ov-td"><span :style="row.value?.status === 'success' ? 'font-size:10px; color:var(--okdb-success);' : 'font-size:10px; color:var(--okdb-danger);'">{{ row.value?.status || '—' }}</span></td><td class="fn-ov-td" style="font-family:monospace;font-size:11px;opacity:.45;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">{{ row.value?.id || row.key }}</td><td class="fn-ov-td" style="text-align:right;opacity:.35;white-space:nowrap;font-size:11px;padding-right:16px">{{ relTime(row.value?.execution?.finishedAt ?? row.value?.request?.requestedAt) }}</td></tr></tbody></table></div><function-logs title="Live function logs" empty="Run a function to see logs here."></function-logs></if></div></if><if :="isDetailView"><div style="display:grid;grid-template-columns:minmax(0,1.45fr) minmax(360px,.95fr);gap:16px;height:100%;min-height:0"><div style="display:grid;grid-template-rows:minmax(0,1fr) minmax(260px,.85fr);gap:16px;min-height:0"><div style="min-height:0;overflow:auto"><function-detail :on-edit="openEditModal"></function-detail></div><div style="min-height:0;overflow:auto"><function-logs :run-id="functions.selectedRun?.id || functions.selectedRun?.runId" :entries="functions.selectedLogEntries" title="Selected function live logs" empty="No logs captured for the selected run yet."></function-logs></div></div><div style="min-height:0;overflow:auto"><function-runner></function-runner></div></div></if></template></component></template><style>.fn-ov-stat-row{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px}.fn-ov-card,.fn-ov-stat-card{border:1px solid var(--okdb-app-border);border-radius:12px;background:var(--okdb-app-bg-deep)}.fn-ov-stat-card{padding:14px}.fn-ov-stat-label{font-size:11px;text-transform:uppercase;color:var(--okdb-app-fg-muted);margin-bottom:6px}.fn-ov-stat-value{font-size:24px;font-weight:700;color:var(--okdb-app-fg)}.fn-ov-empty{border:1px dashed var(--okdb-app-border);border-radius:12px;padding:24px;text-align:center;color:var(--okdb-app-fg-muted);background:var(--okdb-app-bg-deep)}.fn-ov-card-head{display:flex;align-items:center;gap:10px;padding:14px 16px;border-bottom:1px solid var(--okdb-app-border)}.fn-ov-table{width:100%;border-collapse:collapse;font-size:12px}.fn-ov-table thead th{text-align:left;padding:10px 16px;color:var(--okdb-app-fg-muted);font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;border-bottom:1px solid var(--okdb-app-border)}.fn-ov-row{cursor:pointer}.fn-ov-row:hover{background:var(--okdb-app-bg-deep)}.fn-ov-row td,.fn-ov-td{padding:12px 16px;border-bottom:1px solid var(--okdb-app-border)}.fn-ov-row--sm .fn-ov-td,.fn-ov-row--sm td{padding-top:10px;padding-bottom:10px}</style>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const _0x38fc4a=_0x4d5f;function _0xb7a4(){const _0x46398a=['onDone','modalEnabledDraft','stores','modalProcessorContextDraft','modalValidation','isFinite','2aIcmGL','Edit\x20function','join','modalAllowFetchDraft','Dry\x20run\x20complete','{\x0a\x20\x20\x0a}','72335CTQSul','modalPayloadDraft','mode','modalRunning','toast','success','canSave','store','modalDryRunMode','Create\x20function','1393407agPHLX','342384iFjWyX','dryRunActions','$ok','functions','Failed\x20to\x20run\x20draft','modalDescriptionDraft','Function\x20created:\x20','edit','canRun','modalNameDraft','Failed\x20to\x20save\x20function','stringify','name','previewRunId','modalTimeoutMsDraft','2326535pTHOkT','error','modalJobContextDraft','$attr','modalMemoryMbDraft','length','modalPayloadError','close','message','8119296nBuhWa','modalUnsafeDraft','\x0a<div\x20style=\x22position:relative;\x20width:min(1220px,\x20calc(100vw\x20-\x2060px));\x20max-width:calc(100vw\x20-\x2060px);\x20min-width:900px;\x20min-height:760px;\x20display:flex;\x20flex-direction:column;\x20gap:16px;\x22>\x0a\x20\x20<if\x20:=\x22saving\x20||\x20running\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<div\x20style=\x22display:flex;\x20align-items:flex-start;\x20justify-content:space-between;\x20gap:16px;\x22>\x0a\x20\x20\x20\x20<div>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:18px;\x20font-weight:700;\x20color:var(--okdb-app-fg);\x22>{{\x20titleLabel\x20}}</div>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22margin-top:4px;\x20font-size:12px;\x20color:var(--okdb-app-fg-muted);\x22>Scope:\x20{{\x20scopeLabel\x20}}</div>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20align-items:center;\x20gap:16px;\x20font-size:12px;\x20color:var(--okdb-app-fg-muted);\x22>\x0a\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<input\x20type=\x22checkbox\x22\x20:checked=\x22store.modalEnabledDraft\x20!==\x20false\x22\x20@change=\x22setEnabled($el.checked)\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20Enabled\x0a\x20\x20\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20\x20\x20<label\x20:style=\x22unsafe\x20?\x20\x27display:flex;\x20align-items:center;\x20gap:6px;\x20cursor:pointer;\x20user-select:none;\x20color:var(--okdb-orange);\x20font-weight:600;\x27\x20:\x20\x27display:flex;\x20align-items:center;\x20gap:6px;\x20cursor:pointer;\x20user-select:none;\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x20:checked=\x22store.modalUnsafeDraft\x20===\x20true\x22\x20@change=\x22setUnsafe($el.checked)\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<span>{{\x20unsafe\x20?\x20\x27⚠️\x20Unsafe\x27\x20:\x20\x27Unsafe\x27\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</div>\x0a\x0a\x20\x20<if\x20:=\x22unsafe\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22padding:10px\x2014px;\x20border:1px\x20solid\x20#92400e;\x20border-radius:10px;\x20background:#1c0f00;\x20color:#fdba74;\x20font-size:12px;\x20line-height:1.6;\x20display:flex;\x20gap:10px;\x20align-items:flex-start;\x22>\x0a\x20\x20\x20\x20\x20\x20<span\x20style=\x22font-size:16px;\x20flex-shrink:0;\x22>⚠️</span>\x0a\x20\x20\x20\x20\x20\x20<div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<strong\x20style=\x22color:var(--okdb-orange);\x22>Unsafe\x20function</strong>\x20—\x20this\x20function\x20receives\x0a\x20\x20\x20\x20\x20\x20\x20\x20<code\x20style=\x22color:var(--okdb-warning);\x20background:#2c1800;\x20padding:1px\x205px;\x20border-radius:4px;\x22>ctx.okdb</code>\x0a\x20\x20\x20\x20\x20\x20\x20\x20in\x20addition\x20to\x20<code\x20style=\x22color:var(--okdb-accent-muted);\x20background:var(--okdb-app-bg-deep);\x20padding:1px\x205px;\x20border-radius:4px;\x22>ctx.env</code>.\x0a\x20\x20\x20\x20\x20\x20\x20\x20<code\x20style=\x22color:var(--okdb-warning);\x22>ctx.okdb</code>\x20grants\x20full\x20cross-environment\x20database\x20access\x20including\x20creating\x20and\x20removing\x20environments.\x0a\x20\x20\x20\x20\x20\x20\x20\x20Only\x20use\x20this\x20for\x20privileged,\x20trusted\x20operations.\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<div\x20style=\x22display:grid;\x20grid-template-columns:minmax(320px,\x20380px)\x20minmax(0,\x201fr);\x20gap:16px;\x20min-height:0;\x20flex:1;\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:12px;\x20min-height:0;\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22padding:14px;\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:12px;\x20background:var(--okdb-app-bg-deep);\x20display:flex;\x20flex-direction:column;\x20gap:12px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20min-width:0;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20text-transform:uppercase;\x20letter-spacing:.08em;\x20color:var(--okdb-app-fg-muted);\x20margin-bottom:6px;\x22>Function\x20name</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22width:100%;\x20box-sizing:border-box;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20placeholder=\x22e.g.\x20queueFanout\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:value=\x22store.modalNameDraft\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:disabled=\x22mode\x20===\x20\x27edit\x27\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@input=\x22setName($el.value)\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22margin-top:6px;\x20font-size:11px;\x20color:var(--okdb-app-fg-muted);\x20line-height:1.5;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Name\x20is\x20immutable\x20after\x20creation\x20and\x20becomes\x20the\x20function\x20entry\x20point.\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20min-width:0;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20text-transform:uppercase;\x20letter-spacing:.08em;\x20color:var(--okdb-app-fg-muted);\x20margin-bottom:6px;\x22>Description</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<textarea\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22width:100%;\x20box-sizing:border-box;\x20min-height:110px;\x20resize:vertical;\x20background:var(--okdb-app-bg-deep);\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:8px;\x20color:#cfe6f2;\x20padding:10px;\x20font-size:12px;\x20line-height:1.5;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20placeholder=\x22What\x20does\x20this\x20function\x20do?\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:value=\x22store.modalDescriptionDraft\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@input=\x22setDescription($el.value)\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20></textarea>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22margin-top:6px;\x20font-size:11px;\x20color:var(--okdb-app-fg-subtle);\x22>{{\x20descriptionLength\x20}}\x20chars</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22padding:14px;\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:12px;\x20background:var(--okdb-app-bg-deep);\x20display:flex;\x20flex-direction:column;\x20gap:10px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20text-transform:uppercase;\x20letter-spacing:.08em;\x20color:var(--okdb-app-fg-muted);\x22>Runtime</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:grid;\x20grid-template-columns:1fr\x201fr;\x20gap:10px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:4px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20color:var(--okdb-app-fg-muted);\x22>Timeout\x20(ms)</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type=\x22number\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20min=\x221\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20step=\x221000\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22width:100%;\x20box-sizing:border-box;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20placeholder=\x225000\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:value=\x22store.modalTimeoutMsDraft\x20??\x20\x27\x27\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@input=\x22setTimeoutMs($el.value)\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:4px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20color:var(--okdb-app-fg-muted);\x22>Memory\x20(MB)</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type=\x22number\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20min=\x221\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20step=\x221\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22width:100%;\x20box-sizing:border-box;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20placeholder=\x2232\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:value=\x22store.modalMemoryMbDraft\x20??\x20\x27\x27\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@input=\x22setMemoryMb($el.value)\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<label\x20style=\x22display:flex;\x20align-items:center;\x20gap:6px;\x20font-size:12px;\x20color:var(--okdb-app-fg-muted);\x20cursor:pointer;\x20user-select:none;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<input\x20type=\x22checkbox\x22\x20:checked=\x22store.modalAllowFetchDraft\x20!==\x20false\x22\x20@change=\x22setAllowFetch($el.checked)\x22\x20/>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Allow\x20fetch\x0a\x20\x20\x20\x20\x20\x20\x20\x20</label>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20color:var(--okdb-app-fg-subtle);\x20line-height:1.5;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Leave\x20blank\x20to\x20use\x20system\x20defaults\x20(timeout:\x205000ms,\x20memory:\x2032MB).\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22padding:14px;\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:12px;\x20background:var(--okdb-app-bg-deep);\x20display:flex;\x20flex-direction:column;\x20gap:10px;\x20min-height:0;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20text-transform:uppercase;\x20letter-spacing:.08em;\x20color:var(--okdb-app-fg-muted);\x22>Run\x20payload</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;\x20color:var(--okdb-app-fg-muted);\x20line-height:1.55;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Define\x20the\x20JSON\x20payload\x20you\x20want\x20to\x20execute\x20right\x20now\x20against\x20this\x20draft\x20before\x20saving\x20it.\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22height:220px;\x20min-height:220px;\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:10px;\x20overflow:hidden;\x20background:var(--okdb-app-bg-deep);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<ok-text-monaco-input\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22height:100%;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20language=\x22json\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:value=\x22store.modalPayloadDraft\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@edit:debounce.150=\x22setPayload($event.detail)\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20></ok-text-monaco-input>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22payloadError\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;\x20color:var(--okdb-danger);\x20line-height:1.5;\x22>{{\x20payloadError\x20}}</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20justify-content:flex-end;\x20gap:8px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@click=\x22toggleModalDryRun()\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:disabled=\x22running\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:style=\x22modalDryRunMode\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20?\x20\x27font-size:12px;\x20border-color:var(--okdb-accent);\x20color:var(--okdb-accent);\x27\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:\x20\x27font-size:12px;\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Dry\x20Run{{\x20modalDryRunMode\x20?\x20\x27\x20✓\x27\x20:\x20\x27\x27\x20}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20@click=\x22runDraft()\x22\x20:disabled=\x22!canRun\x22>{{\x20running\x20?\x20\x27Running…\x27\x20:\x20(modalDryRunMode\x20?\x20\x27Run\x20draft\x20(dry)\x27\x20:\x20\x27Run\x20draft\x27)\x20}}</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20<if\x20:=\x22previewTriggerKind\x20&&\x20previewTriggerContext\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22padding:14px;\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:12px;\x20background:var(--okdb-app-bg-deep);\x20display:flex;\x20flex-direction:column;\x20gap:10px;\x20min-height:0;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20align-items:center;\x20justify-content:space-between;\x20gap:10px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20text-transform:uppercase;\x20letter-spacing:.08em;\x20color:var(--okdb-app-fg-muted);\x22>Preview\x20trigger\x20context</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20color:var(--okdb-accent-muted);\x20font-family:monospace;\x22>ctx.{{\x20previewTriggerKind\x20}}</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;\x20color:var(--okdb-app-fg-muted);\x20line-height:1.55;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20This\x20draft\x20run\x20simulates\x20the\x20engine\x20metadata\x20shown\x20below\x20so\x20you\x20can\x20reproduce\x20handler\x20behavior\x20before\x20saving.\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<pre\x20style=\x22margin:0;\x20white-space:pre-wrap;\x20word-break:break-word;\x20color:var(--okdb-app-fg-muted);\x20font-size:11px;\x20line-height:1.5;\x20max-height:180px;\x20overflow:auto;\x22>{{\x20formatJson(previewTriggerContext)\x20}}</pre>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</if>\x0a\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22padding:14px;\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:12px;\x20background:var(--okdb-app-bg-deep);\x20display:flex;\x20flex-direction:column;\x20gap:6px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20text-transform:uppercase;\x20letter-spacing:.08em;\x20color:var(--okdb-app-fg-muted);\x22>Validation</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22validation.ok\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;\x20color:var(--okdb-success);\x20line-height:1.55;\x22>Function\x20source\x20is\x20valid\x20and\x20can\x20be\x20saved.</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22!validation.ok\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;\x20color:var(--okdb-danger);\x20line-height:1.55;\x22>{{\x20validation.message\x20||\x20\x27Function\x20source\x20is\x20invalid\x27\x20}}</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20color:#c38989;\x20font-family:monospace;\x22>{{\x20validation.code\x20||\x20\x27FUNCTION_SCRIPT_INVALID\x27\x20}}</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20color:var(--okdb-app-fg-subtle);\x20line-height:1.5;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Allowed\x20shape:\x20<span\x20style=\x22font-family:monospace;\x20color:var(--okdb-accent-muted);\x22>[async]\x20(ctx)\x20=>\x20{\x20}</span>.\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Forbidden\x20symbols:\x20<span\x20style=\x22font-family:monospace;\x20color:var(--okdb-accent-muted);\x22>require</span>,\x20<span\x20style=\x22font-family:monospace;\x20color:var(--okdb-accent-muted);\x22>import</span>,\x20<span\x20style=\x22font-family:monospace;\x20color:var(--okdb-accent-muted);\x22>console</span>,\x20<span\x20style=\x22font-family:monospace;\x20color:var(--okdb-accent-muted);\x22>process</span>.\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20<div\x20style=\x22display:grid;\x20grid-template-rows:minmax(0,1.2fr)\x20minmax(220px,.7fr)\x20minmax(240px,.9fr);\x20min-height:0;\x20gap:12px;\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20min-height:0;\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:12px;\x20background:var(--okdb-app-bg-deep);\x20overflow:hidden;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20align-items:center;\x20justify-content:space-between;\x20gap:10px;\x20padding:12px\x2014px;\x20border-bottom:1px\x20solid\x20var(--okdb-app-border);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20text-transform:uppercase;\x20letter-spacing:.08em;\x20color:var(--okdb-app-fg-muted);\x22>Implementation</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20color:var(--okdb-app-fg-muted);\x20font-family:monospace;\x22>async\x20(ctx)\x20=>\x20{\x20}</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22flex:1;\x20min-height:0;\x20background:var(--okdb-app-bg-deep);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<ok-js-input\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22height:100%;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:value=\x22store.modalSourceDraft\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:unsafe=\x22store.modalUnsafeDraft\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:options=\x22{\x20suggest:\x20{\x20showWords:\x20true\x20},\x20wordBasedSuggestions:\x20\x27currentDocument\x27\x20}\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@edit=\x22setSource($event.detail)\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20></ok-js-input>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20justify-content:space-between;\x20align-items:flex-start;\x20gap:12px;\x20font-size:11px;\x20color:var(--okdb-app-fg-subtle);\x20line-height:1.55;\x20padding:10px\x2014px;\x20border-top:1px\x20solid\x20var(--okdb-app-border);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Runtime\x20receives\x20<span\x20style=\x22font-family:monospace;\x20color:var(--okdb-accent-muted);\x22>ctx</span>\x20with\x20DB\x20access\x20facades,\x20payload,\x20logs,\x20and\x20execution\x20info.\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22unsafe\x22><span\x20style=\x22color:var(--okdb-orange);\x22>\x20⚠\x20Unsafe:\x20also\x20exposes\x20<span\x20style=\x22font-family:monospace;\x20color:var(--okdb-warning);\x22>ctx.okdb</span>\x20(full\x20cross-env\x20access).</span></if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22white-space:nowrap;\x22>JS\x20/\x20Monaco</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22padding:14px;\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:12px;\x20background:var(--okdb-app-bg-deep);\x20min-height:0;\x20overflow:auto;\x20display:flex;\x20flex-direction:column;\x20gap:8px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20align-items:center;\x20justify-content:space-between;\x20gap:8px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22previewRun\x20&&\x20modalDryRunActions\x20!==\x20null\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20text-transform:uppercase;\x20letter-spacing:.08em;\x20color:var(--okdb-accent);\x22>Dry\x20run\x20—\x20intercepted\x20writes\x20({{\x20modalDryRunActions.length\x20}})</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22!previewRun\x20||\x20modalDryRunActions\x20===\x20null\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20text-transform:uppercase;\x20letter-spacing:.08em;\x20color:var(--okdb-app-fg-muted);\x22>Draft\x20execution\x20result</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22previewRun\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20color:var(--okdb-app-fg-muted);\x20font-family:monospace;\x22>{{\x20previewRunId\x20}}</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22!previewRun\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;\x20color:var(--okdb-app-fg-muted);\x20line-height:1.5;\x22>Run\x20the\x20draft\x20to\x20see\x20the\x20latest\x20result\x20before\x20you\x20save.</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22previewRun\x20&&\x20modalDryRunActions\x20!==\x20null\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;\x20color:var(--okdb-app-fg-muted);\x20line-height:1.5;\x22>Status:\x20<strong>{{\x20previewRun.status\x20||\x20(previewRun.error\x20?\x20\x27error\x27\x20:\x20\x27ok\x27)\x20}}</strong></div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22modalDryRunActions.length\x20===\x200\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;\x20color:var(--okdb-app-fg-muted);\x22>No\x20writes\x20intercepted.</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:4px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<each\x20:of=\x22modalDryRunActions\x22\x20let:item=\x22action\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22padding:5px\x208px;\x20border:1px\x20solid\x20color-mix(in\x20srgb,\x20var(--okdb-accent)\x2020%,\x20transparent);\x20border-radius:6px;\x20background:color-mix(in\x20srgb,\x20var(--okdb-accent)\x204%,\x20transparent);\x20font-family:monospace;\x20font-size:11px;\x20color:var(--okdb-app-fg-muted);\x20line-height:1.45;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span\x20style=\x22color:var(--okdb-accent);\x22>{{\x20action.scope\x20}}.{{\x20action.method\x20}}</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22action.envName\x22><span\x20style=\x22opacity:.6;\x22>\x20[{{\x20action.envName\x20}}]</span></if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22actionArgs(action)\x22><span>\x20({{\x20actionArgs(action)\x20}})</span></if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</each>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22previewRun.result?.value\x20!==\x20undefined\x20&&\x20previewRun.result?.value\x20!==\x20null\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20text-transform:uppercase;\x20color:var(--okdb-app-fg-muted);\x20margin-top:4px;\x22>Return\x20value</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<pre\x20style=\x22margin:0;\x20white-space:pre-wrap;\x20word-break:break-word;\x20color:var(--okdb-app-fg-muted);\x20font-size:11px;\x20line-height:1.5;\x22>{{\x20formatJson(previewRun.result.value)\x20}}</pre>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22previewRun\x20&&\x20modalDryRunActions\x20===\x20null\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;\x20color:var(--okdb-app-fg-muted);\x20line-height:1.5;\x22>Status:\x20<strong>{{\x20previewRun.status\x20||\x20(previewRun.error\x20?\x20\x27error\x27\x20:\x20\x27ok\x27)\x20}}</strong></div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<pre\x20style=\x22margin:0;\x20white-space:pre-wrap;\x20word-break:break-word;\x20color:var(--okdb-app-fg-muted);\x20font-size:11px;\x20line-height:1.5;\x22>{{\x20formatJson(previewRun.result?.value\x20??\x20previewRun.error\x20??\x20previewRun)\x20}}</pre>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20<function-logs\x20:run-id=\x22previewRunId\x22\x20:entries=\x22previewLogs\x22\x20title=\x22Draft\x20live\x20log\x22\x20empty=\x22Run\x20the\x20draft\x20to\x20stream\x20function\x20logs\x20here.\x22></function-logs>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</div>\x0a\x0a\x20\x20<div\x20style=\x22display:flex;\x20justify-content:flex-end;\x20gap:10px;\x20padding-top:4px;\x22>\x0a\x20\x20\x20\x20<button\x20@click=\x22cancel()\x22>Cancel</button>\x0a\x20\x20\x20\x20<button\x20@click=\x22submit()\x22\x20:disabled=\x22!canSave\x22>{{\x20saveLabel\x20}}</button>\x0a\x20\x20</div>\x0a</div>\x0a\x20\x20\x20\x20','modalMaterializerContextDraft','setModalSourceDraft','runModalDraft','function-modal','Save\x20changes','7jOodDy','previewRun','envName','create','3684744CpeEkp','map','setPayloadDraft','shared','213258CdvyWD','modal','modalPreviewRun'];_0xb7a4=function(){return _0x46398a;};return _0xb7a4();}(function(_0x397165,_0x3d3a94){const _0x162851=_0x4d5f,_0x454e79=_0x397165();while(!![]){try{const _0x584222=-parseInt(_0x162851(0x13c))/0x1+-parseInt(_0x162851(0x136))/0x2*(-parseInt(_0x162851(0x146))/0x3)+-parseInt(_0x162851(0x147))/0x4+-parseInt(_0x162851(0x156))/0x5+-parseInt(_0x162851(0x12d))/0x6*(parseInt(_0x162851(0x167))/0x7)+-parseInt(_0x162851(0x129))/0x8+parseInt(_0x162851(0x15f))/0x9;if(_0x584222===_0x3d3a94)break;else _0x454e79['push'](_0x454e79['shift']());}catch(_0x39d7d5){_0x454e79['push'](_0x454e79['shift']());}}}(_0xb7a4,0x3c5c7));import _0x2f524d from'@toolkit/elements/ok-icon.ok.js';import _0x18cfbf from'@toolkit/core/ok-overlay.ok.js';import _0xb6b7f2 from'../../../components/ok-js-input.ok.js';import _0x2791fc from'../../../components/ok-text-monaco-input.ok.js';function _0x4d5f(_0x50498c,_0x37a1d8){_0x50498c=_0x50498c-0x129;const _0xb7a493=_0xb7a4();let _0x4d5f92=_0xb7a493[_0x50498c];return _0x4d5f92;}import _0x2498eb from'../parts/function-logs.ok.js';export default{'tag':_0x38fc4a(0x165),'dependencies':[_0x2f524d,_0x18cfbf,_0xb6b7f2,_0x2791fc,_0x2498eb],'attr':{'modal':{},'mode':{},'onDone':{}},'context':_0x2655d6=>({get 'store'(){const _0x5becba=_0x38fc4a;return _0x2655d6[_0x5becba(0x149)][_0x5becba(0x132)][_0x5becba(0x14a)];},get 'mode'(){const _0x299d26=_0x38fc4a;return _0x2655d6[_0x299d26(0x159)][_0x299d26(0x13e)]||this[_0x299d26(0x143)]['modalMode']||_0x299d26(0x16a);},get 'saving'(){const _0x19baba=_0x38fc4a;return this[_0x19baba(0x143)]['saving'];},get 'running'(){const _0x198a0c=_0x38fc4a;return this[_0x198a0c(0x143)]['modalRunning'];},get 'validation'(){const _0x37f83a=_0x38fc4a;return this[_0x37f83a(0x143)]['modalValidation']||{};},get 'canSave'(){const _0x2a1480=_0x38fc4a;return this[_0x2a1480(0x143)]['canSaveModal'];},get 'canRun'(){const _0x380a9e=_0x38fc4a;return!!this[_0x380a9e(0x143)][_0x380a9e(0x134)]?.['ok']&&!this[_0x380a9e(0x143)][_0x380a9e(0x15c)]&&!this[_0x380a9e(0x143)][_0x380a9e(0x13f)];},get 'modalDryRunMode'(){const _0x3ae1c7=_0x38fc4a;return this[_0x3ae1c7(0x143)][_0x3ae1c7(0x144)];},get 'modalDryRunActions'(){const _0x4a057c=_0x38fc4a;return this['store'][_0x4a057c(0x12f)]?.['result']?.[_0x4a057c(0x148)]??null;},'toggleModalDryRun'(){const _0x33c320=_0x38fc4a;this[_0x33c320(0x143)][_0x33c320(0x144)]=!this['store']['modalDryRunMode'];},get 'scopeLabel'(){const _0x225a38=_0x38fc4a;return this[_0x225a38(0x143)][_0x225a38(0x169)]||'—';},get 'unsafe'(){const _0x213908=_0x38fc4a;return!0x0===this['store'][_0x213908(0x160)];},get 'titleLabel'(){const _0x52c716=_0x38fc4a;return _0x52c716(0x14e)===this[_0x52c716(0x13e)]?_0x52c716(0x137):'Create\x20function';},get 'saveLabel'(){const _0x4cc3ff=_0x38fc4a;return _0x4cc3ff(0x14e)===this[_0x4cc3ff(0x13e)]?_0x4cc3ff(0x166):_0x4cc3ff(0x145);},get 'descriptionLength'(){const _0x1d088c=_0x38fc4a;return String(this[_0x1d088c(0x143)][_0x1d088c(0x14c)]||'')[_0x1d088c(0x15b)];},get 'payloadError'(){const _0xd84278=_0x38fc4a;return this['store'][_0xd84278(0x15c)];},get 'previewRun'(){return this['store']['modalPreviewRun'];},get 'previewRunId'(){const _0x2123f3=_0x38fc4a;return this[_0x2123f3(0x168)]?.['id']||this['previewRun']?.['runId']||null;},get 'previewLogs'(){const _0x49a040=_0x38fc4a;return this['store']['logsForRun'](this[_0x49a040(0x154)]);},get 'previewTriggerKind'(){const _0x2a9f4c=_0x38fc4a;return this[_0x2a9f4c(0x143)]['modalMaterializerContextDraft']?'materializer':this[_0x2a9f4c(0x143)][_0x2a9f4c(0x133)]?'processor':this[_0x2a9f4c(0x143)][_0x2a9f4c(0x158)]?'job':null;},get 'previewTriggerContext'(){const _0xa19b3f=_0x38fc4a;return this[_0xa19b3f(0x143)][_0xa19b3f(0x162)]||this[_0xa19b3f(0x143)]['modalProcessorContextDraft']||this['store']['modalJobContextDraft']||null;},'setName'(_0x2cf7f8){const _0x2fbe2b=_0x38fc4a;this['store'][_0x2fbe2b(0x150)]=_0x2cf7f8??'';},'setDescription'(_0x2ae687){this['store']['modalDescriptionDraft']=_0x2ae687??'';},'setEnabled'(_0x437437){const _0x3e5a46=_0x38fc4a;this[_0x3e5a46(0x143)][_0x3e5a46(0x131)]=!!_0x437437;},'setUnsafe'(_0xf158e7){const _0x545ed6=_0x38fc4a;this[_0x545ed6(0x143)][_0x545ed6(0x160)]=!!_0xf158e7;},'setTimeoutMs'(_0x31f699){const _0x18b9a5=_0x38fc4a,_0x203e58=parseInt(_0x31f699,0xa);this['store'][_0x18b9a5(0x155)]=Number[_0x18b9a5(0x135)](_0x203e58)&&_0x203e58>0x0?_0x203e58:null;},'setMemoryMb'(_0x145387){const _0x2158a9=_0x38fc4a,_0x20245d=parseInt(_0x145387,0xa);this[_0x2158a9(0x143)][_0x2158a9(0x15a)]=Number[_0x2158a9(0x135)](_0x20245d)&&_0x20245d>0x0?_0x20245d:null;},'setAllowFetch'(_0x158cc6){const _0x1ec7a4=_0x38fc4a;this[_0x1ec7a4(0x143)][_0x1ec7a4(0x139)]=!!_0x158cc6;},'setSource'(_0x59afd1){const _0x552589=_0x38fc4a;this['store'][_0x552589(0x163)](_0x59afd1??'');},'setPayload'(_0x9fe359){const _0x2682f6=_0x38fc4a;this['store']['setModalPayloadDraft'](_0x9fe359??_0x2682f6(0x13b));},async 'submit'(){const _0x5f0810=_0x38fc4a;if(this[_0x5f0810(0x142)])try{const _0xd0734c=await this[_0x5f0810(0x143)]['saveModalDefinition']();this[_0x5f0810(0x143)][_0x5f0810(0x12b)](this[_0x5f0810(0x143)][_0x5f0810(0x13d)]),_0x2655d6[_0x5f0810(0x149)][_0x5f0810(0x12c)]?.[_0x5f0810(0x140)]?.[_0x5f0810(0x141)]?.(_0x5f0810(0x14e)===this[_0x5f0810(0x13e)]?'Function\x20saved:\x20'+(_0xd0734c?.[_0x5f0810(0x153)]||this[_0x5f0810(0x143)]['selectedName']):_0x5f0810(0x14d)+(_0xd0734c?.['name']||this[_0x5f0810(0x143)]['modalNameDraft'])),await _0x2655d6['$attr'][_0x5f0810(0x12e)]['close'](),await _0x2655d6[_0x5f0810(0x159)][_0x5f0810(0x130)]?.(_0xd0734c);}catch(_0x48da1e){_0x2655d6[_0x5f0810(0x149)][_0x5f0810(0x12c)]?.[_0x5f0810(0x140)]?.[_0x5f0810(0x157)]?.(_0x48da1e?.[_0x5f0810(0x15e)]||_0x5f0810(0x151));}},async 'runDraft'(){const _0x4335b0=_0x38fc4a;if(this[_0x4335b0(0x14f)])try{await this['store'][_0x4335b0(0x164)](),_0x2655d6[_0x4335b0(0x149)][_0x4335b0(0x12c)]?.[_0x4335b0(0x140)]?.[_0x4335b0(0x141)]?.(this[_0x4335b0(0x144)]?_0x4335b0(0x13a):'Draft\x20executed');}catch(_0x3efb3d){_0x2655d6[_0x4335b0(0x149)][_0x4335b0(0x12c)]?.[_0x4335b0(0x140)]?.[_0x4335b0(0x157)]?.(_0x3efb3d?.[_0x4335b0(0x15e)]||_0x4335b0(0x14b));}},'actionArgs'(_0x145fc2){const _0x5b8a8a=_0x38fc4a,_0x54712e=_0x145fc2['args']??[];return 0x0===_0x54712e[_0x5b8a8a(0x15b)]?'':_0x54712e[_0x5b8a8a(0x12a)](_0x5d0d07=>JSON['stringify'](_0x5d0d07))[_0x5b8a8a(0x138)](',\x20');},'formatJson'(_0x1591dd){const _0xf13387=_0x38fc4a;try{return JSON[_0xf13387(0x152)](_0x1591dd,null,0x2);}catch{return String(_0x1591dd??'');}},'cancel'(){const _0x4349d2=_0x38fc4a;_0x2655d6[_0x4349d2(0x159)][_0x4349d2(0x12e)][_0x4349d2(0x15d)]();}}),'template':_0x38fc4a(0x161)};
|
|
1
|
+
import e from"@toolkit/elements/ok-icon.ok.js";import t from"@toolkit/core/ok-overlay.ok.js";import n from"../../../components/ok-js-input.ok.js";import o from"../../../components/ok-text-monaco-input.ok.js";import i from"../parts/function-logs.ok.js";export default{tag:"function-modal",dependencies:[e,t,n,o,i],attr:{modal:{},mode:{},onDone:{}},context:e=>({get store(){return e.$ok.stores.functions},get mode(){return e.$attr.mode||this.store.modalMode||"create"},get saving(){return this.store.saving},get running(){return this.store.modalRunning},get validation(){return this.store.modalValidation||{}},get canSave(){return this.store.canSaveModal},get canRun(){return!!this.store.modalValidation?.ok&&!this.store.modalPayloadError&&!this.store.modalRunning},get modalDryRunMode(){return this.store.modalDryRunMode},get modalDryRunActions(){return this.store.modalPreviewRun?.result?.dryRunActions??null},toggleModalDryRun(){this.store.modalDryRunMode=!this.store.modalDryRunMode},get scopeLabel(){return this.store.envName||"—"},get unsafe(){return!0===this.store.modalUnsafeDraft},get titleLabel(){return"edit"===this.mode?"Edit function":"Create function"},get saveLabel(){return"edit"===this.mode?"Save changes":"Create function"},get descriptionLength(){return String(this.store.modalDescriptionDraft||"").length},get payloadError(){return this.store.modalPayloadError},get previewRun(){return this.store.modalPreviewRun},get previewRunId(){return this.previewRun?.id||this.previewRun?.runId||null},get previewLogs(){return this.store.logsForRun(this.previewRunId)},get previewTriggerKind(){return this.store.modalMaterializerContextDraft?"materializer":this.store.modalProcessorContextDraft?"processor":this.store.modalJobContextDraft?"job":null},get previewTriggerContext(){return this.store.modalMaterializerContextDraft||this.store.modalProcessorContextDraft||this.store.modalJobContextDraft||null},setName(e){this.store.modalNameDraft=e??""},setDescription(e){this.store.modalDescriptionDraft=e??""},setEnabled(e){this.store.modalEnabledDraft=!!e},setUnsafe(e){this.store.modalUnsafeDraft=!!e},setTimeoutMs(e){const t=parseInt(e,10);this.store.modalTimeoutMsDraft=Number.isFinite(t)&&t>0?t:null},setMemoryMb(e){const t=parseInt(e,10);this.store.modalMemoryMbDraft=Number.isFinite(t)&&t>0?t:null},setAllowFetch(e){this.store.modalAllowFetchDraft=!!e},setSource(e){this.store.setModalSourceDraft(e??"")},setPayload(e){this.store.setModalPayloadDraft(e??"{\n \n}")},async submit(){if(this.canSave)try{const t=await this.store.saveModalDefinition();this.store.setPayloadDraft(this.store.modalPayloadDraft),e.$ok.shared?.toast?.success?.("edit"===this.mode?`Function saved: ${t?.name||this.store.selectedName}`:`Function created: ${t?.name||this.store.modalNameDraft}`),await e.$attr.modal.close(),await(e.$attr.onDone?.(t))}catch(t){e.$ok.shared?.toast?.error?.(t?.message||"Failed to save function")}},async runDraft(){if(this.canRun)try{await this.store.runModalDraft(),e.$ok.shared?.toast?.success?.(this.modalDryRunMode?"Dry run complete":"Draft executed")}catch(t){e.$ok.shared?.toast?.error?.(t?.message||"Failed to run draft")}},actionArgs(e){const t=e.args??[];return 0===t.length?"":t.map(e=>JSON.stringify(e)).join(", ")},formatJson(e){try{return JSON.stringify(e,null,2)}catch{return String(e??"")}},cancel(){e.$attr.modal.close()}}),template:'\n<div style="position:relative; width:min(1220px, calc(100vw - 60px)); max-width:calc(100vw - 60px); min-width:900px; min-height:760px; display:flex; flex-direction:column; gap:16px;">\n <if :="saving || running">\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 <div style="display:flex; align-items:flex-start; justify-content:space-between; gap:16px;">\n <div>\n <div style="font-size:18px; font-weight:700; color:var(--okdb-app-fg);">{{ titleLabel }}</div>\n <div style="margin-top:4px; font-size:12px; color:var(--okdb-app-fg-muted);">Scope: {{ scopeLabel }}</div>\n </div>\n <div style="display:flex; align-items:center; gap:16px; font-size:12px; color:var(--okdb-app-fg-muted);">\n <label style="display:flex; align-items:center; gap:6px; cursor:pointer; user-select:none;">\n <input type="checkbox" :checked="store.modalEnabledDraft !== false" @change="setEnabled($el.checked)" />\n Enabled\n </label>\n <label :style="unsafe ? \'display:flex; align-items:center; gap:6px; cursor:pointer; user-select:none; color:var(--okdb-orange); font-weight:600;\' : \'display:flex; align-items:center; gap:6px; cursor:pointer; user-select:none;\'">\n <input type="checkbox" :checked="store.modalUnsafeDraft === true" @change="setUnsafe($el.checked)" />\n <span>{{ unsafe ? \'⚠️ Unsafe\' : \'Unsafe\' }}</span>\n </label>\n </div>\n </div>\n\n <if :="unsafe">\n <div style="padding:10px 14px; border:1px solid #92400e; border-radius:10px; background:#1c0f00; color:#fdba74; font-size:12px; line-height:1.6; display:flex; gap:10px; align-items:flex-start;">\n <span style="font-size:16px; flex-shrink:0;">⚠️</span>\n <div>\n <strong style="color:var(--okdb-orange);">Unsafe function</strong> — this function receives\n <code style="color:var(--okdb-warning); background:#2c1800; padding:1px 5px; border-radius:4px;">ctx.okdb</code>\n in addition to <code style="color:var(--okdb-accent-muted); background:var(--okdb-app-bg-deep); padding:1px 5px; border-radius:4px;">ctx.env</code>.\n <code style="color:var(--okdb-warning);">ctx.okdb</code> grants full cross-environment database access including creating and removing environments.\n Only use this for privileged, trusted operations.\n </div>\n </div>\n </if>\n\n <div style="display:grid; grid-template-columns:minmax(320px, 380px) minmax(0, 1fr); gap:16px; min-height:0; flex:1;">\n <div style="display:flex; flex-direction:column; gap:12px; min-height:0;">\n <div style="padding:14px; border:1px solid var(--okdb-app-border); border-radius:12px; background:var(--okdb-app-bg-deep); display:flex; flex-direction:column; gap:12px;">\n <div style="display:flex; flex-direction:column; min-width:0;">\n <div style="font-size:11px; text-transform:uppercase; letter-spacing:.08em; color:var(--okdb-app-fg-muted); margin-bottom:6px;">Function name</div>\n <input\n style="width:100%; box-sizing:border-box;"\n placeholder="e.g. queueFanout"\n :value="store.modalNameDraft"\n :disabled="mode === \'edit\'"\n @input="setName($el.value)"\n />\n <div style="margin-top:6px; font-size:11px; color:var(--okdb-app-fg-muted); line-height:1.5;">\n Name is immutable after creation and becomes the function entry point.\n </div>\n </div>\n\n <div style="display:flex; flex-direction:column; min-width:0;">\n <div style="font-size:11px; text-transform:uppercase; letter-spacing:.08em; color:var(--okdb-app-fg-muted); margin-bottom:6px;">Description</div>\n <textarea\n style="width:100%; box-sizing:border-box; min-height:110px; resize:vertical; background:var(--okdb-app-bg-deep); border:1px solid var(--okdb-app-border); border-radius:8px; color:#cfe6f2; padding:10px; font-size:12px; line-height:1.5;"\n placeholder="What does this function do?"\n :value="store.modalDescriptionDraft"\n @input="setDescription($el.value)"\n ></textarea>\n <div style="margin-top:6px; font-size:11px; color:var(--okdb-app-fg-subtle);">{{ descriptionLength }} chars</div>\n </div>\n </div>\n\n <div style="padding:14px; border:1px solid var(--okdb-app-border); border-radius:12px; background:var(--okdb-app-bg-deep); display:flex; flex-direction:column; gap:10px;">\n <div style="font-size:11px; text-transform:uppercase; letter-spacing:.08em; color:var(--okdb-app-fg-muted);">Runtime</div>\n <div style="display:grid; grid-template-columns:1fr 1fr; gap:10px;">\n <div style="display:flex; flex-direction:column; gap:4px;">\n <div style="font-size:11px; color:var(--okdb-app-fg-muted);">Timeout (ms)</div>\n <input\n type="number"\n min="1"\n step="1000"\n style="width:100%; box-sizing:border-box;"\n placeholder="5000"\n :value="store.modalTimeoutMsDraft ?? \'\'"\n @input="setTimeoutMs($el.value)"\n />\n </div>\n <div style="display:flex; flex-direction:column; gap:4px;">\n <div style="font-size:11px; color:var(--okdb-app-fg-muted);">Memory (MB)</div>\n <input\n type="number"\n min="1"\n step="1"\n style="width:100%; box-sizing:border-box;"\n placeholder="32"\n :value="store.modalMemoryMbDraft ?? \'\'"\n @input="setMemoryMb($el.value)"\n />\n </div>\n </div>\n <label style="display:flex; align-items:center; gap:6px; font-size:12px; color:var(--okdb-app-fg-muted); cursor:pointer; user-select:none;">\n <input type="checkbox" :checked="store.modalAllowFetchDraft !== false" @change="setAllowFetch($el.checked)" />\n Allow fetch\n </label>\n <div style="font-size:11px; color:var(--okdb-app-fg-subtle); line-height:1.5;">\n Leave blank to use system defaults (timeout: 5000ms, memory: 32MB).\n </div>\n </div>\n\n <div style="padding:14px; border:1px solid var(--okdb-app-border); border-radius:12px; background:var(--okdb-app-bg-deep); display:flex; flex-direction:column; gap:10px; min-height:0;">\n <div style="font-size:11px; text-transform:uppercase; letter-spacing:.08em; color:var(--okdb-app-fg-muted);">Run payload</div>\n <div style="font-size:12px; color:var(--okdb-app-fg-muted); line-height:1.55;">\n Define the JSON payload you want to execute right now against this draft before saving it.\n </div>\n <div style="height:220px; min-height:220px; border:1px solid var(--okdb-app-border); border-radius:10px; overflow:hidden; background:var(--okdb-app-bg-deep);">\n <ok-text-monaco-input\n style="height:100%;"\n language="json"\n :value="store.modalPayloadDraft"\n @edit:debounce.150="setPayload($event.detail)"\n ></ok-text-monaco-input>\n </div>\n <if :="payloadError">\n <div style="font-size:12px; color:var(--okdb-danger); line-height:1.5;">{{ payloadError }}</div>\n </if>\n <div style="display:flex; justify-content:flex-end; gap:8px;">\n <button\n @click="toggleModalDryRun()"\n :disabled="running"\n :style="modalDryRunMode\n ? \'font-size:12px; border-color:var(--okdb-accent); color:var(--okdb-accent);\'\n : \'font-size:12px;\'">\n Dry Run{{ modalDryRunMode ? \' ✓\' : \'\' }}\n </button>\n <button @click="runDraft()" :disabled="!canRun">{{ running ? \'Running…\' : (modalDryRunMode ? \'Run draft (dry)\' : \'Run draft\') }}</button>\n </div>\n </div>\n\n <if :="previewTriggerKind && previewTriggerContext">\n <div style="padding:14px; border:1px solid var(--okdb-app-border); border-radius:12px; background:var(--okdb-app-bg-deep); display:flex; flex-direction:column; gap:10px; min-height:0;">\n <div style="display:flex; align-items:center; justify-content:space-between; gap:10px;">\n <div style="font-size:11px; text-transform:uppercase; letter-spacing:.08em; color:var(--okdb-app-fg-muted);">Preview trigger context</div>\n <div style="font-size:11px; color:var(--okdb-accent-muted); font-family:monospace;">ctx.{{ previewTriggerKind }}</div>\n </div>\n <div style="font-size:12px; color:var(--okdb-app-fg-muted); line-height:1.55;">\n This draft run simulates the engine metadata shown below so you can reproduce handler behavior before saving.\n </div>\n <pre style="margin:0; white-space:pre-wrap; word-break:break-word; color:var(--okdb-app-fg-muted); font-size:11px; line-height:1.5; max-height:180px; overflow:auto;">{{ formatJson(previewTriggerContext) }}</pre>\n </div>\n </if>\n\n <div style="padding:14px; border:1px solid var(--okdb-app-border); border-radius:12px; background:var(--okdb-app-bg-deep); display:flex; flex-direction:column; gap:6px;">\n <div style="font-size:11px; text-transform:uppercase; letter-spacing:.08em; color:var(--okdb-app-fg-muted);">Validation</div>\n <if :="validation.ok">\n <div style="font-size:12px; color:var(--okdb-success); line-height:1.55;">Function source is valid and can be saved.</div>\n </if>\n <if :="!validation.ok">\n <div style="font-size:12px; color:var(--okdb-danger); line-height:1.55;">{{ validation.message || \'Function source is invalid\' }}</div>\n <div style="font-size:11px; color:#c38989; font-family:monospace;">{{ validation.code || \'FUNCTION_SCRIPT_INVALID\' }}</div>\n </if>\n <div style="font-size:11px; color:var(--okdb-app-fg-subtle); line-height:1.5;">\n Allowed shape: <span style="font-family:monospace; color:var(--okdb-accent-muted);">[async] (ctx) => { }</span>.\n Forbidden symbols: <span style="font-family:monospace; color:var(--okdb-accent-muted);">require</span>, <span style="font-family:monospace; color:var(--okdb-accent-muted);">import</span>, <span style="font-family:monospace; color:var(--okdb-accent-muted);">console</span>, <span style="font-family:monospace; color:var(--okdb-accent-muted);">process</span>.\n </div>\n </div>\n </div>\n\n <div style="display:grid; grid-template-rows:minmax(0,1.2fr) minmax(220px,.7fr) minmax(240px,.9fr); min-height:0; gap:12px;">\n <div style="display:flex; flex-direction:column; min-height:0; border:1px solid var(--okdb-app-border); border-radius:12px; background:var(--okdb-app-bg-deep); overflow:hidden;">\n <div style="display:flex; align-items:center; justify-content:space-between; gap:10px; padding:12px 14px; border-bottom:1px solid var(--okdb-app-border);">\n <div style="font-size:11px; text-transform:uppercase; letter-spacing:.08em; color:var(--okdb-app-fg-muted);">Implementation</div>\n <div style="font-size:11px; color:var(--okdb-app-fg-muted); font-family:monospace;">async (ctx) => { }</div>\n </div>\n <div style="flex:1; min-height:0; background:var(--okdb-app-bg-deep);">\n <ok-js-input\n style="height:100%;"\n :value="store.modalSourceDraft"\n :unsafe="store.modalUnsafeDraft"\n :options="{ suggest: { showWords: true }, wordBasedSuggestions: \'currentDocument\' }"\n @edit="setSource($event.detail)"\n ></ok-js-input>\n </div>\n <div style="display:flex; justify-content:space-between; align-items:flex-start; gap:12px; font-size:11px; color:var(--okdb-app-fg-subtle); line-height:1.55; padding:10px 14px; border-top:1px solid var(--okdb-app-border);">\n <div>\n Runtime receives <span style="font-family:monospace; color:var(--okdb-accent-muted);">ctx</span> with DB access facades, payload, logs, and execution info.\n <if :="unsafe"><span style="color:var(--okdb-orange);"> ⚠ Unsafe: also exposes <span style="font-family:monospace; color:var(--okdb-warning);">ctx.okdb</span> (full cross-env access).</span></if>\n </div>\n <div style="white-space:nowrap;">JS / Monaco</div>\n </div>\n </div>\n\n <div style="padding:14px; border:1px solid var(--okdb-app-border); border-radius:12px; background:var(--okdb-app-bg-deep); min-height:0; overflow:auto; display:flex; flex-direction:column; gap:8px;">\n <div style="display:flex; align-items:center; justify-content:space-between; gap:8px;">\n <if :="previewRun && modalDryRunActions !== null">\n <div style="font-size:11px; text-transform:uppercase; letter-spacing:.08em; color:var(--okdb-accent);">Dry run — intercepted writes ({{ modalDryRunActions.length }})</div>\n </if>\n <if :="!previewRun || modalDryRunActions === null">\n <div style="font-size:11px; text-transform:uppercase; letter-spacing:.08em; color:var(--okdb-app-fg-muted);">Draft execution result</div>\n </if>\n <if :="previewRun">\n <div style="font-size:11px; color:var(--okdb-app-fg-muted); font-family:monospace;">{{ previewRunId }}</div>\n </if>\n </div>\n <if :="!previewRun">\n <div style="font-size:12px; color:var(--okdb-app-fg-muted); line-height:1.5;">Run the draft to see the latest result before you save.</div>\n </if>\n <if :="previewRun && modalDryRunActions !== null">\n <div style="font-size:12px; color:var(--okdb-app-fg-muted); line-height:1.5;">Status: <strong>{{ previewRun.status || (previewRun.error ? \'error\' : \'ok\') }}</strong></div>\n <if :="modalDryRunActions.length === 0">\n <div style="font-size:12px; color:var(--okdb-app-fg-muted);">No writes intercepted.</div>\n </if>\n <div style="display:flex; flex-direction:column; gap:4px;">\n <each :of="modalDryRunActions" let:item="action">\n <div style="padding:5px 8px; border:1px solid color-mix(in srgb, var(--okdb-accent) 20%, transparent); border-radius:6px; background:color-mix(in srgb, var(--okdb-accent) 4%, transparent); font-family:monospace; font-size:11px; color:var(--okdb-app-fg-muted); line-height:1.45;">\n <span style="color:var(--okdb-accent);">{{ action.scope }}.{{ action.method }}</span>\n <if :="action.envName"><span style="opacity:.6;"> [{{ action.envName }}]</span></if>\n <if :="actionArgs(action)"><span> ({{ actionArgs(action) }})</span></if>\n </div>\n </each>\n </div>\n <if :="previewRun.result?.value !== undefined && previewRun.result?.value !== null">\n <div style="font-size:11px; text-transform:uppercase; color:var(--okdb-app-fg-muted); margin-top:4px;">Return value</div>\n <pre style="margin:0; white-space:pre-wrap; word-break:break-word; color:var(--okdb-app-fg-muted); font-size:11px; line-height:1.5;">{{ formatJson(previewRun.result.value) }}</pre>\n </if>\n </if>\n <if :="previewRun && modalDryRunActions === null">\n <div style="font-size:12px; color:var(--okdb-app-fg-muted); line-height:1.5;">Status: <strong>{{ previewRun.status || (previewRun.error ? \'error\' : \'ok\') }}</strong></div>\n <pre style="margin:0; white-space:pre-wrap; word-break:break-word; color:var(--okdb-app-fg-muted); font-size:11px; line-height:1.5;">{{ formatJson(previewRun.result?.value ?? previewRun.error ?? previewRun) }}</pre>\n </if>\n </div>\n\n <function-logs :run-id="previewRunId" :entries="previewLogs" title="Draft live log" empty="Run the draft to stream function logs here."></function-logs>\n </div>\n </div>\n\n <div style="display:flex; justify-content:flex-end; gap:10px; padding-top:4px;">\n <button @click="cancel()">Cancel</button>\n <button @click="submit()" :disabled="!canSave">{{ saveLabel }}</button>\n </div>\n</div>\n '};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const _0x44eb6f=_0x4780;function _0x2708(){const _0x387863=['Open\x20linked\x20engine','key','functions','1303903ISERHL','/env/','push','API','onEdit','error','/engines','13182LBezOe','runs','selected','linkedQueueRef','526696bEVQUF','1935TzvNrZ','queue','remove','owner_engine','Open\x20linked\x20queue\x20worker','selectedName','Open\x20queue\x20workers\x20for\x20','\x20for\x20type\x20','stores','latestRun','refreshLinkedPipeline','Open\x20linked\x20pipeline','those\x20pipelines','$vars','8391110TrszCx','logsForRun','runId','Open\x20pipeline\x20','$ok','2898376eLJBjF','\x0a\x20\x20<if\x20:=\x22!fn\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22padding:18px;\x20border:1px\x20dashed\x20var(--okdb-app-border);\x20border-radius:10px;\x20color:var(--okdb-app-fg-muted);\x20line-height:1.6;\x22>\x0a\x20\x20\x20\x20\x20\x20Select\x20a\x20function\x20from\x20the\x20sidebar\x20to\x20inspect\x20or\x20edit\x20it.\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x0a\x20\x20<if\x20:=\x22fn\x22>\x0a\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:12px;\x20min-height:0;\x22>\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22padding:14px;\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:10px;\x20background:var(--okdb-app-bg-deep);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20text-transform:uppercase;\x20letter-spacing:.08em;\x20color:var(--okdb-app-fg-muted);\x20margin-bottom:10px;\x22>Function\x20overview</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20align-items:center;\x20justify-content:space-between;\x20gap:12px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:18px;\x20font-weight:700;\x20color:var(--okdb-app-fg);\x22>{{\x20fn.name\x20}}</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22margin-top:4px;\x20font-size:12px;\x20color:var(--okdb-app-fg-muted);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20fn.scope\x20===\x20\x27global\x27\x20?\x20\x27Global\x20function\x27\x20:\x20\x27Environment\x20function\x27\x20}}\x20·\x20version\x20{{\x20fn.version\x20}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20:style=\x22fn.enabled\x20===\x20false\x20?\x20\x27font-size:11px;\x20color:var(--okdb-danger);\x27\x20:\x20\x27font-size:11px;\x20color:var(--okdb-success);\x27\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20fn.enabled\x20===\x20false\x20?\x20\x27Disabled\x27\x20:\x20\x27Enabled\x27\x20}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20justify-content:flex-end;\x20gap:8px;\x20margin-top:12px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20style=\x22padding:6px\x2010px;\x20font-size:12px;\x22\x20@click=\x22triggerEdit()\x22>Edit</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x20style=\x22padding:6px\x2010px;\x20font-size:12px;\x20border-color:#5c2a34;\x20color:#fda4af;\x22\x20@click=\x22removeSelected()\x22>Delete</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22fn.metadata?.description\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22margin-top:10px;\x20color:#9bb2c3;\x20font-size:13px;\x20line-height:1.5;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20{{\x20fn.metadata.description\x20}}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:grid;\x20grid-template-columns:repeat(2,\x20minmax(0,1fr));\x20gap:12px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22padding:12px;\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:10px;\x20background:var(--okdb-app-bg-deep);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20text-transform:uppercase;\x20color:var(--okdb-app-fg-muted);\x20margin-bottom:8px;\x22>Runtime</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:6px;\x20font-size:12px;\x20color:var(--okdb-app-fg-muted);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div>timeoutMs:\x20<strong>{{\x20fn.runtime?.timeoutMs\x20??\x20\x27—\x27\x20}}</strong></div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div>memoryMb:\x20<strong>{{\x20fn.runtime?.memoryMb\x20??\x20\x27—\x27\x20}}</strong></div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div>allowFetch:\x20<strong>{{\x20fn.runtime?.allowFetch\x20===\x20false\x20?\x20\x27false\x27\x20:\x20\x27true\x27\x20}}</strong></div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22padding:12px;\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:10px;\x20background:var(--okdb-app-bg-deep);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20text-transform:uppercase;\x20color:var(--okdb-app-fg-muted);\x20margin-bottom:8px;\x22>Metadata</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:6px;\x20font-size:12px;\x20color:var(--okdb-app-fg-muted);\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div>createdAt:\x20<strong>{{\x20fn.metadata?.createdAt\x20??\x20\x27—\x27\x20}}</strong></div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div>updatedAt:\x20<strong>{{\x20fn.metadata?.updatedAt\x20??\x20\x27—\x27\x20}}</strong></div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div>hash:\x20<strong\x20style=\x22font-family:monospace;\x20font-size:11px;\x22>{{\x20fn.hash\x20??\x20\x27—\x27\x20}}</strong></div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22hasLinkedQueue\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@click=\x22openLinkedPipeline()\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:title=\x22linkedQueueTitle\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22margin-top:4px;\x20padding:4px\x208px;\x20border:1px\x20solid\x20color-mix(in\x20srgb,\x20var(--okdb-accent)\x2020%,\x20transparent);\x20border-radius:6px;\x20background:color-mix(in\x20srgb,\x20var(--okdb-accent)\x205%,\x20transparent);\x20color:var(--okdb-accent);\x20font-size:11px;\x20text-align:left;\x20cursor:pointer;\x20display:inline-flex;\x20align-items:center;\x20gap:4px;\x20width:fit-content;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span>⇶\x20Queue:</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<strong>{{\x20linkedQueueRef.jobType\x20}}</strong>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22linkedQueueRef?.ownerEngine\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span>·\x20Worker:</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<strong>{{\x20linkedQueueRef.ownerEngine\x20}}</strong>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span>↗</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22hasLinkedPipeline\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@click=\x22openLinkedPipeline()\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:title=\x22linkedPipelineTitle\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22margin-top:4px;\x20padding:4px\x208px;\x20border:1px\x20solid\x20color-mix(in\x20srgb,\x20var(--okdb-accent)\x2020%,\x20transparent);\x20border-radius:6px;\x20background:color-mix(in\x20srgb,\x20var(--okdb-accent)\x205%,\x20transparent);\x20color:var(--okdb-accent);\x20font-size:11px;\x20text-align:left;\x20cursor:pointer;\x20display:inline-flex;\x20align-items:center;\x20gap:4px;\x20width:fit-content;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span>⚡\x20Pipeline:</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<strong>{{\x20linkedPipelineRef.pipelineName\x20}}</strong>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22linkedPipelineRef?.ownerEngine\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span>·\x20Engine:</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<strong>{{\x20linkedPipelineRef.ownerEngine\x20}}</strong>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span>↗</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22!hasLinkedQueue\x20&&\x20!hasLinkedPipeline\x20&&\x20hasLinkedEngine\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<button\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20@click=\x22openLinkedPipeline()\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20:title=\x22linkedEngineTitle\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20style=\x22margin-top:4px;\x20padding:4px\x208px;\x20border:1px\x20solid\x20color-mix(in\x20srgb,\x20var(--okdb-accent)\x2020%,\x20transparent);\x20border-radius:6px;\x20background:color-mix(in\x20srgb,\x20var(--okdb-accent)\x205%,\x20transparent);\x20color:var(--okdb-accent);\x20font-size:11px;\x20text-align:left;\x20cursor:pointer;\x20display:inline-flex;\x20align-items:center;\x20gap:4px;\x20width:fit-content;\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span>⚙\x20Engine:</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<strong>{{\x20linkedEngineRef.ownerEngine\x20}}</strong>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<span>↗</span>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</button>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x0a\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:grid;\x20grid-template-columns:minmax(0,1.2fr)\x20minmax(280px,.8fr);\x20gap:12px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22padding:12px;\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:10px;\x20background:var(--okdb-app-bg-deep);\x20min-height:0;\x20overflow:auto;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20text-transform:uppercase;\x20color:var(--okdb-app-fg-muted);\x20margin-bottom:8px;\x22>Implementation</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<pre\x20style=\x22margin:0;\x20white-space:pre-wrap;\x20word-break:break-word;\x20color:var(--okdb-app-fg-muted);\x20font-size:12px;\x20line-height:1.55;\x22>{{\x20fn.script?.source\x20||\x20\x27—\x27\x20}}</pre>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22padding:12px;\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:10px;\x20background:var(--okdb-app-bg-deep);\x20min-height:0;\x20overflow:auto;\x20display:flex;\x20flex-direction:column;\x20gap:10px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20text-transform:uppercase;\x20color:var(--okdb-app-fg-muted);\x22>Runs</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;\x20color:var(--okdb-app-fg-muted);\x22>Total\x20persisted\x20runs:\x20<strong>{{\x20runs.length\x20}}</strong></div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22!activeRun\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;\x20color:var(--okdb-app-fg-muted);\x20line-height:1.5;\x22>No\x20runs\x20recorded\x20for\x20this\x20function\x20yet.</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22activeRun\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;\x20color:var(--okdb-app-fg-muted);\x20line-height:1.55;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Selected\x20run\x20id:\x20<strong\x20style=\x22font-family:monospace;\x20font-size:11px;\x22>{{\x20activeRun.id\x20||\x20activeRun.runId\x20||\x20\x27—\x27\x20}}</strong>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:12px;\x20color:var(--okdb-app-fg-muted);\x20line-height:1.55;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20Status:\x20<strong>{{\x20activeRun.status\x20||\x20(activeRun.error\x20?\x20\x27error\x27\x20:\x20\x27ok\x27)\x20}}</strong>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<pre\x20style=\x22margin:0;\x20white-space:pre-wrap;\x20word-break:break-word;\x20color:var(--okdb-app-fg-muted);\x20font-size:11px;\x20line-height:1.5;\x20max-height:180px;\x20overflow:auto;\x22>{{\x20formatJson(activeRun.result\x20??\x20activeRun.error\x20??\x20activeRun)\x20}}</pre>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<if\x20:=\x22activeRunLogs.length\x20>\x200\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22font-size:11px;\x20text-transform:uppercase;\x20color:var(--okdb-app-fg-muted);\x22>Selected\x20run\x20log</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22display:flex;\x20flex-direction:column;\x20gap:6px;\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<each\x20:of=\x22activeRunLogs\x22\x20let:item=\x22entry\x22>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20<div\x20style=\x22padding:6px\x208px;\x20border:1px\x20solid\x20var(--okdb-app-border);\x20border-radius:8px;\x20background:var(--okdb-app-bg-deep);\x20color:var(--okdb-app-fg-muted);\x20font-size:11px;\x20line-height:1.45;\x22>{{\x20entry.msg\x20}}</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</each>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20</if>\x0a\x20\x20\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20\x20\x20</div>\x0a\x20\x20\x20\x20</div>\x0a\x20\x20</if>\x0a\x20\x20','/functions','linkedPipelineLookup','json','slice','jobType','linkedPipelineRef','Could\x20not\x20resolve\x20the\x20linked\x20pipeline\x20yet','pipelineName','targetSection','\x0a\x0a⚠\x20This\x20function\x20is\x20used\x20by\x20','\x20(engine\x20','2188718MATpkh','linkedEngineRef','function-detail','success','$router','join','stringify','1724178ZZOLup','ownerEngine','name','that\x20pipeline','confirm','\x0a\x0aDeleting\x20it\x20will\x20break\x20','shared','toast','config','length','sourceType','activeRun','store','metadata','_linkedPipelineRequestId','filter','$watch','envName','pipeline'];_0x2708=function(){return _0x387863;};return _0x2708();}(function(_0xcc8572,_0x58cab7){const _0xda70fc=_0x4780,_0x221344=_0xcc8572();while(!![]){try{const _0x8b29a4=-parseInt(_0xda70fc(0xb0))/0x1+-parseInt(_0xda70fc(0x93))/0x2+parseInt(_0xda70fc(0x9a))/0x3+parseInt(_0xda70fc(0xbb))/0x4+parseInt(_0xda70fc(0xbc))/0x5*(parseInt(_0xda70fc(0xb7))/0x6)+parseInt(_0xda70fc(0xca))/0x7+parseInt(_0xda70fc(0xcf))/0x8;if(_0x8b29a4===_0x58cab7)break;else _0x221344['push'](_0x221344['shift']());}catch(_0x2932e6){_0x221344['push'](_0x221344['shift']());}}}(_0x2708,0xafa2c));import{openLinkedPipelineRoute as _0x20395,resolveLinkedPipeline as _0x5539f7}from'../../engines/engine-ui-utils.js';function _0x4780(_0x27dccb,_0x4c5337){_0x27dccb=_0x27dccb-0x8d;const _0x27089f=_0x2708();let _0x4780fc=_0x27089f[_0x27dccb];return _0x4780fc;}export default{'tag':_0x44eb6f(0x95),'attr':{'onEdit':{}},'context':_0x4cce06=>({'linkedPipelineLookup':null,'_linkedPipelineRequestId':0x0,get 'store'(){const _0x355f97=_0x44eb6f;return _0x4cce06['$ok'][_0x355f97(0xc4)][_0x355f97(0xaf)];},get 'fn'(){const _0x6f4fa1=_0x44eb6f;return this[_0x6f4fa1(0xa6)][_0x6f4fa1(0xb9)];},get 'runs'(){const _0x2f6b0b=_0x44eb6f;return this[_0x2f6b0b(0xa6)][_0x2f6b0b(0xb8)]||[];},get 'latestRun'(){const _0x546fb6=_0x44eb6f;return this[_0x546fb6(0xa6)][_0x546fb6(0xc5)];},get 'activeRun'(){const _0x24e642=_0x44eb6f;return this[_0x24e642(0xa6)][_0x24e642(0xa5)];},get 'activeRunLogs'(){const _0x34c60e=_0x44eb6f;return this['store'][_0x34c60e(0xcb)](this['activeRun']?.['id']||this[_0x34c60e(0xa5)]?.[_0x34c60e(0xcc)])[_0x34c60e(0xd4)](-0x5);},get 'selectedName'(){const _0x58400a=_0x44eb6f;return this[_0x58400a(0xa6)][_0x58400a(0xc1)];},get 'linkedPipelineRef'(){const _0x114437=_0x44eb6f;if('queue'===this[_0x114437(0xd2)]?.[_0x114437(0x90)])return null;const _0x34f55c=this['fn']?.[_0x114437(0xa7)]??{},_0x17ac9f=_0x34f55c[_0x114437(0xac)]??this[_0x114437(0xd2)]?.[_0x114437(0x8f)]??null;return _0x17ac9f?{'envName':this[_0x114437(0xd2)]?.[_0x114437(0xab)]??this[_0x114437(0xa6)]['envName']??null,'pipelineName':_0x17ac9f,'ownerEngine':_0x34f55c[_0x114437(0xbf)]??this[_0x114437(0xd2)]?.[_0x114437(0x9b)]??null,'targetSection':this[_0x114437(0xd2)]?.[_0x114437(0x90)]??'db'}:null;},get 'hasLinkedPipeline'(){const _0x27b62e=_0x44eb6f;return!!this[_0x27b62e(0x8d)]?.[_0x27b62e(0x8f)];},get 'linkedEngineRef'(){const _0x45f686=_0x44eb6f;if(_0x45f686(0xbd)===this[_0x45f686(0xd2)]?.['targetSection'])return null;const _0x1eb6f1=this['linkedPipelineRef'];if(_0x1eb6f1?.[_0x45f686(0x8f)])return _0x1eb6f1;const _0x46f9c8=this['fn']?.[_0x45f686(0xa7)]?.[_0x45f686(0xbf)]??this[_0x45f686(0xd2)]?.[_0x45f686(0x9b)]??null;return _0x46f9c8?{'envName':this[_0x45f686(0xd2)]?.['envName']??this[_0x45f686(0xa6)][_0x45f686(0xab)]??null,'pipelineName':null,'ownerEngine':_0x46f9c8,'sourceType':this[_0x45f686(0xd2)]?.[_0x45f686(0xa4)]??null,'targetSection':this[_0x45f686(0xd2)]?.[_0x45f686(0x90)]??'db'}:null;},get 'linkedQueueRef'(){const _0x5a3be2=_0x44eb6f,_0x45dbaa=this['linkedPipelineLookup'];return _0x5a3be2(0xbd)===_0x45dbaa?.[_0x5a3be2(0x90)]&&_0x45dbaa?.[_0x5a3be2(0xd5)]?{'envName':_0x45dbaa['envName']??this['store'][_0x5a3be2(0xab)]??null,'pipelineName':_0x45dbaa[_0x5a3be2(0x8f)]??this['fn']?.[_0x5a3be2(0xa7)]?.[_0x5a3be2(0xac)]??null,'ownerEngine':_0x45dbaa[_0x5a3be2(0x9b)]??this['fn']?.[_0x5a3be2(0xa7)]?.[_0x5a3be2(0xbf)]??null,'jobType':_0x45dbaa[_0x5a3be2(0xd5)],'targetSection':_0x5a3be2(0xbd)}:null;},get 'hasLinkedQueue'(){const _0x5ee998=_0x44eb6f;return!!this['linkedQueueRef']?.[_0x5ee998(0xd5)];},get 'hasLinkedEngine'(){const _0x3ffb48=_0x44eb6f;return!!this[_0x3ffb48(0x94)]?.['ownerEngine'];},'formatJson'(_0x30370c){const _0x2b82a6=_0x44eb6f;try{return JSON[_0x2b82a6(0x99)](_0x30370c,null,0x2);}catch{return String(_0x30370c??'');}},async 'removeSelected'(){const _0xd3e49e=_0x44eb6f;if(!this[_0xd3e49e(0xa6)][_0xd3e49e(0xc1)])return;const _0xeb8d5f=this[_0xd3e49e(0xa6)]['selectedName'],_0x14e3b3=this[_0xd3e49e(0xa6)][_0xd3e49e(0xab)],_0x474639=this['fn']?.['metadata'],_0x47be5e=_0x474639?.[_0xd3e49e(0xbf)]||_0x474639?.[_0xd3e49e(0xac)];let _0x676fe0=[];if(_0x14e3b3)try{const _0x4990f5=await fetch(__ENV__[_0xd3e49e(0xb3)]+_0xd3e49e(0xb1)+encodeURIComponent(_0x14e3b3)+_0xd3e49e(0xb6));if(_0x4990f5['ok']){const _0x30b461=await _0x4990f5[_0xd3e49e(0xd3)]();_0x676fe0=(_0x30b461?.['result']??_0x30b461??[])[_0xd3e49e(0xa9)](_0x5294bd=>_0x5294bd[_0xd3e49e(0xa2)]?.['handler']?.[_0xd3e49e(0x9c)]===_0xeb8d5f)['map'](_0x5f02f9=>_0x5f02f9[_0xd3e49e(0x9c)]||_0x5f02f9[_0xd3e49e(0xae)]);}}catch{}let _0x4092b0='Delete\x20function\x20\x22'+_0xeb8d5f+'\x22?';if(_0x47be5e||_0x676fe0[_0xd3e49e(0xa3)]>0x0){const _0x57325d=[...new Set([..._0x47be5e?[_0x47be5e]:[],..._0x676fe0])];_0x4092b0+=_0xd3e49e(0x91)+_0x57325d[_0xd3e49e(0xa3)]+'\x20engine(s):\x0a\x20\x20•\x20'+_0x57325d[_0xd3e49e(0x98)]('\x0a\x20\x20•\x20')+_0xd3e49e(0x9f)+(0x1===_0x57325d['length']?_0xd3e49e(0x9d):_0xd3e49e(0xc8))+'.';}const _0x183825=globalThis[_0xd3e49e(0x9e)]?.(_0x4092b0);if(_0x183825)try{await this[_0xd3e49e(0xa6)][_0xd3e49e(0xbe)](_0xeb8d5f),_0x4cce06[_0xd3e49e(0xc9)][_0xd3e49e(0x97)]?.[_0xd3e49e(0xb2)]?.(_0xd3e49e(0xd1)),_0x4cce06[_0xd3e49e(0xce)]['shared']?.['toast']?.[_0xd3e49e(0x96)]?.('Function\x20deleted');}catch(_0x473d39){_0x4cce06['$ok']['shared']?.[_0xd3e49e(0xa1)]?.[_0xd3e49e(0xb5)]?.(_0x473d39?.['message']||'Failed\x20to\x20delete\x20function');}},'triggerEdit'(){const _0x23d940=_0x44eb6f;_0x4cce06['$attr'][_0x23d940(0xb4)]?.();},get 'linkedPipelineTitle'(){const _0x4c53cd=_0x44eb6f,_0x56baa2=this[_0x4c53cd(0x8d)];return _0x56baa2?.[_0x4c53cd(0x8f)]?_0x56baa2['ownerEngine']?_0x4c53cd(0xcd)+_0x56baa2['pipelineName']+_0x4c53cd(0x92)+_0x56baa2['ownerEngine']+')':_0x4c53cd(0xcd)+_0x56baa2[_0x4c53cd(0x8f)]:_0x4c53cd(0xc7);},get 'linkedEngineTitle'(){const _0x215e31=_0x44eb6f,_0x3a1fa1=this[_0x215e31(0x94)];return _0x3a1fa1?.[_0x215e31(0x9b)]?_0x3a1fa1['sourceType']?'Open\x20engine\x20'+_0x3a1fa1[_0x215e31(0x9b)]+_0x215e31(0xc3)+_0x3a1fa1['sourceType']:'Open\x20engine\x20'+_0x3a1fa1['ownerEngine']:_0x215e31(0xad);},get 'linkedQueueTitle'(){const _0x274193=_0x44eb6f,_0x2a1733=this['linkedQueueRef'];return _0x2a1733?.['jobType']?_0x2a1733[_0x274193(0x9b)]?_0x274193(0xc2)+_0x2a1733[_0x274193(0xd5)]+'\x20(worker\x20'+_0x2a1733['ownerEngine']+')':_0x274193(0xc2)+_0x2a1733['jobType']:_0x274193(0xc0);},async 'refreshLinkedPipeline'(){const _0x5db370=_0x44eb6f,_0x1e9ca6=this['fn']?.[_0x5db370(0x9c)]??this[_0x5db370(0xc1)]??null,_0x51dbfb=this['fn']?.['metadata']??{};if(!this[_0x5db370(0xa6)][_0x5db370(0xab)]||!_0x1e9ca6)return void(this[_0x5db370(0xd2)]=null);const _0x579cfc=++this[_0x5db370(0xa8)],_0x4212a8=await _0x5539f7(_0x4cce06,{'envName':this[_0x5db370(0xa6)][_0x5db370(0xab)],'pipelineName':_0x51dbfb[_0x5db370(0xac)]??null,'ownerEngine':_0x51dbfb[_0x5db370(0xbf)]??null,'functionName':_0x1e9ca6});_0x579cfc===this['_linkedPipelineRequestId']&&(this[_0x5db370(0xd2)]=_0x4212a8);},async 'openLinkedPipeline'(){const _0x1043bd=_0x44eb6f,_0x1a180c=this[_0x1043bd(0xba)]??this[_0x1043bd(0x8d)]??this[_0x1043bd(0x94)];(_0x1a180c?.[_0x1043bd(0x9b)]||_0x1a180c?.['pipelineName']||_0x1a180c?.['jobType'])&&(await _0x20395(_0x4cce06,{'envName':_0x1a180c[_0x1043bd(0xab)]??this[_0x1043bd(0xa6)]['envName'],'pipelineName':_0x1a180c['pipelineName']??null,'ownerEngine':_0x1a180c[_0x1043bd(0x9b)]??null,'functionName':this['fn']?.['name']??this[_0x1043bd(0xc1)]??null})||_0x4cce06[_0x1043bd(0xce)][_0x1043bd(0xa0)]?.[_0x1043bd(0xa1)]?.['info']?.(_0x1043bd(0x8e)));}}),async 'init'(_0x577879){const _0x4eeca4=_0x44eb6f;await this[_0x4eeca4(0xc6)](),_0x577879[_0x4eeca4(0xaa)](()=>[_0x577879[_0x4eeca4(0xce)][_0x4eeca4(0xc4)][_0x4eeca4(0xaf)][_0x4eeca4(0xab)],_0x577879[_0x4eeca4(0xce)][_0x4eeca4(0xc4)][_0x4eeca4(0xaf)][_0x4eeca4(0xc1)],_0x577879[_0x4eeca4(0xce)][_0x4eeca4(0xc4)]['functions'][_0x4eeca4(0xb9)]?.[_0x4eeca4(0xa7)]?.['pipeline'],_0x577879[_0x4eeca4(0xce)][_0x4eeca4(0xc4)][_0x4eeca4(0xaf)][_0x4eeca4(0xb9)]?.[_0x4eeca4(0xa7)]?.[_0x4eeca4(0xbf)]][_0x4eeca4(0x98)]('||'),()=>this[_0x4eeca4(0xc6)]());},'template':_0x44eb6f(0xd0)};
|
|
1
|
+
import{openLinkedPipelineRoute as e,resolveLinkedPipeline as n}from"../../engines/engine-ui-utils.js";export default{tag:"function-detail",attr:{onEdit:{}},context:i=>({linkedPipelineLookup:null,_linkedPipelineRequestId:0,get store(){return i.$ok.stores.functions},get fn(){return this.store.selected},get runs(){return this.store.runs||[]},get latestRun(){return this.store.latestRun},get activeRun(){return this.store.activeRun},get activeRunLogs(){return this.store.logsForRun(this.activeRun?.id||this.activeRun?.runId).slice(-5)},get selectedName(){return this.store.selectedName},get linkedPipelineRef(){if("queue"===this.linkedPipelineLookup?.targetSection)return null;const e=this.fn?.metadata??{},n=e.pipeline??this.linkedPipelineLookup?.pipelineName??null;return n?{envName:this.linkedPipelineLookup?.envName??this.store.envName??null,pipelineName:n,ownerEngine:e.owner_engine??this.linkedPipelineLookup?.ownerEngine??null,targetSection:this.linkedPipelineLookup?.targetSection??"db"}:null},get hasLinkedPipeline(){return!!this.linkedPipelineRef?.pipelineName},get linkedEngineRef(){if("queue"===this.linkedPipelineLookup?.targetSection)return null;const e=this.linkedPipelineRef;if(e?.pipelineName)return e;const n=this.fn?.metadata?.owner_engine??this.linkedPipelineLookup?.ownerEngine??null;return n?{envName:this.linkedPipelineLookup?.envName??this.store.envName??null,pipelineName:null,ownerEngine:n,sourceType:this.linkedPipelineLookup?.sourceType??null,targetSection:this.linkedPipelineLookup?.targetSection??"db"}:null},get linkedQueueRef(){const e=this.linkedPipelineLookup;return"queue"===e?.targetSection&&e?.jobType?{envName:e.envName??this.store.envName??null,pipelineName:e.pipelineName??this.fn?.metadata?.pipeline??null,ownerEngine:e.ownerEngine??this.fn?.metadata?.owner_engine??null,jobType:e.jobType,targetSection:"queue"}:null},get hasLinkedQueue(){return!!this.linkedQueueRef?.jobType},get hasLinkedEngine(){return!!this.linkedEngineRef?.ownerEngine},formatJson(e){try{return JSON.stringify(e,null,2)}catch{return String(e??"")}},async removeSelected(){if(!this.store.selectedName)return;const e=this.store.selectedName,n=this.store.envName,t=this.fn?.metadata,o=t?.owner_engine||t?.pipeline;let r=[];if(n)try{const i=await fetch(`${__ENV__.API}/env/${encodeURIComponent(n)}/engines`);if(i.ok){const n=await i.json();r=(n?.result??n??[]).filter(n=>n.config?.handler?.name===e).map(e=>e.name||e.key)}}catch{}let a=`Delete function "${e}"?`;if(o||r.length>0){const e=[...new Set([...o?[o]:[],...r])];a+=`\n\n⚠ This function is used by ${e.length} engine(s):\n • ${e.join("\n • ")}\n\nDeleting it will break ${1===e.length?"that pipeline":"those pipelines"}.`}const p=globalThis.confirm?.(a);if(p)try{await this.store.remove(e),i.$vars.$router?.push?.("/functions"),i.$ok.shared?.toast?.success?.("Function deleted")}catch(e){i.$ok.shared?.toast?.error?.(e?.message||"Failed to delete function")}},triggerEdit(){i.$attr.onEdit?.()},get linkedPipelineTitle(){const e=this.linkedPipelineRef;return e?.pipelineName?e.ownerEngine?`Open pipeline ${e.pipelineName} (engine ${e.ownerEngine})`:`Open pipeline ${e.pipelineName}`:"Open linked pipeline"},get linkedEngineTitle(){const e=this.linkedEngineRef;return e?.ownerEngine?e.sourceType?`Open engine ${e.ownerEngine} for type ${e.sourceType}`:`Open engine ${e.ownerEngine}`:"Open linked engine"},get linkedQueueTitle(){const e=this.linkedQueueRef;return e?.jobType?e.ownerEngine?`Open queue workers for ${e.jobType} (worker ${e.ownerEngine})`:`Open queue workers for ${e.jobType}`:"Open linked queue worker"},async refreshLinkedPipeline(){const e=this.fn?.name??this.selectedName??null,t=this.fn?.metadata??{};if(!this.store.envName||!e)return void(this.linkedPipelineLookup=null);const o=++this._linkedPipelineRequestId,r=await n(i,{envName:this.store.envName,pipelineName:t.pipeline??null,ownerEngine:t.owner_engine??null,functionName:e});o===this._linkedPipelineRequestId&&(this.linkedPipelineLookup=r)},async openLinkedPipeline(){const n=this.linkedQueueRef??this.linkedPipelineRef??this.linkedEngineRef;(n?.ownerEngine||n?.pipelineName||n?.jobType)&&(await e(i,{envName:n.envName??this.store.envName,pipelineName:n.pipelineName??null,ownerEngine:n.ownerEngine??null,functionName:this.fn?.name??this.selectedName??null})||i.$ok.shared?.toast?.info?.("Could not resolve the linked pipeline yet"))}}),async init(e){await this.refreshLinkedPipeline(),e.$watch(()=>[e.$ok.stores.functions.envName,e.$ok.stores.functions.selectedName,e.$ok.stores.functions.selected?.metadata?.pipeline,e.$ok.stores.functions.selected?.metadata?.owner_engine].join("||"),()=>this.refreshLinkedPipeline())},template:'\n <if :="!fn">\n <div style="padding:18px; border:1px dashed var(--okdb-app-border); border-radius:10px; color:var(--okdb-app-fg-muted); line-height:1.6;">\n Select a function from the sidebar to inspect or edit it.\n </div>\n </if>\n\n <if :="fn">\n <div style="display:flex; flex-direction:column; gap:12px; min-height:0;">\n <div style="padding:14px; border:1px solid var(--okdb-app-border); border-radius:10px; background:var(--okdb-app-bg-deep);">\n <div style="font-size:11px; text-transform:uppercase; letter-spacing:.08em; color:var(--okdb-app-fg-muted); margin-bottom:10px;">Function overview</div>\n <div style="display:flex; align-items:center; justify-content:space-between; gap:12px;">\n <div>\n <div style="font-size:18px; font-weight:700; color:var(--okdb-app-fg);">{{ fn.name }}</div>\n <div style="margin-top:4px; font-size:12px; color:var(--okdb-app-fg-muted);">\n {{ fn.scope === \'global\' ? \'Global function\' : \'Environment function\' }} · version {{ fn.version }}\n </div>\n </div>\n <div :style="fn.enabled === false ? \'font-size:11px; color:var(--okdb-danger);\' : \'font-size:11px; color:var(--okdb-success);\'">\n {{ fn.enabled === false ? \'Disabled\' : \'Enabled\' }}\n </div>\n </div>\n\n <div style="display:flex; justify-content:flex-end; gap:8px; margin-top:12px;">\n <button style="padding:6px 10px; font-size:12px;" @click="triggerEdit()">Edit</button>\n <button style="padding:6px 10px; font-size:12px; border-color:#5c2a34; color:#fda4af;" @click="removeSelected()">Delete</button>\n </div>\n\n <if :="fn.metadata?.description">\n <div style="margin-top:10px; color:#9bb2c3; font-size:13px; line-height:1.5;">\n {{ fn.metadata.description }}\n </div>\n </if>\n </div>\n\n <div style="display:grid; grid-template-columns:repeat(2, minmax(0,1fr)); gap:12px;">\n <div style="padding:12px; border:1px solid var(--okdb-app-border); border-radius:10px; background:var(--okdb-app-bg-deep);">\n <div style="font-size:11px; text-transform:uppercase; color:var(--okdb-app-fg-muted); margin-bottom:8px;">Runtime</div>\n <div style="display:flex; flex-direction:column; gap:6px; font-size:12px; color:var(--okdb-app-fg-muted);">\n <div>timeoutMs: <strong>{{ fn.runtime?.timeoutMs ?? \'—\' }}</strong></div>\n <div>memoryMb: <strong>{{ fn.runtime?.memoryMb ?? \'—\' }}</strong></div>\n <div>allowFetch: <strong>{{ fn.runtime?.allowFetch === false ? \'false\' : \'true\' }}</strong></div>\n </div>\n </div>\n <div style="padding:12px; border:1px solid var(--okdb-app-border); border-radius:10px; background:var(--okdb-app-bg-deep);">\n <div style="font-size:11px; text-transform:uppercase; color:var(--okdb-app-fg-muted); margin-bottom:8px;">Metadata</div>\n <div style="display:flex; flex-direction:column; gap:6px; font-size:12px; color:var(--okdb-app-fg-muted);">\n <div>createdAt: <strong>{{ fn.metadata?.createdAt ?? \'—\' }}</strong></div>\n <div>updatedAt: <strong>{{ fn.metadata?.updatedAt ?? \'—\' }}</strong></div>\n <div>hash: <strong style="font-family:monospace; font-size:11px;">{{ fn.hash ?? \'—\' }}</strong></div>\n <if :="hasLinkedQueue">\n <button\n @click="openLinkedPipeline()"\n :title="linkedQueueTitle"\n style="margin-top:4px; padding:4px 8px; border:1px solid color-mix(in srgb, var(--okdb-accent) 20%, transparent); border-radius:6px; background:color-mix(in srgb, var(--okdb-accent) 5%, transparent); color:var(--okdb-accent); font-size:11px; text-align:left; cursor:pointer; display:inline-flex; align-items:center; gap:4px; width:fit-content;"\n >\n <span>⇶ Queue:</span>\n <strong>{{ linkedQueueRef.jobType }}</strong>\n <if :="linkedQueueRef?.ownerEngine">\n <span>· Worker:</span>\n <strong>{{ linkedQueueRef.ownerEngine }}</strong>\n </if>\n <span>↗</span>\n </button>\n </if>\n <if :="hasLinkedPipeline">\n <button\n @click="openLinkedPipeline()"\n :title="linkedPipelineTitle"\n style="margin-top:4px; padding:4px 8px; border:1px solid color-mix(in srgb, var(--okdb-accent) 20%, transparent); border-radius:6px; background:color-mix(in srgb, var(--okdb-accent) 5%, transparent); color:var(--okdb-accent); font-size:11px; text-align:left; cursor:pointer; display:inline-flex; align-items:center; gap:4px; width:fit-content;"\n >\n <span>⚡ Pipeline:</span>\n <strong>{{ linkedPipelineRef.pipelineName }}</strong>\n <if :="linkedPipelineRef?.ownerEngine">\n <span>· Engine:</span>\n <strong>{{ linkedPipelineRef.ownerEngine }}</strong>\n </if>\n <span>↗</span>\n </button>\n </if>\n <if :="!hasLinkedQueue && !hasLinkedPipeline && hasLinkedEngine">\n <button\n @click="openLinkedPipeline()"\n :title="linkedEngineTitle"\n style="margin-top:4px; padding:4px 8px; border:1px solid color-mix(in srgb, var(--okdb-accent) 20%, transparent); border-radius:6px; background:color-mix(in srgb, var(--okdb-accent) 5%, transparent); color:var(--okdb-accent); font-size:11px; text-align:left; cursor:pointer; display:inline-flex; align-items:center; gap:4px; width:fit-content;"\n >\n <span>⚙ Engine:</span>\n <strong>{{ linkedEngineRef.ownerEngine }}</strong>\n <span>↗</span>\n </button>\n </if>\n </div>\n </div>\n </div>\n\n <div style="display:grid; grid-template-columns:minmax(0,1.2fr) minmax(280px,.8fr); gap:12px;">\n <div style="padding:12px; border:1px solid var(--okdb-app-border); border-radius:10px; background:var(--okdb-app-bg-deep); min-height:0; overflow:auto;">\n <div style="font-size:11px; text-transform:uppercase; color:var(--okdb-app-fg-muted); margin-bottom:8px;">Implementation</div>\n <pre style="margin:0; white-space:pre-wrap; word-break:break-word; color:var(--okdb-app-fg-muted); font-size:12px; line-height:1.55;">{{ fn.script?.source || \'—\' }}</pre>\n </div>\n <div style="padding:12px; border:1px solid var(--okdb-app-border); border-radius:10px; background:var(--okdb-app-bg-deep); min-height:0; overflow:auto; display:flex; flex-direction:column; gap:10px;">\n <div style="font-size:11px; text-transform:uppercase; color:var(--okdb-app-fg-muted);">Runs</div>\n <div style="font-size:12px; color:var(--okdb-app-fg-muted);">Total persisted runs: <strong>{{ runs.length }}</strong></div>\n <if :="!activeRun">\n <div style="font-size:12px; color:var(--okdb-app-fg-muted); line-height:1.5;">No runs recorded for this function yet.</div>\n </if>\n <if :="activeRun">\n <div style="font-size:12px; color:var(--okdb-app-fg-muted); line-height:1.55;">\n Selected run id: <strong style="font-family:monospace; font-size:11px;">{{ activeRun.id || activeRun.runId || \'—\' }}</strong>\n </div>\n <div style="font-size:12px; color:var(--okdb-app-fg-muted); line-height:1.55;">\n Status: <strong>{{ activeRun.status || (activeRun.error ? \'error\' : \'ok\') }}</strong>\n </div>\n <pre style="margin:0; white-space:pre-wrap; word-break:break-word; color:var(--okdb-app-fg-muted); font-size:11px; line-height:1.5; max-height:180px; overflow:auto;">{{ formatJson(activeRun.result ?? activeRun.error ?? activeRun) }}</pre>\n <if :="activeRunLogs.length > 0">\n <div style="font-size:11px; text-transform:uppercase; color:var(--okdb-app-fg-muted);">Selected run log</div>\n <div style="display:flex; flex-direction:column; gap:6px;">\n <each :of="activeRunLogs" let:item="entry">\n <div style="padding:6px 8px; border:1px solid var(--okdb-app-border); border-radius:8px; background:var(--okdb-app-bg-deep); color:var(--okdb-app-fg-muted); font-size:11px; line-height:1.45;">{{ entry.msg }}</div>\n </each>\n </div>\n </if>\n </if>\n </div>\n </div>\n </div>\n </if>\n '};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import e from"../../../stores/events-store.js";export default{tag:"function-logs",attr:{runId:{},entries:{},title:{default:"Live log"},empty:{default:"No logs for this execution yet."}},context:t=>({get titleText(){const e=t.$attr.title;return"string"==typeof e&&e.trim()&&"undefined"!==e.trim().toLowerCase()?e:"Live log"},get emptyText(){const e=t.$attr.empty;return"string"==typeof e&&e.trim()&&"undefined"!==e.trim().toLowerCase()?e:"No logs for this execution yet."},get entries(){if(Array.isArray(t.$attr.entries))return t.$attr.entries;const r=t.$attr.runId;return r?(e.logs||[]).filter(e=>(e?.runId||e?.meta?.runId)===r):[]},fmtTime(e){if(!e)return"";const t=new Date(e);return t.toTimeString().slice(0,8)+"."+String(t.getMilliseconds()).padStart(3,"0")},fmtMeta(e){if(null==e)return"";if("object"==typeof e&&!Array.isArray(e)){const t=Object.fromEntries(Object.entries(e).filter(([e,t])=>void 0!==t&&"undefined"!==t&&null!=t&&("title"!==e&&"content"!==e||"undefined"!==String(t).toLowerCase())));if(0===Object.keys(t).length)return"";try{return JSON.stringify(t,null,2)}catch{}}try{return"string"==typeof e?e:JSON.stringify(e)}catch{return String(e)}},fmtMsg(e){const t=e?.msg??e?.message??e?.content??e?.title??"";if(null==t)return"";if("string"==typeof t){const e=t.trim();return e&&"undefined"!==e.toLowerCase()?e:""}try{return JSON.stringify(t,null,2)}catch{return String(t)}}}),template:'\n <div style="display:flex; flex-direction:column; min-height:0; height:100%; border:1px solid var(--okdb-app-border); border-radius:10px; background:var(--okdb-app-bg-deep); overflow:hidden;">\n <div style="padding:10px 12px; border-bottom:1px solid var(--okdb-app-border); font-size:11px; text-transform:uppercase; color:var(--okdb-app-fg-muted); letter-spacing:.08em;">{{ titleText }}</div>\n <div style="display:flex; flex-direction:column; gap:8px; padding:12px; min-height:0; overflow:auto;">\n <if :="entries.length === 0">\n <div style="font-size:12px; color:var(--okdb-app-fg-muted); line-height:1.5;">{{ emptyText }}</div>\n </if>\n <each :of="entries" let:item="entry">\n <div style="padding:8px 10px; border:1px solid var(--okdb-app-border); border-radius:8px; background:var(--okdb-app-bg-deep);">\n <div style="display:flex; align-items:center; gap:8px; font-size:11px; color:var(--okdb-app-fg-muted); margin-bottom:6px;">\n <span>{{ fmtTime(entry.ts || entry._ts) }}</span>\n <span :style="entry.level === \'error\' ? \'color:var(--okdb-danger);\' : entry.level === \'warn\' ? \'color:#f5b481;\' : \'color:var(--okdb-success);\'">{{ entry.level || \'info\' }}</span>\n </div>\n <if :="fmtMsg(entry)">\n <div style="font-size:12px; color:#d4e8f4; line-height:1.5;">{{ fmtMsg(entry) }}</div>\n </if>\n <if :="entry.context != null && fmtMeta(entry.context)">\n <pre style="margin:8px 0 0; white-space:pre-wrap; word-break:break-word; font-size:11px; color:var(--okdb-app-fg-muted); font-family:monospace;">{{ fmtMeta(entry.context) }}</pre>\n </if>\n </div>\n </each>\n </div>\n </div>\n '};
|