Merge branch 'remove-imjoy' into 'v3'

Remove old unmaintained components

Closes #387

See merge request openflexure/openflexure-microscope-server!314
This commit is contained in:
Julian Stirling 2025-07-07 11:53:31 +00:00
commit fd4d51401f
17 changed files with 28 additions and 1761 deletions

View file

@ -2,4 +2,3 @@ NODE_ENV=development
VUE_APP_MODE=development VUE_APP_MODE=development
VUE_APP_PLATFORM=web VUE_APP_PLATFORM=web
VUE_APP_TARGET=web VUE_APP_TARGET=web
VUE_APP_ENABLE_IMJOY=true

View file

@ -2,4 +2,3 @@ NODE_ENV=production
VUE_APP_MODE=production VUE_APP_MODE=production
VUE_APP_PLATFORM=web VUE_APP_PLATFORM=web
VUE_APP_TARGET=web VUE_APP_TARGET=web
VUE_APP_ENABLE_IMJOY=true

456
webapp/package-lock.json generated
View file

@ -9,7 +9,6 @@
"version": "3.0.0-alpha1", "version": "3.0.0-alpha1",
"license": "GNU General Public License v3.0 ", "license": "GNU General Public License v3.0 ",
"dependencies": { "dependencies": {
"imjoy-core": "^0.13",
"material-design-icons": "^3.0", "material-design-icons": "^3.0",
"material-symbols": "^0.14.3", "material-symbols": "^0.14.3",
"mousetrap": "^1.6.5", "mousetrap": "^1.6.5",
@ -34,9 +33,7 @@
"prettier": "^1.19", "prettier": "^1.19",
"uikit": "^3.17", "uikit": "^3.17",
"vue": "^2.7", "vue": "^2.7",
"vue-friendly-iframe": "^0.17",
"vue-template-compiler": "^2.7", "vue-template-compiler": "^2.7",
"vue-tour": "^1.6",
"vuejs-paginate": "^2.1", "vuejs-paginate": "^2.1",
"vuex": "^3.6" "vuex": "^3.6"
} }
@ -1445,11 +1442,6 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"node_modules/@socket.io/component-emitter": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
},
"node_modules/@soda/friendly-errors-webpack-plugin": { "node_modules/@soda/friendly-errors-webpack-plugin": {
"version": "1.8.1", "version": "1.8.1",
"resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.1.tgz", "resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.1.tgz",
@ -2581,15 +2573,11 @@
"node": ">= 10.0.0" "node": ">= 10.0.0"
} }
}, },
"node_modules/after": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
"integrity": "sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA=="
},
"node_modules/ajv": { "node_modules/ajv": {
"version": "6.12.6", "version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0", "fast-json-stable-stringify": "^2.0.0",
@ -2731,15 +2719,11 @@
"version": "1.0.10", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dev": true,
"dependencies": { "dependencies": {
"sprintf-js": "~1.0.2" "sprintf-js": "~1.0.2"
} }
}, },
"node_modules/argsarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/argsarray/-/argsarray-0.0.1.tgz",
"integrity": "sha512-u96dg2GcAKtpTrBdDoFIM7PjcBA+6rSP0OR94MOReNRyUECL6MtQt5XXmRr4qrftYaef9+l5hcpO5te7sML1Cg=="
},
"node_modules/arr-diff": { "node_modules/arr-diff": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
@ -2856,11 +2840,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/arraybuffer.slice": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
"integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog=="
},
"node_modules/asn1": { "node_modules/asn1": {
"version": "0.2.6", "version": "0.2.6",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
@ -3038,6 +3017,7 @@
"version": "0.21.4", "version": "0.21.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
"dev": true,
"dependencies": { "dependencies": {
"follow-redirects": "^1.14.0" "follow-redirects": "^1.14.0"
} }
@ -3146,11 +3126,6 @@
"@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
} }
}, },
"node_modules/backo2": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
"integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA=="
},
"node_modules/balanced-match": { "node_modules/balanced-match": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -3187,14 +3162,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/base64-arraybuffer": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz",
"integrity": "sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg==",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/base64-js": { "node_modules/base64-js": {
"version": "1.5.1", "version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@ -3274,11 +3241,6 @@
"file-uri-to-path": "1.0.0" "file-uri-to-path": "1.0.0"
} }
}, },
"node_modules/blob": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
"integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig=="
},
"node_modules/bluebird": { "node_modules/bluebird": {
"version": "3.7.2", "version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@ -4281,24 +4243,15 @@
"integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
"dev": true "dev": true
}, },
"node_modules/component-bind": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
"integrity": "sha512-WZveuKPeKAG9qY+FkYDeADzdHyTYdIboXS59ixDeRJL5ZhxpqUnxSOwop4FQjMsiYm3/Or8cegVbpAHNA7pHxw=="
},
"node_modules/component-emitter": { "node_modules/component-emitter": {
"version": "1.3.1", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz",
"integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==",
"dev": true,
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/component-inherit": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
"integrity": "sha512-w+LhYREhatpVqTESyGFg3NlP6Iu0kEKUHETY9GoZP/pQyW4mHFZuFWRUCIqVPZ36ueVLtoOEZaAqbCF2RDndaA=="
},
"node_modules/compressible": { "node_modules/compressible": {
"version": "2.0.18", "version": "2.0.18",
"resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
@ -5131,6 +5084,7 @@
"version": "4.3.4", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"dependencies": { "dependencies": {
"ms": "2.1.2" "ms": "2.1.2"
}, },
@ -5642,11 +5596,6 @@
"url": "https://github.com/fb55/domhandler?sponsor=1" "url": "https://github.com/fb55/domhandler?sponsor=1"
} }
}, },
"node_modules/dompurify": {
"version": "2.4.7",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.7.tgz",
"integrity": "sha512-kxxKlPEDa6Nc5WJi+qRgPbOAbgTpSULL+vI3NUXsZMlkJxTqYI9wg5ZTay2sFrdZRWHPWNi+EdAhcJf81WtoMQ=="
},
"node_modules/domutils": { "node_modules/domutils": {
"version": "2.8.0", "version": "2.8.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
@ -5801,49 +5750,6 @@
"once": "^1.4.0" "once": "^1.4.0"
} }
}, },
"node_modules/engine.io-client": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.3.tgz",
"integrity": "sha512-qsgyc/CEhJ6cgMUwxRRtOndGVhIu5hpL5tR4umSpmX/MvkFoIxUTM7oFMDQumHNzlNLwSVy6qhstFPoWTf7dOw==",
"dependencies": {
"component-emitter": "~1.3.0",
"component-inherit": "0.0.3",
"debug": "~3.1.0",
"engine.io-parser": "~2.2.0",
"has-cors": "1.1.0",
"indexof": "0.0.1",
"parseqs": "0.0.6",
"parseuri": "0.0.6",
"ws": "~7.4.2",
"xmlhttprequest-ssl": "~1.6.2",
"yeast": "0.1.2"
}
},
"node_modules/engine.io-client/node_modules/debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/engine.io-client/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/engine.io-parser": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz",
"integrity": "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==",
"dependencies": {
"after": "0.8.2",
"arraybuffer.slice": "~0.0.7",
"base64-arraybuffer": "0.1.4",
"blob": "0.0.5",
"has-binary2": "~1.0.2"
}
},
"node_modules/enhanced-resolve": { "node_modules/enhanced-resolve": {
"version": "4.5.0", "version": "4.5.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz",
@ -6318,6 +6224,7 @@
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true,
"bin": { "bin": {
"esparse": "bin/esparse.js", "esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js" "esvalidate": "bin/esvalidate.js"
@ -6732,7 +6639,8 @@
"node_modules/fast-deep-equal": { "node_modules/fast-deep-equal": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
}, },
"node_modules/fast-diff": { "node_modules/fast-diff": {
"version": "1.3.0", "version": "1.3.0",
@ -6760,7 +6668,8 @@
"node_modules/fast-json-stable-stringify": { "node_modules/fast-json-stable-stringify": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
"dev": true
}, },
"node_modules/fast-levenshtein": { "node_modules/fast-levenshtein": {
"version": "2.0.6", "version": "2.0.6",
@ -6856,11 +6765,6 @@
"node": ">=4.0.0" "node": ">=4.0.0"
} }
}, },
"node_modules/file-saver": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-1.3.8.tgz",
"integrity": "sha512-spKHSBQIxxS81N/O21WmuXA2F6wppUCsutpzenOeZzOCCJ5gEfcbqJP983IrpLXzYmXnMUa6J03SubcNPdKrlg=="
},
"node_modules/file-uri-to-path": { "node_modules/file-uri-to-path": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
@ -7096,6 +7000,7 @@
"version": "1.15.4", "version": "1.15.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
"dev": true,
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
@ -7581,24 +7486,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/has-binary2": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
"integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
"dependencies": {
"isarray": "2.0.1"
}
},
"node_modules/has-binary2/node_modules/isarray": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ=="
},
"node_modules/has-cors": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
"integrity": "sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA=="
},
"node_modules/has-flag": { "node_modules/has-flag": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
@ -8182,112 +8069,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/imjoy-core": {
"version": "0.13.82",
"resolved": "https://registry.npmjs.org/imjoy-core/-/imjoy-core-0.13.82.tgz",
"integrity": "sha512-uXf1YnWXfzQu/DluVfXQDdttEadDt81QOYEfVnRbxeNXV1xtYYpsQxdXCA3aiIju36Zvh/V3zQ4y4uTEQj00VQ==",
"dependencies": {
"ajv": "^6.9.1",
"axios": "^0.21.1",
"dompurify": "^2.0.8",
"file-saver": "^1.3.3",
"imjoy-rpc": "^0.3.16",
"js-yaml": "^3.13.1",
"lodash": "^4.17.15",
"lz-string": "^1.4.4",
"minibus": "^3.1.0",
"pouchdb-browser": "^7.0.0",
"socket.io-client": "^2.3.0",
"spark-md5": "^3.0.0"
}
},
"node_modules/imjoy-rpc": {
"version": "0.3.42",
"resolved": "https://registry.npmjs.org/imjoy-rpc/-/imjoy-rpc-0.3.42.tgz",
"integrity": "sha512-DgkBKL33fkKDV3nPtMZHSJ1FBYr8oay9p6HkOxnKm/MB7IzEi5VJcQJIbyLc8IuDJEsTBCDguZdkGuBSeKKU/w==",
"dependencies": {
"socket.io-client": "^4.0.1"
}
},
"node_modules/imjoy-rpc/node_modules/engine.io-client": {
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz",
"integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.11.0",
"xmlhttprequest-ssl": "~2.0.0"
}
},
"node_modules/imjoy-rpc/node_modules/engine.io-parser": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz",
"integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/imjoy-rpc/node_modules/socket.io-client": {
"version": "4.7.2",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz",
"integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.2",
"engine.io-client": "~6.5.2",
"socket.io-parser": "~4.2.4"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/imjoy-rpc/node_modules/socket.io-parser": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/imjoy-rpc/node_modules/ws": {
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/imjoy-rpc/node_modules/xmlhttprequest-ssl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/immediate": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz",
"integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q=="
},
"node_modules/import-cwd": { "node_modules/import-cwd": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
@ -8405,11 +8186,6 @@
"integrity": "sha512-bup+4tap3Hympa+JBJUG7XuOsdNQ6fxt0MHyXMKuLBKn0OqsTfvUxkUrroEX1+B2VsSHvCjiIcZVxRtYa4nllA==", "integrity": "sha512-bup+4tap3Hympa+JBJUG7XuOsdNQ6fxt0MHyXMKuLBKn0OqsTfvUxkUrroEX1+B2VsSHvCjiIcZVxRtYa4nllA==",
"dev": true "dev": true
}, },
"node_modules/indexof": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
"integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg=="
},
"node_modules/infer-owner": { "node_modules/infer-owner": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
@ -8429,7 +8205,8 @@
"node_modules/inherits": { "node_modules/inherits": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
}, },
"node_modules/inquirer": { "node_modules/inquirer": {
"version": "7.3.3", "version": "7.3.3",
@ -9283,6 +9060,7 @@
"version": "3.14.1", "version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"dev": true,
"dependencies": { "dependencies": {
"argparse": "^1.0.7", "argparse": "^1.0.7",
"esprima": "^4.0.0" "esprima": "^4.0.0"
@ -9330,7 +9108,8 @@
"node_modules/json-schema-traverse": { "node_modules/json-schema-traverse": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
}, },
"node_modules/json-stable-stringify-without-jsonify": { "node_modules/json-stable-stringify-without-jsonify": {
"version": "1.0.1", "version": "1.0.1",
@ -9380,12 +9159,6 @@
"node": ">=0.6.0" "node": ">=0.6.0"
} }
}, },
"node_modules/jump.js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/jump.js/-/jump.js-1.0.2.tgz",
"integrity": "sha512-oUkJJ/Y4ATU5qjkXBntCZSKctbSyS3ewe2jrLaUu/cc9jsQiAn0fnTUxQnZz3mJdDdem1Q279zrD6h3n+Cgxtg==",
"dev": true
},
"node_modules/killable": { "node_modules/killable": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
@ -9637,7 +9410,8 @@
"node_modules/lodash": { "node_modules/lodash": {
"version": "4.17.21", "version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
}, },
"node_modules/lodash.debounce": { "node_modules/lodash.debounce": {
"version": "4.0.8", "version": "4.0.8",
@ -9733,14 +9507,6 @@
"yallist": "^3.0.2" "yallist": "^3.0.2"
} }
}, },
"node_modules/lz-string": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
"bin": {
"lz-string": "bin/bin.js"
}
},
"node_modules/magic-string": { "node_modules/magic-string": {
"version": "0.30.5", "version": "0.30.5",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz",
@ -10057,11 +9823,6 @@
"node": ">= 4" "node": ">= 4"
} }
}, },
"node_modules/minibus": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/minibus/-/minibus-3.1.0.tgz",
"integrity": "sha512-VVhbxJ0DrlHepHS8a8vzGxPhZkBbX1Rjk0LU5gR7mEuDBD8+z8953+mMd/GQtntySTE1l7cOvKAqjEdodDIryQ=="
},
"node_modules/minimalistic-assert": { "node_modules/minimalistic-assert": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
@ -10181,7 +9942,8 @@
"node_modules/ms": { "node_modules/ms": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
}, },
"node_modules/multicast-dns": { "node_modules/multicast-dns": {
"version": "6.2.3", "version": "6.2.3",
@ -11045,16 +10807,6 @@
"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
"dev": true "dev": true
}, },
"node_modules/parseqs": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz",
"integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w=="
},
"node_modules/parseuri": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz",
"integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow=="
},
"node_modules/parseurl": { "node_modules/parseurl": {
"version": "1.3.3", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@ -11325,17 +11077,6 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/popper.js": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
"integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==",
"deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1",
"dev": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/portfinder": { "node_modules/portfinder": {
"version": "1.0.32", "version": "1.0.32",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz",
@ -12043,19 +11784,6 @@
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"dev": true "dev": true
}, },
"node_modules/pouchdb-browser": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/pouchdb-browser/-/pouchdb-browser-7.3.1.tgz",
"integrity": "sha512-qZ8awkXl/woBHvEVqNHjDtwPDA7A9v4ItHtX1y1eVpKel4mlYqnIJ8K6pRcFUZmVaHinJW8K3uS32eHC1q0yOA==",
"dependencies": {
"argsarray": "0.0.1",
"immediate": "3.3.0",
"inherits": "2.0.4",
"spark-md5": "3.0.2",
"uuid": "8.3.2",
"vuvuzela": "1.0.3"
}
},
"node_modules/prelude-ls": { "node_modules/prelude-ls": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
@ -12224,6 +11952,7 @@
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
"dev": true,
"engines": { "engines": {
"node": ">=6" "node": ">=6"
} }
@ -13402,65 +13131,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/socket.io-client": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.5.0.tgz",
"integrity": "sha512-lOO9clmdgssDykiOmVQQitwBAF3I6mYcQAo7hQ7AM6Ny5X7fp8hIJ3HcQs3Rjz4SoggoxA1OgrQyY8EgTbcPYw==",
"dependencies": {
"backo2": "1.0.2",
"component-bind": "1.0.0",
"component-emitter": "~1.3.0",
"debug": "~3.1.0",
"engine.io-client": "~3.5.0",
"has-binary2": "~1.0.2",
"indexof": "0.0.1",
"parseqs": "0.0.6",
"parseuri": "0.0.6",
"socket.io-parser": "~3.3.0",
"to-array": "0.1.4"
}
},
"node_modules/socket.io-client/node_modules/debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/socket.io-client/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/socket.io-parser": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.3.tgz",
"integrity": "sha512-qOg87q1PMWWTeO01768Yh9ogn7chB9zkKtQnya41Y355S0UmpXgpcrFwAgjYJxu9BdKug5r5e9YtVSeWhKBUZg==",
"dependencies": {
"component-emitter": "~1.3.0",
"debug": "~3.1.0",
"isarray": "2.0.1"
}
},
"node_modules/socket.io-parser/node_modules/debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/socket.io-parser/node_modules/isarray": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ=="
},
"node_modules/socket.io-parser/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/sockjs": { "node_modules/sockjs": {
"version": "0.3.24", "version": "0.3.24",
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
@ -13576,11 +13246,6 @@
"deprecated": "See https://github.com/lydell/source-map-url#deprecated", "deprecated": "See https://github.com/lydell/source-map-url#deprecated",
"dev": true "dev": true
}, },
"node_modules/spark-md5": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.2.tgz",
"integrity": "sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw=="
},
"node_modules/spdx-correct": { "node_modules/spdx-correct": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
@ -13672,7 +13337,8 @@
"node_modules/sprintf-js": { "node_modules/sprintf-js": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
"dev": true
}, },
"node_modules/sshpk": { "node_modules/sshpk": {
"version": "1.18.0", "version": "1.18.0",
@ -14459,11 +14125,6 @@
"node": ">=0.6.0" "node": ">=0.6.0"
} }
}, },
"node_modules/to-array": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
"integrity": "sha512-LhVdShQD/4Mk4zXNroIQZJC+Ap3zgLcDuwEdcmLv9CCO73NWockQDwyUnW/m8VX/EElfL6FcYx7EeutN4HJA6A=="
},
"node_modules/to-arraybuffer": { "node_modules/to-arraybuffer": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
@ -14988,6 +14649,7 @@
"version": "4.4.1", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"dev": true,
"dependencies": { "dependencies": {
"punycode": "^2.1.0" "punycode": "^2.1.0"
} }
@ -15160,6 +14822,7 @@
"version": "8.3.2", "version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true,
"bin": { "bin": {
"uuid": "dist/bin/uuid" "uuid": "dist/bin/uuid"
} }
@ -15260,25 +14923,6 @@
"eslint": ">=5.0.0" "eslint": ">=5.0.0"
} }
}, },
"node_modules/vue-friendly-iframe": {
"version": "0.17.0",
"resolved": "https://registry.npmjs.org/vue-friendly-iframe/-/vue-friendly-iframe-0.17.0.tgz",
"integrity": "sha512-2IEHRpz2KIZ7wSXd3h1n6EEQ9HEU6GRC4DNdQ7w5Dm31Udf/xGjWfHErXJUsUw3Qal0fga8SrA6aOPTOX7mg+Q==",
"dev": true,
"dependencies": {
"uuid": "3.1.0"
}
},
"node_modules/vue-friendly-iframe/node_modules/uuid": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
"integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"dev": true,
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/vue-hot-reload-api": { "node_modules/vue-hot-reload-api": {
"version": "2.3.4", "version": "2.3.4",
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",
@ -15500,18 +15144,6 @@
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
"dev": true "dev": true
}, },
"node_modules/vue-tour": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/vue-tour/-/vue-tour-1.6.0.tgz",
"integrity": "sha512-INVkuv3kIqulM3R90W1EF4XzFzOt34y6F0BEOunH+DcIwRVrWvBT/HXBu+Dq0RDJswxYbak2JQto58ep3rULRw==",
"dev": true,
"dependencies": {
"hash-sum": "^2.0.0",
"jump.js": "^1.0.2",
"popper.js": "^1.16.0",
"vue": "^2.6.10"
}
},
"node_modules/vue/node_modules/@vue/compiler-sfc": { "node_modules/vue/node_modules/@vue/compiler-sfc": {
"version": "2.7.16", "version": "2.7.16",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.16.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.16.tgz",
@ -15575,11 +15207,6 @@
"vue": "^2.0.0" "vue": "^2.0.0"
} }
}, },
"node_modules/vuvuzela": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/vuvuzela/-/vuvuzela-1.0.3.tgz",
"integrity": "sha512-Tm7jR1xTzBbPW+6y1tknKiEhz04Wf/1iZkcTJjSFcpNko43+dFW6+OOeQe9taJIug3NdfUAjFKgUSyQrIKaDvQ=="
},
"node_modules/watchpack": { "node_modules/watchpack": {
"version": "1.7.5", "version": "1.7.5",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz",
@ -16545,34 +16172,6 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/ws": {
"version": "7.4.6",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
"integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
"engines": {
"node": ">=8.3.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/xmlhttprequest-ssl": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz",
"integrity": "sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/xtend": { "node_modules/xtend": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
@ -16691,11 +16290,6 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/yeast": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
"integrity": "sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg=="
},
"node_modules/yorkie": { "node_modules/yorkie": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/yorkie/-/yorkie-2.0.0.tgz", "resolved": "https://registry.npmjs.org/yorkie/-/yorkie-2.0.0.tgz",

View file

@ -7,14 +7,11 @@
"scripts": { "scripts": {
"gv": "genversion src/version.js", "gv": "genversion src/version.js",
"serve": "npm run gv && vue-cli-service serve --mode development", "serve": "npm run gv && vue-cli-service serve --mode development",
"serve-without-imjoy": "npm run gv && VUE_APP_ENABLE_IMJOY=false vue-cli-service serve --mode development",
"build": "npm run gv && vue-cli-service build --openssl-legacy-provider --mode production", "build": "npm run gv && vue-cli-service build --openssl-legacy-provider --mode production",
"build-without-imjoy": "npm run gv && VUE_APP_ENABLE_IMJOY=false vue-cli-service build --mode production",
"lint": "vue-cli-service lint", "lint": "vue-cli-service lint",
"lint:fix": "vue-cli-service lint --fix" "lint:fix": "vue-cli-service lint --fix"
}, },
"dependencies": { "dependencies": {
"imjoy-core": "^0.13",
"material-design-icons": "^3.0", "material-design-icons": "^3.0",
"material-symbols": "^0.14.3", "material-symbols": "^0.14.3",
"mousetrap": "^1.6.5", "mousetrap": "^1.6.5",
@ -39,9 +36,7 @@
"prettier": "^1.19", "prettier": "^1.19",
"uikit": "^3.17", "uikit": "^3.17",
"vue": "^2.7", "vue": "^2.7",
"vue-friendly-iframe": "^0.17",
"vue-template-compiler": "^2.7", "vue-template-compiler": "^2.7",
"vue-tour": "^1.6",
"vuejs-paginate": "^2.1", "vuejs-paginate": "^2.1",
"vuex": "^3.6" "vuex": "^3.6"
}, },

View file

@ -1,43 +0,0 @@
<docs>
[TODO: write documentation for this plugin.]
</docs>
<config lang="json">
{
"name": "List services",
"type": "web-worker",
"tags": [],
"ui": "",
"version": "0.1.0",
"cover": "",
"description": "List the available ImJoy services in the console",
"icon": "extension",
"inputs": null,
"outputs": null,
"api_version": "0.1.8",
"env": "",
"permissions": [],
"requirements": [],
"dependencies": []
}
</config>
<script lang="javascript">
class ImJoyPlugin {
async setup() {
api.log('initialized')
}
async run(ctx) {
// get a list of service
const services = await api.getServices({name: "OpenFlexure"});
console.log("OpenFlexure services:");
console.log(services);
const allservices = await api.getServices();
console.log("All services:");
console.log(allservices);
}
}
api.export(new ImJoyPlugin())
</script>

View file

@ -1,131 +0,0 @@
<config lang="json">
{
"name": "Script Editor",
"type": "web-worker",
"tags": [],
"ui": "",
"version": "0.1.0",
"cover": "",
"description": "A Script Editor for Controlling OpenFlexure Microscope with ImJoy",
"icon": "extension",
"inputs": null,
"outputs": null,
"api_version": "0.1.8",
"env": "",
"permissions": [],
"requirements": [],
"dependencies": []
}
</config>
<script lang="javascript">
class ImJoyPlugin {
async setup() {
api.log('initialized')
}
async run(ctx) {
let pluginInEditor, stopped, editorWindow;
const config = {lang: 'javascript'}
config.templates = [
{
name: "New",
url: null,
lang: 'javascript',
},
{
name: "Snap Image Template",
url: "./OpenFlexureSnapImageTemplate.imjoy.html",
lang: "html",
}
]
config.ui_elements = {
save: {
_rintf: true,
type: 'button',
label: "Save",
visible: false,
icon: "content-save",
callback(content) {
console.log(content)
}
},
run: {
_rintf: true,
type: 'button',
label: "Run",
icon: "play",
visible: true,
shortcut: 'Shift-Enter',
async callback(content) {
try {
editorWindow.setLoader(true);
editorWindow.updateUIElement('stop', {
visible: true
})
api.showProgress(0);
pluginInEditor = await api.getPlugin({src: content, hot_reloading: true})
if (stopped) {
pluginInEditor = null;
return;
}
if (pluginInEditor && pluginInEditor.run) {
return await pluginInEditor.run({
config: {},
data: {}
});
}
if (stopped) {
pluginInEditor = null;
return;
}
} catch (e) {
api.showMessage("Failed to load plugin, error: " + e.toString());
} finally {
editorWindow.updateUIElement('stop', {
visible: false
})
editorWindow.setLoader(false);
api.showProgress(100);
}
}
},
stop: {
_rintf: true,
type: 'button',
label: "Stop",
style: "color: #ff0080cf;",
icon: "stop",
visible: false,
async callback() {
stopped = true;
await editorWindow.setLoader(false);
await editorWindow.updateUIElement('stop', {
visible: false
})
}
},
export: {
_rintf: true,
type: 'button',
label: "Export",
icon: "file-download-outline",
visible: true,
async callback(content) {
const fileName = (pluginInEditor && pluginInEditor.config.name && pluginInEditor.config.name + '.imjoy.html') || config.name + '.imjoy.html' || "myPlugin.imjoy.html";
await api.exportFile(content, fileName);
}
}
}
editorWindow = await api.createWindow({
src: 'https://if.imjoy.io',
name: (ctx && ctx.data && ctx.data.name) ||'OpenFlexure Script Editor',
config,
data: {code: ctx && ctx.data && ctx.data.code}
})
}
}
api.export(new ImJoyPlugin())
</script>

View file

@ -1,43 +0,0 @@
<docs>
[TODO: write documentation for this plugin.]
</docs>
<config lang="json">
{
"name": "OpenFlexureSnapImageTemplate",
"type": "web-worker",
"tags": [],
"ui": "",
"version": "0.1.0",
"cover": "",
"description": "[TODO: describe this plugin with one sentence.]",
"icon": "extension",
"inputs": null,
"outputs": null,
"api_version": "0.1.8",
"env": "",
"permissions": [],
"requirements": [],
"dependencies": []
}
</config>
<script lang="javascript">
class ImJoyPlugin {
async setup() {
api.log('initialized')
}
async run(ctx) {
// get a list of service
const services = await api.getServices({name: "OpenFlexure"});
// get the first service
const ofm = services[0];
// snap an image
await ofm.snapImage();
console.log("snapped an image");
}
}
api.export(new ImJoyPlugin())
</script>

View file

@ -1,50 +0,0 @@
<docs>
[TODO: write documentation for this plugin.]
</docs>
<config lang="json">
{
"name": "Test OFM Stage",
"type": "web-worker",
"tags": [],
"ui": "",
"version": "0.1.0",
"cover": "",
"description": "Move the OFM stage to test the API works",
"icon": "extension",
"inputs": null,
"outputs": null,
"api_version": "0.1.8",
"env": "",
"permissions": [],
"requirements": [],
"dependencies": []
}
</config>
<script lang="javascript">
class ImJoyPlugin {
async setup() {
api.log('initialized')
}
async run(ctx) {
// get a list of service
const services = await api.getServices({name: "OpenFlexure"});
// get the first service
const ofm = services[0];
// snap an image
const start = await ofm.getXYZPosition();
console.log(`Starting position: ${start}`);
// move the Z axis up and down
await ofm.setPosition(start[2] + 100);
console.log(`Moved Z to ${await ofm.getPosition()}`);
await ofm.setPosition(start[2]);
console.log(`Moved Z to ${await ofm.getPosition()}`);
await ofm.fullFocus();
console.log("Ran a full autofocus");
}
}
api.export(new ImJoyPlugin())
</script>

View file

@ -5,7 +5,6 @@
:class="handleTheme" :class="handleTheme"
> >
<loadingContent v-if="!$store.getters.ready" /> <loadingContent v-if="!$store.getters.ready" />
<div v-if="$store.getters.ready" id="tour-header"></div>
<appContent v-if="$store.getters.ready" /> <appContent v-if="$store.getters.ready" />
<!-- Runtime modals --> <!-- Runtime modals -->
<div <div
@ -27,13 +26,6 @@
</div> </div>
</div> </div>
</div> </div>
<v-tour
v-show="$store.getters.ready"
name="guidedTour"
:steps="tourSteps"
:callbacks="tourCallbacks"
:options="{ highlight: true }"
></v-tour>
</div> </div>
</template> </template>
@ -79,12 +71,7 @@ export default {
arrowKeysDown: {}, arrowKeysDown: {},
keyboardManual: [], keyboardManual: [],
systemDark: undefined, systemDark: undefined,
themeObserver: undefined, themeObserver: undefined
tourCallbacks: {
onStop: () => {
this.setLocalStorageObj("completedTour", true);
}
}
}; };
}, },
@ -112,68 +99,6 @@ export default {
"uk-light": isDark, "uk-light": isDark,
"uk-background-secondary": isDark "uk-background-secondary": isDark
}; };
},
tourSteps: function() {
let tabPopperParams = {
modifiers: {
preventOverflow: {
boundariesElement: "window"
}
},
placement: "right"
};
return [
{
target: "#tour-header", // We're using document.querySelector() under the hood
header: {
title: "Welcome to the OpenFlexure Microscope"
},
content: `Click Next to learn how to use your microscope`,
params: {
placement: "bottom"
}
},
{
target: "#gallery-tab-icon",
header: {
title: "Capture gallery"
},
content: `View and download your microscope images from the gallery tab`,
params: tabPopperParams
},
{
target: "#navigate-tab-icon",
header: {
title: "Navigate around your sample"
},
content: `Move your microscope stage and perform autofocus from the navigate tab`,
params: tabPopperParams
},
{
target: "#capture-tab-icon",
header: {
title: "Capture microscope images"
},
content: `Take images and simple tile scans from the capture tab`,
params: tabPopperParams
},
{
target: "#settings-tab-icon",
header: {
title: "Change settings"
},
content: `Change app and microscope settings, including microscope calibration, from the settings tab`,
params: tabPopperParams
},
{
target: "#extension-tab-divider",
header: {
title: "Microscope extensions"
},
content: `Extensions installed on your microscope will appear below this line`,
params: tabPopperParams
}
];
} }
}, },
@ -194,12 +119,6 @@ export default {
}); });
// Check connection to API // Check connection to API
this.checkConnection(); this.checkConnection();
// Handle guided tour
// If the user has already completed or skipped the guided tour
var completedTour = this.getLocalStorageObj("completedTour") || true;
if (!completedTour) {
this.$tours["guidedTour"].start();
}
}, },
created: function() { created: function() {
@ -443,57 +362,4 @@ html {
overflow-y: hidden; overflow-y: hidden;
} }
// Style tour
.v-tour__target--highlighted {
box-shadow: 0px 40px 200px 30px rgba(0, 0, 0, 0.5),
0px 0px 0px 4px rgba(128, 128, 128, 0.5) !important;
border-radius: 5px;
opacity: 100% !important;
pointer-events: none !important;
}
.v-step {
background: @global-primary-background !important;
}
.v-step__header {
background-color: darken(@global-primary-background, 7%) !important;
}
.v-step__button {
font-size: 0.9rem !important;
}
// Change step arrow colour
// This is awful and hacky and makes me sad, but needs must
.v-step .v-step__arrow {
border-color: darken(@global-primary-background, 7%) !important;
&--dark {
border-color: darken(@global-primary-background, 7%) !important;
}
}
.v-step[x-placement^="top"] .v-step__arrow {
border-left-color: transparent !important;
border-right-color: transparent !important;
border-bottom-color: transparent !important;
}
.v-step[x-placement^="bottom"] .v-step__arrow {
border-left-color: transparent !important;
border-right-color: transparent !important;
border-top-color: transparent !important;
}
.v-step[x-placement^="right"] .v-step__arrow {
border-left-color: transparent !important;
border-top-color: transparent !important;
border-bottom-color: transparent !important;
}
.v-step[x-placement^="left"] .v-step__arrow {
border-top-color: transparent !important;
border-right-color: transparent !important;
border-bottom-color: transparent !important;
}
</style> </style>

View file

@ -40,25 +40,6 @@
<hr v-if="item.divide" :key="'tab-divider-' + index" /> <hr v-if="item.divide" :key="'tab-divider-' + index" />
</template> </template>
<tabIcon
v-for="imjoyTab in imjoyTabs"
:key="imjoyTab.id"
:tab-i-d="'ImJoy-Plugin-' + imjoyTab.id"
:title="imjoyTab.name"
:require-connection="false"
:current-tab="currentTab"
@set-tab="setTab"
>
<img
v-if="imjoyTab.iconURL"
style="filter: grayscale(100%);width: 22px;margin-top: 5px;margin-bottom: 8px;"
:src="imjoyTab.iconURL"
/>
<span v-if="!imjoyTab.iconURL" class="material-symbols-outlined">
{{ imjoyTab.iconName || "extension" }}
</span>
</tabIcon>
<hr id="extension-tab-divider" /> <hr id="extension-tab-divider" />
<!-- For each bottom tab --> <!-- For each bottom tab -->
@ -98,15 +79,6 @@
<component :is="item.component"></component> <component :is="item.component"></component>
</tabContent> </tabContent>
<tabContent
v-for="imjoyTab in imjoyTabs"
:key="imjoyTab.id"
:tab-i-d="'ImJoy-Plugin-' + imjoyTab.id"
:require-connection="false"
:current-tab="currentTab"
>
<div :id="imjoyTab.window_id" class="window-container">Loading...</div>
</tabContent>
<!-- For each bottom tab --> <!-- For each bottom tab -->
<tabContent <tabContent
@ -124,7 +96,6 @@
</template> </template>
<script> <script>
import { mapState } from "vuex";
// Import generic components // Import generic components
import tabIcon from "./genericComponents/tabIcon"; import tabIcon from "./genericComponents/tabIcon";
@ -139,11 +110,6 @@ import settingsContent from "./tabContentComponents/settingsContent.vue";
import aboutContent from "./tabContentComponents/aboutContent.vue"; import aboutContent from "./tabContentComponents/aboutContent.vue";
import loggingContent from "./tabContentComponents/loggingContent.vue"; import loggingContent from "./tabContentComponents/loggingContent.vue";
import powerContent from "./tabContentComponents/powerContent.vue"; import powerContent from "./tabContentComponents/powerContent.vue";
// ImJoy is loaded asynchronously to allow it to be disabled if needed
const imjoyContent = () =>
import(
/* webpackChunkName: "imjoy" */ "./tabContentComponents/imjoyContent.vue"
);
// Import modal components for device initialisation // Import modal components for device initialisation
import calibrationModal from "./modalComponents/calibrationModal.vue"; import calibrationModal from "./modalComponents/calibrationModal.vue";
@ -166,7 +132,6 @@ export default {
loggingContent, loggingContent,
TabIcon, TabIcon,
powerContent, powerContent,
imjoyContent
}, },
data: function() { data: function() {
return { return {
@ -240,24 +205,12 @@ export default {
if (!this.$store.state.galleryEnabled) { if (!this.$store.state.galleryEnabled) {
tabs = tabs.filter(tab => tab.id != "gallery"); tabs = tabs.filter(tab => tab.id != "gallery");
} }
if (this.$store.state.imjoyEnabled) {
tabs.push({
id: "imjoy",
iconURL: "https://imjoy.io/static/img/imjoy-icon.svg",
component: imjoyContent,
divide: true
});
}
return tabs; return tabs;
}, },
currentTabIndex: function() { currentTabIndex: function() {
return this.tabOrder.indexOf(this.currentTab); return this.tabOrder.indexOf(this.currentTab);
}, }
// Map the tabs from ImJoy's store module so we can display them
...mapState("imjoy", { imjoyTabs: "tabs" }),
...mapState({ imjoyEnabled: "imjoyEnabled" })
}, },
mounted() { mounted() {

View file

@ -62,10 +62,6 @@ export default {
this.$store.commit("changeOrigin", this.newOrigin); this.$store.commit("changeOrigin", this.newOrigin);
event.preventDefault(); event.preventDefault();
} }
},
resetTour: function() {
// Make the introduction tour run next time the app loads
this.setLocalStorageObj("completedTour", false);
} }
} }
}; };

