@oomol-lab/open-flow 0.1.0-beta.81 → 0.1.0-beta.83

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +35 -0
  2. package/dist/browser/{FlowCanvas-CrsiDHK8.js → FlowCanvas-ChbukrDh.js} +879 -535
  3. package/dist/browser/{createResourceDialog-CS3u9ga9.js → createResourceDialog-Bi4fUnbD.js} +5 -4
  4. package/dist/browser/{dialog-CFlvkliO.js → dialog-BzoSxhXQ.js} +1 -1
  5. package/dist/browser/{exportPng-BOPfjeEi.js → exportPng-CrAFfOaD.js} +187 -70
  6. package/dist/browser/{flowChanges-CFj5pL4Y.js → flowChanges-C567g-Pc.js} +2675 -93
  7. package/dist/browser/{flowWorkspace-BeQaeJ3e.js → flowWorkspace-rvcneG4q.js} +980 -2621
  8. package/dist/browser/licenses.md +2 -2
  9. package/dist/browser/{markdownContent-frwDfQQU.js → markdownContent-B-GLj5DU.js} +18 -40
  10. package/dist/browser/{markdownContent-CAG_CQfH.js → markdownContent-D8G_oNOe.js} +18 -41
  11. package/dist/browser/preview.css +125 -80
  12. package/dist/browser/preview.js +1093 -379
  13. package/dist/browser/{tooltip-BDcVTNpu.js → tooltip-DGj5pudg.js} +1 -1
  14. package/dist/browser/ui.css +45 -0
  15. package/dist/browser/{dist-CHwj9BhV.js → videoLink-NAWDmBtf.js} +35 -1
  16. package/dist/browser/workbench-contract.d.ts +6 -0
  17. package/dist/browser/workbench.css +296 -251
  18. package/dist/browser/workbench.d.ts +2 -0
  19. package/dist/browser/workbench.js +294 -141
  20. package/dist/browser/{workbenchSelect-Ci0KCYv9.js → workbenchSelect-BIaEVTx6.js} +2 -2
  21. package/dist/browser/{ContentIcon-CMn0c-kl.js → wrapLayout-C4moMKgb.js} +4400 -4148
  22. package/dist/command/index.js +43 -41
  23. package/dist/common/authoring.d.ts +1 -1
  24. package/dist/common/control-api-conformance.js +306 -2
  25. package/dist/common/control-api.d.ts +20 -0
  26. package/dist/common/control-api.js +306 -4
  27. package/dist/common/control-requests.d.ts +3 -5
  28. package/dist/common/control-requests.js +5 -7
  29. package/dist/common/flow-encoding.d.ts +1 -0
  30. package/dist/common/flow-encoding.js +167 -1
  31. package/dist/common/flow-semantics.js +20 -0
  32. package/dist/common/flow-workflowBundle.d.ts +27 -0
  33. package/dist/common/flow-workflowFile.d.ts +2 -0
  34. package/dist/common/flow-workflowReferences.d.ts +4 -0
  35. package/dist/common/mcp.d.ts +2 -0
  36. package/dist/common/mcp.js +312 -4
  37. package/dist/render/browser/licenses.md +4047 -0
  38. package/dist/render/browser/runtime.css +14914 -0
  39. package/dist/render/browser/runtime.js +267526 -0
  40. package/dist/render/common/png.d.ts +32 -0
  41. package/dist/render/node/index.d.ts +11 -0
  42. package/dist/render/node/index.js +9508 -0
  43. package/dist/render/node/licenses.md +75 -0
  44. package/package.json +12 -2
  45. package/src/control/common/api.ts +50 -0
  46. package/src/control/common/flowDecoders.ts +2 -0
  47. package/src/control/common/mcp.ts +4 -4
  48. package/src/control/common/requests.ts +12 -1
  49. package/src/flow/common/encoding.ts +1 -0
  50. package/src/flow/common/workflowBundle.ts +117 -0
  51. package/src/flow/common/workflowFile.ts +4 -0
  52. package/src/flow/common/workflowReferences.ts +20 -0
@@ -1,5 +1,5 @@
1
1
  import { a as __toCommonJS, n as __esmMin, o as __toESM, r as __exportAll, t as __commonJSMin } from "./rolldown-runtime-CEgmsyvS.js";
2
- import { _ as val, a as toPlainObject, c as useLang, d as attachSetter, f as combine, g as strictEqual, h as readonlyVal, i as isString$1, l as useTranslate, m as derive, n as isBoolean$1, o as I18nProvider, p as compute, r as isPlainObject$2, s as useI18n, t as isArray$2, u as useVal } from "./dist-CHwj9BhV.js";
2
+ import { _ as readonlyVal, a as isPlainObject$2, c as I18nProvider, d as useTranslate, f as useVal, g as derive, h as compute, i as isBoolean$1, l as useI18n, m as combine, n as pasteVideoLink, o as isString$1, p as attachSetter, r as isArray$2, s as toPlainObject, u as useLang, v as strictEqual, y as val } from "./videoLink-NAWDmBtf.js";
3
3
  import * as m$4 from "react";
