Journey functionality

This commit is contained in:
space-nuko
2023-06-02 22:28:18 -05:00
parent 4f237d01a5
commit ab6266704c
11 changed files with 537 additions and 56 deletions

View File

@@ -20,6 +20,8 @@
"devDependencies": {
"@floating-ui/core": "^1.2.6",
"@floating-ui/dom": "^1.2.8",
"@types/cytoscape": "^3.19.9",
"@types/dompurify": "^3.0.2",
"@zerodevx/svelte-toast": "^0.9.3",
"eslint": "^8.37.0",
"eslint-config-prettier": "^8.8.0",
@@ -34,8 +36,6 @@
"svelte-check": "^3.2.0",
"svelte-dnd-action": "^0.9.22",
"typescript": "^5.0.3",
"@types/cytoscape": "^3.19.9",
"@types/dompurify": "^3.0.2",
"vite": "^4.3.8",
"vite-plugin-glsl": "^1.1.2",
"vite-plugin-static-copy": "^0.14.0",
@@ -84,6 +84,7 @@
"csv-parse": "^5.3.10",
"cytoscape": "^3.25.0",
"cytoscape-dagre": "^2.5.0",
"deep-equal": "^2.2.1",
"dompurify": "^3.0.3",
"events": "^3.3.0",
"framework7": "^8.0.3",

286
pnpm-lock.yaml generated
View File

@@ -121,6 +121,9 @@ importers:
cytoscape-dagre:
specifier: ^2.5.0
version: 2.5.0(cytoscape@3.25.0)
deep-equal:
specifier: ^2.2.1
version: 2.2.1
dompurify:
specifier: ^3.0.3
version: 3.0.3
@@ -1372,7 +1375,6 @@ packages:
'@codemirror/language': ^6.0.0
'@codemirror/state': ^6.0.0
'@codemirror/view': ^6.0.0
'@lezer/common': ^1.0.0
dependencies:
'@codemirror/language': 6.6.0
'@codemirror/state': 6.2.0
@@ -2715,6 +2717,13 @@ packages:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
dev: true
/array-buffer-byte-length@1.0.0:
resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==}
dependencies:
call-bind: 1.0.2
is-array-buffer: 3.0.2
dev: false
/array-union@2.1.0:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'}
@@ -2765,6 +2774,11 @@ packages:
postcss-value-parser: 4.2.0
dev: true
/available-typed-arrays@1.0.5:
resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
engines: {node: '>= 0.4'}
dev: false
/aws-sign2@0.7.0:
resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==}
dev: false
@@ -3131,8 +3145,6 @@ packages:
'@codemirror/search': 6.4.0
'@codemirror/state': 6.2.0
'@codemirror/view': 6.11.0
transitivePeerDependencies:
- '@lezer/common'
dev: false
/codemirror@6.0.1(@lezer/common@1.0.2):
@@ -3576,6 +3588,29 @@ packages:
dependencies:
type-detect: 4.0.8
/deep-equal@2.2.1:
resolution: {integrity: sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==}
dependencies:
array-buffer-byte-length: 1.0.0
call-bind: 1.0.2
es-get-iterator: 1.1.3
get-intrinsic: 1.2.0
is-arguments: 1.1.1
is-array-buffer: 3.0.2
is-date-object: 1.0.5
is-regex: 1.1.4
is-shared-array-buffer: 1.0.2
isarray: 2.0.5
object-is: 1.1.5
object-keys: 1.1.1
object.assign: 4.1.4
regexp.prototype.flags: 1.5.0
side-channel: 1.0.4
which-boxed-primitive: 1.0.2
which-collection: 1.0.1
which-typed-array: 1.1.9
dev: false
/deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
dev: true
@@ -3589,6 +3624,14 @@ packages:
engines: {node: '>=8'}
dev: true
/define-properties@1.2.0:
resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==}
engines: {node: '>= 0.4'}
dependencies:
has-property-descriptors: 1.0.0
object-keys: 1.1.1
dev: false
/delaunator@5.0.0:
resolution: {integrity: sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==}
dependencies:
@@ -3690,6 +3733,20 @@ packages:
is-arrayish: 0.2.1
dev: true
/es-get-iterator@1.1.3:
resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==}
dependencies:
call-bind: 1.0.2
get-intrinsic: 1.2.0
has-symbols: 1.0.3
is-arguments: 1.1.1
is-map: 2.0.2
is-set: 2.0.2
is-string: 1.0.7
isarray: 2.0.5
stop-iteration-iterator: 1.0.0
dev: false
/es6-promise@3.3.1:
resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==}
@@ -4295,6 +4352,12 @@ packages:
resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
dev: true
/for-each@0.3.3:
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
dependencies:
is-callable: 1.2.7
dev: false
/forever-agent@0.6.1:
resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==}
dev: false
@@ -4385,6 +4448,10 @@ packages:
/function-bind@1.1.1:
resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
/functions-have-names@1.2.3:
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
dev: false
/gensync@1.0.0-beta.2:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'}
@@ -4495,6 +4562,12 @@ packages:
resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
dev: true
/gopd@1.0.1:
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
dependencies:
get-intrinsic: 1.2.0
dev: false
/graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
@@ -4533,6 +4606,10 @@ packages:
har-schema: 2.0.0
dev: false
/has-bigints@1.0.2:
resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
dev: false
/has-flag@3.0.0:
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
engines: {node: '>=4'}
@@ -4543,11 +4620,24 @@ packages:
engines: {node: '>=8'}
dev: true
/has-property-descriptors@1.0.0:
resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==}
dependencies:
get-intrinsic: 1.2.0
dev: false
/has-symbols@1.0.3:
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
engines: {node: '>= 0.4'}
dev: false
/has-tostringtag@1.0.0:
resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==}
engines: {node: '>= 0.4'}
dependencies:
has-symbols: 1.0.3
dev: false
/has@1.0.3:
resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
engines: {node: '>= 0.4.0'}
@@ -4686,26 +4776,77 @@ packages:
/inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
/internal-slot@1.0.5:
resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==}
engines: {node: '>= 0.4'}
dependencies:
get-intrinsic: 1.2.0
has: 1.0.3
side-channel: 1.0.4
dev: false
/internmap@2.0.3:
resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
engines: {node: '>=12'}
dev: false
/is-arguments@1.1.1:
resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
has-tostringtag: 1.0.0
dev: false
/is-array-buffer@3.0.2:
resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==}
dependencies:
call-bind: 1.0.2
get-intrinsic: 1.2.0
is-typed-array: 1.1.10
dev: false
/is-arrayish@0.2.1:
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
dev: true
/is-bigint@1.0.4:
resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
dependencies:
has-bigints: 1.0.2
dev: false
/is-binary-path@2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
dependencies:
binary-extensions: 2.2.0
/is-boolean-object@1.1.2:
resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
has-tostringtag: 1.0.0
dev: false
/is-callable@1.2.7:
resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
engines: {node: '>= 0.4'}
dev: false
/is-core-module@2.12.0:
resolution: {integrity: sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==}
dependencies:
has: 1.0.3
/is-date-object@1.0.5:
resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
engines: {node: '>= 0.4'}
dependencies:
has-tostringtag: 1.0.0
dev: false
/is-docker@2.2.1:
resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==}
engines: {node: '>=8'}
@@ -4732,6 +4873,17 @@ packages:
dependencies:
is-extglob: 2.1.1
/is-map@2.0.2:
resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==}
dev: false
/is-number-object@1.0.7:
resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==}
engines: {node: '>= 0.4'}
dependencies:
has-tostringtag: 1.0.0
dev: false
/is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
@@ -4745,15 +4897,69 @@ packages:
resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
dev: true
/is-regex@1.1.4:
resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
has-tostringtag: 1.0.0
dev: false
/is-set@2.0.2:
resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==}
dev: false
/is-shared-array-buffer@1.0.2:
resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==}
dependencies:
call-bind: 1.0.2
dev: false
/is-stream@2.0.1:
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
engines: {node: '>=8'}
dev: true
/is-string@1.0.7:
resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
engines: {node: '>= 0.4'}
dependencies:
has-tostringtag: 1.0.0
dev: false
/is-symbol@1.0.4:
resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==}
engines: {node: '>= 0.4'}
dependencies:
has-symbols: 1.0.3
dev: false
/is-typed-array@1.1.10:
resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==}
engines: {node: '>= 0.4'}
dependencies:
available-typed-arrays: 1.0.5
call-bind: 1.0.2
for-each: 0.3.3
gopd: 1.0.1
has-tostringtag: 1.0.0
dev: false
/is-typedarray@1.0.0:
resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==}
dev: false
/is-weakmap@2.0.1:
resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==}
dev: false
/is-weakset@2.0.2:
resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==}
dependencies:
call-bind: 1.0.2
get-intrinsic: 1.2.0
dev: false
/is-wsl@2.2.0:
resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==}
engines: {node: '>=8'}
@@ -4765,6 +4971,10 @@ packages:
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
dev: false
/isarray@2.0.5:
resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
dev: false
/isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
dev: true
@@ -5763,6 +5973,29 @@ packages:
resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
dev: false
/object-is@1.1.5:
resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
define-properties: 1.2.0
dev: false
/object-keys@1.1.1:
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
engines: {node: '>= 0.4'}
dev: false
/object.assign@4.1.4:
resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
define-properties: 1.2.0
has-symbols: 1.0.3
object-keys: 1.1.1
dev: false
/once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
@@ -6182,6 +6415,15 @@ packages:
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
dev: false
/regexp.prototype.flags@1.5.0:
resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
define-properties: 1.2.0
functions-have-names: 1.2.3
dev: false
/request@2.88.2:
resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==}
engines: {node: '>= 6'}
@@ -6554,6 +6796,13 @@ packages:
/std-env@3.3.3:
resolution: {integrity: sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg==}
/stop-iteration-iterator@1.0.0:
resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==}
engines: {node: '>= 0.4'}
dependencies:
internal-slot: 1.0.5
dev: false
/stream-transform@3.2.6:
resolution: {integrity: sha512-/pyOvaCQFqYTmrFhmMbnAEVo3SsTx1H39eUVPOtYeAgbEUc+rDo7GoP8LbHJgU83mKtzJe/7Nq/ipaAnUOHgJQ==}
dev: false
@@ -8408,6 +8657,37 @@ packages:
webidl-conversions: 3.0.1
dev: false
/which-boxed-primitive@1.0.2:
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
dependencies:
is-bigint: 1.0.4
is-boolean-object: 1.1.2
is-number-object: 1.0.7
is-string: 1.0.7
is-symbol: 1.0.4
dev: false
/which-collection@1.0.1:
resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==}
dependencies:
is-map: 2.0.2
is-set: 2.0.2
is-weakmap: 2.0.1
is-weakset: 2.0.2
dev: false
/which-typed-array@1.1.9:
resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==}
engines: {node: '>= 0.4'}
dependencies:
available-typed-arrays: 1.0.5
call-bind: 1.0.2
for-each: 0.3.3
gopd: 1.0.1
has-tostringtag: 1.0.0
is-typed-array: 1.1.10
dev: false
/which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}