View file

@ -1,25 +0,0 @@
<template>
<!-- Grid managing tab content -->
<div uk-grid class="uk-height-1-1 uk-margin-remove uk-padding-remove">
<div class="control-component">
<paneCapture />
</div>
<div class="view-component uk-width-expand">
<streamDisplay />
</div>
</div>
</template>
<script>
import paneCapture from "./captureComponents/paneCapture";
import streamDisplay from "./streamContent.vue";
export default {
name: "CaptureContent",
components: {
paneCapture,
streamDisplay
}
};
</script>

View file

@ -1,58 +0,0 @@
<template>
<!-- Grid managing tab content -->
<div uk-grid class="uk-height-1-1 uk-margin-remove uk-padding-remove">
<div class="control-component">
<vue-friendly-iframe v-if="frame" :src="frame.href"></vue-friendly-iframe>
<!-- OpenFlexure Forms used to be handled here - should now be done another way. -->
</div>
<div class="view-component uk-width-expand">
<galleryContent v-if="viewPanel == 'gallery'" />
<settingsContent v-else-if="viewPanel == 'settings'" />
<streamDisplay v-else />
</div>
</div>
</template>
<script>
import streamDisplay from "./streamContent.vue";
import galleryContent from "../tabContentComponents/galleryContent.vue";
import settingsContent from "../tabContentComponents/settingsContent.vue";
export default {
name: "ExtensionContent",
components: {
streamDisplay,
galleryContent,
settingsContent
},
props: {
forms: {
type: Array,
required: false,
default: () => []
},
frame: {
type: Object,
required: false,
default: null
},
viewPanel: {
type: String,
required: false,
default: "stream"
}
}
};
</script>
<style>
.vue-friendly-iframe {
height: 100%;
}
.vue-friendly-iframe iframe {
height: 100%;
}
</style>

