@portel/photon 1.11.0 → 1.12.0
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/README.md +81 -72
- package/dist/auto-ui/beam/photon-management.d.ts.map +1 -1
- package/dist/auto-ui/beam/photon-management.js +5 -0
- package/dist/auto-ui/beam/photon-management.js.map +1 -1
- package/dist/auto-ui/beam/routes/api-browse.d.ts +1 -2
- package/dist/auto-ui/beam/routes/api-browse.d.ts.map +1 -1
- package/dist/auto-ui/beam/routes/api-browse.js +140 -191
- package/dist/auto-ui/beam/routes/api-browse.js.map +1 -1
- package/dist/auto-ui/beam/routes/api-config.d.ts.map +1 -1
- package/dist/auto-ui/beam/routes/api-config.js +44 -1
- package/dist/auto-ui/beam/routes/api-config.js.map +1 -1
- package/dist/auto-ui/beam.d.ts.map +1 -1
- package/dist/auto-ui/beam.js +874 -20
- package/dist/auto-ui/beam.js.map +1 -1
- package/dist/auto-ui/frontend/index.html +83 -60
- package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -1
- package/dist/auto-ui/streamable-http-transport.js +16 -2
- package/dist/auto-ui/streamable-http-transport.js.map +1 -1
- package/dist/auto-ui/types.d.ts +1 -1
- package/dist/auto-ui/types.d.ts.map +1 -1
- package/dist/auto-ui/types.js.map +1 -1
- package/dist/beam.bundle.js +2794 -322
- package/dist/beam.bundle.js.map +4 -4
- package/dist/cli/commands/package-app.d.ts.map +1 -1
- package/dist/cli/commands/package-app.js +116 -35
- package/dist/cli/commands/package-app.js.map +1 -1
- package/dist/context-store.d.ts +5 -0
- package/dist/context-store.d.ts.map +1 -1
- package/dist/context-store.js +9 -0
- package/dist/context-store.js.map +1 -1
- package/dist/daemon/server.js +303 -6
- package/dist/daemon/server.js.map +1 -1
- package/dist/loader.d.ts +4 -0
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +186 -1
- package/dist/loader.js.map +1 -1
- package/dist/photon-cli-runner.d.ts.map +1 -1
- package/dist/photon-cli-runner.js +21 -1
- package/dist/photon-cli-runner.js.map +1 -1
- package/dist/photon-doc-extractor.d.ts +6 -0
- package/dist/photon-doc-extractor.d.ts.map +1 -1
- package/dist/photon-doc-extractor.js +22 -0
- package/dist/photon-doc-extractor.js.map +1 -1
- package/dist/photons/tunnel.photon.d.ts +5 -9
- package/dist/photons/tunnel.photon.d.ts.map +1 -1
- package/dist/photons/tunnel.photon.js +36 -96
- package/dist/photons/tunnel.photon.js.map +1 -1
- package/dist/photons/tunnel.photon.ts +40 -112
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +27 -2
- package/dist/server.js.map +1 -1
- package/dist/test-runner.d.ts +13 -1
- package/dist/test-runner.d.ts.map +1 -1
- package/dist/test-runner.js +529 -122
- package/dist/test-runner.js.map +1 -1
- package/package.json +22 -6
package/dist/beam.bundle.js
CHANGED
|
@@ -15357,10 +15357,14 @@ var theme = i`
|
|
|
15357
15357
|
bottom: 0;
|
|
15358
15358
|
background-color: var(--bg-glass);
|
|
15359
15359
|
border: 1px solid var(--border-glass);
|
|
15360
|
-
transition: 0.
|
|
15360
|
+
transition: 0.2s;
|
|
15361
15361
|
border-radius: var(--radius-full);
|
|
15362
15362
|
}
|
|
15363
15363
|
|
|
15364
|
+
.slider:hover {
|
|
15365
|
+
border-color: var(--accent-secondary);
|
|
15366
|
+
}
|
|
15367
|
+
|
|
15364
15368
|
.slider:before {
|
|
15365
15369
|
position: absolute;
|
|
15366
15370
|
content: '';
|
|
@@ -15369,7 +15373,7 @@ var theme = i`
|
|
|
15369
15373
|
left: 2px;
|
|
15370
15374
|
bottom: 2px;
|
|
15371
15375
|
background-color: var(--t-muted);
|
|
15372
|
-
transition: 0.
|
|
15376
|
+
transition: 0.2s;
|
|
15373
15377
|
border-radius: 50%;
|
|
15374
15378
|
}
|
|
15375
15379
|
|
|
@@ -15544,7 +15548,7 @@ ToastManager.styles = [
|
|
|
15544
15548
|
pointer-events: auto;
|
|
15545
15549
|
animation: slideIn 0.3s ease-out;
|
|
15546
15550
|
max-width: 350px;
|
|
15547
|
-
box-shadow:
|
|
15551
|
+
box-shadow: var(--shadow-lg);
|
|
15548
15552
|
}
|
|
15549
15553
|
|
|
15550
15554
|
.toast.exiting {
|
|
@@ -15622,7 +15626,7 @@ ToastManager.styles = [
|
|
|
15622
15626
|
|
|
15623
15627
|
.close:hover {
|
|
15624
15628
|
color: var(--t-primary);
|
|
15625
|
-
background:
|
|
15629
|
+
background: var(--bg-glass);
|
|
15626
15630
|
}
|
|
15627
15631
|
|
|
15628
15632
|
.toast-action {
|
|
@@ -15822,7 +15826,8 @@ var iconPaths = {
|
|
|
15822
15826
|
docs: `<path d="M12 7v14"/><path d="M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z"/>`,
|
|
15823
15827
|
expand: `<path d="M15 3h6v6"/><path d="m21 3-7 7"/><path d="m3 21 7-7"/><path d="M9 21H3v-6"/>`,
|
|
15824
15828
|
plus: `<path d="M5 12h14"/><path d="M12 5v14"/>`,
|
|
15825
|
-
clone: `<rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"
|
|
15829
|
+
clone: `<rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>`,
|
|
15830
|
+
installApp: `<path d="M12 3v12"/><path d="m17 11-5 5-5-5"/><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>`
|
|
15826
15831
|
};
|
|
15827
15832
|
|
|
15828
15833
|
// node_modules/@portel/photon-core/dist/design-system/oklch.js
|
|
@@ -16509,7 +16514,8 @@ var buttons = i`
|
|
|
16509
16514
|
color: var(--t-primary);
|
|
16510
16515
|
}
|
|
16511
16516
|
|
|
16512
|
-
.btn-primary:disabled
|
|
16517
|
+
.btn-primary:disabled,
|
|
16518
|
+
.btn-secondary:disabled {
|
|
16513
16519
|
opacity: 0.6;
|
|
16514
16520
|
cursor: not-allowed;
|
|
16515
16521
|
transform: none;
|
|
@@ -16549,7 +16555,21 @@ var forms = i`
|
|
|
16549
16555
|
padding: var(--space-sm);
|
|
16550
16556
|
border-radius: var(--radius-sm);
|
|
16551
16557
|
font-family: var(--font-sans);
|
|
16558
|
+
font-size: var(--text-md);
|
|
16552
16559
|
box-sizing: border-box;
|
|
16560
|
+
transition:
|
|
16561
|
+
border-color 0.15s ease,
|
|
16562
|
+
box-shadow 0.15s ease;
|
|
16563
|
+
}
|
|
16564
|
+
|
|
16565
|
+
input:hover,
|
|
16566
|
+
textarea:hover,
|
|
16567
|
+
select:hover {
|
|
16568
|
+
border-color: var(--accent-secondary);
|
|
16569
|
+
}
|
|
16570
|
+
|
|
16571
|
+
textarea {
|
|
16572
|
+
resize: vertical;
|
|
16553
16573
|
}
|
|
16554
16574
|
|
|
16555
16575
|
::placeholder {
|
|
@@ -16565,12 +16585,12 @@ var forms = i`
|
|
|
16565
16585
|
display: block;
|
|
16566
16586
|
margin-bottom: var(--space-xs);
|
|
16567
16587
|
font-weight: 500;
|
|
16568
|
-
font-size:
|
|
16588
|
+
font-size: var(--text-md);
|
|
16569
16589
|
}
|
|
16570
16590
|
|
|
16571
16591
|
.error-text {
|
|
16572
16592
|
color: var(--color-error);
|
|
16573
|
-
font-size:
|
|
16593
|
+
font-size: var(--text-xs);
|
|
16574
16594
|
margin-top: var(--space-xs);
|
|
16575
16595
|
}
|
|
16576
16596
|
|
|
@@ -16590,7 +16610,7 @@ var forms = i`
|
|
|
16590
16610
|
var badges = i`
|
|
16591
16611
|
.type-badge {
|
|
16592
16612
|
display: inline-block;
|
|
16593
|
-
font-size:
|
|
16613
|
+
font-size: var(--text-2xs);
|
|
16594
16614
|
font-weight: 600;
|
|
16595
16615
|
text-transform: uppercase;
|
|
16596
16616
|
letter-spacing: 0.04em;
|
|
@@ -16624,7 +16644,7 @@ var badges = i`
|
|
|
16624
16644
|
}
|
|
16625
16645
|
|
|
16626
16646
|
.param-tag {
|
|
16627
|
-
font-size:
|
|
16647
|
+
font-size: var(--text-2xs);
|
|
16628
16648
|
padding: 1px 6px;
|
|
16629
16649
|
border-radius: var(--radius-xs);
|
|
16630
16650
|
background: var(--param-tag-bg, hsla(220, 10%, 80%, 0.08));
|
|
@@ -17200,6 +17220,307 @@ function loadSavedThemeConfig() {
|
|
|
17200
17220
|
return null;
|
|
17201
17221
|
}
|
|
17202
17222
|
|
|
17223
|
+
// src/auto-ui/frontend/services/photon-instance-manager.ts
|
|
17224
|
+
var SimpleEventEmitter = class {
|
|
17225
|
+
constructor() {
|
|
17226
|
+
this._listeners = /* @__PURE__ */ new Map();
|
|
17227
|
+
}
|
|
17228
|
+
on(event, callback2) {
|
|
17229
|
+
if (!this._listeners.has(event)) {
|
|
17230
|
+
this._listeners.set(event, /* @__PURE__ */ new Set());
|
|
17231
|
+
}
|
|
17232
|
+
this._listeners.get(event).add(callback2);
|
|
17233
|
+
}
|
|
17234
|
+
off(event, callback2) {
|
|
17235
|
+
const listeners = this._listeners.get(event);
|
|
17236
|
+
if (listeners) {
|
|
17237
|
+
listeners.delete(callback2);
|
|
17238
|
+
}
|
|
17239
|
+
}
|
|
17240
|
+
emit(event, ...args) {
|
|
17241
|
+
const listeners = this._listeners.get(event);
|
|
17242
|
+
if (listeners) {
|
|
17243
|
+
for (const callback2 of listeners) {
|
|
17244
|
+
callback2(...args);
|
|
17245
|
+
}
|
|
17246
|
+
}
|
|
17247
|
+
}
|
|
17248
|
+
};
|
|
17249
|
+
var PhotonSessionProxy = class extends SimpleEventEmitter {
|
|
17250
|
+
constructor(options) {
|
|
17251
|
+
super();
|
|
17252
|
+
this._paginationState = /* @__PURE__ */ new Map();
|
|
17253
|
+
this._pendingPatches = [];
|
|
17254
|
+
this._isApplyingPatches = false;
|
|
17255
|
+
this._name = options.name;
|
|
17256
|
+
this._state = { ...options.initialState };
|
|
17257
|
+
}
|
|
17258
|
+
/**
|
|
17259
|
+
* Get the photon name
|
|
17260
|
+
*/
|
|
17261
|
+
get name() {
|
|
17262
|
+
return this._name;
|
|
17263
|
+
}
|
|
17264
|
+
/**
|
|
17265
|
+
* Get current state
|
|
17266
|
+
*/
|
|
17267
|
+
get state() {
|
|
17268
|
+
return this._state;
|
|
17269
|
+
}
|
|
17270
|
+
/**
|
|
17271
|
+
* Apply JSON Patch array to instance state
|
|
17272
|
+
* Patches from: https://tools.ietf.org/html/rfc6902
|
|
17273
|
+
*/
|
|
17274
|
+
applyPatches(patches) {
|
|
17275
|
+
if (!Array.isArray(patches) || patches.length === 0) {
|
|
17276
|
+
return;
|
|
17277
|
+
}
|
|
17278
|
+
this._pendingPatches.push(...patches);
|
|
17279
|
+
if (!this._isApplyingPatches) {
|
|
17280
|
+
this._isApplyingPatches = true;
|
|
17281
|
+
queueMicrotask(() => this._processPendingPatches());
|
|
17282
|
+
}
|
|
17283
|
+
}
|
|
17284
|
+
/**
|
|
17285
|
+
* Update pagination state for a property (e.g., 'items')
|
|
17286
|
+
*/
|
|
17287
|
+
setPaginationState(property2, state) {
|
|
17288
|
+
const current = this._paginationState.get(property2) || {
|
|
17289
|
+
pageSize: 20,
|
|
17290
|
+
currentPage: 0,
|
|
17291
|
+
hasMore: true,
|
|
17292
|
+
isLoading: false
|
|
17293
|
+
};
|
|
17294
|
+
this._paginationState.set(property2, { ...current, ...state });
|
|
17295
|
+
}
|
|
17296
|
+
/**
|
|
17297
|
+
* Get pagination state for a property
|
|
17298
|
+
*/
|
|
17299
|
+
getPaginationState(property2) {
|
|
17300
|
+
return this._paginationState.get(property2) || {
|
|
17301
|
+
pageSize: 20,
|
|
17302
|
+
currentPage: 0,
|
|
17303
|
+
hasMore: true,
|
|
17304
|
+
isLoading: false
|
|
17305
|
+
};
|
|
17306
|
+
}
|
|
17307
|
+
/**
|
|
17308
|
+
* Create a getter/setter for property access
|
|
17309
|
+
*/
|
|
17310
|
+
_createPropertyDescriptor(key) {
|
|
17311
|
+
return {
|
|
17312
|
+
configurable: true,
|
|
17313
|
+
enumerable: true,
|
|
17314
|
+
get: () => this._state[key],
|
|
17315
|
+
set: (value) => {
|
|
17316
|
+
this._state[key] = value;
|
|
17317
|
+
this.emit("propertyChanged", { property: key, value });
|
|
17318
|
+
}
|
|
17319
|
+
};
|
|
17320
|
+
}
|
|
17321
|
+
/**
|
|
17322
|
+
* Make a property accessible on the proxy
|
|
17323
|
+
*/
|
|
17324
|
+
makeProperty(key) {
|
|
17325
|
+
Object.defineProperty(this, key, this._createPropertyDescriptor(key));
|
|
17326
|
+
}
|
|
17327
|
+
/**
|
|
17328
|
+
* Get all top-level properties (useful for initialization)
|
|
17329
|
+
*/
|
|
17330
|
+
getProperties() {
|
|
17331
|
+
return Object.keys(this._state);
|
|
17332
|
+
}
|
|
17333
|
+
/**
|
|
17334
|
+
* Process pending patches
|
|
17335
|
+
*/
|
|
17336
|
+
_processPendingPatches() {
|
|
17337
|
+
const patches = this._pendingPatches.splice(0);
|
|
17338
|
+
try {
|
|
17339
|
+
for (const patch of patches) {
|
|
17340
|
+
this._applyPatch(patch);
|
|
17341
|
+
}
|
|
17342
|
+
this.emit("state-changed", patches);
|
|
17343
|
+
} finally {
|
|
17344
|
+
this._isApplyingPatches = false;
|
|
17345
|
+
if (this._pendingPatches.length > 0) {
|
|
17346
|
+
queueMicrotask(() => this._processPendingPatches());
|
|
17347
|
+
}
|
|
17348
|
+
}
|
|
17349
|
+
}
|
|
17350
|
+
/**
|
|
17351
|
+
* Apply a single JSON Patch operation
|
|
17352
|
+
*/
|
|
17353
|
+
_applyPatch(patch) {
|
|
17354
|
+
const { op, path, value } = patch;
|
|
17355
|
+
if (!path || typeof path !== "string") {
|
|
17356
|
+
console.warn("Invalid patch: missing or invalid path", patch);
|
|
17357
|
+
return;
|
|
17358
|
+
}
|
|
17359
|
+
const parts = path.split("/").filter((p5) => p5 !== "");
|
|
17360
|
+
let current = this._state;
|
|
17361
|
+
try {
|
|
17362
|
+
for (let i7 = 0; i7 < parts.length - 1; i7++) {
|
|
17363
|
+
const part = this._unescapePath(parts[i7]);
|
|
17364
|
+
if (!(part in current)) {
|
|
17365
|
+
current[part] = {};
|
|
17366
|
+
}
|
|
17367
|
+
current = current[part];
|
|
17368
|
+
}
|
|
17369
|
+
const lastPart = this._unescapePath(parts[parts.length - 1]);
|
|
17370
|
+
switch (op) {
|
|
17371
|
+
case "add":
|
|
17372
|
+
if (Array.isArray(current) && !isNaN(Number(lastPart))) {
|
|
17373
|
+
const index2 = Number(lastPart);
|
|
17374
|
+
current.splice(index2, 0, value);
|
|
17375
|
+
} else {
|
|
17376
|
+
current[lastPart] = value;
|
|
17377
|
+
}
|
|
17378
|
+
break;
|
|
17379
|
+
case "remove":
|
|
17380
|
+
if (Array.isArray(current) && !isNaN(Number(lastPart))) {
|
|
17381
|
+
const index2 = Number(lastPart);
|
|
17382
|
+
current.splice(index2, 1);
|
|
17383
|
+
} else {
|
|
17384
|
+
delete current[lastPart];
|
|
17385
|
+
}
|
|
17386
|
+
break;
|
|
17387
|
+
case "replace":
|
|
17388
|
+
current[lastPart] = value;
|
|
17389
|
+
break;
|
|
17390
|
+
case "move":
|
|
17391
|
+
const fromParts = patch.from.split("/").filter((p5) => p5 !== "");
|
|
17392
|
+
let fromCurrent = this._state;
|
|
17393
|
+
for (let i7 = 0; i7 < fromParts.length - 1; i7++) {
|
|
17394
|
+
fromCurrent = fromCurrent[this._unescapePath(fromParts[i7])];
|
|
17395
|
+
}
|
|
17396
|
+
const fromLast = this._unescapePath(fromParts[fromParts.length - 1]);
|
|
17397
|
+
const movedValue = fromCurrent[fromLast];
|
|
17398
|
+
if (Array.isArray(fromCurrent)) {
|
|
17399
|
+
fromCurrent.splice(Number(fromLast), 1);
|
|
17400
|
+
} else {
|
|
17401
|
+
delete fromCurrent[fromLast];
|
|
17402
|
+
}
|
|
17403
|
+
if (Array.isArray(current)) {
|
|
17404
|
+
current.splice(Number(lastPart), 0, movedValue);
|
|
17405
|
+
} else {
|
|
17406
|
+
current[lastPart] = movedValue;
|
|
17407
|
+
}
|
|
17408
|
+
break;
|
|
17409
|
+
case "copy":
|
|
17410
|
+
const copyFromParts = patch.from.split("/").filter((p5) => p5 !== "");
|
|
17411
|
+
let copyCurrent = this._state;
|
|
17412
|
+
for (let i7 = 0; i7 < copyFromParts.length - 1; i7++) {
|
|
17413
|
+
copyCurrent = copyCurrent[this._unescapePath(copyFromParts[i7])];
|
|
17414
|
+
}
|
|
17415
|
+
const copyFromLast = this._unescapePath(copyFromParts[copyFromParts.length - 1]);
|
|
17416
|
+
const copiedValue = JSON.parse(JSON.stringify(copyCurrent[copyFromLast]));
|
|
17417
|
+
current[lastPart] = copiedValue;
|
|
17418
|
+
break;
|
|
17419
|
+
case "test":
|
|
17420
|
+
if (current[lastPart] !== value) {
|
|
17421
|
+
throw new Error(`Test failed at ${path}: expected ${value}, got ${current[lastPart]}`);
|
|
17422
|
+
}
|
|
17423
|
+
break;
|
|
17424
|
+
default:
|
|
17425
|
+
console.warn(`Unknown patch operation: ${op}`);
|
|
17426
|
+
}
|
|
17427
|
+
} catch (error2) {
|
|
17428
|
+
console.error("Failed to apply patch", { patch, error: error2 });
|
|
17429
|
+
throw error2;
|
|
17430
|
+
}
|
|
17431
|
+
}
|
|
17432
|
+
/**
|
|
17433
|
+
* Unescape JSON Pointer path component
|
|
17434
|
+
* See: https://tools.ietf.org/html/rfc6901
|
|
17435
|
+
*/
|
|
17436
|
+
_unescapePath(part) {
|
|
17437
|
+
return part.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
17438
|
+
}
|
|
17439
|
+
/**
|
|
17440
|
+
* Clear all state
|
|
17441
|
+
*/
|
|
17442
|
+
reset(newState) {
|
|
17443
|
+
this._state = { ...newState };
|
|
17444
|
+
this._paginationState.clear();
|
|
17445
|
+
this.emit("reset");
|
|
17446
|
+
}
|
|
17447
|
+
};
|
|
17448
|
+
var GlobalSessionManager = class {
|
|
17449
|
+
constructor() {
|
|
17450
|
+
this._sessions = /* @__PURE__ */ new Map();
|
|
17451
|
+
}
|
|
17452
|
+
/**
|
|
17453
|
+
* Create or get a photon session
|
|
17454
|
+
*/
|
|
17455
|
+
createOrGetSession(name2, initialState) {
|
|
17456
|
+
if (this._sessions.has(name2)) {
|
|
17457
|
+
return this._sessions.get(name2);
|
|
17458
|
+
}
|
|
17459
|
+
const session = new PhotonSessionProxy({
|
|
17460
|
+
name: name2,
|
|
17461
|
+
initialState
|
|
17462
|
+
});
|
|
17463
|
+
Object.keys(initialState).forEach((key) => {
|
|
17464
|
+
session.makeProperty(key);
|
|
17465
|
+
});
|
|
17466
|
+
this._sessions.set(name2, session);
|
|
17467
|
+
return session;
|
|
17468
|
+
}
|
|
17469
|
+
/**
|
|
17470
|
+
* Get existing session
|
|
17471
|
+
*/
|
|
17472
|
+
getSession(name2) {
|
|
17473
|
+
return this._sessions.get(name2);
|
|
17474
|
+
}
|
|
17475
|
+
/**
|
|
17476
|
+
* Apply patches to a session
|
|
17477
|
+
*/
|
|
17478
|
+
applyPatches(name2, patches) {
|
|
17479
|
+
const session = this._sessions.get(name2);
|
|
17480
|
+
if (!session) {
|
|
17481
|
+
console.warn(`No session found for: ${name2}`);
|
|
17482
|
+
return false;
|
|
17483
|
+
}
|
|
17484
|
+
session.applyPatches(patches);
|
|
17485
|
+
return true;
|
|
17486
|
+
}
|
|
17487
|
+
/**
|
|
17488
|
+
* Remove session
|
|
17489
|
+
*/
|
|
17490
|
+
removeSession(name2) {
|
|
17491
|
+
this._sessions.delete(name2);
|
|
17492
|
+
}
|
|
17493
|
+
/**
|
|
17494
|
+
* Get all session names
|
|
17495
|
+
*/
|
|
17496
|
+
getSessionNames() {
|
|
17497
|
+
return Array.from(this._sessions.keys());
|
|
17498
|
+
}
|
|
17499
|
+
};
|
|
17500
|
+
var globalSessionManager = null;
|
|
17501
|
+
function getGlobalSessionManager() {
|
|
17502
|
+
if (!globalSessionManager) {
|
|
17503
|
+
globalSessionManager = new GlobalSessionManager();
|
|
17504
|
+
if (typeof window !== "undefined") {
|
|
17505
|
+
window.__photonSessionManager = globalSessionManager;
|
|
17506
|
+
}
|
|
17507
|
+
}
|
|
17508
|
+
return globalSessionManager;
|
|
17509
|
+
}
|
|
17510
|
+
function initializeGlobalPhotonSession(photonName, initialState) {
|
|
17511
|
+
const manager = getGlobalSessionManager();
|
|
17512
|
+
const session = manager.createOrGetSession(photonName, initialState);
|
|
17513
|
+
if (typeof window !== "undefined") {
|
|
17514
|
+
const varName = photonName.charAt(0).toLocaleLowerCase() + photonName.slice(1);
|
|
17515
|
+
window[varName] = session;
|
|
17516
|
+
if (photonName === "Boards") {
|
|
17517
|
+
window.boards = session;
|
|
17518
|
+
window.boardsSession = session;
|
|
17519
|
+
}
|
|
17520
|
+
}
|
|
17521
|
+
return session;
|
|
17522
|
+
}
|
|
17523
|
+
|
|
17203
17524
|
// src/auto-ui/frontend/services/mcp-client.ts
|
|
17204
17525
|
var MCPClientService = class {
|
|
17205
17526
|
// Discard operations older than 30s
|
|
@@ -17904,9 +18225,21 @@ var MCPClientService = class {
|
|
|
17904
18225
|
case "photon/refresh-needed":
|
|
17905
18226
|
this.emit("refresh-needed", notification.params);
|
|
17906
18227
|
break;
|
|
17907
|
-
case "
|
|
18228
|
+
case "state-changed":
|
|
18229
|
+
const params = notification.params;
|
|
18230
|
+
if (params?.instance && params?.patches) {
|
|
18231
|
+
try {
|
|
18232
|
+
const manager = getGlobalSessionManager();
|
|
18233
|
+
manager.applyPatches(params.instance, params.patches);
|
|
18234
|
+
} catch (error2) {
|
|
18235
|
+
console.error("Failed to apply patches to session", error2);
|
|
18236
|
+
}
|
|
18237
|
+
}
|
|
17908
18238
|
this.emit("state-changed", notification.params);
|
|
17909
18239
|
break;
|
|
18240
|
+
case "photon/notification":
|
|
18241
|
+
this.emit("photon-notification", notification.params);
|
|
18242
|
+
break;
|
|
17910
18243
|
// MCP Apps standard notifications
|
|
17911
18244
|
case "ui/notifications/tool-result":
|
|
17912
18245
|
this.emit("ui-tool-result", notification.params);
|
|
@@ -17931,6 +18264,439 @@ var MCPClientService = class {
|
|
|
17931
18264
|
};
|
|
17932
18265
|
var mcpClient = new MCPClientService();
|
|
17933
18266
|
|
|
18267
|
+
// src/auto-ui/frontend/services/viewport-aware-proxy.ts
|
|
18268
|
+
var ViewportAwareProxy = class {
|
|
18269
|
+
constructor(photonName, methodName, mcpClient2, options = {}) {
|
|
18270
|
+
// Cache management
|
|
18271
|
+
this._cache = /* @__PURE__ */ new Map();
|
|
18272
|
+
this._viewport = { start: 0, end: 20 };
|
|
18273
|
+
this._pendingRanges = /* @__PURE__ */ new Set();
|
|
18274
|
+
this._pagination = {
|
|
18275
|
+
totalCount: 0,
|
|
18276
|
+
start: 0,
|
|
18277
|
+
end: 0,
|
|
18278
|
+
hasMore: false
|
|
18279
|
+
};
|
|
18280
|
+
// Event listeners
|
|
18281
|
+
this._listeners = /* @__PURE__ */ new Map();
|
|
18282
|
+
this._photonName = photonName;
|
|
18283
|
+
this._methodName = methodName;
|
|
18284
|
+
this._mcpClient = mcpClient2;
|
|
18285
|
+
this._fetchOptions = {
|
|
18286
|
+
pageSize: options.pageSize ?? 20,
|
|
18287
|
+
bufferSize: options.bufferSize ?? 5,
|
|
18288
|
+
maxCacheSize: options.maxCacheSize ?? 1e3
|
|
18289
|
+
};
|
|
18290
|
+
}
|
|
18291
|
+
/**
|
|
18292
|
+
* Initialize with paginated response from server
|
|
18293
|
+
* Server should return: { items: [...], _pagination: {...} }
|
|
18294
|
+
*/
|
|
18295
|
+
initializeWithResponse(response) {
|
|
18296
|
+
if (!response || typeof response !== "object") {
|
|
18297
|
+
return;
|
|
18298
|
+
}
|
|
18299
|
+
const { items = [], _pagination } = response;
|
|
18300
|
+
if (_pagination) {
|
|
18301
|
+
this._pagination = _pagination;
|
|
18302
|
+
items.forEach((item, offset) => {
|
|
18303
|
+
this._cache.set(_pagination.start + offset, item);
|
|
18304
|
+
});
|
|
18305
|
+
this._emit("initialized", { pagination: this._pagination });
|
|
18306
|
+
}
|
|
18307
|
+
}
|
|
18308
|
+
/**
|
|
18309
|
+
* Set visible viewport (what user sees on screen)
|
|
18310
|
+
* Automatically fetches data for this range + buffer
|
|
18311
|
+
*/
|
|
18312
|
+
async setViewport(start, end) {
|
|
18313
|
+
this._viewport = { start, end };
|
|
18314
|
+
const bufferedStart = Math.max(0, start - this._fetchOptions.bufferSize);
|
|
18315
|
+
const bufferedEnd = Math.min(this._pagination.totalCount, end + this._fetchOptions.bufferSize);
|
|
18316
|
+
const missingRanges = this._findMissingRanges(bufferedStart, bufferedEnd);
|
|
18317
|
+
await Promise.all(
|
|
18318
|
+
missingRanges.map(
|
|
18319
|
+
(range) => this._fetchRange(range.start, range.end).catch((err) => {
|
|
18320
|
+
console.error(`Failed to fetch range [${range.start}, ${range.end}]`, err);
|
|
18321
|
+
})
|
|
18322
|
+
)
|
|
18323
|
+
);
|
|
18324
|
+
}
|
|
18325
|
+
/**
|
|
18326
|
+
* Get items in current viewport (array-like interface)
|
|
18327
|
+
*/
|
|
18328
|
+
get items() {
|
|
18329
|
+
const items = [];
|
|
18330
|
+
for (let i7 = this._viewport.start; i7 < this._viewport.end; i7++) {
|
|
18331
|
+
if (this._cache.has(i7)) {
|
|
18332
|
+
items.push(this._cache.get(i7));
|
|
18333
|
+
}
|
|
18334
|
+
}
|
|
18335
|
+
return items;
|
|
18336
|
+
}
|
|
18337
|
+
/**
|
|
18338
|
+
* Get item by index
|
|
18339
|
+
*/
|
|
18340
|
+
getItem(index2) {
|
|
18341
|
+
return this._cache.get(index2);
|
|
18342
|
+
}
|
|
18343
|
+
/**
|
|
18344
|
+
* Get total count of items (if available)
|
|
18345
|
+
*/
|
|
18346
|
+
get totalCount() {
|
|
18347
|
+
return this._pagination.totalCount;
|
|
18348
|
+
}
|
|
18349
|
+
/**
|
|
18350
|
+
* Get current pagination state
|
|
18351
|
+
*/
|
|
18352
|
+
get pagination() {
|
|
18353
|
+
return { ...this._pagination };
|
|
18354
|
+
}
|
|
18355
|
+
/**
|
|
18356
|
+
* Get current viewport
|
|
18357
|
+
*/
|
|
18358
|
+
get viewport() {
|
|
18359
|
+
return { ...this._viewport };
|
|
18360
|
+
}
|
|
18361
|
+
/**
|
|
18362
|
+
* Get cache size (for debugging)
|
|
18363
|
+
*/
|
|
18364
|
+
get cacheSize() {
|
|
18365
|
+
return this._cache.size;
|
|
18366
|
+
}
|
|
18367
|
+
/**
|
|
18368
|
+
* Check if a range is cached
|
|
18369
|
+
*/
|
|
18370
|
+
isCached(start, end) {
|
|
18371
|
+
for (let i7 = start; i7 < end; i7++) {
|
|
18372
|
+
if (!this._cache.has(i7)) {
|
|
18373
|
+
return false;
|
|
18374
|
+
}
|
|
18375
|
+
}
|
|
18376
|
+
return true;
|
|
18377
|
+
}
|
|
18378
|
+
/**
|
|
18379
|
+
* Subscribe to events
|
|
18380
|
+
*/
|
|
18381
|
+
on(event, callback2) {
|
|
18382
|
+
if (!this._listeners.has(event)) {
|
|
18383
|
+
this._listeners.set(event, /* @__PURE__ */ new Set());
|
|
18384
|
+
}
|
|
18385
|
+
this._listeners.get(event).add(callback2);
|
|
18386
|
+
}
|
|
18387
|
+
/**
|
|
18388
|
+
* Unsubscribe from events
|
|
18389
|
+
*/
|
|
18390
|
+
off(event, callback2) {
|
|
18391
|
+
const listeners = this._listeners.get(event);
|
|
18392
|
+
if (listeners) {
|
|
18393
|
+
listeners.delete(callback2);
|
|
18394
|
+
}
|
|
18395
|
+
}
|
|
18396
|
+
/**
|
|
18397
|
+
* Clear cache
|
|
18398
|
+
*/
|
|
18399
|
+
clearCache() {
|
|
18400
|
+
this._cache.clear();
|
|
18401
|
+
this._emit("cache-cleared");
|
|
18402
|
+
}
|
|
18403
|
+
/**
|
|
18404
|
+
* Apply patches from state-changed events
|
|
18405
|
+
* Updates cache with new/modified items
|
|
18406
|
+
*/
|
|
18407
|
+
applyPatches(patches) {
|
|
18408
|
+
for (const patch of patches) {
|
|
18409
|
+
this._applyPatch(patch);
|
|
18410
|
+
}
|
|
18411
|
+
this._emit("patched", { patches });
|
|
18412
|
+
}
|
|
18413
|
+
/**
|
|
18414
|
+
* Find which ranges need to be fetched
|
|
18415
|
+
*/
|
|
18416
|
+
_findMissingRanges(start, end) {
|
|
18417
|
+
const missing = [];
|
|
18418
|
+
for (let i7 = start; i7 < end; i7++) {
|
|
18419
|
+
if (!this._cache.has(i7)) {
|
|
18420
|
+
missing.push(i7);
|
|
18421
|
+
}
|
|
18422
|
+
}
|
|
18423
|
+
const ranges = [];
|
|
18424
|
+
if (missing.length === 0) return ranges;
|
|
18425
|
+
let rangeStart = missing[0];
|
|
18426
|
+
let rangeEnd2 = missing[0];
|
|
18427
|
+
for (let i7 = 1; i7 < missing.length; i7++) {
|
|
18428
|
+
if (missing[i7] === rangeEnd2 + 1) {
|
|
18429
|
+
rangeEnd2 = missing[i7];
|
|
18430
|
+
} else {
|
|
18431
|
+
ranges.push({ start: rangeStart, end: rangeEnd2 + 1 });
|
|
18432
|
+
rangeStart = missing[i7];
|
|
18433
|
+
rangeEnd2 = missing[i7];
|
|
18434
|
+
}
|
|
18435
|
+
}
|
|
18436
|
+
ranges.push({ start: rangeStart, end: rangeEnd2 + 1 });
|
|
18437
|
+
return ranges;
|
|
18438
|
+
}
|
|
18439
|
+
/**
|
|
18440
|
+
* Fetch a range of items via MCP
|
|
18441
|
+
*/
|
|
18442
|
+
async _fetchRange(start, end) {
|
|
18443
|
+
const rangeKey = `${start}-${end}`;
|
|
18444
|
+
if (this._pendingRanges.has(rangeKey)) {
|
|
18445
|
+
return;
|
|
18446
|
+
}
|
|
18447
|
+
this._pendingRanges.add(rangeKey);
|
|
18448
|
+
try {
|
|
18449
|
+
const toolName = `${this._photonName}/${this._methodName}`;
|
|
18450
|
+
const result = await this._mcpClient.callTool(toolName, {
|
|
18451
|
+
start,
|
|
18452
|
+
limit: Math.min(end - start, this._fetchOptions.pageSize)
|
|
18453
|
+
});
|
|
18454
|
+
if (result.isError) {
|
|
18455
|
+
console.error(`Failed to fetch ${toolName}[${start}:${end}]`, result);
|
|
18456
|
+
return;
|
|
18457
|
+
}
|
|
18458
|
+
const parsed = this._mcpClient.parseToolResult(result);
|
|
18459
|
+
if (parsed && typeof parsed === "object") {
|
|
18460
|
+
const { items = [], _pagination } = parsed;
|
|
18461
|
+
if (_pagination) {
|
|
18462
|
+
this._pagination = _pagination;
|
|
18463
|
+
}
|
|
18464
|
+
items.forEach((item, offset) => {
|
|
18465
|
+
this._cache.set(start + offset, item);
|
|
18466
|
+
});
|
|
18467
|
+
if (this._cache.size > this._fetchOptions.maxCacheSize) {
|
|
18468
|
+
this._pruneCache();
|
|
18469
|
+
}
|
|
18470
|
+
this._emit("fetched", { start, end, itemCount: items.length });
|
|
18471
|
+
}
|
|
18472
|
+
} finally {
|
|
18473
|
+
this._pendingRanges.delete(rangeKey);
|
|
18474
|
+
}
|
|
18475
|
+
}
|
|
18476
|
+
/**
|
|
18477
|
+
* Apply a single JSON Patch to cache
|
|
18478
|
+
*/
|
|
18479
|
+
_applyPatch(patch) {
|
|
18480
|
+
const { op, path } = patch;
|
|
18481
|
+
const match = path.match(/\/items\/(\d+)/);
|
|
18482
|
+
if (!match) return;
|
|
18483
|
+
const index2 = parseInt(match[1], 10);
|
|
18484
|
+
switch (op) {
|
|
18485
|
+
case "add": {
|
|
18486
|
+
const newCache = /* @__PURE__ */ new Map();
|
|
18487
|
+
for (const [key, value] of this._cache) {
|
|
18488
|
+
if (key >= index2) {
|
|
18489
|
+
newCache.set(key + 1, value);
|
|
18490
|
+
} else {
|
|
18491
|
+
newCache.set(key, value);
|
|
18492
|
+
}
|
|
18493
|
+
}
|
|
18494
|
+
newCache.set(index2, patch.value);
|
|
18495
|
+
this._cache = newCache;
|
|
18496
|
+
this._pagination.totalCount++;
|
|
18497
|
+
break;
|
|
18498
|
+
}
|
|
18499
|
+
case "remove": {
|
|
18500
|
+
const newCache = /* @__PURE__ */ new Map();
|
|
18501
|
+
for (const [key, value] of this._cache) {
|
|
18502
|
+
if (key > index2) {
|
|
18503
|
+
newCache.set(key - 1, value);
|
|
18504
|
+
} else if (key < index2) {
|
|
18505
|
+
newCache.set(key, value);
|
|
18506
|
+
}
|
|
18507
|
+
}
|
|
18508
|
+
this._cache = newCache;
|
|
18509
|
+
this._pagination.totalCount--;
|
|
18510
|
+
break;
|
|
18511
|
+
}
|
|
18512
|
+
case "replace": {
|
|
18513
|
+
this._cache.set(index2, patch.value);
|
|
18514
|
+
break;
|
|
18515
|
+
}
|
|
18516
|
+
}
|
|
18517
|
+
}
|
|
18518
|
+
/**
|
|
18519
|
+
* Remove least-recently-used items from cache when it gets too large
|
|
18520
|
+
*/
|
|
18521
|
+
_pruneCache() {
|
|
18522
|
+
const toRemove = this._cache.size - this._fetchOptions.maxCacheSize;
|
|
18523
|
+
if (toRemove <= 0) return;
|
|
18524
|
+
const viewportCenter = this._viewport.start + (this._viewport.end - this._viewport.start) / 2;
|
|
18525
|
+
const sortedKeys = Array.from(this._cache.keys()).sort(
|
|
18526
|
+
(a5, b3) => Math.abs(a5 - viewportCenter) - Math.abs(b3 - viewportCenter)
|
|
18527
|
+
);
|
|
18528
|
+
for (let i7 = 0; i7 < toRemove && i7 < sortedKeys.length; i7++) {
|
|
18529
|
+
this._cache.delete(sortedKeys[i7]);
|
|
18530
|
+
}
|
|
18531
|
+
}
|
|
18532
|
+
/**
|
|
18533
|
+
* Emit event to listeners
|
|
18534
|
+
*/
|
|
18535
|
+
_emit(event, data) {
|
|
18536
|
+
const listeners = this._listeners.get(event);
|
|
18537
|
+
if (listeners) {
|
|
18538
|
+
for (const callback2 of listeners) {
|
|
18539
|
+
try {
|
|
18540
|
+
callback2(data);
|
|
18541
|
+
} catch (err) {
|
|
18542
|
+
console.error(`Error in ${event} listener:`, err);
|
|
18543
|
+
}
|
|
18544
|
+
}
|
|
18545
|
+
}
|
|
18546
|
+
}
|
|
18547
|
+
};
|
|
18548
|
+
|
|
18549
|
+
// src/auto-ui/frontend/services/viewport-manager.ts
|
|
18550
|
+
function getPageSizeForClient() {
|
|
18551
|
+
if (typeof window !== "undefined" && window.innerWidth < 600) {
|
|
18552
|
+
return 10;
|
|
18553
|
+
}
|
|
18554
|
+
if (typeof window !== "undefined" && window.innerWidth < 1024) {
|
|
18555
|
+
return 25;
|
|
18556
|
+
}
|
|
18557
|
+
return 50;
|
|
18558
|
+
}
|
|
18559
|
+
var ViewportManager = class {
|
|
18560
|
+
constructor(config3) {
|
|
18561
|
+
this.observer = null;
|
|
18562
|
+
this.visibleSentinels = /* @__PURE__ */ new Set();
|
|
18563
|
+
this.lastVisibleRange = { start: 0, end: 0 };
|
|
18564
|
+
this.lastScrollDirection = "none";
|
|
18565
|
+
this.changeCallbacks = [];
|
|
18566
|
+
this.element = config3.element;
|
|
18567
|
+
this.pageSize = config3.pageSize;
|
|
18568
|
+
this.paddingAbove = config3.paddingAbove ?? this.pageSize;
|
|
18569
|
+
this.paddingBelow = config3.paddingBelow ?? this.pageSize * 2;
|
|
18570
|
+
this.debug = config3.debug ?? false;
|
|
18571
|
+
this.log("ViewportManager initialized", {
|
|
18572
|
+
pageSize: this.pageSize,
|
|
18573
|
+
paddingAbove: this.paddingAbove,
|
|
18574
|
+
paddingBelow: this.paddingBelow
|
|
18575
|
+
});
|
|
18576
|
+
this.initializeObserver();
|
|
18577
|
+
}
|
|
18578
|
+
initializeObserver() {
|
|
18579
|
+
const options = {
|
|
18580
|
+
root: null,
|
|
18581
|
+
rootMargin: "100px",
|
|
18582
|
+
threshold: 0
|
|
18583
|
+
};
|
|
18584
|
+
this.observer = new IntersectionObserver((entries) => {
|
|
18585
|
+
for (const entry of entries) {
|
|
18586
|
+
const index2 = this.getSentinelIndex(entry.target);
|
|
18587
|
+
if (index2 !== null) {
|
|
18588
|
+
if (entry.isIntersecting) {
|
|
18589
|
+
this.visibleSentinels.add(index2);
|
|
18590
|
+
} else {
|
|
18591
|
+
this.visibleSentinels.delete(index2);
|
|
18592
|
+
}
|
|
18593
|
+
}
|
|
18594
|
+
}
|
|
18595
|
+
this.updateVisibleRange();
|
|
18596
|
+
}, options);
|
|
18597
|
+
}
|
|
18598
|
+
createSentinel(index2) {
|
|
18599
|
+
const sentinel = document.createElement("div");
|
|
18600
|
+
sentinel.setAttribute("data-viewport-sentinel", String(index2));
|
|
18601
|
+
sentinel.style.height = "0px";
|
|
18602
|
+
sentinel.style.overflow = "hidden";
|
|
18603
|
+
return sentinel;
|
|
18604
|
+
}
|
|
18605
|
+
observeSentinel(sentinel) {
|
|
18606
|
+
if (this.observer) {
|
|
18607
|
+
this.observer.observe(sentinel);
|
|
18608
|
+
}
|
|
18609
|
+
}
|
|
18610
|
+
unobserveSentinel(sentinel) {
|
|
18611
|
+
if (this.observer) {
|
|
18612
|
+
this.observer.unobserve(sentinel);
|
|
18613
|
+
}
|
|
18614
|
+
}
|
|
18615
|
+
getSentinelIndex(element) {
|
|
18616
|
+
const attr = element.getAttribute("data-viewport-sentinel");
|
|
18617
|
+
return attr !== null ? parseInt(attr, 10) : null;
|
|
18618
|
+
}
|
|
18619
|
+
updateVisibleRange() {
|
|
18620
|
+
if (this.visibleSentinels.size === 0) {
|
|
18621
|
+
return;
|
|
18622
|
+
}
|
|
18623
|
+
const indices = Array.from(this.visibleSentinels).sort((a5, b3) => a5 - b3);
|
|
18624
|
+
const visibleStart = indices[0];
|
|
18625
|
+
const visibleEnd = indices[indices.length - 1] + 1;
|
|
18626
|
+
const direction = this.determineScrollDirection(visibleStart);
|
|
18627
|
+
const bufferStart = Math.max(
|
|
18628
|
+
0,
|
|
18629
|
+
visibleStart - Math.ceil(this.paddingAbove / this.pageSize) * this.pageSize
|
|
18630
|
+
);
|
|
18631
|
+
const bufferEnd = visibleEnd + Math.ceil(this.paddingBelow / this.pageSize) * this.pageSize;
|
|
18632
|
+
const rangeChanged = visibleStart !== this.lastVisibleRange.start || visibleEnd !== this.lastVisibleRange.end;
|
|
18633
|
+
if (rangeChanged) {
|
|
18634
|
+
this.lastVisibleRange = { start: visibleStart, end: visibleEnd };
|
|
18635
|
+
this.lastScrollDirection = direction;
|
|
18636
|
+
const event = {
|
|
18637
|
+
visibleRange: { start: visibleStart, end: visibleEnd },
|
|
18638
|
+
bufferRange: { start: bufferStart, end: bufferEnd },
|
|
18639
|
+
scrollDirection: direction,
|
|
18640
|
+
timestamp: Date.now()
|
|
18641
|
+
};
|
|
18642
|
+
this.log("Viewport changed", event);
|
|
18643
|
+
for (const callback2 of this.changeCallbacks) {
|
|
18644
|
+
callback2(event);
|
|
18645
|
+
}
|
|
18646
|
+
}
|
|
18647
|
+
}
|
|
18648
|
+
determineScrollDirection(newStart) {
|
|
18649
|
+
if (newStart < this.lastVisibleRange.start) {
|
|
18650
|
+
return "up";
|
|
18651
|
+
} else if (newStart > this.lastVisibleRange.start) {
|
|
18652
|
+
return "down";
|
|
18653
|
+
}
|
|
18654
|
+
return "none";
|
|
18655
|
+
}
|
|
18656
|
+
getVisibleRange() {
|
|
18657
|
+
return this.lastVisibleRange;
|
|
18658
|
+
}
|
|
18659
|
+
getBufferRange(totalItems) {
|
|
18660
|
+
const { start, end } = this.lastVisibleRange;
|
|
18661
|
+
const bufferStart = Math.max(0, start - this.paddingAbove);
|
|
18662
|
+
const bufferEnd = Math.min(totalItems, end + this.paddingBelow);
|
|
18663
|
+
return { start: bufferStart, end: bufferEnd };
|
|
18664
|
+
}
|
|
18665
|
+
getScrollDirection() {
|
|
18666
|
+
return this.lastScrollDirection;
|
|
18667
|
+
}
|
|
18668
|
+
getPageSize() {
|
|
18669
|
+
return this.pageSize;
|
|
18670
|
+
}
|
|
18671
|
+
onChange(callback2) {
|
|
18672
|
+
this.changeCallbacks.push(callback2);
|
|
18673
|
+
}
|
|
18674
|
+
offChange(callback2) {
|
|
18675
|
+
this.changeCallbacks = this.changeCallbacks.filter((cb) => cb !== callback2);
|
|
18676
|
+
}
|
|
18677
|
+
setPageSize(newPageSize) {
|
|
18678
|
+
if (newPageSize !== this.pageSize) {
|
|
18679
|
+
this.pageSize = newPageSize;
|
|
18680
|
+
this.log("Page size updated", { newPageSize });
|
|
18681
|
+
this.updateVisibleRange();
|
|
18682
|
+
}
|
|
18683
|
+
}
|
|
18684
|
+
destroy() {
|
|
18685
|
+
if (this.observer) {
|
|
18686
|
+
this.observer.disconnect();
|
|
18687
|
+
this.observer = null;
|
|
18688
|
+
}
|
|
18689
|
+
this.changeCallbacks = [];
|
|
18690
|
+
this.visibleSentinels.clear();
|
|
18691
|
+
this.log("ViewportManager destroyed");
|
|
18692
|
+
}
|
|
18693
|
+
log(message, data) {
|
|
18694
|
+
if (this.debug) {
|
|
18695
|
+
console.log(`[ViewportManager] ${message}`, data);
|
|
18696
|
+
}
|
|
18697
|
+
}
|
|
18698
|
+
};
|
|
18699
|
+
|
|
17934
18700
|
// src/auto-ui/frontend/components/beam-app.ts
|
|
17935
18701
|
var THEME_STORAGE_KEY = "beam-theme";
|
|
17936
18702
|
var PROTOCOL_STORAGE_KEY = "beam-protocol";
|
|
@@ -17994,6 +18760,10 @@ var BeamApp = class extends i4 {
|
|
|
17994
18760
|
this._promptArguments = {};
|
|
17995
18761
|
this._renderedPrompt = "";
|
|
17996
18762
|
this._resourceContent = "";
|
|
18763
|
+
this._splitPanels = [];
|
|
18764
|
+
this._methodPickerOpen = false;
|
|
18765
|
+
this._methodPickerPanelId = null;
|
|
18766
|
+
this._nextPanelId = 0;
|
|
17997
18767
|
// Collection auto-subscription for ReactiveArray/Map/Set events
|
|
17998
18768
|
this._collectionUnsubscribes = [];
|
|
17999
18769
|
this._currentCollectionName = null;
|
|
@@ -18004,6 +18774,10 @@ var BeamApp = class extends i4 {
|
|
|
18004
18774
|
this._fileIdCounter = 0;
|
|
18005
18775
|
// Deep link URL for setOpenInAppUrl
|
|
18006
18776
|
this._openInAppUrl = null;
|
|
18777
|
+
// PWA install state
|
|
18778
|
+
this._pwaInstallPrompt = null;
|
|
18779
|
+
this._pwaIsStandalone = false;
|
|
18780
|
+
this._pwaCurrentPhoton = null;
|
|
18007
18781
|
this._handleDocumentClick = (e8) => {
|
|
18008
18782
|
const path = e8.composedPath();
|
|
18009
18783
|
if (this._showSettingsMenu) {
|
|
@@ -18021,11 +18795,11 @@ var BeamApp = class extends i4 {
|
|
|
18021
18795
|
}
|
|
18022
18796
|
};
|
|
18023
18797
|
this._initialConnectDone = false;
|
|
18024
|
-
this.
|
|
18798
|
+
this._handleRouteChange = () => {
|
|
18025
18799
|
void (async () => {
|
|
18026
|
-
const
|
|
18027
|
-
const
|
|
18028
|
-
const [photonName, methodName] =
|
|
18800
|
+
const fullPath = window.location.pathname.slice(1);
|
|
18801
|
+
const queryPart = window.location.search.slice(1);
|
|
18802
|
+
const [photonName, methodName] = fullPath.split("/");
|
|
18029
18803
|
let sharedParams = {};
|
|
18030
18804
|
if (queryPart) {
|
|
18031
18805
|
const params = new URLSearchParams(queryPart);
|
|
@@ -18042,6 +18816,9 @@ var BeamApp = class extends i4 {
|
|
|
18042
18816
|
}
|
|
18043
18817
|
}
|
|
18044
18818
|
}
|
|
18819
|
+
this._methodPickerOpen = false;
|
|
18820
|
+
this._methodPickerPanelId = null;
|
|
18821
|
+
this._splitPanels = [];
|
|
18045
18822
|
if (!photonName || photonName === "home") {
|
|
18046
18823
|
this._selectedPhoton = null;
|
|
18047
18824
|
this._selectedMethod = null;
|
|
@@ -18068,7 +18845,8 @@ var BeamApp = class extends i4 {
|
|
|
18068
18845
|
return;
|
|
18069
18846
|
}
|
|
18070
18847
|
if (methodName && photon.methods) {
|
|
18071
|
-
const
|
|
18848
|
+
const [firstMethodName, secondMethodName] = methodName.split("+");
|
|
18849
|
+
const method = photon.methods.find((m3) => m3.name === firstMethodName);
|
|
18072
18850
|
if (method) {
|
|
18073
18851
|
if (Object.keys(sharedParams).length > 0) {
|
|
18074
18852
|
this._sharedFormParams = sharedParams;
|
|
@@ -18079,6 +18857,22 @@ var BeamApp = class extends i4 {
|
|
|
18079
18857
|
}
|
|
18080
18858
|
this._selectedMethod = method;
|
|
18081
18859
|
this._view = "form";
|
|
18860
|
+
if (secondMethodName) {
|
|
18861
|
+
const urlPath = location.pathname;
|
|
18862
|
+
const methodPart = urlPath.split("/").pop() || "";
|
|
18863
|
+
const methodNames = methodPart.split("+");
|
|
18864
|
+
for (let i7 = 1; i7 < methodNames.length; i7++) {
|
|
18865
|
+
const name2 = methodNames[i7];
|
|
18866
|
+
if (name2 === "source") {
|
|
18867
|
+
this._addPanel("source");
|
|
18868
|
+
} else {
|
|
18869
|
+
const panelMethod = photon.methods.find((m3) => m3.name === name2);
|
|
18870
|
+
if (panelMethod) {
|
|
18871
|
+
this._addPanel("method", panelMethod);
|
|
18872
|
+
}
|
|
18873
|
+
}
|
|
18874
|
+
}
|
|
18875
|
+
}
|
|
18082
18876
|
if (Object.keys(sharedParams).length === 0) {
|
|
18083
18877
|
this._maybeAutoInvoke(method);
|
|
18084
18878
|
}
|
|
@@ -18098,18 +18892,15 @@ var BeamApp = class extends i4 {
|
|
|
18098
18892
|
}
|
|
18099
18893
|
})();
|
|
18100
18894
|
};
|
|
18101
|
-
this._handlePopState = () => {
|
|
18102
|
-
void this._handleHashChange();
|
|
18103
|
-
};
|
|
18104
18895
|
this._goHome = () => {
|
|
18105
18896
|
this._selectedPhoton = null;
|
|
18106
18897
|
this._selectedMethod = null;
|
|
18107
18898
|
this._lastResult = null;
|
|
18108
|
-
this.
|
|
18899
|
+
this._updateRoute();
|
|
18109
18900
|
};
|
|
18110
18901
|
this._runTests = async () => {
|
|
18111
18902
|
if (!this._selectedPhoton || this._runningTests) return;
|
|
18112
|
-
const testMethods = this.
|
|
18903
|
+
const testMethods = await this._fetchTestList(this._selectedPhoton.name);
|
|
18113
18904
|
if (testMethods.length === 0) return;
|
|
18114
18905
|
this._runningTests = true;
|
|
18115
18906
|
this._testResults = [];
|
|
@@ -18195,6 +18986,7 @@ var BeamApp = class extends i4 {
|
|
|
18195
18986
|
`All photon tests: ${passed}/${total} passed`
|
|
18196
18987
|
);
|
|
18197
18988
|
};
|
|
18989
|
+
this._pickerDismissHandler = null;
|
|
18198
18990
|
this._toggleSettingsMenu = () => {
|
|
18199
18991
|
this._showSettingsMenu = !this._showSettingsMenu;
|
|
18200
18992
|
};
|
|
@@ -18213,8 +19005,45 @@ var BeamApp = class extends i4 {
|
|
|
18213
19005
|
};
|
|
18214
19006
|
this._launchAsApp = () => {
|
|
18215
19007
|
this._closeSettingsMenu();
|
|
18216
|
-
if (this._selectedPhoton)
|
|
18217
|
-
|
|
19008
|
+
if (!this._selectedPhoton) return;
|
|
19009
|
+
if (this._pwaInstallPrompt) {
|
|
19010
|
+
void (async () => {
|
|
19011
|
+
try {
|
|
19012
|
+
await fetch("/api/pwa/configure", {
|
|
19013
|
+
method: "POST",
|
|
19014
|
+
headers: { "Content-Type": "application/json" },
|
|
19015
|
+
body: JSON.stringify({
|
|
19016
|
+
photon: this._selectedPhoton.name,
|
|
19017
|
+
port: location.port || "4100"
|
|
19018
|
+
}),
|
|
19019
|
+
signal: AbortSignal.timeout(5e3)
|
|
19020
|
+
});
|
|
19021
|
+
} catch {
|
|
19022
|
+
}
|
|
19023
|
+
const photonName = this._selectedPhoton.name;
|
|
19024
|
+
const onInstalled = () => {
|
|
19025
|
+
window.open(`/app/${encodeURIComponent(photonName)}`, "_blank");
|
|
19026
|
+
};
|
|
19027
|
+
window.addEventListener("appinstalled", onInstalled, { once: true });
|
|
19028
|
+
const result = await this._pwaInstallPrompt.prompt();
|
|
19029
|
+
this._log("info", `PWA install prompt result: ${result?.outcome}`);
|
|
19030
|
+
if (result?.outcome !== "accepted") {
|
|
19031
|
+
window.removeEventListener("appinstalled", onInstalled);
|
|
19032
|
+
}
|
|
19033
|
+
this._pwaInstallPrompt = null;
|
|
19034
|
+
})();
|
|
19035
|
+
} else {
|
|
19036
|
+
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
19037
|
+
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) || navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1;
|
|
19038
|
+
if (isSafari || isIOS) {
|
|
19039
|
+
const hint = isIOS ? 'Tap the Share button, then "Add to Home Screen"' : "Use File > Add to Dock to install this app";
|
|
19040
|
+
showToast(hint, "info");
|
|
19041
|
+
} else {
|
|
19042
|
+
showToast(
|
|
19043
|
+
"Install not ready yet \u2014 the service worker needs a moment to generate icons. Try again in a few seconds.",
|
|
19044
|
+
"info"
|
|
19045
|
+
);
|
|
19046
|
+
}
|
|
18218
19047
|
}
|
|
18219
19048
|
};
|
|
18220
19049
|
this._handleRemove = async () => {
|
|
@@ -18380,7 +19209,7 @@ var BeamApp = class extends i4 {
|
|
|
18380
19209
|
}
|
|
18381
19210
|
}
|
|
18382
19211
|
this._view = "config";
|
|
18383
|
-
this.
|
|
19212
|
+
this._updateRoute();
|
|
18384
19213
|
};
|
|
18385
19214
|
this._toggleRememberValues = () => {
|
|
18386
19215
|
this._rememberFormValues = !this._rememberFormValues;
|
|
@@ -18965,7 +19794,7 @@ var BeamApp = class extends i4 {
|
|
|
18965
19794
|
}
|
|
18966
19795
|
if (e8.key === "Enter" && this._selectedMethod && this._view === "list") {
|
|
18967
19796
|
this._view = "form";
|
|
18968
|
-
this.
|
|
19797
|
+
this._updateRoute();
|
|
18969
19798
|
return;
|
|
18970
19799
|
}
|
|
18971
19800
|
if (e8.key === "r") {
|
|
@@ -19001,12 +19830,12 @@ var BeamApp = class extends i4 {
|
|
|
19001
19830
|
this._focusMode = !this._focusMode;
|
|
19002
19831
|
if (this._focusMode) {
|
|
19003
19832
|
this.classList.add("focus-mode");
|
|
19004
|
-
const
|
|
19005
|
-
history.replaceState(null, "",
|
|
19833
|
+
const path = window.location.pathname;
|
|
19834
|
+
history.replaceState(null, "", path + "?focus=1");
|
|
19006
19835
|
} else {
|
|
19007
19836
|
this.classList.remove("focus-mode");
|
|
19008
|
-
const
|
|
19009
|
-
history.replaceState(null, "",
|
|
19837
|
+
const path = window.location.pathname;
|
|
19838
|
+
history.replaceState(null, "", path);
|
|
19010
19839
|
}
|
|
19011
19840
|
};
|
|
19012
19841
|
this._handleFullscreen = () => {
|
|
@@ -19105,9 +19934,25 @@ var BeamApp = class extends i4 {
|
|
|
19105
19934
|
case "fullscreen":
|
|
19106
19935
|
this._handleFullscreen();
|
|
19107
19936
|
break;
|
|
19937
|
+
case "install-app":
|
|
19938
|
+
this._launchAsApp();
|
|
19939
|
+
break;
|
|
19940
|
+
}
|
|
19941
|
+
break;
|
|
19942
|
+
}
|
|
19943
|
+
case "split-view:add":
|
|
19944
|
+
this._showMethodPicker();
|
|
19945
|
+
break;
|
|
19946
|
+
case "split-view:change": {
|
|
19947
|
+
const method = this._selectedPhoton?.methods?.find((m3) => m3.name === e8.detail.method);
|
|
19948
|
+
if (method && this._splitPanels.length > 0) {
|
|
19949
|
+
this._changePanelMethod(this._splitPanels[0].id, method);
|
|
19108
19950
|
}
|
|
19109
19951
|
break;
|
|
19110
19952
|
}
|
|
19953
|
+
case "split-view:remove":
|
|
19954
|
+
this._closeSecondPanel();
|
|
19955
|
+
break;
|
|
19111
19956
|
}
|
|
19112
19957
|
};
|
|
19113
19958
|
this._startEditingDescription = () => {
|
|
@@ -19307,7 +20152,7 @@ var BeamApp = class extends i4 {
|
|
|
19307
20152
|
if (method) {
|
|
19308
20153
|
this._selectedMethod = method;
|
|
19309
20154
|
this._view = "form";
|
|
19310
|
-
this.
|
|
20155
|
+
this._updateRoute();
|
|
19311
20156
|
this._log("info", `Starting ${targetName}/${action}...`);
|
|
19312
20157
|
showToast(`Starting ${action}...`, "info");
|
|
19313
20158
|
} else {
|
|
@@ -19334,15 +20179,21 @@ var BeamApp = class extends i4 {
|
|
|
19334
20179
|
*/
|
|
19335
20180
|
_handleGlobalMethodSelect(photon, method) {
|
|
19336
20181
|
this._teardownActiveCustomUI();
|
|
20182
|
+
if (this._selectedPhoton?.name !== photon.name) {
|
|
20183
|
+
this._closeSecondPanel();
|
|
20184
|
+
}
|
|
19337
20185
|
this._selectedPhoton = photon;
|
|
19338
20186
|
if (this._willAutoInvoke(method)) {
|
|
19339
20187
|
this._isExecuting = true;
|
|
19340
20188
|
}
|
|
19341
20189
|
this._selectedMethod = method;
|
|
19342
20190
|
this._view = "form";
|
|
19343
|
-
this.
|
|
20191
|
+
this._updateRoute();
|
|
19344
20192
|
this._maybeAutoInvoke(method);
|
|
19345
20193
|
}
|
|
20194
|
+
get _splitViewEnabled() {
|
|
20195
|
+
return this._splitPanels.length > 0;
|
|
20196
|
+
}
|
|
19346
20197
|
connectedCallback() {
|
|
19347
20198
|
super.connectedCallback();
|
|
19348
20199
|
const savedTheme = localStorage.getItem(THEME_STORAGE_KEY);
|
|
@@ -19374,20 +20225,114 @@ var BeamApp = class extends i4 {
|
|
|
19374
20225
|
}
|
|
19375
20226
|
document.addEventListener("click", this._handleDocumentClick);
|
|
19376
20227
|
void this._connectMCP();
|
|
19377
|
-
|
|
19378
|
-
window.addEventListener("popstate", this.
|
|
20228
|
+
this._setupNotificationHandlers();
|
|
20229
|
+
window.addEventListener("popstate", this._handleRouteChange);
|
|
19379
20230
|
window.addEventListener("message", this._handleBridgeMessage);
|
|
19380
20231
|
window.addEventListener("keydown", this._handleKeydown);
|
|
20232
|
+
this._initPWA();
|
|
19381
20233
|
}
|
|
19382
20234
|
disconnectedCallback() {
|
|
19383
20235
|
super.disconnectedCallback();
|
|
19384
|
-
window.removeEventListener("
|
|
19385
|
-
window.removeEventListener("popstate", this._handlePopState);
|
|
20236
|
+
window.removeEventListener("popstate", this._handleRouteChange);
|
|
19386
20237
|
window.removeEventListener("message", this._handleBridgeMessage);
|
|
19387
20238
|
window.removeEventListener("keydown", this._handleKeydown);
|
|
19388
20239
|
document.removeEventListener("click", this._handleDocumentClick);
|
|
19389
20240
|
this._cleanupCollectionSubscriptions();
|
|
19390
20241
|
}
|
|
20242
|
+
willUpdate(changedProperties) {
|
|
20243
|
+
super.willUpdate(changedProperties);
|
|
20244
|
+
if (changedProperties.has("_selectedPhoton")) {
|
|
20245
|
+
const name2 = this._selectedPhoton?.name || null;
|
|
20246
|
+
if (name2 !== this._pwaCurrentPhoton) {
|
|
20247
|
+
this._pwaCurrentPhoton = name2;
|
|
20248
|
+
if (name2) {
|
|
20249
|
+
this._setupPWAManifest(name2);
|
|
20250
|
+
}
|
|
20251
|
+
}
|
|
20252
|
+
}
|
|
20253
|
+
}
|
|
20254
|
+
// ---------------------------------------------------------------------------
|
|
20255
|
+
// PWA — Progressive Web App support
|
|
20256
|
+
// ---------------------------------------------------------------------------
|
|
20257
|
+
_initPWA() {
|
|
20258
|
+
this._pwaIsStandalone = window.matchMedia("(display-mode: standalone)").matches || window.navigator.standalone === true;
|
|
20259
|
+
if ("serviceWorker" in navigator) {
|
|
20260
|
+
navigator.serviceWorker.register("/sw.js", { scope: "/" }).then((reg) => this._log("info", `PWA SW registered: ${reg.scope}`, true)).catch((err) => this._log("warn", `PWA SW registration failed: ${err}`, true));
|
|
20261
|
+
}
|
|
20262
|
+
window.addEventListener("beforeinstallprompt", (e8) => {
|
|
20263
|
+
this._pwaInstallPrompt = e8;
|
|
20264
|
+
});
|
|
20265
|
+
window.addEventListener("appinstalled", () => {
|
|
20266
|
+
this._pwaInstallPrompt = null;
|
|
20267
|
+
this._log("info", "PWA app installed");
|
|
20268
|
+
});
|
|
20269
|
+
}
|
|
20270
|
+
/**
|
|
20271
|
+
* Set up notification handlers for photon notifications.
|
|
20272
|
+
* When a notification arrives for a photon that cares about that event type,
|
|
20273
|
+
* bring the window to focus (especially important for PWAs/background tabs).
|
|
20274
|
+
*/
|
|
20275
|
+
_setupNotificationHandlers() {
|
|
20276
|
+
mcpClient.on("photon-notification", (notification) => {
|
|
20277
|
+
const { photon, type, priority } = notification;
|
|
20278
|
+
if (!photon || !type) return;
|
|
20279
|
+
const sidebarElement = this.querySelector("beam-sidebar");
|
|
20280
|
+
if (sidebarElement && sidebarElement.isNotificationWatched) {
|
|
20281
|
+
const isWatched = sidebarElement.isNotificationWatched(photon, type);
|
|
20282
|
+
if (isWatched) {
|
|
20283
|
+
window.focus();
|
|
20284
|
+
console.log(`\u{1F4E1} Window focused for ${photon} notification: ${type}`);
|
|
20285
|
+
sidebarElement.updatePhotonWarmth?.(photon);
|
|
20286
|
+
}
|
|
20287
|
+
}
|
|
20288
|
+
});
|
|
20289
|
+
}
|
|
20290
|
+
/**
|
|
20291
|
+
* Set up the PWA manifest & icons for the currently selected photon.
|
|
20292
|
+
* Called whenever the selected photon changes. The manifest points to
|
|
20293
|
+
* /api/pwa/icon-png URLs which the service worker intercepts and renders
|
|
20294
|
+
* as real PNGs via OffscreenCanvas — no client-side blob URL needed.
|
|
20295
|
+
*/
|
|
20296
|
+
_setupPWAManifest(photonName) {
|
|
20297
|
+
let manifestLink = document.head.querySelector('link[rel="manifest"]');
|
|
20298
|
+
if (!manifestLink) {
|
|
20299
|
+
manifestLink = document.createElement("link");
|
|
20300
|
+
manifestLink.rel = "manifest";
|
|
20301
|
+
document.head.appendChild(manifestLink);
|
|
20302
|
+
}
|
|
20303
|
+
manifestLink.href = `/api/pwa/manifest.json?photon=${encodeURIComponent(photonName)}`;
|
|
20304
|
+
let appleIcon = document.head.querySelector('link[rel="apple-touch-icon"]');
|
|
20305
|
+
if (!appleIcon) {
|
|
20306
|
+
appleIcon = document.createElement("link");
|
|
20307
|
+
appleIcon.rel = "apple-touch-icon";
|
|
20308
|
+
document.head.appendChild(appleIcon);
|
|
20309
|
+
}
|
|
20310
|
+
appleIcon.href = `/api/pwa/icon?photon=${encodeURIComponent(photonName)}`;
|
|
20311
|
+
let appleTitleMeta = document.head.querySelector(
|
|
20312
|
+
'meta[name="apple-mobile-web-app-title"]'
|
|
20313
|
+
);
|
|
20314
|
+
if (!appleTitleMeta) {
|
|
20315
|
+
appleTitleMeta = document.createElement("meta");
|
|
20316
|
+
appleTitleMeta.name = "apple-mobile-web-app-title";
|
|
20317
|
+
document.head.appendChild(appleTitleMeta);
|
|
20318
|
+
}
|
|
20319
|
+
appleTitleMeta.content = photonName;
|
|
20320
|
+
this._prewarmIconCache(photonName);
|
|
20321
|
+
this._log("info", `PWA manifest set for "${photonName}"`, true);
|
|
20322
|
+
}
|
|
20323
|
+
/**
|
|
20324
|
+
* Pre-warm the service worker icon cache by fetching the PNG icon URLs.
|
|
20325
|
+
* This ensures the rendered emoji icons are cached before the user
|
|
20326
|
+
* attempts to install the PWA, improving the install dialog appearance.
|
|
20327
|
+
*/
|
|
20328
|
+
_prewarmIconCache(photonName) {
|
|
20329
|
+
const sizes = [192, 512];
|
|
20330
|
+
sizes.forEach((size) => {
|
|
20331
|
+
const url2 = `/api/pwa/icon-png?photon=${encodeURIComponent(photonName)}&size=${size}`;
|
|
20332
|
+
fetch(url2, { mode: "no-cors" }).catch(() => {
|
|
20333
|
+
});
|
|
20334
|
+
});
|
|
20335
|
+
}
|
|
19391
20336
|
async _connectMCP() {
|
|
19392
20337
|
try {
|
|
19393
20338
|
mcpClient.on("connect", () => {
|
|
@@ -19415,12 +20360,24 @@ var BeamApp = class extends i4 {
|
|
|
19415
20360
|
}
|
|
19416
20361
|
this._initialConnectDone = true;
|
|
19417
20362
|
void this._checkForUpdates();
|
|
19418
|
-
if (window.location.
|
|
19419
|
-
void this.
|
|
20363
|
+
if (window.location.pathname !== "/") {
|
|
20364
|
+
void this._handleRouteChange();
|
|
19420
20365
|
} else if (!this._selectedPhoton && this._photons.length > 0) {
|
|
19421
20366
|
const firstUserPhoton = this._photons.find((p5) => !p5.internal);
|
|
19422
|
-
if (firstUserPhoton)
|
|
19423
|
-
|
|
20367
|
+
if (firstUserPhoton) {
|
|
20368
|
+
this._selectedPhoton = firstUserPhoton;
|
|
20369
|
+
if (firstUserPhoton.isApp && firstUserPhoton.appEntry) {
|
|
20370
|
+
if (this._willAutoInvoke(firstUserPhoton.appEntry)) {
|
|
20371
|
+
this._isExecuting = true;
|
|
20372
|
+
}
|
|
20373
|
+
this._selectedMethod = firstUserPhoton.appEntry;
|
|
20374
|
+
this._view = "form";
|
|
20375
|
+
this._maybeAutoInvoke(firstUserPhoton.appEntry);
|
|
20376
|
+
} else {
|
|
20377
|
+
this._view = "list";
|
|
20378
|
+
}
|
|
20379
|
+
}
|
|
20380
|
+
this._updateRoute(true);
|
|
19424
20381
|
}
|
|
19425
20382
|
})();
|
|
19426
20383
|
});
|
|
@@ -19439,15 +20396,37 @@ var BeamApp = class extends i4 {
|
|
|
19439
20396
|
this._photons = photons;
|
|
19440
20397
|
this._externalMCPs = externalMCPs;
|
|
19441
20398
|
this._addUnconfiguredPhotons();
|
|
19442
|
-
if (
|
|
19443
|
-
const
|
|
19444
|
-
|
|
19445
|
-
|
|
19446
|
-
|
|
19447
|
-
this.
|
|
19448
|
-
|
|
19449
|
-
|
|
19450
|
-
|
|
20399
|
+
if (this._selectedPhoton) {
|
|
20400
|
+
const updated = this._photons.find((p5) => p5.name === this._selectedPhoton?.name);
|
|
20401
|
+
if (updated) {
|
|
20402
|
+
const wasApp = this._selectedPhoton.isApp;
|
|
20403
|
+
this._selectedPhoton = updated;
|
|
20404
|
+
if (!wasApp && updated.isApp && updated.appEntry && this._view === "list") {
|
|
20405
|
+
if (this._willAutoInvoke(updated.appEntry)) {
|
|
20406
|
+
this._isExecuting = true;
|
|
20407
|
+
}
|
|
20408
|
+
this._selectedMethod = updated.appEntry;
|
|
20409
|
+
this._view = "form";
|
|
20410
|
+
this._updateRoute(true);
|
|
20411
|
+
this._maybeAutoInvoke(updated.appEntry);
|
|
20412
|
+
}
|
|
20413
|
+
}
|
|
20414
|
+
}
|
|
20415
|
+
if (!this._selectedPhoton && window.location.pathname !== "/") {
|
|
20416
|
+
const pathPhotonName = window.location.pathname.slice(1).split("/")[0];
|
|
20417
|
+
const routePhoton = pathPhotonName ? this._photons.find((p5) => p5.name === pathPhotonName) : null;
|
|
20418
|
+
if (routePhoton) {
|
|
20419
|
+
void this._handleRouteChange();
|
|
20420
|
+
} else {
|
|
20421
|
+
const newUserPhoton = this._photons.find(
|
|
20422
|
+
(p5) => !p5.internal && p5.configured && !prevNames.has(p5.name)
|
|
20423
|
+
);
|
|
20424
|
+
if (newUserPhoton) {
|
|
20425
|
+
this._selectedPhoton = newUserPhoton;
|
|
20426
|
+
this._welcomePhase = "welcome";
|
|
20427
|
+
this._view = "list";
|
|
20428
|
+
this._updateRoute(true);
|
|
20429
|
+
}
|
|
19451
20430
|
}
|
|
19452
20431
|
}
|
|
19453
20432
|
})();
|
|
@@ -19511,7 +20490,7 @@ var BeamApp = class extends i4 {
|
|
|
19511
20490
|
this._selectedPhoton = updated;
|
|
19512
20491
|
}
|
|
19513
20492
|
} else {
|
|
19514
|
-
if (window.location.
|
|
20493
|
+
if (window.location.pathname === "/") return;
|
|
19515
20494
|
const newUserPhoton = this._photons.find(
|
|
19516
20495
|
(p5) => !p5.internal && p5.configured && !prevNames.has(p5.name)
|
|
19517
20496
|
);
|
|
@@ -19540,7 +20519,7 @@ var BeamApp = class extends i4 {
|
|
|
19540
20519
|
} else {
|
|
19541
20520
|
this._view = "list";
|
|
19542
20521
|
}
|
|
19543
|
-
this.
|
|
20522
|
+
this._updateRoute(true);
|
|
19544
20523
|
}
|
|
19545
20524
|
}
|
|
19546
20525
|
}
|
|
@@ -19592,7 +20571,7 @@ var BeamApp = class extends i4 {
|
|
|
19592
20571
|
} else {
|
|
19593
20572
|
this._view = "list";
|
|
19594
20573
|
}
|
|
19595
|
-
this.
|
|
20574
|
+
this._updateRoute(true);
|
|
19596
20575
|
}
|
|
19597
20576
|
}
|
|
19598
20577
|
});
|
|
@@ -19703,20 +20682,27 @@ var BeamApp = class extends i4 {
|
|
|
19703
20682
|
}
|
|
19704
20683
|
}
|
|
19705
20684
|
}
|
|
19706
|
-
|
|
19707
|
-
let
|
|
20685
|
+
_updateRoute(replace2 = false) {
|
|
20686
|
+
let path;
|
|
19708
20687
|
if (!this._selectedPhoton) {
|
|
19709
|
-
|
|
20688
|
+
path = "/";
|
|
19710
20689
|
} else {
|
|
19711
|
-
|
|
20690
|
+
path = "/" + this._selectedPhoton.name;
|
|
19712
20691
|
if (this._selectedMethod) {
|
|
19713
|
-
|
|
20692
|
+
path += `/${this._selectedMethod.name}`;
|
|
20693
|
+
for (const panel of this._splitPanels) {
|
|
20694
|
+
if (panel.type === "method" && panel.method) {
|
|
20695
|
+
path += `+${panel.method.name}`;
|
|
20696
|
+
} else if (panel.type === "source") {
|
|
20697
|
+
path += `+source`;
|
|
20698
|
+
}
|
|
20699
|
+
}
|
|
19714
20700
|
}
|
|
19715
20701
|
}
|
|
19716
20702
|
if (replace2) {
|
|
19717
|
-
history.replaceState(null, "",
|
|
20703
|
+
history.replaceState(null, "", path);
|
|
19718
20704
|
} else {
|
|
19719
|
-
history.pushState(null, "",
|
|
20705
|
+
history.pushState(null, "", path);
|
|
19720
20706
|
}
|
|
19721
20707
|
}
|
|
19722
20708
|
/**
|
|
@@ -19767,6 +20753,21 @@ var BeamApp = class extends i4 {
|
|
|
19767
20753
|
if (!this._selectedPhoton?.methods) return [];
|
|
19768
20754
|
return this._selectedPhoton.methods.filter((m3) => m3.name.startsWith("test_") || m3.name.startsWith("test")).map((m3) => m3.name);
|
|
19769
20755
|
}
|
|
20756
|
+
/** Fetch all tests (external .test.ts + inline) from the server */
|
|
20757
|
+
async _fetchTestList(photonName) {
|
|
20758
|
+
try {
|
|
20759
|
+
const res = await fetch(`/api/test/list?photon=${encodeURIComponent(photonName)}`, {
|
|
20760
|
+
signal: AbortSignal.timeout(5e3)
|
|
20761
|
+
});
|
|
20762
|
+
if (!res.ok) return this._getTestMethods();
|
|
20763
|
+
const data = await res.json();
|
|
20764
|
+
if (data.tests && data.tests.length > 0) {
|
|
20765
|
+
return data.tests.map((t8) => t8.name);
|
|
20766
|
+
}
|
|
20767
|
+
} catch {
|
|
20768
|
+
}
|
|
20769
|
+
return this._getTestMethods();
|
|
20770
|
+
}
|
|
19770
20771
|
_getAllTestMethods() {
|
|
19771
20772
|
const results = [];
|
|
19772
20773
|
for (const p5 of this._photons) {
|
|
@@ -20090,7 +21091,7 @@ var BeamApp = class extends i4 {
|
|
|
20090
21091
|
}}
|
|
20091
21092
|
@diagnostics=${() => {
|
|
20092
21093
|
this._view = "diagnostics";
|
|
20093
|
-
this.
|
|
21094
|
+
this._updateRoute();
|
|
20094
21095
|
}}
|
|
20095
21096
|
@open-studio=${(e8) => {
|
|
20096
21097
|
const photon = this._photons.find((p5) => p5.name === e8.detail.photonName);
|
|
@@ -20110,7 +21111,39 @@ var BeamApp = class extends i4 {
|
|
|
20110
21111
|
></beam-sidebar>
|
|
20111
21112
|
</nav>
|
|
20112
21113
|
|
|
20113
|
-
<main
|
|
21114
|
+
<main
|
|
21115
|
+
class="main-area"
|
|
21116
|
+
id="main-content"
|
|
21117
|
+
tabindex="-1"
|
|
21118
|
+
aria-label="Main content"
|
|
21119
|
+
style="${this._splitViewEnabled ? "overflow: hidden !important;" : ""}"
|
|
21120
|
+
>
|
|
21121
|
+
${this._selectedPhoton && this._selectedMethod ? b2`<button
|
|
21122
|
+
class="beam-back-btn"
|
|
21123
|
+
@click=${() => this._handleBackFromMethod()}
|
|
21124
|
+
@mouseenter=${(e8) => {
|
|
21125
|
+
e8.target.style.color = "var(--t-primary)";
|
|
21126
|
+
e8.target.style.borderColor = "var(--accent-primary)";
|
|
21127
|
+
}}
|
|
21128
|
+
@mouseleave=${(e8) => {
|
|
21129
|
+
e8.target.style.color = "var(--t-muted)";
|
|
21130
|
+
e8.target.style.borderColor = "var(--border-glass)";
|
|
21131
|
+
}}
|
|
21132
|
+
title="Back to ${this._selectedPhoton.name}"
|
|
21133
|
+
>
|
|
21134
|
+
<svg
|
|
21135
|
+
width="16"
|
|
21136
|
+
height="16"
|
|
21137
|
+
viewBox="0 0 24 24"
|
|
21138
|
+
fill="none"
|
|
21139
|
+
stroke="currentColor"
|
|
21140
|
+
stroke-width="2"
|
|
21141
|
+
stroke-linecap="round"
|
|
21142
|
+
stroke-linejoin="round"
|
|
21143
|
+
>
|
|
21144
|
+
<path d="m15 18-6-6 6-6" />
|
|
21145
|
+
</svg>
|
|
21146
|
+
</button>` : ""}
|
|
20114
21147
|
${this._selectedPhoton ? b2`<button
|
|
20115
21148
|
class="beam-fullscreen-btn"
|
|
20116
21149
|
@click=${this._toggleFocusMode}
|
|
@@ -20546,7 +21579,7 @@ var BeamApp = class extends i4 {
|
|
|
20546
21579
|
}}
|
|
20547
21580
|
@click=${() => {
|
|
20548
21581
|
this._view = "diagnostics";
|
|
20549
|
-
this.
|
|
21582
|
+
this._updateRoute();
|
|
20550
21583
|
}}
|
|
20551
21584
|
>
|
|
20552
21585
|
<span style="font-size: 1rem; width: 20px; text-align: center;">🔍</span>
|
|
@@ -20755,7 +21788,7 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
20755
21788
|
@select=${(e8) => {
|
|
20756
21789
|
this._selectedMethod = e8.detail.method;
|
|
20757
21790
|
this._view = "form";
|
|
20758
|
-
this.
|
|
21791
|
+
this._updateRoute();
|
|
20759
21792
|
}}
|
|
20760
21793
|
></method-card>
|
|
20761
21794
|
`
|
|
@@ -20772,7 +21805,7 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
20772
21805
|
if (this._selectedMethod.linkedUi) {
|
|
20773
21806
|
const isAppMain = this._selectedPhoton.isApp && this._selectedMethod.name === "main";
|
|
20774
21807
|
const otherMethods = isAppMain ? this._getVisibleMethods().filter((m3) => m3.name !== "main") : [];
|
|
20775
|
-
const
|
|
21808
|
+
const isExternalMCP = this._selectedPhoton.isExternalMCP;
|
|
20776
21809
|
const appRenderer = this._isExecuting ? b2`
|
|
20777
21810
|
<div
|
|
20778
21811
|
style="display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; height: calc(100vh - 140px);"
|
|
@@ -20782,7 +21815,7 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
20782
21815
|
${this._progress?.message || "Starting up\u2026"}
|
|
20783
21816
|
</span>
|
|
20784
21817
|
</div>
|
|
20785
|
-
` :
|
|
21818
|
+
` : isExternalMCP ? b2`
|
|
20786
21819
|
<mcp-app-renderer
|
|
20787
21820
|
.mcpName=${this._selectedPhoton.name}
|
|
20788
21821
|
.appUri=${`ui://${this._selectedPhoton.name}/${this._selectedMethod.linkedUi}`}
|
|
@@ -20801,7 +21834,48 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
20801
21834
|
></custom-ui-renderer>
|
|
20802
21835
|
`;
|
|
20803
21836
|
if (isAppMain) {
|
|
21837
|
+
if (this._splitPanels.length > 0) {
|
|
21838
|
+
return b2`
|
|
21839
|
+
<div style="display: flex; gap: 1px; height: calc(100vh - 60px); overflow: hidden;">
|
|
21840
|
+
<!-- App Panel (primary) — no title bar, app has its own chrome -->
|
|
21841
|
+
<div style="flex: 1; min-height: 0; overflow: hidden;">${appRenderer}</div>
|
|
21842
|
+
|
|
21843
|
+
<!-- Additional Panels -->
|
|
21844
|
+
${this._splitPanels.map(
|
|
21845
|
+
(panel) => b2`
|
|
21846
|
+
<div style="flex: 1; min-height: 0; background: var(--bg-panel);">
|
|
21847
|
+
${panel.type === "method" ? this._renderSinglePanel(this._buildAdditionalPanelOpts(panel)) : this._renderSourcePanel(panel.id)}
|
|
21848
|
+
</div>
|
|
21849
|
+
`
|
|
21850
|
+
)}
|
|
21851
|
+
</div>
|
|
21852
|
+
`;
|
|
21853
|
+
}
|
|
20804
21854
|
return b2`
|
|
21855
|
+
<!-- Floating add-panel button for app view — sits next to focus button -->
|
|
21856
|
+
<div
|
|
21857
|
+
style="position: sticky; top: calc(-1 * var(--space-lg)); float: right; z-index: 100; margin-top: calc(-1 * var(--space-lg)); margin-right: 6px;"
|
|
21858
|
+
>
|
|
21859
|
+
<button
|
|
21860
|
+
@click=${() => {
|
|
21861
|
+
this._methodPickerOpen = !this._methodPickerOpen;
|
|
21862
|
+
this._methodPickerPanelId = null;
|
|
21863
|
+
}}
|
|
21864
|
+
style="width: 28px; height: 28px; border-radius: var(--radius-sm); background: var(--bg-glass); border: 1px solid var(--border-glass); color: var(--t-muted); cursor: pointer; font-size: 14px; font-weight: 700; display: flex; align-items: center; justify-content: center; transition: all 0.2s ease; backdrop-filter: blur(8px);"
|
|
21865
|
+
@mouseenter=${(e8) => {
|
|
21866
|
+
e8.target.style.color = "var(--accent-secondary)";
|
|
21867
|
+
e8.target.style.borderColor = "var(--accent-secondary)";
|
|
21868
|
+
}}
|
|
21869
|
+
@mouseleave=${(e8) => {
|
|
21870
|
+
e8.target.style.color = "var(--t-muted)";
|
|
21871
|
+
e8.target.style.borderColor = "var(--border-glass)";
|
|
21872
|
+
}}
|
|
21873
|
+
title="Add panel"
|
|
21874
|
+
>
|
|
21875
|
+
+
|
|
21876
|
+
</button>
|
|
21877
|
+
${this._methodPickerOpen && this._methodPickerPanelId === null ? this._renderMethodPickerPopover() : ""}
|
|
21878
|
+
</div>
|
|
20805
21879
|
<app-layout
|
|
20806
21880
|
.photonName=${this._selectedPhoton.name}
|
|
20807
21881
|
.photonIcon=${this._selectedPhoton.appEntry?.icon || "\u{1F4F1}"}
|
|
@@ -20844,61 +21918,72 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
20844
21918
|
</app-layout>
|
|
20845
21919
|
`;
|
|
20846
21920
|
}
|
|
21921
|
+
if (this._splitPanels.length > 0) {
|
|
21922
|
+
return b2`
|
|
21923
|
+
<div style="display: flex; gap: 1px; height: calc(100vh - 60px); overflow: hidden;">
|
|
21924
|
+
<!-- Linked UI Panel (primary) -->
|
|
21925
|
+
<div
|
|
21926
|
+
style="flex: 1; min-height: 0; display: flex; flex-direction: column; position: relative;"
|
|
21927
|
+
>
|
|
21928
|
+
<div
|
|
21929
|
+
style="display: flex; align-items: center; justify-content: space-between; padding: 8px 12px; border-bottom: 1px solid var(--border-glass); background: var(--bg-glass); flex-shrink: 0;"
|
|
21930
|
+
>
|
|
21931
|
+
<span style="font-size: 12px; font-weight: 500; color: var(--t-primary);"
|
|
21932
|
+
>${this._selectedMethod.name}</span
|
|
21933
|
+
>
|
|
21934
|
+
<div style="position: relative; flex-shrink: 0;">
|
|
21935
|
+
<button
|
|
21936
|
+
@click=${() => {
|
|
21937
|
+
this._methodPickerOpen = !this._methodPickerOpen;
|
|
21938
|
+
this._methodPickerPanelId = null;
|
|
21939
|
+
}}
|
|
21940
|
+
style="padding: 4px 8px; background: none; color: var(--accent-secondary); border: 1px solid var(--accent-secondary); border-radius: 3px; cursor: pointer; font-size: 14px; font-weight: 700; transition: all 0.2s ease;"
|
|
21941
|
+
title="Add panel"
|
|
21942
|
+
>
|
|
21943
|
+
+
|
|
21944
|
+
</button>
|
|
21945
|
+
${this._methodPickerOpen && this._methodPickerPanelId === null ? this._renderMethodPickerPopover() : ""}
|
|
21946
|
+
</div>
|
|
21947
|
+
</div>
|
|
21948
|
+
<div style="flex: 1; min-height: 0; overflow: hidden;">${appRenderer}</div>
|
|
21949
|
+
</div>
|
|
21950
|
+
|
|
21951
|
+
<!-- Additional Panels -->
|
|
21952
|
+
${this._splitPanels.map(
|
|
21953
|
+
(panel) => b2`
|
|
21954
|
+
<div style="flex: 1; min-height: 0; background: var(--bg-panel);">
|
|
21955
|
+
${panel.type === "method" ? this._renderSinglePanel(this._buildAdditionalPanelOpts(panel)) : this._renderSourcePanel(panel.id)}
|
|
21956
|
+
</div>
|
|
21957
|
+
`
|
|
21958
|
+
)}
|
|
21959
|
+
</div>
|
|
21960
|
+
`;
|
|
21961
|
+
}
|
|
20847
21962
|
return b2`
|
|
20848
|
-
<
|
|
20849
|
-
|
|
20850
|
-
|
|
20851
|
-
|
|
20852
|
-
|
|
20853
|
-
|
|
20854
|
-
|
|
20855
|
-
|
|
20856
|
-
|
|
20857
|
-
|
|
20858
|
-
|
|
20859
|
-
|
|
20860
|
-
|
|
20861
|
-
|
|
20862
|
-
|
|
20863
|
-
|
|
20864
|
-
|
|
20865
|
-
|
|
20866
|
-
|
|
20867
|
-
|
|
20868
|
-
style="padding: 0; overflow: hidden; min-height: calc(100vh - 80px); margin-top: var(--space-md);"
|
|
20869
|
-
>
|
|
20870
|
-
${appRenderer}
|
|
21963
|
+
<div style="position: relative;">
|
|
21964
|
+
<div style="position: absolute; top: 16px; right: 16px; z-index: 50;">
|
|
21965
|
+
<button
|
|
21966
|
+
@click=${() => {
|
|
21967
|
+
this._methodPickerOpen = !this._methodPickerOpen;
|
|
21968
|
+
this._methodPickerPanelId = null;
|
|
21969
|
+
}}
|
|
21970
|
+
style="padding: 4px 8px; background: var(--bg-glass); color: var(--accent-secondary); border: 1px solid var(--accent-secondary); border-radius: 3px; cursor: pointer; font-size: 14px; font-weight: 700; transition: all 0.2s ease; backdrop-filter: blur(8px);"
|
|
21971
|
+
title="Add panel"
|
|
21972
|
+
>
|
|
21973
|
+
+
|
|
21974
|
+
</button>
|
|
21975
|
+
${this._methodPickerOpen && this._methodPickerPanelId === null ? this._renderMethodPickerPopover() : ""}
|
|
21976
|
+
</div>
|
|
21977
|
+
<div
|
|
21978
|
+
class="glass-panel"
|
|
21979
|
+
style="padding: 0; overflow: hidden; min-height: calc(100vh - 80px); margin-top: var(--space-md);"
|
|
21980
|
+
>
|
|
21981
|
+
${appRenderer}
|
|
21982
|
+
</div>
|
|
20871
21983
|
</div>
|
|
20872
21984
|
`;
|
|
20873
21985
|
}
|
|
20874
|
-
|
|
20875
|
-
return b2`
|
|
20876
|
-
<context-bar
|
|
20877
|
-
.photon=${this._selectedPhoton}
|
|
20878
|
-
.breadcrumbs=${[
|
|
20879
|
-
{
|
|
20880
|
-
label: this._currentInstance !== "default" ? `${this._selectedPhoton.name}:${this._currentInstance}` : this._selectedPhoton.name,
|
|
20881
|
-
action: "back"
|
|
20882
|
-
},
|
|
20883
|
-
{ label: this._selectedMethod.name }
|
|
20884
|
-
]}
|
|
20885
|
-
.live=${this._currentCollectionName !== null}
|
|
20886
|
-
.showEdit=${false}
|
|
20887
|
-
.showConfigure=${false}
|
|
20888
|
-
.showCopyConfig=${false}
|
|
20889
|
-
.overflowItems=${this._buildOverflowItems({
|
|
20890
|
-
showRefresh: !isExternalMCP,
|
|
20891
|
-
showRename: false,
|
|
20892
|
-
showViewSource: false,
|
|
20893
|
-
showDelete: false,
|
|
20894
|
-
showHelp: !isExternalMCP
|
|
20895
|
-
})}
|
|
20896
|
-
.instanceSelectorMode=${this._instanceSelectorMode}
|
|
20897
|
-
.autoInstance=${this._autoInstance}
|
|
20898
|
-
@context-action=${this._handleContextAction}
|
|
20899
|
-
></context-bar>
|
|
20900
|
-
${this._renderMethodContent()}
|
|
20901
|
-
`;
|
|
21986
|
+
return b2` ${this._renderMethodContent()} `;
|
|
20902
21987
|
}
|
|
20903
21988
|
return b2`
|
|
20904
21989
|
${this._renderPhotonToolbar()} ${this._editingIcon ? this._renderEmojiPicker() : ""}
|
|
@@ -21026,6 +22111,7 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
21026
22111
|
}
|
|
21027
22112
|
}
|
|
21028
22113
|
async _handlePhotonSelect(e8) {
|
|
22114
|
+
this._closeSecondPanel();
|
|
21029
22115
|
this._selectedPhoton = e8.detail.photon;
|
|
21030
22116
|
this._selectedMethod = null;
|
|
21031
22117
|
this._lastResult = null;
|
|
@@ -21033,12 +22119,12 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
21033
22119
|
this._currentInstance = "default";
|
|
21034
22120
|
if (this._selectedPhoton.configured === false) {
|
|
21035
22121
|
this._view = "config";
|
|
21036
|
-
this.
|
|
22122
|
+
this._updateRoute();
|
|
21037
22123
|
return;
|
|
21038
22124
|
}
|
|
21039
22125
|
if (this._selectedPhoton.isExternalMCP && this._selectedPhoton.hasMcpApp) {
|
|
21040
22126
|
this._view = "mcp-app";
|
|
21041
|
-
this.
|
|
22127
|
+
this._updateRoute();
|
|
21042
22128
|
return;
|
|
21043
22129
|
}
|
|
21044
22130
|
if (this._selectedPhoton.stateful && this._selectedPhoton.configured) {
|
|
@@ -21065,13 +22151,13 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
21065
22151
|
}
|
|
21066
22152
|
this._selectedMethod = this._selectedPhoton.appEntry;
|
|
21067
22153
|
this._view = "form";
|
|
21068
|
-
this.
|
|
22154
|
+
this._updateRoute();
|
|
21069
22155
|
this._maybeAutoInvoke(this._selectedPhoton.appEntry);
|
|
21070
22156
|
return;
|
|
21071
22157
|
} else {
|
|
21072
22158
|
this._view = "list";
|
|
21073
22159
|
}
|
|
21074
|
-
this.
|
|
22160
|
+
this._updateRoute();
|
|
21075
22161
|
}
|
|
21076
22162
|
/** Fetch available instances for a stateful photon from the server */
|
|
21077
22163
|
async _fetchInstances(photonName) {
|
|
@@ -21114,7 +22200,7 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
21114
22200
|
/**
|
|
21115
22201
|
* Trigger instance switch via MCP elicitation (calls _use without name).
|
|
21116
22202
|
* The transport layer shows an elicitation modal with available instances.
|
|
21117
|
-
* After _use succeeds, the transport broadcasts
|
|
22203
|
+
* After _use succeeds, the transport broadcasts state-changed which
|
|
21118
22204
|
* triggers _silentRefresh() to update the result and notifies custom UIs.
|
|
21119
22205
|
*/
|
|
21120
22206
|
async _switchInstance() {
|
|
@@ -21150,7 +22236,7 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
21150
22236
|
this._selectedMethod = e8.detail.method;
|
|
21151
22237
|
this._lastResult = null;
|
|
21152
22238
|
this._view = "form";
|
|
21153
|
-
this.
|
|
22239
|
+
this._updateRoute();
|
|
21154
22240
|
this._maybeAutoInvoke(e8.detail.method);
|
|
21155
22241
|
}
|
|
21156
22242
|
/**
|
|
@@ -21212,57 +22298,507 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
21212
22298
|
</div>
|
|
21213
22299
|
`;
|
|
21214
22300
|
}
|
|
22301
|
+
if (this._splitPanels.length > 0) {
|
|
22302
|
+
return b2`
|
|
22303
|
+
<div style="display: flex; gap: 1px; height: 100%; overflow: hidden;">
|
|
22304
|
+
<!-- Primary Panel -->
|
|
22305
|
+
<div style="flex: 1; min-height: 0; background: var(--bg-panel);">
|
|
22306
|
+
${this._renderSinglePanel({
|
|
22307
|
+
photon: this._selectedPhoton,
|
|
22308
|
+
method: this._selectedMethod,
|
|
22309
|
+
result: this._lastResult,
|
|
22310
|
+
executing: this._isExecuting,
|
|
22311
|
+
progress: this._progress,
|
|
22312
|
+
formParams: this._lastFormParams,
|
|
22313
|
+
onSubmit: (e8) => void this._handleExecute(e8),
|
|
22314
|
+
onCancel: () => this._handleBackFromMethod(),
|
|
22315
|
+
panelLabel: "Primary",
|
|
22316
|
+
instance: this._currentInstance,
|
|
22317
|
+
instances: this._instances,
|
|
22318
|
+
onInstanceChange: (instance) => this._handleLeftPanelInstanceChange(instance),
|
|
22319
|
+
allMethods: this._selectedPhoton?.methods || [],
|
|
22320
|
+
onMethodChange: (method) => this._handleLeftPanelMethodChange(method),
|
|
22321
|
+
panelSide: "primary",
|
|
22322
|
+
onPanelAction: (action) => this._handlePrimaryPanelAction(action),
|
|
22323
|
+
onInstanceAction: (detail) => void this._handleInstanceAction(detail),
|
|
22324
|
+
isStateful: !!this._selectedPhoton?.stateful,
|
|
22325
|
+
isLive: this._currentCollectionName !== null,
|
|
22326
|
+
overflowItems: this._buildOverflowItems({
|
|
22327
|
+
showRefresh: !this._selectedPhoton?.isExternalMCP,
|
|
22328
|
+
showRename: false,
|
|
22329
|
+
showViewSource: false,
|
|
22330
|
+
showDelete: false,
|
|
22331
|
+
showHelp: !this._selectedPhoton?.isExternalMCP
|
|
22332
|
+
}),
|
|
22333
|
+
onOverflowSelect: (id2) => this._handleOverflowAction(id2)
|
|
22334
|
+
})}
|
|
22335
|
+
</div>
|
|
22336
|
+
|
|
22337
|
+
<!-- Additional Panels -->
|
|
22338
|
+
${this._splitPanels.map(
|
|
22339
|
+
(panel) => b2`
|
|
22340
|
+
<div style="flex: 1; min-height: 0; background: var(--bg-panel);">
|
|
22341
|
+
${panel.type === "method" ? this._renderSinglePanel(this._buildAdditionalPanelOpts(panel)) : this._renderSourcePanel(panel.id)}
|
|
22342
|
+
</div>
|
|
22343
|
+
`
|
|
22344
|
+
)}
|
|
22345
|
+
</div>
|
|
22346
|
+
`;
|
|
22347
|
+
}
|
|
22348
|
+
return this._renderSinglePanel({
|
|
22349
|
+
photon: this._selectedPhoton,
|
|
22350
|
+
method: this._selectedMethod,
|
|
22351
|
+
result: this._lastResult,
|
|
22352
|
+
executing: this._isExecuting,
|
|
22353
|
+
progress: this._progress,
|
|
22354
|
+
formParams: this._lastFormParams,
|
|
22355
|
+
onSubmit: (e8) => void this._handleExecute(e8),
|
|
22356
|
+
onCancel: () => this._handleBackFromMethod(),
|
|
22357
|
+
panelLabel: "Primary",
|
|
22358
|
+
instance: this._currentInstance,
|
|
22359
|
+
instances: this._instances,
|
|
22360
|
+
allMethods: this._selectedPhoton?.methods || [],
|
|
22361
|
+
onMethodChange: (method) => {
|
|
22362
|
+
this._selectedMethod = method;
|
|
22363
|
+
this._lastResult = null;
|
|
22364
|
+
this._lastFormParams = {};
|
|
22365
|
+
if (this._willAutoInvoke(method)) {
|
|
22366
|
+
void this._handleExecute(new CustomEvent("execute", { detail: { args: {} } }));
|
|
22367
|
+
}
|
|
22368
|
+
this._updateRoute();
|
|
22369
|
+
},
|
|
22370
|
+
panelSide: "primary",
|
|
22371
|
+
onPanelAction: (action) => this._handlePrimaryPanelAction(action),
|
|
22372
|
+
onInstanceAction: (detail) => void this._handleInstanceAction(detail),
|
|
22373
|
+
isStateful: !!this._selectedPhoton?.stateful,
|
|
22374
|
+
isLive: this._currentCollectionName !== null,
|
|
22375
|
+
overflowItems: this._buildOverflowItems({
|
|
22376
|
+
showRefresh: !this._selectedPhoton?.isExternalMCP,
|
|
22377
|
+
showRename: false,
|
|
22378
|
+
showViewSource: false,
|
|
22379
|
+
showDelete: false,
|
|
22380
|
+
showHelp: !this._selectedPhoton?.isExternalMCP
|
|
22381
|
+
}),
|
|
22382
|
+
onOverflowSelect: (id2) => this._handleOverflowAction(id2)
|
|
22383
|
+
});
|
|
22384
|
+
}
|
|
22385
|
+
/** Render a single panel with self-contained header */
|
|
22386
|
+
_renderSinglePanel(opts) {
|
|
22387
|
+
const isSplit = this._splitPanels.length > 0;
|
|
21215
22388
|
return b2`
|
|
21216
|
-
<div
|
|
21217
|
-
|
|
21218
|
-
${
|
|
21219
|
-
|
|
21220
|
-
|
|
21221
|
-
|
|
21222
|
-
|
|
21223
|
-
|
|
21224
|
-
|
|
21225
|
-
|
|
21226
|
-
|
|
21227
|
-
|
|
22389
|
+
<div
|
|
22390
|
+
class="glass-panel method-detail"
|
|
22391
|
+
style="${isSplit ? "border-radius: 0; height: 100%;" : ""} display: flex; flex-direction: column;"
|
|
22392
|
+
>
|
|
22393
|
+
<!-- Panel Header: LED + Method ▼ + instance-panel + [+] + [⋯] + [×] -->
|
|
22394
|
+
<div
|
|
22395
|
+
style="display: flex; align-items: center; gap: 8px; padding-bottom: 12px; margin-bottom: 12px; border-bottom: 1px solid var(--border-glass); flex-shrink: 0; position: relative;"
|
|
22396
|
+
>
|
|
22397
|
+
<!-- LED dot (stateful/live indicator) -->
|
|
22398
|
+
${opts.isStateful ? b2`<span
|
|
22399
|
+
style="width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; background: ${opts.isLive ? "var(--color-success, #22c55e)" : "var(--t-tertiary, #666)"}; box-shadow: ${opts.isLive ? "0 0 6px var(--color-success, #22c55e)" : "none"};"
|
|
22400
|
+
title="${opts.isLive ? "Live \u2014 stateful photon with active subscription" : "Stateful photon"}"
|
|
22401
|
+
></span>` : ""}
|
|
22402
|
+
|
|
22403
|
+
<!-- Method Selector (name as dropdown) -->
|
|
22404
|
+
<select
|
|
22405
|
+
.value=${opts.method.name}
|
|
22406
|
+
@change=${(e8) => {
|
|
22407
|
+
const methodName = e8.target.value;
|
|
22408
|
+
const method = opts.allMethods?.find((m3) => m3.name === methodName);
|
|
22409
|
+
if (method && opts.onMethodChange) {
|
|
22410
|
+
opts.onMethodChange(method);
|
|
22411
|
+
}
|
|
21228
22412
|
}}
|
|
21229
|
-
|
|
21230
|
-
|
|
22413
|
+
style="padding: 6px 8px; border-radius: 4px; border: 1px solid var(--border-glass); background: var(--bg-glass); color: var(--t-primary); font-size: 13px; font-weight: 600; flex-shrink: 0;"
|
|
22414
|
+
>
|
|
22415
|
+
${opts.allMethods?.map(
|
|
22416
|
+
(m3) => b2`<option .selected=${m3.name === opts.method.name} value=${m3.name}>
|
|
22417
|
+
${m3.name}
|
|
22418
|
+
</option>`
|
|
22419
|
+
) || b2`<option value=${opts.method.name}>${opts.method.name}</option>`}
|
|
22420
|
+
</select>
|
|
21231
22421
|
|
|
21232
|
-
|
|
21233
|
-
|
|
21234
|
-
|
|
21235
|
-
|
|
21236
|
-
|
|
21237
|
-
|
|
21238
|
-
|
|
22422
|
+
<div style="flex: 1;"></div>
|
|
22423
|
+
|
|
22424
|
+
<!-- Rich Instance Selector -->
|
|
22425
|
+
${opts.isStateful && opts.instances && opts.instances.length > 0 && opts.onInstanceAction ? b2`
|
|
22426
|
+
<instance-panel
|
|
22427
|
+
.instanceName=${opts.instance || "default"}
|
|
22428
|
+
.instances=${opts.instances}
|
|
22429
|
+
.photonName=${opts.photon.name}
|
|
22430
|
+
.selectorMode=${this._instanceSelectorMode}
|
|
22431
|
+
.autoInstance=${this._autoInstance}
|
|
22432
|
+
@instance-action=${(e8) => opts.onInstanceAction?.(e8.detail)}
|
|
22433
|
+
></instance-panel>
|
|
22434
|
+
` : ""}
|
|
22435
|
+
|
|
22436
|
+
<!-- Add panel button (primary only) -->
|
|
22437
|
+
${opts.panelSide === "primary" ? b2`
|
|
22438
|
+
<div style="position: relative; flex-shrink: 0;">
|
|
22439
|
+
<button
|
|
22440
|
+
@click=${() => opts.onPanelAction?.("toggle-picker")}
|
|
22441
|
+
style="padding: 4px 8px; background: none; color: var(--accent-secondary); border: 1px solid var(--accent-secondary); border-radius: 3px; cursor: pointer; font-size: 14px; font-weight: 700; transition: all 0.2s ease;"
|
|
22442
|
+
title="Add panel"
|
|
22443
|
+
>
|
|
22444
|
+
+
|
|
22445
|
+
</button>
|
|
22446
|
+
${this._methodPickerOpen && this._methodPickerPanelId === null ? this._renderMethodPickerPopover() : ""}
|
|
21239
22447
|
</div>
|
|
21240
|
-
|
|
21241
|
-
|
|
21242
|
-
|
|
21243
|
-
|
|
21244
|
-
|
|
21245
|
-
|
|
21246
|
-
|
|
22448
|
+
` : ""}
|
|
22449
|
+
|
|
22450
|
+
<!-- Overflow menu -->
|
|
22451
|
+
${opts.overflowItems && opts.overflowItems.length > 0 ? b2`
|
|
22452
|
+
<overflow-menu
|
|
22453
|
+
.items=${opts.overflowItems}
|
|
22454
|
+
@menu-select=${(e8) => opts.onOverflowSelect?.(e8.detail.id)}
|
|
22455
|
+
></overflow-menu>
|
|
22456
|
+
` : ""}
|
|
22457
|
+
|
|
22458
|
+
<!-- Close button (additional panels only) -->
|
|
22459
|
+
${opts.panelSide === "additional" ? b2`
|
|
22460
|
+
<button
|
|
22461
|
+
@click=${() => opts.onPanelAction?.("close")}
|
|
22462
|
+
style="padding: 4px 8px; background: none; color: var(--color-error); border: 1px solid var(--color-error); border-radius: 3px; cursor: pointer; font-size: 14px; font-weight: 700; flex-shrink: 0; transition: all 0.2s ease;"
|
|
22463
|
+
title="Close panel"
|
|
22464
|
+
>
|
|
22465
|
+
×
|
|
22466
|
+
</button>
|
|
22467
|
+
` : ""}
|
|
22468
|
+
</div>
|
|
22469
|
+
<!-- Panel Content (scrollable) -->
|
|
22470
|
+
<div
|
|
22471
|
+
style="display: flex; flex-direction: column; flex: 1; min-height: 0; overflow-y: auto;"
|
|
22472
|
+
>
|
|
22473
|
+
${this._renderDescription(opts.method.description)}
|
|
22474
|
+
<invoke-form
|
|
22475
|
+
.params=${opts.method.params}
|
|
22476
|
+
.loading=${opts.executing}
|
|
22477
|
+
.photonName=${opts.photon.name}
|
|
22478
|
+
.methodName=${opts.method.name}
|
|
22479
|
+
.rememberValues=${this._rememberFormValues}
|
|
22480
|
+
.sharedValues=${opts.formParams}
|
|
22481
|
+
@submit=${opts.onSubmit}
|
|
22482
|
+
@cancel=${opts.onCancel}
|
|
22483
|
+
></invoke-form>
|
|
22484
|
+
|
|
22485
|
+
${opts.progress ? b2`
|
|
22486
|
+
<div class="progress-container">
|
|
22487
|
+
<div class="progress-bar-wrapper">
|
|
22488
|
+
<div
|
|
22489
|
+
class="progress-bar ${opts.progress.value < 0 ? "indeterminate" : ""}"
|
|
22490
|
+
style="width: ${opts.progress.value < 0 ? "30%" : Math.round(opts.progress.value * 100) + "%"}"
|
|
22491
|
+
></div>
|
|
22492
|
+
</div>
|
|
22493
|
+
<div class="progress-text">
|
|
22494
|
+
<span>${opts.progress.message}</span>
|
|
22495
|
+
</div>
|
|
22496
|
+
</div>
|
|
22497
|
+
` : ""}
|
|
22498
|
+
${opts.result !== null ? b2`
|
|
22499
|
+
<result-viewer
|
|
22500
|
+
.result=${opts.result}
|
|
22501
|
+
.outputFormat=${opts.method?.outputFormat}
|
|
22502
|
+
.layoutHints=${opts.method?.layoutHints}
|
|
22503
|
+
.theme=${this._theme}
|
|
22504
|
+
.live=${this._currentCollectionName !== null}
|
|
22505
|
+
.resultKey=${opts.photon && opts.method ? `${opts.photon.name}/${opts.method.name}` : void 0}
|
|
22506
|
+
@share=${() => this._handleShareResult()}
|
|
22507
|
+
></result-viewer>
|
|
22508
|
+
` : b2`
|
|
22509
|
+
<div class="empty-state-inline result-empty">
|
|
22510
|
+
<span class="empty-state-icon">${play}</span>
|
|
22511
|
+
<span>Run the method to see results here</span>
|
|
21247
22512
|
</div>
|
|
22513
|
+
`}
|
|
22514
|
+
</div>
|
|
22515
|
+
</div>
|
|
22516
|
+
`;
|
|
22517
|
+
}
|
|
22518
|
+
/** Close all split panels and return to single-panel mode */
|
|
22519
|
+
_closeSecondPanel() {
|
|
22520
|
+
this._splitPanels = [];
|
|
22521
|
+
this._methodPickerOpen = false;
|
|
22522
|
+
this._methodPickerPanelId = null;
|
|
22523
|
+
this._updateRoute();
|
|
22524
|
+
}
|
|
22525
|
+
/** Handle instance change for primary panel */
|
|
22526
|
+
_handleLeftPanelInstanceChange(instance) {
|
|
22527
|
+
this._currentInstance = instance;
|
|
22528
|
+
sessionStorage.setItem(`photon-instance:${this._selectedPhoton.name}`, instance);
|
|
22529
|
+
this._lastResult = null;
|
|
22530
|
+
}
|
|
22531
|
+
/** Add a new split panel */
|
|
22532
|
+
_addPanel(type, method) {
|
|
22533
|
+
if (this._splitPanels.length >= 2) return;
|
|
22534
|
+
const panel = {
|
|
22535
|
+
id: `panel-${++this._nextPanelId}`,
|
|
22536
|
+
type,
|
|
22537
|
+
method,
|
|
22538
|
+
result: null,
|
|
22539
|
+
executing: false,
|
|
22540
|
+
progress: null,
|
|
22541
|
+
formParams: {},
|
|
22542
|
+
instance: this._currentInstance || "default"
|
|
22543
|
+
};
|
|
22544
|
+
this._splitPanels = [...this._splitPanels, panel];
|
|
22545
|
+
if (type === "method" && method && this._willAutoInvoke(method)) {
|
|
22546
|
+
void this._executePanelMethod(panel.id, {});
|
|
22547
|
+
}
|
|
22548
|
+
this._methodPickerOpen = false;
|
|
22549
|
+
this._methodPickerPanelId = null;
|
|
22550
|
+
this._cleanupPickerDismiss();
|
|
22551
|
+
this._updateRoute();
|
|
22552
|
+
}
|
|
22553
|
+
/** Remove a split panel by id */
|
|
22554
|
+
_removePanel(panelId) {
|
|
22555
|
+
this._splitPanels = this._splitPanels.filter((p5) => p5.id !== panelId);
|
|
22556
|
+
this._updateRoute();
|
|
22557
|
+
}
|
|
22558
|
+
/** Update a split panel's state */
|
|
22559
|
+
_updatePanel(panelId, updates) {
|
|
22560
|
+
this._splitPanels = this._splitPanels.map((p5) => p5.id === panelId ? { ...p5, ...updates } : p5);
|
|
22561
|
+
}
|
|
22562
|
+
/** Execute a method in a split panel */
|
|
22563
|
+
async _executePanelMethod(panelId, args) {
|
|
22564
|
+
const panel = this._splitPanels.find((p5) => p5.id === panelId);
|
|
22565
|
+
if (!panel || panel.type !== "method" || !panel.method) return;
|
|
22566
|
+
this._updatePanel(panelId, { executing: true, result: null, progress: null, formParams: args });
|
|
22567
|
+
try {
|
|
22568
|
+
const toolName = `${this._selectedPhoton.name}/${panel.method.name}`;
|
|
22569
|
+
const result = await mcpClient.callTool(
|
|
22570
|
+
toolName,
|
|
22571
|
+
args,
|
|
22572
|
+
void 0,
|
|
22573
|
+
panel.instance || this._currentInstance,
|
|
22574
|
+
(progress) => {
|
|
22575
|
+
this._updatePanel(panelId, { progress });
|
|
22576
|
+
}
|
|
22577
|
+
);
|
|
22578
|
+
this._updatePanel(panelId, {
|
|
22579
|
+
result: mcpClient.parseToolResult(result),
|
|
22580
|
+
executing: false,
|
|
22581
|
+
progress: null
|
|
22582
|
+
});
|
|
22583
|
+
} catch (error2) {
|
|
22584
|
+
showToast(`Error: ${error2.message}`, { type: "error" });
|
|
22585
|
+
this._updatePanel(panelId, {
|
|
22586
|
+
result: { error: error2.message },
|
|
22587
|
+
executing: false,
|
|
22588
|
+
progress: null
|
|
22589
|
+
});
|
|
22590
|
+
}
|
|
22591
|
+
}
|
|
22592
|
+
/** Change the method in a split panel */
|
|
22593
|
+
_changePanelMethod(panelId, method) {
|
|
22594
|
+
this._updatePanel(panelId, { method, result: null, formParams: {} });
|
|
22595
|
+
if (this._willAutoInvoke(method)) {
|
|
22596
|
+
void this._executePanelMethod(panelId, {});
|
|
22597
|
+
}
|
|
22598
|
+
this._updateRoute();
|
|
22599
|
+
}
|
|
22600
|
+
/** Change the instance in a split panel */
|
|
22601
|
+
_changePanelInstance(panelId, instance) {
|
|
22602
|
+
this._updatePanel(panelId, { instance, result: null });
|
|
22603
|
+
}
|
|
22604
|
+
/** Open a method in a new split panel (backwards-compatible entry point) */
|
|
22605
|
+
_openInSecondPanel(photon, method) {
|
|
22606
|
+
this._addPanel("method", method);
|
|
22607
|
+
}
|
|
22608
|
+
/** Show method picker popover */
|
|
22609
|
+
_showMethodPicker() {
|
|
22610
|
+
this._methodPickerOpen = !this._methodPickerOpen;
|
|
22611
|
+
this._methodPickerPanelId = null;
|
|
22612
|
+
}
|
|
22613
|
+
/** Clean up picker dismiss listener */
|
|
22614
|
+
_cleanupPickerDismiss() {
|
|
22615
|
+
if (this._pickerDismissHandler) {
|
|
22616
|
+
window.removeEventListener("mousedown", this._pickerDismissHandler, true);
|
|
22617
|
+
this._pickerDismissHandler = null;
|
|
22618
|
+
}
|
|
22619
|
+
}
|
|
22620
|
+
/** Handle method change in primary panel */
|
|
22621
|
+
_handleLeftPanelMethodChange(method) {
|
|
22622
|
+
this._selectedMethod = method;
|
|
22623
|
+
this._lastResult = null;
|
|
22624
|
+
this._lastFormParams = {};
|
|
22625
|
+
this._updateRoute();
|
|
22626
|
+
}
|
|
22627
|
+
/** Handle panel action for primary panel */
|
|
22628
|
+
_handlePrimaryPanelAction(action) {
|
|
22629
|
+
if (action === "toggle-picker") {
|
|
22630
|
+
this._methodPickerOpen = !this._methodPickerOpen;
|
|
22631
|
+
this._methodPickerPanelId = null;
|
|
22632
|
+
}
|
|
22633
|
+
}
|
|
22634
|
+
/** Build opts for an additional (non-primary) split panel */
|
|
22635
|
+
_buildAdditionalPanelOpts(panel) {
|
|
22636
|
+
return {
|
|
22637
|
+
photon: this._selectedPhoton,
|
|
22638
|
+
method: panel.method,
|
|
22639
|
+
result: panel.result,
|
|
22640
|
+
executing: panel.executing || false,
|
|
22641
|
+
progress: panel.progress,
|
|
22642
|
+
formParams: panel.formParams || {},
|
|
22643
|
+
onSubmit: (e8) => {
|
|
22644
|
+
const args = e8.detail?.args || {};
|
|
22645
|
+
void this._executePanelMethod(panel.id, args);
|
|
22646
|
+
},
|
|
22647
|
+
onCancel: () => this._removePanel(panel.id),
|
|
22648
|
+
panelLabel: panel.id,
|
|
22649
|
+
instance: panel.instance,
|
|
22650
|
+
instances: this._instances,
|
|
22651
|
+
onInstanceChange: (inst) => this._changePanelInstance(panel.id, inst),
|
|
22652
|
+
allMethods: this._selectedPhoton?.methods || [],
|
|
22653
|
+
onMethodChange: (m3) => this._changePanelMethod(panel.id, m3),
|
|
22654
|
+
panelSide: "additional",
|
|
22655
|
+
onPanelAction: (action) => {
|
|
22656
|
+
if (action === "close") this._removePanel(panel.id);
|
|
22657
|
+
},
|
|
22658
|
+
onInstanceAction: (detail) => {
|
|
22659
|
+
if (detail.action === "switch") {
|
|
22660
|
+
this._changePanelInstance(panel.id, detail.instance);
|
|
22661
|
+
}
|
|
22662
|
+
},
|
|
22663
|
+
isStateful: !!this._selectedPhoton?.stateful,
|
|
22664
|
+
isLive: this._currentCollectionName !== null,
|
|
22665
|
+
overflowItems: this._buildOverflowItems({
|
|
22666
|
+
showRefresh: false,
|
|
22667
|
+
showRename: false,
|
|
22668
|
+
showViewSource: false,
|
|
22669
|
+
showDelete: false,
|
|
22670
|
+
showHelp: false,
|
|
22671
|
+
showRunTests: false
|
|
22672
|
+
}),
|
|
22673
|
+
onOverflowSelect: (id2) => this._handleOverflowAction(id2)
|
|
22674
|
+
};
|
|
22675
|
+
}
|
|
22676
|
+
/** Handle overflow menu actions from panel headers */
|
|
22677
|
+
_handleOverflowAction(id2) {
|
|
22678
|
+
switch (id2) {
|
|
22679
|
+
case "refresh":
|
|
22680
|
+
if (this._selectedMethod && this._willAutoInvoke(this._selectedMethod)) {
|
|
22681
|
+
void this._handleExecute(new CustomEvent("execute", { detail: { args: {} } }));
|
|
22682
|
+
}
|
|
22683
|
+
break;
|
|
22684
|
+
case "remember-values":
|
|
22685
|
+
this._rememberFormValues = !this._rememberFormValues;
|
|
22686
|
+
break;
|
|
22687
|
+
case "verbose-logging":
|
|
22688
|
+
this._verboseLogging = !this._verboseLogging;
|
|
22689
|
+
break;
|
|
22690
|
+
case "run-tests":
|
|
22691
|
+
void this._runTests();
|
|
22692
|
+
break;
|
|
22693
|
+
case "help":
|
|
22694
|
+
this._showPhotonHelp = true;
|
|
22695
|
+
break;
|
|
22696
|
+
default:
|
|
22697
|
+
this._handleContextAction(new CustomEvent("context-action", { detail: { action: id2 } }));
|
|
22698
|
+
break;
|
|
22699
|
+
}
|
|
22700
|
+
}
|
|
22701
|
+
/** Render source panel for split view */
|
|
22702
|
+
_renderSourcePanel(panelId) {
|
|
22703
|
+
return b2`
|
|
22704
|
+
<div style="height: 100%; overflow: hidden;">
|
|
22705
|
+
<photon-studio
|
|
22706
|
+
.photonName=${this._selectedPhoton?.name}
|
|
22707
|
+
.theme=${this._theme}
|
|
22708
|
+
@studio-saved=${() => this._handleStudioSaved?.()}
|
|
22709
|
+
@studio-close=${() => this._removePanel(panelId)}
|
|
22710
|
+
></photon-studio>
|
|
22711
|
+
</div>
|
|
22712
|
+
`;
|
|
22713
|
+
}
|
|
22714
|
+
/** Render the method picker popover for adding new panels */
|
|
22715
|
+
_renderMethodPickerPopover() {
|
|
22716
|
+
const methods = this._getVisibleMethods();
|
|
22717
|
+
const openMethodNames = /* @__PURE__ */ new Set();
|
|
22718
|
+
if (this._selectedMethod) openMethodNames.add(this._selectedMethod.name);
|
|
22719
|
+
for (const p5 of this._splitPanels) {
|
|
22720
|
+
if (p5.type === "method" && p5.method) openMethodNames.add(p5.method.name);
|
|
22721
|
+
}
|
|
22722
|
+
const availableMethods = methods.filter((m3) => !openMethodNames.has(m3.name));
|
|
22723
|
+
const hasSourcePanel = this._splitPanels.some((p5) => p5.type === "source");
|
|
22724
|
+
const canAddMore = this._splitPanels.length < 2;
|
|
22725
|
+
if (!canAddMore) return "";
|
|
22726
|
+
if (!this._pickerDismissHandler) {
|
|
22727
|
+
const handler = (e8) => {
|
|
22728
|
+
const path = e8.composedPath();
|
|
22729
|
+
const popover = this.renderRoot.querySelector(".method-picker-popover");
|
|
22730
|
+
if (popover && path.includes(popover)) return;
|
|
22731
|
+
this._methodPickerOpen = false;
|
|
22732
|
+
this._pickerDismissHandler = null;
|
|
22733
|
+
window.removeEventListener("mousedown", handler, true);
|
|
22734
|
+
};
|
|
22735
|
+
this._pickerDismissHandler = handler;
|
|
22736
|
+
setTimeout(() => window.addEventListener("mousedown", handler, true), 0);
|
|
22737
|
+
}
|
|
22738
|
+
return b2`
|
|
22739
|
+
<div
|
|
22740
|
+
class="method-picker-popover"
|
|
22741
|
+
@click=${(e8) => e8.stopPropagation()}
|
|
22742
|
+
style="position: absolute; top: 100%; right: 0; z-index: 9999; min-width: 200px; max-height: 360px; overflow-y: auto; background: var(--bg-glass); border: 1px solid var(--border-glass); border-radius: 8px; box-shadow: 0 8px 24px rgba(0,0,0,0.3); backdrop-filter: blur(20px); margin-top: 4px;"
|
|
22743
|
+
>
|
|
22744
|
+
<!-- Header -->
|
|
22745
|
+
<div style="padding: 10px 12px 8px; border-bottom: 1px solid var(--border-glass);">
|
|
22746
|
+
<div
|
|
22747
|
+
style="font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--t-tertiary);"
|
|
22748
|
+
>
|
|
22749
|
+
Split Pane
|
|
22750
|
+
</div>
|
|
22751
|
+
</div>
|
|
22752
|
+
|
|
22753
|
+
<!-- Methods section -->
|
|
22754
|
+
${availableMethods.length > 0 ? b2`
|
|
22755
|
+
<div style="padding: 4px 0;">
|
|
22756
|
+
<div
|
|
22757
|
+
style="padding: 4px 12px 2px; font-size: 10px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.05em; color: var(--t-tertiary);"
|
|
22758
|
+
>
|
|
22759
|
+
Methods
|
|
22760
|
+
</div>
|
|
22761
|
+
${availableMethods.map(
|
|
22762
|
+
(m3) => b2`
|
|
22763
|
+
<div
|
|
22764
|
+
@click=${() => this._addPanel("method", m3)}
|
|
22765
|
+
style="padding: 6px 12px 6px 16px; cursor: pointer; font-size: 12px; color: var(--t-primary); transition: background 0.15s ease; display: flex; align-items: center; gap: 6px;"
|
|
22766
|
+
@mouseenter=${(e8) => e8.target.style.background = "var(--bg-hover)"}
|
|
22767
|
+
@mouseleave=${(e8) => e8.target.style.background = "transparent"}
|
|
22768
|
+
>
|
|
22769
|
+
<span style="color: var(--t-tertiary); font-size: 10px;">▸</span>
|
|
22770
|
+
${m3.name}
|
|
22771
|
+
</div>
|
|
22772
|
+
`
|
|
22773
|
+
)}
|
|
21248
22774
|
</div>
|
|
21249
|
-
` : ""}
|
|
21250
|
-
${this._lastResult !== null ? b2`
|
|
21251
|
-
<result-viewer
|
|
21252
|
-
.result=${this._lastResult}
|
|
21253
|
-
.outputFormat=${this._selectedMethod?.outputFormat}
|
|
21254
|
-
.layoutHints=${this._selectedMethod?.layoutHints}
|
|
21255
|
-
.theme=${this._theme}
|
|
21256
|
-
.live=${this._currentCollectionName !== null}
|
|
21257
|
-
.resultKey=${this._selectedPhoton && this._selectedMethod ? `${this._selectedPhoton.name}/${this._selectedMethod.name}` : void 0}
|
|
21258
|
-
@share=${() => this._handleShareResult()}
|
|
21259
|
-
></result-viewer>
|
|
21260
22775
|
` : b2`
|
|
21261
|
-
<div
|
|
21262
|
-
|
|
21263
|
-
|
|
22776
|
+
<div
|
|
22777
|
+
style="padding: 8px 12px; font-size: 11px; color: var(--t-tertiary); font-style: italic;"
|
|
22778
|
+
>
|
|
22779
|
+
All methods already open
|
|
21264
22780
|
</div>
|
|
21265
22781
|
`}
|
|
22782
|
+
|
|
22783
|
+
<!-- Tools section -->
|
|
22784
|
+
${!hasSourcePanel ? b2`
|
|
22785
|
+
<div style="border-top: 1px solid var(--border-glass); padding: 4px 0;">
|
|
22786
|
+
<div
|
|
22787
|
+
style="padding: 4px 12px 2px; font-size: 10px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.05em; color: var(--t-tertiary);"
|
|
22788
|
+
>
|
|
22789
|
+
Tools
|
|
22790
|
+
</div>
|
|
22791
|
+
<div
|
|
22792
|
+
@click=${() => this._addPanel("source")}
|
|
22793
|
+
style="padding: 6px 12px 6px 16px; cursor: pointer; font-size: 12px; color: var(--t-primary); transition: background 0.15s ease; display: flex; align-items: center; gap: 6px;"
|
|
22794
|
+
@mouseenter=${(e8) => e8.target.style.background = "var(--bg-hover)"}
|
|
22795
|
+
@mouseleave=${(e8) => e8.target.style.background = "transparent"}
|
|
22796
|
+
>
|
|
22797
|
+
<span style="font-size: 11px; color: var(--accent-primary);"></></span>
|
|
22798
|
+
Source Editor
|
|
22799
|
+
</div>
|
|
22800
|
+
</div>
|
|
22801
|
+
` : ""}
|
|
21266
22802
|
</div>
|
|
21267
22803
|
`;
|
|
21268
22804
|
}
|
|
@@ -21291,10 +22827,11 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
21291
22827
|
if (form?.isDirty && !confirm("You have unsaved changes. Discard them?")) {
|
|
21292
22828
|
return;
|
|
21293
22829
|
}
|
|
22830
|
+
this._closeSecondPanel();
|
|
21294
22831
|
if (this._selectedPhoton.isApp && this._selectedPhoton.appEntry) {
|
|
21295
22832
|
this._selectedMethod = this._selectedPhoton.appEntry;
|
|
21296
22833
|
this._view = "form";
|
|
21297
|
-
this.
|
|
22834
|
+
this._updateRoute(true);
|
|
21298
22835
|
void this.updateComplete.then(() => {
|
|
21299
22836
|
setTimeout(() => {
|
|
21300
22837
|
const mainArea = this.shadowRoot?.querySelector(".main-area");
|
|
@@ -21308,11 +22845,11 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
21308
22845
|
this._selectedPhoton = null;
|
|
21309
22846
|
this._welcomePhase = "welcome";
|
|
21310
22847
|
this._view = "list";
|
|
21311
|
-
this.
|
|
22848
|
+
this._updateRoute(true);
|
|
21312
22849
|
} else {
|
|
21313
22850
|
this._view = "list";
|
|
21314
22851
|
this._selectedMethod = null;
|
|
21315
|
-
this.
|
|
22852
|
+
this._updateRoute(true);
|
|
21316
22853
|
}
|
|
21317
22854
|
}
|
|
21318
22855
|
async _openForkDialog() {
|
|
@@ -21386,7 +22923,17 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
21386
22923
|
}
|
|
21387
22924
|
} else {
|
|
21388
22925
|
this._lastResult = mcpClient.parseToolResult(result);
|
|
22926
|
+
if (this._selectedPhoton?.stateful && Array.isArray(this._lastResult) && this._selectedMethod) {
|
|
22927
|
+
this._lastResult = this._autoWrapPaginationIfNeeded(
|
|
22928
|
+
this._lastResult,
|
|
22929
|
+
this._selectedPhoton.name,
|
|
22930
|
+
this._selectedMethod
|
|
22931
|
+
);
|
|
22932
|
+
}
|
|
21389
22933
|
this._log("success", "Execution completed", false, execDuration);
|
|
22934
|
+
if (this._selectedPhoton?.stateful && this._lastResult != null && typeof this._lastResult === "object") {
|
|
22935
|
+
this._initializeGlobalInstance(this._selectedPhoton.name, this._lastResult);
|
|
22936
|
+
}
|
|
21390
22937
|
void this.updateComplete.then(() => {
|
|
21391
22938
|
const rv2 = this.shadowRoot?.querySelector("result-viewer");
|
|
21392
22939
|
if (rv2 && window.innerWidth <= 768) {
|
|
@@ -21421,6 +22968,16 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
21421
22968
|
const result = await mcpClient.callTool(toolName, this._lastFormParams || {});
|
|
21422
22969
|
if (!result.isError) {
|
|
21423
22970
|
this._lastResult = mcpClient.parseToolResult(result);
|
|
22971
|
+
if (this._selectedPhoton.stateful && Array.isArray(this._lastResult) && this._selectedMethod) {
|
|
22972
|
+
this._lastResult = this._autoWrapPaginationIfNeeded(
|
|
22973
|
+
this._lastResult,
|
|
22974
|
+
this._selectedPhoton.name,
|
|
22975
|
+
this._selectedMethod
|
|
22976
|
+
);
|
|
22977
|
+
}
|
|
22978
|
+
if (this._selectedPhoton.stateful && this._lastResult != null && typeof this._lastResult === "object") {
|
|
22979
|
+
this._initializeGlobalInstance(this._selectedPhoton.name, this._lastResult);
|
|
22980
|
+
}
|
|
21424
22981
|
}
|
|
21425
22982
|
} catch {
|
|
21426
22983
|
} finally {
|
|
@@ -21471,6 +23028,162 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
21471
23028
|
this._collectionUnsubscribes = [];
|
|
21472
23029
|
this._currentCollectionName = null;
|
|
21473
23030
|
}
|
|
23031
|
+
/**
|
|
23032
|
+
* Initialize global photon instance for @stateful photons
|
|
23033
|
+
* Makes the photon instance available as window.{photonName}
|
|
23034
|
+
* and keeps it in sync with server state via state-changed patches
|
|
23035
|
+
* Wraps paginated array properties with ViewportAwareProxy for smart fetching
|
|
23036
|
+
*/
|
|
23037
|
+
/**
|
|
23038
|
+
* Auto-wrap array results with pagination metadata for @stateful photons
|
|
23039
|
+
* If method has (start, limit) parameters, detect them and use global instance
|
|
23040
|
+
* to calculate pagination metadata from the full array
|
|
23041
|
+
*/
|
|
23042
|
+
_autoWrapPaginationIfNeeded(items, photonName, method) {
|
|
23043
|
+
const hasStartLimitParams = method.parameters?.some(
|
|
23044
|
+
(p5) => (p5.name === "start" || p5.name === "limit") && p5.required !== true
|
|
23045
|
+
);
|
|
23046
|
+
if (!hasStartLimitParams || items.length === 0) {
|
|
23047
|
+
return items;
|
|
23048
|
+
}
|
|
23049
|
+
try {
|
|
23050
|
+
const manager = getGlobalInstanceManager();
|
|
23051
|
+
const instance = manager.getInstance(photonName);
|
|
23052
|
+
if (!instance) {
|
|
23053
|
+
return items;
|
|
23054
|
+
}
|
|
23055
|
+
const arrayProp = Object.keys(instance).find((key) => {
|
|
23056
|
+
const value = instance[key];
|
|
23057
|
+
return Array.isArray(value) && value.length > 0;
|
|
23058
|
+
});
|
|
23059
|
+
if (!arrayProp) {
|
|
23060
|
+
return items;
|
|
23061
|
+
}
|
|
23062
|
+
const fullArray = instance[arrayProp];
|
|
23063
|
+
const totalCount = fullArray.length;
|
|
23064
|
+
const start = 0;
|
|
23065
|
+
const end = items.length;
|
|
23066
|
+
return {
|
|
23067
|
+
items,
|
|
23068
|
+
_pagination: {
|
|
23069
|
+
totalCount,
|
|
23070
|
+
start,
|
|
23071
|
+
end,
|
|
23072
|
+
hasMore: end < totalCount
|
|
23073
|
+
}
|
|
23074
|
+
};
|
|
23075
|
+
} catch (error2) {
|
|
23076
|
+
if (this._verboseLogging) {
|
|
23077
|
+
const msg = error2 instanceof Error ? error2.message : "Unknown error";
|
|
23078
|
+
this._log("warn", `Could not auto-wrap pagination: ${msg}`);
|
|
23079
|
+
}
|
|
23080
|
+
return items;
|
|
23081
|
+
}
|
|
23082
|
+
}
|
|
23083
|
+
_initializeGlobalInstance(photonName, initialState) {
|
|
23084
|
+
try {
|
|
23085
|
+
const paginatedProps = this._detectPaginatedProperties(initialState);
|
|
23086
|
+
const instance = initializeGlobalPhotonSession(photonName, initialState);
|
|
23087
|
+
for (const [propName, paginationMeta] of Object.entries(paginatedProps)) {
|
|
23088
|
+
this._wrapWithViewportProxy(instance, propName, paginationMeta);
|
|
23089
|
+
}
|
|
23090
|
+
if (this._verboseLogging) {
|
|
23091
|
+
const message = paginatedProps.size > 0 ? `\u{1F4E1} Global instance initialized with ${paginatedProps.size} paginated array(s): window.${photonName.toLowerCase()}` : `\u{1F4E1} Global instance initialized: window.${photonName.toLowerCase()}`;
|
|
23092
|
+
this._log("info", message);
|
|
23093
|
+
}
|
|
23094
|
+
} catch (error2) {
|
|
23095
|
+
console.error("Failed to initialize global photon instance", error2);
|
|
23096
|
+
}
|
|
23097
|
+
}
|
|
23098
|
+
/**
|
|
23099
|
+
* Detect which properties have pagination metadata
|
|
23100
|
+
*/
|
|
23101
|
+
_detectPaginatedProperties(initialState) {
|
|
23102
|
+
const paginated = /* @__PURE__ */ new Map();
|
|
23103
|
+
if (!initialState || typeof initialState !== "object") {
|
|
23104
|
+
return paginated;
|
|
23105
|
+
}
|
|
23106
|
+
for (const [key, value] of Object.entries(initialState)) {
|
|
23107
|
+
if (value && typeof value === "object" && value._pagination) {
|
|
23108
|
+
paginated.set(key, value._pagination);
|
|
23109
|
+
}
|
|
23110
|
+
}
|
|
23111
|
+
return paginated;
|
|
23112
|
+
}
|
|
23113
|
+
/**
|
|
23114
|
+
* Wrap a property with ViewportAwareProxy for smart pagination
|
|
23115
|
+
*/
|
|
23116
|
+
_wrapWithViewportProxy(instance, propertyName2, paginationMeta) {
|
|
23117
|
+
try {
|
|
23118
|
+
const pageSize = getPageSizeForClient();
|
|
23119
|
+
const proxy = new ViewportAwareProxy(
|
|
23120
|
+
this._selectedPhoton?.name || "unknown",
|
|
23121
|
+
this._selectedMethod?.name || propertyName2,
|
|
23122
|
+
mcpClient,
|
|
23123
|
+
{
|
|
23124
|
+
pageSize,
|
|
23125
|
+
bufferSize: 5,
|
|
23126
|
+
// Items to buffer above/below viewport
|
|
23127
|
+
maxCacheSize: 500
|
|
23128
|
+
// Max items to keep in cache
|
|
23129
|
+
}
|
|
23130
|
+
);
|
|
23131
|
+
proxy.initializeWithResponse({
|
|
23132
|
+
items: instance[propertyName2] || [],
|
|
23133
|
+
_pagination: paginationMeta
|
|
23134
|
+
});
|
|
23135
|
+
instance.makeProperty(propertyName2);
|
|
23136
|
+
Object.defineProperty(instance, propertyName2, {
|
|
23137
|
+
configurable: true,
|
|
23138
|
+
enumerable: true,
|
|
23139
|
+
get: () => proxy.items,
|
|
23140
|
+
set: (value) => {
|
|
23141
|
+
proxy.clearCache();
|
|
23142
|
+
proxy.initializeWithResponse({
|
|
23143
|
+
items: value || [],
|
|
23144
|
+
_pagination: paginationMeta
|
|
23145
|
+
});
|
|
23146
|
+
}
|
|
23147
|
+
});
|
|
23148
|
+
const patchHandler = (data) => {
|
|
23149
|
+
if (data?.patches) {
|
|
23150
|
+
proxy.applyPatches(data.patches);
|
|
23151
|
+
}
|
|
23152
|
+
};
|
|
23153
|
+
instance.on("state-changed", patchHandler);
|
|
23154
|
+
queueMicrotask(() => {
|
|
23155
|
+
try {
|
|
23156
|
+
const resultViewer = this._resultViewer;
|
|
23157
|
+
if (resultViewer?.shadowRoot) {
|
|
23158
|
+
const scrollContainer = resultViewer.shadowRoot.querySelector(
|
|
23159
|
+
".result-content"
|
|
23160
|
+
);
|
|
23161
|
+
if (scrollContainer) {
|
|
23162
|
+
const manager = new ViewportManager(proxy, {
|
|
23163
|
+
container: scrollContainer,
|
|
23164
|
+
itemSelector: "[data-index]",
|
|
23165
|
+
pageSize,
|
|
23166
|
+
bufferSize: 5
|
|
23167
|
+
});
|
|
23168
|
+
manager.start();
|
|
23169
|
+
}
|
|
23170
|
+
}
|
|
23171
|
+
} catch (error2) {
|
|
23172
|
+
if (this._verboseLogging) {
|
|
23173
|
+
this._log("warn", `Could not set up automatic viewport tracking for ${propertyName2}`);
|
|
23174
|
+
}
|
|
23175
|
+
}
|
|
23176
|
+
});
|
|
23177
|
+
if (this._verboseLogging) {
|
|
23178
|
+
this._log(
|
|
23179
|
+
"info",
|
|
23180
|
+
`\u2728 Paginated proxy enabled for ${propertyName2} (page size: ${pageSize})`
|
|
23181
|
+
);
|
|
23182
|
+
}
|
|
23183
|
+
} catch (error2) {
|
|
23184
|
+
console.error(`Failed to wrap ${propertyName2} with ViewportAwareProxy`, error2);
|
|
23185
|
+
}
|
|
23186
|
+
}
|
|
21474
23187
|
async _handleConfigure(e8) {
|
|
21475
23188
|
const { photon, config: config3 } = e8.detail;
|
|
21476
23189
|
this._log("info", `Configuring ${photon}...`);
|
|
@@ -21505,8 +23218,7 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
21505
23218
|
showToast("No method selected to share", "error");
|
|
21506
23219
|
return;
|
|
21507
23220
|
}
|
|
21508
|
-
const
|
|
21509
|
-
const hash2 = `${this._selectedPhoton.name}/${this._selectedMethod.name}`;
|
|
23221
|
+
const pathSegment2 = `${this._selectedPhoton.name}/${this._selectedMethod.name}`;
|
|
21510
23222
|
const params = new URLSearchParams();
|
|
21511
23223
|
for (const [key, value] of Object.entries(this._lastFormParams)) {
|
|
21512
23224
|
if (value !== void 0 && value !== null && value !== "") {
|
|
@@ -21517,7 +23229,7 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
21517
23229
|
}
|
|
21518
23230
|
}
|
|
21519
23231
|
}
|
|
21520
|
-
let shareUrl = `${
|
|
23232
|
+
let shareUrl = `${window.location.origin}/${pathSegment2}`;
|
|
21521
23233
|
if (params.toString()) {
|
|
21522
23234
|
shareUrl += `?${params.toString()}`;
|
|
21523
23235
|
}
|
|
@@ -21751,7 +23463,8 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
21751
23463
|
showHelp = true,
|
|
21752
23464
|
showRunTests = this._getTestMethods().length > 0,
|
|
21753
23465
|
showRemove = false,
|
|
21754
|
-
showFullscreen = false
|
|
23466
|
+
showFullscreen = false,
|
|
23467
|
+
showInstallApp = !this._pwaIsStandalone && !!this._selectedPhoton?.isApp
|
|
21755
23468
|
} = opts;
|
|
21756
23469
|
const items = [];
|
|
21757
23470
|
if (showFullscreen) {
|
|
@@ -21797,6 +23510,13 @@ ${photon.errorMessage || "Unknown error"}</pre
|
|
|
21797
23510
|
toggle: true,
|
|
21798
23511
|
toggleActive: this._verboseLogging
|
|
21799
23512
|
});
|
|
23513
|
+
if (showInstallApp) {
|
|
23514
|
+
items.push({
|
|
23515
|
+
id: "install-app",
|
|
23516
|
+
label: "Install as App",
|
|
23517
|
+
iconSvg: iconSvgString(iconPaths.installApp)
|
|
23518
|
+
});
|
|
23519
|
+
}
|
|
21800
23520
|
if (showRename || showViewSource || showFork || showContribute || showDelete || showRemove) {
|
|
21801
23521
|
const first = [
|
|
21802
23522
|
showRename,
|
|
@@ -22722,6 +24442,10 @@ BeamApp.styles = [
|
|
|
22722
24442
|
display: none;
|
|
22723
24443
|
}
|
|
22724
24444
|
|
|
24445
|
+
:host(.focus-mode) .main-area {
|
|
24446
|
+
padding: var(--space-sm);
|
|
24447
|
+
}
|
|
24448
|
+
|
|
22725
24449
|
.main-area {
|
|
22726
24450
|
flex: 1;
|
|
22727
24451
|
position: relative;
|
|
@@ -22730,10 +24454,10 @@ BeamApp.styles = [
|
|
|
22730
24454
|
padding: var(--space-lg);
|
|
22731
24455
|
}
|
|
22732
24456
|
|
|
24457
|
+
.beam-back-btn,
|
|
22733
24458
|
.beam-fullscreen-btn {
|
|
22734
24459
|
position: sticky;
|
|
22735
24460
|
top: calc(-1 * var(--space-lg));
|
|
22736
|
-
float: right;
|
|
22737
24461
|
z-index: 100;
|
|
22738
24462
|
width: 28px;
|
|
22739
24463
|
height: 28px;
|
|
@@ -22747,6 +24471,18 @@ BeamApp.styles = [
|
|
|
22747
24471
|
align-items: center;
|
|
22748
24472
|
justify-content: center;
|
|
22749
24473
|
transition: all 0.2s ease;
|
|
24474
|
+
backdrop-filter: blur(8px);
|
|
24475
|
+
}
|
|
24476
|
+
|
|
24477
|
+
.beam-back-btn {
|
|
24478
|
+
float: left;
|
|
24479
|
+
margin-top: calc(-1 * var(--space-lg));
|
|
24480
|
+
margin-left: calc(-1 * var(--space-lg) + 1px);
|
|
24481
|
+
margin-bottom: calc(-28px + var(--space-lg));
|
|
24482
|
+
}
|
|
24483
|
+
|
|
24484
|
+
.beam-fullscreen-btn {
|
|
24485
|
+
float: right;
|
|
22750
24486
|
margin-top: calc(-1 * var(--space-lg));
|
|
22751
24487
|
margin-right: calc(-1 * var(--space-lg) + 1px);
|
|
22752
24488
|
margin-bottom: calc(-28px + var(--space-lg));
|
|
@@ -23777,7 +25513,7 @@ BeamApp.styles = [
|
|
|
23777
25513
|
min-width: 120px;
|
|
23778
25514
|
font-family: var(--font-mono);
|
|
23779
25515
|
font-size: var(--text-md);
|
|
23780
|
-
color:
|
|
25516
|
+
color: var(--color-warning);
|
|
23781
25517
|
}
|
|
23782
25518
|
|
|
23783
25519
|
.variable-input input {
|
|
@@ -23966,7 +25702,7 @@ BeamApp.styles = [
|
|
|
23966
25702
|
|
|
23967
25703
|
.progress-bar-wrapper {
|
|
23968
25704
|
height: 8px;
|
|
23969
|
-
background:
|
|
25705
|
+
background: var(--bg-glass);
|
|
23970
25706
|
border-radius: var(--radius-xs);
|
|
23971
25707
|
overflow: hidden;
|
|
23972
25708
|
}
|
|
@@ -24084,6 +25820,25 @@ BeamApp.styles = [
|
|
|
24084
25820
|
padding-top: calc(var(--space-md) + 60px); /* Space for mobile menu button */
|
|
24085
25821
|
}
|
|
24086
25822
|
|
|
25823
|
+
.beam-back-btn,
|
|
25824
|
+
.beam-fullscreen-btn {
|
|
25825
|
+
position: fixed;
|
|
25826
|
+
top: var(--space-md);
|
|
25827
|
+
float: none;
|
|
25828
|
+
margin: 0;
|
|
25829
|
+
width: 44px;
|
|
25830
|
+
height: 44px;
|
|
25831
|
+
box-shadow: var(--shadow-md);
|
|
25832
|
+
}
|
|
25833
|
+
|
|
25834
|
+
.beam-back-btn {
|
|
25835
|
+
left: calc(var(--space-md) + 44px + var(--space-sm));
|
|
25836
|
+
}
|
|
25837
|
+
|
|
25838
|
+
.beam-fullscreen-btn {
|
|
25839
|
+
right: var(--space-md);
|
|
25840
|
+
}
|
|
25841
|
+
|
|
24087
25842
|
.photon-header {
|
|
24088
25843
|
flex-direction: column;
|
|
24089
25844
|
align-items: flex-start;
|
|
@@ -24098,10 +25853,9 @@ BeamApp.styles = [
|
|
|
24098
25853
|
grid-template-columns: 1fr;
|
|
24099
25854
|
}
|
|
24100
25855
|
|
|
24101
|
-
/* Touch-friendly targets - min 44px */
|
|
25856
|
+
/* Touch-friendly targets - min 44px (exclude small inline buttons) */
|
|
24102
25857
|
.asset-card,
|
|
24103
25858
|
.method-card,
|
|
24104
|
-
button,
|
|
24105
25859
|
.filter-btn {
|
|
24106
25860
|
min-height: 44px;
|
|
24107
25861
|
}
|
|
@@ -24382,6 +26136,15 @@ __decorateClass([
|
|
|
24382
26136
|
__decorateClass([
|
|
24383
26137
|
r5()
|
|
24384
26138
|
], BeamApp.prototype, "_resourceContent", 2);
|
|
26139
|
+
__decorateClass([
|
|
26140
|
+
r5()
|
|
26141
|
+
], BeamApp.prototype, "_splitPanels", 2);
|
|
26142
|
+
__decorateClass([
|
|
26143
|
+
r5()
|
|
26144
|
+
], BeamApp.prototype, "_methodPickerOpen", 2);
|
|
26145
|
+
__decorateClass([
|
|
26146
|
+
r5()
|
|
26147
|
+
], BeamApp.prototype, "_methodPickerPanelId", 2);
|
|
24385
26148
|
__decorateClass([
|
|
24386
26149
|
e7("beam-sidebar")
|
|
24387
26150
|
], BeamApp.prototype, "_sidebar", 2);
|
|
@@ -24420,6 +26183,7 @@ var BeamSidebar = class extends i4 {
|
|
|
24420
26183
|
this._favorites = /* @__PURE__ */ new Set();
|
|
24421
26184
|
this._collapsedSections = /* @__PURE__ */ new Set();
|
|
24422
26185
|
this._recentPhotons = [];
|
|
26186
|
+
this._notificationWarmth = /* @__PURE__ */ new Map();
|
|
24423
26187
|
}
|
|
24424
26188
|
connectedCallback() {
|
|
24425
26189
|
super.connectedCallback();
|
|
@@ -24790,7 +26554,7 @@ var BeamSidebar = class extends i4 {
|
|
|
24790
26554
|
}
|
|
24791
26555
|
return b2`
|
|
24792
26556
|
<li
|
|
24793
|
-
class="photon-item ${this.selectedPhoton === photon.name ? "active" : ""} ${photon.internal ? "internal" : ""}"
|
|
26557
|
+
class="photon-item ${this.selectedPhoton === photon.name ? "active" : ""} ${photon.internal ? "internal" : ""} ${this._isPhotonWarm(photon.name) ? "warmth" : ""}"
|
|
24794
26558
|
role="option"
|
|
24795
26559
|
aria-selected="${this.selectedPhoton === photon.name}"
|
|
24796
26560
|
tabindex="0"
|
|
@@ -24987,6 +26751,28 @@ ${photon.path}` : ""}"
|
|
|
24987
26751
|
}
|
|
24988
26752
|
});
|
|
24989
26753
|
}
|
|
26754
|
+
/**
|
|
26755
|
+
* Check if a photon currently has a warmth indicator (notification received within last 5 seconds)
|
|
26756
|
+
*/
|
|
26757
|
+
_isPhotonWarm(photonName) {
|
|
26758
|
+
const lastNotificationTime = this._notificationWarmth.get(photonName);
|
|
26759
|
+
if (!lastNotificationTime) return false;
|
|
26760
|
+
return Date.now() - lastNotificationTime < 5e3;
|
|
26761
|
+
}
|
|
26762
|
+
/**
|
|
26763
|
+
* Update the warmth indicator for a photon when a notification arrives
|
|
26764
|
+
*/
|
|
26765
|
+
updatePhotonWarmth(photonName) {
|
|
26766
|
+
this._notificationWarmth.set(photonName, Date.now());
|
|
26767
|
+
this.requestUpdate();
|
|
26768
|
+
}
|
|
26769
|
+
/**
|
|
26770
|
+
* Check if a notification type is watched by a photon
|
|
26771
|
+
* This will be called by beam-app to determine if window.focus() should be triggered
|
|
26772
|
+
*/
|
|
26773
|
+
isNotificationWatched(photonName, notificationType) {
|
|
26774
|
+
return true;
|
|
26775
|
+
}
|
|
24990
26776
|
};
|
|
24991
26777
|
BeamSidebar.styles = [
|
|
24992
26778
|
theme,
|
|
@@ -25221,7 +27007,7 @@ BeamSidebar.styles = [
|
|
|
25221
27007
|
}
|
|
25222
27008
|
|
|
25223
27009
|
.section-header:hover {
|
|
25224
|
-
color: var(--t-
|
|
27010
|
+
color: var(--t-primary);
|
|
25225
27011
|
background: var(--bg-panel);
|
|
25226
27012
|
}
|
|
25227
27013
|
|
|
@@ -25283,7 +27069,7 @@ BeamSidebar.styles = [
|
|
|
25283
27069
|
}
|
|
25284
27070
|
|
|
25285
27071
|
.photon-item:hover {
|
|
25286
|
-
background:
|
|
27072
|
+
background: var(--bg-glass);
|
|
25287
27073
|
}
|
|
25288
27074
|
|
|
25289
27075
|
.photon-item.active {
|
|
@@ -25297,13 +27083,28 @@ BeamSidebar.styles = [
|
|
|
25297
27083
|
|
|
25298
27084
|
@keyframes flash-highlight {
|
|
25299
27085
|
0% {
|
|
25300
|
-
background:
|
|
27086
|
+
background: var(--glow-primary);
|
|
25301
27087
|
}
|
|
25302
27088
|
100% {
|
|
25303
27089
|
background: transparent;
|
|
25304
27090
|
}
|
|
25305
27091
|
}
|
|
25306
27092
|
|
|
27093
|
+
.photon-item.warmth {
|
|
27094
|
+
animation: warmth-fade 5s ease-out forwards;
|
|
27095
|
+
}
|
|
27096
|
+
|
|
27097
|
+
@keyframes warmth-fade {
|
|
27098
|
+
0% {
|
|
27099
|
+
background: var(--color-warning);
|
|
27100
|
+
opacity: 0.15;
|
|
27101
|
+
}
|
|
27102
|
+
100% {
|
|
27103
|
+
background: var(--color-warning);
|
|
27104
|
+
opacity: 0;
|
|
27105
|
+
}
|
|
27106
|
+
}
|
|
27107
|
+
|
|
25307
27108
|
.photon-icon {
|
|
25308
27109
|
width: 28px;
|
|
25309
27110
|
height: 28px;
|
|
@@ -25394,7 +27195,7 @@ BeamSidebar.styles = [
|
|
|
25394
27195
|
gap: 3px;
|
|
25395
27196
|
font-size: var(--text-2xs);
|
|
25396
27197
|
padding: 2px 5px;
|
|
25397
|
-
background:
|
|
27198
|
+
background: var(--bg-glass);
|
|
25398
27199
|
border: 1px solid var(--border-glass);
|
|
25399
27200
|
border-radius: var(--radius-full);
|
|
25400
27201
|
font-weight: 500;
|
|
@@ -25477,7 +27278,7 @@ BeamSidebar.styles = [
|
|
|
25477
27278
|
.marketplace-btn:hover {
|
|
25478
27279
|
background: var(--bg-panel);
|
|
25479
27280
|
border-color: var(--accent-secondary);
|
|
25480
|
-
box-shadow:
|
|
27281
|
+
box-shadow: var(--shadow-sm);
|
|
25481
27282
|
transform: translateY(-1px);
|
|
25482
27283
|
}
|
|
25483
27284
|
|
|
@@ -25709,6 +27510,9 @@ __decorateClass([
|
|
|
25709
27510
|
__decorateClass([
|
|
25710
27511
|
r5()
|
|
25711
27512
|
], BeamSidebar.prototype, "_recentPhotons", 2);
|
|
27513
|
+
__decorateClass([
|
|
27514
|
+
r5()
|
|
27515
|
+
], BeamSidebar.prototype, "_notificationWarmth", 2);
|
|
25712
27516
|
BeamSidebar = __decorateClass([
|
|
25713
27517
|
t4("beam-sidebar")
|
|
25714
27518
|
], BeamSidebar);
|
|
@@ -25798,34 +27602,16 @@ var MethodCard = class extends i4 {
|
|
|
25798
27602
|
</div>
|
|
25799
27603
|
${this.method.isTemplate ? b2`<span class="badge prompt">Prompt</span>` : ""}
|
|
25800
27604
|
${isCron ? b2`<span
|
|
25801
|
-
class="badge"
|
|
25802
|
-
style="background:hsla(215,80%,60%,0.15);color:hsl(215,80%,65%)"
|
|
27605
|
+
class="badge scheduled"
|
|
25803
27606
|
title="Runs automatically on schedule: ${this.method.scheduled}"
|
|
25804
27607
|
>⏱ Scheduled</span
|
|
25805
27608
|
>` : ""}
|
|
25806
|
-
${isDeprecated ? b2`<span
|
|
25807
|
-
|
|
25808
|
-
|
|
25809
|
-
|
|
25810
|
-
>` : ""}
|
|
25811
|
-
${isCached ? b2`<span
|
|
25812
|
-
class="badge"
|
|
25813
|
-
style="background:hsla(280,60%,50%,0.15);color:hsl(280,60%,65%)"
|
|
25814
|
-
>Cached</span
|
|
25815
|
-
>` : ""}
|
|
25816
|
-
${isThrottled ? b2`<span
|
|
25817
|
-
class="badge"
|
|
25818
|
-
style="background:hsla(30,80%,50%,0.15);color:hsl(30,80%,60%)"
|
|
25819
|
-
>Throttled</span
|
|
25820
|
-
>` : ""}
|
|
25821
|
-
${isQueued ? b2`<span
|
|
25822
|
-
class="badge"
|
|
25823
|
-
style="background:hsla(200,70%,50%,0.15);color:hsl(200,70%,60%)"
|
|
25824
|
-
>Queued</span
|
|
25825
|
-
>` : ""}
|
|
27609
|
+
${isDeprecated ? b2`<span class="badge deprecated">Deprecated</span>` : ""}
|
|
27610
|
+
${isCached ? b2`<span class="badge cached">Cached</span>` : ""}
|
|
27611
|
+
${isThrottled ? b2`<span class="badge throttled">Throttled</span>` : ""}
|
|
27612
|
+
${isQueued ? b2`<span class="badge queued">Queued</span>` : ""}
|
|
25826
27613
|
${emitsEvent ? b2`<span
|
|
25827
|
-
class="badge"
|
|
25828
|
-
style="background:hsla(100,70%,50%,0.15);color:hsl(100,70%,60%)"
|
|
27614
|
+
class="badge event"
|
|
25829
27615
|
title="Automatically emits event: ${this.method.eventName}"
|
|
25830
27616
|
>📡 Event</span
|
|
25831
27617
|
>` : ""}
|
|
@@ -26071,7 +27857,7 @@ MethodCard.styles = [
|
|
|
26071
27857
|
|
|
26072
27858
|
.card:hover {
|
|
26073
27859
|
transform: translateY(-2px);
|
|
26074
|
-
box-shadow:
|
|
27860
|
+
box-shadow: var(--shadow-lg);
|
|
26075
27861
|
border-left-color: var(--accent-primary);
|
|
26076
27862
|
}
|
|
26077
27863
|
|
|
@@ -26249,7 +28035,7 @@ MethodCard.styles = [
|
|
|
26249
28035
|
font-size: var(--text-xs);
|
|
26250
28036
|
padding: 2px 8px;
|
|
26251
28037
|
border-radius: var(--radius-md);
|
|
26252
|
-
background:
|
|
28038
|
+
background: var(--bg-glass);
|
|
26253
28039
|
color: var(--t-muted);
|
|
26254
28040
|
flex-shrink: 0;
|
|
26255
28041
|
}
|
|
@@ -26259,6 +28045,37 @@ MethodCard.styles = [
|
|
|
26259
28045
|
color: hsl(45, 80%, 60%);
|
|
26260
28046
|
}
|
|
26261
28047
|
|
|
28048
|
+
.badge.scheduled {
|
|
28049
|
+
background: hsla(215, 80%, 60%, 0.15);
|
|
28050
|
+
color: hsl(215, 80%, 65%);
|
|
28051
|
+
}
|
|
28052
|
+
|
|
28053
|
+
.badge.deprecated {
|
|
28054
|
+
background: hsla(0, 0%, 50%, 0.15);
|
|
28055
|
+
color: hsl(0, 0%, 60%);
|
|
28056
|
+
text-decoration: line-through;
|
|
28057
|
+
}
|
|
28058
|
+
|
|
28059
|
+
.badge.cached {
|
|
28060
|
+
background: hsla(280, 60%, 50%, 0.15);
|
|
28061
|
+
color: hsl(280, 60%, 65%);
|
|
28062
|
+
}
|
|
28063
|
+
|
|
28064
|
+
.badge.throttled {
|
|
28065
|
+
background: hsla(30, 80%, 50%, 0.15);
|
|
28066
|
+
color: hsl(30, 80%, 60%);
|
|
28067
|
+
}
|
|
28068
|
+
|
|
28069
|
+
.badge.queued {
|
|
28070
|
+
background: hsla(200, 70%, 50%, 0.15);
|
|
28071
|
+
color: hsl(200, 70%, 60%);
|
|
28072
|
+
}
|
|
28073
|
+
|
|
28074
|
+
.badge.event {
|
|
28075
|
+
background: hsla(100, 70%, 50%, 0.15);
|
|
28076
|
+
color: hsl(100, 70%, 60%);
|
|
28077
|
+
}
|
|
28078
|
+
|
|
26262
28079
|
.param-tags {
|
|
26263
28080
|
display: flex;
|
|
26264
28081
|
flex-wrap: wrap;
|
|
@@ -26272,9 +28089,9 @@ MethodCard.styles = [
|
|
|
26272
28089
|
font-size: var(--text-xs);
|
|
26273
28090
|
padding: 4px 10px;
|
|
26274
28091
|
border-radius: var(--radius-xs);
|
|
26275
|
-
background: hsla(260, 60%, 50%, 0.12);
|
|
26276
|
-
color: var(--t-primary);
|
|
26277
|
-
border: 1px solid hsla(260, 60%, 50%, 0.2);
|
|
28092
|
+
background: var(--param-tag-bg, hsla(260, 60%, 50%, 0.12));
|
|
28093
|
+
color: var(--param-tag-color, var(--t-primary));
|
|
28094
|
+
border: 1px solid var(--param-tag-border, hsla(260, 60%, 50%, 0.2));
|
|
26278
28095
|
font-weight: 500;
|
|
26279
28096
|
}
|
|
26280
28097
|
|
|
@@ -26283,8 +28100,8 @@ MethodCard.styles = [
|
|
|
26283
28100
|
min-width: 20px;
|
|
26284
28101
|
height: 20px;
|
|
26285
28102
|
border-radius: var(--radius-sm);
|
|
26286
|
-
background: hsla(45, 80%, 50%, 0.2);
|
|
26287
|
-
color: hsl(45, 80%, 60%);
|
|
28103
|
+
background: var(--color-warning-bg, hsla(45, 80%, 50%, 0.2));
|
|
28104
|
+
color: var(--color-warning, hsl(45, 80%, 60%));
|
|
26288
28105
|
display: inline-flex;
|
|
26289
28106
|
align-items: center;
|
|
26290
28107
|
justify-content: center;
|
|
@@ -26314,7 +28131,7 @@ MethodCard.styles = [
|
|
|
26314
28131
|
align-items: center;
|
|
26315
28132
|
justify-content: center;
|
|
26316
28133
|
border-radius: var(--radius-sm);
|
|
26317
|
-
background:
|
|
28134
|
+
background: var(--bg-glass);
|
|
26318
28135
|
}
|
|
26319
28136
|
|
|
26320
28137
|
.card:hover .action-icon {
|
|
@@ -26329,7 +28146,7 @@ MethodCard.styles = [
|
|
|
26329
28146
|
border: 1px solid var(--border-glass);
|
|
26330
28147
|
border-radius: var(--radius-md);
|
|
26331
28148
|
padding: var(--space-sm);
|
|
26332
|
-
box-shadow:
|
|
28149
|
+
box-shadow: var(--shadow-lg);
|
|
26333
28150
|
z-index: 100;
|
|
26334
28151
|
display: grid;
|
|
26335
28152
|
grid-template-columns: repeat(6, 1fr);
|
|
@@ -26498,6 +28315,30 @@ function singularize(word) {
|
|
|
26498
28315
|
if (lower.endsWith("s") && !lower.endsWith("ss")) return word.slice(0, -1);
|
|
26499
28316
|
return word;
|
|
26500
28317
|
}
|
|
28318
|
+
function isValidCharForFormat(char, format, position) {
|
|
28319
|
+
if (!format) return true;
|
|
28320
|
+
switch (format.toLowerCase()) {
|
|
28321
|
+
case "email":
|
|
28322
|
+
return /[a-zA-Z0-9@.\-_+]/.test(char);
|
|
28323
|
+
case "url":
|
|
28324
|
+
case "uri":
|
|
28325
|
+
return /[a-zA-Z0-9:\/\-_.?=&#%@+~;,!]/.test(char);
|
|
28326
|
+
case "uuid":
|
|
28327
|
+
return /[0-9a-fA-F\-]/.test(char);
|
|
28328
|
+
case "ipv4":
|
|
28329
|
+
return /[0-9.]/.test(char);
|
|
28330
|
+
case "ipv6":
|
|
28331
|
+
return /[0-9a-fA-F:]/.test(char);
|
|
28332
|
+
case "slug":
|
|
28333
|
+
return /[a-z0-9\-]/.test(char);
|
|
28334
|
+
case "hex":
|
|
28335
|
+
return position === 0 && char === "#" ? true : /[0-9a-fA-F]/.test(char);
|
|
28336
|
+
case "phone":
|
|
28337
|
+
return /[0-9+\-() ]/.test(char);
|
|
28338
|
+
default:
|
|
28339
|
+
return true;
|
|
28340
|
+
}
|
|
28341
|
+
}
|
|
26501
28342
|
var InvokeForm = class extends i4 {
|
|
26502
28343
|
constructor() {
|
|
26503
28344
|
super(...arguments);
|
|
@@ -26752,9 +28593,7 @@ var InvokeForm = class extends i4 {
|
|
|
26752
28593
|
this._handleChange(key, arr.length > 0 ? arr : raw);
|
|
26753
28594
|
}}
|
|
26754
28595
|
/>
|
|
26755
|
-
<div class="hint"
|
|
26756
|
-
Comma-separated values
|
|
26757
|
-
</div>
|
|
28596
|
+
<div class="hint">Comma-separated values</div>
|
|
26758
28597
|
</div>
|
|
26759
28598
|
`;
|
|
26760
28599
|
}
|
|
@@ -26805,9 +28644,12 @@ var InvokeForm = class extends i4 {
|
|
|
26805
28644
|
min="${min}"
|
|
26806
28645
|
max="${max}"
|
|
26807
28646
|
step="${step2}"
|
|
28647
|
+
style="${this._sliderFillStyle(Number(currentValue2), min, max)}"
|
|
26808
28648
|
.value=${String(currentValue2)}
|
|
26809
28649
|
@input=${(e8) => {
|
|
26810
|
-
const
|
|
28650
|
+
const el2 = e8.target;
|
|
28651
|
+
const v2 = this._sanitizeSliderValue(Number(el2.value), min, max, step2);
|
|
28652
|
+
el2.style.cssText = this._sliderFillStyle(v2, min, max);
|
|
26811
28653
|
this._handleChange(key, v2);
|
|
26812
28654
|
}}
|
|
26813
28655
|
/>
|
|
@@ -26820,7 +28662,14 @@ var InvokeForm = class extends i4 {
|
|
|
26820
28662
|
step="${step2}"
|
|
26821
28663
|
.value=${displayValue2}
|
|
26822
28664
|
@input=${(e8) => {
|
|
26823
|
-
const
|
|
28665
|
+
const raw = e8.target.value;
|
|
28666
|
+
if (raw === "" || raw === "-") return;
|
|
28667
|
+
this._handleChange(key, Number(raw));
|
|
28668
|
+
}}
|
|
28669
|
+
@change=${(e8) => {
|
|
28670
|
+
const el2 = e8.target;
|
|
28671
|
+
const v2 = this._sanitizeSliderValue(Number(el2.value), min, max, step2);
|
|
28672
|
+
el2.value = String(v2);
|
|
26824
28673
|
this._handleChange(key, v2);
|
|
26825
28674
|
}}
|
|
26826
28675
|
/>
|
|
@@ -26839,14 +28688,31 @@ var InvokeForm = class extends i4 {
|
|
|
26839
28688
|
return b2`
|
|
26840
28689
|
<input
|
|
26841
28690
|
id=${o8(inputId)}
|
|
26842
|
-
type="
|
|
26843
|
-
class="${errorClass}"
|
|
28691
|
+
type="text"
|
|
28692
|
+
class="number-input-clean ${errorClass}"
|
|
28693
|
+
inputmode=${isInteger ? "numeric" : "decimal"}
|
|
26844
28694
|
${hasMin ? `min="${schema.minimum}"` : ""}
|
|
26845
|
-
step="${step}"
|
|
26846
28695
|
placeholder="${defaultVal2}"
|
|
26847
28696
|
.value=${displayValue}
|
|
28697
|
+
@keypress=${(e8) => {
|
|
28698
|
+
const char = e8.key;
|
|
28699
|
+
const isDigit = /\d/.test(char);
|
|
28700
|
+
const isMinus = char === "-";
|
|
28701
|
+
const isDecimal = char === "." && !isInteger;
|
|
28702
|
+
if (!isDigit && !isMinus && !isDecimal) {
|
|
28703
|
+
e8.preventDefault();
|
|
28704
|
+
}
|
|
28705
|
+
}}
|
|
26848
28706
|
@input=${(e8) => {
|
|
26849
|
-
|
|
28707
|
+
let text = e8.target.value;
|
|
28708
|
+
if (isInteger) {
|
|
28709
|
+
const cleaned = text.replace(/[^\d-]/g, "");
|
|
28710
|
+
text = cleaned.match(/-.*-/) ? cleaned.replace(/-/g, "").replace(/^/, "-") : cleaned;
|
|
28711
|
+
}
|
|
28712
|
+
let v2 = text === "" || text === "-" ? defaultVal2 : Number(text);
|
|
28713
|
+
if (isNaN(v2)) {
|
|
28714
|
+
v2 = defaultVal2;
|
|
28715
|
+
}
|
|
26850
28716
|
this._handleChange(key, v2);
|
|
26851
28717
|
}}
|
|
26852
28718
|
/>
|
|
@@ -26934,6 +28800,8 @@ var InvokeForm = class extends i4 {
|
|
|
26934
28800
|
}
|
|
26935
28801
|
const defaultVal = schema.default;
|
|
26936
28802
|
const placeholder = defaultVal != null ? String(defaultVal) : "";
|
|
28803
|
+
const format = schema.format;
|
|
28804
|
+
const pattern = schema.pattern;
|
|
26937
28805
|
return b2`
|
|
26938
28806
|
<input
|
|
26939
28807
|
id=${o8(inputId)}
|
|
@@ -26941,6 +28809,23 @@ var InvokeForm = class extends i4 {
|
|
|
26941
28809
|
class="${errorClass}"
|
|
26942
28810
|
placeholder="${placeholder}"
|
|
26943
28811
|
.value=${this._values[key] || ""}
|
|
28812
|
+
@keypress=${(e8) => {
|
|
28813
|
+
if (!isValidCharForFormat(e8.key, format)) {
|
|
28814
|
+
e8.preventDefault();
|
|
28815
|
+
return;
|
|
28816
|
+
}
|
|
28817
|
+
if (pattern) {
|
|
28818
|
+
try {
|
|
28819
|
+
const currentValue = e8.target.value;
|
|
28820
|
+
const newValue = currentValue + e8.key;
|
|
28821
|
+
const regex = new RegExp(pattern);
|
|
28822
|
+
if (!regex.test(newValue)) {
|
|
28823
|
+
e8.preventDefault();
|
|
28824
|
+
}
|
|
28825
|
+
} catch (err) {
|
|
28826
|
+
}
|
|
28827
|
+
}
|
|
28828
|
+
}}
|
|
26944
28829
|
@input=${(e8) => this._handleChange(key, e8.target.value)}
|
|
26945
28830
|
/>
|
|
26946
28831
|
`;
|
|
@@ -27065,7 +28950,11 @@ var InvokeForm = class extends i4 {
|
|
|
27065
28950
|
*/
|
|
27066
28951
|
_cleanDescription(desc, schema) {
|
|
27067
28952
|
if (!desc) return desc;
|
|
27068
|
-
let cleaned = desc
|
|
28953
|
+
let cleaned = desc;
|
|
28954
|
+
const lines = cleaned.split("\n").filter((line) => !line.trim().startsWith("@"));
|
|
28955
|
+
cleaned = lines.join("\n").trim();
|
|
28956
|
+
cleaned = cleaned.replace(/\s*@\w+[\s\S]*?(?=[.!?\n]|$)/g, "").trim();
|
|
28957
|
+
cleaned = cleaned.replace(
|
|
27069
28958
|
/['"][\w-]+['"]\s*(?:\([^)]*\)\s*)?(?:\|\s*['"][\w-]+['"]\s*(?:\([^)]*\)\s*)?)+/g,
|
|
27070
28959
|
""
|
|
27071
28960
|
);
|
|
@@ -27101,6 +28990,23 @@ var InvokeForm = class extends i4 {
|
|
|
27101
28990
|
this._savePersistedValues();
|
|
27102
28991
|
}
|
|
27103
28992
|
}
|
|
28993
|
+
_sliderFillStyle(value, min, max) {
|
|
28994
|
+
const pct = max > min ? (value - min) / (max - min) * 100 : 0;
|
|
28995
|
+
return `background: linear-gradient(to right, var(--accent-primary) ${pct}%, var(--border-glass) ${pct}%)`;
|
|
28996
|
+
}
|
|
28997
|
+
/** Clamp to [min, max] and round to nearest step (integer-safe). */
|
|
28998
|
+
_sanitizeSliderValue(raw, min, max, step) {
|
|
28999
|
+
let v2 = Number.isFinite(raw) ? raw : min;
|
|
29000
|
+
v2 = Math.min(max, Math.max(min, v2));
|
|
29001
|
+
if (step > 0) {
|
|
29002
|
+
v2 = min + Math.round((v2 - min) / step) * step;
|
|
29003
|
+
if (v2 > max) v2 = max;
|
|
29004
|
+
}
|
|
29005
|
+
if (Number.isInteger(step) && step >= 1) {
|
|
29006
|
+
v2 = Math.round(v2);
|
|
29007
|
+
}
|
|
29008
|
+
return v2;
|
|
29009
|
+
}
|
|
27104
29010
|
_handleChange(key, value) {
|
|
27105
29011
|
this._values = { ...this._values, [key]: value };
|
|
27106
29012
|
if (this.rememberValues) {
|
|
@@ -27108,7 +29014,7 @@ var InvokeForm = class extends i4 {
|
|
|
27108
29014
|
}
|
|
27109
29015
|
}
|
|
27110
29016
|
_buildCliCommand() {
|
|
27111
|
-
const parts = [
|
|
29017
|
+
const parts = [this.photonName, this.methodName];
|
|
27112
29018
|
for (const [key, value] of Object.entries(this._values)) {
|
|
27113
29019
|
if (value === void 0 || value === null || value === "") continue;
|
|
27114
29020
|
const strVal = typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
@@ -27232,7 +29138,9 @@ var InvokeForm = class extends i4 {
|
|
|
27232
29138
|
>
|
|
27233
29139
|
<option value="">Select...</option>
|
|
27234
29140
|
${schema.enum.map(
|
|
27235
|
-
(opt) => b2`
|
|
29141
|
+
(opt) => b2`
|
|
29142
|
+
<option value=${opt} ?selected=${opt === value}>${capitalizeEnumValue(opt)}</option>
|
|
29143
|
+
`
|
|
27236
29144
|
)}
|
|
27237
29145
|
</select>
|
|
27238
29146
|
`;
|
|
@@ -27268,8 +29176,14 @@ var InvokeForm = class extends i4 {
|
|
|
27268
29176
|
min="${min}"
|
|
27269
29177
|
max="${max}"
|
|
27270
29178
|
step="${step2}"
|
|
29179
|
+
style="${this._sliderFillStyle(Number(currentVal2), min, max)}"
|
|
27271
29180
|
.value=${String(currentVal2)}
|
|
27272
|
-
@input=${(e8) =>
|
|
29181
|
+
@input=${(e8) => {
|
|
29182
|
+
const el2 = e8.target;
|
|
29183
|
+
const v2 = this._sanitizeSliderValue(Number(el2.value), min, max, step2);
|
|
29184
|
+
el2.style.cssText = this._sliderFillStyle(v2, min, max);
|
|
29185
|
+
onChange(propKey, v2);
|
|
29186
|
+
}}
|
|
27273
29187
|
/>
|
|
27274
29188
|
<input
|
|
27275
29189
|
type="number"
|
|
@@ -27278,7 +29192,17 @@ var InvokeForm = class extends i4 {
|
|
|
27278
29192
|
max="${max}"
|
|
27279
29193
|
step="${step2}"
|
|
27280
29194
|
.value=${displayVal2}
|
|
27281
|
-
@input=${(e8) =>
|
|
29195
|
+
@input=${(e8) => {
|
|
29196
|
+
const raw = e8.target.value;
|
|
29197
|
+
if (raw === "" || raw === "-") return;
|
|
29198
|
+
onChange(propKey, Number(raw));
|
|
29199
|
+
}}
|
|
29200
|
+
@change=${(e8) => {
|
|
29201
|
+
const el2 = e8.target;
|
|
29202
|
+
const v2 = this._sanitizeSliderValue(Number(el2.value), min, max, step2);
|
|
29203
|
+
el2.value = String(v2);
|
|
29204
|
+
onChange(propKey, v2);
|
|
29205
|
+
}}
|
|
27282
29206
|
/>
|
|
27283
29207
|
</div>
|
|
27284
29208
|
<div class="range-labels">
|
|
@@ -27445,18 +29369,23 @@ var InvokeForm = class extends i4 {
|
|
|
27445
29369
|
>
|
|
27446
29370
|
<option value="">Select...</option>
|
|
27447
29371
|
${schema.enum.map(
|
|
27448
|
-
(opt) => b2`
|
|
29372
|
+
(opt) => b2`
|
|
29373
|
+
<option value=${opt} ?selected=${opt === value}>${capitalizeEnumValue(opt)}</option>
|
|
29374
|
+
`
|
|
27449
29375
|
)}
|
|
27450
29376
|
</select>
|
|
27451
29377
|
`;
|
|
27452
29378
|
}
|
|
27453
29379
|
if (schema.type === "boolean") {
|
|
27454
29380
|
return b2`
|
|
27455
|
-
<
|
|
27456
|
-
|
|
27457
|
-
|
|
27458
|
-
|
|
27459
|
-
|
|
29381
|
+
<label class="switch">
|
|
29382
|
+
<input
|
|
29383
|
+
type="checkbox"
|
|
29384
|
+
.checked=${!!value}
|
|
29385
|
+
@change=${(e8) => handleNestedChange(e8.target.checked)}
|
|
29386
|
+
/>
|
|
29387
|
+
<span class="slider"></span>
|
|
29388
|
+
</label>
|
|
27460
29389
|
`;
|
|
27461
29390
|
}
|
|
27462
29391
|
if (schema.type === "number" || schema.type === "integer") {
|
|
@@ -27478,8 +29407,14 @@ var InvokeForm = class extends i4 {
|
|
|
27478
29407
|
min="${min}"
|
|
27479
29408
|
max="${max}"
|
|
27480
29409
|
step="${step2}"
|
|
29410
|
+
style="${this._sliderFillStyle(Number(currentVal2), min, max)}"
|
|
27481
29411
|
.value=${String(currentVal2)}
|
|
27482
|
-
@input=${(e8) =>
|
|
29412
|
+
@input=${(e8) => {
|
|
29413
|
+
const el2 = e8.target;
|
|
29414
|
+
const v2 = this._sanitizeSliderValue(Number(el2.value), min, max, step2);
|
|
29415
|
+
el2.style.cssText = this._sliderFillStyle(v2, min, max);
|
|
29416
|
+
handleNestedChange(v2);
|
|
29417
|
+
}}
|
|
27483
29418
|
/>
|
|
27484
29419
|
<input
|
|
27485
29420
|
type="number"
|
|
@@ -27488,7 +29423,17 @@ var InvokeForm = class extends i4 {
|
|
|
27488
29423
|
max="${max}"
|
|
27489
29424
|
step="${step2}"
|
|
27490
29425
|
.value=${displayVal2}
|
|
27491
|
-
@input=${(e8) =>
|
|
29426
|
+
@input=${(e8) => {
|
|
29427
|
+
const raw = e8.target.value;
|
|
29428
|
+
if (raw === "" || raw === "-") return;
|
|
29429
|
+
handleNestedChange(Number(raw));
|
|
29430
|
+
}}
|
|
29431
|
+
@change=${(e8) => {
|
|
29432
|
+
const el2 = e8.target;
|
|
29433
|
+
const v2 = this._sanitizeSliderValue(Number(el2.value), min, max, step2);
|
|
29434
|
+
el2.value = String(v2);
|
|
29435
|
+
handleNestedChange(v2);
|
|
29436
|
+
}}
|
|
27492
29437
|
/>
|
|
27493
29438
|
</div>
|
|
27494
29439
|
<div class="range-labels">
|
|
@@ -27839,6 +29784,7 @@ InvokeForm.styles = [
|
|
|
27839
29784
|
font-size: var(--text-xs);
|
|
27840
29785
|
padding: 2px 6px;
|
|
27841
29786
|
border-radius: var(--radius-xs);
|
|
29787
|
+
transition: background 0.15s ease;
|
|
27842
29788
|
}
|
|
27843
29789
|
|
|
27844
29790
|
.array-item-remove:hover {
|
|
@@ -27915,11 +29861,17 @@ InvokeForm.styles = [
|
|
|
27915
29861
|
margin-top: var(--space-xs);
|
|
27916
29862
|
}
|
|
27917
29863
|
|
|
29864
|
+
.hint {
|
|
29865
|
+
font-size: var(--text-xs);
|
|
29866
|
+
color: var(--t-muted);
|
|
29867
|
+
margin-top: 2px;
|
|
29868
|
+
}
|
|
29869
|
+
|
|
27918
29870
|
/* Slider-First Numeric Input */
|
|
27919
29871
|
.slider-group {
|
|
27920
29872
|
display: flex;
|
|
27921
29873
|
flex-direction: column;
|
|
27922
|
-
gap:
|
|
29874
|
+
gap: 4px;
|
|
27923
29875
|
}
|
|
27924
29876
|
|
|
27925
29877
|
.slider-row {
|
|
@@ -27930,57 +29882,140 @@ InvokeForm.styles = [
|
|
|
27930
29882
|
|
|
27931
29883
|
.slider-row input[type='range'] {
|
|
27932
29884
|
flex: 1;
|
|
27933
|
-
height:
|
|
27934
|
-
|
|
27935
|
-
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
27936
|
-
border-radius: 3px;
|
|
29885
|
+
height: 4px;
|
|
29886
|
+
border-radius: var(--radius-full, 9999px);
|
|
27937
29887
|
-webkit-appearance: none;
|
|
27938
29888
|
cursor: pointer;
|
|
27939
29889
|
margin: 8px 0;
|
|
29890
|
+
border: none;
|
|
29891
|
+
outline: none;
|
|
29892
|
+
/* Default unfilled track — overridden by inline style for fill effect */
|
|
29893
|
+
background: var(--border-glass);
|
|
27940
29894
|
}
|
|
27941
29895
|
|
|
27942
29896
|
.slider-row input[type='range']::-webkit-slider-thumb {
|
|
27943
29897
|
-webkit-appearance: none;
|
|
27944
|
-
width:
|
|
27945
|
-
height:
|
|
29898
|
+
width: 16px;
|
|
29899
|
+
height: 16px;
|
|
27946
29900
|
background: var(--accent-primary);
|
|
29901
|
+
border: 2px solid var(--bg-panel, var(--bg-glass));
|
|
27947
29902
|
border-radius: 50%;
|
|
27948
29903
|
cursor: pointer;
|
|
27949
|
-
box-shadow:
|
|
29904
|
+
box-shadow:
|
|
29905
|
+
0 0 0 2px var(--accent-primary),
|
|
29906
|
+
0 1px 4px rgba(0, 0, 0, 0.3);
|
|
29907
|
+
transition:
|
|
29908
|
+
box-shadow 0.15s ease,
|
|
29909
|
+
transform 0.15s ease;
|
|
29910
|
+
}
|
|
29911
|
+
|
|
29912
|
+
.slider-row input[type='range']::-webkit-slider-thumb:hover {
|
|
29913
|
+
box-shadow:
|
|
29914
|
+
0 0 0 3px var(--accent-primary),
|
|
29915
|
+
0 0 8px var(--glow-primary);
|
|
29916
|
+
transform: scale(1.1);
|
|
29917
|
+
}
|
|
29918
|
+
|
|
29919
|
+
.slider-row input[type='range']:active::-webkit-slider-thumb {
|
|
29920
|
+
transform: scale(0.95);
|
|
27950
29921
|
}
|
|
27951
29922
|
|
|
27952
29923
|
.slider-row input[type='range']::-moz-range-track {
|
|
27953
|
-
height:
|
|
27954
|
-
background:
|
|
27955
|
-
border-radius:
|
|
27956
|
-
border:
|
|
29924
|
+
height: 4px;
|
|
29925
|
+
background: var(--border-glass);
|
|
29926
|
+
border-radius: var(--radius-full, 9999px);
|
|
29927
|
+
border: none;
|
|
29928
|
+
}
|
|
29929
|
+
|
|
29930
|
+
.slider-row input[type='range']::-moz-range-progress {
|
|
29931
|
+
height: 4px;
|
|
29932
|
+
background: var(--accent-primary);
|
|
29933
|
+
border-radius: var(--radius-full, 9999px);
|
|
27957
29934
|
}
|
|
27958
29935
|
|
|
27959
29936
|
.slider-row input[type='range']::-moz-range-thumb {
|
|
27960
|
-
width:
|
|
27961
|
-
height:
|
|
29937
|
+
width: 12px;
|
|
29938
|
+
height: 12px;
|
|
27962
29939
|
background: var(--accent-primary);
|
|
29940
|
+
border: 2px solid var(--bg-panel, var(--bg-glass));
|
|
27963
29941
|
border-radius: 50%;
|
|
27964
29942
|
cursor: pointer;
|
|
27965
|
-
|
|
27966
|
-
|
|
29943
|
+
box-shadow:
|
|
29944
|
+
0 0 0 2px var(--accent-primary),
|
|
29945
|
+
0 1px 4px rgba(0, 0, 0, 0.3);
|
|
29946
|
+
transition:
|
|
29947
|
+
box-shadow 0.15s ease,
|
|
29948
|
+
transform 0.15s ease;
|
|
27967
29949
|
}
|
|
27968
29950
|
|
|
27969
|
-
.slider-
|
|
27970
|
-
|
|
29951
|
+
.slider-row input[type='range']::-moz-range-thumb:hover {
|
|
29952
|
+
box-shadow:
|
|
29953
|
+
0 0 0 3px var(--accent-primary),
|
|
29954
|
+
0 0 8px var(--glow-primary);
|
|
29955
|
+
}
|
|
29956
|
+
|
|
29957
|
+
.slider-number-input {
|
|
29958
|
+
width: 64px;
|
|
27971
29959
|
text-align: center;
|
|
29960
|
+
font-size: var(--text-sm);
|
|
29961
|
+
font-weight: 500;
|
|
29962
|
+
font-variant-numeric: tabular-nums;
|
|
29963
|
+
padding: 4px 6px;
|
|
29964
|
+
background: var(--bg-glass);
|
|
29965
|
+
border: 1px solid var(--border-glass) !important;
|
|
29966
|
+
border-radius: var(--radius-sm);
|
|
29967
|
+
color: var(--t-primary);
|
|
29968
|
+
-moz-appearance: textfield;
|
|
29969
|
+
transition:
|
|
29970
|
+
border-color 0.15s ease,
|
|
29971
|
+
box-shadow 0.15s ease;
|
|
29972
|
+
}
|
|
29973
|
+
|
|
29974
|
+
.slider-number-input::-webkit-outer-spin-button,
|
|
29975
|
+
.slider-number-input::-webkit-inner-spin-button {
|
|
29976
|
+
-webkit-appearance: none;
|
|
29977
|
+
margin: 0;
|
|
29978
|
+
}
|
|
29979
|
+
|
|
29980
|
+
.slider-number-input:focus-visible {
|
|
29981
|
+
outline: none;
|
|
29982
|
+
border-color: var(--accent-primary) !important;
|
|
29983
|
+
box-shadow: 0 0 0 2px var(--glow-primary);
|
|
29984
|
+
}
|
|
29985
|
+
|
|
29986
|
+
/* Clean numeric input — no spinner, mouse wheel support */
|
|
29987
|
+
.number-input-clean {
|
|
29988
|
+
width: 100%;
|
|
29989
|
+
padding: 8px 12px;
|
|
27972
29990
|
font-size: var(--text-md);
|
|
27973
|
-
|
|
29991
|
+
background: var(--bg-glass);
|
|
29992
|
+
border: 1px solid var(--border-glass);
|
|
29993
|
+
border-radius: var(--radius-sm);
|
|
27974
29994
|
color: var(--t-primary);
|
|
27975
|
-
|
|
29995
|
+
appearance: none;
|
|
29996
|
+
-moz-appearance: textfield;
|
|
29997
|
+
-webkit-appearance: none;
|
|
29998
|
+
transition:
|
|
29999
|
+
border-color 0.15s ease,
|
|
30000
|
+
box-shadow 0.15s ease;
|
|
27976
30001
|
}
|
|
27977
30002
|
|
|
27978
|
-
.
|
|
27979
|
-
|
|
27980
|
-
|
|
27981
|
-
|
|
27982
|
-
|
|
27983
|
-
|
|
30003
|
+
.number-input-clean::-webkit-outer-spin-button,
|
|
30004
|
+
.number-input-clean::-webkit-inner-spin-button {
|
|
30005
|
+
-webkit-appearance: none;
|
|
30006
|
+
appearance: none;
|
|
30007
|
+
display: none;
|
|
30008
|
+
margin: 0;
|
|
30009
|
+
}
|
|
30010
|
+
|
|
30011
|
+
.number-input-clean:hover {
|
|
30012
|
+
border-color: var(--accent-primary);
|
|
30013
|
+
}
|
|
30014
|
+
|
|
30015
|
+
.number-input-clean:focus-visible {
|
|
30016
|
+
outline: none;
|
|
30017
|
+
border-color: var(--accent-primary);
|
|
30018
|
+
box-shadow: 0 0 0 2px var(--glow-primary);
|
|
27984
30019
|
}
|
|
27985
30020
|
|
|
27986
30021
|
.range-labels {
|
|
@@ -28029,6 +30064,15 @@ InvokeForm.styles = [
|
|
|
28029
30064
|
flex-shrink: 0;
|
|
28030
30065
|
}
|
|
28031
30066
|
|
|
30067
|
+
select {
|
|
30068
|
+
appearance: none;
|
|
30069
|
+
-webkit-appearance: none;
|
|
30070
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23888'/%3E%3C/svg%3E");
|
|
30071
|
+
background-repeat: no-repeat;
|
|
30072
|
+
background-position: right 12px center;
|
|
30073
|
+
padding-right: 32px;
|
|
30074
|
+
}
|
|
30075
|
+
|
|
28032
30076
|
/* ===== Responsive Design ===== */
|
|
28033
30077
|
@media (max-width: 768px) {
|
|
28034
30078
|
.form-container {
|
|
@@ -28231,7 +30275,7 @@ ActivityLog.styles = [
|
|
|
28231
30275
|
font-size: var(--text-sm);
|
|
28232
30276
|
text-transform: uppercase;
|
|
28233
30277
|
letter-spacing: 0.1em;
|
|
28234
|
-
color: var(--t-
|
|
30278
|
+
color: var(--t-primary);
|
|
28235
30279
|
font-weight: 600;
|
|
28236
30280
|
}
|
|
28237
30281
|
|
|
@@ -28246,7 +30290,7 @@ ActivityLog.styles = [
|
|
|
28246
30290
|
}
|
|
28247
30291
|
|
|
28248
30292
|
.clear-btn:hover {
|
|
28249
|
-
background:
|
|
30293
|
+
background: var(--bg-glass);
|
|
28250
30294
|
color: var(--t-primary);
|
|
28251
30295
|
}
|
|
28252
30296
|
|
|
@@ -28265,14 +30309,14 @@ ActivityLog.styles = [
|
|
|
28265
30309
|
}
|
|
28266
30310
|
|
|
28267
30311
|
.filter-btn:hover {
|
|
28268
|
-
background:
|
|
30312
|
+
background: var(--bg-glass);
|
|
28269
30313
|
color: var(--t-primary);
|
|
28270
30314
|
}
|
|
28271
30315
|
|
|
28272
30316
|
.filter-btn.active {
|
|
28273
30317
|
border-color: var(--accent-secondary);
|
|
28274
30318
|
color: var(--accent-secondary);
|
|
28275
|
-
background:
|
|
30319
|
+
background: var(--bg-glass);
|
|
28276
30320
|
}
|
|
28277
30321
|
|
|
28278
30322
|
.visually-hidden {
|
|
@@ -28332,7 +30376,7 @@ ActivityLog.styles = [
|
|
|
28332
30376
|
display: inline-block;
|
|
28333
30377
|
font-size: var(--text-xs);
|
|
28334
30378
|
color: var(--t-muted);
|
|
28335
|
-
background:
|
|
30379
|
+
background: var(--bg-glass);
|
|
28336
30380
|
padding: 1px 6px;
|
|
28337
30381
|
border-radius: var(--radius-full);
|
|
28338
30382
|
margin-left: var(--space-sm);
|
|
@@ -28491,6 +30535,8 @@ var ResultViewer = class extends i4 {
|
|
|
28491
30535
|
this._previousResult = null;
|
|
28492
30536
|
// Recency heat: track when items were last added/updated
|
|
28493
30537
|
this._itemHeatTimestamps = /* @__PURE__ */ new Map();
|
|
30538
|
+
// Audit trail expansion state: track which items have expanded audit trails
|
|
30539
|
+
this._expandedAuditTrails = /* @__PURE__ */ new Set();
|
|
28494
30540
|
// The detected ID field for the current result (shared across diff, animation, warmth)
|
|
28495
30541
|
this._activeIdField = "id";
|
|
28496
30542
|
// Chart.js instance for reactive updates
|
|
@@ -28793,19 +30839,32 @@ var ResultViewer = class extends i4 {
|
|
|
28793
30839
|
/**
|
|
28794
30840
|
* Get the warmth class based on recency heat.
|
|
28795
30841
|
* Reads timestamp from item data first (survives refresh), falls back to in-memory map.
|
|
30842
|
+
* Prioritizes __meta timestamps (most recent), then standard timestamp fields.
|
|
28796
30843
|
*/
|
|
28797
30844
|
_getItemWarmthClass(item) {
|
|
28798
30845
|
const idField = this._activeIdField;
|
|
28799
30846
|
let timestamp;
|
|
28800
30847
|
if (item && typeof item === "object") {
|
|
28801
30848
|
const rec = item;
|
|
28802
|
-
|
|
28803
|
-
|
|
28804
|
-
if (
|
|
28805
|
-
const parsed =
|
|
28806
|
-
if (!isNaN(parsed))
|
|
28807
|
-
|
|
28808
|
-
|
|
30849
|
+
const meta4 = rec.__meta;
|
|
30850
|
+
if (meta4 && typeof meta4 === "object") {
|
|
30851
|
+
if (meta4.modifiedAt) {
|
|
30852
|
+
const parsed = new Date(meta4.modifiedAt).getTime();
|
|
30853
|
+
if (!isNaN(parsed)) timestamp = parsed;
|
|
30854
|
+
} else if (meta4.createdAt) {
|
|
30855
|
+
const parsed = new Date(meta4.createdAt).getTime();
|
|
30856
|
+
if (!isNaN(parsed)) timestamp = parsed;
|
|
30857
|
+
}
|
|
30858
|
+
}
|
|
30859
|
+
if (timestamp === void 0) {
|
|
30860
|
+
for (const field of ResultViewer._TIMESTAMP_FIELDS) {
|
|
30861
|
+
const val = rec[field];
|
|
30862
|
+
if (val !== void 0 && val !== null) {
|
|
30863
|
+
const parsed = typeof val === "number" ? val : new Date(typeof val === "string" ? val : String(val)).getTime();
|
|
30864
|
+
if (!isNaN(parsed)) {
|
|
30865
|
+
timestamp = parsed;
|
|
30866
|
+
break;
|
|
30867
|
+
}
|
|
28809
30868
|
}
|
|
28810
30869
|
}
|
|
28811
30870
|
}
|
|
@@ -29314,7 +31373,8 @@ var ResultViewer = class extends i4 {
|
|
|
29314
31373
|
"tabs",
|
|
29315
31374
|
"accordion",
|
|
29316
31375
|
"stack",
|
|
29317
|
-
"columns"
|
|
31376
|
+
"columns",
|
|
31377
|
+
"qr"
|
|
29318
31378
|
].includes(format)) {
|
|
29319
31379
|
return format;
|
|
29320
31380
|
}
|
|
@@ -29481,6 +31541,8 @@ var ResultViewer = class extends i4 {
|
|
|
29481
31541
|
return this._renderStack(filteredData);
|
|
29482
31542
|
case "columns":
|
|
29483
31543
|
return this._renderColumns(filteredData);
|
|
31544
|
+
case "qr":
|
|
31545
|
+
return this._renderQR(filteredData);
|
|
29484
31546
|
case "mermaid":
|
|
29485
31547
|
return this._renderMermaid(filteredData);
|
|
29486
31548
|
case "json":
|
|
@@ -29723,6 +31785,136 @@ var ResultViewer = class extends i4 {
|
|
|
29723
31785
|
</div>
|
|
29724
31786
|
`
|
|
29725
31787
|
)}
|
|
31788
|
+
${this._renderAuditTrail(data)}
|
|
31789
|
+
`;
|
|
31790
|
+
}
|
|
31791
|
+
/**
|
|
31792
|
+
* Render audit trail from __meta object if present
|
|
31793
|
+
*/
|
|
31794
|
+
_renderAuditTrail(data) {
|
|
31795
|
+
if (!data || typeof data !== "object") return "";
|
|
31796
|
+
const meta4 = data.__meta;
|
|
31797
|
+
if (!meta4 || typeof meta4 !== "object") return "";
|
|
31798
|
+
const idField = this._activeIdField;
|
|
31799
|
+
const itemId = data[idField] ? String(data[idField]) : Math.random().toString(36);
|
|
31800
|
+
const auditKey = `audit-${itemId}`;
|
|
31801
|
+
const isExpanded = this._expandedAuditTrails.has(auditKey);
|
|
31802
|
+
const formatTime = (isoString) => {
|
|
31803
|
+
if (!isoString) return "N/A";
|
|
31804
|
+
const date4 = new Date(isoString);
|
|
31805
|
+
return date4.toLocaleString();
|
|
31806
|
+
};
|
|
31807
|
+
const createdAt = formatTime(meta4.createdAt);
|
|
31808
|
+
const modifiedAt = meta4.modifiedAt ? formatTime(meta4.modifiedAt) : null;
|
|
31809
|
+
return b2`
|
|
31810
|
+
<div
|
|
31811
|
+
style="margin-top: var(--space-md); border-top: 1px solid var(--border-glass); padding-top: var(--space-md);"
|
|
31812
|
+
>
|
|
31813
|
+
<details
|
|
31814
|
+
?open="${isExpanded}"
|
|
31815
|
+
@toggle="${(e8) => {
|
|
31816
|
+
const detail = e8.target;
|
|
31817
|
+
if (detail.open) {
|
|
31818
|
+
this._expandedAuditTrails.add(auditKey);
|
|
31819
|
+
} else {
|
|
31820
|
+
this._expandedAuditTrails.delete(auditKey);
|
|
31821
|
+
}
|
|
31822
|
+
}}"
|
|
31823
|
+
>
|
|
31824
|
+
<summary
|
|
31825
|
+
style="cursor: pointer; font-weight: 500; display: flex; align-items: center; gap: var(--space-sm);"
|
|
31826
|
+
>
|
|
31827
|
+
<span
|
|
31828
|
+
style="display: inline-block; width: 0.5em; height: 0.5em; border-radius: 50%; background: var(--text-secondary); margin-right: var(--space-xs);"
|
|
31829
|
+
></span>
|
|
31830
|
+
Audit Trail
|
|
31831
|
+
${meta4.modifications?.length ? b2`<span style="font-size: 0.85em; color: var(--text-secondary);"
|
|
31832
|
+
>(${meta4.modifications.length} changes)</span
|
|
31833
|
+
>` : ""}
|
|
31834
|
+
</summary>
|
|
31835
|
+
|
|
31836
|
+
<div
|
|
31837
|
+
style="margin-top: var(--space-md); padding: var(--space-sm) var(--space-md); background: var(--bg-secondary); border-radius: var(--radius-sm);"
|
|
31838
|
+
>
|
|
31839
|
+
<table style="width: 100%; font-size: 0.9em;">
|
|
31840
|
+
<tbody>
|
|
31841
|
+
<tr style="border-bottom: 1px solid var(--border-subtle);">
|
|
31842
|
+
<td
|
|
31843
|
+
style="padding: var(--space-xs); color: var(--text-secondary); font-weight: 500;"
|
|
31844
|
+
>
|
|
31845
|
+
Created
|
|
31846
|
+
</td>
|
|
31847
|
+
<td style="padding: var(--space-xs);">${createdAt}</td>
|
|
31848
|
+
${meta4.createdBy ? b2`<td
|
|
31849
|
+
style="padding: var(--space-xs); color: var(--text-secondary); font-size: 0.85em;"
|
|
31850
|
+
>
|
|
31851
|
+
(by: ${meta4.createdBy})
|
|
31852
|
+
</td>` : ""}
|
|
31853
|
+
</tr>
|
|
31854
|
+
${modifiedAt ? b2`
|
|
31855
|
+
<tr style="border-bottom: 1px solid var(--border-subtle);">
|
|
31856
|
+
<td
|
|
31857
|
+
style="padding: var(--space-xs); color: var(--text-secondary); font-weight: 500;"
|
|
31858
|
+
>
|
|
31859
|
+
Modified
|
|
31860
|
+
</td>
|
|
31861
|
+
<td style="padding: var(--space-xs);">${modifiedAt}</td>
|
|
31862
|
+
${meta4.modifiedBy ? b2`<td
|
|
31863
|
+
style="padding: var(--space-xs); color: var(--text-secondary); font-size: 0.85em;"
|
|
31864
|
+
>
|
|
31865
|
+
(by: ${meta4.modifiedBy})
|
|
31866
|
+
</td>` : ""}
|
|
31867
|
+
</tr>
|
|
31868
|
+
` : ""}
|
|
31869
|
+
</tbody>
|
|
31870
|
+
</table>
|
|
31871
|
+
|
|
31872
|
+
${meta4.modifications && Array.isArray(meta4.modifications) && meta4.modifications.length > 0 ? b2`
|
|
31873
|
+
<div style="margin-top: var(--space-md);">
|
|
31874
|
+
<div
|
|
31875
|
+
style="font-weight: 500; margin-bottom: var(--space-sm); color: var(--text-secondary);"
|
|
31876
|
+
>
|
|
31877
|
+
Changes
|
|
31878
|
+
</div>
|
|
31879
|
+
<ul style="list-style: none; padding: 0; margin: 0;">
|
|
31880
|
+
${meta4.modifications.map(
|
|
31881
|
+
(mod, idx) => b2`
|
|
31882
|
+
<li
|
|
31883
|
+
key="${idx}"
|
|
31884
|
+
style="padding: var(--space-xs) var(--space-sm); margin-bottom: var(--space-xs); background: var(--bg-hover); border-left: 3px solid var(--primary); border-radius: 2px; font-size: 0.9em;"
|
|
31885
|
+
>
|
|
31886
|
+
<div style="margin-bottom: 2px;">
|
|
31887
|
+
<span style="font-weight: 500; color: var(--text-primary);"
|
|
31888
|
+
>${mod.field}</span
|
|
31889
|
+
>
|
|
31890
|
+
<span style="color: var(--text-secondary); margin: 0 var(--space-xs);"
|
|
31891
|
+
>→</span
|
|
31892
|
+
>
|
|
31893
|
+
<span style="color: var(--text-secondary); font-size: 0.85em;"
|
|
31894
|
+
>${formatTime(mod.timestamp || (/* @__PURE__ */ new Date()).toISOString())}</span
|
|
31895
|
+
>
|
|
31896
|
+
</div>
|
|
31897
|
+
<div
|
|
31898
|
+
style="font-family: monospace; font-size: 0.85em; color: var(--text-secondary); margin-left: var(--space-sm);"
|
|
31899
|
+
>
|
|
31900
|
+
<span style="color: #d87070;">${JSON.stringify(mod.oldValue)}</span>
|
|
31901
|
+
<span style="margin: 0 4px;">→</span>
|
|
31902
|
+
<span style="color: #7cb342;">${JSON.stringify(mod.newValue)}</span>
|
|
31903
|
+
</div>
|
|
31904
|
+
${mod.modifiedBy ? b2`<div
|
|
31905
|
+
style="font-size: 0.8em; color: var(--text-secondary); margin-top: 2px;"
|
|
31906
|
+
>
|
|
31907
|
+
<em>by: ${mod.modifiedBy}</em>
|
|
31908
|
+
</div>` : ""}
|
|
31909
|
+
</li>
|
|
31910
|
+
`
|
|
31911
|
+
)}
|
|
31912
|
+
</ul>
|
|
31913
|
+
</div>
|
|
31914
|
+
` : ""}
|
|
31915
|
+
</div>
|
|
31916
|
+
</details>
|
|
31917
|
+
</div>
|
|
29726
31918
|
`;
|
|
29727
31919
|
}
|
|
29728
31920
|
/** Returns true for arrays of objects or large nested objects that deserve their own section */
|
|
@@ -30181,6 +32373,163 @@ ${code}</pre>`;
|
|
|
30181
32373
|
style="position: relative; background: ${bgColor}; border-radius: var(--radius-sm); padding: 16px; margin: 16px 0; min-height: 120px;"
|
|
30182
32374
|
></div>`;
|
|
30183
32375
|
}
|
|
32376
|
+
_renderQR(data) {
|
|
32377
|
+
const text = typeof data === "object" && data !== null ? String(data.url || data.link || data.value || JSON.stringify(data)) : String(data);
|
|
32378
|
+
const isUrl = /^https?:\/\//i.test(text);
|
|
32379
|
+
const isEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(text);
|
|
32380
|
+
const isPhone = /^[+]?[\d\s\-().]{7,}$/.test(text.trim());
|
|
32381
|
+
let href = "";
|
|
32382
|
+
let linkLabel = text;
|
|
32383
|
+
if (isUrl) {
|
|
32384
|
+
href = text;
|
|
32385
|
+
try {
|
|
32386
|
+
linkLabel = new URL(text).hostname + new URL(text).pathname;
|
|
32387
|
+
} catch {
|
|
32388
|
+
}
|
|
32389
|
+
} else if (isEmail) {
|
|
32390
|
+
href = `mailto:${text}`;
|
|
32391
|
+
} else if (isPhone) {
|
|
32392
|
+
href = `tel:${text.replace(/[\s\-().]/g, "")}`;
|
|
32393
|
+
}
|
|
32394
|
+
setTimeout(() => {
|
|
32395
|
+
if (this._qrContainer) {
|
|
32396
|
+
this._qrContainer.innerHTML = "";
|
|
32397
|
+
try {
|
|
32398
|
+
const containerWidth = this._qrContainer.clientWidth;
|
|
32399
|
+
const qrSize = Math.max(200, Math.min(containerWidth - 48, 400));
|
|
32400
|
+
new window.QRCode(this._qrContainer, {
|
|
32401
|
+
text,
|
|
32402
|
+
width: qrSize,
|
|
32403
|
+
height: qrSize,
|
|
32404
|
+
correctLevel: window.QRCode?.CorrectLevel?.H,
|
|
32405
|
+
colorDark: "#000000",
|
|
32406
|
+
colorLight: "#ffffff"
|
|
32407
|
+
});
|
|
32408
|
+
} catch (error2) {
|
|
32409
|
+
console.error("Failed to generate QR code:", error2);
|
|
32410
|
+
}
|
|
32411
|
+
}
|
|
32412
|
+
}, 0);
|
|
32413
|
+
const message = typeof data === "object" && data !== null ? data.message : void 0;
|
|
32414
|
+
const extraFields = [];
|
|
32415
|
+
if (typeof data === "object" && data !== null) {
|
|
32416
|
+
for (const [k3, v2] of Object.entries(data)) {
|
|
32417
|
+
if (["url", "link", "value", "message", "port"].includes(k3) || v2 == null || typeof v2 === "object")
|
|
32418
|
+
continue;
|
|
32419
|
+
extraFields.push({ label: k3, value: `${v2}` });
|
|
32420
|
+
}
|
|
32421
|
+
}
|
|
32422
|
+
return b2`<div
|
|
32423
|
+
style="
|
|
32424
|
+
display: flex; flex-direction: column; align-items: center; gap: 0;
|
|
32425
|
+
padding: 0; border-radius: var(--radius-md);
|
|
32426
|
+
border: 1px solid var(--border-glass);
|
|
32427
|
+
background: var(--bg-subtle); overflow: hidden;
|
|
32428
|
+
width: 40%; min-width: 280px; max-width: 480px;
|
|
32429
|
+
margin: 16px auto;
|
|
32430
|
+
"
|
|
32431
|
+
>
|
|
32432
|
+
<div
|
|
32433
|
+
id="qr-container"
|
|
32434
|
+
style="
|
|
32435
|
+
width: 100%; padding: 24px;
|
|
32436
|
+
display: flex; justify-content: center; align-items: center;
|
|
32437
|
+
background: #ffffff; border-radius: var(--radius-md) var(--radius-md) 0 0;
|
|
32438
|
+
"
|
|
32439
|
+
></div>
|
|
32440
|
+
|
|
32441
|
+
<div
|
|
32442
|
+
style="
|
|
32443
|
+
width: 100%; padding: 16px 20px;
|
|
32444
|
+
display: flex; flex-direction: column; gap: 10px;
|
|
32445
|
+
border-top: 1px solid var(--border-glass);
|
|
32446
|
+
"
|
|
32447
|
+
>
|
|
32448
|
+
${message ? b2`<div
|
|
32449
|
+
style="
|
|
32450
|
+
font-size: 0.8rem; color: var(--t-secondary, #a0a0a0);
|
|
32451
|
+
text-align: center; font-weight: 500;
|
|
32452
|
+
"
|
|
32453
|
+
>
|
|
32454
|
+
${message}
|
|
32455
|
+
</div>` : ""}
|
|
32456
|
+
${href ? b2`<div
|
|
32457
|
+
style="display: flex; align-items: center; gap: 10px; justify-content: center;"
|
|
32458
|
+
>
|
|
32459
|
+
<a
|
|
32460
|
+
href="${href}"
|
|
32461
|
+
target="_blank"
|
|
32462
|
+
rel="noopener noreferrer"
|
|
32463
|
+
style="
|
|
32464
|
+
font-size: 0.85rem; color: var(--accent, #3b82f6);
|
|
32465
|
+
text-decoration: none; font-weight: 500;
|
|
32466
|
+
text-align: center; word-break: break-word;
|
|
32467
|
+
"
|
|
32468
|
+
@mouseenter=${(e8) => e8.target.style.textDecoration = "underline"}
|
|
32469
|
+
@mouseleave=${(e8) => e8.target.style.textDecoration = "none"}
|
|
32470
|
+
>${linkLabel}</a
|
|
32471
|
+
>
|
|
32472
|
+
<button
|
|
32473
|
+
title="Copy to clipboard"
|
|
32474
|
+
style="
|
|
32475
|
+
background: var(--bg-subtle, rgba(255,255,255,0.06));
|
|
32476
|
+
border: 1px solid var(--border-glass);
|
|
32477
|
+
border-radius: 6px; padding: 6px 10px; cursor: pointer;
|
|
32478
|
+
color: var(--t-muted); font-size: 0.85rem; flex-shrink: 0;
|
|
32479
|
+
transition: all 0.15s; line-height: 1;
|
|
32480
|
+
"
|
|
32481
|
+
@mouseenter=${(e8) => {
|
|
32482
|
+
e8.target.style.color = "var(--accent, #3b82f6)";
|
|
32483
|
+
e8.target.style.borderColor = "var(--accent, #3b82f6)";
|
|
32484
|
+
}}
|
|
32485
|
+
@mouseleave=${(e8) => {
|
|
32486
|
+
e8.target.style.color = "var(--t-muted)";
|
|
32487
|
+
e8.target.style.borderColor = "var(--border-glass)";
|
|
32488
|
+
}}
|
|
32489
|
+
@click=${(e8) => {
|
|
32490
|
+
void navigator.clipboard.writeText(text);
|
|
32491
|
+
const btn = e8.target;
|
|
32492
|
+
const orig = btn.textContent;
|
|
32493
|
+
btn.textContent = "\u2713 Copied";
|
|
32494
|
+
btn.style.color = "var(--accent, #3b82f6)";
|
|
32495
|
+
setTimeout(() => {
|
|
32496
|
+
btn.textContent = orig;
|
|
32497
|
+
btn.style.color = "var(--t-muted)";
|
|
32498
|
+
}, 1500);
|
|
32499
|
+
}}
|
|
32500
|
+
>
|
|
32501
|
+
Copy
|
|
32502
|
+
</button>
|
|
32503
|
+
</div>` : b2`<div
|
|
32504
|
+
style="
|
|
32505
|
+
font-size: 0.875rem; color: var(--t-muted);
|
|
32506
|
+
text-align: center; word-break: break-all;
|
|
32507
|
+
"
|
|
32508
|
+
>
|
|
32509
|
+
${text}
|
|
32510
|
+
</div>`}
|
|
32511
|
+
${extraFields.length > 0 ? b2`<div
|
|
32512
|
+
style="
|
|
32513
|
+
display: flex; flex-direction: column; gap: 6px;
|
|
32514
|
+
padding-top: 10px; border-top: 1px solid var(--border-glass);
|
|
32515
|
+
font-size: 0.8rem;
|
|
32516
|
+
"
|
|
32517
|
+
>
|
|
32518
|
+
${extraFields.map(
|
|
32519
|
+
(f5) => b2`<div style="display: flex; justify-content: space-between; gap: 12px;">
|
|
32520
|
+
<span style="color: var(--t-muted); text-transform: capitalize;"
|
|
32521
|
+
>${f5.label}</span
|
|
32522
|
+
>
|
|
32523
|
+
<span
|
|
32524
|
+
style="color: var(--t-primary); font-family: var(--font-mono, monospace); word-break: break-all; text-align: right;"
|
|
32525
|
+
>${f5.value}</span
|
|
32526
|
+
>
|
|
32527
|
+
</div>`
|
|
32528
|
+
)}
|
|
32529
|
+
</div>` : ""}
|
|
32530
|
+
</div>
|
|
32531
|
+
</div>`;
|
|
32532
|
+
}
|
|
30184
32533
|
_renderText(data) {
|
|
30185
32534
|
const text = String(data);
|
|
30186
32535
|
if (this._isMermaidString(text)) {
|
|
@@ -31440,7 +33789,7 @@ ResultViewer.styles = [
|
|
|
31440
33789
|
}
|
|
31441
33790
|
|
|
31442
33791
|
button:hover {
|
|
31443
|
-
background:
|
|
33792
|
+
background: var(--bg-glass);
|
|
31444
33793
|
color: var(--t-primary);
|
|
31445
33794
|
}
|
|
31446
33795
|
|
|
@@ -31591,7 +33940,7 @@ ResultViewer.styles = [
|
|
|
31591
33940
|
}
|
|
31592
33941
|
|
|
31593
33942
|
.smart-table tr:hover td {
|
|
31594
|
-
background:
|
|
33943
|
+
background: var(--bg-glass);
|
|
31595
33944
|
}
|
|
31596
33945
|
|
|
31597
33946
|
/* Key-Value Table (single object) */
|
|
@@ -32278,7 +34627,7 @@ ResultViewer.styles = [
|
|
|
32278
34627
|
}
|
|
32279
34628
|
|
|
32280
34629
|
.tree-item:hover {
|
|
32281
|
-
background:
|
|
34630
|
+
background: var(--bg-glass);
|
|
32282
34631
|
}
|
|
32283
34632
|
|
|
32284
34633
|
.tree-toggle {
|
|
@@ -32307,16 +34656,16 @@ ResultViewer.styles = [
|
|
|
32307
34656
|
}
|
|
32308
34657
|
|
|
32309
34658
|
.tree-value.string {
|
|
32310
|
-
color:
|
|
34659
|
+
color: var(--syntax-string);
|
|
32311
34660
|
}
|
|
32312
34661
|
.tree-value.number {
|
|
32313
|
-
color:
|
|
34662
|
+
color: var(--syntax-number);
|
|
32314
34663
|
}
|
|
32315
34664
|
.tree-value.boolean {
|
|
32316
|
-
color:
|
|
34665
|
+
color: var(--syntax-boolean);
|
|
32317
34666
|
}
|
|
32318
34667
|
.tree-value.null {
|
|
32319
|
-
color:
|
|
34668
|
+
color: var(--syntax-null);
|
|
32320
34669
|
}
|
|
32321
34670
|
|
|
32322
34671
|
.tree-type {
|
|
@@ -32578,9 +34927,9 @@ ResultViewer.styles = [
|
|
|
32578
34927
|
}
|
|
32579
34928
|
|
|
32580
34929
|
.expand-btn:hover {
|
|
32581
|
-
background: var(--primary);
|
|
34930
|
+
background: var(--accent-primary);
|
|
32582
34931
|
color: white;
|
|
32583
|
-
border-color: var(--primary);
|
|
34932
|
+
border-color: var(--accent-primary);
|
|
32584
34933
|
}
|
|
32585
34934
|
|
|
32586
34935
|
/* Markdown items (array rendering with filter transitions) */
|
|
@@ -32818,13 +35167,13 @@ ResultViewer.styles = [
|
|
|
32818
35167
|
}
|
|
32819
35168
|
|
|
32820
35169
|
.metric-delta.up {
|
|
32821
|
-
color:
|
|
32822
|
-
background:
|
|
35170
|
+
color: var(--color-success);
|
|
35171
|
+
background: var(--color-success-bg);
|
|
32823
35172
|
}
|
|
32824
35173
|
|
|
32825
35174
|
.metric-delta.down {
|
|
32826
|
-
color:
|
|
32827
|
-
background:
|
|
35175
|
+
color: var(--color-error);
|
|
35176
|
+
background: var(--color-error-bg);
|
|
32828
35177
|
}
|
|
32829
35178
|
|
|
32830
35179
|
.metric-delta.neutral {
|
|
@@ -32959,7 +35308,7 @@ ResultViewer.styles = [
|
|
|
32959
35308
|
|
|
32960
35309
|
.timeline-description {
|
|
32961
35310
|
font-size: var(--text-md);
|
|
32962
|
-
color: var(--t-
|
|
35311
|
+
color: var(--t-muted);
|
|
32963
35312
|
margin-top: 2px;
|
|
32964
35313
|
line-height: 1.4;
|
|
32965
35314
|
}
|
|
@@ -33106,7 +35455,7 @@ ResultViewer.styles = [
|
|
|
33106
35455
|
justify-content: space-between;
|
|
33107
35456
|
padding: 4px 0;
|
|
33108
35457
|
font-size: var(--text-md);
|
|
33109
|
-
color: var(--t-
|
|
35458
|
+
color: var(--t-muted);
|
|
33110
35459
|
}
|
|
33111
35460
|
|
|
33112
35461
|
.cart-summary-row.total {
|
|
@@ -33384,6 +35733,9 @@ __decorateClass([
|
|
|
33384
35733
|
__decorateClass([
|
|
33385
35734
|
r5()
|
|
33386
35735
|
], ResultViewer.prototype, "_internalResult", 2);
|
|
35736
|
+
__decorateClass([
|
|
35737
|
+
e7("#qr-container")
|
|
35738
|
+
], ResultViewer.prototype, "_qrContainer", 2);
|
|
33387
35739
|
__decorateClass([
|
|
33388
35740
|
n4({ type: String })
|
|
33389
35741
|
], ResultViewer.prototype, "collectionProperty", 2);
|
|
@@ -83453,9 +85805,13 @@ var ElicitationModal = class extends i4 {
|
|
|
83453
85805
|
min="${min}"
|
|
83454
85806
|
max="${max}"
|
|
83455
85807
|
step="${step}"
|
|
85808
|
+
style="${this._sliderFillStyle(Number(currentValue), min, max)}"
|
|
83456
85809
|
.value=${String(currentValue)}
|
|
83457
85810
|
@input=${(e8) => {
|
|
83458
|
-
|
|
85811
|
+
const el2 = e8.target;
|
|
85812
|
+
const v2 = this._sanitizeSliderValue(Number(el2.value), min, max, step);
|
|
85813
|
+
el2.style.cssText = this._sliderFillStyle(v2, min, max);
|
|
85814
|
+
this._inputValue = v2;
|
|
83459
85815
|
}}
|
|
83460
85816
|
/>
|
|
83461
85817
|
<input
|
|
@@ -83466,7 +85822,15 @@ var ElicitationModal = class extends i4 {
|
|
|
83466
85822
|
step="${step}"
|
|
83467
85823
|
.value=${String(currentValue)}
|
|
83468
85824
|
@input=${(e8) => {
|
|
83469
|
-
|
|
85825
|
+
const raw = e8.target.value;
|
|
85826
|
+
if (raw === "" || raw === "-") return;
|
|
85827
|
+
this._inputValue = Number(raw);
|
|
85828
|
+
}}
|
|
85829
|
+
@change=${(e8) => {
|
|
85830
|
+
const el2 = e8.target;
|
|
85831
|
+
const v2 = this._sanitizeSliderValue(Number(el2.value), min, max, step);
|
|
85832
|
+
el2.value = String(v2);
|
|
85833
|
+
this._inputValue = v2;
|
|
83470
85834
|
}}
|
|
83471
85835
|
@keydown=${(e8) => this._handleKeydown(e8)}
|
|
83472
85836
|
autofocus
|
|
@@ -83710,9 +86074,13 @@ var ElicitationModal = class extends i4 {
|
|
|
83710
86074
|
min="${min}"
|
|
83711
86075
|
max="${max}"
|
|
83712
86076
|
step="${step}"
|
|
86077
|
+
style="${this._sliderFillStyle(Number(currentValue), min, max)}"
|
|
83713
86078
|
.value=${String(currentValue)}
|
|
83714
86079
|
@input=${(e8) => {
|
|
83715
|
-
|
|
86080
|
+
const el2 = e8.target;
|
|
86081
|
+
const v2 = this._sanitizeSliderValue(Number(el2.value), min, max, step);
|
|
86082
|
+
el2.style.cssText = this._sliderFillStyle(v2, min, max);
|
|
86083
|
+
this._updateFormValue(field.name, v2);
|
|
83716
86084
|
}}
|
|
83717
86085
|
/>
|
|
83718
86086
|
<input
|
|
@@ -83723,7 +86091,15 @@ var ElicitationModal = class extends i4 {
|
|
|
83723
86091
|
step="${step}"
|
|
83724
86092
|
.value=${String(currentValue)}
|
|
83725
86093
|
@input=${(e8) => {
|
|
83726
|
-
|
|
86094
|
+
const raw = e8.target.value;
|
|
86095
|
+
if (raw === "" || raw === "-") return;
|
|
86096
|
+
this._updateFormValue(field.name, Number(raw));
|
|
86097
|
+
}}
|
|
86098
|
+
@change=${(e8) => {
|
|
86099
|
+
const el2 = e8.target;
|
|
86100
|
+
const v2 = this._sanitizeSliderValue(Number(el2.value), min, max, step);
|
|
86101
|
+
el2.value = String(v2);
|
|
86102
|
+
this._updateFormValue(field.name, v2);
|
|
83727
86103
|
}}
|
|
83728
86104
|
/>
|
|
83729
86105
|
</div>
|
|
@@ -83744,6 +86120,23 @@ var ElicitationModal = class extends i4 {
|
|
|
83744
86120
|
/>
|
|
83745
86121
|
`;
|
|
83746
86122
|
}
|
|
86123
|
+
_sliderFillStyle(value, min, max) {
|
|
86124
|
+
const pct = max > min ? (value - min) / (max - min) * 100 : 0;
|
|
86125
|
+
return `background: linear-gradient(to right, var(--accent-primary) ${pct}%, var(--border-glass) ${pct}%)`;
|
|
86126
|
+
}
|
|
86127
|
+
/** Clamp to [min, max] and round to nearest step (integer-safe). */
|
|
86128
|
+
_sanitizeSliderValue(raw, min, max, step) {
|
|
86129
|
+
let v2 = Number.isFinite(raw) ? raw : min;
|
|
86130
|
+
v2 = Math.min(max, Math.max(min, v2));
|
|
86131
|
+
if (step > 0) {
|
|
86132
|
+
v2 = min + Math.round((v2 - min) / step) * step;
|
|
86133
|
+
if (v2 > max) v2 = max;
|
|
86134
|
+
}
|
|
86135
|
+
if (Number.isInteger(step) && step >= 1) {
|
|
86136
|
+
v2 = Math.round(v2);
|
|
86137
|
+
}
|
|
86138
|
+
return v2;
|
|
86139
|
+
}
|
|
83747
86140
|
_updateFormValue(name2, value) {
|
|
83748
86141
|
this._formValues = { ...this._formValues, [name2]: value };
|
|
83749
86142
|
}
|
|
@@ -83868,11 +86261,19 @@ ElicitationModal.styles = [
|
|
|
83868
86261
|
color: white;
|
|
83869
86262
|
}
|
|
83870
86263
|
|
|
86264
|
+
.btn-success:hover {
|
|
86265
|
+
filter: brightness(1.1);
|
|
86266
|
+
}
|
|
86267
|
+
|
|
83871
86268
|
.btn-danger {
|
|
83872
86269
|
background: var(--color-error);
|
|
83873
86270
|
color: white;
|
|
83874
86271
|
}
|
|
83875
86272
|
|
|
86273
|
+
.btn-danger:hover {
|
|
86274
|
+
filter: brightness(1.1);
|
|
86275
|
+
}
|
|
86276
|
+
|
|
83876
86277
|
/* Confirm buttons */
|
|
83877
86278
|
.confirm-actions {
|
|
83878
86279
|
display: flex;
|
|
@@ -83982,7 +86383,7 @@ ElicitationModal.styles = [
|
|
|
83982
86383
|
.slider-group {
|
|
83983
86384
|
display: flex;
|
|
83984
86385
|
flex-direction: column;
|
|
83985
|
-
gap:
|
|
86386
|
+
gap: 4px;
|
|
83986
86387
|
}
|
|
83987
86388
|
|
|
83988
86389
|
.slider-row {
|
|
@@ -83993,47 +86394,104 @@ ElicitationModal.styles = [
|
|
|
83993
86394
|
|
|
83994
86395
|
.slider-row input[type='range'] {
|
|
83995
86396
|
flex: 1;
|
|
83996
|
-
height:
|
|
83997
|
-
|
|
83998
|
-
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
83999
|
-
border-radius: 3px;
|
|
86397
|
+
height: 4px;
|
|
86398
|
+
border-radius: var(--radius-full, 9999px);
|
|
84000
86399
|
-webkit-appearance: none;
|
|
84001
86400
|
cursor: pointer;
|
|
84002
86401
|
margin: 8px 0;
|
|
86402
|
+
border: none;
|
|
86403
|
+
outline: none;
|
|
86404
|
+
background: var(--border-glass);
|
|
84003
86405
|
}
|
|
84004
86406
|
|
|
84005
86407
|
.slider-row input[type='range']::-webkit-slider-thumb {
|
|
84006
86408
|
-webkit-appearance: none;
|
|
84007
|
-
width:
|
|
84008
|
-
height:
|
|
86409
|
+
width: 16px;
|
|
86410
|
+
height: 16px;
|
|
84009
86411
|
background: var(--accent-primary);
|
|
86412
|
+
border: 2px solid var(--bg-panel, var(--bg-glass));
|
|
84010
86413
|
border-radius: 50%;
|
|
84011
86414
|
cursor: pointer;
|
|
84012
|
-
box-shadow:
|
|
86415
|
+
box-shadow:
|
|
86416
|
+
0 0 0 2px var(--accent-primary),
|
|
86417
|
+
0 1px 4px rgba(0, 0, 0, 0.3);
|
|
86418
|
+
transition:
|
|
86419
|
+
box-shadow 0.15s ease,
|
|
86420
|
+
transform 0.15s ease;
|
|
86421
|
+
}
|
|
86422
|
+
|
|
86423
|
+
.slider-row input[type='range']::-webkit-slider-thumb:hover {
|
|
86424
|
+
box-shadow:
|
|
86425
|
+
0 0 0 3px var(--accent-primary),
|
|
86426
|
+
0 0 8px var(--glow-primary);
|
|
86427
|
+
transform: scale(1.1);
|
|
86428
|
+
}
|
|
86429
|
+
|
|
86430
|
+
.slider-row input[type='range']:active::-webkit-slider-thumb {
|
|
86431
|
+
transform: scale(0.95);
|
|
84013
86432
|
}
|
|
84014
86433
|
|
|
84015
86434
|
.slider-row input[type='range']::-moz-range-track {
|
|
84016
|
-
height:
|
|
84017
|
-
background:
|
|
84018
|
-
border-radius:
|
|
84019
|
-
border:
|
|
86435
|
+
height: 4px;
|
|
86436
|
+
background: var(--border-glass);
|
|
86437
|
+
border-radius: var(--radius-full, 9999px);
|
|
86438
|
+
border: none;
|
|
86439
|
+
}
|
|
86440
|
+
|
|
86441
|
+
.slider-row input[type='range']::-moz-range-progress {
|
|
86442
|
+
height: 4px;
|
|
86443
|
+
background: var(--accent-primary);
|
|
86444
|
+
border-radius: var(--radius-full, 9999px);
|
|
84020
86445
|
}
|
|
84021
86446
|
|
|
84022
86447
|
.slider-row input[type='range']::-moz-range-thumb {
|
|
84023
|
-
width:
|
|
84024
|
-
height:
|
|
86448
|
+
width: 12px;
|
|
86449
|
+
height: 12px;
|
|
84025
86450
|
background: var(--accent-primary);
|
|
86451
|
+
border: 2px solid var(--bg-panel, var(--bg-glass));
|
|
84026
86452
|
border-radius: 50%;
|
|
84027
86453
|
cursor: pointer;
|
|
84028
|
-
|
|
84029
|
-
|
|
86454
|
+
box-shadow:
|
|
86455
|
+
0 0 0 2px var(--accent-primary),
|
|
86456
|
+
0 1px 4px rgba(0, 0, 0, 0.3);
|
|
86457
|
+
transition:
|
|
86458
|
+
box-shadow 0.15s ease,
|
|
86459
|
+
transform 0.15s ease;
|
|
86460
|
+
}
|
|
86461
|
+
|
|
86462
|
+
.slider-row input[type='range']::-moz-range-thumb:hover {
|
|
86463
|
+
box-shadow:
|
|
86464
|
+
0 0 0 3px var(--accent-primary),
|
|
86465
|
+
0 0 8px var(--glow-primary);
|
|
84030
86466
|
}
|
|
84031
86467
|
|
|
84032
86468
|
.slider-number-input {
|
|
84033
|
-
width:
|
|
84034
|
-
text-align:
|
|
86469
|
+
width: 64px;
|
|
86470
|
+
text-align: center;
|
|
84035
86471
|
font-size: var(--text-sm);
|
|
84036
|
-
|
|
86472
|
+
font-weight: 500;
|
|
86473
|
+
font-variant-numeric: tabular-nums;
|
|
86474
|
+
padding: 4px 6px;
|
|
86475
|
+
background: var(--bg-glass);
|
|
86476
|
+
border: 1px solid var(--border-glass) !important;
|
|
86477
|
+
border-radius: var(--radius-sm);
|
|
86478
|
+
color: var(--t-primary);
|
|
86479
|
+
-moz-appearance: textfield;
|
|
86480
|
+
transition:
|
|
86481
|
+
border-color 0.15s ease,
|
|
86482
|
+
box-shadow 0.15s ease;
|
|
86483
|
+
}
|
|
86484
|
+
|
|
86485
|
+
.slider-number-input::-webkit-outer-spin-button,
|
|
86486
|
+
.slider-number-input::-webkit-inner-spin-button {
|
|
86487
|
+
-webkit-appearance: none;
|
|
86488
|
+
margin: 0;
|
|
86489
|
+
}
|
|
86490
|
+
|
|
86491
|
+
.slider-number-input:focus-visible {
|
|
86492
|
+
outline: none;
|
|
86493
|
+
border-color: var(--accent-primary) !important;
|
|
86494
|
+
box-shadow: 0 0 0 2px var(--glow-primary);
|
|
84037
86495
|
}
|
|
84038
86496
|
|
|
84039
86497
|
.range-labels {
|
|
@@ -84092,7 +86550,13 @@ ElicitationModal.styles = [
|
|
|
84092
86550
|
background: var(--bg-glass-strong);
|
|
84093
86551
|
border-radius: 12px;
|
|
84094
86552
|
cursor: pointer;
|
|
84095
|
-
transition:
|
|
86553
|
+
transition:
|
|
86554
|
+
background 0.2s,
|
|
86555
|
+
box-shadow 0.2s;
|
|
86556
|
+
}
|
|
86557
|
+
|
|
86558
|
+
.toggle-track:hover {
|
|
86559
|
+
background: var(--bg-glass);
|
|
84096
86560
|
}
|
|
84097
86561
|
|
|
84098
86562
|
.toggle-track::after {
|
|
@@ -84111,6 +86575,14 @@ ElicitationModal.styles = [
|
|
|
84111
86575
|
background: var(--accent-primary);
|
|
84112
86576
|
}
|
|
84113
86577
|
|
|
86578
|
+
.toggle-switch input:checked + .toggle-track:hover {
|
|
86579
|
+
background: var(--accent-secondary);
|
|
86580
|
+
}
|
|
86581
|
+
|
|
86582
|
+
.toggle-switch input:focus-visible + .toggle-track {
|
|
86583
|
+
box-shadow: 0 0 0 2px var(--glow-primary);
|
|
86584
|
+
}
|
|
86585
|
+
|
|
84114
86586
|
.toggle-switch input:checked + .toggle-track::after {
|
|
84115
86587
|
transform: translateX(20px);
|
|
84116
86588
|
}
|
|
@@ -84246,7 +86718,7 @@ var OverflowMenu = class extends i4 {
|
|
|
84246
86718
|
return b2`
|
|
84247
86719
|
<button
|
|
84248
86720
|
class="trigger"
|
|
84249
|
-
@click=${() => this._toggle()}
|
|
86721
|
+
@click=${(e8) => this._toggle(e8)}
|
|
84250
86722
|
title="More actions"
|
|
84251
86723
|
aria-label="More actions"
|
|
84252
86724
|
>
|
|
@@ -85753,7 +88225,7 @@ ContextBar.styles = [
|
|
|
85753
88225
|
backdrop-filter: blur(20px);
|
|
85754
88226
|
border: 1px solid var(--border-glass);
|
|
85755
88227
|
border-radius: var(--radius-md);
|
|
85756
|
-
box-shadow:
|
|
88228
|
+
box-shadow: var(--shadow-lg);
|
|
85757
88229
|
padding: 4px;
|
|
85758
88230
|
z-index: 100;
|
|
85759
88231
|
}
|
|
@@ -85764,7 +88236,7 @@ ContextBar.styles = [
|
|
|
85764
88236
|
padding: 6px 10px;
|
|
85765
88237
|
border: none;
|
|
85766
88238
|
background: none;
|
|
85767
|
-
color: var(--t-
|
|
88239
|
+
color: var(--t-muted);
|
|
85768
88240
|
font-size: var(--text-sm);
|
|
85769
88241
|
font-family: inherit;
|
|
85770
88242
|
text-align: left;
|
|
@@ -85790,7 +88262,7 @@ ContextBar.styles = [
|
|
|
85790
88262
|
font-size: var(--text-2xs);
|
|
85791
88263
|
font-weight: 700;
|
|
85792
88264
|
letter-spacing: 0.08em;
|
|
85793
|
-
color:
|
|
88265
|
+
color: var(--color-success);
|
|
85794
88266
|
text-transform: uppercase;
|
|
85795
88267
|
margin-left: auto;
|
|
85796
88268
|
}
|
|
@@ -85799,8 +88271,8 @@ ContextBar.styles = [
|
|
|
85799
88271
|
width: 6px;
|
|
85800
88272
|
height: 6px;
|
|
85801
88273
|
border-radius: 50%;
|
|
85802
|
-
background:
|
|
85803
|
-
box-shadow: 0 0 6px 2px
|
|
88274
|
+
background: var(--color-success);
|
|
88275
|
+
box-shadow: 0 0 6px 2px var(--color-success-glow);
|
|
85804
88276
|
animation: live-pulse 2s ease-in-out infinite;
|
|
85805
88277
|
}
|
|
85806
88278
|
|
|
@@ -85808,11 +88280,11 @@ ContextBar.styles = [
|
|
|
85808
88280
|
0%,
|
|
85809
88281
|
100% {
|
|
85810
88282
|
opacity: 1;
|
|
85811
|
-
box-shadow: 0 0 6px 2px
|
|
88283
|
+
box-shadow: 0 0 6px 2px var(--color-success-glow);
|
|
85812
88284
|
}
|
|
85813
88285
|
50% {
|
|
85814
88286
|
opacity: 0.5;
|
|
85815
|
-
box-shadow: 0 0 3px 1px
|
|
88287
|
+
box-shadow: 0 0 3px 1px var(--color-success-glow);
|
|
85816
88288
|
}
|
|
85817
88289
|
}
|
|
85818
88290
|
|