diff --git a/package.json b/package.json index 17f68b9..c1196bf 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,10 @@ "esbuild@<0.28.1": ">=0.28.1", "@codemirror/view": "^6.42.0", "@codemirror/autocomplete": "6.20.2", - "@health-samurai/aidbox-client": "file:./aidbox-ts-sdk/packages/aidbox-client" + "@health-samurai/aidbox-client": "file:./aidbox-ts-sdk/packages/aidbox-client", + "js-yaml@>=4.0.0 <=4.1.1": ">=4.2.0", + "@babel/core@<=7.29.0": ">=7.29.6", + "js-yaml@>=4.0.0 <4.3.0": ">=4.3.0" } }, "dependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1f108f4..ee710ed 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,6 +16,9 @@ overrides: '@codemirror/view': ^6.42.0 '@codemirror/autocomplete': 6.20.2 '@health-samurai/aidbox-client': file:./aidbox-ts-sdk/packages/aidbox-client + js-yaml@>=4.0.0 <=4.1.1: '>=4.2.0' + '@babel/core@<=7.29.0': '>=7.29.6' + js-yaml@>=4.0.0 <4.3.0: '>=4.3.0' importers: @@ -61,8 +64,8 @@ importers: specifier: ^7.1.0 version: 7.1.0 js-yaml: - specifier: ^4.1.1 - version: 4.1.1 + specifier: '>=4.3.0' + version: 5.2.1 lucide-react: specifier: ^0.577.0 version: 0.577.0(react@19.2.4) @@ -211,35 +214,37 @@ packages: resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.29.0': - resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} - engines: {node: '>=6.9.0'} + '@babel/code-frame@8.0.0': + resolution: {integrity: sha512-dYYg153EyN2Ekbqw2zAsbd6/JR+9N2SEoC7YV2GyyqMM7x9bLDTjBD6XBhSMLH0wtIVyJj03jWNriQhaN+eoCw==} + engines: {node: ^22.18.0 || >=24.11.0} - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} - engines: {node: '>=6.9.0'} + '@babel/compat-data@8.0.0': + resolution: {integrity: sha512-DOjnob/cXOUgDOozCDeq/aK2p5y8dUIVdf6tNhEV1HQRd6I8aQ4f4fbtHRVEvb6lP3BGomrKHiS8ICAASSVQSw==} + engines: {node: ^22.18.0 || >=24.11.0} + + '@babel/core@8.0.1': + resolution: {integrity: sha512-5FgxM4dLQpMJHSiVATk8foW263dVHQHBVpXYiimNECVWG01f4nFyEbQixeT6Mwvg7TayREJ2gpKl3o2RoMdnqw==} + engines: {node: ^22.18.0 || >=24.11.0} '@babel/generator@7.29.1': resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} - engines: {node: '>=6.9.0'} + '@babel/generator@8.0.0': + resolution: {integrity: sha512-NT9NrVwJsbSV6Y2FSstWa71EETOnzrjkL5/wX3D2mYHtKM+qvqB1DvR4D0Setb/gDBsHzRICifwEWMO8CnTF6g==} + engines: {node: ^22.18.0 || >=24.11.0} + + '@babel/helper-compilation-targets@8.0.0': + resolution: {integrity: sha512-JwculLABZvyPvyLBpwU/E/IbH2uM3mnxNtIJpxnIfb24y1PrdVxK5Dqjle4DpgqpGRnwgC7G8IkzPdSXZrO1Ew==} + engines: {node: ^22.18.0 || >=24.11.0} '@babel/helper-globals@7.28.0': resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 + '@babel/helper-globals@8.0.0': + resolution: {integrity: sha512-lLozHOM6sWWlxNo8CYqHy4MBZeTvHXNgVPBfPOGsjPKUzHC2Az9QwB6gxdQmpwHl6GlQtbGgS+lj5887guDiLw==} + engines: {node: ^22.18.0 || >=24.11.0} '@babel/helper-plugin-utils@7.28.6': resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} @@ -249,59 +254,84 @@ packages: resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@8.0.0': + resolution: {integrity: sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==} + engines: {node: ^22.18.0 || >=24.11.0} + '@babel/helper-validator-identifier@7.28.5': resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@8.0.4': + resolution: {integrity: sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==} + engines: {node: ^22.18.0 || >=24.11.0} - '@babel/helpers@7.28.6': - resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} - engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@8.0.0': + resolution: {integrity: sha512-U4Dybxh4WESWHt5XhBeExi4DrY0/DNK1aHpQbsrQXCUbFHuMweT0TpLEWKvaraV2Y6fS+ZXunsZ8zIuZIgvF2Q==} + engines: {node: ^22.18.0 || >=24.11.0} + + '@babel/helpers@8.0.0': + resolution: {integrity: sha512-wfbi91pM3py96oIiJEz7qIpyXDytgr9zQC1HEWwlGNVRAEmItuU/0a41ZUKu1sJGyhhOIpc4t5vk4PYzt8wpsg==} + engines: {node: ^22.18.0 || >=24.11.0} '@babel/parser@7.29.0': resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@8.0.4': + resolution: {integrity: sha512-srpptsAkEbbNIC/q8nT7o+m6CQe8CJUTV/t7MYc9NnWlgYVtHOb7JH6SorxMhN0kuRJjVqXbKClG6xSbPtzz+g==} + engines: {node: ^22.18.0 || >=24.11.0} + hasBin: true + '@babel/plugin-syntax-jsx@7.28.6': resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6' '@babel/plugin-syntax-typescript@7.28.6': resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6' '@babel/plugin-transform-react-jsx-self@7.27.1': resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6' '@babel/plugin-transform-react-jsx-source@7.27.1': resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': '>=7.29.6' '@babel/template@7.28.6': resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} + '@babel/template@8.0.0': + resolution: {integrity: sha512-eAD0QW/AlbamBbw0FeGiwasbCVPq5ncW0HNVyLP3B9czqLyh4gvw+5JTSNt6le9+ziAU7mqDZsKTHf3jTb4chQ==} + engines: {node: ^22.18.0 || >=24.11.0} + '@babel/traverse@7.29.0': resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} engines: {node: '>=6.9.0'} + '@babel/traverse@8.0.4': + resolution: {integrity: sha512-bZnmqzGG8UZneG1lLxBoWIH0G6Gr1D846Yu4/3XnY6FhCndMR49u26nTY08u/dAxWmLWF9vGQOuC+84FfIUoeg==} + engines: {node: ^22.18.0 || >=24.11.0} + '@babel/types@7.29.0': resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} + '@babel/types@8.0.4': + resolution: {integrity: sha512-eY+Yn3dCqTGmyiq2QRU66lA5FL8lqqqvecHt0fF3uHONIa7ToYsaCiWV8lOKqAs0Rb2SjixiKFROngnulPtt2g==} + engines: {node: ^22.18.0 || >=24.11.0} + '@biomejs/biome@2.1.3': resolution: {integrity: sha512-KE/tegvJIxTkl7gJbGWSgun7G6X/n2M6C35COT6ctYrAy7SiPyNvi6JtoQERVK/VRbttZfgGq96j2bFmhmnH4w==} engines: {node: '>=14.21.3'} @@ -1986,6 +2016,9 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/gensync@1.0.5': + resolution: {integrity: sha512-MbsRCT7mTikHwKZ0X+LVUTLRrZZRLipTuXEO9qOYO+zmjMVk81axyClMROf6uoPD9MRVu46bx8zoR0Ad9q3NAg==} + '@types/geojson@7946.0.16': resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} @@ -1995,6 +2028,9 @@ packages: '@types/js-yaml@4.0.9': resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} + '@types/jsesc@2.5.1': + resolution: {integrity: sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==} + '@types/json-patch@0.0.33': resolution: {integrity: sha512-XQ9hIoJCtnvTCnIV+p+SWQbY8Bt1pe+RuTkPG7lQeRCa9sPwYbhb0aYzM2paVPk0SGvV70R33rxjPjBcJ4Kdxw==} @@ -2345,6 +2381,10 @@ packages: emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + empathic@2.0.1: + resolution: {integrity: sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==} + engines: {node: '>=14'} + enhanced-resolve@5.20.0: resolution: {integrity: sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==} engines: {node: '>=10.13.0'} @@ -2466,6 +2506,9 @@ packages: immer@11.1.4: resolution: {integrity: sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==} + import-meta-resolve@4.2.0: + resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} + inline-style-parser@0.2.7: resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} @@ -2519,11 +2562,14 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + js-tokens@10.0.0: + resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + js-yaml@5.2.1: + resolution: {integrity: sha512-zfLtNfQqxVqq3uaTqSkh4x4hZw3KHobGUA0fJUj4wawW8bsQLTVqpHdXSIzidh7o+4lEW36tANuAGdaFx6Zgnw==} hasBin: true jsesc@3.1.0: @@ -2619,8 +2665,9 @@ packages: lowlight@3.3.0: resolution: {integrity: sha512-0JNhgFoPvP6U6lE/UdVsSq99tn6DhjjpAj5MxG49ewd2mOBVtwWYIT8ClyABhq198aXXODMU6Ox8DrGy/CpTZQ==} - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} + engines: {node: 20 || >=22} lucide-react@0.577.0: resolution: {integrity: sha512-4LjoFv2eEPwYDPg/CUdBJQSDfPyzXCRrVW1X7jrx/trgxnxkHFjnVZINbzvzxjN70dxychOfg+FTYwBiS3pQ5A==} @@ -2802,6 +2849,10 @@ packages: oauth4webapi@3.8.5: resolution: {integrity: sha512-A8jmyUckVhRJj5lspguklcl90Ydqk61H3dcU0oLhH3Yv13KpAliKTt5hknpGGPZSSfOwGyraNEFmofDYH+1kSg==} + obug@2.1.4: + resolution: {integrity: sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==} + engines: {node: '>=12.20.0'} + parse-entities@4.0.2: resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} @@ -3012,10 +3063,6 @@ packages: scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - semver@7.8.5: resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} @@ -3405,9 +3452,6 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yaml@2.8.3: resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} engines: {node: '>= 14.6'} @@ -3532,27 +3576,31 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.29.0': {} + '@babel/code-frame@8.0.0': + dependencies: + '@babel/helper-validator-identifier': 8.0.4 + js-tokens: 10.0.0 - '@babel/core@7.29.0': + '@babel/compat-data@8.0.0': {} + + '@babel/core@8.0.1': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.28.6 - '@babel/parser': 7.29.0 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - '@jridgewell/remapping': 2.3.5 + '@babel/code-frame': 8.0.0 + '@babel/generator': 8.0.0 + '@babel/helper-compilation-targets': 8.0.0 + '@babel/helpers': 8.0.0 + '@babel/parser': 8.0.4 + '@babel/template': 8.0.0 + '@babel/traverse': 8.0.4 + '@babel/types': 8.0.4 + '@types/gensync': 1.0.5 convert-source-map: 2.0.0 - debug: 4.4.3 + empathic: 2.0.1 gensync: 1.0.0-beta.2 + import-meta-resolve: 4.2.0 json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color + obug: 2.1.4 + semver: 7.8.5 '@babel/generator@7.29.1': dependencies: @@ -3562,67 +3610,70 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/helper-compilation-targets@7.28.6': + '@babel/generator@8.0.0': dependencies: - '@babel/compat-data': 7.29.0 - '@babel/helper-validator-option': 7.27.1 + '@babel/parser': 8.0.4 + '@babel/types': 8.0.4 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@types/jsesc': 2.5.1 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@8.0.0': + dependencies: + '@babel/compat-data': 8.0.0 + '@babel/helper-validator-option': 8.0.0 browserslist: 4.28.1 - lru-cache: 5.1.1 - semver: 6.3.1 + lru-cache: 11.5.2 + semver: 7.8.5 '@babel/helper-globals@7.28.0': {} - '@babel/helper-module-imports@7.28.6': - dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color + '@babel/helper-globals@8.0.0': {} '@babel/helper-plugin-utils@7.28.6': {} '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-string-parser@8.0.0': {} + '@babel/helper-validator-identifier@7.28.5': {} - '@babel/helper-validator-option@7.27.1': {} + '@babel/helper-validator-identifier@8.0.4': {} - '@babel/helpers@7.28.6': + '@babel/helper-validator-option@8.0.0': {} + + '@babel/helpers@8.0.0': dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 + '@babel/template': 8.0.0 + '@babel/types': 8.0.4 '@babel/parser@7.29.0': dependencies: '@babel/types': 7.29.0 - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + '@babel/parser@8.0.4': + dependencies: + '@babel/types': 8.0.4 + + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@8.0.1)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 8.0.1 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@8.0.1)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 8.0.1 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@8.0.1)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 8.0.1 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@8.0.1)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 8.0.1 '@babel/helper-plugin-utils': 7.28.6 '@babel/template@7.28.6': @@ -3631,6 +3682,12 @@ snapshots: '@babel/parser': 7.29.0 '@babel/types': 7.29.0 + '@babel/template@8.0.0': + dependencies: + '@babel/code-frame': 8.0.0 + '@babel/parser': 8.0.4 + '@babel/types': 8.0.4 + '@babel/traverse@7.29.0': dependencies: '@babel/code-frame': 7.29.0 @@ -3643,11 +3700,26 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/traverse@8.0.4': + dependencies: + '@babel/code-frame': 8.0.0 + '@babel/generator': 8.0.0 + '@babel/helper-globals': 8.0.0 + '@babel/parser': 8.0.4 + '@babel/template': 8.0.0 + '@babel/types': 8.0.4 + obug: 2.1.4 + '@babel/types@7.29.0': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@babel/types@8.0.4': + dependencies: + '@babel/helper-string-parser': 8.0.0 + '@babel/helper-validator-identifier': 8.0.4 + '@biomejs/biome@2.1.3': optionalDependencies: '@biomejs/cli-darwin-arm64': 2.1.3 @@ -5215,9 +5287,9 @@ snapshots: '@tanstack/router-plugin@1.166.12(@tanstack/react-router@1.167.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.5(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/core': 8.0.1 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@8.0.1) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@8.0.1) '@babel/template': 7.28.6 '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 @@ -5236,7 +5308,7 @@ snapshots: '@tanstack/router-utils@1.161.6': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 8.0.1 '@babel/generator': 7.29.1 '@babel/parser': 7.29.0 '@babel/types': 7.29.0 @@ -5330,6 +5402,8 @@ snapshots: '@types/estree@1.0.8': {} + '@types/gensync@1.0.5': {} + '@types/geojson@7946.0.16': {} '@types/hast@3.0.4': @@ -5338,6 +5412,8 @@ snapshots: '@types/js-yaml@4.0.9': {} + '@types/jsesc@2.5.1': {} + '@types/json-patch@0.0.33': {} '@types/mdast@4.0.4': @@ -5372,15 +5448,13 @@ snapshots: '@vitejs/plugin-react@4.7.0(vite@7.3.5(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@babel/core': 8.0.1 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@8.0.1) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@8.0.1) '@rolldown/pluginutils': 1.0.0-beta.27 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 vite: 7.3.5(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.3) - transitivePeerDependencies: - - supports-color '@vue/reactivity@3.5.30': dependencies: @@ -5442,7 +5516,7 @@ snapshots: babel-dead-code-elimination@1.0.12: dependencies: - '@babel/core': 7.29.0 + '@babel/core': 8.0.1 '@babel/parser': 7.29.0 '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 @@ -5692,6 +5766,8 @@ snapshots: emoji-regex@10.6.0: {} + empathic@2.0.1: {} + enhanced-resolve@5.20.0: dependencies: graceful-fs: 4.2.11 @@ -5825,6 +5901,8 @@ snapshots: immer@11.1.4: {} + import-meta-resolve@4.2.0: {} + inline-style-parser@0.2.7: {} input-otp@1.4.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4): @@ -5863,9 +5941,11 @@ snapshots: jiti@2.6.1: {} + js-tokens@10.0.0: {} + js-tokens@4.0.0: {} - js-yaml@4.1.1: + js-yaml@5.2.1: dependencies: argparse: 2.0.1 @@ -5932,9 +6012,7 @@ snapshots: devlop: 1.1.0 highlight.js: 11.11.1 - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 + lru-cache@11.5.2: {} lucide-react@0.577.0(react@19.2.4): dependencies: @@ -6318,6 +6396,8 @@ snapshots: oauth4webapi@3.8.5: {} + obug@2.1.4: {} + parse-entities@4.0.2: dependencies: '@types/unist': 2.0.11 @@ -6631,8 +6711,6 @@ snapshots: scheduler@0.27.0: {} - semver@6.3.1: {} - semver@7.8.5: {} seroval-plugins@1.5.1(seroval@1.5.1): @@ -7140,8 +7218,6 @@ snapshots: y18n@5.0.8: {} - yallist@3.1.1: {} - yaml@2.8.3: {} yargs-parser@22.0.0: {} diff --git a/src/components/SQLQueryBuilder/lineage/base-node.tsx b/src/components/SQLQueryBuilder/lineage/base-node.tsx index d027198..5502343 100644 --- a/src/components/SQLQueryBuilder/lineage/base-node.tsx +++ b/src/components/SQLQueryBuilder/lineage/base-node.tsx @@ -11,7 +11,7 @@ export function BaseNode({ }) { return (
diff --git a/src/components/SQLQueryBuilder/lineage/lineage-tab.tsx b/src/components/SQLQueryBuilder/lineage/lineage-tab.tsx index a2ceecd..18366f3 100644 --- a/src/components/SQLQueryBuilder/lineage/lineage-tab.tsx +++ b/src/components/SQLQueryBuilder/lineage/lineage-tab.tsx @@ -1,7 +1,6 @@ import * as HSComp from "@health-samurai/react-components"; import { useMutation } from "@tanstack/react-query"; import { - Background, Controls, type Edge, MarkerType, @@ -399,6 +398,25 @@ export function LineageTab() { }); }, [edges, selectedId]); + // Dim every node that is not on the selected node's up/downstream path so + // the views and resource tables along the path stand out with the edges. + // The dimming fades only the card content (see .lineage-node-dimmed in + // index.css) so the dotted background never shows through the card. + const styledNodes = React.useMemo(() => { + if (!selectedId) return nodes; + const highlightedEdges = collectConnectedEdges(edges, selectedId); + const connected = new Set([selectedId]); + for (const e of edges) { + if (!highlightedEdges.has(e.id)) continue; + connected.add(e.source); + connected.add(e.target); + } + return nodes.map((n) => ({ + ...n, + className: connected.has(n.id) ? undefined : "lineage-node-dimmed", + })); + }, [nodes, edges, selectedId]); + const clearSelection = React.useCallback(() => { setSelectedId(null); setNodes((nds) => @@ -519,7 +537,7 @@ export function LineageTab() {
- nodes={nodes} + nodes={styledNodes} edges={styledEdges} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} @@ -537,7 +555,6 @@ export function LineageTab() { minZoom={0.2} proOptions={{ hideAttribution: true }} > - diff --git a/src/components/SQLQueryBuilder/lineage/resolve-graph.ts b/src/components/SQLQueryBuilder/lineage/resolve-graph.ts index 086e08e..2f4527b 100644 --- a/src/components/SQLQueryBuilder/lineage/resolve-graph.ts +++ b/src/components/SQLQueryBuilder/lineage/resolve-graph.ts @@ -415,34 +415,338 @@ function attachInheritedParameters( } } +// Horizontal spacing between columns. const COL_WIDTH = 560; -const ROW_HEIGHT = 360; +// Vertical gap kept between neighbouring sibling subtrees in the SQL tree. +const SUBTREE_GAP = 56; +// Vertical gap between nodes stacked in the fixed resource / view columns. +const COLUMN_V_GAP = 40; + +// Fixed left-hand columns: resource tables, then view definitions. Everything +// to the right of them is the SQL dependency tree. +const RESOURCE_COL_X = 0; +const VIEW_COL_X = COL_WIDTH; +const SQL_COL_START = COL_WIDTH * 2; + +// Approximate rendered heights (px) of node chrome, used to reserve enough +// vertical room per node so that tall nodes don't overlap their siblings. +const HEADER_H = 61; +const ROW_H = 25; +const FOOTER_H = 29; +const EMPTY_BODY_H = 32; + +function countViewColumns(selects: ViewSelect[]): number { + let total = 0; + const walk = (list: ViewSelect[]) => { + for (const s of list) { + total += (s.column ?? []).length; + if (s.select) walk(s.select); + if (s.unionAll) walk(s.unionAll); + } + }; + walk(selects); + return total; +} + +function estimateNodeHeight(node: ResolvedNode): number { + if (node.kind === "resource-type") return HEADER_H; + if (node.kind === "view-definition") { + const cols = countViewColumns(node.data.select); + return HEADER_H + (cols > 0 ? cols * ROW_H : EMPTY_BODY_H) + FOOTER_H; + } + const d = node.data; + if (d.libraryKind === "sql-view") return HEADER_H + FOOTER_H; + const own = new Set(d.parameters.map((p) => p.name)); + const paramCount = + d.parameters.length + + d.inheritedParameters.filter((p) => !own.has(p.name)).length; + return ( + HEADER_H + (paramCount > 0 ? paramCount * ROW_H : EMPTY_BODY_H) + FOOTER_H + ); +} + +// Reduce the SQL sub-graph to a spanning tree: every SQL node keeps a single +// parent — the consuming SQL node closest to the root. +function buildSqlParentOf( + edges: Edge[], + depthById: Map, + kindById: Map, +): Map { + const parentOf = new Map(); + for (const e of edges) { + if ( + kindById.get(e.source) !== "sql-query" || + kindById.get(e.target) !== "sql-query" + ) { + continue; + } + // edge: source (dependency) → target (consumer / closer to root) + const current = parentOf.get(e.source); + if (current === undefined) { + parentOf.set(e.source, e.target); + continue; + } + const curDepth = depthById.get(current) ?? 0; + const newDepth = depthById.get(e.target) ?? 0; + if (newDepth < curDepth) parentOf.set(e.source, e.target); + } + return parentOf; +} + +function childrenFromParents( + parentOf: Map, +): Map { + const treeChildren = new Map(); + for (const [child, parent] of parentOf) { + const list = treeChildren.get(parent) ?? []; + list.push(child); + treeChildren.set(parent, list); + } + return treeChildren; +} + +// Vertical extent of a subtree = max of the node's own height and the stacked +// height of all its children (so a tall node still reserves room). +function subtreeHeight( + id: string, + treeChildren: Map, + heightById: Map, + cache: Map, +): number { + const cached = cache.get(id); + if (cached !== undefined) return cached; + const own = heightById.get(id) ?? EMPTY_BODY_H; + const children = treeChildren.get(id); + if (!children || children.length === 0) { + cache.set(id, own); + return own; + } + let total = SUBTREE_GAP * (children.length - 1); + for (const c of children) { + total += subtreeHeight(c, treeChildren, heightById, cache); + } + const height = Math.max(own, total); + cache.set(id, height); + return height; +} + +// Assign the vertical centre of each node so a parent sits centred on the band +// occupied by its children. +function placeSubtree( + id: string, + top: number, + treeChildren: Map, + heightById: Map, + cache: Map, + centerYById: Map, +): void { + const band = subtreeHeight(id, treeChildren, heightById, cache); + centerYById.set(id, top + band / 2); + + const children = treeChildren.get(id); + if (!children || children.length === 0) return; + let childrenTotal = SUBTREE_GAP * (children.length - 1); + for (const c of children) { + childrenTotal += subtreeHeight(c, treeChildren, heightById, cache); + } + let cursor = top + (band - childrenTotal) / 2; + for (const c of children) { + placeSubtree(c, cursor, treeChildren, heightById, cache, centerYById); + cursor += subtreeHeight(c, treeChildren, heightById, cache) + SUBTREE_GAP; + } +} + +function centerAroundZero( + centerYById: Map, + ids: string[], +): void { + let min = Number.POSITIVE_INFINITY; + let max = Number.NEGATIVE_INFINITY; + for (const id of ids) { + const y = centerYById.get(id); + if (y === undefined) continue; + if (y < min) min = y; + if (y > max) max = y; + } + if (min === Number.POSITIVE_INFINITY) return; + const mid = (min + max) / 2; + for (const id of ids) { + const y = centerYById.get(id); + if (y !== undefined) centerYById.set(id, y - mid); + } +} + +// Stack nodes into a single vertical column centred around y = 0. +function stackColumn( + ids: string[], + heightById: Map, + gap: number, +): Map { + let total = gap * Math.max(0, ids.length - 1); + for (const id of ids) total += heightById.get(id) ?? EMPTY_BODY_H; + const centerYById = new Map(); + let cursor = -total / 2; + for (const id of ids) { + const h = heightById.get(id) ?? EMPTY_BODY_H; + centerYById.set(id, cursor + h / 2); + cursor += h + gap; + } + return centerYById; +} + +function buildOutgoing(edges: Edge[]): Map { + const outgoing = new Map(); + for (const e of edges) { + const list = outgoing.get(e.source) ?? []; + list.push(e.target); + outgoing.set(e.source, list); + } + return outgoing; +} + +// Average vertical position of the consumers (edge targets) of a node, used to +// order the fixed columns so their nodes follow the nodes that reference them. +function averageConsumerY( + id: string, + outgoing: Map, + consumerYById: Map, +): number { + const consumers = outgoing.get(id); + if (!consumers || consumers.length === 0) return 0; + let sum = 0; + let count = 0; + for (const c of consumers) { + const y = consumerYById.get(c); + if (y === undefined) continue; + sum += y; + count += 1; + } + return count === 0 ? 0 : sum / count; +} + +// Place each node opposite the consumers that reference it: its centre is the +// average Y of those consumers, then overlaps are resolved by nudging the lower +// node down so the alignment is preserved as closely as possible. +function placeAgainstConsumers( + ids: string[], + outgoing: Map, + consumerYById: Map, + heightById: Map, + gap: number, +): Map { + const desired = ids + .map((id) => ({ id, y: averageConsumerY(id, outgoing, consumerYById) })) + .sort((a, b) => a.y - b.y); + const centerYById = new Map(); + let prevBottom = Number.NEGATIVE_INFINITY; + for (const { id, y } of desired) { + const h = heightById.get(id) ?? EMPTY_BODY_H; + const center = Math.max(y, prevBottom + gap + h / 2); + centerYById.set(id, center); + prevBottom = center + h / 2; + } + return centerYById; +} + +function nodePlacement( + id: string, + kind: LineageNodeData["kind"], + depthById: Map, + maxSqlDepth: number, + columnYById: { + sql: Map; + view: Map; + resource: Map; + }, +): { x: number; centerY: number } { + if (kind === "resource-type") { + return { x: RESOURCE_COL_X, centerY: columnYById.resource.get(id) ?? 0 }; + } + if (kind === "view-definition") { + return { x: VIEW_COL_X, centerY: columnYById.view.get(id) ?? 0 }; + } + // SQL nodes: rank increases towards the root, so the root sits furthest right. + const rank = maxSqlDepth - (depthById.get(id) ?? 0); + return { + x: SQL_COL_START + rank * COL_WIDTH, + centerY: columnYById.sql.get(id) ?? 0, + }; +} function layoutGraph( nodesById: Map, depthById: Map, edges: Edge[], ): LineageGraph { - const byDepth = new Map(); - for (const [id, depth] of depthById) { - const list = byDepth.get(depth) ?? []; - list.push(id); - byDepth.set(depth, list); + const heightById = new Map(); + const kindById = new Map(); + const sqlIds: string[] = []; + const viewIds: string[] = []; + const resourceIds: string[] = []; + for (const [id, resolved] of nodesById) { + heightById.set(id, estimateNodeHeight(resolved)); + kindById.set(id, resolved.kind); + if (resolved.kind === "sql-query") sqlIds.push(id); + else if (resolved.kind === "view-definition") viewIds.push(id); + else resourceIds.push(id); } + // SQL nodes form a tidy tree growing rightwards, root furthest right. + const sqlParentOf = buildSqlParentOf(edges, depthById, kindById); + const sqlChildren = childrenFromParents(sqlParentOf); + const cache = new Map(); + const sqlCenterY = new Map(); + let sqlTop = 0; + for (const id of sqlIds) { + if (sqlParentOf.has(id)) continue; + placeSubtree(id, sqlTop, sqlChildren, heightById, cache, sqlCenterY); + sqlTop += subtreeHeight(id, sqlChildren, heightById, cache) + SUBTREE_GAP; + } + centerAroundZero(sqlCenterY, sqlIds); + + let maxSqlDepth = 0; + for (const id of sqlIds) { + maxSqlDepth = Math.max(maxSqlDepth, depthById.get(id) ?? 0); + } + + // Views and resources: single vertical columns, ordered to follow the nodes + // that consume them so the connecting edges stay readable. + const outgoing = buildOutgoing(edges); + const orderedViews = [...viewIds].sort( + (a, b) => + averageConsumerY(a, outgoing, sqlCenterY) - + averageConsumerY(b, outgoing, sqlCenterY), + ); + const viewCenterY = stackColumn(orderedViews, heightById, COLUMN_V_GAP); + // Draw each resource table opposite the view definition(s) that reference it. + const resourceCenterY = placeAgainstConsumers( + resourceIds, + outgoing, + viewCenterY, + heightById, + COLUMN_V_GAP, + ); + + const columnYById = { + sql: sqlCenterY, + view: viewCenterY, + resource: resourceCenterY, + }; const nodes: Node[] = []; - for (const [depth, ids] of byDepth) { - ids.forEach((id, i) => { - const resolved = nodesById.get(id); - if (!resolved) return; - const x = -depth * COL_WIDTH; - const y = (i - (ids.length - 1) / 2) * ROW_HEIGHT; - nodes.push({ - id, - type: resolved.kind, - position: { x, y }, - data: resolved.data, - }); + for (const [id, resolved] of nodesById) { + const height = heightById.get(id) ?? EMPTY_BODY_H; + const { x, centerY } = nodePlacement( + id, + resolved.kind, + depthById, + maxSqlDepth, + columnYById, + ); + nodes.push({ + id, + type: resolved.kind, + position: { x, y: centerY - height / 2 }, + data: resolved.data, }); } diff --git a/src/index.css b/src/index.css index 3db4a77..695cf1b 100644 --- a/src/index.css +++ b/src/index.css @@ -38,6 +38,14 @@ tr:hover .pin-button { opacity: 0.5 !important; } +/* Lineage graph: de-emphasise nodes that are off the selected path. We fade + only the card's content, keeping the card itself opaque so the dotted + background does not show through (plain opacity on the node would). */ +.react-flow__node.lineage-node-dimmed .lineage-node-card > * { + opacity: 0.25; + transition: opacity 0.15s ease; +} + /* Hidden span used for cross-browser text width measurement (used by CodeSystemPicker for auto-sizing the input field) */ .input-measure {