View file

@ -1,62 +0,0 @@
<template>
<div
class="uk-card uk-card-hover uk-card-small uk-card-default uk-margin"
:class="{ 'uk-card-secondary': $store.state.darkMode }"
>
<div class="uk-card-body">
<div class="uk-grid-small uk-flex-middle" uk-grid>
<div class="uk-width-auto">
<img
v-if="iconURL"
style="height:50px"
:data-src="iconURL"
:alt="name + ' icon'"
uk-img
/>
<span
v-if="!iconURL"
class="material-symbols-outlined"
style="font-size:50px"
>
{{ iconName }}
</span>
</div>
<div class="uk-width-expand">
<h3 class="uk-card-title uk-margin-remove-bottom">{{ name }}</h3>
<p class="uk-text-meta uk-margin-remove-top">
<slot name="subtitle"></slot>
</p>
</div>
<div class="uk-width-auto">
<button class="uk-button" @click="$emit('click')">
<slot name="buttonText">Launch</slot>
</button>
</div>
</div>
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: "ImjoyPluginCard",
props: {
name: {
type: String,
required: true
},
iconURL: {
type: String,
required: false,
default: () => ""
},
iconName: {
type: String,
required: false,
default: () => "extension"
}
}
};
</script>

View file

@ -1,644 +0,0 @@
<template>
<!-- Grid managing tab content -->
<div class="uk-height-1-1 view-component">
<progress
ref="imjoyProgressbar"
style="height: 4px; margin-bottom:0!important"
class="uk-progress"
max="100"
></progress>
<div
class="uk-flex uk-flex-column uk-margin uk-margin-left uk-margin-right"
>
<imjoy-plugin-card
name="Load From URL"
icon-u-r-l="https://imjoy.io/static/img/imjoy-icon.svg"
@click="loadPluginDialog()"
>
<template v-slot:buttonText>Open</template>
</imjoy-plugin-card>
<imjoy-plugin-card
name="ImageJ.JS"
icon-u-r-l="https://ij.imjoy.io/assets/icons/chrome/chrome-installprocess-128-128.png"
@click="openImageJ()"
/>
<imjoy-plugin-card
name="Kaibu"
icon-u-r-l="https://kaibu.org/static/img/kaibu-icon.svg"
@click="startKaibu()"
/>
<imjoy-plugin-card
v-for="(p, name) in loadedPlugins"
:key="p.id"
:name="name"
icon-name="extension"
@click="runPlugin(p)"
/>
</div>
<div v-show="loading" class="progress uk-margin-small">
<div class="indeterminate"></div>
</div>
</div>
</template>
<script>
import * as imjoyCore from "imjoy-core";
import axios from "axios";
import UIkit from "uikit";
import { mapState } from "vuex";
import ImjoyPluginCard from "./imjoyComponents/imjoyPluginCard.vue";
// TODO: move this to a module or something...
async function pollAction(response) {
// Poll an action until its status is completed
// TODO: raise an error if it fails or is cancelled
// For ease, this accepts and returns a response object from
// axios.get
// FIXME: this could be an infinite loop if the task is cancelled/errored
let r = response;
while ((r.data.status == "running") | (r.data.status == "pending")) {
await new Promise(resolve => setTimeout(resolve, 100));
r = await axios.get(r.data.href);
}
return r;
}
/**
* Create a new Image element and wait for it to load.
*
* This returns a Promise, so you can "await" the image
* element rather than needing to add a callback.
*/
function loadImageFromUrl(src) {
// Create an Image, and return it once it has loaded
// see https://stackoverflow.com/a/66180709
// no need to declare async, as it returns a Promise
return new Promise((resolve, reject) => {
const img = new Image();
// We must set crossOrigin="anonymous" in order
// to avoid security errors when we get the pixel
// data
img.crossOrigin = "anonymous";
img.onload = () => resolve(img);
img.onerror = reject;
img.src = src;
});
}
/**
* Retrieve an image from a URL, and return the RGB data
* in a format that can be cast to an ndarray
*
* This follows a slightly convoluted recipe, where we
* "draw" the image, and then extract the pixels from the
* 2D canvas.
*/
async function imageUrlToNdarray(url) {
// see https://stackoverflow.com/questions/934012/get-image-data-url-in-javascript
const img = await loadImageFromUrl(url);
const canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, img.width, img.height);
const imageData = ctx.getImageData(0, 0, img.width, img.height);
const rgbaData = imageData.data; // This gets the RGBA values as an ArrayBuffer
// convert RGBA to RGB
const rgbData = new Uint8Array(new ArrayBuffer(img.height * img.width * 3));
for (let i = 0; i < img.height; i++) {
for (let j = 0; j < img.width; j++) {
const pos = i * img.width + j;
rgbData[pos * 3] = rgbaData[pos * 4];
rgbData[pos * 3 + 1] = rgbaData[pos * 4 + 1];
rgbData[pos * 3 + 2] = rgbaData[pos * 4 + 2];
}
}
return {
_rtype: "ndarray",
_rdtype: "uint8",
_rshape: [img.height, img.width, 3],
_rvalue: rgbData.buffer
};
}
export default {
name: "ImJoyContent",
components: { ImjoyPluginCard },
data() {
return {
loading: false,
loadedPlugins: {},
viewers: {}
};
},
computed: {
captureActionUri: function() {
return `${this.$store.getters.baseUri}/api/v2/actions/camera/capture`;
},
snapshotStreamUri: function() {
return `${this.$store.getters.baseUri}/api/v2/streams/snapshot`;
},
getPositionUri: function() {
return `${this.$store.getters.baseUri}/api/v2/instrument/state/stage/position`;
},
moveActionUri: function() {
return `${this.$store.getters.baseUri}/api/v2/actions/stage/move`;
},
baseUri: function() {
return this.$store.getters.baseUri;
},
...mapState("imjoy", { windows: "tabs" })
},
mounted() {
const self = this;
const imjoy = new imjoyCore.ImJoy({
// We will load the ImJoy plugin base frame via http (instead of https)
// such that imjoy plugins can access insecured urls
// however, some browser features won't work (e.g. webrtc)
// unless we explicitly set `base_frame` in the plugin to
// https://lib.imjoy.io/default_base_frame.html
default_base_frame: "http://lib.imjoy.io/default_base_frame.html",
imjoy_api: {
async showDialog(plugin, config, exta_config) {
return await imjoy.pm.createWindow(plugin, config, exta_config);
},
async showSnackbar(plugin, msg, duration) {
duration = duration || 5;
UIkit.notification.closeAll();
UIkit.notification({
message: msg.slice(0, 100),
status: "primary",
pos: "bottom-center",
timeout: duration * 1000
});
},
async showMessage(plugin, msg) {
imjoy.imjoy_api.showSnackbar(plugin, msg, 5);
},
async showStatus(plugin, status) {
imjoy.imjoy_api.showSnackbar(plugin, status, 5);
},
async showProgress(plugin, p) {
p = p || 0;
if (p < 1.0) p = p * 100;
if (p > 100) p = 100;
if (p) {
self.$refs.imjoyProgressbar.style.display = "block";
self.$refs.imjoyProgressbar.value = parseInt(p);
} else {
self.$refs.imjoyProgressbar.style.display = "none";
}
}
}
});
imjoy.start({ workspace: "default" }).then(async () => {
console.log("ImJoy started");
imjoy.event_bus.on("add_window", w => {
this.addWindow(w);
});
this.setupMicroscopeAPI();
this.setupViewers();
const origin = window.location.origin;
const localPlugins = [
"OpenFlexureSnapImageTemplate",
"OpenFlexureScriptEditor",
"OpenFlexureTestMoveStage",
"ListServices"
];
for (let fname of localPlugins) {
await this.loadPlugin(`${origin}/${fname}.imjoy.html`);
}
this.setupPluginEngine();
});
this.imjoy = imjoy;
},
methods: {
setupPluginEngine() {
// setup a plugin engine for Python plugins
this.imjoy.pm
.reloadPluginRecursively({
uri:
"https://imjoy-team.github.io/jupyter-engine-manager/Jupyter-Engine-Manager.imjoy.html"
})
.then(enginePlugin => {
// TODO: currently the url query are not preserved for ImJoy
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const engine = urlParams.get("engine");
const spec = urlParams.get("spec");
if (engine) {
enginePlugin.api
.createEngine({
name: "MyCustomEngine",
nbUrl: engine,
url: engine.split("?")[0]
})
.then(() => {
console.log("Jupyter Engine connected!");
})
.catch(e => {
console.error("Failed to connect to Jupyter Engine", e);
});
} else {
enginePlugin.api
.createEngine({
name: "MyBinder Engine",
url: "https://mybinder.org",
spec: spec || "oeway/imjoy-binder-image/master"
})
.then(() => {
console.log("Binder Engine connected!");
})
.catch(e => {
console.error("Failed to connect to MyBinder Engine", e);
});
}
});
},
async setupMicroscopeAPI() {
// Here we register a set of API for controlling the microscope as a service
// For interoperatability, it might be good to reuse a subset of the function names defined in MicroManager
// See here: https://valelab4.ucsf.edu/~MM/doc/MMCore/html/class_c_m_m_core.html
const snapshotUri = this.snapshotStreamUri;
const captureActionUri = this.captureActionUri;
const modalError = this.modalError;
const getPositionAsObject = this.getStagePosition;
const setPositionAsObject = this.setStagePosition;
const getInstrumentSettings = this.getInstrumentSettings;
const setInstrumentSettings = this.setInstrumentSettings;
const runAutofocus = this.runAutofocus;
const service = {
_rintf: true, // this will make sure the function can be called multiple times
type: "#microscope-control",
name: "OpenFlexure",
lastSnapResponse: null,
snapPreviewImage() {
// The "proper" capture method is more involved - this one pulls a frame out of the preview stream
return axios
.get(snapshotUri)
.then(response => {
return response.data;
})
.catch(modalError);
},
snapImage() {
// Do capture
return axios.post(captureActionUri, {}).then(response => {
service.lastSnapResponse = response;
// TODO: send the events to flash the stream and update captures
// Flash the stream (capture animation)
//this.$root.$emit("globalFlashStream");
// Update the global capture list
//this.$root.$emit("globalUpdateCaptures");
});
//.catch(modalError);
},
async getImage() {
// FIXME: handle nicely getImage() being called before snapImage()
// Wait until the capture has completed and we can retrieve it
service.lastSnapResponse = await pollAction(service.lastSnapResponse);
let capture = service.lastSnapResponse.data.output;
// TODO: check links.download.href exists and is JPEG
let jpeg = await axios
.get(capture.links.download.href, {
responseType: "arraybuffer",
headers: {
"Content-Type": "image/jpeg"
}
})
.then(r => r.data);
console.log(
"Downloaded ",
jpeg.byteLength,
" bytes of JPEG image data"
);
return jpeg; //TODO: what is the expected output format???
},
setPosition(z) {
// The C api suggests this defaults to just Z, and can accept a "label" to
// select the stage.
return setPositionAsObject({
z: z,
absolute: true
});
},
async getPosition() {
const { z } = await getPositionAsObject();
return z;
},
async setXYPosition(x, y) {
return setPositionAsObject({
x: x,
y: y,
absolute: true
});
},
async getXYPosition() {
const { x, y } = await getPositionAsObject();
return [x, y];
},
async getXYZPosition() {
const { x, y, z } = await getPositionAsObject();
return [x, y, z];
},
async setXYZPosition(x, y, z) {
return setPositionAsObject({
x: x,
y: y,
z: z,
absolute: true
});
},
async getExposure() {
const settings = await getInstrumentSettings();
if (settings.camera.picamera) {
if (settings.camera.picamera.shutter_speed) {
return settings.camera.picamera.shutter_speed / 1000;
}
}
return -1;
},
async setExposure(exposure) {
setInstrumentSettings({
camera: {
picamera: {
shutter_speed: exposure * 1000
}
}
});
},
async fullFocus() {
return runAutofocus();
}
};
const ref = await this.imjoy.pm.registerService(
{ type: "#microscope-control", name: "OpenFlexure" },
service
);
console.log("registered service");
console.log(ref);
},
closeWindow(w) {
if (w) {
w.api.close();
this.$store.commit("imjoy/removeTab", w);
}
},
/**
* Activate a window - you can pass the window object, its name, or its id.
*/
selectWindow(window) {
for (let w of this.windows) {
if ((w === window) | (w.name === window) | (w.id === window)) {
// Make the relevant window visible by switching to its tab
this.$root.$emit("globalSwitchTab", `ImJoy-Plugin-${w.id}`);
break;
}
}
},
setWindowIconUrl(window, iconURL) {
this.$store.commit("imjoy/setTabProperty", {
tab: window,
key: "iconURL",
value: iconURL
});
},
async startKaibu() {
this.viewers.kaibu = await this.imjoy.pm.createWindow(null, {
name: "Kaibu",
src: "https://kaibu.org/#/app"
});
this.viewers.kaibu.on("close", () => {
delete this.viewers.kaibu;
});
this.setWindowIconUrl(
this.viewers.kaibu.config.id,
"https://kaibu.org/static/img/kaibu-icon.svg"
);
this.viewers.kaibu.set_mode("full");
},
async startImageJ() {
this.viewers.imagej = await this.imjoy.pm.createWindow(null, {
name: "ImageJ.JS",
src: "https://ij.imjoy.io"
});
this.viewers.imagej.on("close", () => {
delete this.viewers.imagej;
});
this.setWindowIconUrl(
this.viewers.imagej.config.id,
"https://ij.imjoy.io/assets/icons/chrome/chrome-installprocess-128-128.png"
);
// load the ITK/VTK viewer for imagej.js
this.loadPlugin(
"https://gist.githubusercontent.com/oeway/e5c980fbf6582f25fde795262a7e33ec/raw/itk-vtk-viewer-imagej.imjoy.html"
);
},
/**
* Switch to the ImageJ window, starting it if necessary.
*/
async openImageJ() {
if (!this.viewers.imagej) {
await this.startImageJ();
}
this.selectWindow("ImageJ.JS");
return this.viewers.imagej;
},
/**
* Switch to the Kaibu window, starting it if necessary.
*/
async openKaibu() {
if (!this.viewers.kaibu) {
await this.startKaibu();
}
this.selectWindow("Kaibu"); // TODO: make this behave more nicely when we have multiple Kaibu windows
return this.viewers.kaibu;
},
async setupViewers() {
this.loading = true;
// TODO: improve this using the ImJoy `api.getServices`
// See here: https://imjoy.io/docs/#/api?id=apigetservices
// The idea is that plugins can register custom services via `api.registerService`
// For example, we can have a image visualization service
// Then other plugins can use `api.getServices` to get a list of services
// And this can be used for render our "Open In ImJoy" menu
try {
const self = this;
this.$store.commit("imjoy/addOpenImageItem", {
title: "Kaibu",
async callback(name, imageUrl) {
const viewer = await self.openKaibu();
await viewer.view_image(imageUrl, { type: "2d-image", name });
await viewer.add_shapes([]);
}
});
this.$store.commit("imjoy/addOpenImageItem", {
title: "ImageJ.JS",
async callback(name, imageUrl) {
const viewer = await self.openImageJ();
const response = await fetch(imageUrl);
const buffer = await response.arrayBuffer();
await viewer.viewImage(buffer, {
name: name.replace(".jpeg", ".jpg")
});
}
});
this.$store.commit("imjoy/addOpenImageItem", {
title: "ImageJ.JS [ndarray]",
async callback(name, imageUrl) {
const viewer = await self.openImageJ();
const ndarray = await imageUrlToNdarray(imageUrl);
await viewer.viewImage(ndarray, {
name: name.replace(".jpeg", "")
});
}
});
this.$store.commit("imjoy/addOpenScanItem", {
title: "ImageJ.JS [stack]",
async callback(name, allURLs) {
const viewer = await self.openImageJ();
// allURLs is a list of URLs for *capture objects*, so
// first we need to retrieve them, then extract image URLs
// and finally turn image URLs into "numpy arrays" (RGB data).
const imagesAsNdarrays = await Promise.all(
allURLs.map(async url => {
const r = await axios.get(url);
return await imageUrlToNdarray(r.data.links.download.href);
})
);
// Construct an array to hold all the images, based on the first image
// TODO: assert that _rdtype is uint8, _rshape is the same, _rtype is ndarray
const shape = imagesAsNdarrays[0]._rshape;
const totalSize = imagesAsNdarrays.reduce(
(total, image) => total + image._rvalue.byteLength,
0
);
const stackData = new Uint8Array(new ArrayBuffer(totalSize));
const transferredBytes = imagesAsNdarrays.reduce((total, image) => {
console.log(`inserting image at ${total} bytes`);
// TODO: is it bad to populate stackData as a "side effect"?
stackData.set(new Uint8Array(image._rvalue), total);
//assert image._rshape == shape;
return total + image._rvalue.byteLength;
}, 0);
const stackNdarray = {
_rtype: "ndarray",
_rdtype: "uint8",
_rshape: [imagesAsNdarrays.length, shape[0], shape[1], shape[2]],
_rvalue: stackData.buffer
};
console.log(
`Stack is ${transferredBytes} and will have shape: ${stackNdarray._rshape}`
);
await viewer.viewImage(stackNdarray, {
name
});
}
});
} catch (e) {
alert(`Failed to setup viewers, error: ${e}`);
} finally {
this.loading = false;
}
},
async addWindow(w) {
// Here we can add check w.standalone if we want to allow the plugin to decide whether to open in a new tab.
this.$store.commit("imjoy/addTab", w);
await this.$nextTick();
//this.$forceUpdate();
this.selectWindow(w);
},
loadPlugin(uri) {
return new Promise((resolve, reject) => {
this.loading = true;
this.imjoy.pm
.reloadPluginRecursively({
uri
})
.then(async plugin => {
this.loadedPlugins[plugin.name] = plugin;
this.loading = false;
resolve(plugin);
})
.catch(e => {
console.error(e);
this.loading = false;
reject(e);
alert(`failed to load the plugin, error: ${e}`);
});
});
},
async runPlugin(plugin) {
await plugin.api.run();
},
loadPluginDialog() {
const uri = prompt(
"Paste the ImJoy plugin url here",
"imjoy-team/imjoy-plugins:Welcome"
);
if (uri) {
this.loadPlugin(uri);
}
},
async getStagePosition() {
return axios.get(this.getPositionUri).then(r => r.data);
},
async setStagePosition(payload) {
return axios.post(this.moveActionUri, payload).then(pollAction);
},
async getInstrumentSettings() {
return axios
.get(`${this.baseUri}/api/v2/instrument/settings/`)
.then(r => r.data);
},
async setInstrumentSettings(payload) {
return axios.put(`${this.baseUri}/api/v2/instrument/settings/`, payload);
},
runAutofocus() {
// This mechanism is also used by the keybinding for autofocus.
// It means we don't have a way to poll, but that's not a problem.
this.$root.$emit("globalFastAutofocusEvent");
}
}
};
</script>
<style scoped>
.window-container {
width: 100%;
height: 100%;
}
.imjoy-container-card {
width: 100%;
height: 100%;
}
.window-title {
height: 26px;
text-align: center;
font-size: 1.2rem;
background-color: #efefef;
color: #482727;
font-weight: 500;
}
.plugins-button {
position: absolute;
right: 1px;
height: 26px;
line-height: 11px;
}
.close-button {
position: absolute;
right: 100px;
height: 26px;
}
</style>