4
4
  import reactExports, { Children, Fragment, Suspense, createContext, createElement, forwardRef, isValidElement, lazy, memo, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
5
5
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -4183,6 +4183,223 @@ function isRectIntersect(a, b) {
4183
4183
  return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y;
4184
4184
  }
4185
4185
  //#endregion
4186
+ //#region ../../node_modules/.bun/@wopjs+disposable@0.1.24/node_modules/@wopjs/disposable/dist/index.mjs
4187
+ var isFn = (value) => !!(value && value.constructor && value.call && value.apply);
4188
+ /**
4189
+ * Check if a value is a {@link DisposableType}.
4190
+ * @param value The value to check.
4191
+ * @returns True if the value is a {@link DisposableType}, false otherwise.
4192
+ */
4193
+ var isDisposable = (value) => isFn(value) || isFn(value?.dispose);
4194
+ /**
4195
+ * Dispose a disposable object or a disposer function. Log the error if any.
4196
+ * @param disposable A disposable object or a disposer function. Do nothing otherwise.
4197
+ */
4198
+ function dispose(disposable) {
4199
+ try {
4200
+ if (disposable) {
4201
+ if (isFn(disposable.dispose)) disposable.dispose();
4202
+ else if (isFn(disposable)) disposable();
4203
+ }
4204
+ } catch (e) {
4205
+ console.error(e);
4206
+ }
4207
+ }
4208
+ var isAbortable = (disposable) => isDisposable(disposable) && isFn(disposable.abortable);
4209
+ /**
4210
+ * Create a {@link DisposableStore} that manages {@link Disposer}s and {@link IDisposable}s.
4211
+ *
4212
+ * A {@link DisposableStore} is also a {@link Disposer}, which means it can be the `dispose` method of an {@link IDisposable}.
4213
+ *
4214
+ * A {@link DisposableStore} is also an {@link IDisposable}, which means it can be managed by another {@link DisposableStore}.
4215
+ *
4216
+ * @example
4217
+ * ```ts
4218
+ * import { type IDisposable, disposableStore } from "@wopjs/disposable";
4219
+ *
4220
+ * class A implements IDisposable {
4221
+ * dispose = disposableStore()
4222
+ * constructor() {
4223
+ * this.dispose.add(...);
4224
+ * }
4225
+ * }
4226
+ *
4227
+ * class B implements IDisposable {
4228
+ * dispose = disposableStore()
4229
+ * a = this.dispose.add(new A())
4230
+ * constructor() {
4231
+ * this.dispose.add(...);
4232
+ * }
4233
+ * }
4234
+ *
4235
+ * const b = new B();
4236
+ * b.dispose(); // dispose both `b` and `b.a`.
4237
+ * ```
4238
+ *
4239
+ * @param disposables Optional array of {@link DisposableType}s added to the store.
4240
+ * @returns A disposable store.
4241
+ */
4242
+ function disposableStore(disposables) {
4243
+ let isDisposing;
4244
+ function disposableStore() {
4245
+ if (!isDisposing) {
4246
+ isDisposing = 1;
4247
+ isDisposing = disposableStore._disposables_ = disposableStore._disposables_?.forEach(dispose);
4248
+ }
4249
+ }
4250
+ disposableStore.dispose = disposableStore;
4251
+ disposableStore.size = size$3;
4252
+ disposableStore.has = has$2;
4253
+ disposableStore.add = add;
4254
+ disposableStore.make = make;
4255
+ disposableStore.remove = remove$1;
4256
+ disposableStore.flush = flush;
4257
+ if (disposables) disposableStore.add(disposables);
4258
+ return disposableStore;
4259
+ }
4260
+ function _addOne(disposable) {
4261
+ if (!this._disposables_?.has(disposable)) {
4262
+ (this._disposables_ ??= /* @__PURE__ */ new Set()).add(disposable);
4263
+ if (isAbortable(disposable)) disposable.abortable(remove$1.bind(this, disposable));
4264
+ }
4265
+ }
4266
+ function add(disposables) {
4267
+ Array.isArray(disposables) ? disposables.forEach(_addOne, this) : _addOne.call(this, disposables);
4268
+ return disposables;
4269
+ }
4270
+ function flush(disposable) {
4271
+ dispose(disposable ? this.remove(disposable) && disposable : this);
4272
+ }
4273
+ function has$2(disposable) {
4274
+ return !!this._disposables_?.has(disposable);
4275
+ }
4276
+ function make(executor) {
4277
+ const disposable = executor();
4278
+ return disposable && this.add(disposable);
4279
+ }
4280
+ function remove$1(disposable) {
4281
+ return !!this._disposables_?.delete(disposable);
4282
+ }
4283
+ function size$3() {
4284
+ return this._disposables_?.size || 0;
4285
+ }
4286
+ //#endregion
4287
+ //#region ../../node_modules/.bun/value-enhancer@5.7.2/node_modules/value-enhancer/dist/collections.mjs
4288
+ var ReactiveMapImpl = class extends Map {
4289
+ constructor(entries, config) {
4290
+ super();
4291
+ if (config) this.#onDeleted = config.onDeleted;
4292
+ const [$, set$] = readonlyVal(this, { equal: false });
4293
+ this.$ = $;
4294
+ this.#notify = () => set$(this);
4295
+ if (entries) for (const [key, value] of entries) this.set(key, value);
4296
+ }
4297
+ $;
4298
+ #notify;
4299
+ #onDeleted;
4300
+ #delete(key) {
4301
+ if (this.#onDeleted) {
4302
+ if (super.has(key)) {
4303
+ const value = super.get(key);
4304
+ super.delete(key);
4305
+ this.#onDeleted(value);
4306
+ return true;
4307
+ }
4308
+ return false;
4309
+ }
4310
+ return super.delete(key);
4311
+ }
4312
+ #clear() {
4313
+ if (this.#onDeleted) {
4314
+ const deleted = new Set(this.values());
4315
+ super.clear();
4316
+ for (const value of deleted) this.#onDeleted(value);
4317
+ } else super.clear();
4318
+ }
4319
+ delete(key) {
4320
+ const deleted = this.#delete(key);
4321
+ if (deleted) this.#notify();
4322
+ return deleted;
4323
+ }
4324
+ batchDelete(keys) {
4325
+ let deleted = false;
4326
+ for (const key of keys) deleted = this.#delete(key) || deleted;
4327
+ if (deleted) this.#notify();
4328
+ return deleted;
4329
+ }
4330
+ clear() {
4331
+ if (this.size > 0) {
4332
+ this.#clear();
4333
+ this.#notify();
4334
+ }
4335
+ }
4336
+ #set(key, value) {
4337
+ if (this.has(key)) {
4338
+ const oldValue = this.get(key);
4339
+ if (strictEqual(oldValue, value)) return false;
4340
+ super.set(key, value);
4341
+ if (this.#onDeleted) this.#onDeleted(oldValue);
4342
+ } else super.set(key, value);
4343
+ return true;
4344
+ }
4345
+ set(key, value) {
4346
+ if (this.#set(key, value)) this.#notify();
4347
+ return this;
4348
+ }
4349
+ batchSet(entries) {
4350
+ let isDirty = false;
4351
+ for (const [key, value] of entries) isDirty = this.#set(key, value) || isDirty;
4352
+ if (isDirty) this.#notify();
4353
+ return this;
4354
+ }
4355
+ rename(oldKey, newKey) {
4356
+ if (!strictEqual(oldKey, newKey)) {
4357
+ const value = this.get(oldKey);
4358
+ if (super.delete(oldKey)) {
4359
+ this.set(newKey, value);
4360
+ return true;
4361
+ }
4362
+ }
4363
+ return false;
4364
+ }
4365
+ replace(entries) {
4366
+ const oldMap = new Map(this);
4367
+ const deletedValues = new Set(this.values());
4368
+ let hasNewValue = false;
4369
+ super.clear();
4370
+ for (const [key, value] of entries) {
4371
+ super.set(key, value);
4372
+ deletedValues.delete(value);
4373
+ hasNewValue = hasNewValue || !oldMap.has(key) || !Object.is(oldMap.get(key), value);
4374
+ oldMap.delete(key);
4375
+ }
4376
+ if (hasNewValue || oldMap.size > 0 || deletedValues.size > 0) {
4377
+ if (this.#onDeleted) for (const value of deletedValues) this.#onDeleted(value);
4378
+ this.#notify();
4379
+ }
4380
+ return deletedValues.values();
4381
+ }
4382
+ toJSON() {
4383
+ const result = {};
4384
+ for (const [key, value] of this) if (key != null) {
4385
+ const k = String(key);
4386
+ const v = value;
4387
+ result[k] = v && v.toJSON ? v.toJSON(k) : v;
4388
+ }
4389
+ return result;
4390
+ }
4391
+ dispose() {
4392
+ this.$.dispose();
4393
+ if (this.size > 0) this.#clear();
4394
+ }
4395
+ };
4396
+ var reactiveMap = (entries, config) => new ReactiveMapImpl(entries, config);
4397
+ //#endregion
4398
+ //#region src/canvas/common/direction.ts
4399
+ function canvasDirection(value) {
4400
+ return value === "vertical" ? "vertical" : "horizontal";
4401
+ }
4402
+ //#endregion
4186
4403
  //#region ../../node_modules/.bun/@dagrejs+dagre@3.1.1/node_modules/@dagrejs/dagre/dist/dagre.esm.js
4187
4404
  var Te = Object.defineProperty;
4188
4405
  var In = (e, n, t) => n in e ? Te(e, n, {
@@ -6419,221 +6636,516 @@ function _e(e) {
6419
6636
  }
6420
6637
  /*! For license information please see dagre.esm.js.LEGAL.txt */
6421
6638
  //#endregion
6422
- //#region ../../node_modules/.bun/@wopjs+disposable@0.1.24/node_modules/@wopjs/disposable/dist/index.mjs
6423
- var isFn = (value) => !!(value && value.constructor && value.call && value.apply);
6424
- /**
6425
- * Check if a value is a {@link DisposableType}.
6426
- * @param value The value to check.
6427
- * @returns True if the value is a {@link DisposableType}, false otherwise.
6428
- */
6429
- var isDisposable = (value) => isFn(value) || isFn(value?.dispose);
6430
- /**
6431
- * Dispose a disposable object or a disposer function. Log the error if any.
6432
- * @param disposable A disposable object or a disposer function. Do nothing otherwise.
6433
- */
6434
- function dispose(disposable) {
6435
- try {
6436
- if (disposable) {
6437
- if (isFn(disposable.dispose)) disposable.dispose();
6438
- else if (isFn(disposable)) disposable();
6639
+ //#region src/canvas/browser/base/routeLayout.ts
6640
+ var clearance = 16;
6641
+ var portOffset = 24;
6642
+ /** Orthogonal channels around the measured cards, in primary/cross coordinates. */
6643
+ function routeLayout(nodes, edges) {
6644
+ const byId = new Map(nodes.map((node) => [node.id, node]));
6645
+ const connections = edges.map((edge) => {
6646
+ const source = byId.get(edge.source);
6647
+ const target = byId.get(edge.target);
6648
+ const output = {
6649
+ x: source.x + (edge.sourceOffset?.x ?? source.width),
6650
+ y: source.y + (edge.sourceOffset?.y ?? source.height / 2)
6651
+ };
6652
+ const input = {
6653
+ x: target.x + (edge.targetOffset?.x ?? 0),
6654
+ y: target.y + (edge.targetOffset?.y ?? target.height / 2)
6655
+ };
6656
+ const offset = output.x < input.x ? Math.min(portOffset, (input.x - output.x) / 2) : portOffset;
6657
+ return {
6658
+ id: edge.id,
6659
+ source: output,
6660
+ target: input,
6661
+ returnSide: input.x <= output.x ? Math.sign(input.y - output.y) : 0,
6662
+ start: {
6663
+ x: output.x + offset,
6664
+ y: output.y
6665
+ },
6666
+ end: {
6667
+ x: input.x - offset,
6668
+ y: input.y
6669
+ }
6670
+ };
6671
+ });
6672
+ const obstacles = nodes.map((node) => ({
6673
+ left: node.x - clearance,
6674
+ right: node.x + node.width + clearance,
6675
+ top: node.y - clearance,
6676
+ bottom: node.y + node.height + clearance
6677
+ }));
6678
+ const routes = /* @__PURE__ */ new Map();
6679
+ const pending = connections.filter((edge) => {
6680
+ if (edge.start.x > edge.end.x) return true;
6681
+ const middle = (edge.start.x + edge.end.x) / 2;
6682
+ const points = [
6683
+ edge.start,
6684
+ {
6685
+ x: middle,
6686
+ y: edge.start.y
6687
+ },
6688
+ {
6689
+ x: middle,
6690
+ y: edge.end.y
6691
+ },
6692
+ edge.end
6693
+ ];
6694
+ for (let index = 1; index < points.length; index++) {
6695
+ const a = points[index - 1];
6696
+ const b = points[index];
6697
+ if (obstacles.some((rect) => a.x === b.x ? a.x > rect.left && a.x < rect.right && Math.max(a.y, b.y) > rect.top && Math.min(a.y, b.y) < rect.bottom : a.y > rect.top && a.y < rect.bottom && Math.max(a.x, b.x) > rect.left && Math.min(a.x, b.x) < rect.right)) return true;
6698
+ }
6699
+ routes.set(edge.id, [
6700
+ edge.source,
6701
+ points[1],
6702
+ points[2],
6703
+ edge.target
6704
+ ]);
6705
+ return false;
6706
+ });
6707
+ if (!pending.length) return routes;
6708
+ const xs = [.../* @__PURE__ */ new Set([...obstacles.flatMap((rect) => [rect.left, rect.right]), ...pending.flatMap((edge) => [edge.start.x, edge.end.x])])].toSorted((a, b) => a - b);
6709
+ const ys = [.../* @__PURE__ */ new Set([...obstacles.flatMap((rect) => [rect.top, rect.bottom]), ...pending.flatMap((edge) => [edge.start.y, edge.end.y])])].toSorted((a, b) => a - b);
6710
+ const xIndex = new Map(xs.map((value, index) => [value, index]));
6711
+ const yIndex = new Map(ys.map((value, index) => [value, index]));
6712
+ const columns = xs.length;
6713
+ const size = columns * ys.length;
6714
+ const horizontal = new Uint8Array(size);
6715
+ const vertical = new Uint8Array(size);
6716
+ for (const rect of obstacles) {
6717
+ const left = xIndex.get(rect.left);
6718
+ const right = xIndex.get(rect.right);
6719
+ const top = yIndex.get(rect.top);
6720
+ const bottom = yIndex.get(rect.bottom);
6721
+ for (let y = top + 1; y < bottom; y++) for (let x = left; x < right; x++) horizontal[y * columns + x] = 1;
6722
+ for (let x = left + 1; x < right; x++) for (let y = top; y < bottom; y++) vertical[y * columns + x] = 1;
6723
+ }
6724
+ const distances = new Float64Array(size * 2);
6725
+ const previous = new Int32Array(size * 2);
6726
+ const visited = new Uint32Array(size * 2);
6727
+ for (const [routeIndex, edge] of pending.entries()) {
6728
+ const generation = routeIndex + 1;
6729
+ const start = yIndex.get(edge.start.y) * columns + xIndex.get(edge.start.x);
6730
+ const end = yIndex.get(edge.end.y) * columns + xIndex.get(edge.end.x);
6731
+ const queue = [];
6732
+ const heuristic = (vertex) => Math.abs(xs[vertex % columns] - edge.end.x) + Math.abs(ys[Math.floor(vertex / columns)] - edge.end.y);
6733
+ distances[start * 2] = 0;
6734
+ previous[start * 2] = -1;
6735
+ visited[start * 2] = generation;
6736
+ enqueue(queue, {
6737
+ state: start * 2,
6738
+ score: heuristic(start)
6739
+ });
6740
+ let finish = -1;
6741
+ while (queue.length) {
6742
+ const entry = dequeue(queue);
6743
+ const vertex = Math.floor(entry.state / 2);
6744
+ if (entry.score > distances[entry.state] + heuristic(vertex) + 1e-6) continue;
6745
+ if (vertex === end) {
6746
+ finish = entry.state;
6747
+ break;
6748
+ }
6749
+ const x = vertex % columns;
6750
+ const y = Math.floor(vertex / columns);
6751
+ const moves = [
6752
+ x > 0 && !horizontal[vertex - 1] ? vertex - 1 : -1,
6753
+ x + 1 < columns && !horizontal[vertex] ? vertex + 1 : -1,
6754
+ y > 0 && !vertical[vertex - columns] ? vertex - columns : -1,
6755
+ y + 1 < ys.length && !vertical[vertex] ? vertex + columns : -1
6756
+ ];
6757
+ for (const [index, next] of moves.entries()) {
6758
+ if (next < 0 || vertex === start && index === 0 || next === end && index === 0) continue;
6759
+ if (edge.returnSide * (ys[Math.floor(next / columns)] - edge.start.y) < -1e-6) continue;
6760
+ const axis = index < 2 ? 0 : 1;
6761
+ const state = next * 2 + axis;
6762
+ const length = Math.abs(xs[next % columns] - xs[x]) + Math.abs(ys[Math.floor(next / columns)] - ys[y]);
6763
+ const distance = distances[entry.state] + length + (entry.state % 2 === axis ? 0 : 8);
6764
+ if (visited[state] === generation && distance >= distances[state]) continue;
6765
+ visited[state] = generation;
6766
+ distances[state] = distance;
6767
+ previous[state] = entry.state;
6768
+ enqueue(queue, {
6769
+ state,
6770
+ score: distance + heuristic(next)
6771
+ });
6772
+ }
6439
6773
  }
6440
- } catch (e) {
6441
- console.error(e);
6442
- }
6443
- }
6444
- var isAbortable = (disposable) => isDisposable(disposable) && isFn(disposable.abortable);
6445
- /**
6446
- * Create a {@link DisposableStore} that manages {@link Disposer}s and {@link IDisposable}s.
6447
- *
6448
- * A {@link DisposableStore} is also a {@link Disposer}, which means it can be the `dispose` method of an {@link IDisposable}.
6449
- *
6450
- * A {@link DisposableStore} is also an {@link IDisposable}, which means it can be managed by another {@link DisposableStore}.
6451
- *
6452
- * @example
6453
- * ```ts
6454
- * import { type IDisposable, disposableStore } from "@wopjs/disposable";
6455
- *
6456
- * class A implements IDisposable {
6457
- * dispose = disposableStore()
6458
- * constructor() {
6459
- * this.dispose.add(...);
6460
- * }
6461
- * }
6462
- *
6463
- * class B implements IDisposable {
6464
- * dispose = disposableStore()
6465
- * a = this.dispose.add(new A())
6466
- * constructor() {
6467
- * this.dispose.add(...);
6468
- * }
6469
- * }
6470
- *
6471
- * const b = new B();
6472
- * b.dispose(); // dispose both `b` and `b.a`.
6473
- * ```
6474
- *
6475
- * @param disposables Optional array of {@link DisposableType}s added to the store.
6476
- * @returns A disposable store.
6477
- */
6478
- function disposableStore(disposables) {
6479
- let isDisposing;
6480
- function disposableStore() {
6481
- if (!isDisposing) {
6482
- isDisposing = 1;
6483
- isDisposing = disposableStore._disposables_ = disposableStore._disposables_?.forEach(dispose);
6774
+ if (finish < 0) throw new Error("Could not route the compact workflow connection.");
6775
+ const points = [];
6776
+ for (let state = finish; state >= 0; state = previous[state]) {
6777
+ const vertex = Math.floor(state / 2);
6778
+ points.push({
6779
+ x: xs[vertex % columns],
6780
+ y: ys[Math.floor(vertex / columns)]
6781
+ });
6484
6782
  }
6783
+ points.reverse();
6784
+ const turns = points.filter((point, index) => {
6785
+ const before = points[index - 1];
6786
+ const after = points[index + 1];
6787
+ return !before || !after || !(before.x === point.x && point.x === after.x || before.y === point.y && point.y === after.y);
6788
+ });
6789
+ routes.set(edge.id, [
6790
+ edge.source,
6791
+ ...turns,
6792
+ edge.target
6793
+ ]);
6485
6794
  }
6486
- disposableStore.dispose = disposableStore;
6487
- disposableStore.size = size$3;
6488
- disposableStore.has = has$2;
6489
- disposableStore.add = add;
6490
- disposableStore.make = make;
6491
- disposableStore.remove = remove$1;
6492
- disposableStore.flush = flush;
6493
- if (disposables) disposableStore.add(disposables);
6494
- return disposableStore;
6795
+ return routes;
6495
6796
  }
6496
- function _addOne(disposable) {
6497
- if (!this._disposables_?.has(disposable)) {
6498
- (this._disposables_ ??= /* @__PURE__ */ new Set()).add(disposable);
6499
- if (isAbortable(disposable)) disposable.abortable(remove$1.bind(this, disposable));
6797
+ function enqueue(queue, entry) {
6798
+ let index = queue.length;
6799
+ queue.push(entry);
6800
+ while (index > 0) {
6801
+ const parent = Math.floor((index - 1) / 2);
6802
+ if (queue[parent].score <= entry.score) break;
6803
+ queue[index] = queue[parent];
6804
+ index = parent;
6500
6805
  }
6806
+ queue[index] = entry;
6501
6807
  }
6502
- function add(disposables) {
6503
- Array.isArray(disposables) ? disposables.forEach(_addOne, this) : _addOne.call(this, disposables);
6504
- return disposables;
6505
- }
6506
- function flush(disposable) {
6507
- dispose(disposable ? this.remove(disposable) && disposable : this);
6508
- }
6509
- function has$2(disposable) {
6510
- return !!this._disposables_?.has(disposable);
6511
- }
6512
- function make(executor) {
6513
- const disposable = executor();
6514
- return disposable && this.add(disposable);
6515
- }
6516
- function remove$1(disposable) {
6517
- return !!this._disposables_?.delete(disposable);
6518
- }
6519
- function size$3() {
6520
- return this._disposables_?.size || 0;
6808
+ function dequeue(queue) {
6809
+ const first = queue[0];
6810
+ const last = queue.pop();
6811
+ if (!queue.length) return first;
6812
+ let index = 0;
6813
+ while (index * 2 + 1 < queue.length) {
6814
+ let child = index * 2 + 1;
6815
+ if (child + 1 < queue.length && queue[child + 1].score < queue[child].score) child++;
6816
+ if (last.score <= queue[child].score) break;
6817
+ queue[index] = queue[child];
6818
+ index = child;
6819
+ }
6820
+ queue[index] = last;
6821
+ return first;
6521
6822
  }
6522
6823
  //#endregion
6523
- //#region ../../node_modules/.bun/value-enhancer@5.7.2/node_modules/value-enhancer/dist/collections.mjs
6524
- var ReactiveMapImpl = class extends Map {
6525
- constructor(entries, config) {
6526
- super();
6527
- if (config) this.#onDeleted = config.onDeleted;
6528
- const [$, set$] = readonlyVal(this, { equal: false });
6529
- this.$ = $;
6530
- this.#notify = () => set$(this);
6531
- if (entries) for (const [key, value] of entries) this.set(key, value);
6532
- }
6533
- $;
6534
- #notify;
6535
- #onDeleted;
6536
- #delete(key) {
6537
- if (this.#onDeleted) {
6538
- if (super.has(key)) {
6539
- const value = super.get(key);
6540
- super.delete(key);
6541
- this.#onDeleted(value);
6542
- return true;
6543
- }
6544
- return false;
6824
+ //#region src/canvas/browser/base/wrapLayout.ts
6825
+ /** Normalize primary/cross coordinates without rotating cards. */
6826
+ function layoutAxes(point, direction) {
6827
+ return direction === "vertical" ? {
6828
+ x: point.y,
6829
+ y: point.x
6830
+ } : point;
6831
+ }
6832
+ var columnsPerRow = 6;
6833
+ var rowGap = 160;
6834
+ /** Wrap whole dependency columns; unmeasured default placement keeps six columns per row. */
6835
+ function wrapLayout(nodes, availableWidth) {
6836
+ const byColumn = Map.groupBy(nodes, (node) => node.column);
6837
+ const columns = [...byColumn.keys()].toSorted((a, b) => a - b).map((column) => {
6838
+ const columnNodes = byColumn.get(column);
6839
+ return {
6840
+ nodes: columnNodes,
6841
+ left: Math.min(...columnNodes.map((node) => node.x)),
6842
+ right: Math.max(...columnNodes.map((node) => node.x + node.width))
6843
+ };
6844
+ });
6845
+ const positions = {};
6846
+ let rowTop = 0;
6847
+ let rowLeft = 0;
6848
+ for (let start = 0; start < columns.length;) {
6849
+ let end = start + 1;
6850
+ let left = columns[start].left;
6851
+ let right = columns[start].right;
6852
+ while (end < columns.length) {
6853
+ const nextLeft = Math.min(left, columns[end].left);
6854
+ const nextRight = Math.max(right, columns[end].right);
6855
+ if (availableWidth == null ? end - start >= columnsPerRow : nextRight - nextLeft > availableWidth) break;
6856
+ left = nextLeft;
6857
+ right = nextRight;
6858
+ end++;
6545
6859
  }
6546
- return super.delete(key);
6547
- }
6548
- #clear() {
6549
- if (this.#onDeleted) {
6550
- const deleted = new Set(this.values());
6551
- super.clear();
6552
- for (const value of deleted) this.#onDeleted(value);
6553
- } else super.clear();
6554
- }
6555
- delete(key) {
6556
- const deleted = this.#delete(key);
6557
- if (deleted) this.#notify();
6558
- return deleted;
6559
- }
6560
- batchDelete(keys) {
6561
- let deleted = false;
6562
- for (const key of keys) deleted = this.#delete(key) || deleted;
6563
- if (deleted) this.#notify();
6564
- return deleted;
6565
- }
6566
- clear() {
6567
- if (this.size > 0) {
6568
- this.#clear();
6569
- this.#notify();
6860
+ const row = columns.slice(start, end).flatMap((column) => column.nodes);
6861
+ const top = Math.min(...row.map((node) => node.y));
6862
+ const bottom = Math.max(...row.map((node) => node.y + node.height));
6863
+ if (start == 0) {
6864
+ rowLeft = left;
6865
+ rowTop = top;
6570
6866
  }
6867
+ for (const node of row) positions[node.id] = {
6868
+ x: node.x - left + rowLeft,
6869
+ y: node.y - top + rowTop
6870
+ };
6871
+ rowTop += bottom - top + rowGap;
6872
+ start = end;
6571
6873
  }
6572
- #set(key, value) {
6573
- if (this.has(key)) {
6574
- const oldValue = this.get(key);
6575
- if (strictEqual(oldValue, value)) return false;
6576
- super.set(key, value);
6577
- if (this.#onDeleted) this.#onDeleted(oldValue);
6578
- } else super.set(key, value);
6579
- return true;
6580
- }
6581
- set(key, value) {
6582
- if (this.#set(key, value)) this.#notify();
6583
- return this;
6584
- }
6585
- batchSet(entries) {
6586
- let isDirty = false;
6587
- for (const [key, value] of entries) isDirty = this.#set(key, value) || isDirty;
6588
- if (isDirty) this.#notify();
6589
- return this;
6874
+ return positions;
6875
+ }
6876
+ //#endregion
6877
+ //#region src/canvas/browser/base/compactLayout.ts
6878
+ function bounds(nodes, routes = /* @__PURE__ */ new Map()) {
6879
+ const points = [...routes.values()].flat();
6880
+ for (const node of nodes) points.push(node, {
6881
+ x: node.x + node.width,
6882
+ y: node.y + node.height
6883
+ });
6884
+ const x = Math.min(...points.map((point) => point.x));
6885
+ const y = Math.min(...points.map((point) => point.y));
6886
+ return {
6887
+ x,
6888
+ y,
6889
+ width: Math.max(...points.map((point) => point.x)) - x,
6890
+ height: Math.max(...points.map((point) => point.y)) - y
6891
+ };
6892
+ }
6893
+ /** Place branches at their earliest dependency level, rather than delaying short
6894
+ * branches until the longest sibling reaches a shared join. Cycles remain one
6895
+ * component whose internal order follows the measured base layout. */
6896
+ function dependencyLevels(nodes, edges, gap) {
6897
+ const graph = new ie.Graph();
6898
+ for (const node of nodes) graph.setNode(node.id);
6899
+ for (const edge of edges) graph.setEdge(edge.source, edge.target);
6900
+ const components = ie.alg.tarjan(graph);
6901
+ const componentOf = new Map(components.flatMap((members, index) => members.map((id) => [id, String(index)])));
6902
+ const dependencies = new ie.Graph();
6903
+ for (let index = 0; index < components.length; index++) dependencies.setNode(String(index));
6904
+ for (const edge of edges) {
6905
+ const source = componentOf.get(edge.source);
6906
+ const target = componentOf.get(edge.target);
6907
+ if (source !== target) dependencies.setEdge(source, target);
6908
+ }
6909
+ const byId = new Map(nodes.map((node) => [node.id, node]));
6910
+ const levels = /* @__PURE__ */ new Map();
6911
+ const ends = /* @__PURE__ */ new Map();
6912
+ for (const id of ie.alg.topsort(dependencies)) {
6913
+ const start = Math.max(0, ...(dependencies.predecessors(id) ?? []).map((parent) => ends.get(parent) + 1));
6914
+ const members = components[Number(id)].map((member) => byId.get(member)).toSorted((a, b) => a.column - b.column || a.y - b.y);
6915
+ for (const [index, member] of members.entries()) levels.set(member.id, start + index);
6916
+ ends.set(id, start + members.length - 1);
6917
+ }
6918
+ const isolated = nodes.filter((node) => graph.nodeEdges(node.id)?.length === 0);
6919
+ const isolatedColumns = [...new Set(isolated.map((node) => node.column))].toSorted((a, b) => a - b);
6920
+ for (const node of isolated) levels.set(node.id, isolatedColumns.indexOf(node.column));
6921
+ let primary = 0;
6922
+ const groups = [...Map.groupBy(nodes, (node) => levels.get(node.id)).entries()].toSorted(([a], [b]) => a - b);
6923
+ for (const [level, members] of groups) {
6924
+ const size = Math.max(...members.map((node) => node.width));
6925
+ for (const node of members) Object.assign(node, {
6926
+ column: level,
6927
+ x: primary + (size - node.width) / 2
6928
+ });
6929
+ primary += size + gap;
6590
6930
  }
6591
- rename(oldKey, newKey) {
6592
- if (!strictEqual(oldKey, newKey)) {
6593
- const value = this.get(oldKey);
6594
- if (super.delete(oldKey)) {
6595
- this.set(newKey, value);
6596
- return true;
6597
- }
6931
+ }
6932
+ /** Compact each connected subgraph, then wrap the forest to the requested ratio. */
6933
+ function compactLayout(graph, insets = {
6934
+ width: 0,
6935
+ height: 0
6936
+ }, aspectRatio = 1) {
6937
+ if (!graph.nodes.length) return {
6938
+ positions: {},
6939
+ routes: /* @__PURE__ */ new Map(),
6940
+ bounds: {
6941
+ x: 0,
6942
+ y: 0,
6943
+ width: 320,
6944
+ height: 120
6598
6945
  }
6599
- return false;
6946
+ };
6947
+ const connected = new ie.Graph();
6948
+ for (const node of graph.nodes) connected.setNode(node.id);
6949
+ for (const edge of graph.edges) connected.setEdge(edge.source, edge.target);
6950
+ const members = ie.alg.components(connected);
6951
+ if (members.length === 1) return compactComponent(graph, insets, aspectRatio);
6952
+ const componentOf = new Map(members.flatMap((ids, index) => ids.map((id) => [id, index])));
6953
+ const edges = Map.groupBy(graph.edges, (edge) => componentOf.get(edge.source));
6954
+ return packComponents([...Map.groupBy(graph.nodes, (node) => componentOf.get(node.id))].map(([id, nodes]) => ({
6955
+ nodes,
6956
+ edges: edges.get(id) ?? [],
6957
+ bounds: bounds(nodes)
6958
+ })).toSorted((a, b) => a.bounds.x - b.bounds.x || a.bounds.y - b.bounds.y).map((component) => component.nodes.length === 1 && !component.edges.length ? {
6959
+ positions: { [component.nodes[0].id]: component.nodes[0] },
6960
+ routes: /* @__PURE__ */ new Map(),
6961
+ bounds: component.bounds
6962
+ } : compactComponent(component, {
6963
+ width: 0,
6964
+ height: 0
6965
+ }, aspectRatio)), insets, aspectRatio);
6966
+ }
6967
+ /** Keep reading order, with a larger gap between independent trees than within one. */
6968
+ function packComponents(layouts, insets, aspectRatio) {
6969
+ const gap = 96;
6970
+ const largestWidth = Math.max(...layouts.map((layout) => layout.bounds.width));
6971
+ const contentArea = layouts.reduce((sum, layout) => sum + layout.bounds.width * layout.bounds.height, 0);
6972
+ const limits = /* @__PURE__ */ new Set([largestWidth, Math.max(largestWidth, Math.sqrt(contentArea * aspectRatio))]);
6973
+ let prefixWidth = -96;
6974
+ for (const layout of layouts) {
6975
+ prefixWidth += layout.bounds.width + gap;
6976
+ limits.add(Math.max(largestWidth, prefixWidth));
6977
+ }
6978
+ let best;
6979
+ for (const limit of limits) {
6980
+ let x = 0;
6981
+ let y = 0;
6982
+ let width = 0;
6983
+ let rowHeight = 0;
6984
+ let rows = 1;
6985
+ const positions = layouts.map((layout) => {
6986
+ if (x > 0 && x + layout.bounds.width > limit + 1e-6) {
6987
+ y += rowHeight + gap;
6988
+ x = rowHeight = 0;
6989
+ rows++;
6990
+ }
6991
+ const position = {
6992
+ x: x - layout.bounds.x,
6993
+ y: y - layout.bounds.y
6994
+ };
6995
+ width = Math.max(width, x + layout.bounds.width);
6996
+ rowHeight = Math.max(rowHeight, layout.bounds.height);
6997
+ x += layout.bounds.width + gap;
6998
+ return position;
6999
+ });
7000
+ const height = y + rowHeight;
7001
+ const score = Math.max((width + insets.width) / aspectRatio, height + insets.height);
7002
+ const area = (width + insets.width) * (height + insets.height);
7003
+ if (!best || score < best.score - 1e-9 || Math.abs(score - best.score) < 1e-9 && (area < best.area || area === best.area && rows < best.rows)) best = {
7004
+ positions,
7005
+ width,
7006
+ height,
7007
+ score,
7008
+ area,
7009
+ rows
7010
+ };
6600
7011
  }
6601
- replace(entries) {
6602
- const oldMap = new Map(this);
6603
- const deletedValues = new Set(this.values());
6604
- let hasNewValue = false;
6605
- super.clear();
6606
- for (const [key, value] of entries) {
6607
- super.set(key, value);
6608
- deletedValues.delete(value);
6609
- hasNewValue = hasNewValue || !oldMap.has(key) || !Object.is(oldMap.get(key), value);
6610
- oldMap.delete(key);
6611
- }
6612
- if (hasNewValue || oldMap.size > 0 || deletedValues.size > 0) {
6613
- if (this.#onDeleted) for (const value of deletedValues) this.#onDeleted(value);
6614
- this.#notify();
7012
+ const translate = (point, index) => ({
7013
+ x: point.x + best.positions[index].x,
7014
+ y: point.y + best.positions[index].y
7015
+ });
7016
+ return {
7017
+ positions: Object.fromEntries(layouts.flatMap((layout, index) => Object.entries(layout.positions).map(([id, point]) => [id, translate(point, index)]))),
7018
+ routes: new Map(layouts.flatMap((layout, index) => [...layout.routes].map(([id, points]) => [id, points.map((point) => translate(point, index))]))),
7019
+ bounds: {
7020
+ x: 0,
7021
+ y: 0,
7022
+ width: best.width,
7023
+ height: best.height
6615
7024
  }
6616
- return deletedValues.values();
6617
- }
6618
- toJSON() {
6619
- const result = {};
6620
- for (const [key, value] of this) if (key != null) {
6621
- const k = String(key);
6622
- const v = value;
6623
- result[k] = v && v.toJSON ? v.toJSON(k) : v;
7025
+ };
7026
+ }
7027
+ /** Bend dependency paths continuously; the ports retain their original orientation. */
7028
+ function compactComponent(graph, insets, aspectRatio) {
7029
+ const normalized = graph.nodes.map((node) => ({
7030
+ ...node,
7031
+ ...layoutAxes(node, "vertical"),
7032
+ width: node.height,
7033
+ height: node.width
7034
+ }));
7035
+ dependencyLevels(normalized, graph.edges, 48);
7036
+ const incoming = new Set(graph.edges.map((edge) => edge.target));
7037
+ const outgoing = new Set(graph.edges.map((edge) => edge.source));
7038
+ const roots = normalized.filter((node) => !incoming.has(node.id) && outgoing.has(node.id));
7039
+ const centers = (roots.length ? roots : normalized).map((node) => node.y + node.height / 2);
7040
+ const center = centers.reduce((sum, value) => sum + value, 0) / centers.length;
7041
+ const gap = 48;
7042
+ const pathNodes = normalized.filter((node) => incoming.has(node.id) || outgoing.has(node.id));
7043
+ const crossSize = Math.max(...(pathNodes.length ? pathNodes : normalized).map((node) => node.height));
7044
+ const bow = crossSize * .75;
7045
+ const separation = crossSize + 48;
7046
+ const bucketSize = Math.max(...normalized.map((node) => node.width)) + gap;
7047
+ const byId = new Map(normalized.map((node) => [node.id, node]));
7048
+ const forwardEdges = graph.edges.filter((edge) => byId.get(edge.source).column < byId.get(edge.target).column);
7049
+ const parents = Map.groupBy(forwardEdges, (edge) => edge.target);
7050
+ const children = Map.groupBy(forwardEdges, (edge) => edge.source);
7051
+ const ordered = normalized.toSorted((a, b) => a.column - b.column || a.y - b.y);
7052
+ const remaining = /* @__PURE__ */ new Map();
7053
+ for (const node of ordered.toReversed()) remaining.set(node.id, 1 + Math.max(0, ...(children.get(node.id) ?? []).filter((edge) => parents.get(edge.target)?.length === 1).map((edge) => remaining.get(edge.target))));
7054
+ const rankEnds = new Map([...Map.groupBy(normalized, (node) => node.column)].map(([rank, nodes]) => [rank, Math.max(...nodes.map((node) => node.x + node.width))]));
7055
+ const spans = /* @__PURE__ */ new Set([Infinity, ...rankEnds.values()]);
7056
+ let best;
7057
+ for (const span of spans) {
7058
+ const placed = /* @__PURE__ */ new Map();
7059
+ const buckets = /* @__PURE__ */ new Map();
7060
+ let turns = 0;
7061
+ for (const original of ordered) {
7062
+ const upstream = parents.get(original.id)?.map((edge) => placed.get(edge.source)) ?? [];
7063
+ const parent = upstream[0];
7064
+ const side = original.y + original.height / 2 < center - 1e-6 ? -1 : 1;
7065
+ let primary = upstream.length ? Math.max(...upstream.map(({ node }) => {
7066
+ const source = byId.get(node.id);
7067
+ return node.x + rankEnds.get(source.column) - source.x;
7068
+ })) + gap : original.x;
7069
+ let shift = 0;
7070
+ let start = 0;
7071
+ if (upstream.length > 1) {
7072
+ primary = Math.max(...upstream.map((entry) => entry.extent)) + gap;
7073
+ shift = upstream.reduce((sum, { node }) => sum + node.y + node.height / 2, 0) / upstream.length - original.y - original.height / 2;
7074
+ start = primary;
7075
+ } else if (parent) {
7076
+ shift = parent.shift;
7077
+ start = parent.start;
7078
+ if ((children.get(parent.node.id)?.length ?? 0) > 1) {
7079
+ shift = parent.node.y - byId.get(parent.node.id).y;
7080
+ start = primary;
7081
+ } else if (primary + original.width > span && remaining.get(original.id) > 2) {
7082
+ primary = Math.max(0, start - span / 3);
7083
+ shift = parent.shift + side * separation;
7084
+ start = primary;
7085
+ turns++;
7086
+ }
7087
+ }
7088
+ const progress = Number.isFinite(span) && span > start ? Math.min(1, Math.max(0, (primary - start) / (span - start))) : 0;
7089
+ const drift = side * bow * Math.sin(progress * Math.PI);
7090
+ const node = {
7091
+ ...original,
7092
+ x: primary,
7093
+ y: original.y + shift + drift
7094
+ };
7095
+ const firstBucket = Math.floor(node.x / bucketSize);
7096
+ const lastBucket = Math.floor((node.x + node.width + gap) / bucketSize);
7097
+ const nearby = /* @__PURE__ */ new Set();
7098
+ for (let bucket = firstBucket; bucket <= lastBucket; bucket++) for (const entry of buckets.get(bucket) ?? []) nearby.add(entry);
7099
+ const candidates = [...nearby].toSorted((a, b) => a.order - b.order);
7100
+ while (true) {
7101
+ const collision = candidates.find(({ node: other }) => node.x < other.x + other.width + 48 - 1e-6 && other.x < node.x + node.width + 48 - 1e-6 && node.y < other.y + other.height + 48 - 1e-6 && other.y < node.y + node.height + 48 - 1e-6);
7102
+ if (!collision) break;
7103
+ node.y = side < 0 ? collision.node.y - node.height - 48 : collision.node.y + collision.node.height + 48;
7104
+ }
7105
+ const placement = {
7106
+ node,
7107
+ order: placed.size,
7108
+ shift: node.y - original.y - drift,
7109
+ start,
7110
+ extent: Math.max(node.x + node.width, ...upstream.map((entry) => entry.extent))
7111
+ };
7112
+ placed.set(node.id, placement);
7113
+ for (let bucket = firstBucket; bucket <= lastBucket; bucket++) {
7114
+ const entries = buckets.get(bucket);
7115
+ if (entries) entries.push(placement);
7116
+ else buckets.set(bucket, [placement]);
7117
+ }
6624
7118
  }
6625
- return result;
6626
- }
6627
- dispose() {
6628
- this.$.dispose();
6629
- if (this.size > 0) this.#clear();
7119
+ const nodes = [...placed.values()].map((entry) => entry.node);
7120
+ const extent = bounds(nodes);
7121
+ const width = extent.height + insets.width + 48;
7122
+ const height = extent.width + insets.height + 48;
7123
+ const area = width * height;
7124
+ const score = Math.max(width / aspectRatio, height);
7125
+ if (!best || score < best.score - 1e-9 || Math.abs(score - best.score) < 1e-9 && (area < best.area || area === best.area && turns < best.turns)) best = {
7126
+ nodes,
7127
+ score,
7128
+ area,
7129
+ turns
7130
+ };
6630
7131
  }
6631
- };
6632
- var reactiveMap = (entries, config) => new ReactiveMapImpl(entries, config);
6633
- //#endregion
6634
- //#region src/canvas/common/direction.ts
6635
- function canvasDirection(value) {
6636
- return value === "vertical" ? "vertical" : "horizontal";
7132
+ const routes = routeLayout(best.nodes, graph.edges.map((edge) => Object.assign({}, edge, {
7133
+ sourceOffset: edge.sourceOffset && layoutAxes(edge.sourceOffset, "vertical"),
7134
+ targetOffset: edge.targetOffset && layoutAxes(edge.targetOffset, "vertical")
7135
+ })));
7136
+ const physicalNodes = best.nodes.map((node) => Object.assign({}, node, layoutAxes(node, "vertical"), {
7137
+ width: node.height,
7138
+ height: node.width
7139
+ }));
7140
+ const physicalRoutes = new Map([...routes].map(([id, points]) => [id, points.map((point) => layoutAxes(point, "vertical"))]));
7141
+ return {
7142
+ positions: Object.fromEntries(physicalNodes.map(({ id, x, y }) => [id, {
7143
+ x,
7144
+ y
7145
+ }])),
7146
+ routes: physicalRoutes,
7147
+ bounds: bounds(physicalNodes, physicalRoutes)
7148
+ };
6637
7149
  }
6638
7150
  function isFunction$1(value) {
6639
7151
  return typeof value === "function";
@@ -6680,50 +7192,61 @@ function isInside(target, selector) {
6680
7192
  return target?.closest?.(selector) != null;
6681
7193
  }
6682
7194
  //#endregion
6683
- //#region src/canvas/browser/base/wrapLayout.ts
6684
- var columnsPerRow = 6;
6685
- var rowGap = 160;
6686
- /** Wrap whole dependency columns; unmeasured default placement keeps six columns per row. */
6687
- function wrapLayout(nodes, availableWidth) {
6688
- const byColumn = Map.groupBy(nodes, (node) => node.column);
6689
- const columns = [...byColumn.keys()].toSorted((a, b) => a - b).map((column) => {
6690
- const columnNodes = byColumn.get(column);
6691
- return {
6692
- nodes: columnNodes,
6693
- left: Math.min(...columnNodes.map((node) => node.x)),
6694
- right: Math.max(...columnNodes.map((node) => node.x + node.width))
6695
- };
6696
- });
6697
- const positions = {};
6698
- let rowTop = 0;
6699
- let rowLeft = 0;
6700
- for (let start = 0; start < columns.length;) {
6701
- let end = start + 1;
6702
- let left = columns[start].left;
6703
- let right = columns[start].right;
6704
- while (end < columns.length) {
6705
- const nextLeft = Math.min(left, columns[end].left);
6706
- const nextRight = Math.max(right, columns[end].right);
6707
- if (availableWidth == null ? end - start >= columnsPerRow : nextRight - nextLeft > availableWidth) break;
6708
- left = nextLeft;
6709
- right = nextRight;
6710
- end++;
6711
- }
6712
- const row = columns.slice(start, end).flatMap((column) => column.nodes);
6713
- const top = Math.min(...row.map((node) => node.y));
6714
- const bottom = Math.max(...row.map((node) => node.y + node.height));
6715
- if (start == 0) {
6716
- rowLeft = left;
6717
- rowTop = top;
7195
+ //#region src/canvas/browser/base/graphLayout.ts
7196
+ /** The measured dependency layout shared by canvas arrangement and image export. */
7197
+ function graphLayout(nodes, edges, direction) {
7198
+ if (!nodes.length) return {
7199
+ nodes: [],
7200
+ edges: []
7201
+ };
7202
+ const graph = new ie.Graph().setDefaultEdgeLabel(() => ({}));
7203
+ graph.setGraph({
7204
+ rankdir: direction === "vertical" ? "TB" : "LR",
7205
+ ranksep: direction === "vertical" ? 48 : 80
7206
+ });
7207
+ const singles = new Set(nodes.map((node) => node.id));
7208
+ for (const node of nodes) graph.setNode(node.id, {
7209
+ width: node.width,
7210
+ height: node.height
7211
+ });
7212
+ const connections = edges.filter((edge) => graph.hasNode(edge.source) && graph.hasNode(edge.target));
7213
+ for (const edge of connections) {
7214
+ singles.delete(edge.source);
7215
+ singles.delete(edge.target);
7216
+ graph.setEdge(edge.source, edge.target);
7217
+ }
7218
+ const isolated = [...singles];
7219
+ for (let start = 0; start < isolated.length; start += 10) for (let index = start; index < Math.min(start + 9, isolated.length - 1); index++) graph.setEdge(isolated[index], isolated[index + 1]);
7220
+ const constraints = [];
7221
+ const ordering = new ie.Graph();
7222
+ for (const node of nodes) {
7223
+ const targets = [...new Set(node.branchHandles?.flatMap((handle) => connections.filter((edge) => edge.source === node.id && edge.sourceHandle === handle).map((edge) => edge.target)))];
7224
+ for (let index = 1; index < targets.length; index++) {
7225
+ const left = targets[index - 1];
7226
+ const right = targets[index];
7227
+ ordering.setEdge(left, right);
7228
+ if (ie.alg.isAcyclic(ordering)) constraints.push({
7229
+ left,
7230
+ right
7231
+ });
7232
+ else ordering.removeEdge(left, right);
6718
7233
  }
6719
- for (const node of row) positions[node.id] = {
6720
- x: node.x - left + rowLeft,
6721
- y: node.y - top + rowTop
6722
- };
6723
- rowTop += bottom - top + rowGap;
6724
- start = end;
6725
7234
  }
6726
- return positions;
7235
+ Oe(graph, { constraints });
7236
+ return {
7237
+ nodes: nodes.map((node) => {
7238
+ const { x, y, width, height, rank } = graph.node(node.id);
7239
+ return {
7240
+ id: node.id,
7241
+ column: rank,
7242
+ x: x - width / 2,
7243
+ y: y - height / 2,
7244
+ width,
7245
+ height
7246
+ };
7247
+ }),
7248
+ edges: connections.map((edge) => Object.assign({}, edge, { points: graph.edge(edge.source, edge.target).points }))
7249
+ };
6727
7250
  }
6728
7251
  //#endregion
6729
7252
  //#region src/canvas/browser/graph/FlowCanvas/model.ts
@@ -12405,6 +12928,7 @@ var CanvasStore = class {
12405
12928
  constructor(model, editable, language, callbacks, autoLayout = false, interactiveMode$) {
12406
12929
  this.canDeleteNodes = true;
12407
12930
  this.dispose = disposableStore();
12931
+ this.connectionRoutes = this.dispose.add(val(/* @__PURE__ */ new Map()));
12408
12932
  this.ignoredNodeIds = this.dispose.add(val([]));
12409
12933
  this.ignoreNodes = (nodeIds, ignored) => {
12410
12934
  if (this.$.editable.value) this.#callbacks.onIgnoreNodes?.(nodeIds, ignored);
@@ -12644,7 +13168,7 @@ var CanvasStore = class {
12644
13168
  this.$$.changingDirection.set(false);
12645
13169
  }
12646
13170
  allLayoutNodes() {
12647
- return [...this.$.nodes.values()];
13171
+ return [...this.$.nodes.values(), ...this.$.commentNodes?.values() ?? []];
12648
13172
  }
12649
13173
  /** Deletes nodes programmatically, such as from a menu action. */
12650
13174
  async deleteNodes(nodes, skipConfirm) {
@@ -12669,7 +13193,7 @@ var CanvasStore = class {
12669
13193
  }
12670
13194
  doRelayout(availableWidth) {
12671
13195
  const selected = this.$.selectedNodes.value.length > 1 ? this.$.selectedNodes.value : [];
12672
- const nodes = selected.length > 0 ? selected.filter(NodeStore.is) : this.allLayoutNodes();
13196
+ const nodes = selected.length > 0 ? selected : this.allLayoutNodes();
12673
13197
  if (nodes.length === 0) return;
12674
13198
  let positions = this.layoutPositions(nodes, availableWidth);
12675
13199
  if (selected.length > 0) {
@@ -12689,65 +13213,52 @@ var CanvasStore = class {
12689
13213
  if (position) node.$$.position.set(position);
12690
13214
  }
12691
13215
  }
12692
- layoutPositions(nodes, availableWidth) {
12693
- const g = new ie.Graph().setDefaultEdgeLabel(() => ({}));
12694
- g.setGraph({
12695
- rankdir: this.$.direction.value === "vertical" ? "TB" : "LR",
12696
- ranksep: 80
12697
- });
12698
- const singles = /* @__PURE__ */ new Set();
12699
- for (const node of nodes) {
12700
- const { id, measured } = node.$.rfNode.value;
12701
- singles.add(id);
12702
- g.setNode(id, {
12703
- width: measured?.width ?? 0,
12704
- height: measured?.height ?? 0
12705
- });
12706
- }
12707
- for (const rfEdge of this.$.rfEdges.value) {
12708
- if (!g.hasNode(rfEdge.source) || !g.hasNode(rfEdge.target)) continue;
12709
- singles.delete(rfEdge.source);
12710
- singles.delete(rfEdge.target);
12711
- g.setEdge(rfEdge.source, rfEdge.target);
12712
- }
12713
- if (singles.size > 0) for (const list of cluster([...singles], 10)) for (let i = 0; i < list.length - 1; i++) g.setEdge(list[i], list[i + 1]);
12714
- const constraints = [];
12715
- const ordering = new ie.Graph();
12716
- for (const node of nodes) {
12717
- const content = node.content$.value;
12718
- if (content.kind !== "condition" && content.kind !== "approval" && content.kind !== "wait") continue;
12719
- const targets = [...new Set(content.outputs.flatMap((port) => "handle" in port ? this.#connections.value.filter((edge) => edge.source === node.nodeId && edge.sourceHandle === `$branch:${port.handle}`).flatMap((edge) => {
12720
- const target = this.$.nodes.get(edge.target);
12721
- return target && g.hasNode(target.rfNodeId) ? [target.rfNodeId] : [];
12722
- }) : []))];
12723
- for (let index = 1; index < targets.length; index++) {
12724
- const left = targets[index - 1];
12725
- const right = targets[index];
12726
- ordering.setEdge(left, right);
12727
- if (ie.alg.isAcyclic(ordering)) constraints.push({
12728
- left,
12729
- right
12730
- });
12731
- else ordering.removeEdge(left, right);
12732
- }
12733
- }
12734
- Oe(g, { constraints });
12735
- const layoutNodes = nodes.map((node) => {
12736
- const { x, y, width, height, rank } = g.node(node.rfNodeId);
13216
+ measuredLayout(nodes) {
13217
+ return graphLayout(nodes.map((node) => {
13218
+ const measured = node.$.measured.value;
13219
+ const content = NodeStore.is(node) ? node.content$.value : void 0;
12737
13220
  return {
12738
13221
  id: node.nodeId,
12739
- column: rank,
12740
- x: x - width / 2,
12741
- y: y - height / 2,
12742
- width,
12743
- height
13222
+ width: measured?.width ?? 0,
13223
+ height: measured?.height ?? 0,
13224
+ branchHandles: content?.kind === "condition" || content?.kind === "approval" || content?.kind === "wait" ? content.outputs.flatMap((port) => "handle" in port ? ["$branch:" + port.handle] : []) : void 0
12744
13225
  };
12745
- });
13226
+ }), this.#connections.value.map((edge) => ({
13227
+ ...edge,
13228
+ id: getRFEdgeId(edge)
13229
+ })), this.$.direction.value);
13230
+ }
13231
+ layoutPositions(nodes, availableWidth) {
13232
+ const { nodes: layoutNodes } = this.measuredLayout(nodes);
12746
13233
  return this.$.direction.value === "horizontal" ? wrapLayout(layoutNodes, availableWidth) : Object.fromEntries(layoutNodes.map(({ id, x, y }) => [id, {
12747
13234
  x,
12748
13235
  y
12749
13236
  }]));
12750
13237
  }
13238
+ /** Arrange the isolated export store without saving presentation or history. */
13239
+ compactForExport(insets, instance, aspectRatio = 1) {
13240
+ const graph = this.measuredLayout(this.allLayoutNodes());
13241
+ const port = (id, handle, type) => {
13242
+ const node = this.$.nodes.get(id);
13243
+ const measured = (node && instance?.getInternalNode(node.rfNodeId)?.internals.handleBounds?.[type])?.find((entry) => entry.id === `h:${handle}`);
13244
+ return measured && {
13245
+ x: measured.x + measured.width / 2,
13246
+ y: measured.y + (type === "source" ? measured.height : 0)
13247
+ };
13248
+ };
13249
+ const connections = new Map(this.#connections.value.map((edge) => [getRFEdgeId(edge), edge]));
13250
+ const edges = graph.edges.map((edge) => Object.assign({}, edge, {
13251
+ sourceOffset: port(edge.source, connections.get(edge.id)?.sourceHandle, "source"),
13252
+ targetOffset: port(edge.target, connections.get(edge.id)?.targetHandle, "target")
13253
+ }));
13254
+ const result = compactLayout({
13255
+ nodes: graph.nodes,
13256
+ edges
13257
+ }, insets, aspectRatio);
13258
+ this.applyPositions(result.positions);
13259
+ this.connectionRoutes.set(result.routes);
13260
+ return result.bounds;
13261
+ }
12751
13262
  doRemoveNodes(nodes) {
12752
13263
  if (this.disposed || !nodes?.size) return;
12753
13264
  for (const node of nodes) this.pendingNodeDeletes.add(node);
@@ -32505,11 +33016,47 @@ function connectionNodeBounds(node) {
32505
33016
  };
32506
33017
  }
32507
33018
  /** Align arrows with their ports and route returns outside both cards. */
32508
- function getConnectionPath({ sourceBounds, targetBounds, ...params }) {
33019
+ function getConnectionPath({ sourceBounds, targetBounds, waypoints, ...params }) {
32509
33020
  const { sourcePosition = Position$1.Bottom, targetPosition = Position$1.Top } = params;
32510
33021
  const vertical = sourcePosition === Position$1.Bottom && targetPosition === Position$1.Top || sourcePosition === Position$1.Top && targetPosition === Position$1.Bottom;
32511
33022
  const reverse = sourcePosition === Position$1.Left && targetPosition === Position$1.Right || sourcePosition === Position$1.Top && targetPosition === Position$1.Bottom;
32512
33023
  const horizontal = sourcePosition === Position$1.Right && targetPosition === Position$1.Left || sourcePosition === Position$1.Left && targetPosition === Position$1.Right;
33024
+ if (waypoints && waypoints.length > 2) {
33025
+ const interior = waypoints.slice(1, -1);
33026
+ const first = interior[0];
33027
+ const last = interior.at(-1);
33028
+ const points = [
33029
+ {
33030
+ x: params.sourceX,
33031
+ y: params.sourceY
33032
+ },
33033
+ vertical ? {
33034
+ x: params.sourceX,
33035
+ y: first.y
33036
+ } : {
33037
+ x: first.x,
33038
+ y: params.sourceY
33039
+ },
33040
+ ...interior,
33041
+ vertical ? {
33042
+ x: params.targetX,
33043
+ y: last.y
33044
+ } : {
33045
+ x: last.x,
33046
+ y: params.targetY
33047
+ },
33048
+ {
33049
+ x: params.targetX,
33050
+ y: params.targetY
33051
+ }
33052
+ ];
33053
+ const label = interior[Math.floor(interior.length / 2)];
33054
+ return [
33055
+ roundedConnectionPath(points),
33056
+ label.x,
33057
+ label.y
33058
+ ];
33059
+ }
32513
33060
  const primary = (x, y) => vertical ? y : x;
32514
33061
  const cross = (x, y) => vertical ? x : y;
32515
33062
  const sourceX = primary(params.sourceX, params.sourceY);
@@ -32594,6 +33141,15 @@ function getConnectionPath({ sourceBounds, targetBounds, ...params }) {
32594
33141
  y: point.x
32595
33142
  } : point);
32596
33143
  if (reverse) points.reverse();
33144
+ const middle = (left + right) / 2;
33145
+ return [
33146
+ roundedConnectionPath(points),
33147
+ vertical ? laneY : middle,
33148
+ vertical ? middle : laneY
33149
+ ];
33150
+ }
33151
+ function roundedConnectionPath(input) {
33152
+ const points = input.filter((point, index) => index === 0 || point.x !== input[index - 1].x || point.y !== input[index - 1].y);
32597
33153
  const radius = 16;
32598
33154
  let path = `M ${points[0].x} ${points[0].y}`;
32599
33155
  for (let i = 1; i < points.length - 1; i++) {
@@ -32607,12 +33163,7 @@ function getConnectionPath({ sourceBounds, targetBounds, ...params }) {
32607
33163
  path += ` Q ${corner.x} ${corner.y} ${corner.x + (next.x - corner.x) * r / after} ${corner.y + (next.y - corner.y) * r / after}`;
32608
33164
  }
32609
33165
  const end = points.at(-1);
32610
- const middle = (left + right) / 2;
32611
- return [
32612
- `${path} L ${end.x} ${end.y}`,
32613
- vertical ? laneY : middle,
32614
- vertical ? middle : laneY
32615
- ];
33166
+ return `${path} L ${end.x} ${end.y}`;
32616
33167
  }
32617
33168
  //#endregion
32618
33169
  //#region src/canvas/browser/graph/Edges/EdgeGradient.tsx
@@ -32641,12 +33192,14 @@ function BasicEdge(props) {
32641
33192
  const error = useVal(edgeStore?.$.error);
32642
33193
  const canvasStore = useCanvasStore();
32643
33194
  const scale = useVal(canvasStore.$.scale);
33195
+ const routes = useVal(canvasStore.connectionRoutes);
32644
33196
  const gap = 3;
32645
33197
  const targetX = props.targetX + (props.targetPosition == Position$1.Left ? -3 : props.targetPosition == Position$1.Right ? gap : 0);
32646
33198
  const targetY = props.targetY + (props.targetPosition == Position$1.Top ? -3 : props.targetPosition == Position$1.Bottom ? gap : 0);
32647
33199
  const sourceNode = useInternalNode(props.source);
32648
33200
  const targetNode = useInternalNode(props.target);
32649
33201
  const [path, labelX, labelY] = getConnectionPath({
33202
+ waypoints: routes.get(props.id),
32650
33203
  sourceBounds: connectionNodeBounds(sourceNode),
32651
33204
  targetBounds: connectionNodeBounds(targetNode),
32652
33205
  sourceX: props.sourceX,
@@ -43337,12 +43890,12 @@ function CommentNodeActions({ canvasStore, nodeStore }) {
43337
43890
  });
43338
43891
  }
43339
43892
  var CommentNodeContent_module_default = {
43340
- body: "CommentNodeContent_body_01471",
43341
- container: "CommentNodeContent_container_01471",
43342
- resizeButton: "CommentNodeContent_resizeButton_01471",
43343
- sourceCode: "CommentNodeContent_sourceCode_01471",
43344
- markdown: "CommentNodeContent_markdown_01471",
43345
- taskCheckbox: "CommentNodeContent_taskCheckbox_01471"
43893
+ body: "CommentNodeContent_body_7c741",
43894
+ container: "CommentNodeContent_container_7c741",
43895
+ resizeButton: "CommentNodeContent_resizeButton_7c741",
43896
+ sourceCode: "CommentNodeContent_sourceCode_7c741",
43897
+ markdown: "CommentNodeContent_markdown_7c741",
43898
+ taskCheckbox: "CommentNodeContent_taskCheckbox_7c741"
43346
43899
  };
43347
43900
  //#endregion
43348
43901
  //#region ../../node_modules/.bun/@base-ui+utils@0.2.8+b87d06724be9db7a/node_modules/@base-ui/utils/esm/useControlled.js
@@ -43972,13 +44525,13 @@ var Textarea = m$4.forwardRef(function Textarea({ className, ...props }, ref) {
43972
44525
  });
43973
44526
  });
43974
44527
  var markdownPreview_module_default = {
43975
- container: "markdownPreview_container_c03ca",
43976
- body: "markdownPreview_body_c03ca",
43977
- draggable: "markdownPreview_draggable_c03ca"
44528
+ container: "markdownPreview_container_2a1d9",
44529
+ body: "markdownPreview_body_2a1d9",
44530
+ draggable: "markdownPreview_draggable_2a1d9"
43978
44531
  };
43979
44532
  //#endregion
43980
44533
  //#region src/canvas/browser/preview/markdownPreview.tsx
43981
- var MarkdownContent$1 = lazy(() => import("./markdownContent-CAG_CQfH.js"));
44534
+ var MarkdownContent$1 = lazy(() => import("./markdownContent-D8G_oNOe.js"));
43982
44535
  var MarkdownPreview = /* @__PURE__ */ memo(({ dark, unstyled, components, contentClassName, content, draggable, onDoubleClick }) => {
43983
44536
  const [focus, setFocus] = useState(false);
43984
44537
  return /* @__PURE__ */ jsx("div", {
@@ -43987,8 +44540,9 @@ var MarkdownPreview = /* @__PURE__ */ memo(({ dark, unstyled, components, conten
43987
44540
  onFocus: () => setFocus(true),
43988
44541
  onBlur: () => setFocus(false),
43989
44542
  onDoubleClick,
43990
- children: /* @__PURE__ */ jsx("div", {
44543
+ children: /* @__PURE__ */ jsx(ScrollArea, {
43991
44544
  className: `${markdownPreview_module_default.body} markdown-body`,
44545
+ autoHide: "leave",
43992
44546
  children: /* @__PURE__ */ jsx(Suspense, {
43993
44547
  fallback: /* @__PURE__ */ jsx("span", {
43994
44548
  hidden: true,
@@ -44166,6 +44720,7 @@ function CommentNodeContent({ store }) {
44166
44720
  setComposing(false);
44167
44721
  },
44168
44722
  onChange: (event) => store.$$.content.set(event.target.value),
44723
+ onPaste: (event) => pasteVideoLink(event, t),
44169
44724
  onBlur: (event) => {
44170
44725
  setFocused(false);
44171
44726
  if (editable && !composing) store.saveContent(event.target.value);
@@ -46620,9 +47175,6 @@ function DropdownMenuSeparator({ className, ...props }) {
46620
47175
  });
46621
47176
  }
46622
47177
  //#endregion
46623
- //#region src/canvas/browser/nodeActions.tsx
46624
- var NodeHistoryContext = createContext(void 0);
46625
- //#endregion
46626
47178
  //#region ../../node_modules/.bun/@base-ui+react@1.4.1+fa6c2f29eeb10566/node_modules/@base-ui/react/esm/context-menu/root/ContextMenuRoot.js
46627
47179
  /**
46628
47180
  * A component that creates a context menu activated by right clicking or long pressing.
@@ -46889,16 +47441,7 @@ function NodeHeadContextMenu({ canvasStore, children }) {
46889
47441
  function useNodeMenuItems({ t, nodeStore, onDelete, editable }) {
46890
47442
  const skip = useVal(NodeStore.to(nodeStore)?.ignore);
46891
47443
  const { duplicateNode } = nodeStore;
46892
- const history = useContext(NodeHistoryContext)?.(nodeStore.nodeId);
46893
47444
  return coalesce([
46894
- history && {
46895
- ...history,
46896
- key: "$history",
46897
- icon: /* @__PURE__ */ jsx("i", {
46898
- "aria-hidden": "true",
46899
- className: "i-lucide-light:database"
46900
- })
46901
- },
46902
47445
  editable && duplicateNode && {
46903
47446
  label: t("nodeActions.duplicate"),
46904
47447
  key: "$duplicate",
@@ -55390,7 +55933,7 @@ function tooShort(from, to) {
55390
55933
  }
55391
55934
  //#endregion
55392
55935
  //#region src/canvas/browser/graph/FlowCanvas/FlowCanvas.tsx
55393
- var FlowCanvas = ({ flowCanvasStore, annotationContext, onActivateSelection, onSelectionStart, onSelectionEnd, onInspectSelection, inspectorOpen = false, onRequestAddNode, cornerTools, cornerLeading, topLeftTools, bottomRightTools, toolbar, dark, dottedBackground, fitView, nodesDraggable, layoutMotion, className, addNodeRequest, addItemRequest, onMove, onMoveEnd, onNodeDragStop, onSelectionChange, isValidConnection, onDropAddItem }) => {
55936
+ var FlowCanvas = ({ flowCanvasStore, annotationContext, onActivateSelection, onSelectionStart, onSelectionEnd, onInspectSelection, inspectorOpen = false, onRequestAddNode, cornerTools, cornerLeading, topLeftTools, bottomRightTools, toolbar, dark, dottedBackground, fitView, nodesDraggable, layoutMotion, className, addNodeRequest, addItemRequest, onInit, onMove, onMoveEnd, onNodeDragStop, onSelectionChange, isValidConnection, onDropAddItem }) => {
55394
55937
  const editable = useVal(flowCanvasStore.$.editable);
55395
55938
  const direction = useVal(flowCanvasStore.$.direction);
55396
55939
  const changingDirection = useVal(flowCanvasStore.$.changingDirection);
@@ -55454,7 +55997,10 @@ var FlowCanvas = ({ flowCanvasStore, annotationContext, onActivateSelection, onS
55454
55997
  onRelayout: editable ? flowCanvasStore.onRelayout : void 0,
55455
55998
  onLayoutMeasured: flowCanvasStore.completeLayout,
55456
55999
  onInstance: flowCanvasStore.rfCommand.onRFInstance,
55457
- onInit: flowCanvasStore.onInit,
56000
+ onInit: (instance) => {
56001
+ flowCanvasStore.onInit();
56002
+ onInit?.(instance);
56003
+ },
55458
56004
  onCopy: flowCanvasStore.onCopy,
55459
56005
  onPaste: flowCanvasStore.onPaste,
55460
56006
  waitNode: flowCanvasStore.waitNode,
@@ -62228,9 +62774,29 @@ strictObject({
62228
62774
  kind: literal("open-flow-workflow"),
62229
62775
  version: literal(1),
62230
62776
  name: string$1().optional(),
62777
+ icon: string$1().optional(),
62778
+ description: string$1().optional(),
62231
62779
  content: unknown(),
62232
62780
  presentation: record$3(string$1(), json$4()).optional()
62233
62781
  });
62782
+ //#endregion
62783
+ //#region src/flow/common/workflowBundle.ts
62784
+ var entries = array(strictObject({
62785
+ flowId: string$1().min(1),
62786
+ file: unknown()
62787
+ })).min(1);
62788
+ strictObject({
62789
+ kind: literal("open-flow-workflow-bundle"),
62790
+ version: literal(1),
62791
+ entryFlowId: string$1().min(1),
62792
+ workflows: entries
62793
+ });
62794
+ strictObject({
62795
+ version: literal(1),
62796
+ entryFlowId: string$1().min(1),
62797
+ workflows: entries,
62798
+ unavailableFlowIds: array(string$1().min(1))
62799
+ });
62234
62800
  new TextEncoder();
62235
62801
  //#endregion
62236
62802
  //#region ../../node_modules/.bun/@babel+parser@8.0.4/node_modules/@babel/parser/lib/index.js
@@ -63247,11 +63813,10 @@ var RevisionView = class {
63247
63813
  }
63248
63814
  };
63249
63815
  function revisionView(revision) {
63250
- let view = views.get(revision);
63251
- if (view == null) {
63252
- view = new RevisionView(revision);
63253
- views.set(revision, view);
63254
- }
63816
+ const cached = views.get(revision);
63817
+ if (cached) return cached;
63818
+ const view = new RevisionView(revision);
63819
+ views.set(revision, view);
63255
63820
  return view;
63256
63821
  }
63257
63822
  function connectorAccessReferences(document) {
@@ -64373,7 +64938,7 @@ function nodeDiagnosticCount(node, diagnostics) {
64373
64938
  return diagnostics.filter((diagnostic) => paths.some((path) => diagnostic.path.startsWith(path))).length;
64374
64939
  }
64375
64940
  function runProjection(revision, run, events) {
64376
- if (run?.flowId != revision.revision.flowId || run.revisionId != revision.revision.revisionId) return { nodes: /* @__PURE__ */ new Map() };
64941
+ if (run == null || revision.revision.flowId == null || revision.revision.revisionId == null || run.flowId != revision.revision.flowId || run.revisionId != revision.revision.revisionId) return { nodes: /* @__PURE__ */ new Map() };
64377
64942
  const active = run.status == "queued" || run.status == "starting" || run.status == "running" || run.status == "waiting";
64378
64943
  const nodes = /* @__PURE__ */ new Map();
64379
64944
  if ("waits" in run) for (const wait of run.waits) nodes.set(wait.nodeId, {
@@ -65468,7 +66033,7 @@ function TabsContent({ className, ...props }) {
65468
66033
  }
65469
66034
  //#endregion
65470
66035
  //#region src/workbench/browser/runtime/editor/commentInspector.tsx
65471
- var MarkdownContent = lazy(() => import("./markdownContent-CAG_CQfH.js"));
66036
+ var MarkdownContent = lazy(() => import("./markdownContent-D8G_oNOe.js"));
65472
66037
  /** A comment is presentation data; editing it does not require the canvas store. */
65473
66038
  function CommentInspector({ title, content, disabled = false, readOnly, dark, onSave }) {
65474
66039
  const t = useTranslate();
@@ -65510,14 +66075,16 @@ function CommentInspector({ title, content, disabled = false, readOnly, dark, on
65510
66075
  readOnly,
65511
66076
  value: draftContent,
65512
66077
  onChange: (event) => setDraftContent(event.target.value),
66078
+ onPaste: (event) => pasteVideoLink(event, t),
65513
66079
  onBlur: save
65514
66080
  })
65515
66081
  }),
65516
66082
  /* @__PURE__ */ jsx(TabsContent, {
65517
66083
  value: "preview",
65518
66084
  className: "flex min-h-0 flex-1 flex-col rounded-[var(--ui-control-radius,calc(var(--ui-radius)_+_2px))] border border-[var(--_open-flow-comment-border)] bg-[var(--_open-flow-comment-surface)] p-2",
65519
- children: /* @__PURE__ */ jsx("div", {
65520
- className: "min-h-0 flex-1 overflow-auto rounded-[var(--ui-control-radius,calc(var(--ui-radius)_+_2px))] border border-[color-mix(in_srgb,var(--_open-flow-comment-border)_45%,transparent)] bg-[var(--_open-flow-comment-content)] p-3",
66085
+ children: /* @__PURE__ */ jsx(ScrollArea, {
66086
+ autoHide: "leave",
66087
+ className: "min-h-0 flex-1 rounded-[var(--ui-control-radius,calc(var(--ui-radius)_+_2px))] border border-[color-mix(in_srgb,var(--_open-flow-comment-border)_45%,transparent)] bg-[var(--_open-flow-comment-content)] p-3",
65521
66088
  children: /* @__PURE__ */ jsx("div", {
65522
66089
  className: "markdown-body min-w-0",
65523
66090
  onDoubleClick: () => setSource(true),
@@ -102224,14 +102791,24 @@ var resources = {
102224
102791
  "exportFlow": "Export workflow",
102225
102792
  "exportPng": "Export PNG image",
102226
102793
  "exportPngFrame": "Show frame",
102794
+ "exportPngCompact": "Compact layout",
102227
102795
  "exportPngLight": "Light",
102228
102796
  "exportPngDark": "Dark",
102229
- "exportPngPending": "Exporting PNG…",
102230
- "exportPngPendingDescription": "Preparing the workflow and image resources. Large images may take a little longer.",
102231
102797
  "exportPngComplete": "PNG image exported.",
102232
102798
  "exportPngPartial": "PNG image exported. Some images were replaced with placeholders.",
102233
102799
  "exportPngFailed": "Could not export the PNG image. Please try again.",
102234
- "importInvalid": "Invalid or unsupported workflow file."
102800
+ "importInvalid": "Invalid or unsupported workflow file.",
102801
+ "exportPngAspectRatio": "Canvas ratio",
102802
+ "exportPngAuto": "Auto",
102803
+ "exportPngLayout": "Layout",
102804
+ "exportPngOriginal": "Original",
102805
+ "exportPngTheme": "Theme",
102806
+ "exportPngPreview": "Preview",
102807
+ "exportPngPreviewPending": "Generating preview…",
102808
+ "exportPngPreviewFailed": "Could not generate the preview.",
102809
+ "exportPngPreviewPartial": "Some images could not load and were replaced with placeholders.",
102810
+ "exportPngDownload": "Download PNG",
102811
+ "exportPngPreviewRetry": "Retry"
102235
102812
  },
102236
102813
  inspector: /* @__PURE__ */ JSON.parse("{\"outline\":\"Node outline\",\"backToOutline\":\"Back to node outline\",\"emptyOutline\":\"No nodes yet\",\"triggers\":\"Triggers\",\"nodes\":\"Nodes\",\"multipleSelected\":\"{{count}} nodes selected\",\"account\":{\"contactAdmin\":\"You do not have permission to perform this operation. Contact an administrator.\",\"accessTitle\":\"Access permissions\",\"manageFlowAccess\":\"Connections available to Code\",\"configureAccess\":\"Choose an account\",\"manageAccount\":\"Manage accounts\",\"required\":\"Account connection required\",\"addAccount\":\"Add account\",\"manage\":\"Manage\",\"authorizationPending\":\"Finish authorization in the Connection page, then return here to refresh this account.\",\"chooseAccount\":\"Choose an account\",\"deferred\":\"Not configured for now\",\"clearDeferred\":\"Clear selection\",\"noAccounts\":\"No accounts available\",\"connectBeforeRun\":\"Connect {{service}} before this block can run or be published.\",\"connectService\":\"Connect {{service}}\",\"connection\":\"Connection\",\"loading\":\"Loading connections…\",\"oomolBuiltIn\":\"OOMOL Built-in\",\"missing\":\"The account selected for this node is unavailable. Choose another account or manage connections.\",\"refreshFailed\":\"Connections could not be refreshed.\",\"retry\":\"Retry\",\"status\":{\"disconnected\":\"This Connection is disconnected. Reconnect it or choose another account.\",\"error\":\"This Connection has an error. Repair it or choose another account.\",\"reauth_required\":\"This Connection needs authorization again. Reconnect it or choose another account.\"},\"statusUnavailable\":\"Connection status is unavailable for {{action}}.\",\"teamDefault\":\"Team default\",\"title\":\"Account\",\"unavailable\":\"unavailable\"},\"close\":\"Close inspector\",\"configurationRequired\":\"Configuration required\",\"diagnostics\":\"Diagnostics\",\"errors\":{\"jsonObject\":\"{{label}} must be a JSON object.\",\"portDefinitions\":\"Enter valid port definitions.\"},\"node\":{\"nameDuplicate\":\"A node with this name already exists in this graph.\",\"nameEmpty\":\"Node name cannot be empty.\",\"timeout\":\"Timeout (ms)\",\"maxExecutions\":\"Node execution limit\",\"maxExecutionsError\":\"Node execution limit must be a positive integer.\",\"timeoutError\":\"Timeout must be a positive integer in milliseconds.\",\"title\":\"Node settings\",\"description\":\"Purpose\",\"describe\":\"Describe what this step does.\",\"icon\":\"Icon\",\"name\":\"Title\",\"retry\":\"Retry on error\",\"retryCount\":\"Up to {{count}} retries\",\"retryInterval\":\"Retry interval\",\"retryError\":\"Use an interval of 1–60 whole seconds.\",\"retryHint\":\"The retry count is the number of additional attempts after the first execution. Retries repeat the entire node and may repeat external operations. The timeout includes all attempts and intervals.\",\"retryNone\":\"No retries\",\"retrySeconds\":\"seconds\",\"retryHelp\":\"About retries\",\"retryOnce\":\"Retry once\",\"onError\":\"On failure\",\"onErrorStop\":\"Stop workflow\",\"onErrorOutput\":\"Output to error port\",\"onErrorHelp\":\"About failure handling\",\"onErrorHint\":\"After retries fail, write the error to the system error output and continue along existing connections. On success, error is null. Cancellation, timeouts, resource limits and indeterminate outcomes still stop execution.\",\"systemOutputs\":\"System outputs\",\"systemError\":\"Error information (system)\",\"errorFields\":{\"error\":\"Error information when the node fails; null on success.\",\"code\":\"A code identifying the type of error.\",\"message\":\"A description of the error, with sensitive content redacted.\",\"nodeId\":\"The ID of the node that failed.\",\"nodeName\":\"The node name at the time of failure.\",\"runId\":\"The ID of this workflow run.\",\"executionId\":\"The ID of this node execution, shared across its retry attempts.\"}},\"selectNode\":\"Select one Draft node to inspect and edit it.\",\"locateNode\":\"Locate this node on the canvas\",\"task\":{\"sharedPermissions\":\"Use Flow shared permission group\",\"sharedPermissionsHint\":\"Use all Actions authorized by the Flow permission group. No need to add them to this node.\",\"httpHosts\":\"HTTP hosts\",\"httpHostsHint\":\"One host per line. *.example.com includes subdomains.\",\"httpHostsInvalid\":\"\\\"{{host}}\\\" is not a valid host. Use a host name such as api.example.com.\",\"httpHostsLimit\":\"Declare at most {{count}} hosts.\",\"addAction\":\"Add Action\",\"removeAction\":\"Remove Action\",\"actionAccount\":\"Account\",\"chooseAccount\":\"Choose an account\",\"permissionSaveFailed\":\"Could not save Code permissions. Retry the change.\",\"chatText\":\"Chat text\",\"connectorAction\":\"Connector action\",\"definition\":\"Task definition\",\"discardCode\":\"Discard changes\",\"editorLoading\":\"Loading editor…\",\"editorUnavailable\":\"The code editor couldn’t be loaded.\",\"inputPorts\":\"Input ports\",\"javascriptModule\":\"Code\",\"missing\":\"The referenced Task does not exist.\",\"outputPorts\":\"Output ports\",\"responseMode\":\"Response mode\",\"source\":\"Source\",\"structuredJson\":\"Structured JSON\",\"retrySave\":\"Retry save\",\"additionalInputs\":\"Additional inputs\",\"httpHostsUpdated\":\"Hosts changed elsewhere. The latest configuration is loaded; review it before saving.\"},\"wait\":{\"approval\":\"Approve or reject\",\"changeNotification\":\"Change\",\"continue\":\"Continue\",\"mode\":\"Resolution\",\"inputsLoading\":\"Loading notification parameters…\",\"pendingDescription\":\"The pending output fires once when waiting begins and provides confirmation links and related data. Connect it to send a message or run other steps.\",\"prompt\":\"Prompt\",\"promptError\":\"Prompt must contain 1 to 1,000 characters.\",\"autoContinue\":\"Automatic continuation\",\"autoOff\":\"Off\",\"autoAfter\":\"After a duration\",\"autoAt\":\"At a specific time\",\"autoSeconds\":\"Duration (seconds)\",\"autoDate\":\"Date and time\",\"autoInvalid\":\"Enter a positive duration or a valid date and time.\",\"autoDescription\":\"You can continue manually before the scheduled time.\"},\"title\":\"Inspector\",\"sources\":{\"loading\":\"Loading input sources…\",\"loadFailed\":\"Could not load input sources. Reopen the menu to retry.\",\"checkFailed\":\"Could not check this source.\",\"select\":\"Select input source\",\"title\":\"Input source\",\"sourceMissing\":\"The original input source no longer exists. Choose again.\",\"outputMissing\":\"“{{output}}” could not be found in “{{source}}”. Choose again.\",\"wholeObject\":\"Whole object\",\"fieldMissing\":\"Field {{field}} is no longer declared in “{{output}}”. Choose again.\",\"notReady\":\"“{{source}} {{handle}}” may not have a value when this step runs.\",\"sourceConflict\":\"These fields may have values at the same time: {{sources}}. Only one can be used here.\",\"incompatibleRight\":\"The right value type is incompatible with this comparison.\",\"incompatible\":\"Mismatch\",\"unverified\":\"Unverified\",\"schemaIncompatible\":\"The data format does not match.\",\"schemaPathIncompatible\":\"The data format of “{{path}}” does not match.\",\"schemaCompareFailed\":\"Could not check the data format. Check the JSON Schema.\",\"binaryIncompatible\":\"Binary data cannot be used here.\",\"artifactIncompatible\":\"File data cannot be used here.\",\"nullableIncompatible\":\"A value is required, but the selected field may be empty.\",\"typeIncompatible\":\"Expected {{target}}, but the selected field is {{source}}.\",\"propertyTypeIncompatible\":\"“{{path}}” must be {{target}}, but it is {{source}}.\",\"requiredIncompatible\":\"The required property “{{property}}” may be missing.\",\"enumIncompatible\":\"Some possible values are not accepted: {{values}}.\",\"constIncompatible\":\"Only {{target}} is accepted, but the selected field is always {{source}}.\",\"constraintSubject\":\"“{{path}}” \",\"minLength\":\"{{subject}}must contain at least {{value}} characters.\",\"maxLength\":\"{{subject}}must contain at most {{value}} characters.\",\"pattern\":\"{{subject}}must match {{value}}.\",\"minimum\":\"{{subject}}cannot be less than {{value}}.\",\"exclusiveMinimum\":\"{{subject}}must be greater than {{value}}.\",\"maximum\":\"{{subject}}cannot be greater than {{value}}.\",\"exclusiveMaximum\":\"{{subject}}must be less than {{value}}.\",\"multipleOf\":\"{{subject}}must be a multiple of {{value}}.\",\"minItems\":\"{{subject}}must contain at least {{value}} items.\",\"maxItems\":\"{{subject}}must contain at most {{value}} items.\",\"minProperties\":\"{{subject}}must contain at least {{value}} properties.\",\"maxProperties\":\"{{subject}}must contain at most {{value}} properties.\",\"integer\":\"Integer\",\"unknownType\":\"unknown type\",\"typeSeparator\":\" or \"},\"actions\":{\"flowAccess\":\"Available services\",\"flowAccessHint\":\"Manage connections shared by all Code nodes in this Flow\",\"chooseConnection\":\"Choose a {{provider}} connection\",\"connectionDescription\":\"The connection is inserted into this call. Flow provider access still controls whether it may be used.\",\"title\":\"Actions available to this code\",\"search\":\"Search actions\",\"description\":\"Choose the actions and accounts this code can use.\",\"empty\":\"No matching actions.\",\"remove\":\"Remove\",\"default\":\"Default account\",\"defaultHint\":\"Used when the call does not specify an account.\",\"removeAction\":\"Remove action\",\"explicit\":\"Choose explicitly in code\",\"connect\":\"Connect account\",\"refresh\":\"Refresh accounts\",\"aliases\":\"Update saved aliases\",\"add\":\"Add action\",\"cancel\":\"Cancel\",\"loading\":\"Searching…\",\"needsAccount\":\"Connect an account\",\"accounts\":\"{{count}} accounts\",\"public\":\"No account needed\",\"allowed\":\"Allowed accounts\",\"unavailable\":\"Unavailable\",\"details\":\"Connection details\",\"example\":\"Call example\",\"syntax\":\"Call syntax\",\"nested\":\"Provider method\",\"fullId\":\"Full ID\",\"copy\":\"Copy\",\"copied\":\"Copied\",\"copyError\":\"Copy failed. Select the code and copy it manually.\",\"introDescription\":\"Add actions as needed to call external apps through {{context}}.\",\"insertAction\":\"Insert code\",\"chooseAccounts\":\"Manage accounts\"},\"comment\":{\"markdown\":\"Markdown\",\"preview\":\"Preview\"},\"ports\":{\"reorder\":\"Reorder {{name}}\",\"reorderHint\":\"Drag to reorder within the group, or use Up / Down while focused.\",\"moved\":\"{{name}} moved to position {{position}}.\",\"groupSettings\":\"Group settings\",\"connected\":\"Connected\",\"sort\":\"Sort\",\"finishSorting\":\"Done sorting\",\"inputsTitle\":\"Inputs\",\"requiredInputs\":\"Required\",\"optionalInputs\":\"Optional\",\"noInputs\":\"This node does not require input data.\",\"noOutputs\":\"This node does not provide output data.\",\"outputsTitle\":\"Outputs\",\"valuesTitle\":\"Values\",\"columnHandle\":\"Handle\",\"columnName\":\"Name\",\"columnType\":\"Type\",\"columnValue\":\"Value\",\"builtIn\":{\"cron\":{\"scheduledAt\":\"The scheduled time that triggered this run, in ISO 8601 format.\"},\"webhook\":{\"headers\":\"The headers received with this Webhook request.\",\"query\":\"The URL query parameters received with this Webhook request.\",\"body\":\"The body received with this Webhook request.\",\"webhookUrl\":\"The Webhook URL that received this request, without query parameters.\"}},\"startParametersTitle\":\"Start parameters\"}}"),
102237
102814
  language: { "label": "Language" },
@@ -103315,7 +103892,10 @@ var resources = {
103315
103892
  "discardTitle": "Discard changes?",
103316
103893
  "discardDescription": "Your Flow settings have not been saved.",
103317
103894
  "continueEditing": "Continue editing",
103318
- "discardChanges": "Discard changes"
103895
+ "discardChanges": "Discard changes",
103896
+ "icon": "Icon",
103897
+ "resetIcon": "Reset icon",
103898
+ "description": "Description"
103319
103899
  },
103320
103900
  flowState: {
103321
103901
  "title": "Persistent data",
@@ -103329,7 +103909,7 @@ var resources = {
103329
103909
  "clear": "Clear",
103330
103910
  "orphaned": "Outside the current view",
103331
103911
  "nearLimit": "Flow history is at least 80% full. Clear unused history.",
103332
- "history": "Usage",
103912
+ "usage": "Usage",
103333
103913
  "scope": "Scope",
103334
103914
  "refresh": "Refresh",
103335
103915
  "cancel": "Cancel",
@@ -103357,7 +103937,7 @@ var resources = {
103357
103937
  "pendingClear": "{{count}} pending; finish or cancel their Runs before clearing.",
103358
103938
  "clearBlocked": "This history has pending records. Finish or cancel their Runs, then refresh.",
103359
103939
  "clearSource": "Clear {{name}}",
103360
- "sourceHistory": "{{name}} history",
103940
+ "sourceUsage": "{{name}} usage",
103361
103941
  "confirmTitle": "Clear {{name}}?",
103362
103942
  "confirmValues": "This will clear {{count}} saved entries in {{scope}}. Subsequent Runs will no longer be able to read these values.",
103363
103943
  "confirmHistory": "This will clear {{count}} deduplication records in {{scope}}. These items may be processed again.",
@@ -103368,6 +103948,14 @@ var resources = {
103368
103948
  "loadFailed": "Unable to load",
103369
103949
  "valuesHelp": "{{name}}: Content explicitly saved by the workflow, available to later runs.",
103370
103950
  "historyHelp": "{{name}}: Item identifiers used to avoid processing duplicates."
103951
+ },
103952
+ workflowTransfer: {
103953
+ "includeDependencies": "Include referenced workflows",
103954
+ "workflowCount": "Workflows ({{count}})",
103955
+ "unavailable": "Unavailable workflows: {{count}}.",
103956
+ "export": "Export",
103957
+ "hostUnsupported": "This host does not support workflow bundle imports yet.",
103958
+ "unnamed": "Untitled workflow"
103371
103959
  }
103372
103960
  },
103373
103961
  "zh-CN": {
@@ -103593,14 +104181,24 @@ var resources = {
103593
104181
  "exportFlow": "导出工作流",
103594
104182
  "exportPng": "导出 PNG 图片",
103595
104183
  "exportPngFrame": "显示外框",
104184
+ "exportPngCompact": "紧凑布局",
103596
104185
  "exportPngLight": "浅色",
103597
104186
  "exportPngDark": "深色",
103598
- "exportPngPending": "正在导出 PNG…",
103599
- "exportPngPendingDescription": "正在处理工作流和图片资源,图片较大时可能需要一些时间。",
103600
104187
  "exportPngComplete": "PNG 图片已导出。",
103601
104188
  "exportPngPartial": "PNG 图片已导出,部分图片已用占位图替代。",
103602
104189
  "exportPngFailed": "PNG 图片导出失败,请重试。",
103603
- "importInvalid": "文件损坏或工作流格式不受支持。"
104190
+ "importInvalid": "文件损坏或工作流格式不受支持。",
104191
+ "exportPngAspectRatio": "画布比例",
104192
+ "exportPngAuto": "自动",
104193
+ "exportPngLayout": "布局",
104194
+ "exportPngOriginal": "原布局",
104195
+ "exportPngTheme": "主题",
104196
+ "exportPngPreview": "预览",
104197
+ "exportPngPreviewPending": "正在生成预览…",
104198
+ "exportPngPreviewFailed": "预览生成失败,请重试。",
104199
+ "exportPngPreviewPartial": "部分图片加载失败,已使用占位图。",
104200
+ "exportPngDownload": "下载 PNG",
104201
+ "exportPngPreviewRetry": "重试"
103604
104202
  },
103605
104203
  inspector: /* @__PURE__ */ JSON.parse("{\"outline\":\"节点大纲\",\"backToOutline\":\"返回节点大纲\",\"emptyOutline\":\"暂无节点\",\"triggers\":\"触发器\",\"nodes\":\"节点\",\"multipleSelected\":\"已选择 {{count}} 个节点\",\"account\":{\"contactAdmin\":\"你没有执行此操作的权限,请联系管理员。\",\"accessTitle\":\"访问权限\",\"manageFlowAccess\":\"Code 允许使用的连接\",\"configureAccess\":\"选择可用账号\",\"manageAccount\":\"管理账号\",\"required\":\"待连接账号\",\"addAccount\":\"添加账号\",\"manage\":\"管理\",\"authorizationPending\":\"请在 Connection 页面完成授权,返回这里后会刷新当前账号。\",\"chooseAccount\":\"选择账号\",\"deferred\":\"暂不设置\",\"clearDeferred\":\"清除选择\",\"noAccounts\":\"暂无可用账号\",\"connectBeforeRun\":\"请先连接 {{service}},此节点才能运行或发布。\",\"connectService\":\"连接 {{service}}\",\"connection\":\"连接\",\"loading\":\"正在加载连接…\",\"oomolBuiltIn\":\"OOMOL 内置账号\",\"missing\":\"此节点选择的账号当前不可用,请选择其他账号或管理账号。\",\"refreshFailed\":\"无法刷新 Connection。\",\"retry\":\"重试\",\"status\":{\"disconnected\":\"此 Connection 已断开,请重新连接或选择其他账号。\",\"error\":\"此 Connection 状态异常,请修复后重试或选择其他账号。\",\"reauth_required\":\"此 Connection 需要重新授权,请重新连接或选择其他账号。\"},\"statusUnavailable\":\"暂时无法获取 {{action}} 的连接状态。\",\"teamDefault\":\"团队默认\",\"title\":\"账号\",\"unavailable\":\"不可用\"},\"close\":\"关闭检查器\",\"configurationRequired\":\"配置待完成\",\"diagnostics\":\"诊断\",\"errors\":{\"jsonObject\":\"{{label}} 必须是 JSON 对象。\",\"portDefinitions\":\"请输入有效的端口定义。\"},\"node\":{\"nameDuplicate\":\"当前图中已存在同名节点。\",\"nameEmpty\":\"节点名称不能为空。\",\"timeout\":\"超时时间(毫秒)\",\"maxExecutions\":\"节点执行上限\",\"maxExecutionsError\":\"节点执行上限必须是正整数。\",\"timeoutError\":\"超时时间必须是以毫秒为单位的正整数。\",\"title\":\"节点设置\",\"description\":\"用途说明\",\"describe\":\"描述这一步要完成什么。\",\"icon\":\"图标\",\"name\":\"标题\",\"retry\":\"失败重试\",\"retryCount\":\"最多重试 {{count}} 次\",\"retryInterval\":\"重试间隔\",\"retryError\":\"间隔须为 1~60 整数秒。\",\"retryHint\":\"重试次数是首次执行失败后的追加次数。重试会重新执行整个节点,可能重复外部操作。超时包含全部尝试和等待间隔。\",\"retryNone\":\"不重试\",\"retrySeconds\":\"秒\",\"retryHelp\":\"重试说明\",\"retryOnce\":\"最多重试 1 次\",\"onError\":\"失败处理\",\"onErrorStop\":\"终止工作流\",\"onErrorOutput\":\"输出到 error 端口\",\"onErrorHelp\":\"失败处理说明\",\"onErrorHint\":\"重试后仍失败时,将错误写入系统 error 并沿现有连线继续。成功时 error 为 null。取消、超时、资源限制和结果不确定仍终止工作流。\",\"systemOutputs\":\"系统输出\",\"systemError\":\"错误信息(系统)\",\"errorFields\":{\"error\":\"节点失败时的错误信息;成功时为 null。\",\"code\":\"用于识别错误类型的错误码。\",\"message\":\"错误的说明信息,敏感内容已脱敏。\",\"nodeId\":\"发生错误的节点 ID。\",\"nodeName\":\"发生错误时的节点名称。\",\"runId\":\"本次工作流运行的 ID。\",\"executionId\":\"本次节点执行的 ID,多次重试共用此 ID。\"}},\"selectNode\":\"选择一个草稿节点以查看和编辑。\",\"locateNode\":\"在画布上定位该节点\",\"task\":{\"sharedPermissions\":\"使用 Flow 共享权限组\",\"sharedPermissionsHint\":\"直接使用 Flow 共享权限组已授权的全部 Actions,无需逐个添加。\",\"httpHosts\":\"HTTP 主机\",\"httpHostsHint\":\"每行一个主机,支持 *.example.com 子域名匹配。\",\"httpHostsInvalid\":\"“{{host}}”不是有效的主机,请填写 api.example.com 这样的主机名。\",\"httpHostsLimit\":\"最多声明 {{count}} 个主机。\",\"addAction\":\"添加 Action\",\"removeAction\":\"移除 Action\",\"actionAccount\":\"账号\",\"chooseAccount\":\"选择账号\",\"permissionSaveFailed\":\"无法保存 Code 权限,请重试。\",\"chatText\":\"对话文本\",\"connectorAction\":\"连接器操作\",\"definition\":\"任务定义\",\"discardCode\":\"放弃修改\",\"editorLoading\":\"正在加载编辑器…\",\"editorUnavailable\":\"代码编辑器加载失败。\",\"inputPorts\":\"输入端口\",\"javascriptModule\":\"代码\",\"missing\":\"引用的任务不存在。\",\"outputPorts\":\"输出端口\",\"responseMode\":\"响应模式\",\"source\":\"源代码\",\"structuredJson\":\"结构化 JSON\",\"retrySave\":\"重试保存\",\"additionalInputs\":\"附加输入\",\"httpHostsUpdated\":\"主机配置已在别处更新。已加载最新配置,请检查后再保存。\"},\"wait\":{\"approval\":\"通过或拒绝\",\"changeNotification\":\"更换\",\"continue\":\"继续\",\"mode\":\"处理方式\",\"inputsLoading\":\"正在加载通知参数…\",\"pendingDescription\":\"待确认出口在开始等待时触发一次,提供确认链接及相关数据。连接此出口可发送消息或执行其他步骤。\",\"prompt\":\"提示\",\"promptError\":\"提示必须包含 1 到 1,000 个字符。\",\"autoContinue\":\"自动继续\",\"autoOff\":\"关闭\",\"autoAfter\":\"等待一段时间\",\"autoAt\":\"到指定时间\",\"autoSeconds\":\"等待时长(秒)\",\"autoDate\":\"日期和时间\",\"autoInvalid\":\"请输入正数时长或有效的日期和时间。\",\"autoDescription\":\"可提前手动继续。\"},\"title\":\"检查器\",\"sources\":{\"loading\":\"正在加载输入来源…\",\"loadFailed\":\"无法加载输入来源,请重新打开菜单重试。\",\"checkFailed\":\"无法检查此来源。\",\"select\":\"选择输入来源\",\"title\":\"输入来源\",\"sourceMissing\":\"原输入来源已不存在,请重新选择。\",\"outputMissing\":\"“{{source}}”中找不到“{{output}}”,请重新选择。\",\"wholeObject\":\"整个对象\",\"fieldMissing\":\"“{{output}}”中已不再声明字段 {{field}},请重新选择。\",\"notReady\":\"运行到这里时,“{{source}} {{handle}}”可能还没有值。\",\"sourceConflict\":\"这些字段可能同时有值:{{sources}}。这里只能取一个。\",\"incompatibleRight\":\"右值类型不符合此比较的要求。\",\"incompatible\":\"不兼容\",\"unverified\":\"无法验证\",\"schemaIncompatible\":\"数据格式不匹配。\",\"schemaPathIncompatible\":\"“{{path}}”的数据格式不匹配。\",\"schemaCompareFailed\":\"无法检查数据格式,请检查 JSON Schema。\",\"binaryIncompatible\":\"不能使用二进制数据。\",\"artifactIncompatible\":\"不能使用文件数据。\",\"nullableIncompatible\":\"不能为空,但所选字段可能为空。\",\"typeIncompatible\":\"需要{{target}},但所选字段是{{source}}。\",\"propertyTypeIncompatible\":\"“{{path}}”需要{{target}},实际是{{source}}。\",\"requiredIncompatible\":\"不一定包含必填属性“{{property}}”。\",\"enumIncompatible\":\"可能出现不接受的值:{{values}}。\",\"constIncompatible\":\"只接受 {{target}},所选字段固定为 {{source}}。\",\"constraintSubject\":\"“{{path}}”\",\"minLength\":\"{{subject}}至少需要 {{value}} 个字符。\",\"maxLength\":\"{{subject}}最多接受 {{value}} 个字符。\",\"pattern\":\"{{subject}}文本格式应符合 {{value}}。\",\"minimum\":\"{{subject}}不能小于 {{value}}。\",\"exclusiveMinimum\":\"{{subject}}必须大于 {{value}}。\",\"maximum\":\"{{subject}}不能大于 {{value}}。\",\"exclusiveMaximum\":\"{{subject}}必须小于 {{value}}。\",\"multipleOf\":\"{{subject}}必须是 {{value}} 的倍数。\",\"minItems\":\"{{subject}}至少需要 {{value}} 项。\",\"maxItems\":\"{{subject}}最多接受 {{value}} 项。\",\"minProperties\":\"{{subject}}至少需要 {{value}} 个属性。\",\"maxProperties\":\"{{subject}}最多接受 {{value}} 个属性。\",\"integer\":\"整数\",\"unknownType\":\"未知类型\",\"typeSeparator\":\"或\"},\"actions\":{\"flowAccess\":\"可用服务\",\"flowAccessHint\":\"管理整个工作流的 Code 共享使用的连接\",\"chooseConnection\":\"选择 {{provider}} Connection\",\"connectionDescription\":\"Connection 将写入本次调用;是否允许使用仍由工作流 Provider Access 决定。\",\"title\":\"代码可调用的动作\",\"search\":\"搜索应用或动作…\",\"description\":\"搜索并添加这段代码需要调用的动作。\",\"empty\":\"没有匹配的 Action。\",\"remove\":\"移除\",\"default\":\"默认账号\",\"defaultHint\":\"调用时未指定账号,将使用此账号。\",\"removeAction\":\"移除动作\",\"explicit\":\"每次调用时指定\",\"connect\":\"连接账号\",\"refresh\":\"刷新账号\",\"aliases\":\"同步账号别名\",\"add\":\"添加动作\",\"cancel\":\"取消\",\"loading\":\"搜索中…\",\"needsAccount\":\"待连接账号\",\"accounts\":\"{{count}} 个账号\",\"public\":\"无需账号\",\"allowed\":\"允许使用的账号\",\"unavailable\":\"不可用\",\"details\":\"账号详情\",\"example\":\"调用示例\",\"syntax\":\"调用写法\",\"nested\":\"分层写法\",\"fullId\":\"完整 ID\",\"copy\":\"复制\",\"copied\":\"已复制\",\"copyError\":\"复制失败,请选中示例代码手动复制。\",\"introDescription\":\"按需添加动作,通过 {{context}} 调用外部应用。\",\"insertAction\":\"插入代码\",\"chooseAccounts\":\"管理账号\"},\"comment\":{\"markdown\":\"Markdown\",\"preview\":\"预览\"},\"ports\":{\"reorder\":\"调整 {{name}} 的顺序\",\"reorderHint\":\"拖动调整组内顺序,或聚焦后使用上、下方向键。\",\"moved\":\"{{name}} 已移至第 {{position}} 位。\",\"groupSettings\":\"分组设置\",\"connected\":\"已连接\",\"sort\":\"排序\",\"finishSorting\":\"完成排序\",\"inputsTitle\":\"输入\",\"requiredInputs\":\"必填\",\"optionalInputs\":\"选填\",\"noInputs\":\"此节点不需要输入数据\",\"noOutputs\":\"此节点不提供输出数据\",\"outputsTitle\":\"输出\",\"valuesTitle\":\"数据\",\"columnHandle\":\"Handle\",\"columnName\":\"名称\",\"columnType\":\"类型\",\"columnValue\":\"值\",\"builtIn\":{\"cron\":{\"scheduledAt\":\"本次运行的计划触发时间,采用 ISO 8601 格式。\"},\"webhook\":{\"headers\":\"此 Webhook 请求携带的请求头。\",\"query\":\"此 Webhook 请求携带的 URL 查询参数。\",\"body\":\"此 Webhook 请求携带的请求体。\",\"webhookUrl\":\"接收此次请求的 Webhook URL,不含查询参数。\"}},\"startParametersTitle\":\"启动参数\"}}"),
103606
104204
  language: { "label": "语言" },
@@ -104684,7 +105282,10 @@ var resources = {
104684
105282
  "discardTitle": "放弃修改?",
104685
105283
  "discardDescription": "工作流设置的修改尚未保存。",
104686
105284
  "continueEditing": "继续编辑",
104687
- "discardChanges": "放弃修改"
105285
+ "discardChanges": "放弃修改",
105286
+ "icon": "图标",
105287
+ "resetIcon": "重置图标",
105288
+ "description": "描述"
104688
105289
  },
104689
105290
  flowState: {
104690
105291
  "title": "持久化数据",
@@ -104698,7 +105299,7 @@ var resources = {
104698
105299
  "clear": "清空",
104699
105300
  "orphaned": "当前视图外",
104700
105301
  "nearLimit": "该工作流的去重记录已使用至少 80%。请清理不再需要的记录。",
104701
- "history": "用量",
105302
+ "usage": "用量",
104702
105303
  "scope": "作用域",
104703
105304
  "refresh": "刷新",
104704
105305
  "cancel": "取消",
@@ -104726,7 +105327,7 @@ var resources = {
104726
105327
  "pendingClear": "{{count}} 条待提交,相关运行结束或取消后可清理。",
104727
105328
  "clearBlocked": "这些记录尚待提交。请等待相关运行结束或取消后再刷新。",
104728
105329
  "clearSource": "清空{{name}}",
104729
- "sourceHistory": "{{name}}的历史记录",
105330
+ "sourceUsage": "{{name}}用量",
104730
105331
  "confirmTitle": "清空「{{name}}」?",
104731
105332
  "confirmValues": "将清空{{scope}}环境保存的 {{count}} 条数据,后续运行将无法读取这些值。",
104732
105333
  "confirmHistory": "将清空{{scope}}环境的 {{count}} 条去重记录,这些条目之后可能再次被处理。",
@@ -104737,6 +105338,14 @@ var resources = {
104737
105338
  "loadFailed": "加载失败",
104738
105339
  "valuesHelp": "{{name}}:工作流主动保存的内容,后续运行可以继续读取。",
104739
105340
  "historyHelp": "{{name}}:条目的识别标记,用来避免重复处理。"
105341
+ },
105342
+ workflowTransfer: {
105343
+ "includeDependencies": "包含引用的工作流",
105344
+ "workflowCount": "{{count}} 个工作流",
105345
+ "unavailable": "{{count}} 个引用的工作流不可用。",
105346
+ "export": "导出",
105347
+ "hostUnsupported": "当前宿主尚不支持导入工作流包。",
105348
+ "unnamed": "未命名工作流"
104740
105349
  }
104741
105350
  },
104742
105351
  "zh-TW": {
@@ -104962,14 +105571,24 @@ var resources = {
104962
105571
  "exportFlow": "匯出工作流",
104963
105572
  "exportPng": "匯出 PNG 圖片",
104964
105573
  "exportPngFrame": "顯示外框",
105574
+ "exportPngCompact": "緊湊配置",
104965
105575
  "exportPngLight": "淺色",
104966
105576
  "exportPngDark": "深色",
104967
- "exportPngPending": "正在匯出 PNG…",
104968
- "exportPngPendingDescription": "正在處理工作流程和圖片資源,圖片較大時可能需要一些時間。",
104969
105577
  "exportPngComplete": "PNG 圖片已匯出。",
104970
105578
  "exportPngPartial": "PNG 圖片已匯出,部分圖片已用佔位圖替代。",
104971
105579
  "exportPngFailed": "PNG 圖片匯出失敗,請重試。",
104972
- "importInvalid": "檔案損壞或工作流格式不受支援。"
105580
+ "importInvalid": "檔案損壞或工作流格式不受支援。",
105581
+ "exportPngAspectRatio": "畫布比例",
105582
+ "exportPngAuto": "自動",
105583
+ "exportPngLayout": "配置",
105584
+ "exportPngOriginal": "原配置",
105585
+ "exportPngTheme": "主題",
105586
+ "exportPngPreview": "預覽",
105587
+ "exportPngPreviewPending": "正在產生預覽…",
105588
+ "exportPngPreviewFailed": "無法產生預覽,請重試。",
105589
+ "exportPngPreviewPartial": "部分圖片載入失敗,已使用預留位置圖片。",
105590
+ "exportPngDownload": "下載 PNG",
105591
+ "exportPngPreviewRetry": "重試"
104973
105592
  },
104974
105593
  inspector: /* @__PURE__ */ JSON.parse("{\"outline\":\"節點大綱\",\"backToOutline\":\"返回節點大綱\",\"emptyOutline\":\"暫無節點\",\"triggers\":\"觸發器\",\"nodes\":\"節點\",\"multipleSelected\":\"已選擇 {{count}} 個節點\",\"account\":{\"contactAdmin\":\"你沒有執行此操作的權限,請聯絡管理員。\",\"accessTitle\":\"存取權限\",\"manageFlowAccess\":\"Code 允許使用的連線\",\"configureAccess\":\"選擇可用帳號\",\"manageAccount\":\"管理帳號\",\"required\":\"待連線帳號\",\"addAccount\":\"新增帳號\",\"manage\":\"管理\",\"authorizationPending\":\"請在 Connection 頁面完成授權,再回到這裡重新整理這個帳號。\",\"chooseAccount\":\"選擇帳號\",\"deferred\":\"暫不設定\",\"clearDeferred\":\"清除選擇\",\"noAccounts\":\"暫無可用帳號\",\"connectBeforeRun\":\"請先連接 {{service}},這個節點才能執行或發布。\",\"connectService\":\"連接 {{service}}\",\"connection\":\"Connection\",\"loading\":\"正在載入 Connection…\",\"oomolBuiltIn\":\"OOMOL 內建帳號\",\"missing\":\"此節點選擇的帳號目前無法使用,請選擇其他帳號或管理帳號。\",\"refreshFailed\":\"無法重新整理 Connection。\",\"retry\":\"重試\",\"status\":{\"disconnected\":\"這個 Connection 已中斷。請重新連接或選擇其他帳號。\",\"error\":\"這個 Connection 發生錯誤。請修復它或選擇其他帳號。\",\"reauth_required\":\"這個 Connection 需要重新授權。請重新連接或選擇其他帳號。\"},\"statusUnavailable\":\"無法取得 {{action}} 的 Connection 狀態。\",\"teamDefault\":\"團隊預設\",\"title\":\"帳號\",\"unavailable\":\"無法使用\"},\"close\":\"關閉檢查器\",\"configurationRequired\":\"尚未完成設定\",\"diagnostics\":\"診斷\",\"errors\":{\"jsonObject\":\"{{label}} 必須是 JSON 物件。\",\"portDefinitions\":\"請輸入有效的埠定義。\"},\"node\":{\"nameDuplicate\":\"目前圖中已存在同名節點。\",\"nameEmpty\":\"節點名稱不能為空。\",\"timeout\":\"逾時時間(毫秒)\",\"maxExecutions\":\"節點執行上限\",\"maxExecutionsError\":\"節點執行上限必須是正整數。\",\"timeoutError\":\"逾時時間必須是以毫秒為單位的正整數。\",\"title\":\"節點設定\",\"description\":\"用途說明\",\"describe\":\"描述這個步驟要完成什麼。\",\"icon\":\"圖示\",\"name\":\"標題\",\"retry\":\"失敗重試\",\"retryCount\":\"最多重試 {{count}} 次\",\"retryInterval\":\"重試間隔\",\"retryError\":\"間隔須為 1~60 整數秒。\",\"retryHint\":\"重試次數是首次執行失敗後的追加次數。重試會重新執行整個節點,可能重複外部操作。逾時包含全部嘗試和等待間隔。\",\"retryNone\":\"不重試\",\"retrySeconds\":\"秒\",\"retryHelp\":\"重試說明\",\"retryOnce\":\"最多重試 1 次\",\"onError\":\"失敗處理\",\"onErrorStop\":\"終止工作流程\",\"onErrorOutput\":\"輸出至 error 連接埠\",\"onErrorHelp\":\"失敗處理說明\",\"onErrorHint\":\"重試後仍失敗時,將錯誤寫入系統 error 並沿現有連線繼續。成功時 error 為 null。取消、逾時、資源限制及結果不確定仍終止工作流程。\",\"systemOutputs\":\"系統輸出\",\"systemError\":\"錯誤資訊(系統)\",\"errorFields\":{\"error\":\"節點失敗時的錯誤資訊;成功時為 null。\",\"code\":\"用於識別錯誤類型的錯誤碼。\",\"message\":\"錯誤的說明資訊,敏感內容已遮蔽。\",\"nodeId\":\"發生錯誤的節點 ID。\",\"nodeName\":\"發生錯誤時的節點名稱。\",\"runId\":\"本次工作流程執行的 ID。\",\"executionId\":\"本次節點執行的 ID,多次重試共用此 ID。\"}},\"selectNode\":\"選取一個草稿節點即可檢視並編輯它。\",\"locateNode\":\"在畫布上定位此節點\",\"task\":{\"sharedPermissions\":\"使用 Flow 共用權限群組\",\"sharedPermissionsHint\":\"直接使用 Flow 共用權限群組已授權的所有 Actions,無需逐一新增。\",\"httpHosts\":\"HTTP 主機\",\"httpHostsHint\":\"每行一個主機,支援 *.example.com 子網域比對。\",\"httpHostsInvalid\":\"「{{host}}」不是有效的主機,請填寫 api.example.com 這類主機名稱。\",\"httpHostsLimit\":\"最多宣告 {{count}} 個主機。\",\"addAction\":\"新增 Action\",\"removeAction\":\"移除 Action\",\"actionAccount\":\"帳號\",\"chooseAccount\":\"選擇帳號\",\"permissionSaveFailed\":\"無法儲存 Code 權限,請重試。\",\"chatText\":\"對話文字\",\"connectorAction\":\"Connector 操作\",\"definition\":\"任務定義\",\"discardCode\":\"放棄變更\",\"editorLoading\":\"正在載入編輯器…\",\"editorUnavailable\":\"無法載入程式碼編輯器。\",\"inputPorts\":\"輸入埠\",\"javascriptModule\":\"程式碼\",\"missing\":\"引用的任務不存在。\",\"outputPorts\":\"輸出埠\",\"responseMode\":\"回應模式\",\"source\":\"原始碼\",\"structuredJson\":\"結構化 JSON\",\"retrySave\":\"重試儲存\",\"additionalInputs\":\"附加輸入\",\"httpHostsUpdated\":\"主機設定已在別處更新。已載入最新設定,請檢查後再儲存。\"},\"wait\":{\"approval\":\"通過或拒絕\",\"changeNotification\":\"更換\",\"continue\":\"繼續\",\"mode\":\"處理方式\",\"inputsLoading\":\"正在載入通知參數…\",\"pendingDescription\":\"待確認出口在開始等待時觸發一次,提供確認連結及相關資料。連接此出口可傳送訊息或執行其他步驟。\",\"prompt\":\"提示\",\"promptError\":\"提示必須包含 1 到 1,000 個字元。\",\"autoContinue\":\"自動繼續\",\"autoOff\":\"關閉\",\"autoAfter\":\"等待一段時間\",\"autoAt\":\"到指定時間\",\"autoSeconds\":\"等待時長(秒)\",\"autoDate\":\"日期和時間\",\"autoInvalid\":\"請輸入正數時長或有效的日期和時間。\",\"autoDescription\":\"可提前手動繼續。\"},\"title\":\"檢查器\",\"sources\":{\"loading\":\"正在載入輸入來源…\",\"loadFailed\":\"無法載入輸入來源,請重新開啟選單重試。\",\"checkFailed\":\"無法檢查此來源。\",\"select\":\"選擇輸入來源\",\"title\":\"輸入來源\",\"sourceMissing\":\"原輸入來源已不存在,請重新選擇。\",\"outputMissing\":\"「{{source}}」中找不到「{{output}}」,請重新選擇。\",\"wholeObject\":\"整個物件\",\"fieldMissing\":\"「{{output}}」中已不再宣告欄位 {{field}},請重新選擇。\",\"notReady\":\"執行到這裡時,「{{source}} {{handle}}」可能還沒有值。\",\"sourceConflict\":\"這些欄位可能同時有值:{{sources}}。這裡只能取一個。\",\"incompatibleRight\":\"右值類型不符合此比較的要求。\",\"incompatible\":\"不相容\",\"unverified\":\"無法驗證\",\"schemaIncompatible\":\"資料格式不符。\",\"schemaPathIncompatible\":\"「{{path}}」的資料格式不符。\",\"schemaCompareFailed\":\"無法檢查資料格式,請檢查 JSON Schema。\",\"binaryIncompatible\":\"不能使用二進位資料。\",\"artifactIncompatible\":\"不能使用檔案資料。\",\"nullableIncompatible\":\"不能為空,但所選欄位可能為空。\",\"typeIncompatible\":\"需要{{target}},但所選欄位是{{source}}。\",\"propertyTypeIncompatible\":\"「{{path}}」需要{{target}},實際是{{source}}。\",\"requiredIncompatible\":\"不一定包含必填屬性「{{property}}」。\",\"enumIncompatible\":\"可能出現不接受的值:{{values}}。\",\"constIncompatible\":\"只接受 {{target}},所選欄位固定為 {{source}}。\",\"constraintSubject\":\"「{{path}}」\",\"minLength\":\"{{subject}}至少需要 {{value}} 個字元。\",\"maxLength\":\"{{subject}}最多接受 {{value}} 個字元。\",\"pattern\":\"{{subject}}文字格式應符合 {{value}}。\",\"minimum\":\"{{subject}}不能小於 {{value}}。\",\"exclusiveMinimum\":\"{{subject}}必須大於 {{value}}。\",\"maximum\":\"{{subject}}不能大於 {{value}}。\",\"exclusiveMaximum\":\"{{subject}}必須小於 {{value}}。\",\"multipleOf\":\"{{subject}}必須是 {{value}} 的倍數。\",\"minItems\":\"{{subject}}至少需要 {{value}} 項。\",\"maxItems\":\"{{subject}}最多接受 {{value}} 項。\",\"minProperties\":\"{{subject}}至少需要 {{value}} 個屬性。\",\"maxProperties\":\"{{subject}}最多接受 {{value}} 個屬性。\",\"integer\":\"整數\",\"unknownType\":\"未知類型\",\"typeSeparator\":\"或\"},\"actions\":{\"flowAccess\":\"可用服務\",\"flowAccessHint\":\"管理此 Flow 中所有 Code 節點共用的連線\",\"chooseConnection\":\"選擇 {{provider}} Connection\",\"connectionDescription\":\"Connection 將寫入這次呼叫;是否允許使用仍由 Flow Provider Access 決定。\",\"title\":\"程式碼可呼叫的動作\",\"search\":\"搜尋應用程式或動作…\",\"description\":\"搜尋並新增這段程式碼需要呼叫的動作。\",\"empty\":\"沒有符合的 Action。\",\"remove\":\"移除\",\"default\":\"預設帳號\",\"defaultHint\":\"呼叫時未指定帳號,將使用此帳號。\",\"removeAction\":\"移除動作\",\"explicit\":\"在程式碼中明確選擇\",\"connect\":\"連接帳號\",\"refresh\":\"重新整理帳號\",\"aliases\":\"同步帳號別名\",\"add\":\"新增動作\",\"cancel\":\"取消\",\"loading\":\"搜尋中…\",\"needsAccount\":\"待連接帳號\",\"accounts\":\"{{count}} 個帳號\",\"public\":\"無需帳號\",\"allowed\":\"可用帳號\",\"unavailable\":\"無法使用\",\"details\":\"帳號詳情\",\"example\":\"呼叫範例\",\"syntax\":\"呼叫寫法\",\"nested\":\"分層寫法\",\"fullId\":\"完整 ID\",\"copy\":\"複製\",\"copied\":\"已複製\",\"copyError\":\"複製失敗,請選取範例程式碼手動複製。\",\"introDescription\":\"依需求新增動作,透過 {{context}} 呼叫外部應用程式。\",\"insertAction\":\"插入程式碼\",\"chooseAccounts\":\"管理帳號\"},\"comment\":{\"markdown\":\"Markdown\",\"preview\":\"預覽\"},\"ports\":{\"reorder\":\"調整 {{name}} 的順序\",\"reorderHint\":\"拖動調整組內順序,或聚焦後使用上、下方向鍵。\",\"moved\":\"{{name}} 已移至第 {{position}} 位。\",\"groupSettings\":\"群組設定\",\"connected\":\"已連接\",\"sort\":\"排序\",\"finishSorting\":\"完成排序\",\"inputsTitle\":\"輸入\",\"requiredInputs\":\"必填\",\"optionalInputs\":\"選填\",\"noInputs\":\"此節點不需要輸入資料\",\"noOutputs\":\"此節點不提供輸出資料\",\"outputsTitle\":\"輸出\",\"valuesTitle\":\"資料\",\"columnHandle\":\"Handle\",\"columnName\":\"名稱\",\"columnType\":\"類型\",\"columnValue\":\"值\",\"builtIn\":{\"cron\":{\"scheduledAt\":\"本次執行的排程觸發時間,採用 ISO 8601 格式。\"},\"webhook\":{\"headers\":\"此 Webhook 請求攜帶的請求標頭。\",\"query\":\"此 Webhook 請求攜帶的 URL 查詢參數。\",\"body\":\"此 Webhook 請求攜帶的請求本文。\",\"webhookUrl\":\"接收此次請求的 Webhook URL,不含查詢參數。\"}},\"startParametersTitle\":\"啟動參數\"}}"),
104975
105594
  language: { "label": "語言" },
@@ -106053,7 +106672,10 @@ var resources = {
106053
106672
  "discardTitle": "放棄變更?",
106054
106673
  "discardDescription": "工作流程設定的變更尚未儲存。",
106055
106674
  "continueEditing": "繼續編輯",
106056
- "discardChanges": "放棄變更"
106675
+ "discardChanges": "放棄變更",
106676
+ "icon": "圖示",
106677
+ "resetIcon": "重設圖示",
106678
+ "description": "說明"
106057
106679
  },
106058
106680
  flowState: {
106059
106681
  "title": "持久化資料",
@@ -106067,7 +106689,7 @@ var resources = {
106067
106689
  "clear": "清空",
106068
106690
  "orphaned": "目前檢視之外",
106069
106691
  "nearLimit": "此工作流的去重記錄已使用至少 80%。請清理不再需要的記錄。",
106070
- "history": "用量",
106692
+ "usage": "用量",
106071
106693
  "scope": "範圍",
106072
106694
  "refresh": "重新整理",
106073
106695
  "cancel": "取消",
@@ -106095,7 +106717,7 @@ var resources = {
106095
106717
  "pendingClear": "{{count}} 筆待提交,相關執行結束或取消後可清理。",
106096
106718
  "clearBlocked": "這些記錄尚待提交。請等待相關執行結束或取消後再重新整理。",
106097
106719
  "clearSource": "清空{{name}}",
106098
- "sourceHistory": "{{name}}的歷史記錄",
106720
+ "sourceUsage": "{{name}}用量",
106099
106721
  "confirmTitle": "清空「{{name}}」?",
106100
106722
  "confirmValues": "將清空{{scope}}環境儲存的 {{count}} 筆資料,後續執行將無法讀取這些值。",
106101
106723
  "confirmHistory": "將清空{{scope}}環境的 {{count}} 筆去重記錄,這些項目之後可能再次被處理。",
@@ -106106,6 +106728,14 @@ var resources = {
106106
106728
  "loadFailed": "載入失敗",
106107
106729
  "valuesHelp": "{{name}}:工作流主動儲存的內容,後續執行可以繼續讀取。",
106108
106730
  "historyHelp": "{{name}}:項目的識別標記,用來避免重複處理。"
106731
+ },
106732
+ workflowTransfer: {
106733
+ "includeDependencies": "包含參照的工作流程",
106734
+ "workflowCount": "{{count}} 個工作流程",
106735
+ "unavailable": "{{count}} 個參照的工作流程無法使用。",
106736
+ "export": "匯出",
106737
+ "hostUnsupported": "目前的宿主尚未支援匯入工作流程套件。",
106738
+ "unnamed": "未命名工作流程"
106109
106739
  }
106110
106740
  },
106111
106741
  "ja": {
@@ -106331,14 +106961,24 @@ var resources = {
106331
106961
  "exportFlow": "ワークフローをエクスポート",
106332
106962
  "exportPng": "PNG 画像をエクスポート",
106333
106963
  "exportPngFrame": "フレームを表示",
106964
+ "exportPngCompact": "コンパクトな配置",
106334
106965
  "exportPngLight": "ライト",
106335
106966
  "exportPngDark": "ダーク",
106336
- "exportPngPending": "PNG をエクスポート中…",
106337
- "exportPngPendingDescription": "ワークフローと画像を準備しています。画像が大きい場合は時間がかかることがあります。",
106338
106967
  "exportPngComplete": "PNG 画像をエクスポートしました。",
106339
106968
  "exportPngPartial": "PNG 画像をエクスポートしました。一部の画像はプレースホルダーに置き換えられました。",
106340
106969
  "exportPngFailed": "PNG 画像をエクスポートできませんでした。もう一度お試しください。",
106341
- "importInvalid": "無効または未対応のワークフローファイルです。"
106970
+ "importInvalid": "無効または未対応のワークフローファイルです。",
106971
+ "exportPngAspectRatio": "キャンバス比率",
106972
+ "exportPngAuto": "自動",
106973
+ "exportPngLayout": "レイアウト",
106974
+ "exportPngOriginal": "元の配置",
106975
+ "exportPngTheme": "テーマ",
106976
+ "exportPngPreview": "プレビュー",
106977
+ "exportPngPreviewPending": "プレビューを生成中…",
106978
+ "exportPngPreviewFailed": "プレビューを生成できませんでした。",
106979
+ "exportPngPreviewPartial": "一部の画像を読み込めず、代替画像に置き換えました。",
106980
+ "exportPngDownload": "PNG をダウンロード",
106981
+ "exportPngPreviewRetry": "再試行"
106342
106982
  },
106343
106983
  inspector: /* @__PURE__ */ JSON.parse("{\"outline\":\"ノード一覧\",\"backToOutline\":\"ノード一覧に戻る\",\"emptyOutline\":\"ノードはまだありません\",\"triggers\":\"トリガー\",\"nodes\":\"ノード\",\"multipleSelected\":\"{{count}} 個のノードを選択中\",\"account\":{\"contactAdmin\":\"この操作を実行する権限がありません。管理者にお問い合わせください。\",\"accessTitle\":\"アクセス権限\",\"manageFlowAccess\":\"Code で使用できる接続\",\"configureAccess\":\"アカウントを選択\",\"manageAccount\":\"アカウントを管理\",\"required\":\"アカウント接続が必要\",\"addAccount\":\"アカウントを追加\",\"manage\":\"管理\",\"authorizationPending\":\"Connection ページで認証を完了してください。ここに戻ると、このアカウントが更新されます。\",\"chooseAccount\":\"アカウントを選択\",\"deferred\":\"今は設定しない\",\"clearDeferred\":\"選択をクリア\",\"noAccounts\":\"利用可能なアカウントがありません\",\"connectBeforeRun\":\"このノードを実行または公開するには、先に {{service}} を接続してください。\",\"connectService\":\"{{service}} を接続\",\"connection\":\"Connection\",\"loading\":\"Connection を読み込み中…\",\"oomolBuiltIn\":\"OOMOL 組み込みアカウント\",\"missing\":\"このノードで選択されたアカウントは現在利用できません。別のアカウントを選択するか、アカウントを管理してください。\",\"refreshFailed\":\"Connection を更新できませんでした。\",\"retry\":\"再試行\",\"status\":{\"disconnected\":\"この Connection は切断されています。再接続するか、別のアカウントを選択してください。\",\"error\":\"この Connection にエラーがあります。修復するか、別のアカウントを選択してください。\",\"reauth_required\":\"この Connection は再認証が必要です。再接続するか、別のアカウントを選択してください。\"},\"statusUnavailable\":\"{{action}} の Connection 状態を取得できません。\",\"teamDefault\":\"チームのデフォルト\",\"title\":\"アカウント\",\"unavailable\":\"利用不可\"},\"close\":\"インスペクターを閉じる\",\"configurationRequired\":\"設定が必要\",\"diagnostics\":\"診断\",\"errors\":{\"jsonObject\":\"{{label}} は JSON オブジェクトである必要があります。\",\"portDefinitions\":\"有効なポート定義を入力してください。\"},\"node\":{\"nameDuplicate\":\"このグラフには同じ名前のノードが既に存在します。\",\"nameEmpty\":\"ノード名を空にすることはできません。\",\"timeout\":\"タイムアウト(ミリ秒)\",\"maxExecutions\":\"ノード実行上限\",\"maxExecutionsError\":\"ノード実行上限は正の整数で指定してください。\",\"timeoutError\":\"タイムアウトはミリ秒単位の正の整数で指定してください。\",\"title\":\"ノード設定\",\"description\":\"目的\",\"describe\":\"このステップの目的を記述します。\",\"icon\":\"アイコン\",\"name\":\"タイトル\",\"retry\":\"失敗時の再試行\",\"retryCount\":\"最大 {{count}} 回再試行\",\"retryInterval\":\"再試行の間隔\",\"retryError\":\"間隔は 1~60 の整数秒で指定してください。\",\"retryHint\":\"再試行回数は、初回の実行に失敗した後に追加する試行の回数です。再試行はノード全体を再実行するため、外部操作が重複する場合があります。タイムアウトには全試行と待機時間を含みます。\",\"retryNone\":\"再試行しない\",\"retrySeconds\":\"秒\",\"retryHelp\":\"再試行について\",\"retryOnce\":\"最大 1 回再試行\",\"onError\":\"失敗時の処理\",\"onErrorStop\":\"ワークフローを停止\",\"onErrorOutput\":\"error ポートに出力\",\"onErrorHelp\":\"失敗時の処理について\",\"onErrorHint\":\"再試行後も失敗した場合、システム error にエラーを出力して既存の接続で続行します。成功時は null です。キャンセル、タイムアウト、リソース制限、結果不明の場合は停止します。\",\"systemOutputs\":\"システム出力\",\"systemError\":\"エラー情報(システム)\",\"errorFields\":{\"error\":\"ノードが失敗した場合のエラー情報。成功時は null です。\",\"code\":\"エラーの種類を識別するコード。\",\"message\":\"機密情報をマスクしたエラーの説明。\",\"nodeId\":\"エラーが発生したノードの ID。\",\"nodeName\":\"エラー発生時のノード名。\",\"runId\":\"今回のワークフロー実行の ID。\",\"executionId\":\"今回のノード実行の ID。再試行でも同じ ID を使用します。\"}},\"selectNode\":\"ドラフトのノードを 1 つ選択すると、内容を確認して編集できます。\",\"locateNode\":\"キャンバス上でこのノードを表示\",\"task\":{\"sharedPermissions\":\"Flow の共有権限グループを使用\",\"sharedPermissionsHint\":\"Flow の共有権限グループで許可されたすべての Action を使用します。個別の追加は不要です。\",\"httpHosts\":\"HTTP ホスト\",\"httpHostsHint\":\"1 行に 1 ホスト。*.example.com はサブドメインに一致します。\",\"httpHostsInvalid\":\"「{{host}}」は有効なホストではありません。api.example.com のようなホスト名を入力してください。\",\"httpHostsLimit\":\"宣言できるホストは最大 {{count}} 個です。\",\"addAction\":\"Action を追加\",\"removeAction\":\"Action を削除\",\"actionAccount\":\"アカウント\",\"chooseAccount\":\"アカウントを選択\",\"permissionSaveFailed\":\"Code の権限を保存できませんでした。再試行してください。\",\"chatText\":\"チャットテキスト\",\"connectorAction\":\"Connector アクション\",\"definition\":\"タスク定義\",\"discardCode\":\"変更を破棄\",\"editorLoading\":\"エディターを読み込み中…\",\"editorUnavailable\":\"コードエディターを読み込めませんでした。\",\"inputPorts\":\"入力ポート\",\"javascriptModule\":\"コード\",\"missing\":\"参照しているタスクが存在しません。\",\"outputPorts\":\"出力ポート\",\"responseMode\":\"応答モード\",\"source\":\"ソースコード\",\"structuredJson\":\"構造化 JSON\",\"retrySave\":\"保存を再試行\",\"additionalInputs\":\"追加入力\",\"httpHostsUpdated\":\"ホスト設定が別の場所で更新されました。最新の設定を読み込みました。確認してから保存してください。\"},\"wait\":{\"approval\":\"承認または拒否\",\"changeNotification\":\"変更\",\"continue\":\"続行\",\"mode\":\"処理方法\",\"inputsLoading\":\"通知パラメーターを読み込んでいます…\",\"pendingDescription\":\"確認待ち出力は待機開始時に一度だけ発火し、確認リンクと関連データを提供します。接続先でメッセージの送信や他のステップを実行できます。\",\"prompt\":\"プロンプト\",\"promptError\":\"プロンプトは1〜1,000文字で入力してください。\",\"autoContinue\":\"自動続行\",\"autoOff\":\"オフ\",\"autoAfter\":\"一定時間後\",\"autoAt\":\"指定日時\",\"autoSeconds\":\"待機時間(秒)\",\"autoDate\":\"日時\",\"autoInvalid\":\"正の待機時間または有効な日時を入力してください。\",\"autoDescription\":\"予定時刻前に手動で続行できます。\"},\"title\":\"インスペクター\",\"sources\":{\"loading\":\"入力元を読み込み中…\",\"loadFailed\":\"入力元を読み込めません。メニューを開き直してください。\",\"checkFailed\":\"このソースを確認できませんでした。\",\"select\":\"入力元を選択\",\"title\":\"入力元\",\"sourceMissing\":\"元の入力元は存在しません。選択し直してください。\",\"outputMissing\":\"「{{source}}」に「{{output}}」が見つかりません。選択し直してください。\",\"wholeObject\":\"オブジェクト全体\",\"fieldMissing\":\"「{{output}}」にフィールド {{field}} が宣言されていません。選択し直してください。\",\"notReady\":\"ここを実行するとき、「{{source}} {{handle}}」にまだ値がない可能性があります。\",\"sourceConflict\":\"同時に値を持つ可能性があります:{{sources}}。ここでは 1 つだけ使用できます。\",\"incompatibleRight\":\"右辺の値の型はこの比較に対応していません。\",\"incompatible\":\"非互換\",\"unverified\":\"未検証\",\"schemaIncompatible\":\"データ形式が一致しません。\",\"schemaPathIncompatible\":\"「{{path}}」のデータ形式が一致しません。\",\"schemaCompareFailed\":\"データ形式を確認できません。JSON Schema を確認してください。\",\"binaryIncompatible\":\"バイナリデータは使用できません。\",\"artifactIncompatible\":\"ファイルデータは使用できません。\",\"nullableIncompatible\":\"値が必要ですが、選択したフィールドは空になる可能性があります。\",\"typeIncompatible\":\"{{target}}が必要ですが、選択したフィールドは{{source}}です。\",\"propertyTypeIncompatible\":\"「{{path}}」は{{target}}である必要がありますが、実際は{{source}}です。\",\"requiredIncompatible\":\"必須プロパティ「{{property}}」がない可能性があります。\",\"enumIncompatible\":\"使用できない値が含まれる可能性があります:{{values}}。\",\"constIncompatible\":\"{{target}}のみ使用できますが、選択したフィールドは常に {{source}} です。\",\"constraintSubject\":\"「{{path}}」は\",\"minLength\":\"{{subject}}少なくとも {{value}} 文字必要です。\",\"maxLength\":\"{{subject}}最大 {{value}} 文字です。\",\"pattern\":\"{{subject}}{{value}} に一致する必要があります。\",\"minimum\":\"{{subject}}{{value}} 未満にできません。\",\"exclusiveMinimum\":\"{{subject}}{{value}} より大きい必要があります。\",\"maximum\":\"{{subject}}{{value}} を超えられません。\",\"exclusiveMaximum\":\"{{subject}}{{value}} より小さい必要があります。\",\"multipleOf\":\"{{subject}}{{value}} の倍数である必要があります。\",\"minItems\":\"{{subject}}少なくとも {{value}} 項必要です。\",\"maxItems\":\"{{subject}}最大 {{value}} 項です。\",\"minProperties\":\"{{subject}}少なくとも {{value}} 個のプロパティが必要です。\",\"maxProperties\":\"{{subject}}最大 {{value}} 個のプロパティです。\",\"integer\":\"整数\",\"unknownType\":\"不明な型\",\"typeSeparator\":\"または\"},\"actions\":{\"flowAccess\":\"利用可能なサービス\",\"flowAccessHint\":\"この Flow のすべての Code ノードで共有する接続を管理\",\"chooseConnection\":\"{{provider}} Connection を選択\",\"connectionDescription\":\"Connection はこの呼び出しに挿入されます。使用可否は引き続き Flow Provider Access によって制御されます。\",\"title\":\"このコードから呼び出せるアクション\",\"search\":\"Action を検索\",\"description\":\"このコードで使用する Action とアカウントを選択します。\",\"empty\":\"一致する Action はありません。\",\"remove\":\"削除\",\"default\":\"既定のアカウント\",\"defaultHint\":\"呼び出し時にアカウントを指定しない場合に使用します。\",\"removeAction\":\"アクションを削除\",\"explicit\":\"コード内で明示的に選択\",\"connect\":\"アカウントを接続\",\"refresh\":\"アカウントを更新\",\"aliases\":\"保存済みの別名を更新\",\"add\":\"アクションを追加\",\"cancel\":\"キャンセル\",\"loading\":\"検索中…\",\"needsAccount\":\"アカウントを接続\",\"accounts\":\"{{count}} アカウント\",\"public\":\"アカウント不要\",\"allowed\":\"使用するアカウント\",\"unavailable\":\"利用不可\",\"details\":\"接続の詳細\",\"example\":\"呼び出し例\",\"syntax\":\"呼び出し形式\",\"nested\":\"プロバイダー形式\",\"fullId\":\"完全な ID\",\"copy\":\"コピー\",\"copied\":\"コピー済み\",\"copyError\":\"コピーできませんでした。コードを選択して手動でコピーしてください。\",\"introDescription\":\"必要に応じてアクションを追加し、{{context}} から外部アプリを呼び出せます。\",\"insertAction\":\"コードを挿入\",\"chooseAccounts\":\"アカウントを管理\"},\"comment\":{\"markdown\":\"Markdown\",\"preview\":\"プレビュー\"},\"ports\":{\"reorder\":\"{{name}} の順序を変更\",\"reorderHint\":\"ドラッグでグループ内の順序を変更。フォーカス時は上下キーでも移動できます。\",\"moved\":\"{{name}} を {{position}} 番目に移動しました。\",\"groupSettings\":\"グループ設定\",\"connected\":\"接続済み\",\"sort\":\"並べ替え\",\"finishSorting\":\"並べ替えを完了\",\"inputsTitle\":\"入力\",\"requiredInputs\":\"必須\",\"optionalInputs\":\"任意\",\"noInputs\":\"このノードには入力データが必要ありません。\",\"noOutputs\":\"このノードは出力データを提供しません。\",\"outputsTitle\":\"出力\",\"valuesTitle\":\"値\",\"columnHandle\":\"Handle\",\"columnName\":\"名前\",\"columnType\":\"型\",\"columnValue\":\"値\",\"builtIn\":{\"cron\":{\"scheduledAt\":\"この実行をトリガーした予定時刻(ISO 8601 形式)です。\"},\"webhook\":{\"headers\":\"この Webhook リクエストで受信したリクエストヘッダーです。\",\"query\":\"この Webhook リクエストで受信した URL クエリパラメーターです。\",\"body\":\"この Webhook リクエストで受信したリクエストボディです。\",\"webhookUrl\":\"このリクエストを受信した Webhook URL(クエリパラメーターを除く)です。\"}},\"startParametersTitle\":\"開始パラメーター\"}}"),
106344
106984
  language: { "label": "言語" },
@@ -107422,7 +108062,10 @@ var resources = {
107422
108062
  "discardTitle": "変更を破棄しますか?",
107423
108063
  "discardDescription": "ワークフロー設定の変更は保存されていません。",
107424
108064
  "continueEditing": "編集を続ける",
107425
- "discardChanges": "変更を破棄"
108065
+ "discardChanges": "変更を破棄",
108066
+ "icon": "アイコン",
108067
+ "resetIcon": "アイコンをリセット",
108068
+ "description": "説明"
107426
108069
  },
107427
108070
  flowState: {
107428
108071
  "title": "永続データ",
@@ -107436,7 +108079,7 @@ var resources = {
107436
108079
  "clear": "消去",
107437
108080
  "orphaned": "現在のビューの外",
107438
108081
  "nearLimit": "フローの重複履歴が 80% 以上使用されています。不要な履歴を削除してください。",
107439
- "history": "使用量",
108082
+ "usage": "使用量",
107440
108083
  "scope": "スコープ",
107441
108084
  "refresh": "更新",
107442
108085
  "cancel": "キャンセル",
@@ -107464,7 +108107,7 @@ var resources = {
107464
108107
  "pendingClear": "{{count}} 件が確定待ちです。関連する実行の完了またはキャンセル後に消去できます。",
107465
108108
  "clearBlocked": "確定待ちの記録があります。関連する実行の完了またはキャンセル後に更新してください。",
107466
108109
  "clearSource": "{{name}}を消去",
107467
- "sourceHistory": "{{name}}の履歴",
108110
+ "sourceUsage": "{{name}}の使用量",
107468
108111
  "confirmTitle": "「{{name}}」を消去しますか?",
107469
108112
  "confirmValues": "{{scope}}環境の保存データ {{count}} 件を消去します。以降の実行ではこれらの値を読み取れなくなります。",
107470
108113
  "confirmHistory": "{{scope}}環境の重複排除記録 {{count}} 件を消去します。これらの項目が再処理される場合があります。",
@@ -107475,6 +108118,14 @@ var resources = {
107475
108118
  "loadFailed": "読み込みに失敗しました",
107476
108119
  "valuesHelp": "{{name}}:フローが明示的に保存し、後続の実行で読み取れる内容です。",
107477
108120
  "historyHelp": "{{name}}:同じ項目を繰り返し処理しないための識別情報です。"
108121
+ },
108122
+ workflowTransfer: {
108123
+ "includeDependencies": "参照先のワークフローを含める",
108124
+ "workflowCount": "ワークフロー({{count}} 件)",
108125
+ "unavailable": "参照先のワークフロー {{count}} 件を利用できません。",
108126
+ "export": "エクスポート",
108127
+ "hostUnsupported": "このホストはワークフローバンドルのインポートにまだ対応していません。",
108128
+ "unnamed": "無題のワークフロー"
107478
108129
  }
107479
108130
  },
107480
108131
  "ko": {
@@ -107700,14 +108351,24 @@ var resources = {
107700
108351
  "exportFlow": "워크플로 내보내기",
107701
108352
  "exportPng": "PNG 이미지 내보내기",
107702
108353
  "exportPngFrame": "프레임 표시",
108354
+ "exportPngCompact": "간결한 배치",
107703
108355
  "exportPngLight": "라이트",
107704
108356
  "exportPngDark": "다크",
107705
- "exportPngPending": "PNG 내보내는 중…",
107706
- "exportPngPendingDescription": "워크플로와 이미지를 준비하고 있습니다. 이미지가 크면 시간이 더 걸릴 수 있습니다.",
107707
108357
  "exportPngComplete": "PNG 이미지를 내보냈습니다.",
107708
108358
  "exportPngPartial": "PNG 이미지를 내보냈습니다. 일부 이미지는 자리 표시자로 대체되었습니다.",
107709
108359
  "exportPngFailed": "PNG 이미지를 내보내지 못했습니다. 다시 시도해 주세요.",
107710
- "importInvalid": "잘못되었거나 지원하지 않는 워크플로 파일입니다."
108360
+ "importInvalid": "잘못되었거나 지원하지 않는 워크플로 파일입니다.",
108361
+ "exportPngAspectRatio": "캔버스 비율",
108362
+ "exportPngAuto": "자동",
108363
+ "exportPngLayout": "레이아웃",
108364
+ "exportPngOriginal": "원래 배치",
108365
+ "exportPngTheme": "테마",
108366
+ "exportPngPreview": "미리보기",
108367
+ "exportPngPreviewPending": "미리보기 생성 중…",
108368
+ "exportPngPreviewFailed": "미리보기를 생성하지 못했습니다.",
108369
+ "exportPngPreviewPartial": "일부 이미지를 불러오지 못해 대체 이미지로 표시했습니다.",
108370
+ "exportPngDownload": "PNG 다운로드",
108371
+ "exportPngPreviewRetry": "다시 시도"
107711
108372
  },
107712
108373
  inspector: /* @__PURE__ */ JSON.parse("{\"outline\":\"노드 목록\",\"backToOutline\":\"노드 목록으로 돌아가기\",\"emptyOutline\":\"아직 노드가 없습니다\",\"triggers\":\"트리거\",\"nodes\":\"노드\",\"multipleSelected\":\"노드 {{count}}개 선택됨\",\"account\":{\"contactAdmin\":\"이 작업을 실행할 권한이 없습니다. 관리자에게 문의하세요.\",\"accessTitle\":\"접근 권한\",\"manageFlowAccess\":\"Code에서 사용할 수 있는 연결\",\"configureAccess\":\"계정 선택\",\"manageAccount\":\"계정 관리\",\"required\":\"계정 연결 필요\",\"addAccount\":\"계정 추가\",\"manage\":\"관리\",\"authorizationPending\":\"Connection 페이지에서 인증을 마친 뒤 여기로 돌아와 이 계정을 새로 고치세요.\",\"chooseAccount\":\"계정 선택\",\"deferred\":\"지금은 설정하지 않음\",\"clearDeferred\":\"선택 지우기\",\"noAccounts\":\"사용 가능한 계정이 없습니다\",\"connectBeforeRun\":\"이 블록을 실행하거나 게시하려면 먼저 {{service}}에 연결하세요.\",\"connectService\":\"{{service}} 연결\",\"connection\":\"Connection\",\"loading\":\"Connection 불러오는 중…\",\"oomolBuiltIn\":\"OOMOL 기본 제공 계정\",\"missing\":\"이 노드에서 선택한 계정을 현재 사용할 수 없습니다. 다른 계정을 선택하거나 계정을 관리하세요.\",\"refreshFailed\":\"Connection을 새로 고치지 못했습니다.\",\"retry\":\"다시 시도\",\"status\":{\"disconnected\":\"이 Connection은 연결이 끊어졌습니다. 다시 연결하거나 다른 계정을 선택하세요.\",\"error\":\"이 Connection에 오류가 있습니다. 문제를 해결하거나 다른 계정을 선택하세요.\",\"reauth_required\":\"이 Connection은 다시 인증해야 합니다. 다시 연결하거나 다른 계정을 선택하세요.\"},\"statusUnavailable\":\"{{action}}의 Connection 상태를 확인할 수 없습니다.\",\"teamDefault\":\"팀 기본값\",\"title\":\"계정\",\"unavailable\":\"사용할 수 없음\"},\"close\":\"인스펙터 닫기\",\"configurationRequired\":\"설정 필요\",\"diagnostics\":\"진단\",\"errors\":{\"jsonObject\":\"{{label}} 값은 JSON 객체여야 합니다.\",\"portDefinitions\":\"올바른 포트 정의를 입력하세요.\"},\"node\":{\"nameDuplicate\":\"이 그래프에 같은 이름의 노드가 이미 있습니다.\",\"nameEmpty\":\"노드 이름은 비워 둘 수 없습니다.\",\"timeout\":\"제한 시간(ms)\",\"maxExecutions\":\"노드 실행 한도\",\"maxExecutionsError\":\"노드 실행 한도는 양의 정수여야 합니다.\",\"timeoutError\":\"제한 시간은 밀리초 단위의 양의 정수여야 합니다.\",\"title\":\"노드 설정\",\"description\":\"목적\",\"describe\":\"이 단계의 목적을 설명하세요.\",\"icon\":\"아이콘\",\"name\":\"제목\",\"retry\":\"실패 시 재시도\",\"retryCount\":\"최대 {{count}}회 재시도\",\"retryInterval\":\"재시도 간격\",\"retryError\":\"간격은 1~60초의 정수로 입력하세요.\",\"retryHint\":\"재시도 횟수는 최초 실행 실패 후 추가로 시도하는 횟수입니다. 노드 전체를 다시 실행하므로 외부 작업이 중복될 수 있습니다. 제한 시간에는 모든 시도와 대기 시간이 포함됩니다.\",\"retryNone\":\"재시도 안 함\",\"retrySeconds\":\"초\",\"retryHelp\":\"재시도 안내\",\"retryOnce\":\"최대 1회 재시도\",\"onError\":\"실패 처리\",\"onErrorStop\":\"워크플로 중지\",\"onErrorOutput\":\"error 포트로 출력\",\"onErrorHelp\":\"실패 처리 안내\",\"onErrorHint\":\"재시도 후에도 실패하면 시스템 error에 오류를 기록하고 기존 연결을 따라 계속합니다. 성공 시 null입니다. 취소, 시간 초과, 리소스 제한 및 결과 불명 상태는 실행을 중지합니다.\",\"systemOutputs\":\"시스템 출력\",\"systemError\":\"오류 정보(시스템)\",\"errorFields\":{\"error\":\"노드 실패 시 오류 정보입니다. 성공 시 null입니다.\",\"code\":\"오류 유형을 식별하는 코드입니다.\",\"message\":\"민감한 내용이 가려진 오류 설명입니다.\",\"nodeId\":\"오류가 발생한 노드의 ID입니다.\",\"nodeName\":\"오류 발생 시점의 노드 이름입니다.\",\"runId\":\"이번 워크플로 실행의 ID입니다.\",\"executionId\":\"이번 노드 실행의 ID입니다. 재시도에서도 같은 ID를 사용합니다.\"}},\"selectNode\":\"확인하고 편집할 초안 노드를 하나 선택하세요.\",\"locateNode\":\"캔버스에서 이 노드 위치 보기\",\"task\":{\"sharedPermissions\":\"Flow 공유 권한 그룹 사용\",\"sharedPermissionsHint\":\"Flow 공유 권한 그룹에서 승인한 모든 Action을 사용합니다. 개별적으로 추가할 필요가 없습니다.\",\"httpHosts\":\"HTTP 호스트\",\"httpHostsHint\":\"한 줄에 호스트 하나. *.example.com은 하위 도메인과 일치합니다.\",\"httpHostsInvalid\":\"\\\"{{host}}\\\"은(는) 올바른 호스트가 아닙니다. api.example.com 같은 호스트 이름을 입력하세요.\",\"httpHostsLimit\":\"호스트는 최대 {{count}}개까지 선언할 수 있습니다.\",\"addAction\":\"Action 추가\",\"removeAction\":\"Action 제거\",\"actionAccount\":\"계정\",\"chooseAccount\":\"계정 선택\",\"permissionSaveFailed\":\"Code 권한을 저장하지 못했습니다. 다시 시도하세요.\",\"chatText\":\"대화 텍스트\",\"connectorAction\":\"Connector 액션\",\"definition\":\"태스크 정의\",\"discardCode\":\"변경 사항 버리기\",\"editorLoading\":\"편집기 불러오는 중…\",\"editorUnavailable\":\"코드 편집기를 불러오지 못했습니다.\",\"inputPorts\":\"입력 포트\",\"javascriptModule\":\"코드\",\"missing\":\"참조된 태스크가 존재하지 않습니다.\",\"outputPorts\":\"출력 포트\",\"responseMode\":\"응답 모드\",\"source\":\"소스\",\"structuredJson\":\"구조화된 JSON\",\"retrySave\":\"저장 재시도\",\"additionalInputs\":\"추가 입력\",\"httpHostsUpdated\":\"다른 곳에서 호스트 설정이 변경되었습니다. 최신 설정을 불러왔습니다. 확인 후 저장하세요.\"},\"wait\":{\"approval\":\"승인 또는 거부\",\"changeNotification\":\"변경\",\"continue\":\"계속\",\"mode\":\"처리 방식\",\"inputsLoading\":\"알림 매개변수를 불러오는 중…\",\"pendingDescription\":\"확인 대기 출력은 대기가 시작될 때 한 번 실행되어 확인 링크와 관련 데이터를 제공합니다. 연결하여 메시지를 보내거나 다른 단계를 실행할 수 있습니다.\",\"prompt\":\"프롬프트\",\"promptError\":\"프롬프트는 1~1,000자여야 합니다.\",\"autoContinue\":\"자동 계속\",\"autoOff\":\"끄기\",\"autoAfter\":\"일정 시간 후\",\"autoAt\":\"지정 시간에\",\"autoSeconds\":\"대기 시간(초)\",\"autoDate\":\"날짜 및 시간\",\"autoInvalid\":\"양수 대기 시간 또는 유효한 날짜와 시간을 입력하세요.\",\"autoDescription\":\"예정 시간 전에 수동으로 계속할 수 있습니다.\"},\"title\":\"인스펙터\",\"sources\":{\"loading\":\"입력 소스 불러오는 중…\",\"loadFailed\":\"입력 소스를 불러올 수 없습니다. 메뉴를 다시 열어 주세요.\",\"checkFailed\":\"이 소스를 확인할 수 없습니다.\",\"select\":\"입력 소스 선택\",\"title\":\"입력 소스\",\"sourceMissing\":\"기존 입력 소스가 더 이상 존재하지 않습니다. 다시 선택하세요.\",\"outputMissing\":\"“{{source}}”에서 “{{output}}”을(를) 찾을 수 없습니다. 다시 선택하세요.\",\"wholeObject\":\"전체 객체\",\"fieldMissing\":\"“{{output}}”에 {{field}} 필드가 선언되어 있지 않습니다. 다시 선택하세요.\",\"notReady\":\"여기까지 실행될 때 “{{source}} {{handle}}”에 아직 값이 없을 수 있습니다.\",\"sourceConflict\":\"다음 필드에 값이 동시에 있을 수 있습니다: {{sources}}. 여기서는 하나만 사용할 수 있습니다.\",\"incompatibleRight\":\"오른쪽 값의 형식이 이 비교와 호환되지 않습니다.\",\"incompatible\":\"호환되지 않음\",\"unverified\":\"확인되지 않음\",\"schemaIncompatible\":\"데이터 형식이 일치하지 않습니다.\",\"schemaPathIncompatible\":\"“{{path}}”의 데이터 형식이 일치하지 않습니다.\",\"schemaCompareFailed\":\"데이터 형식을 확인할 수 없습니다. JSON Schema를 확인하세요.\",\"binaryIncompatible\":\"바이너리 데이터는 사용할 수 없습니다.\",\"artifactIncompatible\":\"파일 데이터는 사용할 수 없습니다.\",\"nullableIncompatible\":\"값이 필요하지만 선택한 필드는 비어 있을 수 있습니다.\",\"typeIncompatible\":\"{{target}}이(가) 필요하지만 선택한 필드는 {{source}}입니다.\",\"propertyTypeIncompatible\":\"“{{path}}”은(는) {{target}}이어야 하지만 실제로는 {{source}}입니다.\",\"requiredIncompatible\":\"필수 속성 “{{property}}”이(가) 없을 수 있습니다.\",\"enumIncompatible\":\"허용되지 않는 값이 포함될 수 있습니다: {{values}}.\",\"constIncompatible\":\"{{target}}만 허용되지만 선택한 필드는 항상 {{source}}입니다.\",\"constraintSubject\":\"“{{path}}”은(는) \",\"minLength\":\"{{subject}}최소 {{value}}자여야 합니다.\",\"maxLength\":\"{{subject}}최대 {{value}}자여야 합니다.\",\"pattern\":\"{{subject}}{{value}} 형식과 일치해야 합니다.\",\"minimum\":\"{{subject}}{{value}}보다 작을 수 없습니다.\",\"exclusiveMinimum\":\"{{subject}}{{value}}보다 커야 합니다.\",\"maximum\":\"{{subject}}{{value}}보다 클 수 없습니다.\",\"exclusiveMaximum\":\"{{subject}}{{value}}보다 작아야 합니다.\",\"multipleOf\":\"{{subject}}{{value}}의 배수여야 합니다.\",\"minItems\":\"{{subject}}최소 {{value}}개 항목이 필요합니다.\",\"maxItems\":\"{{subject}}최대 {{value}}개 항목을 허용합니다.\",\"minProperties\":\"{{subject}}최소 {{value}}개 속성이 필요합니다.\",\"maxProperties\":\"{{subject}}최대 {{value}}개 속성을 허용합니다.\",\"integer\":\"정수\",\"unknownType\":\"알 수 없는 유형\",\"typeSeparator\":\" 또는 \"},\"actions\":{\"flowAccess\":\"사용 가능한 서비스\",\"flowAccessHint\":\"이 Flow의 모든 Code 노드가 공유하는 연결 관리\",\"chooseConnection\":\"{{provider}} Connection 선택\",\"connectionDescription\":\"Connection이 이 호출에 삽입됩니다. 사용 가능 여부는 계속 Flow Provider Access에서 제어합니다.\",\"title\":\"이 코드에서 호출할 수 있는 작업\",\"search\":\"Action 검색\",\"description\":\"이 코드에서 사용할 Action과 계정을 선택하세요.\",\"empty\":\"일치하는 Action이 없습니다.\",\"remove\":\"제거\",\"default\":\"기본 계정\",\"defaultHint\":\"호출 시 계정을 지정하지 않으면 이 계정을 사용합니다.\",\"removeAction\":\"액션 제거\",\"explicit\":\"코드에서 명시적으로 선택\",\"connect\":\"계정 연결\",\"refresh\":\"계정 새로 고침\",\"aliases\":\"저장된 별칭 업데이트\",\"add\":\"액션 추가\",\"cancel\":\"취소\",\"loading\":\"검색 중…\",\"needsAccount\":\"계정 연결 필요\",\"accounts\":\"계정 {{count}}개\",\"public\":\"계정 불필요\",\"allowed\":\"사용할 계정\",\"unavailable\":\"사용 불가\",\"details\":\"연결 세부 정보\",\"example\":\"호출 예제\",\"syntax\":\"호출 형식\",\"nested\":\"계층형\",\"fullId\":\"전체 ID\",\"copy\":\"복사\",\"copied\":\"복사됨\",\"copyError\":\"복사하지 못했습니다. 코드를 선택하여 직접 복사하세요.\",\"introDescription\":\"필요한 작업을 추가하고 {{context}}로 외부 앱을 호출하세요.\",\"insertAction\":\"코드 삽입\",\"chooseAccounts\":\"계정 관리\"},\"comment\":{\"markdown\":\"Markdown\",\"preview\":\"미리보기\"},\"ports\":{\"reorder\":\"{{name}} 순서 변경\",\"reorderHint\":\"그룹 안에서 드래그하거나 포커스 후 위 / 아래 키로 순서를 변경하세요.\",\"moved\":\"{{name}}이(가) {{position}}번째로 이동했습니다.\",\"groupSettings\":\"그룹 설정\",\"connected\":\"연결됨\",\"sort\":\"순서 변경\",\"finishSorting\":\"순서 변경 완료\",\"inputsTitle\":\"입력\",\"requiredInputs\":\"필수\",\"optionalInputs\":\"선택\",\"noInputs\":\"이 노드에는 입력 데이터가 필요하지 않습니다.\",\"noOutputs\":\"이 노드는 출력 데이터를 제공하지 않습니다.\",\"outputsTitle\":\"출력\",\"valuesTitle\":\"값\",\"columnHandle\":\"Handle\",\"columnName\":\"이름\",\"columnType\":\"유형\",\"columnValue\":\"값\",\"builtIn\":{\"cron\":{\"scheduledAt\":\"이 실행을 트리거한 예약 시간이며 ISO 8601 형식입니다.\"},\"webhook\":{\"headers\":\"이 Webhook 요청과 함께 수신된 요청 헤더입니다.\",\"query\":\"이 Webhook 요청과 함께 수신된 URL 쿼리 매개변수입니다.\",\"body\":\"이 Webhook 요청과 함께 수신된 요청 본문입니다.\",\"webhookUrl\":\"이 요청을 수신한 Webhook URL이며 쿼리 매개변수는 포함하지 않습니다.\"}},\"startParametersTitle\":\"시작 매개변수\"}}"),
107713
108374
  language: { "label": "언어" },
@@ -108791,7 +109452,10 @@ var resources = {
108791
109452
  "discardTitle": "변경 사항을 버릴까요?",
108792
109453
  "discardDescription": "워크플로 설정의 변경 사항이 저장되지 않았습니다.",
108793
109454
  "continueEditing": "계속 편집",
108794
- "discardChanges": "변경 사항 버리기"
109455
+ "discardChanges": "변경 사항 버리기",
109456
+ "icon": "아이콘",
109457
+ "resetIcon": "아이콘 초기화",
109458
+ "description": "설명"
108795
109459
  },
108796
109460
  flowState: {
108797
109461
  "title": "영구 데이터",
@@ -108805,7 +109469,7 @@ var resources = {
108805
109469
  "clear": "지우기",
108806
109470
  "orphaned": "현재 보기 외부",
108807
109471
  "nearLimit": "Flow 중복 기록이 80% 이상 찼습니다. 필요 없는 기록을 지우세요.",
108808
- "history": "사용량",
109472
+ "usage": "사용량",
108809
109473
  "scope": "범위",
108810
109474
  "refresh": "새로 고침",
108811
109475
  "cancel": "취소",
@@ -108833,7 +109497,7 @@ var resources = {
108833
109497
  "pendingClear": "{{count}}개 확정 대기 중. 관련 실행이 완료되거나 취소된 후 지울 수 있습니다.",
108834
109498
  "clearBlocked": "확정 대기 중인 기록이 있습니다. 관련 실행을 완료하거나 취소한 후 새로 고침하세요.",
108835
109499
  "clearSource": "{{name}} 지우기",
108836
- "sourceHistory": "{{name}} 기록",
109500
+ "sourceUsage": "{{name}} 사용량",
108837
109501
  "confirmTitle": "{{name}}을(를) 지울까요?",
108838
109502
  "confirmValues": "{{scope}} 환경에 저장된 데이터 {{count}}개를 지웁니다. 이후 실행에서 이 값을 읽을 수 없습니다.",
108839
109503
  "confirmHistory": "{{scope}} 환경의 중복 제거 기록 {{count}}개를 지웁니다. 해당 항목이 다시 처리될 수 있습니다.",
@@ -108844,6 +109508,14 @@ var resources = {
108844
109508
  "loadFailed": "불러오기 실패",
108845
109509
  "valuesHelp": "{{name}}: 워크플로가 직접 저장하여 이후 실행에서 읽을 수 있는 내용입니다.",
108846
109510
  "historyHelp": "{{name}}: 같은 항목을 반복 처리하지 않기 위한 식별 정보입니다."
109511
+ },
109512
+ workflowTransfer: {
109513
+ "includeDependencies": "참조된 워크플로 포함",
109514
+ "workflowCount": "워크플로 {{count}}개",
109515
+ "unavailable": "참조된 워크플로 {{count}}개를 사용할 수 없습니다.",
109516
+ "export": "내보내기",
109517
+ "hostUnsupported": "이 호스트는 아직 워크플로 번들 가져오기를 지원하지 않습니다.",
109518
+ "unnamed": "이름 없는 워크플로"
108847
109519
  }
108848
109520
  },
108849
109521
  "ru": {
@@ -109069,14 +109741,24 @@ var resources = {
109069
109741
  "exportFlow": "Экспортировать процесс",
109070
109742
  "exportPng": "Экспорт изображения PNG",
109071
109743
  "exportPngFrame": "Показать рамку",
109744
+ "exportPngCompact": "Компактная компоновка",
109072
109745
  "exportPngLight": "Светлая",
109073
109746
  "exportPngDark": "Тёмная",
109074
- "exportPngPending": "Экспорт PNG…",
109075
- "exportPngPendingDescription": "Подготовка рабочего процесса и изображений. Большие изображения могут потребовать больше времени.",
109076
109747
  "exportPngComplete": "Изображение PNG экспортировано.",
109077
109748
  "exportPngPartial": "Изображение PNG экспортировано. Некоторые изображения заменены заглушками.",
109078
109749
  "exportPngFailed": "Не удалось экспортировать изображение PNG. Повторите попытку.",
109079
- "importInvalid": "Некорректный или неподдерживаемый файл процесса."
109750
+ "importInvalid": "Некорректный или неподдерживаемый файл процесса.",
109751
+ "exportPngAspectRatio": "Пропорции холста",
109752
+ "exportPngAuto": "Авто",
109753
+ "exportPngLayout": "Компоновка",
109754
+ "exportPngOriginal": "Исходная",
109755
+ "exportPngTheme": "Тема",
109756
+ "exportPngPreview": "Предпросмотр",
109757
+ "exportPngPreviewPending": "Создание предпросмотра…",
109758
+ "exportPngPreviewFailed": "Не удалось создать предпросмотр.",
109759
+ "exportPngPreviewPartial": "Некоторые изображения заменены заглушками.",
109760
+ "exportPngDownload": "Скачать PNG",
109761
+ "exportPngPreviewRetry": "Повторить"
109080
109762
  },
109081
109763
  inspector: /* @__PURE__ */ JSON.parse("{\"outline\":\"Список узлов\",\"backToOutline\":\"Вернуться к списку узлов\",\"emptyOutline\":\"Узлов пока нет\",\"triggers\":\"Триггеры\",\"nodes\":\"Узлы\",\"multipleSelected\":\"Выбрано узлов: {{count}}\",\"account\":{\"contactAdmin\":\"У вас нет прав для выполнения этой операции. Обратитесь к администратору.\",\"accessTitle\":\"Права доступа\",\"manageFlowAccess\":\"Подключения, доступные Code\",\"configureAccess\":\"Выбрать аккаунт\",\"manageAccount\":\"Управление аккаунтами\",\"required\":\"Требуется подключение аккаунта\",\"addAccount\":\"Добавить аккаунт\",\"manage\":\"Управление\",\"authorizationPending\":\"Завершите авторизацию на странице Connection, затем вернитесь сюда, чтобы обновить этот аккаунт.\",\"chooseAccount\":\"Выберите аккаунт\",\"deferred\":\"Пока не настраивать\",\"clearDeferred\":\"Сбросить выбор\",\"noAccounts\":\"Нет доступных аккаунтов\",\"connectBeforeRun\":\"Подключите {{service}}, чтобы этот узел можно было запускать и публиковать.\",\"connectService\":\"Подключить {{service}}\",\"connection\":\"Connection\",\"loading\":\"Загрузка Connection…\",\"oomolBuiltIn\":\"Встроенный аккаунт OOMOL\",\"missing\":\"Выбранный для этого узла аккаунт недоступен. Выберите другой аккаунт или откройте управление подключениями.\",\"refreshFailed\":\"Не удалось обновить Connection.\",\"retry\":\"Повторить\",\"status\":{\"disconnected\":\"Этот Connection отключён. Подключите его заново или выберите другой аккаунт.\",\"error\":\"В этом Connection ошибка. Исправьте её или выберите другой аккаунт.\",\"reauth_required\":\"Этому Connection нужна повторная авторизация. Подключите его заново или выберите другой аккаунт.\"},\"statusUnavailable\":\"Статус Connection недоступен для {{action}}.\",\"teamDefault\":\"По умолчанию для команды\",\"title\":\"Аккаунт\",\"unavailable\":\"недоступно\"},\"close\":\"Закрыть инспектор\",\"configurationRequired\":\"Требуется настройка\",\"diagnostics\":\"Диагностика\",\"errors\":{\"jsonObject\":\"{{label}} должен быть JSON-объектом.\",\"portDefinitions\":\"Введите корректные определения портов.\"},\"node\":{\"nameDuplicate\":\"Узел с таким именем уже существует в этом графе.\",\"nameEmpty\":\"Имя узла не может быть пустым.\",\"timeout\":\"Время ожидания (мс)\",\"maxExecutions\":\"Лимит выполнений узла\",\"maxExecutionsError\":\"Лимит выполнений узла должен быть положительным целым числом.\",\"timeoutError\":\"Время ожидания должно быть положительным целым числом в миллисекундах.\",\"title\":\"Настройки узла\",\"description\":\"Назначение\",\"describe\":\"Опишите назначение этого шага.\",\"icon\":\"Значок\",\"name\":\"Заголовок\",\"retry\":\"Повторять при ошибке\",\"retryCount\":\"До {{count}} повторов\",\"retryInterval\":\"Интервал повторов\",\"retryError\":\"Укажите целый интервал от 1 до 60 секунд.\",\"retryHint\":\"Число повторов означает дополнительные попытки после неудачной первой попытки. Повтор запускает весь узел заново и может повторить внешние операции. Тайм-аут включает все попытки и интервалы.\",\"retryNone\":\"Без повторов\",\"retrySeconds\":\"сек.\",\"retryHelp\":\"О повторах\",\"retryOnce\":\"Не более 1 повтора\",\"onError\":\"При ошибке\",\"onErrorStop\":\"Остановить процесс\",\"onErrorOutput\":\"Вывод в порт error\",\"onErrorHelp\":\"Обработка ошибок\",\"onErrorHint\":\"После неудачных повторов записать ошибку в системный выход error и продолжить по существующим связям. При успехе error равен null. Отмена, тайм-ауты, ограничения ресурсов и неопределённые результаты останавливают выполнение.\",\"systemOutputs\":\"Системные выходы\",\"systemError\":\"Ошибка (системная)\",\"errorFields\":{\"error\":\"Информация об ошибке узла; при успешном выполнении — null.\",\"code\":\"Код, определяющий тип ошибки.\",\"message\":\"Описание ошибки со скрытыми конфиденциальными данными.\",\"nodeId\":\"Идентификатор узла, в котором произошла ошибка.\",\"nodeName\":\"Имя узла на момент ошибки.\",\"runId\":\"Идентификатор этого запуска рабочего процесса.\",\"executionId\":\"Идентификатор этого выполнения узла, общий для всех повторных попыток.\"}},\"selectNode\":\"Выберите один узел черновика, чтобы просмотреть и изменить его.\",\"locateNode\":\"Найти этот узел на холсте\",\"task\":{\"sharedPermissions\":\"Использовать общую группу разрешений Flow\",\"sharedPermissionsHint\":\"Используйте все Actions, разрешённые общей группой Flow. Добавлять их в узел по отдельности не нужно.\",\"httpHosts\":\"HTTP-хосты\",\"httpHostsHint\":\"Один хост на строку. *.example.com включает поддомены.\",\"httpHostsInvalid\":\"«{{host}}» — недопустимый хост. Укажите имя хоста, например api.example.com.\",\"httpHostsLimit\":\"Можно объявить не более {{count}} хостов.\",\"addAction\":\"Добавить Action\",\"removeAction\":\"Удалить Action\",\"actionAccount\":\"Аккаунт\",\"chooseAccount\":\"Выбрать аккаунт\",\"permissionSaveFailed\":\"Не удалось сохранить разрешения Code. Повторите попытку.\",\"chatText\":\"Текст чата\",\"connectorAction\":\"Действие Connector\",\"definition\":\"Определение задачи\",\"discardCode\":\"Отменить изменения\",\"editorLoading\":\"Загрузка редактора…\",\"editorUnavailable\":\"Не удалось загрузить редактор кода.\",\"inputPorts\":\"Входные порты\",\"javascriptModule\":\"Код\",\"missing\":\"Указанная задача не существует.\",\"outputPorts\":\"Выходные порты\",\"responseMode\":\"Режим ответа\",\"source\":\"Исходный код\",\"structuredJson\":\"Структурированный JSON\",\"retrySave\":\"Повторить сохранение\",\"additionalInputs\":\"Дополнительные входы\",\"httpHostsUpdated\":\"Настройки хостов изменены в другом месте. Загружена новая конфигурация; проверьте её перед сохранением.\"},\"wait\":{\"approval\":\"Одобрить или отклонить\",\"changeNotification\":\"Изменить\",\"continue\":\"Продолжить\",\"mode\":\"Обработка\",\"inputsLoading\":\"Загрузка параметров уведомления…\",\"pendingDescription\":\"Выход ожидания срабатывает один раз при начале ожидания и передаёт ссылки подтверждения и связанные данные. Подключите его для отправки сообщения или выполнения других шагов.\",\"prompt\":\"Запрос\",\"promptError\":\"Запрос должен содержать от 1 до 1 000 символов.\",\"autoContinue\":\"Автоматическое продолжение\",\"autoOff\":\"Выключено\",\"autoAfter\":\"Через интервал\",\"autoAt\":\"В указанное время\",\"autoSeconds\":\"Длительность (секунды)\",\"autoDate\":\"Дата и время\",\"autoInvalid\":\"Введите положительную длительность или корректные дату и время.\",\"autoDescription\":\"До указанного времени можно продолжить вручную.\"},\"title\":\"Инспектор\",\"sources\":{\"loading\":\"Загрузка источников входных данных…\",\"loadFailed\":\"Не удалось загрузить источники входных данных. Откройте меню ещё раз.\",\"checkFailed\":\"Не удалось проверить этот источник.\",\"select\":\"Выбрать источник входных данных\",\"title\":\"Источник входных данных\",\"sourceMissing\":\"Исходный источник входных данных больше не существует. Выберите другой.\",\"outputMissing\":\"«{{output}}» не найден в «{{source}}». Выберите снова.\",\"wholeObject\":\"Весь объект\",\"fieldMissing\":\"Поле {{field}} больше не объявлено в «{{output}}». Выберите снова.\",\"notReady\":\"К моменту выполнения этого шага у «{{source}} {{handle}}» может ещё не быть значения.\",\"sourceConflict\":\"Эти поля могут иметь значения одновременно: {{sources}}. Здесь можно использовать только одно.\",\"incompatibleRight\":\"Тип правого значения несовместим с этим сравнением.\",\"incompatible\":\"Несовместимо\",\"unverified\":\"Не проверено\",\"schemaIncompatible\":\"Формат данных не совпадает.\",\"schemaPathIncompatible\":\"Формат данных «{{path}}» не совпадает.\",\"schemaCompareFailed\":\"Не удалось проверить формат данных. Проверьте схему JSON.\",\"binaryIncompatible\":\"Двоичные данные здесь использовать нельзя.\",\"artifactIncompatible\":\"Файловые данные здесь использовать нельзя.\",\"nullableIncompatible\":\"Требуется значение, но выбранное поле может быть пустым.\",\"typeIncompatible\":\"Ожидается {{target}}, но выбранное поле имеет тип {{source}}.\",\"propertyTypeIncompatible\":\"«{{path}}» должно иметь тип {{target}}, но имеет тип {{source}}.\",\"requiredIncompatible\":\"Обязательное свойство «{{property}}» может отсутствовать.\",\"enumIncompatible\":\"Некоторые возможные значения не принимаются: {{values}}.\",\"constIncompatible\":\"Принимается только {{target}}, но выбранное поле всегда равно {{source}}.\",\"constraintSubject\":\"«{{path}}» \",\"minLength\":\"{{subject}}должно содержать не менее {{value}} символов.\",\"maxLength\":\"{{subject}}должно содержать не более {{value}} символов.\",\"pattern\":\"{{subject}}должно соответствовать {{value}}.\",\"minimum\":\"{{subject}}не может быть меньше {{value}}.\",\"exclusiveMinimum\":\"{{subject}}должно быть больше {{value}}.\",\"maximum\":\"{{subject}}не может быть больше {{value}}.\",\"exclusiveMaximum\":\"{{subject}}должно быть меньше {{value}}.\",\"multipleOf\":\"{{subject}}должно быть кратно {{value}}.\",\"minItems\":\"{{subject}}должно содержать не менее {{value}} элементов.\",\"maxItems\":\"{{subject}}должно содержать не более {{value}} элементов.\",\"minProperties\":\"{{subject}}должно содержать не менее {{value}} свойств.\",\"maxProperties\":\"{{subject}}должно содержать не более {{value}} свойств.\",\"integer\":\"Целое число\",\"unknownType\":\"неизвестный тип\",\"typeSeparator\":\" или \"},\"actions\":{\"flowAccess\":\"Доступные сервисы\",\"flowAccessHint\":\"Управлять подключениями, общими для всех узлов Code в этом Flow\",\"chooseConnection\":\"Выбрать подключение {{provider}}\",\"connectionDescription\":\"Подключение будет вставлено в этот вызов. Возможность его использования по-прежнему контролирует Flow Provider Access.\",\"title\":\"Действия, доступные коду\",\"search\":\"Поиск действий\",\"description\":\"Выберите действия и аккаунты, доступные этому коду.\",\"empty\":\"Подходящих действий нет.\",\"remove\":\"Удалить\",\"default\":\"Аккаунт по умолчанию\",\"defaultHint\":\"Используется, если при вызове не указан аккаунт.\",\"removeAction\":\"Удалить действие\",\"explicit\":\"Выбирать явно в коде\",\"connect\":\"Подключить аккаунт\",\"refresh\":\"Обновить аккаунты\",\"aliases\":\"Обновить сохранённые псевдонимы\",\"add\":\"Добавить действие\",\"cancel\":\"Отмена\",\"loading\":\"Поиск…\",\"needsAccount\":\"Подключите аккаунт\",\"accounts\":\"Аккаунты: {{count}}\",\"public\":\"Без аккаунта\",\"allowed\":\"Разрешённые аккаунты\",\"unavailable\":\"Недоступен\",\"details\":\"Данные подключений\",\"example\":\"Пример вызова\",\"syntax\":\"Синтаксис вызова\",\"nested\":\"Через провайдера\",\"fullId\":\"Полный ID\",\"copy\":\"Копировать\",\"copied\":\"Скопировано\",\"copyError\":\"Не удалось скопировать. Выделите код и скопируйте вручную.\",\"introDescription\":\"При необходимости добавьте действия для вызова внешних приложений через {{context}}.\",\"insertAction\":\"Вставить код\",\"chooseAccounts\":\"Управление аккаунтами\"},\"comment\":{\"markdown\":\"Markdown\",\"preview\":\"Предпросмотр\"},\"ports\":{\"reorder\":\"Изменить порядок {{name}}\",\"reorderHint\":\"Перетащите внутри группы или используйте стрелки вверх / вниз при фокусе.\",\"moved\":\"{{name}} перемещён на позицию {{position}}.\",\"groupSettings\":\"Настройки группы\",\"connected\":\"Подключено\",\"sort\":\"Изменить порядок\",\"finishSorting\":\"Готово\",\"inputsTitle\":\"Входы\",\"requiredInputs\":\"Обязательные\",\"optionalInputs\":\"Необязательные\",\"noInputs\":\"Этому узлу не требуются входные данные.\",\"noOutputs\":\"Этот узел не предоставляет выходных данных.\",\"outputsTitle\":\"Выходы\",\"valuesTitle\":\"Значения\",\"columnHandle\":\"Handle\",\"columnName\":\"Имя\",\"columnType\":\"Тип\",\"columnValue\":\"Значение\",\"builtIn\":{\"cron\":{\"scheduledAt\":\"Запланированное время этого запуска в формате ISO 8601.\"},\"webhook\":{\"headers\":\"Заголовки, полученные с этим Webhook-запросом.\",\"query\":\"Параметры URL-запроса, полученные с этим Webhook-запросом.\",\"body\":\"Тело, полученное с этим Webhook-запросом.\",\"webhookUrl\":\"URL Webhook, получивший этот запрос, без параметров запроса.\"}},\"startParametersTitle\":\"Параметры запуска\"}}"),
109082
109764
  language: { "label": "Язык" },
@@ -110160,7 +110842,10 @@ var resources = {
110160
110842
  "discardTitle": "Отменить изменения?",
110161
110843
  "discardDescription": "Изменения настроек процесса не сохранены.",
110162
110844
  "continueEditing": "Продолжить редактирование",
110163
- "discardChanges": "Отменить изменения"
110845
+ "discardChanges": "Отменить изменения",
110846
+ "icon": "Значок",
110847
+ "resetIcon": "Сбросить значок",
110848
+ "description": "Описание"
110164
110849
  },
110165
110850
  flowState: {
110166
110851
  "title": "Постоянные данные",
@@ -110174,7 +110859,7 @@ var resources = {
110174
110859
  "clear": "Очистить",
110175
110860
  "orphaned": "Вне текущего представления",
110176
110861
  "nearLimit": "История Flow заполнена минимум на 80 %. Удалите ненужные записи.",
110177
- "history": "Использование",
110862
+ "usage": "Использование",
110178
110863
  "scope": "Область",
110179
110864
  "refresh": "Обновить",
110180
110865
  "cancel": "Отмена",
@@ -110202,7 +110887,7 @@ var resources = {
110202
110887
  "pendingClear": "Ожидают фиксации: {{count}}. Завершите или отмените связанные запуски перед очисткой.",
110203
110888
  "clearBlocked": "Есть записи, ожидающие фиксации. Завершите или отмените связанные запуски и обновите данные.",
110204
110889
  "clearSource": "Очистить {{name}}",
110205
- "sourceHistory": "История: {{name}}",
110890
+ "sourceUsage": "Использование: {{name}}",
110206
110891
  "confirmTitle": "Очистить «{{name}}»?",
110207
110892
  "confirmValues": "Будут удалены сохранённые записи ({{count}}) в среде «{{scope}}». Последующие запуски не смогут прочитать эти значения.",
110208
110893
  "confirmHistory": "Будут удалены записи дедупликации ({{count}}) в среде «{{scope}}». Эти элементы могут быть обработаны повторно.",
@@ -110213,6 +110898,14 @@ var resources = {
110213
110898
  "loadFailed": "Не удалось загрузить",
110214
110899
  "valuesHelp": "{{name}}: данные, явно сохранённые процессом для чтения в следующих запусках.",
110215
110900
  "historyHelp": "{{name}}: идентификаторы элементов, предотвращающие повторную обработку."
110901
+ },
110902
+ workflowTransfer: {
110903
+ "includeDependencies": "Включить связанные процессы",
110904
+ "workflowCount": "Процессы ({{count}})",
110905
+ "unavailable": "Связанные процессы недоступны: {{count}}.",
110906
+ "export": "Экспортировать",
110907
+ "hostUnsupported": "Этот хост пока не поддерживает импорт пакетов процессов.",
110908
+ "unnamed": "Процесс без названия"
110216
110909
  }
110217
110910
  },
110218
110911
  "fr": {
@@ -110438,14 +111131,24 @@ var resources = {
110438
111131
  "exportFlow": "Exporter le workflow",
110439
111132
  "exportPng": "Exporter une image PNG",
110440
111133
  "exportPngFrame": "Afficher le cadre",
111134
+ "exportPngCompact": "Disposition compacte",
110441
111135
  "exportPngLight": "Clair",
110442
111136
  "exportPngDark": "Sombre",
110443
- "exportPngPending": "Exportation du PNG…",
110444
- "exportPngPendingDescription": "Préparation du workflow et des images. Les images volumineuses peuvent prendre un peu plus de temps.",
110445
111137
  "exportPngComplete": "Image PNG exportée.",
110446
111138
  "exportPngPartial": "Image PNG exportée. Certaines images ont été remplacées par des espaces réservés.",
110447
111139
  "exportPngFailed": "Impossible d’exporter l’image PNG. Veuillez réessayer.",
110448
- "importInvalid": "Fichier de workflow invalide ou non pris en charge."
111140
+ "importInvalid": "Fichier de workflow invalide ou non pris en charge.",
111141
+ "exportPngAspectRatio": "Format du canevas",
111142
+ "exportPngAuto": "Auto",
111143
+ "exportPngLayout": "Disposition",
111144
+ "exportPngOriginal": "Originale",
111145
+ "exportPngTheme": "Thème",
111146
+ "exportPngPreview": "Aperçu",
111147
+ "exportPngPreviewPending": "Génération de l’aperçu…",
111148
+ "exportPngPreviewFailed": "Impossible de générer l’aperçu.",
111149
+ "exportPngPreviewPartial": "Certaines images ont été remplacées par des espaces réservés.",
111150
+ "exportPngDownload": "Télécharger le PNG",
111151
+ "exportPngPreviewRetry": "Réessayer"
110449
111152
  },
110450
111153
  inspector: /* @__PURE__ */ JSON.parse("{\"outline\":\"Liste des nœuds\",\"backToOutline\":\"Retour à la liste des nœuds\",\"emptyOutline\":\"Aucun nœud pour le moment\",\"triggers\":\"Déclencheurs\",\"nodes\":\"Nœuds\",\"multipleSelected\":\"{{count}} nœuds sélectionnés\",\"account\":{\"contactAdmin\":\"Vous n’avez pas l’autorisation d’effectuer cette opération. Contactez un administrateur.\",\"accessTitle\":\"Autorisations d’accès\",\"manageFlowAccess\":\"Connexions disponibles pour Code\",\"configureAccess\":\"Choisir un compte\",\"manageAccount\":\"Gérer les comptes\",\"required\":\"Compte à connecter\",\"addAccount\":\"Ajouter un compte\",\"manage\":\"Gérer\",\"authorizationPending\":\"Terminez l'autorisation sur la page Connection, puis revenez ici pour actualiser ce compte.\",\"chooseAccount\":\"Choisir un compte\",\"deferred\":\"Ne pas configurer maintenant\",\"clearDeferred\":\"Effacer la sélection\",\"noAccounts\":\"Aucun compte disponible\",\"connectBeforeRun\":\"Connectez {{service}} pour que ce bloc puisse être exécuté ou publié.\",\"connectService\":\"Connecter {{service}}\",\"connection\":\"Connection\",\"loading\":\"Chargement des Connections…\",\"oomolBuiltIn\":\"Compte intégré OOMOL\",\"missing\":\"Le compte sélectionné pour ce nœud est indisponible. Choisissez un autre compte ou gérez les connexions.\",\"refreshFailed\":\"Impossible d'actualiser les Connections.\",\"retry\":\"Réessayer\",\"status\":{\"disconnected\":\"Cette Connection est déconnectée. Reconnectez-la ou choisissez un autre compte.\",\"error\":\"Cette Connection présente une erreur. Réparez-la ou choisissez un autre compte.\",\"reauth_required\":\"Cette Connection doit être autorisée à nouveau. Reconnectez-la ou choisissez un autre compte.\"},\"statusUnavailable\":\"Le statut de la Connection est indisponible pour {{action}}.\",\"teamDefault\":\"Par défaut de l'équipe\",\"title\":\"Compte\",\"unavailable\":\"indisponible\"},\"close\":\"Fermer l'inspecteur\",\"configurationRequired\":\"Configuration requise\",\"diagnostics\":\"Diagnostics\",\"errors\":{\"jsonObject\":\"{{label}} doit être un objet JSON.\",\"portDefinitions\":\"Saisissez des définitions de ports valides.\"},\"node\":{\"nameDuplicate\":\"Un nœud portant ce nom existe déjà dans ce graphe.\",\"nameEmpty\":\"Le nom du nœud ne peut pas être vide.\",\"timeout\":\"Délai d'expiration (ms)\",\"maxExecutions\":\"Limite d’exécutions du nœud\",\"maxExecutionsError\":\"La limite d’exécutions du nœud doit être un entier positif.\",\"timeoutError\":\"Le délai d'expiration doit être un entier positif exprimé en millisecondes.\",\"title\":\"Paramètres du nœud\",\"description\":\"Objectif\",\"describe\":\"Décrivez le rôle de cette étape.\",\"icon\":\"Icône\",\"name\":\"Titre\",\"retry\":\"Réessayer en cas d’erreur\",\"retryCount\":\"Nouvelles tentatives : {{count}} max.\",\"retryInterval\":\"Intervalle\",\"retryError\":\"Indiquez un intervalle entier de 1 à 60 secondes.\",\"retryHint\":\"Le nombre de nouvelles tentatives s’ajoute à la première exécution en cas d’échec. Chaque tentative réexécute le nœud entier et peut répéter des opérations externes. Le délai maximal inclut toutes les tentatives et les intervalles.\",\"retryNone\":\"Aucune nouvelle tentative\",\"retrySeconds\":\"secondes\",\"retryHelp\":\"À propos des nouvelles tentatives\",\"retryOnce\":\"Une nouvelle tentative max.\",\"onError\":\"En cas d’échec\",\"onErrorStop\":\"Arrêter le workflow\",\"onErrorOutput\":\"Sortir vers le port error\",\"onErrorHelp\":\"Gestion des échecs\",\"onErrorHint\":\"Après les nouvelles tentatives, placer l’erreur dans la sortie système error et continuer par les connexions existantes. En cas de succès, error vaut null. Annulation, délais, limites de ressources et résultats indéterminés arrêtent toujours l’exécution.\",\"systemOutputs\":\"Sorties système\",\"systemError\":\"Erreur (système)\",\"errorFields\":{\"error\":\"Informations sur l’erreur en cas d’échec du nœud ; null en cas de réussite.\",\"code\":\"Code identifiant le type d’erreur.\",\"message\":\"Description de l’erreur, avec les informations sensibles masquées.\",\"nodeId\":\"Identifiant du nœud ayant échoué.\",\"nodeName\":\"Nom du nœud au moment de l’échec.\",\"runId\":\"Identifiant de cette exécution du workflow.\",\"executionId\":\"Identifiant de cette exécution du nœud, commun à toutes ses tentatives.\"}},\"selectNode\":\"Sélectionnez un nœud du Brouillon pour l'inspecter et le modifier.\",\"locateNode\":\"Localiser ce nœud sur le canevas\",\"task\":{\"sharedPermissions\":\"Utiliser le groupe d’autorisations partagé du Flow\",\"sharedPermissionsHint\":\"Utilisez toutes les Actions autorisées par le groupe du Flow, sans les ajouter à ce nœud.\",\"httpHosts\":\"Hôtes HTTP\",\"httpHostsHint\":\"Un hôte par ligne. *.example.com inclut les sous-domaines.\",\"httpHostsInvalid\":\"« {{host}} » n’est pas un hôte valide. Utilisez un nom d’hôte comme api.example.com.\",\"httpHostsLimit\":\"Déclarez au plus {{count}} hôtes.\",\"addAction\":\"Ajouter une action\",\"removeAction\":\"Supprimer l’action\",\"actionAccount\":\"Compte\",\"chooseAccount\":\"Choisir un compte\",\"permissionSaveFailed\":\"Impossible d’enregistrer les autorisations Code. Réessayez.\",\"chatText\":\"Texte de conversation\",\"connectorAction\":\"Action Connector\",\"definition\":\"Définition de la tâche\",\"discardCode\":\"Abandonner les modifications\",\"editorLoading\":\"Chargement de l'éditeur…\",\"editorUnavailable\":\"Impossible de charger l'éditeur de code.\",\"inputPorts\":\"Ports d'entrée\",\"javascriptModule\":\"Code\",\"missing\":\"La tâche référencée n'existe pas.\",\"outputPorts\":\"Ports de sortie\",\"responseMode\":\"Mode de réponse\",\"source\":\"Source\",\"structuredJson\":\"JSON structuré\",\"retrySave\":\"Réessayer\",\"additionalInputs\":\"Entrées supplémentaires\",\"httpHostsUpdated\":\"Les hôtes ont été modifiés ailleurs. La dernière configuration est chargée ; vérifiez-la avant d’enregistrer.\"},\"wait\":{\"approval\":\"Approuver ou refuser\",\"changeNotification\":\"Changer\",\"continue\":\"Continuer\",\"mode\":\"Traitement\",\"inputsLoading\":\"Chargement des paramètres de notification…\",\"pendingDescription\":\"La sortie en attente se déclenche une fois au début de l’attente et fournit les liens de confirmation et les données associées. Reliez-la pour envoyer un message ou exécuter d’autres étapes.\",\"prompt\":\"Invite\",\"promptError\":\"L’invite doit contenir entre 1 et 1 000 caractères.\",\"autoContinue\":\"Reprise automatique\",\"autoOff\":\"Désactivée\",\"autoAfter\":\"Après une durée\",\"autoAt\":\"À une date précise\",\"autoSeconds\":\"Durée (secondes)\",\"autoDate\":\"Date et heure\",\"autoInvalid\":\"Saisissez une durée positive ou une date et une heure valides.\",\"autoDescription\":\"Vous pouvez reprendre manuellement avant l’heure prévue.\"},\"title\":\"Inspecteur\",\"sources\":{\"loading\":\"Chargement des sources d’entrée…\",\"loadFailed\":\"Impossible de charger les sources d’entrée. Rouvrez le menu pour réessayer.\",\"checkFailed\":\"Impossible de vérifier cette source.\",\"select\":\"Sélectionner la source d’entrée\",\"title\":\"Source d’entrée\",\"sourceMissing\":\"La source d’entrée d’origine n’existe plus. Choisissez-en une autre.\",\"outputMissing\":\"« {{output}} » est introuvable dans « {{source}} ». Choisissez à nouveau.\",\"wholeObject\":\"Objet entier\",\"fieldMissing\":\"Le champ {{field}} n’est plus déclaré dans « {{output}} ». Choisissez à nouveau.\",\"notReady\":\"« {{source}} {{handle}} » peut ne pas avoir de valeur lors de cette étape.\",\"sourceConflict\":\"Ces champs peuvent avoir une valeur en même temps : {{sources}}. Un seul peut être utilisé ici.\",\"incompatibleRight\":\"Le type de la valeur de droite est incompatible avec cette comparaison.\",\"incompatible\":\"Incompatible\",\"unverified\":\"Non vérifié\",\"schemaIncompatible\":\"Le format des données ne correspond pas.\",\"schemaPathIncompatible\":\"Le format de « {{path}} » ne correspond pas.\",\"schemaCompareFailed\":\"Impossible de vérifier le format. Vérifiez le schéma JSON.\",\"binaryIncompatible\":\"Les données binaires ne peuvent pas être utilisées ici.\",\"artifactIncompatible\":\"Les données de fichier ne peuvent pas être utilisées ici.\",\"nullableIncompatible\":\"Une valeur est requise, mais le champ sélectionné peut être vide.\",\"typeIncompatible\":\"Le type attendu est {{target}}, mais le champ sélectionné est de type {{source}}.\",\"propertyTypeIncompatible\":\"« {{path}} » doit être de type {{target}}, mais est de type {{source}}.\",\"requiredIncompatible\":\"La propriété requise « {{property}} » peut être absente.\",\"enumIncompatible\":\"Certaines valeurs possibles ne sont pas acceptées : {{values}}.\",\"constIncompatible\":\"Seul {{target}} est accepté, mais le champ sélectionné vaut toujours {{source}}.\",\"constraintSubject\":\"« {{path}} » \",\"minLength\":\"{{subject}}doit contenir au moins {{value}} caractères.\",\"maxLength\":\"{{subject}}doit contenir au plus {{value}} caractères.\",\"pattern\":\"{{subject}}doit correspondre à {{value}}.\",\"minimum\":\"{{subject}}ne peut pas être inférieur à {{value}}.\",\"exclusiveMinimum\":\"{{subject}}doit être supérieur à {{value}}.\",\"maximum\":\"{{subject}}ne peut pas être supérieur à {{value}}.\",\"exclusiveMaximum\":\"{{subject}}doit être inférieur à {{value}}.\",\"multipleOf\":\"{{subject}}doit être un multiple de {{value}}.\",\"minItems\":\"{{subject}}doit contenir au moins {{value}} éléments.\",\"maxItems\":\"{{subject}}doit contenir au plus {{value}} éléments.\",\"minProperties\":\"{{subject}}doit contenir au moins {{value}} propriétés.\",\"maxProperties\":\"{{subject}}doit contenir au plus {{value}} propriétés.\",\"integer\":\"Entier\",\"unknownType\":\"type inconnu\",\"typeSeparator\":\" ou \"},\"actions\":{\"flowAccess\":\"Services disponibles\",\"flowAccessHint\":\"Gérer les connexions partagées par tous les nœuds Code de ce Flow\",\"chooseConnection\":\"Choisir une connexion {{provider}}\",\"connectionDescription\":\"La connexion est insérée dans cet appel. L’accès Provider du Flow détermine toujours si elle peut être utilisée.\",\"title\":\"Actions accessibles au code\",\"search\":\"Rechercher des actions\",\"description\":\"Choisissez les actions et les comptes autorisés pour ce code.\",\"empty\":\"Aucune action correspondante.\",\"remove\":\"Retirer\",\"default\":\"Compte par défaut\",\"defaultHint\":\"Compte utilisé si aucun compte n’est précisé lors de l’appel.\",\"removeAction\":\"Retirer l’action\",\"explicit\":\"Choisir explicitement dans le code\",\"connect\":\"Connecter un compte\",\"refresh\":\"Actualiser les comptes\",\"aliases\":\"Mettre à jour les alias enregistrés\",\"add\":\"Ajouter une action\",\"cancel\":\"Annuler\",\"loading\":\"Recherche…\",\"needsAccount\":\"Connecter un compte\",\"accounts\":\"{{count}} comptes\",\"public\":\"Sans compte\",\"allowed\":\"Comptes autorisés\",\"unavailable\":\"Indisponible\",\"details\":\"Détails des connexions\",\"example\":\"Exemple d’appel\",\"syntax\":\"Syntaxe d’appel\",\"nested\":\"Par fournisseur\",\"fullId\":\"ID complet\",\"copy\":\"Copier\",\"copied\":\"Copié\",\"copyError\":\"Échec de la copie. Sélectionnez le code pour le copier manuellement.\",\"introDescription\":\"Ajoutez des actions au besoin pour appeler des applications externes via {{context}}.\",\"insertAction\":\"Insérer le code\",\"chooseAccounts\":\"Gérer les comptes\"},\"comment\":{\"markdown\":\"Markdown\",\"preview\":\"Aperçu\"},\"ports\":{\"reorder\":\"Réordonner {{name}}\",\"reorderHint\":\"Glissez dans le groupe ou utilisez les flèches haut / bas au clavier.\",\"moved\":\"{{name}} déplacé en position {{position}}.\",\"groupSettings\":\"Paramètres du groupe\",\"connected\":\"Connecté\",\"sort\":\"Réordonner\",\"finishSorting\":\"Terminer\",\"inputsTitle\":\"Entrées\",\"requiredInputs\":\"Obligatoires\",\"optionalInputs\":\"Facultatifs\",\"noInputs\":\"Ce nœud ne nécessite pas de données d’entrée.\",\"noOutputs\":\"Ce nœud ne fournit pas de données de sortie.\",\"outputsTitle\":\"Sorties\",\"valuesTitle\":\"Valeurs\",\"columnHandle\":\"Handle\",\"columnName\":\"Nom\",\"columnType\":\"Type\",\"columnValue\":\"Valeur\",\"builtIn\":{\"cron\":{\"scheduledAt\":\"Heure planifiée ayant déclenché cette exécution, au format ISO 8601.\"},\"webhook\":{\"headers\":\"Les en-têtes reçus avec cette requête Webhook.\",\"query\":\"Les paramètres de requête URL reçus avec cette requête Webhook.\",\"body\":\"Le corps reçu avec cette requête Webhook.\",\"webhookUrl\":\"L’URL Webhook ayant reçu cette requête, sans les paramètres de requête.\"}},\"startParametersTitle\":\"Paramètres de démarrage\"}}"),
110451
111154
  language: { "label": "Langue" },
@@ -111529,7 +112232,10 @@ var resources = {
111529
112232
  "discardTitle": "Ignorer les modifications ?",
111530
112233
  "discardDescription": "Les modifications des paramètres du workflow n’ont pas été enregistrées.",
111531
112234
  "continueEditing": "Continuer à modifier",
111532
- "discardChanges": "Ignorer les modifications"
112235
+ "discardChanges": "Ignorer les modifications",
112236
+ "icon": "Icône",
112237
+ "resetIcon": "Réinitialiser l’icône",
112238
+ "description": "Description"
111533
112239
  },
111534
112240
  flowState: {
111535
112241
  "title": "Données persistantes",
@@ -111543,7 +112249,7 @@ var resources = {
111543
112249
  "clear": "Effacer",
111544
112250
  "orphaned": "Hors de la vue actuelle",
111545
112251
  "nearLimit": "L’historique du Flow est rempli à au moins 80 %. Effacez les entrées inutiles.",
111546
- "history": "Utilisation",
112252
+ "usage": "Utilisation",
111547
112253
  "scope": "Portée",
111548
112254
  "refresh": "Actualiser",
111549
112255
  "cancel": "Annuler",
@@ -111571,7 +112277,7 @@ var resources = {
111571
112277
  "pendingClear": "{{count}} en attente de validation. Terminez ou annulez les exécutions concernées avant de vider.",
111572
112278
  "clearBlocked": "Des entrées sont en attente de validation. Terminez ou annulez les exécutions concernées, puis actualisez.",
111573
112279
  "clearSource": "Vider {{name}}",
111574
- "sourceHistory": "Historique de {{name}}",
112280
+ "sourceUsage": "Utilisation de {{name}}",
111575
112281
  "confirmTitle": "Vider « {{name}} » ?",
111576
112282
  "confirmValues": "Cela supprimera {{count}} entrées enregistrées en environnement {{scope}}. Les exécutions suivantes ne pourront plus lire ces valeurs.",
111577
112283
  "confirmHistory": "Cela supprimera {{count}} entrées de déduplication en environnement {{scope}}. Ces éléments pourront être traités à nouveau.",
@@ -111582,6 +112288,14 @@ var resources = {
111582
112288
  "loadFailed": "Chargement impossible",
111583
112289
  "valuesHelp": "{{name}} : contenu enregistré explicitement par le workflow, accessible aux exécutions suivantes.",
111584
112290
  "historyHelp": "{{name}} : identifiants des éléments utilisés pour éviter les traitements en double."
112291
+ },
112292
+ workflowTransfer: {
112293
+ "includeDependencies": "Inclure les workflows référencés",
112294
+ "workflowCount": "Workflows ({{count}})",
112295
+ "unavailable": "Workflows référencés indisponibles : {{count}}.",
112296
+ "export": "Exporter",
112297
+ "hostUnsupported": "Cet hôte ne prend pas encore en charge l’import de lots de workflows.",
112298
+ "unnamed": "Workflow sans nom"
111585
112299
  }
111586
112300
  }
111587
112301
  };
@@ -113942,7 +114656,7 @@ function FlowStateButton({ client, flowId, nodes, history, notify, onClose }) {
113942
114656
  children: [/* @__PURE__ */ jsx("i", {
113943
114657
  "aria-hidden": "true",
113944
114658
  className: "i-lucide-light:database"
113945
- }), t(space == null ? "flowState.title" : "flowState.history")]
114659
+ }), t(space == null ? "flowState.title" : "flowState.usage")]
113946
114660
  }), /* @__PURE__ */ jsxs(DialogContent, {
113947
114661
  ref: dialogRoot,
113948
114662
  container,
@@ -113951,7 +114665,7 @@ function FlowStateButton({ client, flowId, nodes, history, notify, onClose }) {
113951
114665
  children: [
113952
114666
  /* @__PURE__ */ jsx(DialogTitle, {
113953
114667
  className: "break-words pr-8",
113954
- children: space == null ? t("flowState.title") : t("flowState.sourceHistory", { name: sourceName(space, nodes, t) })
114668
+ children: space == null ? t("flowState.title") : t("flowState.sourceUsage", { name: sourceName(space, nodes, t) })
113955
114669
  }),
113956
114670
  /* @__PURE__ */ jsxs(Tabs, {
113957
114671
  value: scope,