View File

@@ -7,11 +7,12 @@
import type ComfyApp from './ComfyApp';
import type { ComfyBoxWorkflow } from '$lib/stores/workflowState';
import workflowState from '$lib/stores/workflowState';
import type { WritableJourneyStateStore } from '$lib/stores/journeyStates';
import { calculateWorkflowParamsPatch, resolvePatch, type JourneyPatchNode, type WritableJourneyStateStore } from '$lib/stores/journeyStates';
import JourneyRenderer from './JourneyRenderer.svelte';
import { Plus } from "svelte-bootstrap-icons";
import { getWorkflowRestoreParams, getWorkflowRestoreParamsFromWorkflow } from '$lib/restoreParameters';
import notify from '$lib/notify';
import selectionState from '$lib/stores/selectionState';
export let app: ComfyApp;
@@ -27,20 +28,86 @@
return;
}
const nodes = Array.from(journey.iterateBreadthFirst());
let parent = null;
if (nodes.length > 0)
parent = nodes[nodes.length - 1]
const workflowParams = getWorkflowRestoreParamsFromWorkflow(workflow)
journey.addNode(workflowParams, parent?.id);
const activeNode = journey.getActiveNode();
let journeyNode
if (activeNode == null) {
// add root node
if ($journey.root != null) {
return;
}
journeyNode = journey.addNode(workflowParams, null);
notify("Pushed a new base workflow state.", { type: "info" })
}
else {
// add patch node
const patch = calculateWorkflowParamsPatch(activeNode, workflowParams);
const patchedCount = Object.keys(patch).length;
if (patchedCount === 0) {
notify("No changes were made to active parameters yet.", { type: "warning" })
return;
}
journeyNode = journey.addNode(patch, activeNode);
notify(`Pushed new state with ${patchedCount} changes.`, { type: "info" })
}
if (journeyNode != null) {
journey.selectNode(journeyNode);
}
}
function onSelectNode(e: CustomEvent<{ cyto: cytoscape.Core, node: cytoscape.NodeSingular }>) {
const { node } = e.detail;
const id = node.id();
const journeyNode = $journey.nodesByID[id];
if (journeyNode == null) {
console.error("[ComfyJourneyView] Missing journey node!", id)
return;
}
const patch = resolvePatch(journeyNode);
// ensure reactive state is updated
workflow.applyParamsPatch(patch);
$workflowState = $workflowState
}
function onHoverNode(e: CustomEvent<{ cyto: cytoscape.Core, node: cytoscape.NodeSingular }>) {
const { node } = e.detail;
const id = node.id();
const journeyNode = $journey.nodesByID[id];
if (journeyNode == null) {
console.error("[ComfyJourneyView] Missing journey node!", id)
return;
}
if (journeyNode.type === "patch") {
$selectionState.currentPatchHoveredNodes = new Set(Object.keys((journeyNode as JourneyPatchNode).patch))
}
else {
$selectionState.currentPatchHoveredNodes = new Set();
}
}
function onHoverNodeOut(e: CustomEvent<{ cyto: cytoscape.Core, node: cytoscape.NodeSingular }>) {
$selectionState.currentPatchHoveredNodes = new Set();
}
</script>
<div class="journey-view">
<JourneyRenderer {workflow} {journey} />
<JourneyRenderer {workflow} {journey}
on:select_node={onSelectNode}
on:hover_node={onHoverNode}
on:hover_node_out={onHoverNodeOut}
/>
<div class="bottom">
<button class="mode-button ternary"
title={"Add new"}
disabled={$journey.activeNodeID === null && $journey.root !== null}
on:click={doAdd}>
<Plus width="100%" height="100%" />
</button>