View file

@ -3,11 +3,9 @@ import App from "./App.vue";
import store from "./store"; import store from "./store";
import axios from "axios"; import axios from "axios";
import UIkit from "uikit"; import UIkit from "uikit";
import VueTour from "vue-tour";
import VueFriendlyIframe from "vue-friendly-iframe";
import VueObserveVisibility from "vue-observe-visibility"; import VueObserveVisibility from "vue-observe-visibility";
require("vue-tour/dist/vue-tour.css");
// Import MD icons // Import MD icons
import "material-symbols/outlined.css"; import "material-symbols/outlined.css";
@ -23,12 +21,6 @@ UIkit.mixin(
"accordion" "accordion"
); );
// Use vue-tour module
Vue.use(VueTour);
// Use Friendly Iframe module
Vue.use(VueFriendlyIframe);
// Use visibility observer // Use visibility observer
Vue.use(VueObserveVisibility); Vue.use(VueObserveVisibility);

View file

@ -4,64 +4,6 @@ import wotStoreModule from "./wot-client";
Vue.use(Vuex); Vue.use(Vuex);
const moduleImjoy = {
namespaced: true,
state: () => ({
tabs: [],
openImageMenu: [],
openScanMenu: []
}),
mutations: {
addOpenImageItem(state, newItem) {
state.openImageMenu.push(newItem);
}, // TODO: add a mutation to remove items when plugins are unloaded
addOpenScanItem(state, newItem) {
state.openScanMenu.push(newItem);
}, // TODO: add a mutation to remove items when plugins are unloaded
clearMenus(state) {
// This is primarily useful to reset the state in hot-reloads of
// imjoyContent.vue
state.openImageMenu = [];
state.openScanMenu = [];
},
addTab(state, newItem) {
// Add a tab to the list of ImJoy tabs
state.tabs.push(newItem);
},
removeTab(state, tabToRemove) {
const index = state.tabs.indexOf(tabToRemove);
if (index > -1) {
state.tabs.splice(index, 1);
} else {
console.warn(
`Attempted to remove a non-existing ImJoy tab ${tabToRemove}`
);
}
},
/**
* Set a parameter on the tab with a given id
*
* Payload should contain:
* tab: ID of the tab to modify (not window_id)
* key: name of the property to add/change
* value: value of the property to add/change
*/
setTabProperty(state, payload) {
let tab = payload.tab;
let key = payload.key;
let value = payload.value;
state.tabs = state.tabs.map(t => {
if (t.id === tab) {
t[key] = value;
}
return t;
});
}
},
actions: {},
getters: {}
};
function getOriginFromLocation() { function getOriginFromLocation() {
// This will default to the same origin that's serving // This will default to the same origin that's serving
// the web app - but can be overridden by the URL. // the web app - but can be overridden by the URL.
@ -77,7 +19,6 @@ function getOriginFromLocation() {
export default new Vuex.Store({ export default new Vuex.Store({
modules: { modules: {
imjoy: moduleImjoy,
wot: wotStoreModule wot: wotStoreModule
}, },
state: { state: {
@ -88,7 +29,6 @@ export default new Vuex.Store({
disableStream: false, disableStream: false,
autoGpuPreview: false, autoGpuPreview: false,
trackWindow: true, trackWindow: true,
imjoyEnabled: false,
galleryEnabled: true, galleryEnabled: true,
appTheme: "system", appTheme: "system",
activeStreams: {}, activeStreams: {},
@ -114,17 +54,6 @@ export default new Vuex.Store({
changeAppTheme(state, theme) { changeAppTheme(state, theme) {
state.appTheme = theme; state.appTheme = theme;
}, },
changeImjoyEnabled(state, enabled) {
if (process.env.VUE_APP_ENABLE_IMJOY === "true") {
state.imjoyEnabled = enabled;
} else {
state.imjoyEnabled = false;
if (enabled)
console.warn(
"Attempted to enable ImJoy, but it's disabled by VUE_APP_ENABLE_IMJOY."
);
}
},
changeGalleryEnabled(state, enabled) { changeGalleryEnabled(state, enabled) {
state.galleryEnabled = enabled; state.galleryEnabled = enabled;
}, },