@mindexec/cli 0.2.481 → 0.2.483
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/electron/main.cjs +2 -0
- package/electron/source-smoke.mjs +4 -0
- package/electron/update-manager-smoke.mjs +14 -2
- package/electron/update-manager.cjs +31 -3
- package/package.json +6 -5
- package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
- package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
- package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
- package/scripts/desktop-update-publisher-smoke.mjs +12 -1
- package/scripts/desktop-update-worker-smoke.mjs +95 -0
- package/scripts/publish-mindexec-desktop-updates.mjs +13 -5
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-automation-edge-motion.js +41 -5
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-automation-edge-routing.js +400 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +75 -8
- package/wwwroot/_framework/{MindExecution.Core.2r5s0vx16i.dll → MindExecution.Core.zs4n1f9hjc.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Kernel.8y4azlvjyi.dll → MindExecution.Kernel.l9idvg7mp7.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Admin.dtzk93cn6n.dll → MindExecution.Plugins.Admin.l37qx5d8zi.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Business.uyqiv67u0q.dll → MindExecution.Plugins.Business.d7b282yazn.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Concept.5w50lskzj6.dll → MindExecution.Plugins.Concept.iw98n0qz5k.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Directory.a8isl4htud.dll → MindExecution.Plugins.Directory.cqgn6pa8di.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.imbm6hfih7.dll → MindExecution.Plugins.PlanMaster.j8xoa8nl57.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.YouTube.ua03os14kk.dll → MindExecution.Plugins.YouTube.zvpzk7om4z.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Shared.yxk1a55sjz.dll → MindExecution.Shared.ovot7q606x.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Web.9bmh8f8s3k.dll → MindExecution.Web.bzuaz35jv0.dll} +0 -0
- package/wwwroot/_framework/System.Collections.3iuoxbe8my.dll +0 -0
- package/wwwroot/_framework/{System.Private.CoreLib.wflwsce1yq.dll → System.Private.CoreLib.7s8wte759y.dll} +0 -0
- package/wwwroot/_framework/blazor.boot.json +27 -27
- package/wwwroot/_framework/{dotnet.native.x6q5aixc38.wasm → dotnet.native.60hhmnxyoo.wasm} +0 -0
- package/wwwroot/index.html +2 -1
- package/wwwroot/service-worker-assets.js +37 -33
- package/wwwroot/service-worker.js +1 -1
- package/wwwroot/_framework/System.Collections.zyvbaq6mpd.dll +0 -0
package/electron/main.cjs
CHANGED
|
@@ -252,6 +252,8 @@ function sendUpdateStatus(status) {
|
|
|
252
252
|
appendDesktopLog(
|
|
253
253
|
`[update] state=${status.state} current=${status.currentVersion || ''} ` +
|
|
254
254
|
`available=${status.availableVersion || ''} progress=${Math.round(status.progress || 0)} ` +
|
|
255
|
+
`bytes=${Math.round(status.downloadTransferredBytes || 0)}/${Math.round(status.downloadTotalBytes || 0)} ` +
|
|
256
|
+
`speed=${Math.round(status.downloadBytesPerSecond || 0)} ` +
|
|
255
257
|
`kind=${status.installKind || ''}${status.error ? ` error=${status.error}` : ''}`
|
|
256
258
|
);
|
|
257
259
|
if (mainWindow && !mainWindow.isDestroyed() && !mainWindow.webContents.isDestroyed()) {
|
|
@@ -34,6 +34,8 @@ assert.match(packageJson.scripts?.['desktop:publish:update:dev'] || '', /--chann
|
|
|
34
34
|
assert.equal(packageJson.dependencies?.['electron-updater'], '^6.8.9', 'The packaged updater dependency is missing.');
|
|
35
35
|
assert.equal(packageJson.build?.extraMetadata?.desktopUpdateChannel, 'dev', 'Development installers must stay on the dev feed.');
|
|
36
36
|
assert.equal(packageJson.build?.publish?.provider, 'generic', 'Desktop updates must use the generic R2-backed provider.');
|
|
37
|
+
assert.equal(packageJson.build?.publish?.useMultipleRangeRequest, false,
|
|
38
|
+
'Packaged differential downloads must use one byte range per request.');
|
|
37
39
|
assert.equal(
|
|
38
40
|
packageJson.build?.publish?.url,
|
|
39
41
|
'https://mindexec.lovecrdm.workers.dev/dev/windows/x64',
|
|
@@ -98,6 +100,8 @@ assert.match(preloadSource, /mindExecDesktop/, 'The updater preload namespace ch
|
|
|
98
100
|
assert.match(preloadSource, /updates:\s*\{/, 'The updater preload API is missing.');
|
|
99
101
|
assert.match(updateManagerSource, /autoDownload\s*=\s*false/, 'Updates must not download through an unowned implicit path.');
|
|
100
102
|
assert.match(updateManagerSource, /autoInstallOnAppQuit\s*=\s*false/, 'Updates must not restart without the explicit prompt path.');
|
|
103
|
+
assert.match(updateManagerSource, /useMultipleRangeRequest:\s*false/,
|
|
104
|
+
'Differential downloads must use Worker-compatible single byte ranges.');
|
|
101
105
|
assert.match(updateManagerSource, /quitAndInstall\(true, true\)/, 'Downloaded updates must relaunch silently after approval.');
|
|
102
106
|
assert.match(updateManagerSource, /desktop-updates-require-installed-windows-app/,
|
|
103
107
|
'Portable and unpacked builds must fail closed instead of replacing themselves.');
|
|
@@ -31,7 +31,12 @@ class FakeUpdater extends EventEmitter {
|
|
|
31
31
|
|
|
32
32
|
async downloadUpdate() {
|
|
33
33
|
this.downloadCalls += 1;
|
|
34
|
-
this.emit('download-progress', {
|
|
34
|
+
this.emit('download-progress', {
|
|
35
|
+
percent: 42,
|
|
36
|
+
total: 2_737_300,
|
|
37
|
+
transferred: 1_149_666,
|
|
38
|
+
bytesPerSecond: 5_000_000
|
|
39
|
+
});
|
|
35
40
|
await new Promise(resolve => setTimeout(resolve, 5));
|
|
36
41
|
this.emit('update-downloaded', { version: '1.1.0' });
|
|
37
42
|
}
|
|
@@ -79,7 +84,14 @@ test('concurrent checks share one version request and one download', async () =>
|
|
|
79
84
|
assert.equal(second.state, 'downloaded');
|
|
80
85
|
assert.equal(updater.checkCalls, 1);
|
|
81
86
|
assert.equal(updater.downloadCalls, 1);
|
|
82
|
-
assert.deepEqual(updater.feed, {
|
|
87
|
+
assert.deepEqual(updater.feed, {
|
|
88
|
+
provider: 'generic',
|
|
89
|
+
url: 'https://updates.example/dev/windows/x64',
|
|
90
|
+
useMultipleRangeRequest: false
|
|
91
|
+
});
|
|
92
|
+
assert.equal(first.downloadTotalBytes, 2_737_300);
|
|
93
|
+
assert.equal(first.downloadTransferredBytes, 1_149_666);
|
|
94
|
+
assert.equal(first.downloadBytesPerSecond, 5_000_000);
|
|
83
95
|
});
|
|
84
96
|
|
|
85
97
|
test('portable and unpacked executables never call electron-updater', async () => {
|
|
@@ -49,6 +49,9 @@ function createProductUpdateManager({
|
|
|
49
49
|
availableVersion: '',
|
|
50
50
|
downloaded: false,
|
|
51
51
|
progress: 0,
|
|
52
|
+
downloadTotalBytes: 0,
|
|
53
|
+
downloadTransferredBytes: 0,
|
|
54
|
+
downloadBytesPerSecond: 0,
|
|
52
55
|
error: '',
|
|
53
56
|
configured: feed.configured,
|
|
54
57
|
feedUrl: feed.url,
|
|
@@ -89,7 +92,13 @@ function createProductUpdateManager({
|
|
|
89
92
|
|
|
90
93
|
updater.autoDownload = false;
|
|
91
94
|
updater.autoInstallOnAppQuit = false;
|
|
92
|
-
if (feed.url)
|
|
95
|
+
if (feed.url) {
|
|
96
|
+
updater.setFeedURL({
|
|
97
|
+
provider: 'generic',
|
|
98
|
+
url: feed.url,
|
|
99
|
+
useMultipleRangeRequest: false
|
|
100
|
+
});
|
|
101
|
+
}
|
|
93
102
|
|
|
94
103
|
updater.on('checking-for-update', () => {
|
|
95
104
|
checkOutcome = 'checking';
|
|
@@ -102,15 +111,34 @@ function createProductUpdateManager({
|
|
|
102
111
|
availableVersion: String(info?.version || ''),
|
|
103
112
|
downloaded: false,
|
|
104
113
|
progress: 0,
|
|
114
|
+
downloadTotalBytes: 0,
|
|
115
|
+
downloadTransferredBytes: 0,
|
|
116
|
+
downloadBytesPerSecond: 0,
|
|
105
117
|
error: ''
|
|
106
118
|
});
|
|
107
119
|
});
|
|
108
120
|
updater.on('update-not-available', () => {
|
|
109
121
|
checkOutcome = 'current';
|
|
110
|
-
publish({
|
|
122
|
+
publish({
|
|
123
|
+
state: 'current',
|
|
124
|
+
availableVersion: '',
|
|
125
|
+
downloaded: false,
|
|
126
|
+
progress: 0,
|
|
127
|
+
downloadTotalBytes: 0,
|
|
128
|
+
downloadTransferredBytes: 0,
|
|
129
|
+
downloadBytesPerSecond: 0,
|
|
130
|
+
error: ''
|
|
131
|
+
});
|
|
111
132
|
});
|
|
112
133
|
updater.on('download-progress', progress => {
|
|
113
|
-
publish({
|
|
134
|
+
publish({
|
|
135
|
+
state: 'downloading',
|
|
136
|
+
progress: Number(progress?.percent || 0),
|
|
137
|
+
downloadTotalBytes: Number(progress?.total || 0),
|
|
138
|
+
downloadTransferredBytes: Number(progress?.transferred || 0),
|
|
139
|
+
downloadBytesPerSecond: Number(progress?.bytesPerSecond || 0),
|
|
140
|
+
error: ''
|
|
141
|
+
});
|
|
114
142
|
});
|
|
115
143
|
updater.on('update-downloaded', info => {
|
|
116
144
|
publish({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindexec/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.483",
|
|
4
4
|
"description": "MindExec local runtime and bridge CLI",
|
|
5
5
|
"main": "server.js",
|
|
6
6
|
"type": "module",
|
|
@@ -160,9 +160,10 @@
|
|
|
160
160
|
"portable": {
|
|
161
161
|
"artifactName": "MindExec-Portable-${version}-${arch}.${ext}"
|
|
162
162
|
},
|
|
163
|
-
"publish": {
|
|
164
|
-
"provider": "generic",
|
|
165
|
-
"url": "https://mindexec.lovecrdm.workers.dev/dev/windows/x64"
|
|
166
|
-
|
|
163
|
+
"publish": {
|
|
164
|
+
"provider": "generic",
|
|
165
|
+
"url": "https://mindexec.lovecrdm.workers.dev/dev/windows/x64",
|
|
166
|
+
"useMultipleRangeRequest": false
|
|
167
|
+
}
|
|
167
168
|
}
|
|
168
169
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -54,6 +54,17 @@ test('publisher validates version, size, and SHA-512 before upload', async () =>
|
|
|
54
54
|
}),
|
|
55
55
|
/desktop-update-dev-unsigned-ack-required/
|
|
56
56
|
);
|
|
57
|
+
assert.throws(
|
|
58
|
+
() => readReleasePlan({
|
|
59
|
+
platform: 'windows-x64',
|
|
60
|
+
directory,
|
|
61
|
+
packageVersion: '1.2.3',
|
|
62
|
+
channel: 'dev',
|
|
63
|
+
allowUnsigned: true
|
|
64
|
+
}),
|
|
65
|
+
/desktop-update-blockmap-missing/
|
|
66
|
+
);
|
|
67
|
+
await writeFile(join(directory, `${artifact}.blockmap`), Buffer.from('blockmap'));
|
|
57
68
|
const plan = readReleasePlan({
|
|
58
69
|
platform: 'windows-x64',
|
|
59
70
|
directory,
|
|
@@ -62,7 +73,7 @@ test('publisher validates version, size, and SHA-512 before upload', async () =>
|
|
|
62
73
|
allowUnsigned: true
|
|
63
74
|
});
|
|
64
75
|
assert.equal(plan.prefix, 'dev/windows/x64');
|
|
65
|
-
assert.deepEqual(plan.artifacts.map(item => item.fileName), [artifact]);
|
|
76
|
+
assert.deepEqual(plan.artifacts.map(item => item.fileName), [artifact, `${artifact}.blockmap`]);
|
|
66
77
|
assert.throws(
|
|
67
78
|
() => readReleasePlan({
|
|
68
79
|
platform: 'windows-x64',
|
|
@@ -70,3 +70,98 @@ test('worker preserves resumable byte-range responses for large installers', asy
|
|
|
70
70
|
assert.equal(response.headers.get('content-range'), 'bytes 8-11/20');
|
|
71
71
|
assert.equal(response.headers.get('content-length'), '4');
|
|
72
72
|
});
|
|
73
|
+
|
|
74
|
+
test('worker serves electron-updater multi-range requests as multipart without returning the full installer', async () => {
|
|
75
|
+
const source = new TextEncoder().encode('0123456789abcdefghij');
|
|
76
|
+
const calls = [];
|
|
77
|
+
const env = {
|
|
78
|
+
UPDATE_BUCKET: {
|
|
79
|
+
head: async () => ({
|
|
80
|
+
size: source.byteLength,
|
|
81
|
+
httpEtag: '"release-etag"',
|
|
82
|
+
writeHttpMetadata(headers) { headers.set('content-type', 'application/octet-stream'); }
|
|
83
|
+
}),
|
|
84
|
+
get: async (_key, options) => {
|
|
85
|
+
calls.push(options.range);
|
|
86
|
+
const { offset, length } = options.range;
|
|
87
|
+
const bytes = source.slice(offset, offset + length);
|
|
88
|
+
return {
|
|
89
|
+
body: new ReadableStream({ start(controller) { controller.enqueue(bytes); controller.close(); } }),
|
|
90
|
+
size: source.byteLength,
|
|
91
|
+
range: { offset, length },
|
|
92
|
+
httpEtag: '"release-etag"',
|
|
93
|
+
writeHttpMetadata(headers) { headers.set('content-type', 'application/octet-stream'); }
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const response = await worker.fetch(new Request(
|
|
100
|
+
'https://updates.example/dev/windows/x64/MindExec-0.2.461-dev-x64.exe',
|
|
101
|
+
{ headers: { range: 'bytes=0-3,10-13' } }
|
|
102
|
+
), env);
|
|
103
|
+
const body = await response.text();
|
|
104
|
+
|
|
105
|
+
assert.equal(response.status, 206);
|
|
106
|
+
assert.match(response.headers.get('content-type') || '', /^multipart\/byteranges; boundary=/i);
|
|
107
|
+
assert.equal(response.headers.has('content-range'), false);
|
|
108
|
+
assert.deepEqual(calls, [{ offset: 0, length: 4 }, { offset: 10, length: 4 }]);
|
|
109
|
+
assert.match(body, /Content-Range: bytes 0-3\/20\r\n\r\n0123/);
|
|
110
|
+
assert.match(body, /Content-Range: bytes 10-13\/20\r\n\r\nabcd/);
|
|
111
|
+
assert.equal(new TextEncoder().encode(body).byteLength, Number(response.headers.get('content-length')));
|
|
112
|
+
assert.ok(Number(response.headers.get('content-length')) < source.byteLength * 20,
|
|
113
|
+
'multi-range response must contain only requested parts, not the full installer');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test('worker rejects oversized or overlapping multi-range requests before reading R2', async () => {
|
|
117
|
+
let getCount = 0;
|
|
118
|
+
const metadata = {
|
|
119
|
+
size: 100_000_000,
|
|
120
|
+
httpEtag: '"release-etag"',
|
|
121
|
+
writeHttpMetadata(headers) { headers.set('content-type', 'application/octet-stream'); }
|
|
122
|
+
};
|
|
123
|
+
const env = {
|
|
124
|
+
UPDATE_BUCKET: {
|
|
125
|
+
head: async () => metadata,
|
|
126
|
+
get: async () => { getCount += 1; return null; }
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const oversized = await worker.fetch(new Request(
|
|
131
|
+
'https://updates.example/dev/windows/x64/MindExec-0.2.461-dev-x64.exe',
|
|
132
|
+
{ headers: { range: 'bytes=0-33554431,33554432-67108864' } }
|
|
133
|
+
), env);
|
|
134
|
+
assert.equal(oversized.status, 416);
|
|
135
|
+
|
|
136
|
+
const overlapping = await worker.fetch(new Request(
|
|
137
|
+
'https://updates.example/dev/windows/x64/MindExec-0.2.461-dev-x64.exe',
|
|
138
|
+
{ headers: { range: 'bytes=0-10,10-20' } }
|
|
139
|
+
), env);
|
|
140
|
+
assert.equal(overlapping.status, 416);
|
|
141
|
+
assert.equal(getCount, 0);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('worker fails closed when R2 does not honor an explicit multipart range', async () => {
|
|
145
|
+
const source = new TextEncoder().encode('0123456789abcdefghij');
|
|
146
|
+
const metadata = {
|
|
147
|
+
size: source.byteLength,
|
|
148
|
+
httpEtag: '"release-etag"',
|
|
149
|
+
writeHttpMetadata(headers) { headers.set('content-type', 'application/octet-stream'); }
|
|
150
|
+
};
|
|
151
|
+
const env = {
|
|
152
|
+
UPDATE_BUCKET: {
|
|
153
|
+
head: async () => metadata,
|
|
154
|
+
get: async () => ({
|
|
155
|
+
...metadata,
|
|
156
|
+
range: { offset: 0, length: source.byteLength },
|
|
157
|
+
body: new ReadableStream({ start(controller) { controller.enqueue(source); controller.close(); } })
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const response = await worker.fetch(new Request(
|
|
163
|
+
'https://updates.example/dev/windows/x64/MindExec-0.2.461-dev-x64.exe',
|
|
164
|
+
{ headers: { range: 'bytes=0-3,10-13' } }
|
|
165
|
+
), env);
|
|
166
|
+
await assert.rejects(response.arrayBuffer(), /desktop-update-range-mismatch:0-3/);
|
|
167
|
+
});
|
|
@@ -100,6 +100,12 @@ export function readReleasePlan({
|
|
|
100
100
|
if (sha512Base64(filePath) !== item.sha512) {
|
|
101
101
|
throw new Error(`desktop-update-artifact-hash-mismatch:${item.name}`);
|
|
102
102
|
}
|
|
103
|
+
if (/\.exe$/i.test(item.name)) {
|
|
104
|
+
const blockmapName = `${item.name}.blockmap`;
|
|
105
|
+
if (!existsSync(resolve(releaseDir, blockmapName))) {
|
|
106
|
+
throw new Error(`desktop-update-blockmap-missing:${blockmapName}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
103
109
|
}
|
|
104
110
|
|
|
105
111
|
const artifacts = readdirSync(releaseDir)
|
|
@@ -164,15 +170,17 @@ async function verifyPublished(plan) {
|
|
|
164
170
|
throw new Error('desktop-update-public-manifest-mismatch');
|
|
165
171
|
}
|
|
166
172
|
|
|
167
|
-
for (const
|
|
168
|
-
const artifactResponse = await fetch(`${PUBLIC_BASE_URL}/${plan.prefix}/${encodeURIComponent(
|
|
173
|
+
for (const artifact of plan.artifacts) {
|
|
174
|
+
const artifactResponse = await fetch(`${PUBLIC_BASE_URL}/${plan.prefix}/${encodeURIComponent(artifact.fileName)}`, {
|
|
169
175
|
method: 'HEAD',
|
|
170
176
|
cache: 'no-store'
|
|
171
177
|
});
|
|
172
|
-
if (!artifactResponse.ok)
|
|
173
|
-
|
|
178
|
+
if (!artifactResponse.ok) {
|
|
179
|
+
throw new Error(`desktop-update-public-artifact-http-${artifactResponse.status}:${artifact.fileName}`);
|
|
180
|
+
}
|
|
181
|
+
const expectedSize = statSync(artifact.filePath).size;
|
|
174
182
|
if (Number(artifactResponse.headers.get('content-length') || 0) !== expectedSize) {
|
|
175
|
-
throw new Error(`desktop-update-public-artifact-size-mismatch:${
|
|
183
|
+
throw new Error(`desktop-update-public-artifact-size-mismatch:${artifact.fileName}`);
|
|
176
184
|
}
|
|
177
185
|
}
|
|
178
186
|
}
|
|
@@ -17,10 +17,39 @@
|
|
|
17
17
|
function buildEdgePathData(source, target) {
|
|
18
18
|
const deltaX = target.x - source.x;
|
|
19
19
|
const absDeltaX = Math.abs(deltaX);
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return `M ${source.x.toFixed(1)} ${source.y.toFixed(1)} C ${(source.x +
|
|
20
|
+
const handleDistance = deltaX < 0
|
|
21
|
+
? Math.min(260, Math.max(84, absDeltaX * 0.22, Math.abs(target.y - source.y) * 0.35))
|
|
22
|
+
: Math.min(180, Math.max(12, absDeltaX * 0.38), Math.max(0, absDeltaX * 0.45));
|
|
23
|
+
return `M ${source.x.toFixed(1)} ${source.y.toFixed(1)} C ${(source.x + handleDistance).toFixed(1)} ${source.y.toFixed(1)}, ${(target.x - handleDistance).toFixed(1)} ${target.y.toFixed(1)}, ${target.x.toFixed(1)} ${target.y.toFixed(1)}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function buildRoundedRoutePathData(points, radius = 12) {
|
|
27
|
+
if (!Array.isArray(points) || points.length < 2) {
|
|
28
|
+
return '';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const commands = [`M ${points[0].x.toFixed(1)} ${points[0].y.toFixed(1)}`];
|
|
32
|
+
for (let index = 1; index < points.length - 1; index += 1) {
|
|
33
|
+
const previous = points[index - 1];
|
|
34
|
+
const current = points[index];
|
|
35
|
+
const next = points[index + 1];
|
|
36
|
+
const incomingLength = Math.abs(current.x - previous.x) + Math.abs(current.y - previous.y);
|
|
37
|
+
const outgoingLength = Math.abs(next.x - current.x) + Math.abs(next.y - current.y);
|
|
38
|
+
const cornerRadius = Math.min(radius, incomingLength / 2, outgoingLength / 2);
|
|
39
|
+
const before = {
|
|
40
|
+
x: current.x - Math.sign(current.x - previous.x) * cornerRadius,
|
|
41
|
+
y: current.y - Math.sign(current.y - previous.y) * cornerRadius
|
|
42
|
+
};
|
|
43
|
+
const after = {
|
|
44
|
+
x: current.x + Math.sign(next.x - current.x) * cornerRadius,
|
|
45
|
+
y: current.y + Math.sign(next.y - current.y) * cornerRadius
|
|
46
|
+
};
|
|
47
|
+
commands.push(`L ${before.x.toFixed(1)} ${before.y.toFixed(1)}`);
|
|
48
|
+
commands.push(`Q ${current.x.toFixed(1)} ${current.y.toFixed(1)} ${after.x.toFixed(1)} ${after.y.toFixed(1)}`);
|
|
49
|
+
}
|
|
50
|
+
const finalPoint = points[points.length - 1];
|
|
51
|
+
commands.push(`L ${finalPoint.x.toFixed(1)} ${finalPoint.y.toFixed(1)}`);
|
|
52
|
+
return commands.join(' ');
|
|
24
53
|
}
|
|
25
54
|
|
|
26
55
|
function getCachedViewportMetrics(module) {
|
|
@@ -96,7 +125,14 @@
|
|
|
96
125
|
return false;
|
|
97
126
|
}
|
|
98
127
|
|
|
99
|
-
const
|
|
128
|
+
const routePoints = Array.isArray(item.motionRoutePoints)
|
|
129
|
+
? item.motionRoutePoints
|
|
130
|
+
.map(point => transformPoint(point, scale, offsetX, offsetY))
|
|
131
|
+
.filter(Boolean)
|
|
132
|
+
: null;
|
|
133
|
+
const pathData = routePoints?.length >= 2
|
|
134
|
+
? buildRoundedRoutePathData(routePoints)
|
|
135
|
+
: buildEdgePathData(source, target);
|
|
100
136
|
setSvgAttributes(item.hitPath, { d: pathData });
|
|
101
137
|
setSvgAttributes(item.path, { d: pathData });
|
|
102
138
|
setSvgAttributes(item.sourceDot, { cx: source.x.toFixed(1), cy: source.y.toFixed(1) });
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
// File: mind-map-automation-edge-routing.js
|
|
2
|
+
// Settled business-automation edge routing kept separate from the CSS3D runtime.
|
|
3
|
+
(function registerMindMapAutomationEdgeRouting(global) {
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
function buildRoute(source, target, obstacles = []) {
|
|
7
|
+
obstacles = selectRelevantBusinessAutomationRoutingObstacles(source, target, obstacles);
|
|
8
|
+
const deltaX = target.x - source.x;
|
|
9
|
+
const absDeltaX = Math.abs(deltaX);
|
|
10
|
+
const handleDistance = deltaX < 0
|
|
11
|
+
? Math.min(260, Math.max(84, absDeltaX * 0.22, Math.abs(target.y - source.y) * 0.35))
|
|
12
|
+
: Math.min(180, Math.max(12, absDeltaX * 0.38), Math.max(0, absDeltaX * 0.45));
|
|
13
|
+
|
|
14
|
+
// Folded room islands can legitimately place a later stage to the
|
|
15
|
+
// left. Keep both handles outside their cards so the connector loops
|
|
16
|
+
// around the island instead of diving back through intervening nodes.
|
|
17
|
+
const firstControl = { x: source.x + handleDistance, y: source.y };
|
|
18
|
+
const secondControl = { x: target.x - handleDistance, y: target.y };
|
|
19
|
+
const cubicPoints = [];
|
|
20
|
+
for (let segment = 0; segment <= 12; segment += 1) {
|
|
21
|
+
const t = segment / 12;
|
|
22
|
+
const inverse = 1 - t;
|
|
23
|
+
const inverseSquared = inverse * inverse;
|
|
24
|
+
const tSquared = t * t;
|
|
25
|
+
cubicPoints.push({
|
|
26
|
+
x: inverseSquared * inverse * source.x
|
|
27
|
+
+ 3 * inverseSquared * t * firstControl.x
|
|
28
|
+
+ 3 * inverse * tSquared * secondControl.x
|
|
29
|
+
+ tSquared * t * target.x,
|
|
30
|
+
y: inverseSquared * inverse * source.y
|
|
31
|
+
+ 3 * inverseSquared * t * firstControl.y
|
|
32
|
+
+ 3 * inverse * tSquared * secondControl.y
|
|
33
|
+
+ tSquared * t * target.y
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
const cubicPathData = `M ${source.x.toFixed(1)} ${source.y.toFixed(1)} C ${firstControl.x.toFixed(1)} ${source.y.toFixed(1)}, ${secondControl.x.toFixed(1)} ${target.y.toFixed(1)}, ${target.x.toFixed(1)} ${target.y.toFixed(1)}`;
|
|
37
|
+
if (isRouteClear(cubicPoints, obstacles)) {
|
|
38
|
+
return { pathData: cubicPathData, points: null, blocked: false };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const clearance = 18;
|
|
42
|
+
const left = Math.min(source.x, target.x, ...obstacles.map(rect => rect.x));
|
|
43
|
+
const right = Math.max(source.x, target.x, ...obstacles.map(rect => rect.x + rect.width));
|
|
44
|
+
const top = Math.min(source.y, target.y, ...obstacles.map(rect => rect.y));
|
|
45
|
+
const bottom = Math.max(source.y, target.y, ...obstacles.map(rect => rect.y + rect.height));
|
|
46
|
+
const obstacleChannels = obstacles.flatMap(rect => [rect.x - clearance, rect.x + rect.width + clearance]);
|
|
47
|
+
const sourceExitCandidates = Array.from(new Set([
|
|
48
|
+
source.x + clearance,
|
|
49
|
+
right + clearance,
|
|
50
|
+
...obstacleChannels.filter(value => value >= source.x + clearance - 0.01)
|
|
51
|
+
]))
|
|
52
|
+
.sort((a, b) => Math.abs(a - source.x) - Math.abs(b - source.x))
|
|
53
|
+
.slice(0, 12);
|
|
54
|
+
const targetEntryCandidates = Array.from(new Set([
|
|
55
|
+
target.x - clearance,
|
|
56
|
+
left - clearance,
|
|
57
|
+
...obstacleChannels.filter(value => value <= target.x - clearance + 0.01)
|
|
58
|
+
]))
|
|
59
|
+
.sort((a, b) => Math.abs(a - target.x) - Math.abs(b - target.x))
|
|
60
|
+
.slice(0, 12);
|
|
61
|
+
const laneCandidates = Array.from(new Set([
|
|
62
|
+
top - clearance,
|
|
63
|
+
bottom + clearance,
|
|
64
|
+
...obstacles.flatMap(rect => [rect.y - clearance, rect.y + rect.height + clearance])
|
|
65
|
+
])).sort((a, b) => {
|
|
66
|
+
const distanceA = Math.min(Math.abs(a - source.y), Math.abs(a - target.y));
|
|
67
|
+
const distanceB = Math.min(Math.abs(b - source.y), Math.abs(b - target.y));
|
|
68
|
+
return distanceA - distanceB || a - b;
|
|
69
|
+
}).slice(0, 16);
|
|
70
|
+
const candidates = [];
|
|
71
|
+
sourceExitCandidates.forEach(sourceExitX => {
|
|
72
|
+
targetEntryCandidates.forEach(targetEntryX => {
|
|
73
|
+
laneCandidates.forEach(laneY => {
|
|
74
|
+
const points = removeDuplicateRoutePoints([
|
|
75
|
+
source,
|
|
76
|
+
{ x: sourceExitX, y: source.y },
|
|
77
|
+
{ x: sourceExitX, y: laneY },
|
|
78
|
+
{ x: targetEntryX, y: laneY },
|
|
79
|
+
{ x: targetEntryX, y: target.y },
|
|
80
|
+
target
|
|
81
|
+
]);
|
|
82
|
+
if (!isRouteClear(points, obstacles)) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const length = points.slice(1).reduce((total, point, index) => (
|
|
87
|
+
total
|
|
88
|
+
+ Math.abs(point.x - points[index].x)
|
|
89
|
+
+ Math.abs(point.y - points[index].y)
|
|
90
|
+
), 0);
|
|
91
|
+
candidates.push({
|
|
92
|
+
points,
|
|
93
|
+
score: length + (points.length - 2) * 9,
|
|
94
|
+
signature: points.map(point => `${point.x.toFixed(2)}:${point.y.toFixed(2)}`).join(',')
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
candidates.sort((a, b) => a.score - b.score || a.signature.localeCompare(b.signature));
|
|
100
|
+
const best = candidates[0] || null;
|
|
101
|
+
if (best) {
|
|
102
|
+
return { pathData: buildRoundedRoutePathData(best.points), points: best.points, blocked: false };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const orthogonalPoints = buildOrthogonalRoute(source, target, obstacles, clearance);
|
|
106
|
+
return orthogonalPoints
|
|
107
|
+
? { pathData: buildRoundedRoutePathData(orthogonalPoints), points: orthogonalPoints, blocked: false }
|
|
108
|
+
: { pathData: '', points: null, blocked: true };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function selectRelevantBusinessAutomationRoutingObstacles(source, target, obstacles) {
|
|
112
|
+
if (!Array.isArray(obstacles) || obstacles.length === 0) {
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const margin = Math.max(120, Math.min(420, (Math.abs(target.x - source.x) + Math.abs(target.y - source.y)) * 0.3));
|
|
117
|
+
const left = Math.min(source.x, target.x) - margin;
|
|
118
|
+
const right = Math.max(source.x, target.x) + margin;
|
|
119
|
+
const top = Math.min(source.y, target.y) - margin;
|
|
120
|
+
const bottom = Math.max(source.y, target.y) + margin;
|
|
121
|
+
const centreX = (source.x + target.x) * 0.5;
|
|
122
|
+
const centreY = (source.y + target.y) * 0.5;
|
|
123
|
+
return obstacles
|
|
124
|
+
.filter(rect => rect.x < right
|
|
125
|
+
&& rect.x + rect.width > left
|
|
126
|
+
&& rect.y < bottom
|
|
127
|
+
&& rect.y + rect.height > top)
|
|
128
|
+
.sort((first, second) => {
|
|
129
|
+
const firstX = first.x + first.width * 0.5;
|
|
130
|
+
const firstY = first.y + first.height * 0.5;
|
|
131
|
+
const secondX = second.x + second.width * 0.5;
|
|
132
|
+
const secondY = second.y + second.height * 0.5;
|
|
133
|
+
const firstDistance = Math.abs(firstX - centreX) + Math.abs(firstY - centreY);
|
|
134
|
+
const secondDistance = Math.abs(secondX - centreX) + Math.abs(secondY - centreY);
|
|
135
|
+
return firstDistance - secondDistance
|
|
136
|
+
|| String(first.nodeId || '').localeCompare(String(second.nodeId || ''));
|
|
137
|
+
})
|
|
138
|
+
.slice(0, 32);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function buildOrthogonalRoute(source, target, obstacles, clearance) {
|
|
142
|
+
const start = { x: source.x + clearance, y: source.y };
|
|
143
|
+
const goal = { x: target.x - clearance, y: target.y };
|
|
144
|
+
if (!isRouteClear([source, start], obstacles)
|
|
145
|
+
|| !isRouteClear([goal, target], obstacles)) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const xCoordinates = Array.from(new Set([
|
|
150
|
+
start.x,
|
|
151
|
+
goal.x,
|
|
152
|
+
...obstacles.flatMap(rect => [rect.x - clearance, rect.x + rect.width + clearance])
|
|
153
|
+
])).sort((a, b) => a - b);
|
|
154
|
+
const yCoordinates = Array.from(new Set([
|
|
155
|
+
start.y,
|
|
156
|
+
goal.y,
|
|
157
|
+
...obstacles.flatMap(rect => [rect.y - clearance, rect.y + rect.height + clearance])
|
|
158
|
+
])).sort((a, b) => a - b);
|
|
159
|
+
const startX = xCoordinates.indexOf(start.x);
|
|
160
|
+
const startY = yCoordinates.indexOf(start.y);
|
|
161
|
+
const goalX = xCoordinates.indexOf(goal.x);
|
|
162
|
+
const goalY = yCoordinates.indexOf(goal.y);
|
|
163
|
+
if (startX < 0 || startY < 0 || goalX < 0 || goalY < 0) {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const pointIsClear = (xIndex, yIndex) => {
|
|
168
|
+
const x = xCoordinates[xIndex];
|
|
169
|
+
const y = yCoordinates[yIndex];
|
|
170
|
+
return !obstacles.some(rect => x > rect.x + 0.01
|
|
171
|
+
&& x < rect.x + rect.width - 0.01
|
|
172
|
+
&& y > rect.y + 0.01
|
|
173
|
+
&& y < rect.y + rect.height - 0.01);
|
|
174
|
+
};
|
|
175
|
+
const segmentIsClear = (fromX, fromY, toX, toY) => isRouteClear([
|
|
176
|
+
{ x: xCoordinates[fromX], y: yCoordinates[fromY] },
|
|
177
|
+
{ x: xCoordinates[toX], y: yCoordinates[toY] }
|
|
178
|
+
], obstacles);
|
|
179
|
+
const stateKey = (x, y, direction) => `${x}|${y}|${direction}`;
|
|
180
|
+
const compareQueueEntries = (first, second) => first.cost - second.cost
|
|
181
|
+
|| first.x - second.x
|
|
182
|
+
|| first.y - second.y
|
|
183
|
+
|| first.direction - second.direction;
|
|
184
|
+
const queue = [];
|
|
185
|
+
const queuePush = entry => {
|
|
186
|
+
queue.push(entry);
|
|
187
|
+
let index = queue.length - 1;
|
|
188
|
+
while (index > 0) {
|
|
189
|
+
const parent = Math.floor((index - 1) / 2);
|
|
190
|
+
if (compareQueueEntries(queue[parent], queue[index]) <= 0) break;
|
|
191
|
+
[queue[parent], queue[index]] = [queue[index], queue[parent]];
|
|
192
|
+
index = parent;
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
const queuePop = () => {
|
|
196
|
+
if (queue.length === 0) return null;
|
|
197
|
+
const first = queue[0];
|
|
198
|
+
const last = queue.pop();
|
|
199
|
+
if (queue.length > 0 && last) {
|
|
200
|
+
queue[0] = last;
|
|
201
|
+
let index = 0;
|
|
202
|
+
while (true) {
|
|
203
|
+
const left = index * 2 + 1;
|
|
204
|
+
const right = left + 1;
|
|
205
|
+
let best = index;
|
|
206
|
+
if (left < queue.length && compareQueueEntries(queue[left], queue[best]) < 0) best = left;
|
|
207
|
+
if (right < queue.length && compareQueueEntries(queue[right], queue[best]) < 0) best = right;
|
|
208
|
+
if (best === index) break;
|
|
209
|
+
[queue[index], queue[best]] = [queue[best], queue[index]];
|
|
210
|
+
index = best;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return first;
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const startKey = stateKey(startX, startY, 0);
|
|
217
|
+
const distances = new Map([[startKey, 0]]);
|
|
218
|
+
const previous = new Map();
|
|
219
|
+
queuePush({ x: startX, y: startY, direction: 0, cost: 0, key: startKey });
|
|
220
|
+
const moves = [
|
|
221
|
+
{ dx: 1, dy: 0, direction: 1 },
|
|
222
|
+
{ dx: -1, dy: 0, direction: 1 },
|
|
223
|
+
{ dx: 0, dy: 1, direction: 2 },
|
|
224
|
+
{ dx: 0, dy: -1, direction: 2 }
|
|
225
|
+
];
|
|
226
|
+
let resolved = null;
|
|
227
|
+
while (queue.length > 0) {
|
|
228
|
+
const state = queuePop();
|
|
229
|
+
if (!state || state.cost > (distances.get(state.key) ?? Number.POSITIVE_INFINITY) + 0.001) continue;
|
|
230
|
+
if (state.x === goalX && state.y === goalY) {
|
|
231
|
+
resolved = state;
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
moves.forEach(move => {
|
|
236
|
+
const nextX = state.x + move.dx;
|
|
237
|
+
const nextY = state.y + move.dy;
|
|
238
|
+
if (nextX < 0 || nextX >= xCoordinates.length || nextY < 0 || nextY >= yCoordinates.length
|
|
239
|
+
|| !pointIsClear(nextX, nextY)
|
|
240
|
+
|| !segmentIsClear(state.x, state.y, nextX, nextY)) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const segmentLength = Math.abs(xCoordinates[nextX] - xCoordinates[state.x])
|
|
244
|
+
+ Math.abs(yCoordinates[nextY] - yCoordinates[state.y]);
|
|
245
|
+
const turnCost = state.direction !== 0 && state.direction !== move.direction ? 12 : 0;
|
|
246
|
+
const cost = state.cost + segmentLength + turnCost;
|
|
247
|
+
const key = stateKey(nextX, nextY, move.direction);
|
|
248
|
+
if ((distances.get(key) ?? Number.POSITIVE_INFINITY) <= cost + 0.001) return;
|
|
249
|
+
distances.set(key, cost);
|
|
250
|
+
previous.set(key, state);
|
|
251
|
+
queuePush({ x: nextX, y: nextY, direction: move.direction, cost, key });
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
if (!resolved) {
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const reversed = [];
|
|
259
|
+
let cursor = resolved;
|
|
260
|
+
while (cursor) {
|
|
261
|
+
reversed.push({ x: xCoordinates[cursor.x], y: yCoordinates[cursor.y] });
|
|
262
|
+
if (cursor.key === startKey) break;
|
|
263
|
+
cursor = previous.get(cursor.key) || null;
|
|
264
|
+
}
|
|
265
|
+
reversed.reverse();
|
|
266
|
+
return simplifyOrthogonalRoute(removeDuplicateRoutePoints([
|
|
267
|
+
source,
|
|
268
|
+
start,
|
|
269
|
+
...reversed,
|
|
270
|
+
goal,
|
|
271
|
+
target
|
|
272
|
+
]));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function simplifyOrthogonalRoute(points) {
|
|
276
|
+
if (!Array.isArray(points) || points.length < 3) {
|
|
277
|
+
return points;
|
|
278
|
+
}
|
|
279
|
+
const simplified = [points[0]];
|
|
280
|
+
for (let index = 1; index < points.length - 1; index += 1) {
|
|
281
|
+
const previous = simplified[simplified.length - 1];
|
|
282
|
+
const current = points[index];
|
|
283
|
+
const next = points[index + 1];
|
|
284
|
+
const sameVertical = Math.abs(previous.x - current.x) < 0.01 && Math.abs(current.x - next.x) < 0.01;
|
|
285
|
+
const sameHorizontal = Math.abs(previous.y - current.y) < 0.01 && Math.abs(current.y - next.y) < 0.01;
|
|
286
|
+
if (!sameVertical && !sameHorizontal) {
|
|
287
|
+
simplified.push(current);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
simplified.push(points[points.length - 1]);
|
|
291
|
+
return simplified;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function buildPathData(source, target) {
|
|
295
|
+
return buildRoute(source, target).pathData;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function removeDuplicateRoutePoints(points) {
|
|
299
|
+
const result = [];
|
|
300
|
+
points.forEach(point => {
|
|
301
|
+
const previous = result[result.length - 1];
|
|
302
|
+
if (previous && Math.abs(previous.x - point.x) < 0.01 && Math.abs(previous.y - point.y) < 0.01) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
result.push({ x: Number(point.x), y: Number(point.y) });
|
|
306
|
+
});
|
|
307
|
+
return result;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function isRouteClear(points, obstacles) {
|
|
311
|
+
if (!Array.isArray(points) || points.length < 2) {
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
return !obstacles.some(rect => {
|
|
315
|
+
for (let index = 1; index < points.length; index += 1) {
|
|
316
|
+
if (doesSegmentIntersectRectInterior(points[index - 1], points[index], rect)) {
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return false;
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function doesSegmentIntersectRectInterior(source, target, rect) {
|
|
325
|
+
const inset = 0.5;
|
|
326
|
+
const left = Number(rect.x) + inset;
|
|
327
|
+
const right = Number(rect.x) + Number(rect.width) - inset;
|
|
328
|
+
const top = Number(rect.y) + inset;
|
|
329
|
+
const bottom = Number(rect.y) + Number(rect.height) - inset;
|
|
330
|
+
if (!(left < right && top < bottom)) {
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
const inside = point => point.x > left && point.x < right && point.y > top && point.y < bottom;
|
|
334
|
+
if (inside(source) || inside(target)) {
|
|
335
|
+
return true;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const orientation = (a, b, c) => (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
|
|
339
|
+
const onSegment = (a, b, c) => b.x >= Math.min(a.x, c.x) - 0.0001
|
|
340
|
+
&& b.x <= Math.max(a.x, c.x) + 0.0001
|
|
341
|
+
&& b.y >= Math.min(a.y, c.y) - 0.0001
|
|
342
|
+
&& b.y <= Math.max(a.y, c.y) + 0.0001;
|
|
343
|
+
const intersects = (a, b, c, d) => {
|
|
344
|
+
const first = orientation(a, b, c);
|
|
345
|
+
const second = orientation(a, b, d);
|
|
346
|
+
const third = orientation(c, d, a);
|
|
347
|
+
const fourth = orientation(c, d, b);
|
|
348
|
+
if (((first > 0.0001 && second < -0.0001) || (first < -0.0001 && second > 0.0001))
|
|
349
|
+
&& ((third > 0.0001 && fourth < -0.0001) || (third < -0.0001 && fourth > 0.0001))) {
|
|
350
|
+
return true;
|
|
351
|
+
}
|
|
352
|
+
return (Math.abs(first) <= 0.0001 && onSegment(a, c, b))
|
|
353
|
+
|| (Math.abs(second) <= 0.0001 && onSegment(a, d, b))
|
|
354
|
+
|| (Math.abs(third) <= 0.0001 && onSegment(c, a, d))
|
|
355
|
+
|| (Math.abs(fourth) <= 0.0001 && onSegment(c, b, d));
|
|
356
|
+
};
|
|
357
|
+
const topLeft = { x: left, y: top };
|
|
358
|
+
const topRight = { x: right, y: top };
|
|
359
|
+
const bottomRight = { x: right, y: bottom };
|
|
360
|
+
const bottomLeft = { x: left, y: bottom };
|
|
361
|
+
return intersects(source, target, topLeft, topRight)
|
|
362
|
+
|| intersects(source, target, topRight, bottomRight)
|
|
363
|
+
|| intersects(source, target, bottomRight, bottomLeft)
|
|
364
|
+
|| intersects(source, target, bottomLeft, topLeft);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function buildRoundedRoutePathData(points, radius = 12) {
|
|
368
|
+
if (!Array.isArray(points) || points.length < 2) {
|
|
369
|
+
return '';
|
|
370
|
+
}
|
|
371
|
+
const commands = [`M ${points[0].x.toFixed(1)} ${points[0].y.toFixed(1)}`];
|
|
372
|
+
for (let index = 1; index < points.length - 1; index += 1) {
|
|
373
|
+
const previous = points[index - 1];
|
|
374
|
+
const current = points[index];
|
|
375
|
+
const next = points[index + 1];
|
|
376
|
+
const incomingLength = Math.abs(current.x - previous.x) + Math.abs(current.y - previous.y);
|
|
377
|
+
const outgoingLength = Math.abs(next.x - current.x) + Math.abs(next.y - current.y);
|
|
378
|
+
const cornerRadius = Math.min(radius, incomingLength / 2, outgoingLength / 2);
|
|
379
|
+
const before = {
|
|
380
|
+
x: current.x - Math.sign(current.x - previous.x) * cornerRadius,
|
|
381
|
+
y: current.y - Math.sign(current.y - previous.y) * cornerRadius
|
|
382
|
+
};
|
|
383
|
+
const after = {
|
|
384
|
+
x: current.x + Math.sign(next.x - current.x) * cornerRadius,
|
|
385
|
+
y: current.y + Math.sign(next.y - current.y) * cornerRadius
|
|
386
|
+
};
|
|
387
|
+
commands.push(`L ${before.x.toFixed(1)} ${before.y.toFixed(1)}`);
|
|
388
|
+
commands.push(`Q ${current.x.toFixed(1)} ${current.y.toFixed(1)} ${after.x.toFixed(1)} ${after.y.toFixed(1)}`);
|
|
389
|
+
}
|
|
390
|
+
const finalPoint = points[points.length - 1];
|
|
391
|
+
commands.push(`L ${finalPoint.x.toFixed(1)} ${finalPoint.y.toFixed(1)}`);
|
|
392
|
+
return commands.join(' ');
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
global.MindMapAutomationEdgeRouting = Object.freeze({
|
|
396
|
+
buildRoute,
|
|
397
|
+
buildPathData,
|
|
398
|
+
isRouteClear
|
|
399
|
+
});
|
|
400
|
+
})(typeof window !== 'undefined' ? window : globalThis);
|
|
@@ -10762,6 +10762,33 @@
|
|
|
10762
10762
|
return rects;
|
|
10763
10763
|
}
|
|
10764
10764
|
|
|
10765
|
+
function collectBusinessAutomationRoutingObstacles(module, containerRect, viewportWidth, viewportHeight) {
|
|
10766
|
+
if (!(module?.nodeObjectsById instanceof Map)) {
|
|
10767
|
+
return [];
|
|
10768
|
+
}
|
|
10769
|
+
|
|
10770
|
+
const rects = [];
|
|
10771
|
+
module.nodeObjectsById.forEach((entry, nodeId) => {
|
|
10772
|
+
if (!entry?.model || entry.isVisibleInFrustum === false) {
|
|
10773
|
+
return;
|
|
10774
|
+
}
|
|
10775
|
+
|
|
10776
|
+
const residentFrame = getBusinessAutomationResidentNodeFrame(module, nodeId);
|
|
10777
|
+
const rect = projectBusinessAutomationNodeOcclusionRect(
|
|
10778
|
+
module,
|
|
10779
|
+
entry,
|
|
10780
|
+
containerRect,
|
|
10781
|
+
viewportWidth,
|
|
10782
|
+
viewportHeight,
|
|
10783
|
+
residentFrame
|
|
10784
|
+
);
|
|
10785
|
+
if (rect) {
|
|
10786
|
+
rects.push({ ...rect, nodeId: String(nodeId || '') });
|
|
10787
|
+
}
|
|
10788
|
+
});
|
|
10789
|
+
return rects;
|
|
10790
|
+
}
|
|
10791
|
+
|
|
10765
10792
|
function applyBusinessAutomationResidentOcclusionMask(visualLayer, visualGroup, module, containerRect, viewportWidth, viewportHeight) {
|
|
10766
10793
|
if (!visualLayer || !visualGroup) {
|
|
10767
10794
|
return;
|
|
@@ -11057,13 +11084,35 @@
|
|
|
11057
11084
|
event.stopImmediatePropagation?.();
|
|
11058
11085
|
}
|
|
11059
11086
|
|
|
11060
|
-
function
|
|
11087
|
+
function buildBusinessAutomationEdgeRoute(source, target, obstacles = []) {
|
|
11088
|
+
const routing = window.MindMapAutomationEdgeRouting;
|
|
11089
|
+
if (typeof routing?.buildRoute === 'function') {
|
|
11090
|
+
return routing.buildRoute(source, target, obstacles);
|
|
11091
|
+
}
|
|
11092
|
+
|
|
11093
|
+
// Loading the focused router is a release contract, but an omitted
|
|
11094
|
+
// script must not crash the whole canvas. Fall back only for a direct
|
|
11095
|
+
// unobstructed connector; obstacle-bearing routes fail closed.
|
|
11096
|
+
if (Array.isArray(obstacles) && obstacles.length > 0) {
|
|
11097
|
+
return { pathData: '', points: null, blocked: true };
|
|
11098
|
+
}
|
|
11099
|
+
|
|
11061
11100
|
const deltaX = target.x - source.x;
|
|
11062
11101
|
const absDeltaX = Math.abs(deltaX);
|
|
11063
|
-
const
|
|
11064
|
-
|
|
11065
|
-
|
|
11066
|
-
|
|
11102
|
+
const handleDistance = deltaX < 0
|
|
11103
|
+
? Math.min(260, Math.max(84, absDeltaX * 0.22, Math.abs(target.y - source.y) * 0.35))
|
|
11104
|
+
: Math.min(180, Math.max(12, absDeltaX * 0.38), Math.max(0, absDeltaX * 0.45));
|
|
11105
|
+
const firstControl = { x: source.x + handleDistance, y: source.y };
|
|
11106
|
+
const secondControl = { x: target.x - handleDistance, y: target.y };
|
|
11107
|
+
return {
|
|
11108
|
+
pathData: `M ${source.x.toFixed(1)} ${source.y.toFixed(1)} C ${firstControl.x.toFixed(1)} ${source.y.toFixed(1)}, ${secondControl.x.toFixed(1)} ${target.y.toFixed(1)}, ${target.x.toFixed(1)} ${target.y.toFixed(1)}`,
|
|
11109
|
+
points: null,
|
|
11110
|
+
blocked: false
|
|
11111
|
+
};
|
|
11112
|
+
}
|
|
11113
|
+
|
|
11114
|
+
function buildBusinessAutomationEdgePathData(source, target) {
|
|
11115
|
+
return buildBusinessAutomationEdgeRoute(source, target).pathData;
|
|
11067
11116
|
}
|
|
11068
11117
|
|
|
11069
11118
|
function getBusinessAutomationDraftTargetPoint(module, draft, containerRect) {
|
|
@@ -11179,7 +11228,7 @@
|
|
|
11179
11228
|
item.targetDot?.remove?.();
|
|
11180
11229
|
}
|
|
11181
11230
|
|
|
11182
|
-
function updateBusinessAutomationEdgeItem(item, edge, pathData, source, target, theme, isContextEdge, isSelected, isRelationHighlighted, hitPointerEvents) {
|
|
11231
|
+
function updateBusinessAutomationEdgeItem(item, edge, pathData, source, target, theme, isContextEdge, isSelected, isRelationHighlighted, hitPointerEvents, routePoints = null) {
|
|
11183
11232
|
setBusinessAutomationSvgAttributes(item.hitPath, {
|
|
11184
11233
|
d: pathData,
|
|
11185
11234
|
class: 'mind-map-business-automation-edge-hit',
|
|
@@ -11224,6 +11273,9 @@
|
|
|
11224
11273
|
});
|
|
11225
11274
|
item.motionSource = { x: source.x, y: source.y };
|
|
11226
11275
|
item.motionTarget = { x: target.x, y: target.y };
|
|
11276
|
+
item.motionRoutePoints = Array.isArray(routePoints)
|
|
11277
|
+
? routePoints.map(point => ({ x: Number(point.x), y: Number(point.y) }))
|
|
11278
|
+
: null;
|
|
11227
11279
|
item.motionVisible = true;
|
|
11228
11280
|
setBusinessAutomationSvgElementsVisible([item.hitPath, item.path, item.sourceDot, item.targetDot], true);
|
|
11229
11281
|
}
|
|
@@ -11256,6 +11308,7 @@
|
|
|
11256
11308
|
const containerRect = module.container.getBoundingClientRect();
|
|
11257
11309
|
const width = Math.max(1, Math.round(containerRect.width || 1));
|
|
11258
11310
|
const height = Math.max(1, Math.round(containerRect.height || 1));
|
|
11311
|
+
const routingObstacles = collectBusinessAutomationRoutingObstacles(module, containerRect, width, height);
|
|
11259
11312
|
recordBusinessAutomationEdgeCameraState(module, width, height);
|
|
11260
11313
|
for (const layer of [visualLayer, hitLayer]) {
|
|
11261
11314
|
setBusinessAutomationSvgAttributes(layer, {
|
|
@@ -11335,12 +11388,26 @@
|
|
|
11335
11388
|
: isWorkerEdge
|
|
11336
11389
|
? AUTOMATION_WORKER_PIN_THEME
|
|
11337
11390
|
: getAutomationPinTheme(sourceType);
|
|
11338
|
-
const
|
|
11391
|
+
const route = buildBusinessAutomationEdgeRoute(
|
|
11392
|
+
source,
|
|
11393
|
+
target,
|
|
11394
|
+
routingObstacles.filter(rect => rect.nodeId !== String(edge.sourceNodeId || '')
|
|
11395
|
+
&& rect.nodeId !== String(edge.targetNodeId || ''))
|
|
11396
|
+
);
|
|
11397
|
+
const pathData = route.pathData;
|
|
11398
|
+
if (route.blocked === true || !pathData) {
|
|
11399
|
+
const existing = renderState.edgeItems.get(edgeId);
|
|
11400
|
+
if (existing) {
|
|
11401
|
+
existing.motionVisible = false;
|
|
11402
|
+
setBusinessAutomationSvgElementsVisible([existing.hitPath, existing.path, existing.sourceDot, existing.targetDot], false);
|
|
11403
|
+
}
|
|
11404
|
+
continue;
|
|
11405
|
+
}
|
|
11339
11406
|
const isSelected = String(edge.id || '') === _businessAutomationSelectedEdgeId;
|
|
11340
11407
|
const isRelationHighlighted = relationContext?.edgeIds?.has?.(String(edge.id || '').trim()) === true;
|
|
11341
11408
|
const hitPointerEvents = _businessAutomationConnectionDraft ? 'none' : 'stroke';
|
|
11342
11409
|
const item = ensureBusinessAutomationEdgeItem(renderState, edgeId);
|
|
11343
|
-
updateBusinessAutomationEdgeItem(item, edge, pathData, source, target, theme, isReferenceEdge, isSelected, isRelationHighlighted, hitPointerEvents);
|
|
11410
|
+
updateBusinessAutomationEdgeItem(item, edge, pathData, source, target, theme, isReferenceEdge, isSelected, isRelationHighlighted, hitPointerEvents, route.points);
|
|
11344
11411
|
liveEdgeIds.add(edgeId);
|
|
11345
11412
|
}
|
|
11346
11413
|
|
package/wwwroot/_framework/{MindExecution.Core.2r5s0vx16i.dll → MindExecution.Core.zs4n1f9hjc.dll}
RENAMED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/wwwroot/_framework/{MindExecution.Web.9bmh8f8s3k.dll → MindExecution.Web.bzuaz35jv0.dll}
RENAMED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"mainAssemblyName": "MindExecution.Web",
|
|
3
3
|
"resources": {
|
|
4
|
-
"hash": "sha256-
|
|
4
|
+
"hash": "sha256-VyYJMbhTNysenfG7hYUM60kwM/91meEc0+JAIXAd4MA=",
|
|
5
5
|
"fingerprinting": {
|
|
6
6
|
"Google.Protobuf.9h59ukbel7.dll": "Google.Protobuf.dll",
|
|
7
7
|
"Markdig.d1j7v41cl1.dll": "Markdig.dll",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"System.Collections.Immutable.ap9596utv5.dll": "System.Collections.Immutable.dll",
|
|
62
62
|
"System.Collections.NonGeneric.npjkaz40oc.dll": "System.Collections.NonGeneric.dll",
|
|
63
63
|
"System.Collections.Specialized.ugkjbs6p02.dll": "System.Collections.Specialized.dll",
|
|
64
|
-
"System.Collections.
|
|
64
|
+
"System.Collections.3iuoxbe8my.dll": "System.Collections.dll",
|
|
65
65
|
"System.ComponentModel.Annotations.clwo0z2oyu.dll": "System.ComponentModel.Annotations.dll",
|
|
66
66
|
"System.ComponentModel.Primitives.end4v0xe2c.dll": "System.ComponentModel.Primitives.dll",
|
|
67
67
|
"System.ComponentModel.TypeConverter.tgtp5sm4iv.dll": "System.ComponentModel.TypeConverter.dll",
|
|
@@ -121,19 +121,19 @@
|
|
|
121
121
|
"System.Xml.XDocument.sn51jas17n.dll": "System.Xml.XDocument.dll",
|
|
122
122
|
"System.brmz7yk5qh.dll": "System.dll",
|
|
123
123
|
"netstandard.b50t77veor.dll": "netstandard.dll",
|
|
124
|
-
"System.Private.CoreLib.
|
|
125
|
-
"MindExecution.Core.
|
|
126
|
-
"MindExecution.Kernel.
|
|
127
|
-
"MindExecution.Plugins.Admin.
|
|
128
|
-
"MindExecution.Plugins.Business.
|
|
129
|
-
"MindExecution.Plugins.Concept.
|
|
130
|
-
"MindExecution.Plugins.Directory.
|
|
131
|
-
"MindExecution.Plugins.PlanMaster.
|
|
132
|
-
"MindExecution.Plugins.YouTube.
|
|
133
|
-
"MindExecution.Shared.
|
|
134
|
-
"MindExecution.Web.
|
|
124
|
+
"System.Private.CoreLib.7s8wte759y.dll": "System.Private.CoreLib.dll",
|
|
125
|
+
"MindExecution.Core.zs4n1f9hjc.dll": "MindExecution.Core.dll",
|
|
126
|
+
"MindExecution.Kernel.l9idvg7mp7.dll": "MindExecution.Kernel.dll",
|
|
127
|
+
"MindExecution.Plugins.Admin.l37qx5d8zi.dll": "MindExecution.Plugins.Admin.dll",
|
|
128
|
+
"MindExecution.Plugins.Business.d7b282yazn.dll": "MindExecution.Plugins.Business.dll",
|
|
129
|
+
"MindExecution.Plugins.Concept.iw98n0qz5k.dll": "MindExecution.Plugins.Concept.dll",
|
|
130
|
+
"MindExecution.Plugins.Directory.cqgn6pa8di.dll": "MindExecution.Plugins.Directory.dll",
|
|
131
|
+
"MindExecution.Plugins.PlanMaster.j8xoa8nl57.dll": "MindExecution.Plugins.PlanMaster.dll",
|
|
132
|
+
"MindExecution.Plugins.YouTube.zvpzk7om4z.dll": "MindExecution.Plugins.YouTube.dll",
|
|
133
|
+
"MindExecution.Shared.ovot7q606x.dll": "MindExecution.Shared.dll",
|
|
134
|
+
"MindExecution.Web.bzuaz35jv0.dll": "MindExecution.Web.dll",
|
|
135
135
|
"dotnet.native.566r55w3xu.js": "dotnet.native.js",
|
|
136
|
-
"dotnet.native.
|
|
136
|
+
"dotnet.native.60hhmnxyoo.wasm": "dotnet.native.wasm",
|
|
137
137
|
"dotnet.js": "dotnet.js",
|
|
138
138
|
"dotnet.runtime.opaiwunc3t.js": "dotnet.runtime.js",
|
|
139
139
|
"icudt_CJK.tjcz0u77k5.dat": "icudt_CJK.dat",
|
|
@@ -147,7 +147,7 @@
|
|
|
147
147
|
"dotnet.runtime.opaiwunc3t.js": "sha256-vM4cfmuAtxs/dLoxiTCzPyPCyNkwOJu14cp6lXv3Sak="
|
|
148
148
|
},
|
|
149
149
|
"wasmNative": {
|
|
150
|
-
"dotnet.native.
|
|
150
|
+
"dotnet.native.60hhmnxyoo.wasm": "sha256-VpLSM7+jVkgAxK0IdGVTMs1H8WAqeTX3Qqjhf85yP0s="
|
|
151
151
|
},
|
|
152
152
|
"icu": {
|
|
153
153
|
"icudt_CJK.tjcz0u77k5.dat": "sha256-SZLtQnRc0JkwqHab0VUVP7T3uBPSeYzxzDnpxPpUnHk=",
|
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
},
|
|
157
157
|
"coreAssembly": {
|
|
158
158
|
"System.Runtime.InteropServices.JavaScript.pn2wvizzet.dll": "sha256-dczkyi5P7nETlP7roYWNE0BobJPm6wyt7Bc+ZhBu3NA=",
|
|
159
|
-
"System.Private.CoreLib.
|
|
159
|
+
"System.Private.CoreLib.7s8wte759y.dll": "sha256-iSaryfzFI9zYnC5XopFpIBHr1sej8SGOWduSn1XMmvs="
|
|
160
160
|
},
|
|
161
161
|
"assembly": {
|
|
162
162
|
"Google.Protobuf.9h59ukbel7.dll": "sha256-A541k1abRTWr6MqmCXfGDYcKHirypJS19mzPQu3lJt0=",
|
|
@@ -217,7 +217,7 @@
|
|
|
217
217
|
"System.Collections.Immutable.ap9596utv5.dll": "sha256-op5xSkGyOSKVhFHn5U0j7SiJ3WEPLqA02/ss1NKf2Yg=",
|
|
218
218
|
"System.Collections.NonGeneric.npjkaz40oc.dll": "sha256-y5bX6NSbxA8o7EJ9C0vujUNU93Wd2UhdpA5+C8WpRPY=",
|
|
219
219
|
"System.Collections.Specialized.ugkjbs6p02.dll": "sha256-opanE88Yp6SrsrXZ9LaqM1diY8Q0jMrG3jvYM8v3Rao=",
|
|
220
|
-
"System.Collections.
|
|
220
|
+
"System.Collections.3iuoxbe8my.dll": "sha256-a103KEA3xZ0tBaSi99B7VXuEscpr6RMGe1/eFNuz670=",
|
|
221
221
|
"System.ComponentModel.Annotations.clwo0z2oyu.dll": "sha256-ALmLuW4qrS6x9RlN/Gl2e3DeAW9Ms8T9YcuoATYejvc=",
|
|
222
222
|
"System.ComponentModel.Primitives.end4v0xe2c.dll": "sha256-Gi1I/XBckUQXoJLoNNMmz5spL9eqeCkS/D1vYEgV57g=",
|
|
223
223
|
"System.ComponentModel.TypeConverter.tgtp5sm4iv.dll": "sha256-bdYu+4aR6MdkA7o/05m1kwDrWA4dxqHs1kRme5Xna24=",
|
|
@@ -276,18 +276,18 @@
|
|
|
276
276
|
"System.Xml.XDocument.sn51jas17n.dll": "sha256-GNI2kFgFmPTwzuzwUn8gxK+AzGLUWRJFdg9JzIbrybQ=",
|
|
277
277
|
"System.brmz7yk5qh.dll": "sha256-CfM2miyj1KHApFmqMdLYWio3S/jrdON2pW9Xr2nTwlo=",
|
|
278
278
|
"netstandard.b50t77veor.dll": "sha256-//jQGOXjb8ET8WtXgOJrAxLx6E7zDJ5RjRRutwkvmxo=",
|
|
279
|
-
"MindExecution.Core.
|
|
280
|
-
"MindExecution.Kernel.
|
|
281
|
-
"MindExecution.Plugins.Business.
|
|
282
|
-
"MindExecution.Plugins.Concept.
|
|
283
|
-
"MindExecution.Plugins.PlanMaster.
|
|
284
|
-
"MindExecution.Shared.
|
|
285
|
-
"MindExecution.Web.
|
|
279
|
+
"MindExecution.Core.zs4n1f9hjc.dll": "sha256-7XrZrL5PkRnemA1LjFguxgE7rqR8wOLZXdACUZG0MWg=",
|
|
280
|
+
"MindExecution.Kernel.l9idvg7mp7.dll": "sha256-uUzGo7hkUYV9pS1KkxLa5+9cFsVlHBGjV/9K0NYwl8Y=",
|
|
281
|
+
"MindExecution.Plugins.Business.d7b282yazn.dll": "sha256-x2oOQwLMyVaZxKffXxSG3RCoRjXlINsX90AHK9sLqQk=",
|
|
282
|
+
"MindExecution.Plugins.Concept.iw98n0qz5k.dll": "sha256-3kSdSqvBJAqTuy//MpLkJbupPx0hTSS3nL7nmpvyZFs=",
|
|
283
|
+
"MindExecution.Plugins.PlanMaster.j8xoa8nl57.dll": "sha256-Q9g9/Xs3dhJT+2RVAXb5ZoCT0ep5DeXYPy/8W5TWtvY=",
|
|
284
|
+
"MindExecution.Shared.ovot7q606x.dll": "sha256-zG0OUiZmgQ3P0BbT/fTv5PLjerpbYsHPyYB4qYl7l00=",
|
|
285
|
+
"MindExecution.Web.bzuaz35jv0.dll": "sha256-V7qhdSCSM+AG31Pc8swykgZwg1EN4Agz4VA/kCma+98="
|
|
286
286
|
},
|
|
287
287
|
"lazyAssembly": {
|
|
288
|
-
"MindExecution.Plugins.Admin.
|
|
289
|
-
"MindExecution.Plugins.Directory.
|
|
290
|
-
"MindExecution.Plugins.YouTube.
|
|
288
|
+
"MindExecution.Plugins.Admin.l37qx5d8zi.dll": "sha256-cWsGhcCLF1k1nJxbJosjPxO4RwkkmEkW+SwPRqnIWhM=",
|
|
289
|
+
"MindExecution.Plugins.Directory.cqgn6pa8di.dll": "sha256-dB6SrNy6adA7R6ubKq0YDreLSzAA2ws0m13aFP/wWVc=",
|
|
290
|
+
"MindExecution.Plugins.YouTube.zvpzk7om4z.dll": "sha256-z31H/4EKYUcn0Ev09Yd1r9F9j6NvemCmjQzZhVHuehY="
|
|
291
291
|
}
|
|
292
292
|
},
|
|
293
293
|
"cacheBootResources": true,
|
|
Binary file
|
package/wwwroot/index.html
CHANGED
|
@@ -614,7 +614,7 @@
|
|
|
614
614
|
}
|
|
615
615
|
|
|
616
616
|
const base = '_content/MindExecution.Shared/js/';
|
|
617
|
-
const scriptVersion = '20260824-
|
|
617
|
+
const scriptVersion = '20260824-compact-organic-v3-v986';
|
|
618
618
|
const scriptUrl = (script) => `${base}${script}?v=${scriptVersion}`;
|
|
619
619
|
console.log(`[Script Loader] Shared JS version: ${scriptVersion}`);
|
|
620
620
|
const criticalScripts = [
|
|
@@ -632,6 +632,7 @@
|
|
|
632
632
|
'mind-map-remote-codecs.js',
|
|
633
633
|
'mind-map-css3d-hotpath.js',
|
|
634
634
|
'mind-map-image-policy.js',
|
|
635
|
+
'mind-map-automation-edge-routing.js',
|
|
635
636
|
'mind-map-automation-edge-motion.js',
|
|
636
637
|
'mind-map-css3d-manager.js',
|
|
637
638
|
'mind-map-object-manager.js',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
self.assetsManifest = {
|
|
2
|
-
"version": "
|
|
2
|
+
"version": "Xc2iV1/U",
|
|
3
3
|
"assets": [
|
|
4
4
|
{
|
|
5
5
|
"hash": "sha256-+CSYMcqLNTsq3VnH11jgYyOCCdxvHzL74CBmo4sCmMU=",
|
|
@@ -82,9 +82,13 @@ self.assetsManifest = {
|
|
|
82
82
|
"url": "_content/MindExecution.Shared/js/mind-map-animated-image-preview.js"
|
|
83
83
|
},
|
|
84
84
|
{
|
|
85
|
-
"hash": "sha256-
|
|
85
|
+
"hash": "sha256-aBb3Ws6aKr8HoqdvMWhlFcTioAtGCuev1ciwVTsGvWI=",
|
|
86
86
|
"url": "_content/MindExecution.Shared/js/mind-map-automation-edge-motion.js"
|
|
87
87
|
},
|
|
88
|
+
{
|
|
89
|
+
"hash": "sha256-3Eq/7KjgDLLpaVaYN6QORrPEMEnSvAov7PpMsVC9r0A=",
|
|
90
|
+
"url": "_content/MindExecution.Shared/js/mind-map-automation-edge-routing.js"
|
|
91
|
+
},
|
|
88
92
|
{
|
|
89
93
|
"hash": "sha256-W/h4gC38IZn54pM6q++JJFSbDBLokscPLSNvh3xMFpw=",
|
|
90
94
|
"url": "_content/MindExecution.Shared/js/mind-map-board-render-ownership.js"
|
|
@@ -102,7 +106,7 @@ self.assetsManifest = {
|
|
|
102
106
|
"url": "_content/MindExecution.Shared/js/mind-map-css3d-hotpath.js"
|
|
103
107
|
},
|
|
104
108
|
{
|
|
105
|
-
"hash": "sha256-
|
|
109
|
+
"hash": "sha256-agt+cyYP3mh+j+38obj+qziQPfOltovg2kWJUndOJXI=",
|
|
106
110
|
"url": "_content/MindExecution.Shared/js/mind-map-css3d-manager.js"
|
|
107
111
|
},
|
|
108
112
|
{
|
|
@@ -446,44 +450,44 @@ self.assetsManifest = {
|
|
|
446
450
|
"url": "_framework/MimeMapping.og9ys58ylm.dll"
|
|
447
451
|
},
|
|
448
452
|
{
|
|
449
|
-
"hash": "sha256-
|
|
450
|
-
"url": "_framework/MindExecution.Core.
|
|
453
|
+
"hash": "sha256-7XrZrL5PkRnemA1LjFguxgE7rqR8wOLZXdACUZG0MWg=",
|
|
454
|
+
"url": "_framework/MindExecution.Core.zs4n1f9hjc.dll"
|
|
451
455
|
},
|
|
452
456
|
{
|
|
453
|
-
"hash": "sha256-
|
|
454
|
-
"url": "_framework/MindExecution.Kernel.
|
|
457
|
+
"hash": "sha256-uUzGo7hkUYV9pS1KkxLa5+9cFsVlHBGjV/9K0NYwl8Y=",
|
|
458
|
+
"url": "_framework/MindExecution.Kernel.l9idvg7mp7.dll"
|
|
455
459
|
},
|
|
456
460
|
{
|
|
457
|
-
"hash": "sha256-
|
|
458
|
-
"url": "_framework/MindExecution.Plugins.Admin.
|
|
461
|
+
"hash": "sha256-cWsGhcCLF1k1nJxbJosjPxO4RwkkmEkW+SwPRqnIWhM=",
|
|
462
|
+
"url": "_framework/MindExecution.Plugins.Admin.l37qx5d8zi.dll"
|
|
459
463
|
},
|
|
460
464
|
{
|
|
461
|
-
"hash": "sha256-
|
|
462
|
-
"url": "_framework/MindExecution.Plugins.Business.
|
|
465
|
+
"hash": "sha256-x2oOQwLMyVaZxKffXxSG3RCoRjXlINsX90AHK9sLqQk=",
|
|
466
|
+
"url": "_framework/MindExecution.Plugins.Business.d7b282yazn.dll"
|
|
463
467
|
},
|
|
464
468
|
{
|
|
465
|
-
"hash": "sha256-
|
|
466
|
-
"url": "_framework/MindExecution.Plugins.Concept.
|
|
469
|
+
"hash": "sha256-3kSdSqvBJAqTuy//MpLkJbupPx0hTSS3nL7nmpvyZFs=",
|
|
470
|
+
"url": "_framework/MindExecution.Plugins.Concept.iw98n0qz5k.dll"
|
|
467
471
|
},
|
|
468
472
|
{
|
|
469
|
-
"hash": "sha256-
|
|
470
|
-
"url": "_framework/MindExecution.Plugins.Directory.
|
|
473
|
+
"hash": "sha256-dB6SrNy6adA7R6ubKq0YDreLSzAA2ws0m13aFP/wWVc=",
|
|
474
|
+
"url": "_framework/MindExecution.Plugins.Directory.cqgn6pa8di.dll"
|
|
471
475
|
},
|
|
472
476
|
{
|
|
473
|
-
"hash": "sha256-
|
|
474
|
-
"url": "_framework/MindExecution.Plugins.PlanMaster.
|
|
477
|
+
"hash": "sha256-Q9g9/Xs3dhJT+2RVAXb5ZoCT0ep5DeXYPy/8W5TWtvY=",
|
|
478
|
+
"url": "_framework/MindExecution.Plugins.PlanMaster.j8xoa8nl57.dll"
|
|
475
479
|
},
|
|
476
480
|
{
|
|
477
|
-
"hash": "sha256-
|
|
478
|
-
"url": "_framework/MindExecution.Plugins.YouTube.
|
|
481
|
+
"hash": "sha256-z31H/4EKYUcn0Ev09Yd1r9F9j6NvemCmjQzZhVHuehY=",
|
|
482
|
+
"url": "_framework/MindExecution.Plugins.YouTube.zvpzk7om4z.dll"
|
|
479
483
|
},
|
|
480
484
|
{
|
|
481
|
-
"hash": "sha256-
|
|
482
|
-
"url": "_framework/MindExecution.Shared.
|
|
485
|
+
"hash": "sha256-zG0OUiZmgQ3P0BbT/fTv5PLjerpbYsHPyYB4qYl7l00=",
|
|
486
|
+
"url": "_framework/MindExecution.Shared.ovot7q606x.dll"
|
|
483
487
|
},
|
|
484
488
|
{
|
|
485
|
-
"hash": "sha256-
|
|
486
|
-
"url": "_framework/MindExecution.Web.
|
|
489
|
+
"hash": "sha256-V7qhdSCSM+AG31Pc8swykgZwg1EN4Agz4VA/kCma+98=",
|
|
490
|
+
"url": "_framework/MindExecution.Web.bzuaz35jv0.dll"
|
|
487
491
|
},
|
|
488
492
|
{
|
|
489
493
|
"hash": "sha256-IsZJ91/OW+fHzNqIgEc7Y072ns8z9dGritiSyvR9Wgc=",
|
|
@@ -529,6 +533,10 @@ self.assetsManifest = {
|
|
|
529
533
|
"hash": "sha256-Kon62RCQ4pqGTawYsp9LgAVwT/66ptahk8JIgsdBQvk=",
|
|
530
534
|
"url": "_framework/Supabase.azmaw5pgcz.dll"
|
|
531
535
|
},
|
|
536
|
+
{
|
|
537
|
+
"hash": "sha256-a103KEA3xZ0tBaSi99B7VXuEscpr6RMGe1/eFNuz670=",
|
|
538
|
+
"url": "_framework/System.Collections.3iuoxbe8my.dll"
|
|
539
|
+
},
|
|
532
540
|
{
|
|
533
541
|
"hash": "sha256-PytlRTU4Hx5iWOPXNkXYQIt24hVsUppWY5vgpx8PTIc=",
|
|
534
542
|
"url": "_framework/System.Collections.Concurrent.vow3rm1dku.dll"
|
|
@@ -545,10 +553,6 @@ self.assetsManifest = {
|
|
|
545
553
|
"hash": "sha256-opanE88Yp6SrsrXZ9LaqM1diY8Q0jMrG3jvYM8v3Rao=",
|
|
546
554
|
"url": "_framework/System.Collections.Specialized.ugkjbs6p02.dll"
|
|
547
555
|
},
|
|
548
|
-
{
|
|
549
|
-
"hash": "sha256-ZbcBWmgkYTGdeU2GzVkRs8SERVp8OCUrNQFKiPseGb0=",
|
|
550
|
-
"url": "_framework/System.Collections.zyvbaq6mpd.dll"
|
|
551
|
-
},
|
|
552
556
|
{
|
|
553
557
|
"hash": "sha256-ALmLuW4qrS6x9RlN/Gl2e3DeAW9Ms8T9YcuoATYejvc=",
|
|
554
558
|
"url": "_framework/System.ComponentModel.Annotations.clwo0z2oyu.dll"
|
|
@@ -670,8 +674,8 @@ self.assetsManifest = {
|
|
|
670
674
|
"url": "_framework/System.ObjectModel.yct1gdirzf.dll"
|
|
671
675
|
},
|
|
672
676
|
{
|
|
673
|
-
"hash": "sha256-
|
|
674
|
-
"url": "_framework/System.Private.CoreLib.
|
|
677
|
+
"hash": "sha256-iSaryfzFI9zYnC5XopFpIBHr1sej8SGOWduSn1XMmvs=",
|
|
678
|
+
"url": "_framework/System.Private.CoreLib.7s8wte759y.dll"
|
|
675
679
|
},
|
|
676
680
|
{
|
|
677
681
|
"hash": "sha256-MB8kD4MSWVtneMtZ06c8cKXJCO/EBXrSY3H535KTU9o=",
|
|
@@ -802,7 +806,7 @@ self.assetsManifest = {
|
|
|
802
806
|
"url": "_framework/Websocket.Client.vapounvmnl.dll"
|
|
803
807
|
},
|
|
804
808
|
{
|
|
805
|
-
"hash": "sha256-
|
|
809
|
+
"hash": "sha256-PhUrI4I2+YbbML6TFXABhXBOVOkTCkSjSyLFEU3MV6w=",
|
|
806
810
|
"url": "_framework/blazor.boot.json"
|
|
807
811
|
},
|
|
808
812
|
{
|
|
@@ -818,8 +822,8 @@ self.assetsManifest = {
|
|
|
818
822
|
"url": "_framework/dotnet.native.566r55w3xu.js"
|
|
819
823
|
},
|
|
820
824
|
{
|
|
821
|
-
"hash": "sha256-
|
|
822
|
-
"url": "_framework/dotnet.native.
|
|
825
|
+
"hash": "sha256-VpLSM7+jVkgAxK0IdGVTMs1H8WAqeTX3Qqjhf85yP0s=",
|
|
826
|
+
"url": "_framework/dotnet.native.60hhmnxyoo.wasm"
|
|
823
827
|
},
|
|
824
828
|
{
|
|
825
829
|
"hash": "sha256-vM4cfmuAtxs/dLoxiTCzPyPCyNkwOJu14cp6lXv3Sak=",
|
|
@@ -878,7 +882,7 @@ self.assetsManifest = {
|
|
|
878
882
|
"url": "icon-512.png"
|
|
879
883
|
},
|
|
880
884
|
{
|
|
881
|
-
"hash": "sha256
|
|
885
|
+
"hash": "sha256-/4FO6qWSOiPW1lArHLy42ItKBPAa8YEu4eEs058CFJs=",
|
|
882
886
|
"url": "index.html"
|
|
883
887
|
},
|
|
884
888
|
{
|
|
Binary file
|