diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..80bb704 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,24 @@ +## What + + +## Why + + +## How + + +## Testing + + +## Screenshots + + +## Checklist +- [ ] Branch name +- [ ] Target branch +- [ ] Commit messages +- [ ] Squash commits +- [ ] MR name +- [ ] MR Description +- [ ] Tests +- [ ] Browser support verified diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8fd57a9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +node_modules/ +dist/ +loader/ +www/ +*.log +.DS_Store +/.idea/ diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..e69de29 diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..604d86f --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,35 @@ +pipeline { + agent { + label 'aws-small' + } + + tools { + nodejs 'nodejs-22' + } + + stages { + stage('Install Dependencies') { + steps { + sh 'npm ci' + } + } + + stage('Build') { + steps { + sh 'npm run build' + } + } + } + + post { + always { + cleanWs() + } + success { + echo 'Build completed successfully!' + } + failure { + echo 'Build failed!' + } + } +} \ No newline at end of file diff --git a/JenkinsfileRelease b/JenkinsfileRelease new file mode 100644 index 0000000..2c69a71 --- /dev/null +++ b/JenkinsfileRelease @@ -0,0 +1,123 @@ +@Library('ontotext-platform@v0.1.51') _ + +def performCleanup = { + sh "git restore .npmrc" +} + +pipeline { + agent { + label 'aws-small' + } + + tools { + nodejs 'nodejs-22' + } + + parameters { + gitParameter name: 'GIT_BRANCH', + description: 'The Git branch to build', + branchFilter: 'origin/(.*)', + defaultValue: 'main', + selectedValue: 'DEFAULT', + type: 'PT_BRANCH', + listSize: '0', + quickFilterEnabled: true + + string name: 'RELEASE_VERSION', + description: 'Version to release', + defaultValue: '' + + booleanParam( + name: 'NOTIFY_SLACK', + defaultValue: true, + description: 'Send Slack notification after successful build' + ) + + string( + name: 'SLACK_CHANNEL', + defaultValue: '#frontend-notifications', + description: 'Slack channel for notification (only used if checkbox above is selected)' + ) + } + + options { + disableConcurrentBuilds() + timeout(time: 15, unit: 'MINUTES') + timestamps() + } + + stages { + stage ('Prepare & Publish') { + steps { + script { + git_cmd.checkout(branch: params.GIT_BRANCH) + npm.prepareRelease(version: params.RELEASE_VERSION, scripts: ['build']) + + withKsm(application: [ + [ + credentialsId: 'ksm-jenkins', + secrets: [ + [destination: 'env', envVar: 'NPM_TOKEN', filePath: '', notation: 'keeper://FcbEgbi287PN2yx_3uCz4Q/field/note'], + ] + ] + ]) { + sh "echo //registry.npmjs.org/:_authToken=${NPM_TOKEN} > .npmrc" + sh "npm whoami || echo 'whoami failed'" + sh "npm publish" + } + } + } + } + } + + post { + success { + script { + performCleanup() + + // Commit and tag the release + sh "git commit -a -m 'Release ${params.RELEASE_VERSION}'" + sh "git tag -a v${params.RELEASE_VERSION} -m 'Release v${params.RELEASE_VERSION}'" + + withKsm(application: [ + [ + credentialsId: 'ksm-jenkins', + secrets: [ + [destination: 'env', envVar: 'GIT_USER', filePath: '', notation: 'keeper://8hm1g9HCfBPgoWAmpiHn6w/field/login'], + [destination: 'env', envVar: 'GIT_TOKEN', filePath: '', notation: 'keeper://8hm1g9HCfBPgoWAmpiHn6w/field/password'] + ] + ] + ]) { + sh 'mkdir -p ~/.ssh' + sh 'ssh-keyscan github.com >> ~/.ssh/known_hosts' + + sh 'git config --global user.name "$GIT_USER"' + sh 'git config --global user.email "$GIT_USER@users.noreply.github.com"' + + sh 'git remote set-url origin git@github.com:Ontotext-AD/graphwise-reactodia.git' + sh "git push --set-upstream origin ${params.GIT_BRANCH}" + sh 'git push --tags' + } + + // Optional Slack notification if enabled and channel is provided + if (params.NOTIFY_SLACK && params.SLACK_CHANNEL?.trim()) { + try { + slack.notifyResult(channel: params.SLACK_CHANNEL, color:'good', message:"Released graphwise-reactodia v${params.RELEASE_VERSION}") + } catch (e) { + echo "Slack notification failed: ${e.getMessage()}" + } + } + } + } + + failure { + wrap([$class: 'BuildUser']) { + sendMail(env.BUILD_USER_EMAIL) + } + + script { + performCleanup() + } + } + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..3c3225b --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1441 @@ +{ + "name": "graphwise-reactodia", + "version": "0.0.1-TR3", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "graphwise-reactodia", + "version": "0.0.1-TR3", + "license": "Apache-2.0", + "dependencies": { + "@reactodia/workspace": "^0.34.1", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@rdfjs/types": "^2.0.1", + "@stencil/core": "4.35.1", + "@stencil/sass": "^3.2.3", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "rollup-plugin-node-polyfills": "^0.2.1" + } + }, + "node_modules/@bufbuild/protobuf": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.12.0.tgz", + "integrity": "sha512-B/XlCaFIP8LOwzo+bz5uFzATYokcwCKQcghqnlfwSmM5eX/qTkvDBnDPs+gXtX/RyjxJ4DRikECcPJbyALA8FA==", + "dev": true, + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@parcel/watcher": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@rdfjs/types": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@rdfjs/types/-/types-2.0.1.tgz", + "integrity": "sha512-uyAzpugX7KekAXAHq26m3JlUIZJOC0uSBhpnefGV5i15bevDyyejoB7I+9MKeUrzXD8OOUI3+4FeV1wwQr5ihA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@reactodia/hashmap": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@reactodia/hashmap/-/hashmap-0.2.1.tgz", + "integrity": "sha512-SruXxvsqPQcszDlwYgPCM1SKZ0Ds6cTEpFzxpex51KYpLdCJ1bXjrqVyQq7kLEXNmLNBLIj+j6WtHCVy0D68+w==", + "license": "MIT" + }, + "node_modules/@reactodia/worker-proxy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@reactodia/worker-proxy/-/worker-proxy-0.1.0.tgz", + "integrity": "sha512-5yLJp18398bDzxtnuU3foj1SJJmtZd/wltr69+hWrKXxaFlsO3My5A/kqF9M/sclnQPrflgkJVetvq1COaAuSA==", + "license": "MIT" + }, + "node_modules/@reactodia/workspace": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@reactodia/workspace/-/workspace-0.34.1.tgz", + "integrity": "sha512-dqZJ/BxKzKGabfQbHDFSdvDW81Vi89c2v0aOs7YFyG/bodqWCQEzuQ4yBd/bB6Z8hKm9uHmybtkFjkCpXAHcJQ==", + "license": "LGPL-2.1-or-later", + "dependencies": { + "@reactodia/hashmap": "^0.2.1", + "@reactodia/worker-proxy": "^0.1.0", + "clsx": "^2.1.1", + "d3-color": "^3.1.0", + "file-saver": "^2.0.5", + "n3": "^1.26.0" + }, + "peerDependencies": { + "react": "^17.0.2 || ^18 || ^19", + "react-dom": "^17.0.2 || ^18 || ^19" + } + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.9.tgz", + "integrity": "sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.9.tgz", + "integrity": "sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.9.tgz", + "integrity": "sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.9.tgz", + "integrity": "sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.9.tgz", + "integrity": "sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.9.tgz", + "integrity": "sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.9.tgz", + "integrity": "sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.9.tgz", + "integrity": "sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@stencil/core": { + "version": "4.35.1", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.35.1.tgz", + "integrity": "sha512-u65m3TbzOtpn679gUV4Yvi8YpInhRJ62js30a7YtXief9Ej/vzrhwDE22U0w4DMWJOYwAsJl133BUaZkWwnmzg==", + "dev": true, + "license": "MIT", + "bin": { + "stencil": "bin/stencil" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.10.0" + }, + "optionalDependencies": { + "@rollup/rollup-darwin-arm64": "4.34.9", + "@rollup/rollup-darwin-x64": "4.34.9", + "@rollup/rollup-linux-arm64-gnu": "4.34.9", + "@rollup/rollup-linux-arm64-musl": "4.34.9", + "@rollup/rollup-linux-x64-gnu": "4.34.9", + "@rollup/rollup-linux-x64-musl": "4.34.9", + "@rollup/rollup-win32-arm64-msvc": "4.34.9", + "@rollup/rollup-win32-x64-msvc": "4.34.9" + } + }, + "node_modules/@stencil/sass": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@stencil/sass/-/sass-3.2.3.tgz", + "integrity": "sha512-Wru76NJqa6D79/fDjSuiXoe2U0Ky1j7LLycqn7DV0jCmVO3tiWqXHBUPg0gMXJtxEiIbIJeiH/VpKhjNrBIUkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "sass-embedded": "^1.89.2" + }, + "engines": { + "node": ">=12.0.0", + "npm": ">=6.0.0" + }, + "peerDependencies": { + "@stencil/core": ">=2.0.0 || >=3.0.0-beta.0 || >= 4.0.0-beta.0 || >= 4.0.0" + } + }, + "node_modules/@types/node": { + "version": "25.9.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.3.tgz", + "integrity": "sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.31", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz", + "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/colorjs.io": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz", + "integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==", + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/immutable": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.6.tgz", + "integrity": "sha512-q1swsS8K7L8usSHuOqF2TAoCCkonYz0SG38wLAggaa4Wml70zixIvt2ql4coQ2C2B3hTjltJry4r6bULwgAXLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/n3": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/n3/-/n3-1.26.0.tgz", + "integrity": "sha512-SQknS0ua90rN+3RHuk8BeIqeYyqIH/+ecViZxX08jR4j6MugqWRjtONl3uANG/crWXnOM2WIqBJtjIhVYFha+w==", + "license": "MIT", + "dependencies": { + "buffer": "^6.0.3", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">=12.0" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/rollup-plugin-inject": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", + "integrity": "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==", + "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.", + "dev": true, + "license": "MIT", + "dependencies": { + "estree-walker": "^0.6.1", + "magic-string": "^0.25.3", + "rollup-pluginutils": "^2.8.1" + } + }, + "node_modules/rollup-plugin-node-polyfills": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", + "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==", + "dev": true, + "license": "MIT", + "dependencies": { + "rollup-plugin-inject": "^3.0.0" + } + }, + "node_modules/rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "estree-walker": "^0.6.1" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/sass": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.100.0.tgz", + "integrity": "sha512-B5j0rYMlinhhOo9tjQebMVVn0TfyXAF+wB3b2ggZUuJ/is/Y+7+JGjirAMxHZ9Z3hIP98NPfamlAkBHa1lAaXQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "chokidar": "^5.0.0", + "immutable": "^5.1.5", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=20.19.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/sass-embedded": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.100.0.tgz", + "integrity": "sha512-Ut8wlQSk19tm7jMK6mz6cF1+e+E7tUnW2tM02zQDPnOTcVbV8qCQG8UWxZkkNlY50+hV3hqP24OOkUlMz8xBpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bufbuild/protobuf": "^2.5.0", + "colorjs.io": "^0.5.0", + "immutable": "^5.1.5", + "rxjs": "^7.4.0", + "supports-color": "^8.1.1", + "sync-child-process": "^1.0.2", + "varint": "^6.0.0" + }, + "bin": { + "sass": "dist/bin/sass.js" + }, + "engines": { + "node": ">=16.0.0" + }, + "optionalDependencies": { + "sass-embedded-all-unknown": "1.100.0", + "sass-embedded-android-arm": "1.100.0", + "sass-embedded-android-arm64": "1.100.0", + "sass-embedded-android-riscv64": "1.100.0", + "sass-embedded-android-x64": "1.100.0", + "sass-embedded-darwin-arm64": "1.100.0", + "sass-embedded-darwin-x64": "1.100.0", + "sass-embedded-linux-arm": "1.100.0", + "sass-embedded-linux-arm64": "1.100.0", + "sass-embedded-linux-musl-arm": "1.100.0", + "sass-embedded-linux-musl-arm64": "1.100.0", + "sass-embedded-linux-musl-riscv64": "1.100.0", + "sass-embedded-linux-musl-x64": "1.100.0", + "sass-embedded-linux-riscv64": "1.100.0", + "sass-embedded-linux-x64": "1.100.0", + "sass-embedded-unknown-all": "1.100.0", + "sass-embedded-win32-arm64": "1.100.0", + "sass-embedded-win32-x64": "1.100.0" + } + }, + "node_modules/sass-embedded-all-unknown": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-all-unknown/-/sass-embedded-all-unknown-1.100.0.tgz", + "integrity": "sha512-auFtXY/kwYILmSVjtBDwyj0axcLbYYiffOKWoaXHnI5bsYwiRbBh3EneR1rpbX2ZIZCrwX93i5pxKLTZF/662Q==", + "cpu": [ + "!arm", + "!arm64", + "!riscv64", + "!x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "sass": "1.100.0" + } + }, + "node_modules/sass-embedded-android-arm": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.100.0.tgz", + "integrity": "sha512-70f3HgX2pFNmzpGQ86n5e6QfWn2fP4QUQGfFQK0P1XH73ZLIzLo2YqygrGKGKeeqtc5eU2Wl1/xQzhzuKnO4kw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-arm64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.100.0.tgz", + "integrity": "sha512-W+Ru9JwTnfU0UX3jSZcbqFdtKFMcYdfFwytc57h2DgnqCOIiAqI2E06mABZBZC+r3LwXCBuS5GbXAGeVgvVDkA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-riscv64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.100.0.tgz", + "integrity": "sha512-icU3o0V/uCSytSpf+tX5Lf51BvyQEbLzDUJfUi9etSauYBGHpPKkdtdZH0si4v98phq11Kl8rSV1SggksxF1Hg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-android-x64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.100.0.tgz", + "integrity": "sha512-mevF9VQk6gEYByy8+jusaHGmd7Usb2ytX/DsEOd0JtOGCtcf1kh575xJ6OUBDIcJ15uLnbau/0iy1eP6WVBvWA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-darwin-arm64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.100.0.tgz", + "integrity": "sha512-1PVlYi61POo93IT/FfrG1mc1tAHxeSTyUALF2aOFmXGWjVXr3bQzEQiBGCOvQbj/ix+5hNyXFXcEMEyKvtUJJA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-darwin-x64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.100.0.tgz", + "integrity": "sha512-x97o3JnGyImZNCIVs9wQHJUE5QCvmVIKaH1cwrz/5dK7OT1FpeNiW+u9TUomP9hG6Ekjd8EL8NBHpxTfIhdjmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-arm": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.100.0.tgz", + "integrity": "sha512-9Ul7O1eKrc5YlhwWjkp8tZPSe3UEwSZ1uwUZOQom1HL0pRlBA6F/IlGZYFTLwnHMIP1fc77MMNaBRfc05mKMpw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-arm64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.100.0.tgz", + "integrity": "sha512-Dwjmj8Z6VRy7rAi53JAdEwIyUjpfl7PhpSc2/LpQPQx+aO5Dp7Spaipkax0ufJl1SoDUdchCsM4y/88YaluorQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-arm": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.100.0.tgz", + "integrity": "sha512-sl0JgbGloPyJg66XXx5UDSDScZ0oU85DpMQU4JU/sCUCFj1Z8zZ69SJWKTCNE4/jwnce7WI2zPCV5AG+RHOZJw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-arm64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.100.0.tgz", + "integrity": "sha512-XpACJB2KjSLjf2e9uuvGVdOURsoNrFqgRiihhXyUHK9W0t3LIHb7z5MA/7XGPIT9bWSOO2zyw+rH/FHtDV/Yrg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-riscv64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.100.0.tgz", + "integrity": "sha512-ShvI0Kx04mwoCARwZ0UjiT97isQvzO80tAt91zmFyHLN9kelc/IrQi940farSm2xQVPCKdeVyeG0ekBsokSpYQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-musl-x64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.100.0.tgz", + "integrity": "sha512-TDBCRWNuS4RDLQXvRc1gjZlWiWTWaWGp0Bwu/IKwJxov81lsvrCs3TihTyNXtW7V5aoN4Ky3r0QOkNb3mwmBnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-riscv64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.100.0.tgz", + "integrity": "sha512-j4ENJGOheO+fm3j/yorLxCjBP6/XskrZx7dTLlT+lXYwN/qqCqoA/gsNLI0McS3DFM6GBwPiffzWsdWS8t6sEQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-linux-x64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.100.0.tgz", + "integrity": "sha512-0vUSN8j0WGtCJIOPh//EmUvYGHW0QOe5iul8qyhPk50MAcw49MA0r34AhftjDdx94ILPF6vApFs0gwHPQRlpVA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-unknown-all": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.100.0.tgz", + "integrity": "sha512-c+naBgWId4MIpToXcI0DgqetjdAkwTTAxFAuOaBz7HUXLdyG1oZRrEvSsbe41nEdQOKH0vgofVFCeSQgoXOG9A==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "!android", + "!darwin", + "!linux", + "!win32" + ], + "dependencies": { + "sass": "1.100.0" + } + }, + "node_modules/sass-embedded-win32-arm64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.100.0.tgz", + "integrity": "sha512-iE+yxj+hUXwwbqpHkXxgAWTzeRfcWxJ7SSTQEPMk48lwq3oCrWLlz5sQuWHbuTK/i0GKQfROdP+hOmPi89yjUg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-embedded-win32-x64": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.100.0.tgz", + "integrity": "sha512-qI4F8MI7/KYoy9NdjJfhSspG42WPkADSNDvwEV7qWvCSFC83koJssRsKO2/PfY+niZz6BG65Ic/D+A11h959hw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "dev": true, + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/sync-child-process": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz", + "integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "sync-message-port": "^1.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/sync-message-port": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/sync-message-port/-/sync-message-port-1.2.0.tgz", + "integrity": "sha512-gAQ9qrUN/UCypHtGFbbe7Rc/f9bzO88IwrG8TDo/aMKAApKyD6E3W4Cm0EfhfBb6Z6SKt59tTCTfD+n1xmAvMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "dev": true, + "license": "MIT" + }, + "node_modules/varint": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", + "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..9183133 --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "graphwise-reactodia", + "version": "0.0.1-TR3", + "description": "Graphwise wrapper around the Reactodia graph explorer.", + "license": "Apache-2.0", + "author": "Ontotext AD", + "main": "dist/index.cjs.js", + "collection": "dist/collection/collection-manifest.json", + "files": [ + "dist/", + "loader/" + ], + "scripts": { + "build": "stencil build", + "start": "stencil build --dev --watch --serve" + }, + "dependencies": { + "@reactodia/workspace": "^0.34.1", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@rdfjs/types": "^2.0.1", + "@stencil/core": "4.35.1", + "@stencil/sass": "^3.2.3", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "rollup-plugin-node-polyfills": "^0.2.1" + } +} diff --git a/src/components.d.ts b/src/components.d.ts new file mode 100644 index 0000000..99e29cf --- /dev/null +++ b/src/components.d.ts @@ -0,0 +1,109 @@ +/* eslint-disable */ +/* tslint:disable */ +/** + * This is an autogenerated file created by the Stencil compiler. + * It contains typing information for all components that exist in this project. + */ +import { HTMLStencilElement, JSXBase } from "@stencil/core/internal"; +import { SparqlDataProviderSettings, SparqlQueryFunction } from "@reactodia/workspace"; +export { SparqlDataProviderSettings, SparqlQueryFunction } from "@reactodia/workspace"; +export namespace Components { + /** + * A web component that renders a graph with the Reactodia workspace. + * The component is backed by a SPARQL endpoint but is endpoint-agnostic: the host passes + * the active repository's endpoint via `current-repository` and a `queryFunction` that + * performs the actual HTTP request. Reactodia fetches all node, link and type data lazily + * through them; the canvas starts empty and the user populates it via the search bar. + * The component is a thin wrapper around Reactodia: query configuration lives outside the + * wrapper and is supplied through the `providerSettings` prop. + */ + interface GraphwiseReactodia { + /** + * The active repository id. Appended to {@link queryFunction} as the request `url`; changing it re-points the graph at the new repository (and resets the canvas), which is how runtime repository changes are handled. + */ + "currentRepository": string; + /** + * UI language code (e.g. `en`, `fr`) for the Reactodia interface. Defaults to English. + * @default 'en' + */ + "language": string; + /** + * Query preset for the SPARQL data provider, owned and configured by the host. A DOM property (an object, not an attribute) passed in from outside the wrapper. When omitted, the data provider falls back to Reactodia's generic OWL/RDFS preset. Changing it rebuilds the data provider and resets the canvas. + */ + "providerSettings"?: SparqlDataProviderSettings; + /** + * HTTP transport for the SPARQL requests. Set by the host so requests go through the host's HTTP layer (auth, interceptors) instead of a built-in `fetch`. + */ + "queryFunction": SparqlQueryFunction; + } +} +declare global { + /** + * A web component that renders a graph with the Reactodia workspace. + * The component is backed by a SPARQL endpoint but is endpoint-agnostic: the host passes + * the active repository's endpoint via `current-repository` and a `queryFunction` that + * performs the actual HTTP request. Reactodia fetches all node, link and type data lazily + * through them; the canvas starts empty and the user populates it via the search bar. + * The component is a thin wrapper around Reactodia: query configuration lives outside the + * wrapper and is supplied through the `providerSettings` prop. + */ + interface HTMLGraphwiseReactodiaElement extends Components.GraphwiseReactodia, HTMLStencilElement { + } + var HTMLGraphwiseReactodiaElement: { + prototype: HTMLGraphwiseReactodiaElement; + new (): HTMLGraphwiseReactodiaElement; + }; + interface HTMLElementTagNameMap { + "graphwise-reactodia": HTMLGraphwiseReactodiaElement; + } +} +declare namespace LocalJSX { + /** + * A web component that renders a graph with the Reactodia workspace. + * The component is backed by a SPARQL endpoint but is endpoint-agnostic: the host passes + * the active repository's endpoint via `current-repository` and a `queryFunction` that + * performs the actual HTTP request. Reactodia fetches all node, link and type data lazily + * through them; the canvas starts empty and the user populates it via the search bar. + * The component is a thin wrapper around Reactodia: query configuration lives outside the + * wrapper and is supplied through the `providerSettings` prop. + */ + interface GraphwiseReactodia { + /** + * The active repository id. Appended to {@link queryFunction} as the request `url`; changing it re-points the graph at the new repository (and resets the canvas), which is how runtime repository changes are handled. + */ + "currentRepository"?: string; + /** + * UI language code (e.g. `en`, `fr`) for the Reactodia interface. Defaults to English. + * @default 'en' + */ + "language"?: string; + /** + * Query preset for the SPARQL data provider, owned and configured by the host. A DOM property (an object, not an attribute) passed in from outside the wrapper. When omitted, the data provider falls back to Reactodia's generic OWL/RDFS preset. Changing it rebuilds the data provider and resets the canvas. + */ + "providerSettings"?: SparqlDataProviderSettings; + /** + * HTTP transport for the SPARQL requests. Set by the host so requests go through the host's HTTP layer (auth, interceptors) instead of a built-in `fetch`. + */ + "queryFunction"?: SparqlQueryFunction; + } + interface IntrinsicElements { + "graphwise-reactodia": GraphwiseReactodia; + } +} +export { LocalJSX as JSX }; +declare module "@stencil/core" { + export namespace JSX { + interface IntrinsicElements { + /** + * A web component that renders a graph with the Reactodia workspace. + * The component is backed by a SPARQL endpoint but is endpoint-agnostic: the host passes + * the active repository's endpoint via `current-repository` and a `queryFunction` that + * performs the actual HTTP request. Reactodia fetches all node, link and type data lazily + * through them; the canvas starts empty and the user populates it via the search bar. + * The component is a thin wrapper around Reactodia: query configuration lives outside the + * wrapper and is supplied through the `providerSettings` prop. + */ + "graphwise-reactodia": LocalJSX.GraphwiseReactodia & JSXBase.HTMLAttributes; + } + } +} diff --git a/src/components/graphwise-reactodia/graphwise-reactodia.scss b/src/components/graphwise-reactodia/graphwise-reactodia.scss new file mode 100644 index 0000000..6de67a8 --- /dev/null +++ b/src/components/graphwise-reactodia/graphwise-reactodia.scss @@ -0,0 +1,11 @@ +graphwise-reactodia { + display: block; + width: 100%; + height: 75vh; + + .reactodia-container { + position: relative; + width: 100%; + height: 100%; + } +} diff --git a/src/components/graphwise-reactodia/graphwise-reactodia.tsx b/src/components/graphwise-reactodia/graphwise-reactodia.tsx new file mode 100644 index 0000000..6af2491 --- /dev/null +++ b/src/components/graphwise-reactodia/graphwise-reactodia.tsx @@ -0,0 +1,111 @@ +import {Component, Element, h, Host, Prop, Watch} from '@stencil/core'; +import {Root} from 'react-dom/client'; +import {SerializedDiagram, SparqlDataProviderSettings, SparqlQueryFunction} from '@reactodia/workspace'; +import {exportReactodiaLayout, mountReactodia, unmountReactodia, updateReactodia} from './reactodia-app'; + +/** + * A web component that renders a graph with the Reactodia workspace. + * + * The component is backed by a SPARQL endpoint but is endpoint-agnostic: the host passes + * the active repository's endpoint via `current-repository` and a `queryFunction` that + * performs the actual HTTP request. Reactodia fetches all node, link and type data lazily + * through them; the canvas starts empty and the user populates it via the search bar. + * + * The component is a thin wrapper around Reactodia: query configuration lives outside the + * wrapper and is supplied through the `providerSettings` prop. + */ +@Component({ + tag: 'graphwise-reactodia', + styleUrl: 'graphwise-reactodia.scss', +}) +export class GraphwiseReactodia { + @Element() private readonly hostElement: HTMLElement; + + /** + * The active repository id. Appended to {@link queryFunction} as the request `url`; + * changing it re-points the graph at the new repository (and resets the canvas), + * which is how runtime repository changes are handled. + */ + @Prop() currentRepository: string; + + /** + * HTTP transport for the SPARQL requests. Set by the host so requests go through the host's HTTP layer (auth, + * interceptors) instead of a built-in `fetch`. + */ + @Prop() queryFunction: SparqlQueryFunction; + + /** + * UI language code (e.g. `en`, `fr`) for the Reactodia interface. Defaults to English. + */ + @Prop() language = 'en'; + + /** + * Query preset for the SPARQL data provider, owned and configured by the host. A DOM + * property (an object, not an attribute) passed in from outside the wrapper. When omitted, + * the data provider falls back to Reactodia's generic OWL/RDFS preset. Changing it rebuilds + * the data provider and resets the canvas. + */ + @Prop() providerSettings?: SparqlDataProviderSettings; + + private reactRoot: Root; + + @Watch('currentRepository') + @Watch('providerSettings') + onProviderSettingsChange(): void { + this.renderGraph(); + } + + @Watch('language') + onLanguageChange(): void { + // The translations are evaluated by the workspace at construction, so the only way + // to re-translate the UI is to re-create the graph. We carry the + // current diagram across the remount so switching languages does not wipe the canvas. + const diagram = exportReactodiaLayout(); + this.renderGraph(diagram); + } + + componentDidLoad(): void { + this.renderGraph(); + } + + disconnectedCallback(): void { + if (this.reactRoot) { + unmountReactodia(this.reactRoot); + this.reactRoot = undefined; + } + } + + render() { + return ( + + ); + } + + private renderGraph(initialDiagram?: SerializedDiagram): void { + if (!this.currentRepository) { + throw new Error('currentRepository is required'); + } + + if (!this.queryFunction) { + throw new Error('queryFunction is required'); + } + + if (!this.hostElement) { + return; + } + + const props = { + initialDiagram, + currentRepository: this.currentRepository, + queryFunction: this.queryFunction, + language: this.language, + providerSettings: this.providerSettings, + }; + + if (this.reactRoot && !initialDiagram) { + void updateReactodia(props); + } else { + this.reactRoot = mountReactodia(this.hostElement, props); + } + } +} diff --git a/src/components/graphwise-reactodia/i18n/fr.reactodia.translation.json b/src/components/graphwise-reactodia/i18n/fr.reactodia.translation.json new file mode 100644 index 0000000..5f28427 --- /dev/null +++ b/src/components/graphwise-reactodia/i18n/fr.reactodia.translation.json @@ -0,0 +1,341 @@ +{ + "authoring_state": { + "entity_action_delete.label": "supprimer", + "entity_action_delete.title": "Supprimer l'entité", + "entity_action_delete.title_disabled": "Impossible de supprimer l'entité", + "entity_action_discard.label": "annuler", + "entity_action_discard.title": "Annuler toutes les modifications de l'entité", + "entity_action_edit.label": "modifier", + "entity_action_edit.title": "Modifier l'entité", + "entity_action_edit.title_disabled": "Impossible de modifier l'entité", + "entity_add.label": "Nouveau", + "entity_change.label": "Modifier", + "entity_delete.label": "Supprimer", + "relation_action_discard.label": "annuler", + "relation_action_discard.title": "Annuler toutes les modifications de la relation", + "relation_add.label": "Nouveau", + "relation_change.label": "Modifier", + "relation_delete.label": "Supprimer" + }, + "classic_workspace": { + "canvas.label": "Canevas", + "class_tree.heading": "Classes", + "connections.heading": "Connexions", + "instances.heading": "Instances" + }, + "commands": { + "change_entity.title": "Modifier les données de l'entité", + "change_link_type_visibility.title": "Modifier la visibilité du type de lien", + "change_relation.title": "Modifier les données de la relation", + "collapse_element.title": "Réduire l'élément", + "expand_element.title": "Développer l'élément", + "place_elements_around.title": "Placer les éléments", + "restore_geometry.title": "Déplacer les éléments et les liens", + "restore_link_vertices.title": "Modifier les sommets du lien", + "restore_viewport.title": "Définir la zone d'affichage", + "set_element_state.title": "Modifier l'état de l'élément", + "set_entity_data.title": "Définir les données de l'élément d'entité", + "set_entity_group_items.title": "Définir les éléments du groupe d'entités", + "set_link_state.title": "Modifier l'état du lien", + "set_relation_data.title": "Définir les données du lien de relation", + "set_relation_group_items.title": "Définir les éléments du groupe de relations", + "transform_elements.title": "Redimensionner les éléments" + }, + "connections_menu": { + "all_link.label": "Tous", + "breadcrumbs_root.label": "Types de liens", + "dialog.caption": "Connexions", + "entities.add_all": "Tout ajouter", + "entities.add_group": "Ajouter en tant que groupe", + "entities.add_selected": "Ajouter la sélection", + "entities.counter_label": "{{count}} sur {{total}}", + "entities.extra_label": " ({{value}})", + "entities.extra_title": "Entités supplémentaires", + "entities.missing_label": " ({{value}})", + "entities.missing_title": "Entités manquantes", + "entities.no_results": "Aucun résultat", + "entities.truncated_results": "Seules les {{limit}} premières entités sont affichées", + "entities.truncated_results_expand": "Seules les {{limit}} premières entités sont affichées,\ncliquez ici pour voir tous les résultats", + "input.placeholder": null, + "link.both_navigate_title": "Naviguer vers tous les éléments connectés", + "link.both_title": "tous connectés", + "link.source_navigate_title": "Naviguer vers les éléments source « {{relation}} »", + "link.source_title": "source de « {{relation}} » {{relationIri}}", + "link.target_navigate_title": "Naviguer vers les éléments cible « {{target}} »", + "link.target_title": "cible de « {{relation}} » {{relationIri}}", + "link.move_to_filter.title": "Définir comme filtre dans le panneau Instances", + "links.no_results": "Aucun résultat", + "links.suggest_similar": "Vous cherchez probablement...", + "place_elements.command": "Ajouter les éléments connectés", + "select_all.label": "Tout sélectionner", + "select_all.title": "Sélectionner ou désélectionner toutes les entités", + "sort_alphabetically.title": "Trier par ordre alphabétique", + "sort_smart.title": "Tri intelligent" + }, + "data_diagram_model": { + "add_element.command": "Ajouter un élément", + "add_link.command": "Ajouter un lien", + "create_links.command": "Créer des liens", + "group_entities.command": "Grouper les entités", + "import_layout.command": "Importer la disposition", + "regroup_relations.command": "Regrouper les relations", + "request_entities.command": "Demander les données des entités", + "request_relations.command": "Demander les relations entre les entités", + "remove_element.command": "Supprimer l'élément", + "remove_link.command": "Supprimer le lien", + "ungroup_entities.command": "Dégrouper les entités" + }, + "default_data_locale": { + "iri": "<{{value}}>", + "iri_blank": "(nœud anonyme)" + }, + "default_workspace": { + "search_section_entities.label": "Entités", + "search_section_entities.title": "Recherche d'entités", + "search_section_entity_types.label": "Types", + "search_section_entity_types.title": "Hiérarchie des types d'entités", + "search_section_link_types.label": "Liens", + "search_section_link_types.title": "Types de relations sur le diagramme" + }, + "drop_on_canvas": { + "drop.command": "Glisser-déposer sur le diagramme" + }, + "editor_controller": { + "apply_authored_changes.command": "Appliquer les modifications au diagramme", + "discard_change.command": "Annuler la modification", + "entity_add.command": "Créer une nouvelle entité", + "entity_change.command": "Modifier l'entité", + "entity_delete.command": "Supprimer l'entité", + "relation_add.command": "Créer une nouvelle relation", + "relation_change.command": "Modifier la relation", + "relation_delete.command": "Supprimer la relation", + "relation_move_source.command": "Déplacer la source de la relation", + "relation_move_target.command": "Déplacer la cible de la relation", + "remove_items.command": "Supprimer les éléments du diagramme", + "set_authoring_state.command": "Créer, modifier ou supprimer des entités et des relations", + "validate_entity_failed.message": "Échec de la validation de l'entité" + }, + "forms": { + "input_file.drag_hint": "Glissez des fichiers ici ou", + "input_file.remove_value.title": "Supprimer le fichier", + "input_file.select_files.label": "Sélectionner des fichiers", + "input_list.add_value.title": "Ajouter une valeur de propriété", + "input_list.remove_value.title": "Supprimer la valeur de propriété" + }, + "group_paginator": { + "current_page.label": "{{page}} sur {{pageCount}}", + "go_next.title": "Aller à la page suivante", + "go_previous.title": "Aller à la page précédente", + "page_size.title": "Nombre d'éléments à afficher par page" + }, + "inline_entity": { + "title": "{{entity}} {{entityIri}}", + "title_extra": "Types : {{entityTypes}}" + }, + "link_action": { + "delete_annotation.title": "Supprimer le lien d'annotation", + "delete_relation.title": "Supprimer la relation", + "delete_relation.title_disabled": "Impossible de supprimer la relation", + "edit_relation.title": "Modifier la relation", + "edit_relation.title_disabled": "Impossible de modifier la relation", + "rename_link.title": "Renommer le lien", + "move_relation.move_source_title": "Déplacer la source du lien", + "move_relation.move_target_title": "Déplacer la cible du lien", + "vertex.remove_title": "Supprimer le sommet" + }, + "navigator": { + "toggle_collapse.title": "Réduire le navigateur", + "toggle_expand.title": "Développer le navigateur" + }, + "note_annotation": { + "change_text.command": "Modifier le texte de l'annotation", + "style_align_center.title": "Centrer", + "style_align_left.title": "Aligner à gauche", + "style_align_right.title": "Aligner à droite", + "style_bold.title": "Gras", + "style_color_variant.title": "Variante de couleur : {{variant}}", + "style_italic.title": "Italique", + "style_strikethrough.title": "Barré", + "style_underline.title": "Souligné" + }, + "overlay_controller": { + "multiple_tasks_in_progress": "Plusieurs tâches sont en cours", + "unknown_error": "Une erreur inconnue s'est produite" + }, + "search_defaults": { + "empty_input_term": "Saisissez un terme à rechercher.", + "input.placeholder": "Rechercher...", + "input_clear.title": "Effacer la recherche", + "input_submit.title": "Rechercher", + "input_term_too_short": "Saisissez au moins {{termLength}} caractères pour rechercher.", + "no_results": "Aucun résultat trouvé." + }, + "search_element_types": { + "drag_create.title": "Cliquez ou glissez pour créer une nouvelle entité de ce type", + "input.placeholder": null, + "no_results": "Aucun type d'élément trouvé.", + "refresh_progress.title": "Chargement de l'arborescence des types d'éléments", + "show_only_creatable": "Afficher uniquement les constructibles" + }, + "search_entities": { + "add_group.label": "Ajouter en tant que groupe", + "add_group.title": "Placer les entités sélectionnées sur le canevas en tant que groupe", + "add_selected.label": "Ajouter la sélection", + "add_selected.title": "Placer les entités sélectionnées sur le canevas", + "criteria_has_type": "A le type {{entityType}}", + "criteria_connected": "Connecté à {{entity}}", + "criteria_connected_via": "Connecté à {{entity}} via {{relationType}}", + "criteria_connected_to_source": "Connecté à {{entity}} via {{relationType}} en tant que {{sourceIcon}} source", + "criteria_connected_to_target": "Connecté à {{entity}} via {{relationType}} en tant que {{targetIcon}} cible", + "input.placeholder": null, + "place_elements.command": "Ajouter les éléments sélectionnés", + "query_progress.title": "Recherche d'entités en cours", + "show_more_results.label": "Afficher plus", + "show_more_results.title": "Charger plus de résultats" + }, + "search_link_types": { + "add_to_filter.title": "Rechercher les éléments connectés via la relation", + "heading_connected": "Connecté aux entités sélectionnées", + "heading_connected_single": "Connecté à {{entity}}", + "heading_other": "Autres liens", + "input.placeholder": null, + "no_results": "Aucun lien trouvé.", + "switch.command": "Modifier la visibilité des types de liens", + "switch_all.label": "Tout basculer", + "switch_hidden.title": "Masquer les liens et les étiquettes", + "switch_visible.title": "Afficher les liens avec étiquettes", + "switch_without_label.title": "Afficher uniquement les lignes des liens (sans étiquettes)" + }, + "selection_action": { + "add_to_filter.title": "Rechercher les éléments connectés", + "anchor.title": "Accéder à la ressource", + "annotate.defaultContent": "Annotation", + "annotate.title": "Ajouter une annotation à cet élément", + "connections.title": "Naviguer vers les éléments connectés", + "expand.collapse_command": "Réduire les éléments", + "expand.expand_command": "Développer les éléments", + "expand.title": "Développer les éléments sélectionnés pour révéler des propriétés supplémentaires", + "expand.title_single": "Développer un élément pour révéler des propriétés supplémentaires", + "establish_relation.title": "Établir un lien", + "establish_relation.title_disabled": "L'établissement d'un lien n'est pas autorisé pour cet élément", + "group.title": "Grouper les entités", + "group.title_ungroup": "Dégrouper les entités", + "layout.title": "Disposer les éléments sélectionnés avec l'algorithme à forces dirigées", + "remove.title": "Supprimer les éléments sélectionnés du diagramme", + "remove.title_new": "Annuler le nouvel élément", + "remove.title_single": "Supprimer un élément du diagramme", + "zoom_to_fit.title": "Ajuster le zoom aux éléments sélectionnés" + }, + "standard_element": { + "blank_node": "(nœud anonyme)", + "default_type": "Chose", + "delete.label": "Supprimer", + "delete.title": "Supprimer l'entité", + "delete.title_disabled": "Impossible de supprimer l'entité", + "edit.label": "Modifier", + "edit.title": "Modifier l'entité", + "edit.title_disabled": "Impossible de modifier l'entité", + "group_item.title": "{{entity}}\nIRI : {{entityIri}}\nTypes : {{entityTypes}}", + "iri.label": "IRI :", + "iri.label_modified": "IRI (modifié) :", + "no_properties": "aucune propriété", + "property.title": "{{property}} {{propertyIri}}", + "ungroup.title": "Dégrouper une entité" + }, + "standard_link": { + "group_source.title": "{{value}} éléments source", + "group_source.value": "{{value}}", + "group_target.title": "{{value}} éléments cible", + "group_target.value": "{{value}}", + "label.title": "{{relation}} {{relationIri}}", + "property.title": "{{property}} {{propertyIri}}" + }, + "toolbar": { + "menu_toggle.title": "Ouvrir le menu" + }, + "toolbar_action": { + "clear_all.command": "Tout effacer", + "clear_all.title": "Supprimer tous les éléments et liens du diagramme", + "clear_all.label": "Tout effacer", + "export_print.label": "Imprimer", + "export_print.title": "Imprimer le diagramme", + "export_raster.label": "Exporter en PNG", + "export_raster.title": "Exporter le diagramme en image PNG", + "export_svg.label": "Exporter en SVG", + "export_svg.title": "Exporter le diagramme en image SVG", + "redo.label": "Rétablir", + "redo.title": "Rétablir la dernière commande annulée", + "redo.title_named": "Rétablir : {{command}}", + "save_authoring.title": "Appliquer les modifications du graphe", + "save_layout.title": "Enregistrer la disposition du diagramme", + "language_selector.title": "Sélectionner la langue des données (étiquettes, propriétés, etc.)", + "layout.label": "Disposition", + "layout.title": "Disposer le diagramme avec l'algorithme à forces dirigées", + "undo.label": "Annuler", + "undo.title": "Annuler la dernière commande", + "undo.title_named": "Annuler : {{command}}" + }, + "unified_search": { + "input.placeholder": null, + "input_clear.title": "Effacer", + "input_collapse.title": "Fermer" + }, + "visual_authoring": { + "dialog.apply.label": "Appliquer", + "dialog.apply.title": "Appliquer les modifications", + "dialog.cancel.label": "Annuler", + "dialog.cancel.title": "Annuler la boîte de dialogue", + "edit_entity.dialog.apply.label": null, + "edit_entity.dialog.apply.title": null, + "edit_entity.dialog.caption": "Modifier l'entité", + "edit_entity.iri.label": "IRI", + "edit_entity.iri.placeholder": "IRI de l'entité", + "edit_relation.dialog.apply.label": null, + "edit_relation.dialog.apply.title": null, + "edit_relation.dialog.caption": "Modifier la relation", + "edit_relation.dialog.caption_new": "Établir une nouvelle relation", + "edit_relation.validation_progress.title": "Validation du type de lien sélectionné", + "find_or_create.connect_command": "Lier à une entité", + "find_or_create.create_command": "Créer une nouvelle entité", + "find_or_create.dialog.apply.label": null, + "find_or_create.dialog.apply.title": null, + "find_or_create.dialog.caption": "Établir une nouvelle connexion", + "find_or_create.loading.label": "Chargement de l'entité...", + "find_or_create.validation_progress.title": "Validation des types d'élément et de lien sélectionnés", + "property.label": "{{property}}", + "property.text_value.placeholder": "Valeur de la propriété", + "property.title": "{{property}} {{propertyIri}}", + "rename_link.dialog.apply.label": null, + "rename_link.dialog.apply.title": null, + "rename_link.dialog.caption": "Renommer le lien", + "rename_link.label.label": "Étiquette", + "select_entity.entity_type.label": "{{type}}", + "select_entity.input.placeholder": null, + "select_entity.type.label": "Type d'entité", + "select_entity.type.placeholder": "Sélectionner le type d'entité", + "select_entity.results.aria_label": "Sélectionner un élément existant à placer sur le diagramme", + "select_entity.separator.label": "ou créer une nouvelle entité", + "select_entity.validation.error_required": "Requis.", + "select_relation.relation_type.label": "{{relation}} [{{source}} → {{target}}]", + "select_relation.type.label": "Type de relation", + "select_relation.type.placeholder": "Sélectionner le type de relation", + "select_relation.validation.error_duplicate": "La relation existe déjà.", + "select_relation.validation.error_required": "Requis." + }, + "workspace": { + "group_entities.command": "Grouper les entités", + "perform_layout.task": "Calcul de la disposition du graphe", + "perform_layout.command": "Disposition du graphe", + "ungroup_entities.command": "Dégrouper les entités" + }, + "workspace_layout": { + "toggle_collapse.title": "Réduire le panneau", + "toggle_expand.title": "Développer le panneau" + }, + "zoom_control": { + "pointer_mode.title": "Basculer le mode de sélection :\nGlissez pour sélectionner, Maj + pointeur pour déplacer le canevas", + "zoom_in.title": "Zoom avant", + "zoom_out.title": "Zoom arrière", + "zoom_to_fit.title": "Ajuster à l'écran" + } +} diff --git a/src/components/graphwise-reactodia/i18n/translations.ts b/src/components/graphwise-reactodia/i18n/translations.ts new file mode 100644 index 0000000..eb09e39 --- /dev/null +++ b/src/components/graphwise-reactodia/i18n/translations.ts @@ -0,0 +1,5 @@ +import frTranslation from './fr.reactodia.translation.json'; + +export const TRANSLATIONS = { + 'fr': frTranslation +} diff --git a/src/components/graphwise-reactodia/models/reactodia-app-props.ts b/src/components/graphwise-reactodia/models/reactodia-app-props.ts new file mode 100644 index 0000000..a92103b --- /dev/null +++ b/src/components/graphwise-reactodia/models/reactodia-app-props.ts @@ -0,0 +1,35 @@ +import {SerializedDiagram, SparqlDataProviderSettings, SparqlQueryFunction} from '@reactodia/workspace'; + +/** + * Props for the internal Reactodia React application. + */ +export interface ReactodiaAppProps { + /** + * The active repository id. Passed to the SPARQL data provider as its `endpointUrl` and + * surfaced to {@link queryFunction} as the request `url`, which the host transport uses to + * target the repository. Changing it re-points the diagram at a different repository. + */ + currentRepository: string; + /** + * Transport for the SPARQL requests. The host owns the connection (auth, interceptors, + * base URL) inside this function; Reactodia delegates every SPARQL call to it instead + * of using the built-in `fetch`. + */ + queryFunction: SparqlQueryFunction; + /** + * UI language code (e.g. `en`, `fr`); selects the Reactodia translation bundle + * and is also used as the initial graph-data language. + */ + language: string; + /** + * A previously exported diagram to restore on mount. Used to carry the user's current + * canvas across a remount (e.g. forced by a language change). When omitted, the canvas + * starts empty. + */ + initialDiagram?: SerializedDiagram; + /** + * Query preset for the SPARQL data provider, owned and configured by the host. Falls back + * to Reactodia's generic `OwlRdfsSettings` OWL/RDFS preset when omitted. + */ + providerSettings?: SparqlDataProviderSettings; +} \ No newline at end of file diff --git a/src/components/graphwise-reactodia/reactodia-app.ts b/src/components/graphwise-reactodia/reactodia-app.ts new file mode 100644 index 0000000..9e30934 --- /dev/null +++ b/src/components/graphwise-reactodia/reactodia-app.ts @@ -0,0 +1,138 @@ +import {createElement} from 'react'; +import {createRoot, Root} from 'react-dom/client'; +import { + DefaultWorkspace, + OwlRdfsSettings, + SerializedDiagram, + SparqlDataProvider, + SparqlDataProviderSettings, + SparqlQueryFunction, + useLoadedWorkspace, + Workspace, + WorkspaceContext, +} from '@reactodia/workspace'; +import {blockingDefaultLayout} from '@reactodia/workspace/layout-sync'; +import {ReactodiaAppProps} from './models/reactodia-app-props'; +import {TRANSLATIONS} from './i18n/translations'; + + +/** + * Reactodia ships English as its built-in default bundle, so English needs no override. + * Other languages are layered on top as partial bundles; unknown codes fall back to English. + * + * Reactodia never re-reads the translations, so the component must be remounted + * to switch the UI language (handled in `graphwise-reactodia.tsx`). + */ +function translationsForLanguage(language: string): readonly object[] { + const translation = TRANSLATIONS[language] + return translation ? [translation] : []; + } + +/** + * The workspace context captured from the Workspace `ref` once it mounts. + * Used to drive the diagram imperatively from {@link updateReactodia}, which + * runs outside React and therefore cannot call the `useWorkspace` hook. + */ +let workspaceContext: WorkspaceContext | null = null; + +/** + * Builds a Reactodia {@link SparqlDataProvider} for the given endpoint using the supplied + * query preset. The host owns the query configuration and passes it in via props; when none + * is provided we fall back to Reactodia's generic {@link OwlRdfsSettings} OWL/RDFS preset. + */ +function createDataProvider( + currentRepository: string, + queryFunction: SparqlQueryFunction, + settings?: SparqlDataProviderSettings +): SparqlDataProvider { + return new SparqlDataProvider({ + endpointUrl: currentRepository, + queryMethod: 'POST', + queryFunction, + }, settings); +} + +/** + * The Reactodia workspace React component. + * + * Authored with `React.createElement` (no TSX) on purpose, since there are differences in stencil and react + * + * The canvas starts empty; the user populates it through the workspace search bar + * (Reactodia's `DefaultWorkspace` unified search), which is backed by the SPARQL + * data provider's lookup. + */ +function ReactodiaApp(props: ReactodiaAppProps) { + const {currentRepository, queryFunction, language, initialDiagram, providerSettings} = props; + + const {onMount} = useLoadedWorkspace(async ({context, signal}) => { + workspaceContext = context; + const {model} = context; + const dataProvider = createDataProvider(currentRepository, queryFunction, providerSettings); + // A language change remounts this component to rebuild the workspace with the new + // translation bundle; restoring the exported diagram keeps the user's canvas intact. + // This is done because there is no existing mechanism to re-translate the UI at runtime (not for the UI labels at least) + if (initialDiagram) { + await model.importLayout({dataProvider, diagram: initialDiagram, signal}); + } else { + await model.createNewDiagram({dataProvider, signal}); + } + }, [language]); + + /** + * From the documentation + * + * return ( + * + * + * + * ); + */ + return createElement( + Workspace, + { + ref: onMount, + defaultLayout: blockingDefaultLayout, + defaultLanguage: language, + translations: translationsForLanguage(language) + } as never, + createElement(DefaultWorkspace, {}) + ); +} + +/** + * Mounts the Reactodia application into the given container and returns the React root. + */ +export function mountReactodia(container: HTMLElement, props: ReactodiaAppProps): Root { + const root = createRoot(container); + root.render(createElement(ReactodiaApp, props)); + return root; +} + +/** + * Re-points the diagram at a new SPARQL endpoint or query preset by recreating it with a + * fresh data provider. The canvas is reset to empty, matching the initial mount. + */ +export async function updateReactodia(props: ReactodiaAppProps): Promise { + if (!workspaceContext) { + return; + } + const {model} = workspaceContext; + const dataProvider = createDataProvider(props.currentRepository, props.queryFunction, props.providerSettings); + await model.createNewDiagram({dataProvider}); +} + +/** + * Serializes the current diagram so it can be restored after a remount (e.g. when a + * language change rebuilds the workspace). Returns `undefined` if nothing is mounted yet. + */ +export function exportReactodiaLayout(): SerializedDiagram | undefined { + return workspaceContext?.model.exportLayout(); +} + +/** + * Unmounts the Reactodia application. + */ +export function unmountReactodia(root: Root): void { + root.unmount(); +} diff --git a/src/components/graphwise-reactodia/readme.md b/src/components/graphwise-reactodia/readme.md new file mode 100644 index 0000000..947313f --- /dev/null +++ b/src/components/graphwise-reactodia/readme.md @@ -0,0 +1,32 @@ +# graphwise-reactodia + + + + + + +## Overview + +A web component that renders a graph with the Reactodia workspace. + +The component is backed by a SPARQL endpoint but is endpoint-agnostic: the host passes +the active repository's endpoint via `current-repository` and a `queryFunction` that +performs the actual HTTP request. Reactodia fetches all node, link and type data lazily +through them; the canvas starts empty and the user populates it via the search bar. + +The component is a thin wrapper around Reactodia: query configuration lives outside the +wrapper and is supplied through the `providerSettings` prop. + +## Properties + +| Property | Attribute | Description | Type | Default | +| ------------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | +| `currentRepository` | `current-repository` | The active repository id. Appended to {@link queryFunction} as the request `url`; changing it re-points the graph at the new repository (and resets the canvas), which is how runtime repository changes are handled. | `string` | `undefined` | +| `language` | `language` | UI language code (e.g. `en`, `fr`) for the Reactodia interface. Defaults to English. | `string` | `'en'` | +| `providerSettings` | `provider-settings` | Query preset for the SPARQL data provider, owned and configured by the host. A DOM property (an object, not an attribute) passed in from outside the wrapper. When omitted, the data provider falls back to Reactodia's generic OWL/RDFS preset. Changing it rebuilds the data provider and resets the canvas. | `SparqlDataProviderSettings` | `undefined` | +| `queryFunction` | `query-function` | HTTP transport for the SPARQL requests. Set by the host so requests go through the host's HTTP layer (auth, interceptors) instead of a built-in `fetch`. | `(params: { url: string; body?: string; headers: { [header: string]: string; }; method: string; signal?: AbortSignal; }) => Promise` | `undefined` | + + +---------------------------------------------- + +*Built with [StencilJS](https://stenciljs.com/)* diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..5f19bf0 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,3 @@ +export { + +}; diff --git a/src/polyfill/polyfill-node.ts b/src/polyfill/polyfill-node.ts new file mode 100644 index 0000000..48d57ef --- /dev/null +++ b/src/polyfill/polyfill-node.ts @@ -0,0 +1,16 @@ +/** + * Stencil global script, executed once before any component bundle loads. + * + * Reactodia's transitive dependencies (n3 / readable-stream) reference the Node.js + * `process` global at module-evaluation time (e.g. `util.debuglog` reads + * `process.env.NODE_DEBUG`). That global does not exist in the browser, so we provide + * a minimal shim here to keep those modules from crashing + */ +export default function polyfillNode(): void { + const globalScope = globalThis as unknown as {process?: {env?: Record}}; + if (!globalScope.process) { + globalScope.process = {env: {NODE_ENV: 'production'}}; + } else if (!globalScope.process.env) { + globalScope.process.env = {NODE_ENV: 'production'}; + } +} diff --git a/stencil.config.ts b/stencil.config.ts new file mode 100644 index 0000000..d7f2ab6 --- /dev/null +++ b/stencil.config.ts @@ -0,0 +1,31 @@ +import {Config} from '@stencil/core'; +import {sass} from '@stencil/sass'; +import nodePolyfills from 'rollup-plugin-node-polyfills'; + +export const config: Config = { + namespace: 'graphwise-reactodia', + // Runs once before any component loads; rollup-plugin-node-polyfills is a code-transform plugin, + // so it needs to run AFTER the commonjs transform plugin, that's the reason it's placed in the "after" array of plugins. + // This issue occurs before that, so we need to polyfill Node APIs for the browser bundle here as well. + globalScript: 'src/polyfill/polyfill-node.ts', + sourceMap: false, + outputTargets: [ + { + type: 'dist', + esmLoaderPath: '../loader', + }, + { + type: 'docs-readme', + }, + ], + plugins: [ + sass(), + ], + // Reactodia uses some Node APIs. Polyfill them for the browser bundle. + // https://stenciljs.com/docs/module-bundling#node-polyfills + rollupPlugins: { + after: [ + nodePolyfills(), + ], + }, +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..d76b347 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "allowUnreachableCode": false, + "declaration": false, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "lib": [ + "dom", + "es2017" + ], + "baseUrl": "./", + "paths": { + "@reactodia/workspace/layout-sync": [ + "node_modules/@reactodia/workspace/dist/typings/layout-sync.d.ts" + ] + }, + "moduleResolution": "node", + "module": "esnext", + "target": "es2017", + "noUnusedLocals": true, + "noUnusedParameters": true, + "jsx": "react", + "jsxFactory": "h", + "esModuleInterop": true + }, + "include": [ + "src" + ], + "exclude": [ + "node_modules" + ] +}