View File

@@ -4,34 +4,19 @@
import { get } from 'svelte/store';
import Graph from './graph/Graph.svelte'
import type { NodeDataDefinition, EdgeDataDefinition } from 'cytoscape';
import { createEventDispatcher } from "svelte";
import selectionState from '$lib/stores/selectionState';
export let workflow: ComfyBoxWorkflow | null = null
export let journey: WritableJourneyStateStore | null = null
//
// const nodes: NodeDataDefinition[] = [
// //{ id: 'N1', label: 'Start' },
// //{ id: 'N2', label: '4' },
// //{ id: 'N4', label: '8' },
// //{ id: 'N5', label: '15' },
// //{ id: 'N3', label: '16' },
// //{ id: 'N6', label: '23' },
// //{ id: 'N7', label: '42' },
// //{ id: 'N8', label: 'End' }
// ]
//
// const edges: EdgeDataDefinition[] = [
// //{ id: 'E1', source: 'N1', target: 'N2' },
// //{ id: 'E2', source: 'N2', target: 'N3' },
// //{ id: 'E3', source: 'N3', target: 'N6' },
// //{ id: 'E4', source: 'N2', target: 'N4' },
// //{ id: 'E5', source: 'N4', target: 'N5' },
// //{ id: 'E6', source: 'N5', target: 'N4', label: '2' },
// //{ id: 'E7', source: 'N5', target: 'N6' },
// //{ id: 'E8', source: 'N6', target: 'N7' },
// //{ id: 'E9', source: 'N7', target: 'N7', label: '3' },
// //{ id: 'E10', source: 'N7', target: 'N8' }
// ]
const dispatch = createEventDispatcher<{
select_node: { cyto: cytoscape.Core, node: cytoscape.NodeSingular };
hover_node: { cyto: cytoscape.Core, node: cytoscape.NodeSingular };
hover_node_out: { cyto: cytoscape.Core, node: cytoscape.NodeSingular };
}>();
let lastSelected = null;
let lastVersion = -1;
@@ -48,6 +33,7 @@
}
const journeyState = get(journey);
lastSelected = journeyState.activeNodeID;
const nodes: NodeDataDefinition[] = []
const edges: EdgeDataDefinition[] = []
@@ -86,17 +72,48 @@
function onNodeSelected(e: cytoscape.InputEventObject) {
console.warn("SELECT", e)
const node = e.target;
const node = e.target as cytoscape.NodeSingular;
journey.selectNode(node.id());
e.cy.animate({
center: { eles: node }
}, {
duration: 400,
easing: "ease-in-out-quad"
});
e.cy.center(node)
dispatch("select_node", { cyto: e.cy, node })
}
function onNodeHovered(e: cytoscape.InputEventObject) {
const node = e.target as cytoscape.NodeSingular;
dispatch("hover_node", { cyto: e.cy, node })
}
function onNodeHoveredOut(e: cytoscape.InputEventObject) {
const node = e.target as cytoscape.NodeSingular;
dispatch("hover_node_out", { cyto: e.cy, node })
}
function onRebuilt(e: CustomEvent<{cyto: cytoscape.Core}>) {
const { cyto } = e.detail;
for (const node of cyto.nodes().components()) {
if (node.id() === lastSelected) {
// why doesn't passing `selected` work in the ctor?
node.select();
}
}
$selectionState.currentPatchHoveredNodes = new Set()
cyto.nodes()
.lock()
.on("select", onNodeSelected)
.on("mouseover", onNodeHovered)
.on("mouseout", onNodeHoveredOut)
const nodes = Array.from(journey.iterateBreadthFirst());
if (nodes.length > 0) {

View File

@@ -84,6 +84,7 @@
class:edit={edit}
class:hovered
class:selected
class:patch-affected={$selectionState.currentPatchHoveredNodes.has(widget.node.id)}
class:is-executing={$queueState.runningNodeID && $queueState.runningNodeID == widget.node.id}
class:hidden={hidden}
>
@@ -112,6 +113,10 @@
&.selected {
background: var(--comfy-widget-selected-background-fill);
}
&.patch-affected {
background: var(--secondary-500);
}
}
.is-executing {

View File

@@ -30,9 +30,6 @@
cyInstance = null;
}
let _nodes: any[];
let _edges: any[];
function rebuildGraph() {
cytoscape.use(dagre)
@@ -41,6 +38,7 @@
style: GraphStyles,
wheelSensitivity: 0.1,
maxZoom: 1,
minZoom: 0.5,
})
cyInstance.on("add", () => {
@@ -74,8 +72,7 @@
let cyInstance: cytoscape.Core = null
</script>
<div class="cy-graph" {style} bind:this={refElement}>
</div>
<div class="cy-graph" {style} bind:this={refElement} />
<style lang="scss">
.cy-graph {

View File

@@ -1,10 +1,11 @@
import { get, writable } from 'svelte/store';
import type { Readable, Writable } from 'svelte/store';
import type { DragItemID, IDragItem } from './layoutStates';
import type { LGraphNode, NodeID, UUID } from '@litegraph-ts/core';
import { LiteGraph, type LGraphNode, type NodeID, type UUID } from '@litegraph-ts/core';
import type { SerializedAppState } from '$lib/components/ComfyApp';
import type { RestoreParamTargets, RestoreParamWorkflowNodeTargets } from '$lib/restoreParameters';
import { v4 as uuidv4 } from "uuid";
import deepEqual from "deep-equal";
export type JourneyNodeType = "root" | "patch";
@@ -55,7 +56,7 @@ function diffParams(base: RestoreParamWorkflowNodeTargets, updated: RestoreParam
const result = {}
for (const [k, v] of Object.entries(updated)) {
if (!(k in base) || base[k].finalValue !== v) {
if (!(k in base) || !deepEqual(base[k].finalValue, v.finalValue, { strict: true })) {
result[k] = v
}
}
@@ -63,7 +64,7 @@ function diffParams(base: RestoreParamWorkflowNodeTargets, updated: RestoreParam
return result;
}
function calculatePatch(parent: JourneyNode, newParams: RestoreParamWorkflowNodeTargets): RestoreParamWorkflowNodeTargets {
export function calculateWorkflowParamsPatch(parent: JourneyNode, newParams: RestoreParamWorkflowNodeTargets): RestoreParamWorkflowNodeTargets {
const patch = resolvePatch(parent);
const diff = diffParams(patch, newParams)
return diff;
@@ -87,8 +88,9 @@ export type JourneyState = {
type JourneyStateOps = {
clear: () => void,
addNode: (params: RestoreParamWorkflowNodeTargets, parent?: JourneyNodeID) => JourneyNode,
selectNode: (id?: JourneyNodeID) => void,
getActiveNode: () => JourneyNode | null,
addNode: (params: RestoreParamWorkflowNodeTargets, parent?: JourneyNodeID | JourneyNode) => JourneyNode,
selectNode: (id?: JourneyNodeID | JourneyNode) => void,
iterateBreadthFirst: (id?: JourneyNodeID | null) => Iterable<JourneyNode>
}
@@ -112,15 +114,28 @@ function create() {
})
}
function getActiveNode(): JourneyNode | null {
const state = get(store)
if (state.activeNodeID === null)
return null;
const active = state.nodesByID[state.activeNodeID]
if (active == null) {
console.error("[journeyStates] Active node not found in graph!", state.activeNodeID);
}
return active;
}
/*
* params: full state of widgets in the UI
* params: full state or state patch of widgets in the UI
* parent: parent node to patch against
*/
function addNode(params: RestoreParamWorkflowNodeTargets, parent?: JourneyNodeID): JourneyNode {
function addNode(params: RestoreParamWorkflowNodeTargets, parent?: JourneyNodeID | JourneyNode): JourneyNode {
let _node: JourneyRootNode | JourneyPatchNode;
store.update(s => {
let parentNode: JourneyNode | null = null
if (parent != null) {
if (typeof parent === "object")
parent = parent.id;
parentNode = s.nodesByID[parent];
if (parentNode == null) {
throw new Error(`Could not find parent node ${parent} to insert into!`)
@@ -141,7 +156,7 @@ function create() {
type: "patch",
parent: parentNode,
children: [],
patch: calculatePatch(parentNode, params)
patch: params,
}
parentNode.children.push(_node);
}
@@ -152,9 +167,12 @@ function create() {
return _node;
}
function selectNode(id?: JourneyNodeID) {
function selectNode(obj?: JourneyNodeID | JourneyNode) {
store.update(s => {
s.activeNodeID = id;
if (typeof obj === "string")
s.activeNodeID = obj;
else
s.activeNodeID = obj.id;
return s;
})
}
@@ -201,6 +219,7 @@ function create() {
return {
...store,
getActiveNode,
clear,
addNode,
selectNode,

View File

@@ -24,7 +24,12 @@ export type SelectionState = {
/*
* Currently hovered nodes.
*/
currentHoveredNodes: Set<NodeID>
currentHoveredNodes: Set<NodeID>,
/*
* Nodes affected by the patch hovered in the journey pane
*/
currentPatchHoveredNodes: Set<NodeID>
}
type SelectionStateOps = {
@@ -38,6 +43,7 @@ const store: Writable<SelectionState> = writable(
currentSelectionNodes: [],
currentHovered: new Set(),
currentHoveredNodes: new Set(),
currentPatchHoveredNodes: new Set(),
})
function clear() {
@@ -46,12 +52,13 @@ function clear() {
currentSelectionNodes: [],
currentHovered: new Set(),
currentHoveredNodes: new Set(),
currentPatchHoveredNodes: new Set(),
})
}
const uiStateStore: WritableSelectionStateStore =
const selectionStateStore: WritableSelectionStateStore =
{
...store,
clear
}
export default uiStateStore;
export default selectionStateStore;

View File

@@ -2,7 +2,7 @@ import type { SerializedGraphCanvasState } from '$lib/ComfyGraphCanvas';
import { clamp, LGraphNode, type LGraphCanvas, type NodeID, type SerializedLGraph, type UUID, LGraph, LiteGraph, type SlotType, NodeMode } from '@litegraph-ts/core';
import { get, writable } from 'svelte/store';
import type { Readable, Writable } from 'svelte/store';
import { defaultWorkflowAttributes, type SerializedLayoutState, type WritableLayoutStateStore } from './layoutStates';
import { defaultWorkflowAttributes, isComfyWidgetNode, type SerializedLayoutState, type WritableLayoutStateStore } from './layoutStates';
import ComfyGraph from '$lib/ComfyGraph';
import layoutStates from './layoutStates';
import { v4 as uuidv4 } from "uuid";
@@ -14,6 +14,7 @@ import type { ComfyBoxPromptExtraData, PromptID } from '$lib/api';
import type { ComfyAPIPromptErrorResponse, ComfyExecutionError } from '$lib/apiErrors';
import type { WritableJourneyStateStore } from './journeyState';
import journeyStates from './journeyStates';
import type { RestoreParamWorkflowNodeTargets } from '$lib/restoreParameters';
type ActiveCanvas = {
canvas: LGraphCanvas | null;
@@ -212,6 +213,21 @@ export class ComfyBoxWorkflow {
}
}
applyParamsPatch(patch: RestoreParamWorkflowNodeTargets) {
for (const [nodeId, source] of Object.entries(patch)) {
const node = this.graph.getNodeByIdRecursive(nodeId);
if (node == null) {
console.error("[applyParamsPatch] Node was missing in patch!!", nodeId, source)
continue;
}
if (!isComfyWidgetNode(node)) {
console.error("[applyParamsPatch] Node was not ComfyWidgetNode!!", nodeId, source)
continue;
}
node.setValue(source.finalValue);
}
}
/*
* Creates a workflow and layout.
*

View File

@@ -0,0 +1,71 @@
import { get } from "svelte/store";
import journeyState, { type JourneyState } from "$lib/stores/journeyState"
import { expect } from 'vitest';
import UnitTest from "../UnitTest";
import { Watch } from "@litegraph-ts/nodes-basic";
import { ComfyBoxWorkflow } from "$lib/stores/workflowState";
import { ComfyNumberNode } from "$lib/nodes/widgets";
import { LiteGraph } from "@litegraph-ts/core";
import { getWorkflowRestoreParamsFromWorkflow } from "$lib/restoreParameters";
import { calculateWorkflowParamsPatch } from "$lib/stores/journeyStates";
export default class journeyStateTests extends UnitTest {
test__patches() {
const [workflow, layoutState] = ComfyBoxWorkflow.create()
const { graph, journey } = workflow;
layoutState.initDefaultLayout() // adds 3 containers
const widget1 = LiteGraph.createNode(ComfyNumberNode);
const widget2 = LiteGraph.createNode(ComfyNumberNode);
const watch1 = LiteGraph.createNode(Watch);
const watch2 = LiteGraph.createNode(Watch);
graph.add(widget1)
graph.add(watch1)
graph.add(widget2)
graph.add(watch2)
widget1.connect(0, watch1, 0);
widget2.connect(0, watch2, 0);
widget1.setValue(0)
widget2.setValue(0)
let workflowParams = getWorkflowRestoreParamsFromWorkflow(workflow)
const root = journey.addNode(workflowParams, null);
expect(root).toEqual({
id: root.id,
type: "root",
children: [],
base: {
[widget1.id]: {
type: "workflow",
finalValue: 0,
},
[widget2.id]: {
type: "workflow",
finalValue: 0,
}
}
});
widget1.setValue(5)
workflowParams = getWorkflowRestoreParamsFromWorkflow(workflow)
const patchParams = calculateWorkflowParamsPatch(root, workflowParams)
const patch = journey.addNode(patchParams, root.id);
expect(patch).toEqual({
id: patch.id,
type: "patch",
parent: root,
children: [],
patch: {
[widget1.id]: {
type: "workflow",
finalValue: 5
},
}
})
}
}

View File

@@ -4,3 +4,4 @@ export { default as parseA1111Tests } from "./parseA1111Tests"
export { default as convertA1111ToStdPromptTests } from "./convertA1111ToStdPromptTests"
export { default as convertVanillaWorkflowTest } from "./convertVanillaWorkflowTests"
export { default as configStateTests } from "./stores/configStateTests"
export { default as journeyStates } from "./stores/journeyStatesTests"