diff --git a/package-lock.json b/package-lock.json index f2b4fe15..cd8cce23 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@abi-software/map-side-bar", - "version": "2.14.1", + "version": "2.14.1-acupoint.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@abi-software/map-side-bar", - "version": "2.14.1", + "version": "2.14.1-acupoint.0", "license": "Apache-2.0", "dependencies": { "@abi-software/gallery": "1.3.0", @@ -763,21 +763,6 @@ "vue": "^3.2.0" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "dev": true, @@ -1011,227 +996,6 @@ } } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", - "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", - "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", - "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", - "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", - "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", - "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", - "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", - "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", - "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", - "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", - "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", - "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", - "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", - "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", - "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", - "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", - "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.59.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", @@ -1258,84 +1022,6 @@ "linux" ] }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", - "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", - "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", - "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", - "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", - "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", - "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@shikijs/core": { "version": "2.5.0", "dev": true, @@ -2103,13 +1789,13 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", - "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", + "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", - "proxy-from-env": "^1.1.0" + "proxy-from-env": "^2.1.0" } }, "node_modules/babel-walk": { @@ -2197,9 +1883,9 @@ "license": "ISC" }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "dependencies": { "balanced-match": "^1.0.0", @@ -3655,17 +3341,6 @@ "dev": true, "license": "ISC" }, - "node_modules/fsevents": { - "version": "2.3.3", - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/fsu": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/fsu/-/fsu-1.1.1.tgz", @@ -3841,9 +3516,10 @@ } }, "node_modules/handlebars": { - "version": "4.7.8", + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", "dev": true, - "license": "MIT", "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", @@ -4463,14 +4139,14 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==" + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==" }, "node_modules/lodash-es": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", - "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==" + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==" }, "node_modules/lodash-unified": { "version": "1.0.3", @@ -4848,9 +4524,9 @@ } }, "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", "dev": true, "peer": true, "dependencies": { @@ -5295,8 +4971,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "license": "MIT", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "engines": { "node": ">=8.6" }, @@ -5420,8 +5097,12 @@ } }, "node_modules/proxy-from-env": { - "version": "1.1.0", - "license": "MIT" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "engines": { + "node": ">=10" + } }, "node_modules/pug": { "version": "3.0.3", @@ -6537,9 +6218,9 @@ } }, "node_modules/unplugin-vue-components/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", "dependencies": { "balanced-match": "^1.0.0" } diff --git a/package.json b/package.json index e045a616..2e643b17 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@abi-software/map-side-bar", - "version": "2.14.1", + "version": "2.14.1-acupoint.0", "license": "Apache-2.0", "repository": { "type": "git", diff --git a/src/App.vue b/src/App.vue index 3299be0d..c82fe1cb 100644 --- a/src/App.vue +++ b/src/App.vue @@ -18,6 +18,7 @@ keyword search Get facets Create Data/Annotation + Search Acupoints Connectivity Search @@ -42,6 +48,7 @@ + + diff --git a/src/components/AcupointsInfoSearch.vue b/src/components/AcupointsInfoSearch.vue new file mode 100644 index 00000000..1b77323c --- /dev/null +++ b/src/components/AcupointsInfoSearch.vue @@ -0,0 +1,620 @@ + + + + + + + Search + + + + + + + + + + No results found - Please change your search / filter criteria. + + + + + + + + + diff --git a/src/components/SearchFilters.vue b/src/components/SearchFilters.vue index ec21d8b5..5a3a447e 100644 --- a/src/components/SearchFilters.vue +++ b/src/components/SearchFilters.vue @@ -105,10 +105,10 @@ trigger="hover" popper-class="filter-help-popover" > - + - + Within categories: OR example: {{ entry.helper.within }} @@ -362,7 +362,7 @@ export default { }) // trigger reactivity only once - Object.assign(this.options, processedOptions); + Object.assign(this.options, processedOptions) }, populateCascader: function () { if (this.entry.options) { @@ -542,6 +542,13 @@ export default { }) return count } + const found = facet.children.find((item) => { + return item.label === "Show all" + }) + if (found) { + return facet.children.length - 1 + } + return facet.children.length }, /** diff --git a/src/components/SideBar.vue b/src/components/SideBar.vue index ff630c17..3c9d72cf 100644 --- a/src/components/SideBar.vue +++ b/src/components/SideBar.vue @@ -65,6 +65,15 @@ @connectivity-item-close="onConnectivityItemClose" /> + + + { + console.log("broken") + const acupointTabRef = this.getTabRef(undefined, 'acupoints', true); + acupointTabRef.openSearch(facets, query) + }) + }, openConnectivitySearch: function (facets, query) { this.drawerOpen = true; // Because refs are in v-for, nextTick is needed here @@ -299,9 +335,6 @@ export default { datasetExplorerTabRef.openSearch(facets, query); }) }, - /** - * Get the ref id of the tab by id and type. - */ getTabRef: function (id, type, switchTab = false) { const matchedTab = this.tabEntries.filter((tabEntry) => { return (id === undefined || tabEntry.id === id) && @@ -507,6 +540,11 @@ export default { // This should respect the information provided by the property tabEntries: function () { return this.tabs.filter((tab) => + (tab.type === "acupoints" && + ( + this.acupointsInfoList && + Object.keys(this.acupointsInfoList).length > 0 + )) || tab.type === "datasetExplorer" || tab.type === "connectivityExplorer" || ( @@ -572,6 +610,16 @@ export default { this.$emit('show-connectivity-graph', payLoad); }) + // Emit acupoints clicked event + EventBus.on('acupoints-clicked', (payLoad) => { + this.$emit('acupoints-clicked', payLoad); + }) + + // Emit acupoints hovered event + EventBus.on('acupoints-hovered', (payLoad) => { + this.$emit('acupoints-hovered', payLoad); + }) + // Get available anatomy facets for the connectivity info EventBus.on('available-facets', (payLoad) => { this.availableAnatomyFacets = payLoad.find((facet) => facet.label === 'Anatomical Structure').children diff --git a/src/services/flatmapKnowledge.js b/src/services/flatmapKnowledge.js new file mode 100644 index 00000000..e5116292 --- /dev/null +++ b/src/services/flatmapKnowledge.js @@ -0,0 +1,94 @@ +async function getReferenceConnectivitiesFromStorage(resource) { + const flatmapKnowledgeRaw = sessionStorage.getItem('flatmap-knowledge'); + + if (flatmapKnowledgeRaw) { + const flatmapKnowledge = JSON.parse(flatmapKnowledgeRaw); + const dataWithRefs = flatmapKnowledge.filter((x) => x.references && x.references.length); + const foundData = dataWithRefs.filter((x) => x.references.includes(resource)); + + if (foundData.length) { + const featureIds = foundData.map((x) => x.id); + return featureIds; + } + } + return []; +} + +async function getReferenceConnectivitiesByAPI(mapImp, resource, flatmapQueries) { + const knowledgeSource = getKnowledgeSource(mapImp); + const sql = `select knowledge from knowledge + where source="${knowledgeSource}" and + knowledge like "%${resource}%" order by source desc`; + console.log(sql) + const response = await flatmapQueries.flatmapQuery(sql); + const mappedData = response.values.map((x) => x[0]); + const parsedData = mappedData.map((x) => JSON.parse(x)); + const featureIds = parsedData.map((x) => x.id); + return featureIds; +} + +function getKnowledgeSource(mapImp) { + let mapKnowledgeSource = ''; + if (mapImp.provenance?.connectivity) { + const sckanProvenance = mapImp.provenance.connectivity; + if ('knowledge-source' in sckanProvenance) { + mapKnowledgeSource = sckanProvenance['knowledge-source']; + } else if ('npo' in sckanProvenance) { + mapKnowledgeSource = `${sckanProvenance.npo.release}-npo`; + } + } + + return mapKnowledgeSource; +} + +function loadAndStoreKnowledge(mapImp, flatmapQueries) { + const knowledgeSource = getKnowledgeSource(mapImp); + const sql = `select knowledge from knowledge + where source="${knowledgeSource}" + order by source desc`; + const flatmapKnowledge = sessionStorage.getItem('flatmap-knowledge'); + + if (!flatmapKnowledge) { + flatmapQueries.flatmapQuery(sql).then((response) => { + const mappedData = response.values.map(x => x[0]); + const parsedData = mappedData.map(x => JSON.parse(x)); + sessionStorage.setItem('flatmap-knowledge', JSON.stringify(parsedData)); + updateFlatmapKnowledgeCache(); + }); + } +} + +function updateFlatmapKnowledgeCache() { + const CACHE_LIFETIME = 24 * 60 * 60 * 1000; // One day + const now = new Date(); + const expiry = now.getTime() + CACHE_LIFETIME; + + sessionStorage.setItem('flatmap-knowledge-expiry', expiry); +} + +function removeFlatmapKnowledgeCache() { + const keys = [ + 'flatmap-knowledge', + 'flatmap-knowledge-expiry', + ]; + keys.forEach((key) => { + sessionStorage.removeItem(key); + }); +} + +function refreshFlatmapKnowledgeCache() { + const expiry = sessionStorage.getItem('flatmap-knowledge-expiry'); + const now = new Date(); + + if (now.getTime() > expiry) { + removeFlatmapKnowledgeCache(); + } +} + +export { + getReferenceConnectivitiesFromStorage, + getReferenceConnectivitiesByAPI, + loadAndStoreKnowledge, + getKnowledgeSource, + refreshFlatmapKnowledgeCache, +} diff --git a/src/services/flatmapQueries.js b/src/services/flatmapQueries.js new file mode 100644 index 00000000..b343a043 --- /dev/null +++ b/src/services/flatmapQueries.js @@ -0,0 +1,498 @@ +/* eslint-disable no-alert, no-console */ +// remove duplicates by stringifying the objects +const removeDuplicates = function (arrayOfAnything) { + if (!arrayOfAnything) return [] + return [...new Set(arrayOfAnything.map((e) => JSON.stringify(e)))].map((e) => + JSON.parse(e) + ) +} + +const cachedLabels = {} +const cachedTaxonLabels = []; + +const findTaxonomyLabel = async function (flatmapAPI, taxonomy) { + if (cachedLabels && cachedLabels.hasOwnProperty(taxonomy)) { + return cachedLabels[taxonomy] + } + + return new Promise((resolve) => { + fetch(`${flatmapAPI}knowledge/label/${taxonomy}`, { + method: 'GET', + }) + .then((response) => response.json()) + .then((data) => { + let label = data.label + if (label === 'Mammalia') { + label = 'Mammalia not otherwise specified' + } + cachedLabels[taxonomy] = label + resolve(label) + }) + .catch((error) => { + console.error('Error:', error) + cachedLabels[taxonomy] = taxonomy + resolve(taxonomy) + }) + }) +} + +const findTaxonomyLabels = async function (mapImp, taxonomies) { + const intersectionTaxonomies = taxonomies.filter((taxonomy) => + cachedTaxonLabels.some((obj) => obj.taxon === taxonomy) + ); + + const foundCachedTaxonLabels = cachedTaxonLabels.filter((obj) => + intersectionTaxonomies.includes(obj.taxon) + ); + + const leftoverTaxonomies = taxonomies.filter((taxonomy) => + !intersectionTaxonomies.includes(taxonomy) + ); + + if (!leftoverTaxonomies.length) { + return foundCachedTaxonLabels; + } else { + const entityLabels = await mapImp.queryLabels(leftoverTaxonomies); + if (entityLabels.length) { + entityLabels.forEach((entityLabel) => { + let { entity: taxon, label } = entityLabel; + if (label === 'Mammalia') { + label = 'Mammalia not otherwise specified' + } + const item = { taxon, label }; + foundCachedTaxonLabels.push(item); + cachedTaxonLabels.push(item); + }); + return foundCachedTaxonLabels; + } + } +} + +const inArray = function (ar1, ar2) { + if (!ar1 || !ar2) return false + let as1 = JSON.stringify(ar1) + let as2 = JSON.stringify(ar2) + return as1.indexOf(as2) !== -1 +} + +let FlatmapQueries = function () { + this.initialise = function (flatmapApi) { + this.flatmapApi = flatmapApi + this.destinations = [] + this.origins = [] + this.components = [] + this.rawURLs = [] + this.controller = undefined + this.uberons = [] + this.lookUp = [] + } + + this.createTooltipData = async function (mapImp, eventData) { + let hyperlinks = [] + if ( + eventData.feature.hyperlinks && + eventData.feature.hyperlinks.length > 0 + ) { + hyperlinks = eventData.feature.hyperlinks + } else { + hyperlinks = this.rawURLs; + } + let taxonomyLabel = undefined + if (eventData.provenanceTaxonomy) { + taxonomyLabel = [] + const entityLabels = await findTaxonomyLabels(mapImp, eventData.provenanceTaxonomy); + if (entityLabels.length) { + entityLabels.forEach((entityLabel) => { + const { label } = entityLabel; + taxonomyLabel.push(label); + }); + } + } + + let tooltipData = { + destinations: this.destinations, + origins: this.origins, + components: this.components, + destinationsWithDatasets: this.destinationsWithDatasets, + originsWithDatasets: this.originsWithDatasets, + componentsWithDatasets: this.componentsWithDatasets, + title: eventData.label, + featureId: eventData.resource, + hyperlinks: hyperlinks, + provenanceTaxonomy: eventData.provenanceTaxonomy, + provenanceTaxonomyLabel: taxonomyLabel, + } + return tooltipData + } + + this.createComponentsLabelList = function (components, lookUp) { + let labelList = [] + components.forEach((n) => { + labelList.push(this.createLabelFromNeuralNode(n[0]), lookUp) + if (n.length === 2) { + labelList.push(this.createLabelFromNeuralNode(n[1]), lookUp) + } + }) + return labelList + } + + this.createLabelLookup = function (mapImp, uberons) { + return new Promise(async (resolve) => { + let uberonMap = {} + this.uberons = [] + const entityLabels = await findTaxonomyLabels(mapImp, uberons); + if (entityLabels.length) { + entityLabels.forEach((entityLabel) => { + const { taxon: entity, label } = entityLabel; + uberonMap[entity] = label; + this.uberons.push({ + id: entity, + name: label, + }) + }); + resolve(uberonMap) + } + }) + } + + this.buildConnectivitySqlStatement = function (keastIds) { + let sql = 'select knowledge from knowledge where entity in (' + if (keastIds.length === 1) { + sql += `'${keastIds[0]}')` + } else if (keastIds.length > 1) { + for (let i in keastIds) { + sql += `'${keastIds[i]}'${i >= keastIds.length - 1 ? ')' : ','} ` + } + } + return sql + } + + this.buildLabelSqlStatement = function (uberons) { + let sql = 'select entity, label from labels where entity in (' + if (uberons.length === 1) { + sql += `'${uberons[0]}')` + } else if (uberons.length > 1) { + for (let i in uberons) { + sql += `'${uberons[i]}'${i >= uberons.length - 1 ? ')' : ','} ` + } + } + return sql + } + + this.findAllIdsFromConnectivity = function (connectivity) { + let dnodes = connectivity.connectivity.flat() // get nodes from edgelist + let nodes = [...new Set(dnodes)] // remove duplicates + let found = [] + nodes.forEach((n) => { + if (Array.isArray(n)) { + found.push(n.flat()) + } else { + found.push(n) + } + }) + return [...new Set(found.flat())] + } + + this.flattenConntectivity = function (connectivity) { + let dnodes = connectivity.flat() // get nodes from edgelist + let nodes = [...new Set(dnodes)] // remove duplicates + let found = [] + nodes.forEach((n) => { + if (Array.isArray(n)) { + found.push(n.flat()) + } else { + found.push(n) + } + }) + return found.flat() + } + + this.findComponents = function (connectivity) { + let dnodes = connectivity.connectivity.flat() // get nodes from edgelist + let nodes = removeDuplicates(dnodes) + + let found = [] + let terminal = false + nodes.forEach((node) => { + terminal = false + // Check if the node is an destination or origin (note that they are labelled dendrite and axon as opposed to origin and destination) + if (inArray(connectivity.axons, node)) { + terminal = true + } + if (connectivity.somas && inArray(connectivity.somas, node)) { + terminal = true + } + if (inArray(connectivity.dendrites, node)) { + terminal = true + } + if (!terminal) { + found.push(node) + } + }) + + return found + } + + this.retrieveFlatmapKnowledgeForEvent = async function (mapImp, eventData) { + // check if there is an existing query + if (this.controller) this.controller.abort() + + // set up the abort controller + this.controller = new AbortController() + const signal = this.controller.signal + + const keastIds = eventData.resource + this.destinations = [] + this.origins = [] + this.components = [] + this.rawURLs = [] + if (!keastIds || keastIds.length == 0 || !keastIds[0]) return + + let prom1 = this.queryForConnectivityNew(mapImp, keastIds, signal) // This on returns a promise so dont need 'await' + let results = await Promise.all([prom1]) + return results + } + + this.queryForConnectivityNew = function (mapImp, keastIds, signal, processConnectivity=true) { + return new Promise((resolve) => { + mapImp.queryKnowledge(keastIds[0]) + .then((response) => { + if (this.checkConnectivityExists(response)) { + let connectivity = response; + if (processConnectivity) { + this.processConnectivity(mapImp, connectivity).then((processedConnectivity) => { + // response.references is publication urls + if (response.references) { + // with publications from both PubMed and Others + this.rawURLs = [...response.references]; + resolve(processedConnectivity) + } else { + // without publications + resolve(processedConnectivity) + } + }) + } + else resolve(connectivity) + } else { + resolve(false) + } + }) + .catch((error) => { + if (error.name === 'AbortError') { + // This error is from AbortController's abort method. + } else { + // console.error('Error:', error) + // TODO: to update after queryKnowledge method update + console.warn(`Unable to get the knowledge for the entity ${keastIds[0]}.`) + } + resolve(false) + }) + }) + } + + this.queryForConnectivity = function (mapImp, keastIds, signal, processConnectivity=true) { + const data = { sql: this.buildConnectivitySqlStatement(keastIds) } + const headers = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + ...(signal ? { signal: signal } : {}), // add signal to header if it exists + } + return new Promise((resolve) => { + fetch(`${this.flatmapApi}knowledge/query/`, headers) + .then((response) => response.json()) + .then((data) => { + if (this.connectivityExists(data)) { + let connectivity = JSON.parse(data.values[0][0]) + if (processConnectivity) { + this.processConnectivity(mapImp, connectivity).then((processedConnectivity) => { + resolve(processedConnectivity) + }) + } + else resolve(connectivity) + } else { + resolve(false) + } + }) + .catch((error) => { + if (error.name === 'AbortError') { + // This error is from AbortController's abort method. + } else { + console.error('Error:', error) + } + resolve(false) + }) + }) + } + + this.checkConnectivityExists = function (data) { + return data && data.connectivity?.length; + }; + + this.connectivityExists = function (data) { + if ( + data.values && + data.values.length > 0 && + JSON.parse(data.values[0][0]).connectivity && + JSON.parse(data.values[0][0]).connectivity.length > 0 + ) { + return true + } else { + return false + } + } + + // This function is used to determine if a node is a single node or a node with multiple children + // Returns the id of the node if it is a single node, otherwise returns false + this.findIfNodeIsSingle = function (node) { + if (node.length === 1) { // If the node is in the form [id] + console.error("Server returns a single node", node) + return node[0] + } else { + if (node.length === 2 && node[1].length === 0) { // If the node is in the form [id, []] + return node[0] + } else { + return false // If the node is in the form [id, [id1, id2]] + } + } + } + + this.createLabelFromNeuralNode = function (node, lookUp) { + + // Check if the node is a single node or a node with multiple children + let nodeIsSingle = this.findIfNodeIsSingle(node) + + // Case where node is in the form [id] + if (nodeIsSingle) { + return lookUp[nodeIsSingle] + } + + // Case where node is in the form [id, [id1 (,id2)]] + let label = lookUp[node[0]] + if (node.length === 2 && node[1].length > 0) { + node[1].forEach((n) => { + if (lookUp[n] == undefined) { + label += `, ${n}` + } else { + label += `, ${lookUp[n]}` + } + }) + } + return label + } + + this.flattenAndFindDatasets = function (components, axons, dendrites) { + // process the nodes for finding datasets (Note this is not critical to the tooltip, only for the 'search on components' button) + let componentsFlat = this.flattenConntectivity(components) + let axonsFlat = this.flattenConntectivity(axons) + let dendritesFlat = this.flattenConntectivity(dendrites) + + // Filter for the anatomy which is annotated on datasets + this.destinationsWithDatasets = this.uberons.filter( + (ub) => axonsFlat.indexOf(ub.id) !== -1 + ) + this.originsWithDatasets = this.uberons.filter( + (ub) => dendritesFlat.indexOf(ub.id) !== -1 + ) + this.componentsWithDatasets = this.uberons.filter( + (ub) => componentsFlat.indexOf(ub.id) !== -1 + ) + } + + this.processConnectivity = function (mapImp, connectivity) { + return new Promise((resolve) => { + // Filter the origin and destinations from components + let components = this.findComponents(connectivity) + + // Remove duplicates + let axons = removeDuplicates(connectivity.axons) + //Somas will become part of origins, support this for future proof + let dendrites = [] + if (connectivity.somas && connectivity.somas.length > 0) { + dendrites.push(...connectivity.somas) + } + if (connectivity.dendrites && connectivity.dendrites.length > 0) { + dendrites.push(...connectivity.dendrites) + } + dendrites = removeDuplicates(dendrites) + + // Create list of ids to get labels for + let conIds = this.findAllIdsFromConnectivity(connectivity) + + // Create readable labels from the nodes. Setting this to 'this.origins' updates the display + this.createLabelLookup(mapImp, conIds).then((lookUp) => { + this.destinations = axons.map((a) => + this.createLabelFromNeuralNode(a, lookUp) + ) + this.origins = dendrites.map((d) => + this.createLabelFromNeuralNode(d, lookUp) + ) + this.components = components.map((c) => + this.createLabelFromNeuralNode(c, lookUp) + ) + this.flattenAndFindDatasets(components, axons, dendrites) + resolve({ + ids: { + axons: axons, + dendrites: dendrites, + components: components, + }, + labels: { + destinations: this.destinations, + origins: this.origins, + components: this.components, + } + }) + }) + }) + } + + this.flattenConntectivity = function (connectivity) { + let dnodes = connectivity.flat() // get nodes from edgelist + let nodes = [...new Set(dnodes)] // remove duplicates + let found = [] + nodes.forEach((n) => { + if (Array.isArray(n)) { + found.push(n.flat()) + } else { + found.push(n) + } + }) + return found.flat() + } + + this.buildPubmedSqlStatement = function (keastIds) { + let sql = 'select distinct publication from publications where entity in (' + if (keastIds.length === 1) { + sql += `'${keastIds[0]}')` + } else if (keastIds.length > 1) { + for (let i in keastIds) { + sql += `'${keastIds[i]}'${i >= keastIds.length - 1 ? ')' : ','} ` + } + } + return sql + } + + this.buildPubmedSqlStatementForModels = function (model) { + return `select distinct publication from publications where entity = '${model}'` + } + + this.flatmapQuery = function (sql) { + const data = { sql: sql } + return fetch(`${this.flatmapApi}knowledge/query/`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }) + .then((response) => response.json()) + .catch((error) => { + console.error('Error:', error) + }) + } +} + +export { FlatmapQueries, findTaxonomyLabel, findTaxonomyLabels }