├── .babelrc ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── cypress.json ├── cypress ├── fixtures │ └── example.json ├── integration │ └── tests │ │ ├── test_0.spec.js │ │ ├── test_1.spec.js │ │ ├── test_2.spec.js │ │ ├── test_3.spec.js │ │ ├── test_4.1.spec.js │ │ ├── test_4.2.spec.js │ │ ├── test_4.3.spec.js │ │ ├── test_5.spec.js │ │ └── test_6.spec.js ├── plugins │ └── index.js └── support │ ├── commands.js │ └── index.js ├── images ├── bg.png ├── favicon.png ├── icons │ ├── css │ │ └── font-awesome.css │ └── font │ │ ├── fontawesome-webfont3294.eot │ │ ├── fontawesome-webfont3294.ttf │ │ ├── fontawesome-webfont3294.woff │ │ └── fontawesome-webfontd41d.eot ├── img.jpg ├── jquery-ui │ └── picker.png ├── logo.JPG ├── settings.png └── user.png ├── localconfig.js ├── package.json ├── public_pages.sh ├── server.js ├── src ├── ApiExplorer.js ├── TerminusDB.js ├── TerminusQuery.js ├── TerminusSchema.js ├── TerminusServer.js ├── TerminusTutorial.js ├── TerminusUI.js ├── TerminusURL.js ├── UIconfig.json ├── Utils.js ├── css │ ├── basic.css │ ├── img │ │ ├── TerminusDB_Logo_Original.png │ │ └── favicon.png │ └── theme.css ├── cypress.json ├── html │ ├── DatatypeRenderers.js │ ├── Datatypes.js │ ├── DocumentPane.js │ ├── HTMLHelper.js │ ├── QueryPane.js │ ├── ResultPane.js │ ├── ScriptPane.js │ ├── TerminusViewer.js │ ├── TerminusViolation.js │ ├── chooser │ │ └── SimpleChooser.js │ ├── datatypes │ │ ├── Boolean.js │ │ ├── BooleanEditor.js │ │ ├── Choice.js │ │ ├── ChoiceEditor.js │ │ ├── Coordinate.js │ │ ├── CoordinateEditor.js │ │ ├── Date.js │ │ ├── DateEditor.js │ │ ├── DateHelper.js │ │ ├── Entity.js │ │ ├── EntityEditor.js │ │ ├── GoogleMapEditor.js │ │ ├── GoogleMapHelper.js │ │ ├── GoogleMapViewer.js │ │ ├── HTMLMarkupEditor.js │ │ ├── Image.js │ │ ├── ImageEditor.js │ │ ├── Link.js │ │ ├── Number.js │ │ ├── Range.js │ │ ├── RangeEditor.js │ │ ├── S2EntityEditor.js │ │ ├── String.js │ │ └── StringEditor.js │ ├── document │ │ ├── DocumentTable.js │ │ ├── SimpleDocument.js │ │ └── SimpleFrameViewer.js │ ├── graph │ │ ├── GraphResultsViewer.js │ │ └── SimpleGraph.js │ ├── query │ │ └── TerminusCodeSnippet.js │ ├── stream │ │ └── SimpleStream.js │ └── table │ │ └── SimpleTable.js ├── index.html ├── index.js ├── plugins │ ├── TerminusPlugin.js │ ├── codemirror.terminus.js │ └── datatables.terminus.js ├── test.js └── viewer │ └── WOQLRule.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"] 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | .env 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | public_pages 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | 18 | # nyc test coverage 19 | .nyc_output 20 | 21 | # Compiled binary addons (http://nodejs.org/api/addons.html) 22 | build/Release 23 | 24 | # Dependency directories 25 | node_modules 26 | jspm_packages 27 | 28 | # Optional npm cache directory 29 | .npm 30 | 31 | # Optional REPL history 32 | .node_repl_history 33 | 34 | # Editors 35 | .idea 36 | 37 | 38 | # npm package lock 39 | package-lock.json 40 | yarn.lock 41 | 42 | others 43 | .DS_Store 44 | 45 | .project 46 | .settings 47 | 48 | cypress/integration/examples01 49 | 50 | 51 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: required 3 | node_js: 4 | - 6 5 | # travis call prepare 6 | # create the minify version 7 | before_install: 8 | #for installing the dev version of terminus-client 9 | - | 10 | if [[ $TRAVIS_BRANCH == 'dev' ]]; then 11 | cd ../ 12 | git clone https://github.com/terminusdb/terminus-client.git 13 | cd terminus-client 14 | git checkout dev 15 | npm install 16 | cd ../terminus-dashboard 17 | npm run installClient:local 18 | fi 19 | - | 20 | if [[ $TRAVIS_BRANCH == 'master' && $TRAVIS_COMMIT_MESSAGE == *"[run deploy]"* ]]; then 21 | echo "__INCREMENT_VERSION_NUMBER__" 22 | export PACKAGE_VERSION=$(npm version patch) 23 | fi 24 | 25 | # after_script: "npm run build:all" 26 | # after_success: 27 | 28 | branches: 29 | only: 30 | - dev 31 | - master 32 | 33 | before_deploy: 34 | - | 35 | if [[ ! $TRAVIS_VAR ]]; then 36 | npm run build 37 | echo "___TRAVIS_VAR____" 38 | export TRAVIS_VAR="1.$TRAVIS_BUILD_NUMBER" 39 | 40 | git commit --amend -m "[skip travis] version changed $PACKAGE_VERSION" 41 | git push https://${GITHUB_TOKEN}@github.com/$TRAVIS_REPO_SLUG HEAD:$TRAVIS_BRANCH 42 | git tag -f -a "$PACKAGE_VERSION" -m "new version $PACKAGE_VERSION" 43 | export LAST_HASH=$(git ls-remote https://github.com/$TRAVIS_REPO_SLUG refs/heads/$TRAVIS_BRANCH | awk '{ print $1}') 44 | fi 45 | 46 | #LAST_HASH=$(git ls-remote https://github.com/terminusdb/terminus-dashboard.git master | awk '{ print $1}') 47 | #https://blog.travis-ci.com/2018-04-11-how_to_publish_node_js_packages_with_travis_ci_and_packagecloud/ 48 | deploy: 49 | - provider: releases 50 | target_commitish : $LAST_HASH 51 | keep_history: true 52 | api_key: $GITHUB_TOKEN 53 | skip_cleanup: true 54 | overwrite: true 55 | file : package-lock.json 56 | on: 57 | branch: master 58 | condition: $TRAVIS_COMMIT_MESSAGE == *"[run deploy]"* 59 | - provider: script 60 | skip_cleanup: true 61 | keep_history: true 62 | script: bash public_pages.sh 63 | on: 64 | branch: master 65 | condition: $TRAVIS_COMMIT_MESSAGE == *"[run deploy]"* 66 | # - provider: npm 67 | # registry: "https://registry.npmjs.org/" 68 | # skip_cleanup: true 69 | # access: public 70 | # email: "francesca@datachemist.com" 71 | # api_key: $NPM_TOKEN 72 | # keep_history: true 73 | # auth_method: "authToken" 74 | # on: 75 | # branch : master 76 | # condition: $TRAVIS_COMMIT_MESSAGE == *"[run deploy]"* 77 | 78 | 79 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # terminus-dashboard 2 | 3 | Management Dashboard for TerminusDB 4 | 5 | The Terminus Dashboard is a simple javascript client application that provides users with an interface for managing and querying TerminusDB. It ships with TerminusDB and is available by default at the /dashboard URL of an installed TerminusDB server (default is http://localhost:6363/dashboard 6 | 7 | The dashboard requires terminus-client to be available. 8 | 9 | To install the manually dashboard, you have 3 choices: 10 | 11 | * Include the mininfied javascript libraries (in the /dist directory) in a web page 12 | * Download the package and use npm to manage the dependencies 13 | * For developors, the npm package includes a development server 14 | 15 | 1. Minified Javascript libraries 16 | For simple HTML use, you can just add the following scripts to any HTML page 17 | ``` 18 | 19 | ``` 20 | 21 | 2. npm 22 | Clone this repo, then cd into the root dir and run: 23 | `npm install` 24 | And all of the dependencies should be automatically installed 25 | 26 | 3. developers 27 | As above and then type 28 | `npm run start:dev` 29 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } -------------------------------------------------------------------------------- /cypress/integration/tests/test_0.spec.js: -------------------------------------------------------------------------------- 1 | // to check server connect 2 | 3 | context('check connection', () => { 4 | beforeEach(() => { 5 | cy.visit('http://localhost:6363/dashboard'); 6 | }) 7 | 8 | it('Connect to a Server', () => { 9 | cy.wait(2000); 10 | cy.get('#terminus-control-panel') 11 | .find('a') 12 | .contains('Change Server') 13 | .click().then(() => { 14 | cy.wait(1000); 15 | 16 | // enter server url 17 | cy.get('#terminus-content-viewer') 18 | .find('input[placeholder="Terminus DB URL"]') 19 | .focus().type("http://195.201.12.87:6363"); 20 | 21 | // enter key 22 | cy.get('#terminus-content-viewer') 23 | .find('input[placeholder="Server API Key"]') 24 | .focus().type("root"); 25 | cy.wait(1000); 26 | 27 | // click on connect button 28 | cy.get('#terminus-content-viewer') 29 | .find('button').click().then(() => { 30 | alert('connect success'); 31 | }) 32 | }) 33 | }) // connect to a server 34 | }) 35 | -------------------------------------------------------------------------------- /cypress/integration/tests/test_1.spec.js: -------------------------------------------------------------------------------- 1 | // test to create a new database 2 | 3 | context('create database', () => { 4 | beforeEach(() => { 5 | cy.visit('http://localhost:6363/dashboard'); 6 | }) 7 | 8 | // generate random db info 9 | const dbId = 'database_e2e_test'; 10 | const dbTitle = "Test db"; 11 | const dbCommment = "Test db comment"; 12 | 13 | it('create database', () => { 14 | cy.get('#terminus-control-panel') 15 | .find('a') 16 | .contains('Create New Database') 17 | .click().then(() => { 18 | cy.wait(1000) 19 | 20 | // enter id 21 | cy.get('#terminus-content-viewer') 22 | .find('input[placeholder="No spaces or special characters allowed in IDs"]') 23 | .focus().type(dbId); 24 | 25 | // enter db name 26 | cy.get('#terminus-content-viewer') 27 | .find('input[placeholder="A brief title for the Database"]') 28 | .focus().type(dbTitle); 29 | cy.wait(1000); 30 | 31 | // enter db comment 32 | cy.get('#terminus-content-viewer') 33 | .find('textarea[placeholder="A short text describing the database and its purpose"]') 34 | .focus().type(dbCommment); 35 | cy.wait(1000); 36 | 37 | // click on create 38 | cy.get('#terminus-content-viewer') 39 | .find('button').contains('Create').click().then(() => { 40 | alert('createDatabase success'); 41 | }) 42 | 43 | cy.wait(2000); 44 | }) 45 | }) // create database 46 | }) 47 | -------------------------------------------------------------------------------- /cypress/integration/tests/test_2.spec.js: -------------------------------------------------------------------------------- 1 | // import schema from 'http://195.201.12.87:6363/docs' 2 | context('import schema', () => { 3 | beforeEach(() => { 4 | //connect to server and db 5 | cy.visit('http://localhost:6363/dashboard'); 6 | cy.get('#terminus-content-viewer') 7 | .find('table tbody tr td p') 8 | .contains('database_e2e_test') 9 | .click(); 10 | }) 11 | it('import schema', () => { 12 | // populate import schema details 13 | const schurl = 'http://195.201.12.87:6363/myFirstTerminusDB'; 14 | const key = 'nooooooooooooooooooooooo'; 15 | 16 | cy.get('.terminus-db-controller') 17 | .find('a') 18 | .contains('Schema') 19 | .click().then(() => { 20 | 21 | cy.wait(1000); 22 | cy.get('#terminus-content-viewer') 23 | .find('button') 24 | .contains('Import New Schema') 25 | .click().then(() => { 26 | cy.wait(1000); 27 | // enter url 28 | cy.get('#terminus-content-viewer') 29 | .find('input[placeholder="Enter URL of DB to import from"]') 30 | .focus().type(schurl); 31 | 32 | cy.wait(1000); 33 | // enter api key 34 | cy.get('#terminus-content-viewer') 35 | .find('input[class="terminus-form-value terminus-input-text terminus-url-key"]') 36 | .focus().type(key); 37 | 38 | // click on create 39 | cy.get('#terminus-content-viewer') 40 | .find('button').contains('Import').click().then(() => { 41 | alert('import schema success'); 42 | cy.wait(3000); 43 | }) 44 | }); 45 | }) 46 | }) // import schema 47 | }) 48 | -------------------------------------------------------------------------------- /cypress/integration/tests/test_3.spec.js: -------------------------------------------------------------------------------- 1 | // update schema 2 | // on click of import button we make sure getSchema works as well 3 | context('update schema', () => { 4 | beforeEach(() => { 5 | //connect to server and db 6 | cy.visit('http://localhost:6363/dashboard'); 7 | cy.get('#terminus-content-viewer') 8 | .find('table tbody tr td p') 9 | .contains('database_e2e_test') 10 | .click(); 11 | }) 12 | it('update schema', () => { 13 | 14 | cy.get('.terminus-db-controller') 15 | .find('a') 16 | .contains('Schema') 17 | .click().then(() => { 18 | 19 | cy.wait(1000); 20 | cy.get('#terminus-content-viewer') 21 | .find('button') 22 | .contains('Edit') 23 | .click().then(() => { 24 | cy.wait(1000); 25 | 26 | // use force: true below because the textarea is hidden 27 | // and by default Cypress won't interact with hidden elements 28 | cy.get('.CodeMirror textarea') 29 | .type('test test test test ... \n updating something here ....\n', 30 | {force: true}) 31 | 32 | cy.wait(1000); 33 | // click on save 34 | cy.get('#terminus-content-viewer') 35 | .find('button').contains('Save').click().then(() => { 36 | alert('updateSchema success'); 37 | cy.wait(3000);}) 38 | }) 39 | }) 40 | }) // import schema 41 | }) 42 | -------------------------------------------------------------------------------- /cypress/integration/tests/test_4.1.spec.js: -------------------------------------------------------------------------------- 1 | // create documents 2 | context('create document KareteGroup', () => { 3 | beforeEach(() => { 4 | //connect to server and db 5 | cy.visit('http://localhost:6363/dashboard'); 6 | cy.get('#terminus-content-viewer') 7 | .find('table tbody tr td p') 8 | .contains('database_e2e_test') 9 | .click(); 10 | }) 11 | it('create documents', () => { 12 | 13 | cy.get('.terminus-db-controller') 14 | .find('a') 15 | .contains('Document') 16 | .click().then(() => { 17 | 18 | cy.wait(2000); 19 | 20 | cy.get('.terminus-create-doc') 21 | .get('span[class="terminus-class-chooser"]') 22 | .find('select') 23 | .select('Group').then(() => { 24 | 25 | cy.wait(1000); 26 | // input id 27 | cy.get('#terminus-content-viewer') 28 | .find('input[class="terminus-object-id-input" ]') 29 | .focus().type('doc:KarateGroup'); 30 | 31 | // input label 32 | cy.get('#terminus-content-viewer') 33 | .find('div[data-property="rdfs:label"]') 34 | .find('input[type="text"]') 35 | .focus().type('KarateGroup'); 36 | cy.wait(1000); 37 | 38 | // input comment 39 | cy.get('#terminus-content-viewer') 40 | .find('div[data-property="rdfs:comment"]') 41 | .find('textarea') 42 | .focus().type('Creating a group for Karate'); 43 | cy.wait(1000); 44 | 45 | // input website 46 | cy.get('#terminus-content-viewer') 47 | .find('div[data-property="tcs:website"]') 48 | .find('input[type="text"]') 49 | .focus().type('www.awesomnessKarate.com'); 50 | cy.wait(1000); 51 | 52 | // input fb 53 | cy.get('#terminus-content-viewer') 54 | .find('div[data-property="tcs:facebook_page"]') 55 | .find('input[type="text"]') 56 | .focus().type('https://facebook/KarateKickAsses'); 57 | cy.wait(1000); 58 | 59 | // input email 60 | cy.get('#terminus-content-viewer') 61 | .find('div[data-property="tcs:email_address"]') 62 | .find('input[type="text"]') 63 | .focus().type('karateKickers.info@whatever.com'); 64 | cy.wait(3000); 65 | 66 | // hit save 67 | cy.get('#terminus-content-viewer') 68 | .find('button') 69 | .contains('Save') 70 | .click().then(() => { 71 | alert('createDocument Group Karate success'); 72 | }) 73 | }) 74 | }) 75 | }) // create document 76 | }) 77 | -------------------------------------------------------------------------------- /cypress/integration/tests/test_4.2.spec.js: -------------------------------------------------------------------------------- 1 | // create documents 2 | context('create document Bruce Lee', () => { 3 | beforeEach(() => { 4 | //connect to server and db 5 | cy.visit('http://localhost:6363/dashboard'); 6 | cy.get('#terminus-content-viewer') 7 | .find('table tbody tr td p') 8 | .contains('database_e2e_test') 9 | .click(); 10 | }) 11 | it('create documents', () => { 12 | 13 | cy.get('.terminus-db-controller') 14 | .find('a') 15 | .contains('Document') 16 | .click().then(() => { 17 | 18 | cy.wait(2000); 19 | 20 | cy.get('.terminus-create-doc') 21 | .get('span[class="terminus-class-chooser"]') 22 | .find('select') 23 | .select('Person').then(() => { 24 | 25 | cy.wait(1000); 26 | 27 | // input id 28 | cy.get('#terminus-content-viewer') 29 | .find('input[class="terminus-object-id-input" ]') 30 | .focus().type('doc:BruceLee'); 31 | 32 | // input member of 33 | cy.get('#terminus-content-viewer') 34 | .find('div[data-property="tcs:member_of"]') 35 | .find('input[type="text"]') 36 | .focus().type('doc:KarateGroup'); 37 | cy.wait(1000); 38 | 39 | // input Label 40 | cy.get('#terminus-content-viewer') 41 | .find('div[data-property="rdfs:label"]') 42 | .find('input[type="text"]') 43 | .focus().type('Bruce Lee'); 44 | cy.wait(1000); 45 | 46 | // input comment 47 | cy.get('#terminus-content-viewer') 48 | .find('div[data-property="rdfs:comment"]') 49 | .find('textarea') 50 | .focus().type('Creating a person Bruce Lee'); 51 | cy.wait(1000); 52 | 53 | // input fb 54 | cy.get('#terminus-content-viewer') 55 | .find('div[data-property="tcs:facebook_page"]') 56 | .find('input[type="text"]') 57 | .focus().type('https://facebook/BruceLee.555'); 58 | cy.wait(1000); 59 | 60 | // input email 61 | cy.get('#terminus-content-viewer') 62 | .find('div[data-property="tcs:email_address"]') 63 | .find('input[type="text"]') 64 | .focus().type('bruceLeeKicker@whatever.com'); 65 | cy.wait(3000); 66 | 67 | // hit save 68 | cy.get('#terminus-content-viewer') 69 | .find('button') 70 | .contains('Save') 71 | .click().then(() => { 72 | alert('createDocument Person Bruce Lee success'); 73 | }) 74 | }) 75 | }) 76 | }) // create document 77 | }) 78 | -------------------------------------------------------------------------------- /cypress/integration/tests/test_4.3.spec.js: -------------------------------------------------------------------------------- 1 | // create documents 2 | context('create document Jackie Chan', () => { 3 | beforeEach(() => { 4 | //connect to server and db 5 | cy.visit('http://localhost:6363/dashboard'); 6 | cy.get('#terminus-content-viewer') 7 | .find('table tbody tr td p') 8 | .contains('database_e2e_test') 9 | .click(); 10 | }) 11 | it('create documents', () => { 12 | 13 | cy.get('.terminus-db-controller') 14 | .find('a') 15 | .contains('Document') 16 | .click().then(() => { 17 | 18 | cy.wait(2000); 19 | 20 | cy.get('.terminus-create-doc') 21 | .get('span[class="terminus-class-chooser"]') 22 | .find('select') 23 | .select('Person').then(() => { 24 | 25 | cy.wait(1000); 26 | 27 | // input id 28 | cy.get('#terminus-content-viewer') 29 | .find('input[class="terminus-object-id-input" ]') 30 | .focus().type('doc:JackieChan'); 31 | 32 | // input member of 33 | cy.get('#terminus-content-viewer') 34 | .find('div[data-property="tcs:member_of"]') 35 | .find('input[type="text"]') 36 | .focus().type('doc:KarateGroup'); 37 | cy.wait(1000); 38 | 39 | // input Label 40 | cy.get('#terminus-content-viewer') 41 | .find('div[data-property="rdfs:label"]') 42 | .find('input[type="text"]') 43 | .focus().type('Jackie Chan'); 44 | cy.wait(1000); 45 | 46 | // input comment 47 | cy.get('#terminus-content-viewer') 48 | .find('div[data-property="rdfs:comment"]') 49 | .find('textarea') 50 | .focus().type('Creating a person Jackie Chan'); 51 | cy.wait(1000); 52 | 53 | // input fb 54 | cy.get('#terminus-content-viewer') 55 | .find('div[data-property="tcs:facebook_page"]') 56 | .find('input[type="text"]') 57 | .focus().type('https://facebook/JackieChan.555'); 58 | cy.wait(1000); 59 | 60 | // hit save 61 | cy.get('#terminus-content-viewer') 62 | .find('button') 63 | .contains('Save') 64 | .click().then(() => { 65 | alert('createDocument Person Jackie Chan success'); 66 | }) 67 | }) 68 | }) 69 | }) // create document 70 | }) 71 | -------------------------------------------------------------------------------- /cypress/integration/tests/test_5.spec.js: -------------------------------------------------------------------------------- 1 | // update document 2 | // on clicking on a doc getDocument is also tested 3 | context('update document Jackie Chan', () => { 4 | 5 | beforeEach(() => { 6 | //connect to server and db 7 | cy.visit('http://localhost:6363/dashboard'); 8 | cy.get('#terminus-content-viewer') 9 | .find('table tbody tr td p') 10 | .contains('database_e2e_test') 11 | .click().then(() => { 12 | cy.wait(1000); 13 | cy.get('#terminus-content-viewer') 14 | .find('a') 15 | .contains('doc:JackieChan') 16 | .click(); 17 | cy.wait(1000); 18 | }) 19 | }) 20 | 21 | it('update documents', () => { 22 | cy.wait(1000); 23 | cy.get('#terminus-content-viewer') 24 | .find('div[class="terminus-document-controller"]') 25 | .find('select') 26 | .select('Edit Document').then(() => { 27 | cy.wait(1000); 28 | 29 | // update comment 30 | cy.get('#terminus-content-viewer') 31 | .find('div[data-property="rdfs:comment"]') 32 | .find('textarea') 33 | .focus().clear().type('Updating Jackie Chans info'); 34 | cy.wait(1000); 35 | 36 | // make Jackie Chan friends with Bruce Lee 37 | cy.get('#terminus-content-viewer') 38 | .find('span[class="terminus-object-add-property"]:first') // the first obj header 39 | .find('select') 40 | .select('Friend').then(() => { 41 | cy.wait(1000); 42 | 43 | // input friend 44 | cy.get('#terminus-content-viewer') 45 | .find('div[data-property="tcs:friend"]') 46 | .find('input[type="text"]') 47 | .focus().type('doc:BruceLee'); 48 | cy.wait(1000); 49 | 50 | }) // add property 51 | 52 | // add fb a/c 53 | cy.get('#terminus-content-viewer') 54 | .find('div[data-property="tcs:facebook_page"]') 55 | .find('button') 56 | .contains('Add') 57 | .click().then(() => { 58 | cy.wait(1000); 59 | 60 | cy.get('#terminus-content-viewer') 61 | .find('div[data-property="tcs:facebook_page"]') 62 | .find('input[type="text"]:eq(1)') 63 | .focus().type('https://facebook.secondProfileForJackie'); 64 | }) 65 | }); 66 | 67 | // hit save 68 | cy.get('#terminus-content-viewer') 69 | .find('button') 70 | .contains('Save') 71 | .click().then(() => { 72 | alert('updatedDocument for Person Jackie Chan success'); 73 | }) 74 | }) // update document 75 | }) 76 | -------------------------------------------------------------------------------- /cypress/integration/tests/test_6.spec.js: -------------------------------------------------------------------------------- 1 | // delete database 2 | context('delete database', () => { 3 | 4 | beforeEach(() => { 5 | //connect to server and db 6 | cy.visit('http://localhost:6363/dashboard'); 7 | cy.get('#terminus-content-viewer') 8 | .find('table tbody tr td p') 9 | .contains('database_e2e_test') 10 | .click().then(() => { 11 | cy.wait(1000); 12 | }) 13 | }) 14 | 15 | it('delete database', () => { 16 | cy.wait(1000); 17 | cy.get('#terminus-content-viewer') 18 | .find('button') 19 | .contains('Delete Database') 20 | .click().then(() => { 21 | cy.wait(3000); 22 | alert('deleteDatabase successfully'); 23 | }) 24 | }) // delete database 25 | }) 26 | -------------------------------------------------------------------------------- /cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example plugins/index.js can be used to load plugins 3 | // 4 | // You can change the location of this file or turn off loading 5 | // the plugins file with the 'pluginsFile' configuration option. 6 | // 7 | // You can read more here: 8 | // https://on.cypress.io/plugins-guide 9 | // *********************************************************** 10 | 11 | // This function is called when a project is opened or re-opened (e.g. due to 12 | // the project's config changing) 13 | 14 | module.exports = (on, config) => { 15 | // `on` is used to hook into various events Cypress emits 16 | // `config` is the resolved Cypress config 17 | } 18 | -------------------------------------------------------------------------------- /cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add("login", (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This is will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /cypress/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /images/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terminusdb/terminus-dashboard/f578c3004cbea315fc8f41c789cf57f59db01c39/images/bg.png -------------------------------------------------------------------------------- /images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terminusdb/terminus-dashboard/f578c3004cbea315fc8f41c789cf57f59db01c39/images/favicon.png -------------------------------------------------------------------------------- /images/icons/font/fontawesome-webfont3294.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terminusdb/terminus-dashboard/f578c3004cbea315fc8f41c789cf57f59db01c39/images/icons/font/fontawesome-webfont3294.eot -------------------------------------------------------------------------------- /images/icons/font/fontawesome-webfont3294.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terminusdb/terminus-dashboard/f578c3004cbea315fc8f41c789cf57f59db01c39/images/icons/font/fontawesome-webfont3294.ttf -------------------------------------------------------------------------------- /images/icons/font/fontawesome-webfont3294.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terminusdb/terminus-dashboard/f578c3004cbea315fc8f41c789cf57f59db01c39/images/icons/font/fontawesome-webfont3294.woff -------------------------------------------------------------------------------- /images/icons/font/fontawesome-webfontd41d.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terminusdb/terminus-dashboard/f578c3004cbea315fc8f41c789cf57f59db01c39/images/icons/font/fontawesome-webfontd41d.eot -------------------------------------------------------------------------------- /images/img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terminusdb/terminus-dashboard/f578c3004cbea315fc8f41c789cf57f59db01c39/images/img.jpg -------------------------------------------------------------------------------- /images/jquery-ui/picker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terminusdb/terminus-dashboard/f578c3004cbea315fc8f41c789cf57f59db01c39/images/jquery-ui/picker.png -------------------------------------------------------------------------------- /images/logo.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terminusdb/terminus-dashboard/f578c3004cbea315fc8f41c789cf57f59db01c39/images/logo.JPG -------------------------------------------------------------------------------- /images/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terminusdb/terminus-dashboard/f578c3004cbea315fc8f41c789cf57f59db01c39/images/settings.png -------------------------------------------------------------------------------- /images/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terminusdb/terminus-dashboard/f578c3004cbea315fc8f41c789cf57f59db01c39/images/user.png -------------------------------------------------------------------------------- /localconfig.js: -------------------------------------------------------------------------------- 1 | // config.js 2 | const dotenv = require('dotenv'); 3 | dotenv.config(); 4 | module.exports = { 5 | endpoint: process.env.API_URL, 6 | apiKey: process.env.API_KEY 7 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@terminusdb/terminus-dashboard", 3 | "version": "1.1.10", 4 | "description": "Terminus DB Management Dashboard", 5 | "main": "src/index.js", 6 | "directories": { 7 | "src": "src" 8 | }, 9 | "scripts": { 10 | "test": "", 11 | "clean": "rimraf -r dist/*", 12 | "start:dev": "webpack-dev-server", 13 | "build:all": "npm run build:client && npm run build", 14 | "build": "webpack --mode production", 15 | "build:client": "cd ./node_modules/@terminusdb/terminus-client && npm install && npm run build", 16 | "prepare": "npm run clean && npm run build", 17 | "cypress:open": "cypress open", 18 | "cypress:run": "cypress run --browser chrome", 19 | "installClient:local": "npm install --no-save ../terminus-client" 20 | }, 21 | "devDependencies": { 22 | "@babel/core": "^7.5.5", 23 | "@babel/preset-env": "^7.5.5", 24 | "@babel/register": "^7.5.5", 25 | "babel-loader": "^8.0.6", 26 | "cypress": "^3.4.1", 27 | "html-loader": "^0.5.5", 28 | "html-webpack-plugin": "^3.2.0", 29 | "rimraf": "^2.6.2", 30 | "uglify-js": "^3.6.0", 31 | "webpack": "^4.39.3", 32 | "webpack-cli": "^3.3.7", 33 | "webpack-dev-server": "^3.8.0" 34 | }, 35 | "repository": { 36 | "type": "git", 37 | "url": "git+https://github.com/terminusdb/terminus-dashboard.git" 38 | }, 39 | "keywords": [ 40 | "Terminus", 41 | "WOQL", 42 | "Driver", 43 | "DB" 44 | ], 45 | "author": "kevin@datachemist.com", 46 | "license": "Apache-2.0", 47 | "bugs": { 48 | "url": "https://github.com/terminusdb/terminus-dashboard/issues" 49 | }, 50 | "homepage": "https://github.com/terminusdb/terminus-dashboard#readme", 51 | "dependencies": { 52 | "copy-webpack-plugin": "^5.0.4", 53 | "dotenv-webpack": "^1.7.0", 54 | "@terminusdb/terminus-client": "^1.1.4" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /public_pages.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "___SONO IN SCRIPT____" 3 | 4 | 5 | PUBLICATION_BRANCH=gh-pages 6 | # Checkout the branch 7 | REPO_PATH=$PWD 8 | 9 | echo "$REPO_PATH" 10 | 11 | pushd "$HOME" || exit 12 | git clone --branch=$PUBLICATION_BRANCH "https://${GITHUB_TOKEN}@github.com/$TRAVIS_REPO_SLUG" tmp_pages 2>&1 > /dev/null 13 | cd tmp_pages || exit 14 | 15 | rm -rf ./1.1.10 16 | 17 | echo 'package=$PACKAGE_VERSION' 18 | # Update pages 19 | cp -r $REPO_PATH/public_pages/. . 20 | 21 | rm -rf ./dist/* 22 | 23 | cp -r $REPO_PATH/public_pages/$PACKAGE_VERSION/dist/* ./dist 24 | 25 | # Commit and push latest version 26 | git add . 27 | git config user.name "Travis" 28 | git config user.email "travis@travis-ci.org" 29 | git commit -m "Updated version." 30 | git push -fq origin $PUBLICATION_BRANCH 2>&1 > /dev/null 31 | popd || exit 32 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Webpack = require('webpack'); 4 | const WebpackDevServer = require("webpack-dev-server"); 5 | const webpackConfig = require('./webpack.config'); 6 | 7 | const compiler = Webpack(webpackConfig); 8 | const devServerOptions = Object.assign({}, webpackConfig.devServer, { 9 | open: true, 10 | stats: { 11 | colors: true, 12 | }, 13 | }); 14 | const server = new WebpackDevServer(compiler, devServerOptions); 15 | 16 | server.listen(8080, '127.0.0.1', () => { 17 | console.log('Starting server on http://localhost:8080'); 18 | }); -------------------------------------------------------------------------------- /src/TerminusQuery.js: -------------------------------------------------------------------------------- 1 | const TerminusClient = require('@terminusdb/terminus-client'); 2 | const ScriptPane = require("./html/ScriptPane"); 3 | const HTMLHelper = require('./html/HTMLHelper'); 4 | const TerminusViewer = require("./html/TerminusViewer"); 5 | 6 | function TerminusQueryViewer(ui, options){ 7 | this.ui = ui; 8 | this.tv = new TerminusViewer(ui.client); 9 | this.options = options; 10 | this.panes = []; 11 | this.new_pane = false; 12 | this.new_pane_type = false; 13 | this.meta = {}; 14 | this.container = document.createElement("div"); 15 | this.container.setAttribute("class", "terminus-query-page"); 16 | } 17 | 18 | TerminusQueryViewer.prototype.newPaneOptions = function(){ 19 | var opts = { 20 | showQuery: "always", 21 | editQuery: true, 22 | showHeader: true, 23 | css: "terminus-full-query-pane" 24 | }; 25 | return opts; 26 | } 27 | 28 | TerminusQueryViewer.prototype.defaultResultOptions = function(){ 29 | var opts = { 30 | showConfig: "icon", 31 | editConfig: true, 32 | showHeader: false, 33 | viewers: [new TerminusClient.View.graph()], 34 | }; 35 | return opts; 36 | } 37 | 38 | TerminusQueryViewer.prototype.getNewQueryPane = function(){ 39 | let table = TerminusClient.View.table(); 40 | let qpane = this.tv.getQueryPane(false, [table], false, [this.defaultResultOptions()], this.newPaneOptions()); 41 | return qpane; 42 | } 43 | 44 | TerminusQueryViewer.prototype.addQueryPane = function(){ 45 | var qpane = this.getNewQueryPane(); 46 | this.panes.push(qpane); 47 | return qpane; 48 | } 49 | 50 | TerminusQueryViewer.prototype.addScriptPane = function(q){ 51 | let qpane = new ScriptPane(this.ui.client, q); 52 | this.panes.push(qpane); 53 | return qpane; 54 | } 55 | 56 | TerminusQueryViewer.prototype.addScriptPaneDOM = function(){ 57 | let qpane = new ScriptPane(this.ui.client); 58 | this.addNewPaneDOM(qpane); 59 | } 60 | 61 | TerminusQueryViewer.prototype.addQueryPaneDOM = function(){ 62 | let qpane = this.addQueryPane(); 63 | this.addNewPaneDOM(qpane); 64 | } 65 | 66 | TerminusQueryViewer.prototype.setNewDocumentPaneDOM = function(){ 67 | this.new_pane = this.tv.getDocumentPane(); 68 | //this.new_pane = new DocumentPane(this.ui.client).options({showQuery: true, editQuery: true}); 69 | this.new_pane_type = "document"; 70 | } 71 | 72 | TerminusQueryViewer.prototype.addNewPaneDOM = function(qpane){ 73 | var lpane = this.panes[this.panes.length-1]; 74 | //if(lpane && lpane.empty()){ 75 | // this.panes[this.panes.length-1] = qpane; 76 | // this.paneDOM.removeChild(this.paneDOM.lastChild) 77 | //} 78 | //else { 79 | this.panes.push(qpane); 80 | //} 81 | var qdom = qpane.getAsDOM(); 82 | var qhdr = this.getPaneHeader(); 83 | qdom.prepend(qhdr); 84 | this.paneDOM.appendChild(qdom); 85 | } 86 | 87 | TerminusQueryViewer.prototype.getAsDOM = function(q){ 88 | HTMLHelper.removeChildren(this.container); 89 | if(!this.paneDOM) this.paneDOM = this.getPanesDOM(); 90 | this.container.appendChild(this.paneDOM); 91 | this.controlDOM = this.getControlsDOM(); 92 | //this.container.appendChild(this.controlDOM); 93 | var cont = document.createElement("span"); 94 | cont.setAttribute("class", "terminus-new-query-pane"); 95 | var newPaneButton = document.createElement('button'); 96 | newPaneButton.setAttribute('class', 'terminus-btn terminus-query-btn'); 97 | newPaneButton.appendChild(document.createTextNode('Add New Query')); 98 | newPaneButton.addEventListener('click', () => this.addQueryPaneDOM()); 99 | cont.appendChild(newPaneButton); 100 | this.container.appendChild(cont); 101 | return this.container; 102 | } 103 | 104 | TerminusQueryViewer.prototype.getPanesDOM = function(q){ 105 | this.panesDOM = document.createElement("div"); 106 | this.panesDOM.setAttribute("class", "terminus-query-panes"); 107 | for(var i = 0; i this.addQueryPaneDOM()); 167 | c.appendChild(newPaneButton); 168 | var newScriptButton = document.createElement('button'); 169 | newScriptButton.setAttribute('class', 'terminus-btn terminus-query-btn'); 170 | newScriptButton.appendChild(document.createTextNode('Script')); 171 | //newScriptButton.addEventListener('click', () => this.addScriptPaneDOM()); 172 | c.appendChild(newScriptButton); 173 | var newDocButton = document.createElement('button'); 174 | newDocButton.setAttribute('class', 'terminus-btn terminus-query-btn'); 175 | newDocButton.appendChild(document.createTextNode('Document Query')); 176 | newDocButton.addEventListener('click', () => this.setNewDocumentPaneDOM()); 177 | c.appendChild(newDocButton); 178 | } 179 | else { 180 | var savePaneButton = document.createElement('button'); 181 | savePaneButton.setAttribute('class', 'terminus-btn terminus-query-btn'); 182 | savePaneButton.appendChild(document.createTextNode('Save')); 183 | c.appendChild(savePaneButton); 184 | var closePaneButton = document.createElement('button'); 185 | closePaneButton.setAttribute('class', 'terminus-btn terminus-query-btn'); 186 | closePaneButton.appendChild(document.createTextNode('Close')); 187 | c.appendChild(closePaneButton); 188 | var collapsePaneButton = document.createElement('button'); 189 | collapsePaneButton.setAttribute('class', 'terminus-btn terminus-query-btn'); 190 | collapsePaneButton.appendChild(document.createTextNode('Collapse')); 191 | c.appendChild(collapsePaneButton); 192 | } 193 | return c; 194 | } 195 | 196 | 197 | module.exports=TerminusQueryViewer 198 | -------------------------------------------------------------------------------- /src/TerminusSchema.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Draws the screen for viewing and updating the schema 3 | * and provides wrappers around the client's schema API 4 | */ 5 | const UTILS=require('./Utils') 6 | const TerminusClient = require('@terminusdb/terminus-client'); 7 | const HTMLHelper = require('./html/HTMLHelper'); 8 | const TerminusViewer = require('./html/TerminusViewer'); 9 | 10 | 11 | function TerminusSchemaViewer(ui){ 12 | this.ui = ui; 13 | this.tv = new TerminusViewer(ui.client); 14 | 15 | this.mode = "view"; 16 | this.format = "turtle"; 17 | this.confirm_before_update = false; 18 | this.woql = TerminusClient.WOQL; 19 | this.views = { 20 | classes: { 21 | title: "Classes" 22 | }, 23 | properties: { 24 | title: "Properties" 25 | }, 26 | owl: { 27 | title: "OWL" 28 | } 29 | } 30 | this.views_dom = document.createElement("div"); 31 | this.current_view = "classes"; 32 | this.retrieveViews(); 33 | } 34 | 35 | TerminusSchemaViewer.prototype.getClassesPane = function() { 36 | let WOQL = TerminusClient.WOQL; 37 | let query = this.woql.limit(100) 38 | .start(0) 39 | .and( 40 | WOQL.quad("v:Class", "rdf:type", "owl:Class", "db:schema"), 41 | WOQL.opt().quad("v:Class", "rdfs:label", "v:Label", "db:schema"), 42 | WOQL.opt().quad("v:Class", "rdfs:subClassOf", "v:Parent", "db:schema"), 43 | WOQL.opt().quad("v:Child", "rdfs:subClassOf", "v:Class", "db:schema"), 44 | WOQL.opt().quad("v:Class", "rdfs:comment", "v:Comment", "db:schema"), 45 | WOQL.opt().quad("v:Class", "tcs:tag", "v:Abstract", "db:schema") 46 | ); 47 | 48 | var table = TerminusClient.View.table(); 49 | table.column_order("Class", "Label", "Comment", "Parent", "Child", "Abstract") 50 | table.column('Comment').header('Description'); 51 | table.column('Class').header('Class ID'); 52 | table.column('Label').header('Name'); 53 | table.column('Child').header('Subclasses'); 54 | table.column('Parent').header('Parent Classes'); 55 | table.column('Range').header('Type'); 56 | 57 | var graph = TerminusClient.View.graph(); 58 | graph.edges(["v:Class", "v:Parent"], ["v:Child", "v:Class"], ["v:Class", "v:Abstract"]); 59 | 60 | 61 | graph.height(800); 62 | graph.width(1200); 63 | graph.edge("v:Class", "v:Parent").text("Parent Class").distance(120); 64 | graph.edge("v:Child", "v:Class").text("Parent Class").distance(120); 65 | graph.edge("v:Class", "v:Abstract").text("Abstract Class").weight(2).color([0,0,0]); 66 | graph.node("Parent").size(20).color([180, 220, 250]).icon({label: true, size: 0.7, color: [90, 90, 140]}); 67 | graph.node("Class").text("v:Label").size(32).collisionRadius(80).icon({label: true, size: 0.7, color: [24, 34, 89]}); 68 | 69 | var rpc = { viewers: [graph] } 70 | var qp = this.tv.getQueryPane(query, [table], false, [rpc]); 71 | //var qp = this.tv.getQueryPane(query, [graph, table]); 72 | 73 | return qp; 74 | } 75 | 76 | TerminusSchemaViewer.prototype.getPropertiesPane = function() { 77 | let query = this.woql.from(this.ui.client.connectionConfig.dbURL()) 78 | .limit(100) 79 | .start(0) 80 | .propertyMetadata(); 81 | 82 | var table = TerminusClient.View.table(); 83 | table.column_order("Property", "Label", "Range", "Domain", "Comment") 84 | table.column('Comment').header('Description'); 85 | table.column('Property').header('Property ID'); 86 | table.column('Label').header('Name'); 87 | table.column('Domain').header('Domain'); 88 | table.column('Range').header('Type'); 89 | 90 | var graph = TerminusClient.View.graph(); 91 | graph.height(800); 92 | graph.width(1200); 93 | graph.edges(["Domain", "Property"], ["Property", "Range"]); 94 | graph.edge("Domain", "Property").text("Domain Class").color([20, 200, 20]).distance(120); 95 | graph.edge("Property", "Range").text("Property Type").distance(100); 96 | graph.node("Type").hidden(true); 97 | graph.node("Range").text("v:Range").size(20).collisionRadius(100).color([220, 250, 180]).icon({label: true, size: 0.8, color: [50, 60, 40]}); 98 | graph.node("Range").v("Type").in("owl:datatypeProperty").hidden(true); 99 | graph.node("Property").text("v:Label").size(24).collisionRadius(100).color([180, 220, 250]).icon({label: true, size: 0.8, color: [50, 60, 40]}); 100 | graph.node("Domain").color([220, 250, 180]).size(20).collisionRadius(100).icon({label: true, size: 0.7, color: [24, 34, 89]}); 101 | var rpc = { viewers: [graph] } 102 | var qp = this.tv.getQueryPane(query, [table], false, [rpc]); 103 | //var qp = this.tv.getQueryPane(query, [graph, table]); 104 | return qp; 105 | } 106 | 107 | TerminusSchemaViewer.prototype.refreshPanes = function(){ 108 | if(this.views.classes.pane) this.views.classes.pane.load(); 109 | if(this.views.properties.pane) this.views.properties.pane.load(); 110 | } 111 | 112 | TerminusSchemaViewer.prototype.retrieveViews = function(){ 113 | if(!this.views.classes.pane){ 114 | let pane = this.getClassesPane(); 115 | this.views.classes.pane = pane; 116 | let dom = pane.getAsDOM(); 117 | if(this.current_view != "classes") dom.style.display = "none"; 118 | this.views_dom.appendChild(dom); 119 | pane.load(); 120 | this.views.classes.dom = dom; 121 | } 122 | if(!this.views.properties.pane){ 123 | let pane = this.getPropertiesPane(); 124 | this.views.properties.pane = pane; 125 | let dom = pane.getAsDOM(); 126 | if(this.current_view != "properties") dom.style.display = "none"; 127 | this.views_dom.appendChild(dom); 128 | this.views.properties.dom = dom; 129 | pane.load(); 130 | } 131 | if(!this.views.owl.dom){ 132 | this.views.owl.dom = this.getOWLView(); 133 | this.views_dom.appendChild(this.views.owl.dom); 134 | if(this.current_view != "owl") this.views.owl.dom.style.display = "none"; 135 | } 136 | } 137 | 138 | 139 | /* 140 | * Retrieves schema from API and writes the response into the page 141 | */ 142 | TerminusSchemaViewer.prototype.getAsDOM = function(){ 143 | 144 | this.holder = document.createElement("div"); 145 | this.controldom = document.createElement("div"); 146 | this.controldom.setAttribute("class", "terminus-schema-controls"); 147 | this.controldom.appendChild(this.getTabsDOM()); 148 | this.view = document.createElement("div"); 149 | this.view.setAttribute("class", "terminus-schema-view"); 150 | this.view.appendChild(this.views_dom); 151 | this.pagedom = document.createElement("div"); 152 | this.pagedom.setAttribute("class", "terminus-schema-viewer"); 153 | this.holder.appendChild(this.controldom); 154 | this.pagedom.appendChild(this.view); 155 | this.holder.appendChild(this.pagedom); 156 | return this.holder; 157 | } 158 | 159 | TerminusSchemaViewer.prototype.getOWLView = function(){ 160 | var owldom = document.createElement("div"); 161 | this.loadSchema(); 162 | return owldom; 163 | } 164 | 165 | TerminusSchemaViewer.prototype.updateOWLContents = function(){ 166 | var owldom = this.views.owl.dom; 167 | HTMLHelper.removeChildren(owldom); 168 | if(this.mode == 'view'){ 169 | owldom.appendChild(this.getSchemaEditButton()); 170 | owldom.appendChild(this.getSchemaViewDOM()); 171 | } 172 | else if(this.mode == "edit"){ 173 | owldom.appendChild(this.getSchemaSaveButtons()); 174 | owldom.appendChild(this.getSchemaEditDOM()); 175 | owldom.appendChild(this.getSchemaSaveButtons()); 176 | } 177 | } 178 | 179 | 180 | TerminusSchemaViewer.prototype.getTabsDOM = function(){ 181 | var ul = document.createElement('ul'); 182 | ul.setAttribute('class', 'terminus-ul-horizontal'); 183 | for(var k in this.views){ 184 | var a = this.getTabDOM(k, this.views[k].title); 185 | ul.appendChild(a); 186 | if(k == this.current_view) UTILS.setSelectedSubMenu(a); 187 | } 188 | return ul; 189 | } 190 | 191 | TerminusSchemaViewer.prototype.getTabDOM = function(view, title){ 192 | var a = document.createElement('a'); 193 | a.setAttribute('class', 'terminus-a terminus-hz-list-group-a terminus-list-group-a-action terminus-nav-width terminus-pointer'); 194 | var self = this; 195 | a.addEventListener("click", function(){ 196 | self.switchView(this, view); 197 | }) 198 | a.appendChild(document.createTextNode(title)); 199 | return a; 200 | } 201 | 202 | TerminusSchemaViewer.prototype.switchView = function(a, view){ 203 | UTILS.setSelectedSubMenu(a); 204 | if(view != this.current_view){ 205 | this.current_view = view; 206 | this.toggleTabs(); 207 | } 208 | } 209 | 210 | TerminusSchemaViewer.prototype.toggleTabs = function(){ 211 | for(var k in this.views){ 212 | if(this.views[k].dom && k == this.current_view) this.views[k].dom.style.display = "block"; 213 | else if(this.views[k].dom) this.views[k].dom.style.display = "none"; 214 | } 215 | } 216 | 217 | TerminusSchemaViewer.prototype.loadSchema = function(msg, msgtype){ 218 | var self = this; 219 | this.ui.showBusy("Fetching Database Schema"); 220 | return this.ui.client.getSchema(false, {"terminus:encoding": "terminus:" + this.format}) 221 | .then(function(response){ 222 | self.ui.clearBusy(); 223 | self.schema = response; 224 | self.updateOWLContents() 225 | }) 226 | .catch(function(error){ 227 | self.ui.clearBusy(); 228 | self.ui.showError(error); 229 | }); 230 | } 231 | 232 | TerminusSchemaViewer.prototype.getSchemaSaveButtons = function(){ 233 | var ssb = document.createElement("span"); 234 | ssb.setAttribute("class", "terminus-schema-save-buttons"); 235 | ssb.appendChild(this.getCancelButton()); 236 | ssb.appendChild(this.getSaveButton()); 237 | return ssb; 238 | } 239 | 240 | TerminusSchemaViewer.prototype.getCancelButton = function(is_import){ 241 | var self = this; 242 | var func = function(){ 243 | self.ui.clearMessages(); 244 | self.mode = "view"; 245 | self.updateOWLContents(); 246 | } 247 | return this.getSchemaButton("Cancel", "cancel_update", func); 248 | } 249 | 250 | TerminusSchemaViewer.prototype.getSaveButton = function(){ 251 | var self = this; 252 | var func = function(){ 253 | self.ui.clearMessages(); 254 | var text = self.schema_edit_dom.value; 255 | if(typeof(self.schema) == "object"){ 256 | text = JSON.parse(text); 257 | } 258 | var opts = {}; 259 | opts['terminus:encoding'] = 'terminus:' + self.format; 260 | if(!(TerminusClient.UTILS.empty(self.schema_edit_dom_name))) 261 | opts['schemaId'] = self.ui.client.connectionConfig.dbURL() + '/' + self.schema_edit_dom_name.value; 262 | else opts['schemaId'] = self.ui.client.connectionConfig.dbURL() + '/' + 'schema'; 263 | return self.updateSchema(text, opts); 264 | } 265 | return this.getSchemaButton("Save", "update_schema", func); 266 | } 267 | 268 | TerminusSchemaViewer.prototype.getSchemaEditButton = function(){ 269 | var ssb = document.createElement("span"); 270 | ssb.setAttribute("class", "terminus-schema-save-buttons"); 271 | var self = this; 272 | var func = function(){ 273 | self.mode = "edit"; 274 | self.updateOWLContents(); 275 | } 276 | var but = this.getSchemaButton("Edit", "update_schema", func); 277 | ssb.appendChild(but); 278 | return ssb; 279 | } 280 | 281 | /* 282 | * Updates schema, then fetches updated version and updates the page with it 283 | */ 284 | TerminusSchemaViewer.prototype.updateSchema = function(text, opts) { 285 | this.ui.showBusy("Updating Database Schema"); 286 | var self = this; 287 | return this.ui.client.updateSchema(false, text, opts) 288 | .then(function(response){ 289 | if(response['terminus:status'] && response['terminus:status'] == "terminus:success"){ 290 | self.ui.showBusy("Retrieving updated schema"); 291 | self.mode = "view"; 292 | self.loadSchema("Successfully Updated Schema"); 293 | self.refreshPanes(); 294 | self.updateOWLContents(); 295 | } 296 | else if(response['terminus:status'] && response['terminus:status'] == "terminus:failure"){ 297 | self.ui.clearBusy(); 298 | self.ui.showViolations(response['terminus:witnesses'], "schema"); 299 | } 300 | else { 301 | throw new Error("Update Schema returned no terminus:status code"); 302 | } 303 | }) 304 | .catch(function(error){ 305 | self.ui.clearBusy(); 306 | if(error.data && error.data['terminus:witnesses']){ 307 | self.ui.showViolations(error.data['terminus:witnesses'], "schema"); 308 | } 309 | else { 310 | self.ui.showError(error); 311 | } 312 | }); 313 | } 314 | 315 | TerminusSchemaViewer.prototype.getSchemaEditDOM = function(){ 316 | var np = document.createElement("div"); 317 | np.setAttribute("class", "terminus-schema-page terminus-schema-edit-page"); 318 | if(this.ui.showControl("add_new_library")) var sid = this.getSchemaNameInputDOM(np); 319 | var ipval = document.createElement("textarea"); 320 | ipval.setAttribute("class", "terminus-schema-edit terminus-schema-textarea"); 321 | ipval.setAttribute("width", "100%"); 322 | ipval.setAttribute("style", "min-width: 400px; min-height: 400px;"); 323 | if(typeof(this.schema) == "string"){ 324 | ipval.innerHTML = this.schema; 325 | } 326 | else if(typeof (this.schema) == "object") { 327 | ipval.innerHTML = JSON.stringify(this.schema, 0, 4); 328 | } 329 | if(this.ui.showControl("add_new_library")) this.schema_edit_dom_name = sid; 330 | this.schema_edit_dom = ipval; 331 | np.appendChild(ipval); 332 | UTILS.stylizeEditor(this.ui, ipval, 'schema', 'turtle'); 333 | return np; 334 | } 335 | 336 | TerminusSchemaViewer.prototype.getSchemaViewDOM = function(){ 337 | var self = this; 338 | var np = document.createElement("div"); 339 | np.setAttribute("class", "terminus-schema-page terminus-schema-view-page"); 340 | var ipval = document.createElement("pre"); 341 | ipval.setAttribute("class", "terminus-schema-view terminus-scheme-pre"); 342 | if(typeof(this.schema) == "string"){ 343 | var txt = this.schema.replace(/&/g, "&") 344 | .replace(//g, ">") 346 | .replace(/"/g, """) 347 | .replace(/'/g, "'"); 348 | ipval.innerHTML = txt; 349 | } 350 | else if(typeof (this.schema) == "object") { 351 | ipval.innerHTML = JSON.stringify(this.schema, 0, 4); 352 | } 353 | var cm = UTILS.stylizeCodeDisplay(this.ui, ipval, np, 'turtle'); 354 | if(!cm) np.appendChild(ipval); 355 | return np; 356 | } 357 | 358 | TerminusSchemaViewer.prototype.getSchemaButton = function(label, action, func){ 359 | var opt = document.createElement("button"); 360 | opt.appendChild(document.createTextNode(label)); 361 | opt.setAttribute("class", "terminus-btn terminus-control-button terminus-schema-" + action); 362 | opt.addEventListener("click", func); 363 | return opt; 364 | } 365 | 366 | 367 | module.exports=TerminusSchemaViewer 368 | -------------------------------------------------------------------------------- /src/TerminusServer.js: -------------------------------------------------------------------------------- 1 | /* User interface elements that relate to server context 2 | * 3 | * TerminusServerController is a control widget that invokes server actions 4 | * TerminusServerViewer is a window that displays server actions and server screens 5 | * 6 | */ 7 | const Datatables = require('./plugins/datatables.terminus'); 8 | const UTILS =require('./Utils'); 9 | const HTMLHelper = require('./html/HTMLHelper'); 10 | 11 | function TerminusServerController(ui){ 12 | this.ui = ui; 13 | } 14 | 15 | TerminusServerController.prototype.getAsDOM = function(){ 16 | var rsc = document.createElement("div"); 17 | rsc.setAttribute("class", "terminus-server-controller"); 18 | var self = this; 19 | if(this.ui && this.ui.server()){ 20 | var scd = document.createElement("div"); 21 | scd.setAttribute("class", "terminus-server-connection"); 22 | var nav = document.createElement('div'); 23 | nav.setAttribute('class', 'span3'); 24 | var ul = document.createElement('ul'); 25 | ul.setAttribute('class', 'terminus-ul'); 26 | nav.appendChild(ul); 27 | rsc.appendChild(nav); 28 | // connected to server 29 | // change server 30 | if(this.ui.showControl("change-server")){ 31 | var a = document.createElement('a'); 32 | a.setAttribute('class', 'terminus-a terminus-list-group-a terminus-list-group-a-action terminus-nav-width terminus-pointer'); 33 | var self = this; 34 | a.addEventListener("click", function(){ 35 | UTILS.activateSelectedNav(this, self); 36 | self.ui.clearMessages(); 37 | self.ui.showLoadURLPage(); 38 | }) 39 | var icon = document.createElement('i'); 40 | icon.setAttribute('class', 'terminus-menu-icon fa fa-link'); 41 | a.appendChild(icon); 42 | var txt = document.createTextNode('Change Server'); 43 | a.appendChild(txt); 44 | ul.appendChild(a); 45 | } 46 | // view databases 47 | if(this.ui.showControl("db")){ 48 | var a = document.createElement('a'); 49 | a.setAttribute('class', 'terminus-a terminus-list-group-a terminus-list-group-a-action terminus-nav-width terminus-pointer'); 50 | var self = this; 51 | a.addEventListener("click", function(){ 52 | UTILS.activateSelectedNav(this, self); 53 | if(self.ui.db()){ 54 | self.ui.clearDB(); 55 | self.ui.redrawControls(); 56 | } 57 | self.ui.clearMessages(); 58 | self.ui.showServerMainPage(); 59 | }) 60 | var icon = document.createElement('i'); 61 | icon.setAttribute('class', 'terminus-menu-icon fa fa-home'); 62 | a.appendChild(icon); 63 | var txt = document.createTextNode('Home'); 64 | a.appendChild(txt); 65 | ul.appendChild(a); 66 | } 67 | if(this.ui.showControl("create_database")){ 68 | var a = document.createElement('a'); 69 | a.setAttribute('class', 'terminus-a terminus-list-group-a terminus-list-group-a-action terminus-nav-width terminus-pointer'); 70 | var self = this; 71 | a.addEventListener("click", function(){ 72 | UTILS.activateSelectedNav(this, self); 73 | if(self.ui.db()){ 74 | self.ui.clearDB(); 75 | self.ui.redrawControls(); 76 | } 77 | self.ui.clearMessages(); 78 | self.ui.showCreateDBPage(); 79 | }) 80 | var icon = document.createElement('i'); 81 | icon.setAttribute('class', 'terminus-menu-icon fa fa-plus'); 82 | a.appendChild(icon); 83 | var txt = document.createTextNode('Create Database'); 84 | a.appendChild(txt); 85 | ul.appendChild(a); 86 | } 87 | if(this.ui.showControl("collaborate")){ 88 | var a = document.createElement('a'); 89 | a.setAttribute('class', 'terminus-a terminus-list-group-a terminus-list-group-a-action terminus-nav-width terminus-pointer'); 90 | var self = this; 91 | a.addEventListener("click", function(){ 92 | UTILS.activateSelectedNav(this, self); 93 | if(self.ui.db()){ 94 | self.ui.clearDB(); 95 | self.ui.redrawControls(); 96 | } 97 | self.ui.clearMessages(); 98 | self.ui.showCollaboratePage(); 99 | }) 100 | var icon = document.createElement('i'); 101 | icon.setAttribute('class', 'terminus-menu-icon fa fa-share-alt'); 102 | a.appendChild(icon); 103 | var txt = document.createTextNode('Collaborate'); 104 | a.appendChild(txt); 105 | ul.appendChild(a); 106 | } 107 | if(this.ui.showControl("tutorials")){ 108 | var a = document.createElement('a'); 109 | a.setAttribute('class', 'terminus-a terminus-list-group-a terminus-list-group-a-action terminus-nav-width terminus-pointer'); 110 | var self = this; 111 | a.addEventListener("click", function(){ 112 | UTILS.activateSelectedNav(this, self); 113 | if(self.ui.db()){ 114 | self.ui.clearDB(); 115 | self.ui.redrawControls(); 116 | } 117 | self.ui.clearMessages(); 118 | self.ui.showTutorialPage(); 119 | }) 120 | var icon = document.createElement('i'); 121 | icon.setAttribute('class', 'terminus-menu-icon fa fa-university'); 122 | a.appendChild(icon); 123 | var txt = document.createTextNode('Tutorials'); 124 | a.appendChild(txt); 125 | ul.appendChild(a); 126 | } 127 | } 128 | return rsc; 129 | } 130 | 131 | TerminusServerController.prototype.getServerLabelDOM = function(){ 132 | var srec = this.ui.client.connection.getServerRecord(); 133 | var lab = (srec && srec['rdfs:label'] && srec['rdfs:label']["@value"] ? srec['rdfs:label']["@value"] : this.ui.server()); 134 | var desc = (srec && srec['rdfs:comment'] && srec['rdfs:comment']["@value"] ? srec['rdfs:comment']["@value"] : ""); 135 | desc += " Server URL: "+ this.ui.server(); 136 | var val = document.createElement("span"); 137 | val.setAttribute("class", "terminus-server-value"); 138 | val.setAttribute("title", desc); 139 | val.appendChild(document.createTextNode(lab)); 140 | val = document.createElement('div'); 141 | return val; 142 | } 143 | 144 | function TerminusServerViewer(ui){ 145 | this.ui = ui; 146 | this.server = this.ui.server(); 147 | this.max_cell_size = 500; 148 | this.max_word_size = 40; 149 | this.css_base = window.css_base || '';//"https://terminusdb.github.io/terminus-dashboard/dist/"; 150 | 151 | } 152 | 153 | TerminusServerViewer.prototype.getAsDOM = function(selected){ 154 | var self = this; 155 | var pd = document.createElement("span"); 156 | pd.setAttribute("class", "terminus-server-home-page"); 157 | if(this.ui.server()){ 158 | var scd = document.createElement("span"); 159 | scd.setAttribute("class", "terminus-server-home"); 160 | if(this.ui.showView("server")){ 161 | scd.appendChild(this.getServerDetailsDOM()); 162 | } 163 | if(this.ui.showView("change-server")){ 164 | var csbut = document.createElement("button"); 165 | csbut.setAttribute("class", "terminus-control-button terminus-change-server-button terminus-btn") 166 | csbut.appendChild(document.createTextNode("Disconnect")); 167 | csbut.addEventListener("click", function(){ 168 | if(self.ui.db()){ 169 | self.ui.clearDB(); 170 | } 171 | self.ui.showLoadURLPage(); 172 | }) 173 | // 11092019 scd.appendChild(csbut); 174 | } 175 | if(this.ui.showView("create_database")){ 176 | var crbut = document.createElement("button"); 177 | crbut.setAttribute("class", "terminus-control-button terminus-create-db-button terminus-btn") 178 | crbut.appendChild(document.createTextNode("Create New Database")); 179 | crbut.addEventListener("click", function(){ 180 | if(self.ui.db()){ 181 | self.ui.clearDB(); 182 | } 183 | self.ui.clearMessages(); 184 | self.ui.showCreateDBPage(); 185 | }) 186 | } 187 | if(this.ui.showView("db")){ 188 | scd.appendChild(this.getDBListDOM()); 189 | } 190 | pd.appendChild(scd); 191 | } 192 | else { 193 | self.ui.showLoadURLPage(); 194 | } 195 | return pd; 196 | } 197 | 198 | TerminusServerViewer.prototype.getServerDetailsDOM = function(){ 199 | var scd = document.createElement("div"); 200 | scd.setAttribute("class", "terminus-server-details terminus-welcome-box terminus-no-res-alert"); 201 | var icon = document.createElement("img"); 202 | icon.setAttribute("class", "terminus-server-main-logo") 203 | var url = this.css_base + "css/img/TerminusDB_Logo_Original.png" 204 | icon.setAttribute("src", url); 205 | scd.appendChild(icon); 206 | var scl = document.createElement("p"); 207 | scl.setAttribute("class", "terminus-server-running") 208 | scl.appendChild(document.createTextNode("Terminus Server running at ")) 209 | scl.appendChild(document.createTextNode(this.ui.server())) 210 | scd.appendChild(scl); 211 | return scd; 212 | } 213 | 214 | TerminusServerViewer.prototype.wrapTableLinkCell = function(tdElement,dbid, text){ 215 | var self = this; 216 | var wrap = document.createElement("p"); 217 | // wrap.setAttribute("href", "#"); 218 | wrap.setAttribute("class", "terminus-table-content"); 219 | HTMLHelper.wrapShortenedText(wrap, text, this.max_cell_size, this.max_word_size); 220 | tdElement.addEventListener("click", function(){ 221 | self.ui.connectToDB(dbid); 222 | self.ui.showDBMainPage(); 223 | }); 224 | return wrap; 225 | } 226 | 227 | TerminusServerViewer.prototype.getDBListDOM = function(){ 228 | //var self = this; 229 | var sec = document.createElement("div"); 230 | sec.setAttribute("class", "terminus-db-list"); 231 | //sec.appendChild(UTILS.getHeaderDom('Databases')); 232 | var scd = document.createElement("table"); 233 | scd.setAttribute("class", "terminus-db-list terminus-db-size terminus-hover-table terminus-margin-top"); 234 | var thead = document.createElement("thead"); 235 | var thr = document.createElement("tr"); 236 | var th1 = document.createElement("th"); 237 | th1.appendChild(document.createTextNode("Database ID")); 238 | th1.setAttribute("class", "terminus-db-id terminus-table-header-full-css"); 239 | th1.style.width = "20%"; 240 | var th2 = document.createElement("th"); 241 | th2.appendChild(document.createTextNode("Title")); 242 | th2.setAttribute("class", "terminus-db-title terminus-table-header-full-css"); 243 | th2.style.width = "30%"; 244 | var th3 = document.createElement("th"); 245 | th3.appendChild(document.createTextNode("Description")); 246 | th3.setAttribute("class", "terminus-db-description terminus-table-header-full-css"); 247 | th3.style.width = "50%"; 248 | var th4 = document.createElement("th"); 249 | th4.setAttribute("class", "terminus-db-size terminus-table-header-full-css"); 250 | th4.appendChild(document.createTextNode("Size")); 251 | var th5 = document.createElement("th"); 252 | th5.setAttribute("class", "terminus-db-created terminus-table-header-full-css"); 253 | th5.appendChild(document.createTextNode("Created")); 254 | var th6 = document.createElement("th"); 255 | th6.appendChild(document.createTextNode("Delete")); 256 | th6.setAttribute("class", "terminus-db-delete terminus-table-header-full-css"); 257 | thr.appendChild(th1); 258 | thr.appendChild(th2); 259 | thr.appendChild(th3); 260 | //thr.appendChild(th4); 261 | //thr.appendChild(th5); 262 | //thr.appendChild(th6); 263 | thead.appendChild(thr); 264 | scd.appendChild(thead); 265 | var tbody = document.createElement("tbody"); 266 | var dbrecs = this.ui.client.connection.getServerDBRecords(); 267 | for(let fullid in dbrecs){ 268 | let dbrec = dbrecs[fullid]; 269 | const dbid = fullid.split(":")[1]; 270 | let tr = document.createElement("tr"); 271 | var td1 = document.createElement("td"); 272 | td1.appendChild(this.wrapTableLinkCell(td1,dbid, dbid)); 273 | td1.setAttribute("class", "terminus-db-id terminus-db-pointer"); 274 | var td2 = document.createElement("td"); 275 | td2.setAttribute("class", "terminus-db-title terminus-db-pointer"); 276 | var txt = (dbrec && dbrec['rdfs:label'] && dbrec['rdfs:label']['@value'] ? dbrec['rdfs:label']['@value'] : ""); 277 | td2.appendChild(this.wrapTableLinkCell(td2,dbid, txt)); 278 | var td3 = document.createElement("td"); 279 | td3.setAttribute("class", "terminus-db-description terminus-db-pointer"); 280 | var txt = (dbrec && dbrec['rdfs:comment'] && dbrec['rdfs:comment']['@value'] ? dbrec['rdfs:comment']['@value'] : ""); 281 | td3.appendChild(this.wrapTableLinkCell(td3,dbid, txt)); 282 | var td4 = document.createElement("td"); 283 | td4.setAttribute("class", "terminus-db-size terminus-db-pointer"); 284 | var txt = (dbrec && dbrec['terminus:size'] && dbrec['terminus:size']['@value'] ? dbrec['terminus:size']['@value'] : ""); 285 | td4.appendChild(this.wrapTableLinkCell(td4,dbid, txt)); 286 | var td5 = document.createElement("td"); 287 | td5.setAttribute("class", "terminus-db-created terminus-db-pointer"); 288 | var txt = (dbrec && dbrec['terminus:last_updated'] && dbrec['terminus:last_updated']['@value'] ? dbrec['terminus:last_updated']['@value'] : ""); 289 | td5.appendChild(this.wrapTableLinkCell(td5,dbid, txt)); 290 | var td6 = document.createElement("td"); 291 | td6.setAttribute("class", "db-delete"); 292 | var delbut = this.ui.getDeleteDBButton(dbid); 293 | if(delbut) td6.appendChild(delbut); 294 | 295 | tr.appendChild(td1); 296 | tr.appendChild(td2); 297 | tr.appendChild(td3); 298 | //tr.appendChild(td4); 299 | //tr.appendChild(td5); 300 | //tr.appendChild(td6); 301 | tbody.appendChild(tr); 302 | } 303 | scd.appendChild(tbody); 304 | sec.appendChild(scd); 305 | 306 | if(this.ui.pluginAvailable("datatables")){ 307 | var dt = new Datatables.CspDatatables(this.ui); 308 | var tab = dt.draw(scd); 309 | } 310 | return sec; 311 | } 312 | 313 | 314 | module.exports = {TerminusServerViewer,TerminusServerController} 315 | -------------------------------------------------------------------------------- /src/TerminusTutorial.js: -------------------------------------------------------------------------------- 1 | const UTILS = require("./Utils.js"); 2 | const HTMLHelper = require('./html/HTMLHelper'); 3 | 4 | 5 | function TerminusTutorialLoader(ui){ 6 | this.ui = ui; 7 | this.tutorial_server = "https://terminusdb.github.io/terminus-tutorials/"; 8 | this.fetchOptions(); 9 | this.container = document.createElement("span"); 10 | this.container.setAttribute("class", "terminus-main-page"); 11 | } 12 | 13 | TerminusTutorialLoader.prototype.fetchOptions = function(){ 14 | let self = this; 15 | let cback = function(){ 16 | self.showTutorialChoices() 17 | } 18 | HTMLHelper.loadDynamicScript("tutorials", this.tutorial_server + "tutorials.js", cback); 19 | } 20 | 21 | TerminusTutorialLoader.prototype.drawChoices = function(){ 22 | if(this.choices){ 23 | for(var i = 0 ; i < this.choices.length; i++){ 24 | this.showChoice(this.choices[i]); 25 | } 26 | } 27 | } 28 | 29 | 30 | TerminusTutorialLoader.prototype.showTutorialChoices = function(){ 31 | this.choices = getTutorialOptions(); 32 | this.drawChoices(); 33 | } 34 | 35 | 36 | TerminusTutorialLoader.prototype.showChoice = function(choice){ 37 | var hbox = document.createElement("div"); 38 | hbox.setAttribute("class", "terminus-welcome-box terminus-no-res-alert"); 39 | var ispan = document.createElement("span"); 40 | ispan.setAttribute("class", "terminus-db-widget"); 41 | if(choice.css){ 42 | var ic = document.createElement("i"); 43 | ic.setAttribute("class", choice.css); 44 | ispan.appendChild(ic); 45 | } 46 | hbox.appendChild(ispan); 47 | var htit = document.createElement("span"); 48 | htit.appendChild(document.createElement("strong").appendChild(document.createTextNode(choice.title))); 49 | htit.classList.add('terminus-welcome-title'); 50 | hbox.appendChild(htit); 51 | var body = document.createElement("p"); 52 | body.setAttribute('class', 'terminus-welcome-body'); 53 | body.appendChild(document.createTextNode(choice.text)); 54 | hbox.appendChild(body); 55 | let self = this 56 | hbox.addEventListener("click", function(){ 57 | self.prepareDatabase(choice) 58 | }); 59 | this.container.appendChild(hbox); 60 | } 61 | 62 | TerminusTutorialLoader.prototype.getAsDOM = function(){ 63 | HTMLHelper.removeChildren(this.container); 64 | this.drawChoices(); 65 | return this.container; 66 | } 67 | 68 | TerminusTutorialLoader.prototype.prepareDatabase = function(choice){ 69 | this.client.deleteDatabase(choice.id) 70 | .finally(()=>{ 71 | this.ui.CreateDatabase(choice) 72 | .finally(()=>{ 73 | this.loadTutorial(choice) 74 | }) 75 | }) 76 | } 77 | 78 | //also need to update the UI screen 79 | TerminusTutorialLoader.prototype.loadTutorial = function(choice){ 80 | let self = this; 81 | let cback = function(){ 82 | self.startTutorial(choice, TerminusTutorial); 83 | } 84 | HTMLHelper.loadDynamicScript(choice.id, this.tutorial_server + choice.id + "/tutorial.js", cback); 85 | } 86 | 87 | 88 | TerminusTutorialLoader.prototype.showTutorialLaunchPage = function(choice, tutorialConfig){ 89 | HTMLHelper.removeChildren(this.container); 90 | //alert(tid) 91 | return this.container; 92 | } 93 | 94 | TerminusTutorialLoader.prototype.startTutorial = function(choice, tutorialConfig) { 95 | this.showTutorialLaunchPage(choice, tutorialConfig) 96 | } 97 | 98 | TerminusTutorialLoader.prototype.createSchema = function(OWLSchema){ 99 | return this.client.updateSchema(OWLSchema) 100 | } 101 | 102 | TerminusTutorialLoader.prototype.insert = function(insertJSON){ 103 | return this.client.woql(insertJSON) 104 | } 105 | 106 | TerminusTutorialLoader.prototype.query = function(selectWOQL){ 107 | return this.client.woql(selectWOQL) 108 | } 109 | 110 | TerminusTutorialLoader.prototype.showTutorialStages = function(stages){ 111 | // 112 | this.stages = []; 113 | 114 | return this.client.woql(InsertJSON) 115 | } 116 | 117 | TerminusTutorialLoader.prototype.loadTutorialStage = function(stage){ 118 | // 119 | 120 | return this.client.woql(InsertJSON) 121 | } 122 | 123 | function getNextStageButton(func){ 124 | let but = document.createElement("button"); 125 | but.appendChild(document.createTextNode("Next Step")) 126 | but.addEventListener("click", function(){ 127 | func(); 128 | }) 129 | return but; 130 | } 131 | 132 | TerminusTutorialLoader.prototype.executeStage = function(func){ 133 | let but = document.createElement("button"); 134 | but.appendChild(document.createTextNode("Run Query")) 135 | but.addEventListener("click", function(){ 136 | func(); 137 | }) 138 | return but; 139 | } 140 | 141 | 142 | TerminusTutorialLoader.prototype.showStageResult = function(q, v, complete){ 143 | let vu = v || `let view = View.table()`; 144 | var rq = Viewer.getQueryPane(eval(q), eval(vu), false, false, {showQuery: false}); 145 | let rd = rq.getAsDOM(); 146 | rq.load(); 147 | return rd; 148 | } 149 | 150 | 151 | /** 152 | * 153 | * @param {WOQLClient} client 154 | * @param {String} id 155 | * @param {String} title 156 | * @param {String} description 157 | 158 | function createDatabase(id, title, description){ 159 | title = title || "Seshat"; 160 | description = description || "Seshat global history databank"; 161 | const dbdetails = { 162 | "@context" : { 163 | rdfs: "http://www.w3.org/2000/01/rdf-schema#", 164 | terminus: "http://terminusdb.com/schema/terminus#" 165 | }, 166 | "@type": "terminus:Database", 167 | 'rdfs:label' : { "@language": "en", "@value": title }, 168 | 'rdfs:comment': { "@language": "en", "@value": description}, 169 | 'terminus:allow_origin': { "@type" : "xsd:string", "@value" : "*" } 170 | }; 171 | return WOQLclient.createDatabase(id, dbdetails); 172 | } 173 | 174 | 175 | */ 176 | 177 | module.exports=TerminusTutorialLoader 178 | -------------------------------------------------------------------------------- /src/TerminusURL.js: -------------------------------------------------------------------------------- 1 | const UTILS = require("./Utils.js"); 2 | 3 | function TerminusURLLoader(ui, val){ 4 | this.ui = ui; 5 | this.val = val; 6 | this.url_input = false; 7 | this.key_input = false; 8 | } 9 | 10 | TerminusURLLoader.prototype.getLabelDOM = function(){ 11 | return document.createTextNode("Connect"); 12 | } 13 | 14 | TerminusURLLoader.prototype.getFormFieldDOM = function(ip, fname, ltxt, pholder){ 15 | var sci = document.createElement("div"); 16 | sci.setAttribute("class", "terminus-form-horizontal terminus-control-group terminus-form-field-spacing terminus-display-flex terminus-field-"+fname); 17 | var lab = document.createElement("span"); 18 | lab.setAttribute("class", "terminus-control-label terminus-form-label terminus-form-field-label terminus-label-"+fname); 19 | lab.appendChild(document.createTextNode(ltxt)) 20 | ip.setAttribute("type", "text"); 21 | ip.setAttribute("placeholder", pholder); 22 | sci.appendChild(lab); 23 | sci.appendChild(ip); 24 | return sci; 25 | } 26 | 27 | TerminusURLLoader.prototype.getAsDOM = function(){ 28 | var scd = document.createElement("div"); 29 | scd.setAttribute("class", "terminus-form terminus-url-loader"); 30 | scd.appendChild(UTILS.getHeaderDom('Connect To Terminus Server')); 31 | var mfd = document.createElement('div'); 32 | mfd.setAttribute('class', 'terminus-form-border terminus-margin-top'); 33 | scd.appendChild(mfd); 34 | this.url_input = document.createElement("input"); 35 | this.url_input.setAttribute("class", "terminus-form-value terminus-form-url terminus-form-field-input terminus-input-text"); 36 | if(this.val){ 37 | this.url_input.value = this.val; 38 | } 39 | var dht = document.createElement('div'); 40 | dht.setAttribute('class', 'terminus-form-margin-top'); 41 | mfd.appendChild(dht); 42 | if(!this.ui.attachedServer()){ 43 | mfd.appendChild(this.getFormFieldDOM(this.url_input, "connect", "URL", "Terminus DB URL")); 44 | } 45 | this.key_input = document.createElement("input"); 46 | this.key_input.setAttribute("class", "terminus-form-value terminus-value terminus-input-text"); 47 | mfd.appendChild(this.getFormFieldDOM(this.key_input, "connect", "Key", "Server API Key")); 48 | var loadbuts = document.createElement("div"); 49 | loadbuts.setAttribute("class", "terminus-control-buttons"); 50 | var loadbut = document.createElement("button"); 51 | loadbut.setAttribute("class", "terminus-control-button terminus-url-load terminus-btn terminus-btn-float-right"); 52 | loadbut.appendChild(document.createTextNode("Connect")); 53 | var self = this; 54 | loadbut.addEventListener("click", function(){ 55 | let keyval = self.key_input.value; 56 | let url = (self.ui.attachedServer() ? self.ui.attachedServer() : self.url_input.value); 57 | if(url){ 58 | self.ui.load(url, keyval); 59 | } 60 | }); 61 | loadbuts.appendChild(loadbut); 62 | mfd.appendChild(loadbuts); 63 | return scd; 64 | } 65 | 66 | 67 | module.exports=TerminusURLLoader 68 | -------------------------------------------------------------------------------- /src/UIconfig.json: -------------------------------------------------------------------------------- 1 | let TerminusConfig = { 2 | controls: ["collaborate", "server", "db", "import_schema", "create_database", 3 | "get_document", "get_schema", "update_schema", "woql_select" 4 | ], 5 | css: "theme", 6 | plugins: { 7 | "font-awesome": true, 8 | gmaps: { 9 | key: "GMAPS_DEV_KEY_HERE", 10 | loaded: false 11 | }, 12 | jquery: true, 13 | jqueryui: false, 14 | datatables: false, 15 | quill: true, 16 | select2: false, 17 | codemirror: { 18 | darkMode: false, // true for dark theamed text editor 19 | loaded: true 20 | } 21 | }, 22 | location: { server: "http://localhost:6363", key: "root"} 23 | }; 24 | -------------------------------------------------------------------------------- /src/css/img/TerminusDB_Logo_Original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terminusdb/terminus-dashboard/f578c3004cbea315fc8f41c789cf57f59db01c39/src/css/img/TerminusDB_Logo_Original.png -------------------------------------------------------------------------------- /src/css/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terminusdb/terminus-dashboard/f578c3004cbea315fc8f41c789cf57f59db01c39/src/css/img/favicon.png -------------------------------------------------------------------------------- /src/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:3000" 3 | } 4 | -------------------------------------------------------------------------------- /src/html/DatatypeRenderers.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Maintains a list of renderers that are available for rendering 3 | * datatype values - also covers choice values and id values 4 | */ 5 | 6 | function DatatypeRenderers(options){ 7 | this.registeredDataViewers = {}, 8 | this.registeredDataEditors = {}, 9 | this.defaultViewers = {}; 10 | this.defaultEditors = {}; 11 | this.universalViewer = false; 12 | this.universalEditor = false; 13 | if(options) this.options(options); 14 | //links to other documents, choices, id field, id fields of contained objects, ids of structural elements: properties, etc 15 | this.specials = ['document', 'oneOf', 'id', 'contained', 'structural']; 16 | } 17 | 18 | DatatypeRenderers.prototype.options = function (options){ 19 | this.universalViewer = (options && options.universalViewer ? options.universalViewer : false); 20 | this.universalEditor = (options && options.universalEditor ? options.universalEditor : false); 21 | this.editor = (options && options.editor ? options.editor : false); 22 | } 23 | 24 | DatatypeRenderers.prototype.getValidDataViewerList = function(datatype){ 25 | let valids = []; 26 | if(datatype && typeof this.registeredDataViewers[datatype] != "undefined"){ 27 | valids = valids.concat(this.registeredDataViewers[datatype]); 28 | } 29 | if(this.universalViewer && valids.indexOf(this.universalViewer) == -1){ 30 | valids.push(this.universalViewer); 31 | } 32 | return valids; 33 | }; 34 | 35 | DatatypeRenderers.prototype.getValidDataEditorList = function(datatype){ 36 | let valids = []; 37 | if(datatype && typeof this.registeredDataEditors[datatype] != "undefined"){ 38 | var nftypes = this.registeredDataEditors[datatype]; 39 | if(nftypes){ 40 | for(var i = 0; i this.filterFrame()); 30 | } 31 | if(this.clsid){ 32 | return this.frame.load(false, this.clsid).then(() => { 33 | this.frame.document.fillFromSchema("_:"); 34 | this.filterFrame(); 35 | }); 36 | } 37 | return Promise.reject("Either document id or class id must be specified before loading a document"); 38 | } 39 | 40 | DocumentPane.prototype.options = function(opts){ 41 | this.showQuery = (opts && typeof opts.showQuery != "undefined" ? opts.showQuery : false); 42 | this.showConfig = (opts && typeof opts.showConfig != "undefined" ? opts.showConfig : false); 43 | this.editConfig = (opts && typeof opts.editConfig != "undefined" ? opts.editConfig : false); 44 | this.intro = (opts && typeof opts.intro != "undefined" ? opts.intro : false); 45 | this.documentLoader = (opts && typeof opts.loadDocument != "undefined" ? opts.loadDocument : false); 46 | this.loadSchema = (opts && typeof opts.loadSchema != "undefined" ? opts.loadSchema : false); 47 | this.viewers = (opts && typeof opts.viewers != "undefined" ? opts.viewers : false); 48 | Datatypes.initialiseDataRenderers(this.datatypes, false, opts); 49 | return this; 50 | } 51 | 52 | DocumentPane.prototype.filterFrame = function(){ 53 | var self = this; 54 | var myfilt = function(frame, rule){ 55 | if(typeof rule.render() != "undefined"){ 56 | frame.render = rule.render(); 57 | } 58 | else { 59 | if(rule.renderer()){ 60 | var renderer = self.loadRenderer(rule.renderer(), frame, rule.args); 61 | } 62 | if(renderer && renderer.render){ 63 | frame.render = function(fframe){ 64 | return renderer.render(fframe); 65 | } 66 | } 67 | } 68 | if(rule.compare()){ 69 | frame.compare = rule.compare(); 70 | } 71 | } 72 | this.frame.applyRules(false, false, myfilt); 73 | } 74 | 75 | DocumentPane.prototype.loadDocument = function(docid, config){ 76 | this.docid = docid; 77 | this.view = config; 78 | return this.load(); 79 | } 80 | 81 | DocumentPane.prototype.loadClass = function(cls, config){ 82 | this.clsid = cls; 83 | this.docid = false; 84 | this.view = config; 85 | return this.load(); 86 | } 87 | 88 | 89 | 90 | DocumentPane.prototype.setClassLoader = function(cloader){ 91 | this.classLoader = cloader; 92 | if(this.queryPane){ 93 | this.queryPane.appendChild(this.classLoader); 94 | } 95 | return this; 96 | } 97 | 98 | DocumentPane.prototype.getQueryPane = function(){ 99 | var pane = document.createElement("div"); 100 | pane.setAttribute("class", "terminus-document-query"); 101 | if(this.documentLoader){ 102 | pane.appendChild(this.documentLoader); 103 | } 104 | if(this.classLoader){ 105 | pane.appendChild(this.classLoader); 106 | } 107 | return pane; 108 | } 109 | 110 | DocumentPane.prototype.getAsDOM = function(){ 111 | if(this.intro){ 112 | this.container.appendChild(UTILS.getHeaderDom(this.intro)); 113 | } 114 | var configspan = document.createElement("span"); 115 | configspan.setAttribute("class", "pane-config-icons"); 116 | this.container.appendChild(configspan); 117 | if(this.showQuery && (this.documentLoader || this.classLoader)){ 118 | var ipdom = this.getQueryPane(); 119 | var ispan = document.createElement("span"); 120 | ispan.setAttribute("class", "document-pane-config"); 121 | var ic = document.createElement("i"); 122 | ispan.appendChild(ic); 123 | if(this.showQuery != "always") configspan.appendChild(ispan); 124 | var self = this; 125 | function showQueryConfig(){ 126 | ispan.title="Click to Hide Query"; 127 | ic.setAttribute("class", "fas fa fa-times-circle"); 128 | if(configspan.nextSibling) self.container.insertBefore(ipdom, configspan.nextSibling); 129 | else self.container.appendChild(ipdom); 130 | } 131 | function hideQueryConfig(){ 132 | ispan.title="Click to View Query"; 133 | ic.setAttribute("class", "fas fa fa-search"); 134 | self.container.removeChild(ipdom); 135 | } 136 | ispan.addEventListener("click", () => { 137 | if(this.showingQuery) hideQueryConfig(); 138 | else showQueryConfig(); 139 | this.showingQuery = !this.showingQuery; 140 | }); 141 | showQueryConfig(); 142 | if(this.showQuery == "icon") hideQueryConfig(); 143 | this.queryPane = ipdom; 144 | } 145 | if(this.showConfig){ 146 | this.showingConfig = (this.showConfig != "icon"); 147 | var mode = (this.editConfig ? "edit" : "view"); 148 | this.input = this.createInput(mode); 149 | var ndom = this.input.getAsDOM(); 150 | var nspan = document.createElement("span"); 151 | nspan.addEventListener('mouseover', function(){ 152 | this.style.cursor = "pointer"; 153 | }); 154 | nspan.setAttribute("class", "result-pane-config"); 155 | var nc = document.createElement("i"); 156 | nspan.appendChild(nc); 157 | configspan.appendChild(nspan); 158 | var self = this; 159 | function showDocConfig(){ 160 | nspan.title="Click to Hide View Configuration"; 161 | nc.setAttribute("class", "fas fa fa-times-circle"); 162 | if(configspan.nextSibling) self.container.insertBefore(ndom, configspan.nextSibling); 163 | else self.container.appendChild(ndom); 164 | //stylize only after ta or pre have been appended 165 | if((self.input.snippet.value) || (self.input.snippet.innerHTML)) 166 | self.input.stylizeSnippet(); 167 | } 168 | function hideDocConfig(){ 169 | nspan.title="Click to View Configuration"; 170 | nc.setAttribute("class", "fas fa fa-vial"); 171 | self.container.removeChild(ndom); 172 | } 173 | nspan.addEventListener("click", () => { 174 | if(this.showingConfig) hideDocConfig(); 175 | else showDocConfig(); 176 | this.showingConfig = !this.showingConfig; 177 | }); 178 | showDocConfig(); 179 | if(this.showConfig == "icon") hideDocConfig(); 180 | } 181 | this.resultDOM = document.createElement("span"); 182 | this.resultDOM.setAttribute("class", "terminus-document-results"); 183 | //var form = (this.input.format == "js" ? "javascript" : "json"); 184 | //UTILS.stylizeEditor(ui, this.input.snippet, {width: this.input.width, height: this.input.height}, form); 185 | this.container.appendChild(this.resultDOM); 186 | this.renderResult(); 187 | return this.container; 188 | } 189 | 190 | DocumentPane.prototype.renderResult = function(){ 191 | if(this.resultDOM){ 192 | HTMLHelper.removeChildren(this.resultDOM); 193 | } 194 | else { 195 | this.resultDOM = document.createElement("span"); 196 | this.resultDOM.setAttribute("class", "terminus-document-results"); 197 | //var form = (this.input.format == "js" ? "javascript" : "json"); 198 | //UTILS.stylizeEditor(ui, this.input.snippet, {width: this.input.width, height: this.input.height}, form); 199 | this.container.appendChild(this.resultDOM); 200 | } 201 | if(this.frame && this.frame.document.render){ 202 | var fpt = this.frame.document.render(); 203 | if(fpt){ 204 | this.resultDOM.appendChild(fpt); 205 | } 206 | } 207 | } 208 | 209 | DocumentPane.prototype.loadRenderer = function(rendname, frame, args, termframe){ 210 | var evalstr = "new " + rendname + "("; 211 | if(args) evalstr += JSON.stringify(args); 212 | evalstr += ");"; 213 | try { 214 | var nr = eval(evalstr); 215 | nr.frame = frame; 216 | nr.datatypes = this.datatypes; 217 | return nr; 218 | } 219 | catch(e){ 220 | console.log("Failed to load " + rendname + e.toString()); 221 | return false; 222 | } 223 | } 224 | 225 | 226 | DocumentPane.prototype.createInput = function(mode){ 227 | let input = new TerminusCodeSnippet("rule", mode); 228 | if(this.view){ 229 | input.setQuery(this.view); 230 | } 231 | var self = this; 232 | input.submit = function(qObj){ 233 | self.updateView(qObj); 234 | }; 235 | return input; 236 | } 237 | 238 | DocumentPane.prototype.updateView = function(docview){ 239 | this.view = docview; 240 | this.frame.options(this.view); 241 | if(this.input) this.input.setQuery(this.view); 242 | this.frame.applyRulesToDocument(this.frame.document, this.frame.config); 243 | this.frame.renderer = this.frame.document; 244 | this.renderResult(); 245 | } 246 | 247 | DocumentPane.prototype.updateResult = function(result){ 248 | this.result = result; 249 | this.updateQuery(result.query); 250 | this.refreshViews(); 251 | } 252 | 253 | DocumentPane.prototype.empty = function(){ 254 | return (typeof this.view == "undefined"); 255 | } 256 | 257 | DocumentPane.prototype.clearMessages = function(){} 258 | DocumentPane.prototype.showError = function(){} 259 | 260 | DocumentPane.prototype.submitQuery = function(qObj){ 261 | this.clearMessages(); 262 | tdv.owner = this; 263 | tdv.setDatatypes(Datatypes.initialiseDataRenderers); 264 | tdv.loadDocument(id).then(() => { 265 | let dom = tdv.render(); 266 | if(dom) holder.appendChild(dom); 267 | }); 268 | return holder; 269 | } 270 | 271 | module.exports = DocumentPane; 272 | -------------------------------------------------------------------------------- /src/html/ResultPane.js: -------------------------------------------------------------------------------- 1 | const TerminusCodeSnippet = require('./query/TerminusCodeSnippet'); 2 | const Datatypes = require("./Datatypes"); 3 | const DatatypeRenderers = require("./DatatypeRenderers"); 4 | 5 | const SimpleTable = require("./table/SimpleTable"); 6 | const SimpleGraph = require("./graph/SimpleGraph"); 7 | const SimpleStream = require("./stream/SimpleStream"); 8 | const SimpleChooser = require("./chooser/SimpleChooser"); 9 | const HTMLHelper = require('./HTMLHelper'); 10 | 11 | /** 12 | * Result Pane is defined by a WOQL configuration object 13 | * Visually it consists of a single rule editor (showing the current state of the configuration object) which may be collapsed behind a configuration link 14 | * and a single result view which shows the result of the rule when applied to the current results. 15 | * 16 | */ 17 | function ResultPane(client, querypane, config){ 18 | this.client = client; 19 | this.qp = querypane; 20 | this.config = config; 21 | this.container = document.createElement('span'); 22 | this.container.setAttribute('class', 'terminus-result-pane'); 23 | } 24 | 25 | ResultPane.prototype.options = function(opts){ 26 | this.showConfig = (opts && typeof opts.showConfig != "undefined" ? opts.showConfig : false); 27 | this.editConfig = (opts && typeof opts.editConfig != "undefined" ? opts.editConfig : false); 28 | this.changeViewType = (opts && typeof opts.changeViewType != "undefined" ? opts.changeViewType : true); 29 | this.intro = (opts && typeof opts.intro != "undefined" ? opts.intro : false); 30 | this.renderers = (opts && opts.renderers ? opts.renderers : { 31 | table: new SimpleTable(), 32 | graph: new SimpleGraph(), 33 | stream: new SimpleStream(), 34 | chooser: new SimpleChooser() 35 | }); 36 | if(this.config){ 37 | this.viewers = [this.config]; 38 | } 39 | this.viewers = (opts && typeof opts.viewers != "undefined" ? this.viewers.concat(opts.viewers) : this.viewers); 40 | this.currentViewer = 0; 41 | return this; 42 | } 43 | 44 | ResultPane.prototype.getRenderer = function(){ 45 | if(this.config && this.config.renderer()){ 46 | return this.config.renderer(); 47 | } 48 | else { 49 | if(this.config.type && this.renderers[this.config.type]){ 50 | return this.renderers[this.config.type]; 51 | } 52 | } 53 | return false; 54 | } 55 | 56 | ResultPane.prototype.getAsDOM = function(){ 57 | if(this.intro){ 58 | var di = (typeof this.intro == "string" ? document.createTextNode(this.intro) : this.intro); 59 | this.container.appendChild(di); 60 | } 61 | var configspan = document.createElement("span"); 62 | configspan.setAttribute("class", "pane-config-icons"); 63 | this.container.appendChild(configspan); 64 | this.resultDOM = document.createElement('span'); 65 | this.resultDOM.setAttribute('class', 'terminus-result-view'); 66 | if(this.result){ 67 | this.resultDOM.appendChild(this.getResultDOM()); 68 | } 69 | this.container.appendChild(this.resultDOM); 70 | if(this.showConfig){ 71 | this.showingQuery = (this.showConfig != "icon"); 72 | var mode = (this.editConfig ? "edit" : "view"); 73 | this.input = this.createInput(mode); 74 | var ipdom = this.input.getAsDOM(); 75 | var ispan = document.createElement("span"); 76 | ispan.addEventListener('mouseover', function(){ 77 | this.style.cursor = "pointer"; 78 | }); 79 | ispan.setAttribute("class", "result-pane-config"); 80 | var ic = document.createElement("i"); 81 | ispan.appendChild(ic); 82 | configspan.appendChild(ispan); 83 | var self = this; 84 | function showQueryConfig(){ 85 | configspan.title="Click to Hide View Configuration"; 86 | ic.setAttribute("class", "fas fa fa-times-circle"); 87 | if(configspan.nextSibling){ 88 | self.container.insertBefore(ipdom, configspan.nextSibling); 89 | if(self.input.snippet.value) 90 | self.input.stylizeSnippet(); 91 | } 92 | else{ 93 | self.container.appendChild(ipdom); 94 | if(self.input.snippet.value) 95 | self.input.stylizeSnippet(); 96 | } 97 | } 98 | function hideQueryConfig(){ 99 | configspan.title="Click to View Configuration"; 100 | ic.setAttribute("class", "terminus-result-icons terminus-result-view-icon " + self.getViewConfigIconClass()); 101 | self.container.removeChild(ipdom); 102 | } 103 | ispan.addEventListener("click", () => { 104 | if(this.showingQuery) hideQueryConfig(); 105 | else showQueryConfig(); 106 | this.showingQuery = !this.showingQuery; 107 | }); 108 | showQueryConfig(); 109 | if(this.showConfig == "icon") hideQueryConfig(); 110 | } 111 | if(this.changeViewType){ 112 | cvicons = this.getViewTypeIconDOM(ipdom); 113 | if(cvicons) configspan.prepend(cvicons); 114 | } 115 | return this.container; 116 | } 117 | 118 | ResultPane.prototype.getViewConfigIconClass = function(){ 119 | if(this.changeViewType && this.viewers.length > 1){ 120 | return "fas fa fa-vial"; 121 | } 122 | if(this.viewers[this.currentViewer].icon){ 123 | return this.viewers[this.currentViewer].icon; 124 | } 125 | var def = this.getDefaultViewerIcon(this.viewers[this.currentViewer]); 126 | return def.icon; 127 | } 128 | 129 | 130 | ResultPane.prototype.getViewTypeIconDOM = function(sp, ipdom){ 131 | var bsp = document.createElement('span'); 132 | bsp.setAttribute('class', 'terminus-result-icons'); 133 | if(this.viewers.length > 1){ 134 | for(var i = 0; i { 187 | this.changeViewerType(viewer, index); 188 | HTMLHelper.removeChildren(container); 189 | for(var i = 0; i { 55 | this.client = client; 56 | }); 57 | } 58 | 59 | TerminusViewer.prototype.tutorial = function(terminus_server_url, terminus_server_key){ 60 | 61 | } 62 | 63 | 64 | TerminusViewer.prototype.loadConsole = function(create_json, import_json, query_json, view_json){} 65 | 66 | module.exports = TerminusViewer; -------------------------------------------------------------------------------- /src/html/TerminusViolation.js: -------------------------------------------------------------------------------- 1 | function TerminusViolations(vios, ui){ 2 | this.ui = ui; 3 | this.vios = []; 4 | var nvios = []; 5 | for(var i = 0; i 1 ? " Violations Detected" : " Violation Detected"); 20 | if(context_msg) msg += " " + context_msg; 21 | vioHeading.appendChild(document.createTextNode(msg)); 22 | for(var i = 0; i 2 || (ty == "xdd:coordinatePolyline" && index > 1)){ 24 | var delbut = document.createElement("button"); 25 | delbut.setAttribute("class", "delete-coordinate"); 26 | delbut.appendChild(document.createTextNode("Remove")); 27 | delbut.addEventListener("click", function(){ 28 | long.value = ""; 29 | lat.value = ""; 30 | parent.removeChild(lldom); 31 | }); 32 | firstcol.appendChild(delbut); 33 | } 34 | lldom.appendChild(document.createTextNode("Latitude: ")); 35 | lldom.appendChild(lat); 36 | lldom.appendChild(document.createTextNode(" °" + " ")); 37 | lldom.appendChild(document.createTextNode(" Longitude: ")); 38 | lldom.appendChild(long); 39 | lldom.appendChild(document.createTextNode(" ° " )); 40 | return lldom; 41 | } 42 | 43 | 44 | HTMLCoordinateEditor.prototype.renderFrame = function(frame, dataviewer){ 45 | var value = frame.get(); 46 | var input = document.createElement("span"); 47 | input.setAttribute('class', "terminus-literal-value terminus-literal-coordinate"); 48 | input.setAttribute('data-value', value); 49 | try { 50 | var parsed = (value ? JSON.parse(value) : false); 51 | } 52 | catch(e){ 53 | this.error = this.type + " failed to parse as json", e.toString(); 54 | var parsed = false; 55 | } 56 | var self = this; 57 | var updateValueFromForm = function(){ 58 | var vals = []; 59 | for(var i = 0; i 0 ? vals[0] : ""); 22 | var data2 = (vals.length > 1 ? vals[1] : ""); 23 | var firstip = document.createElement("input"); 24 | firstip.setAttribute('type', "text"); 25 | firstip.setAttribute('size', 16); 26 | if(data1){ 27 | firstip.value = data1; 28 | } 29 | var secondip = document.createElement("input"); 30 | secondip.setAttribute('type', "text"); 31 | secondip.setAttribute('size', 16); 32 | if(data2){ 33 | this.showing_range = true; 34 | secondip.value = data2; 35 | } 36 | rvals.appendChild(firstip); 37 | d.appendChild(rvals); 38 | if(this.showing_range){ 39 | svals.appendChild(getRangeSymbolDOM()); 40 | svals.appendChild(secondip); 41 | } 42 | d.appendChild(svals); 43 | var but = document.createElement("button"); 44 | but.setAttribute("class", "terminus-change-range"); 45 | var txt = this.showing_range ? "Change to Simple Value" : "Change to Uncertain Range"; 46 | but.appendChild(document.createTextNode(txt)); 47 | d.appendChild(but); 48 | var self = this; 49 | but.addEventListener("click", function(){ 50 | if(self.showing_range){ 51 | self.showing_range = false; 52 | secondip.value = ""; 53 | HTMLHelper.removeChildren(svals); 54 | } 55 | else { 56 | self.showing_range = true; 57 | secondip.value = ""; 58 | svals.appendChild(getRangeSymbolDOM()); 59 | svals.appendChild(secondip); 60 | } 61 | var txt = self.showing_range ? "Change to Simple Value" : "Change to Uncertain Range"; 62 | but.innerText = txt; 63 | changeHandler(); 64 | }); 65 | var changeHandler = function(){ 66 | if(self.showing_range && secondip.value){ 67 | if(firstip.value) frame.set("[" + firstip.value + "," + secondip.value + "]"); 68 | else frame.set(secondip.value); 69 | } 70 | else { 71 | frame.set(firstip.value); 72 | } 73 | } 74 | firstip.addEventListener("change", changeHandler); 75 | secondip.addEventListener("change", changeHandler); 76 | return d; 77 | } 78 | 79 | function getRangeSymbolDOM(){ 80 | var d = document.createElement("span"); 81 | d.setAttribute("class", "terminus-range-indicator"); 82 | d.setAttribute("title", "The value is uncertain, it lies somewhere in this range"); 83 | d.appendChild(document.createTextNode(" ... ")); 84 | return d; 85 | } 86 | 87 | module.exports={HTMLRangeEditor} 88 | -------------------------------------------------------------------------------- /src/html/datatypes/S2EntityEditor.js: -------------------------------------------------------------------------------- 1 | function S2EntityEditor(options){} 2 | 3 | S2EntityEditor.prototype.renderFrame = function(frame, dataviewer){ 4 | var value = frame.get(); 5 | var cls = frame.range(); 6 | var cback = frame.set; 7 | var ctl = dataviewer.getClient(); 8 | var d2ch = new TerminusDocumentChooser(ctl, cls, value); 9 | d2ch.change = function(val){ 10 | frame.set(val); 11 | } 12 | d2ch.view = "label"; 13 | var d2dom = d2ch.getAsDOM(); 14 | return d2dom; 15 | } 16 | 17 | 18 | module.exports={S2EntityEditor} -------------------------------------------------------------------------------- /src/html/datatypes/String.js: -------------------------------------------------------------------------------- 1 | const HTMLHelper = require('../HTMLHelper'); 2 | 3 | function HTMLStringViewer(options){ 4 | this.options(options); 5 | } 6 | 7 | HTMLStringViewer.prototype.options = function(options){ 8 | this.size = ((options && options.size) ? options.size : false); 9 | this.css = ((options && options.css) ? "terminus-literal-value " + options.css : "terminus-literal-value"); 10 | this.max_word_size = (options && options.max_word_size ? options.max_word_size : false); 11 | this.max_cell_size = (options && options.max_cell_size ? options.max_cell_size : false); 12 | this.show_types = (options && options.show_types ? options.show_types : false); 13 | } 14 | 15 | HTMLStringViewer.prototype.renderFrame = function(frame, dataviewer){ 16 | var value = frame.get(); 17 | return this.render(value); 18 | } 19 | 20 | HTMLStringViewer.prototype.renderValue = function(dataviewer){ 21 | return this.render(dataviewer.value()); 22 | } 23 | 24 | HTMLStringViewer.prototype.render = function(value){ 25 | var input = document.createElement("span"); 26 | input.setAttribute('class', this.css); 27 | input.setAttribute('data-value', value); 28 | if(this.show_types && this.type != "id"){ 29 | value += " (" + this.type + ")"; 30 | } 31 | if(this.max_word_size || this.max_cell_size){ 32 | HTMLHelper.wrapShortenedText(input, value, this.max_cell_size, this.max_word_size); 33 | } 34 | else { 35 | value = document.createTextNode(value); 36 | input.appendChild(value); 37 | } 38 | return input; 39 | } 40 | 41 | module.exports={HTMLStringViewer} 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/html/datatypes/StringEditor.js: -------------------------------------------------------------------------------- 1 | function HTMLStringEditor(options){ 2 | this.options(options); 3 | } 4 | 5 | HTMLStringEditor.prototype.options = function(options){ 6 | this.css = ((options && options.css) ? "terminus-literal-value " + options.css : "terminus-literal-value"); 7 | this.opts = options; 8 | } 9 | 10 | HTMLStringEditor.prototype.renderFrame = function(frame, dataviewer){ 11 | var value = frame.get(); 12 | var big = ((this.opts && typeof this.opts.big != "undefined") ? this.opts.big : this.isBigType(this.type, value)); 13 | if(big){ 14 | var input = document.createElement("textarea"); 15 | this.css += " terminus-literal-big-value"; 16 | } 17 | else { 18 | var size = ((this.opts && typeof this.opts.size != "undefined") ? this.opts.size : this.getTypeSize(this.type, value)); 19 | var input = document.createElement("input"); 20 | input.setAttribute('type', "text"); 21 | input.setAttribute('size', size); 22 | } 23 | input.setAttribute('class', this.css); 24 | input.setAttribute("data-value", value); 25 | 26 | input.value = value; 27 | var self = this; 28 | input.addEventListener("input", function(){ 29 | frame.set(this.value); 30 | }); 31 | return input; 32 | } 33 | 34 | HTMLStringEditor.prototype.isBigType = function(ty, value){ 35 | if(value && value.length && value.length > 100) return true; 36 | var longs = ["xdd:coordinatePolyline", "xdd:coordinatePolygon", "xsd:base64Binary", "xdd:html", "xdd:json", "rdf:XMLLiteral"]; 37 | if(longs.indexOf(ty) == -1) return false; 38 | return true; 39 | } 40 | 41 | HTMLStringEditor.prototype.getTypeSize = function(ty, value){ 42 | if(value && value.length && value.length > 40) return 80; 43 | var bigs = ["xdd:url", "xdd:coordinate", "xsd:anyURI"]; 44 | var smalls = ["xsd:gYearMonth", "xdd:gYearRange", "xsd:decimal", "xsd:float", "xsd:time", "xsd:date", 45 | "xsd:dateTimeStamp","xsd:gYearMonth", "xsd:gMonthDay", "xsd:duration", "xsd:yearMonthDuration", "xsd:dayTimeDuration", 46 | "xsd:nonNegativeInteger", "xsd:positiveInteger", "xsd:negativeInteger", "xsd:nonPositiveInteger", "xsd:integer","xsd:unsignedInt"]; 47 | var tinys = ["xsd:boolean", "xsd:gYear", "xsd:gMonth", "xsd:gDay", "xsd:byte", "xsd:short", "xsd:unsignedByte", "xsd:language"]; 48 | if(bigs.indexOf(ty) != -1) return 80; 49 | if(smalls.indexOf(ty) != -1) return 16; 50 | if(tinys.indexOf(ty) != -1) return 8; 51 | return 32; 52 | } 53 | 54 | module.exports={HTMLStringEditor} 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/html/document/DocumentTable.js: -------------------------------------------------------------------------------- 1 | function DocumentTable(){} 2 | 3 | DocumentTable.prototype.render = function(frame){ 4 | var t = this.getTableDOM(frame); 5 | var tbody = document.createElement("tbody"); 6 | for(var p in frame.properties){ 7 | //s.appendChild(document.createTextNode(p)); 8 | var pr = this.renderProperty(tbody, frame.properties[p]); 9 | //if(pr) tbody.appendChild(pr); 10 | } 11 | t.appendChild(tbody); 12 | return t; 13 | } 14 | 15 | DocumentTable.prototype.getTableDOM = function(frame){ 16 | //const columns = this.woqltable.getColumnsToRender(); 17 | var tab = document.createElement("table"); 18 | tab.setAttribute("class", "terminus-hover-table"); 19 | var thead = document.createElement("thead"); 20 | var thr = document.createElement("tr"); 21 | var th = document.createElement("th"); 22 | th.setAttribute('class', 'terminus-table-header-full-css'); 23 | th.setAttribute('colspan', 2); 24 | th.appendChild(document.createTextNode(frame.subject() + ", " + frame.subjectClass())); 25 | thr.appendChild(th); 26 | thead.appendChild(thr); 27 | tab.appendChild(thead); 28 | return tab; 29 | } 30 | 31 | DocumentTable.prototype.renderProperty = function(tbody, frame){ 32 | for(var i = 0 ; i < frame.values.length; i++){ 33 | var thr = document.createElement("tr"); 34 | var td = document.createElement("td"); 35 | td.appendChild(document.createTextNode(frame.getLabel())); 36 | var td2 = document.createElement("td"); 37 | if(frame.values[i].isData()){ 38 | td2.appendChild(this.renderValue(frame.values[i])); 39 | } 40 | else { 41 | td2.appendChild(this.render(frame.values[i])); 42 | } 43 | thr.appendChild(td); 44 | thr.appendChild(td2); 45 | tbody.appendChild(thr); 46 | } 47 | } 48 | 49 | DocumentTable.prototype.renderValue = function(frame){ 50 | return document.createTextNode(frame.get()); 51 | } 52 | 53 | module.exports = DocumentTable; -------------------------------------------------------------------------------- /src/html/document/SimpleDocument.js: -------------------------------------------------------------------------------- 1 | function SimpleDocument(){} 2 | 3 | SimpleDocument.prototype.render = function(frame){ 4 | var s = document.createElement("div"); 5 | for(var p in frame.properties){ 6 | var pr = this.renderProperty(frame.properties[p]) 7 | if(pr) s.appendChild(pr); 8 | } 9 | return s; 10 | } 11 | 12 | SimpleDocument.prototype.renderProperty = function(frame){ 13 | var s = document.createElement("div"); 14 | s.appendChild(document.createTextNode(frame.getLabel() + ": ")); 15 | for(var i = 0 ; i < frame.values.length; i++){ 16 | if(frame.values[i].isData()){ 17 | var pr = this.renderValue(frame.values[i]); 18 | } 19 | else { 20 | var pr = this.render(frame.values[i]); 21 | } 22 | if(pr) s.appendChild(pr); 23 | } 24 | return s; 25 | } 26 | 27 | SimpleDocument.prototype.renderValue = function(frame){ 28 | var s = document.createElement("span"); 29 | s.appendChild(document.createTextNode(frame.get() + " ")); 30 | return s; 31 | } 32 | 33 | module.exports = SimpleDocument; -------------------------------------------------------------------------------- /src/html/document/SimpleFrameViewer.js: -------------------------------------------------------------------------------- 1 | const HTMLHelper = require("../HTMLHelper"); 2 | 3 | function SimpleFrameViewer(){} 4 | 5 | SimpleFrameViewer.prototype.getScope = function(frame){ 6 | if(frame.isProperty()) return "property"; 7 | if(frame.isObject()) return "object"; 8 | if(frame.isData()) return "data"; 9 | } 10 | 11 | SimpleFrameViewer.prototype.setDatatypeViewers = function(datatypes){ 12 | this.datatypes = datatypes; 13 | } 14 | 15 | 16 | SimpleFrameViewer.prototype.getDatatypeViewer = function(frame, mode){ 17 | var dv = frame.display_options.dataviewer; 18 | if(!dv){ 19 | if(frame.isChoice()) var t = "oneOf"; 20 | else if(frame.isDocument()) var t = "document"; 21 | else t = frame.getType(); 22 | if(mode && mode == "edit"){ 23 | var r = this.datatypes.getEditor(t); 24 | } 25 | else { 26 | var r = this.datatypes.getRenderer(t); 27 | } 28 | dv = r.name; 29 | } 30 | if(frame.display_options.args){ 31 | var args = frame.display_options.args ; 32 | } 33 | else { 34 | if(r && r.args){ 35 | args = r.args; 36 | } 37 | else args = false; 38 | } 39 | var rend = this.datatypes.createRenderer(dv, args); 40 | rend.type = frame.getType(); 41 | return rend; 42 | } 43 | 44 | SimpleFrameViewer.prototype.render = function(frame){ 45 | if(!frame) frame = this.frame; 46 | if(!frame) return; 47 | 48 | var scope = this.getScope(frame); 49 | if(frame.display_options.header_features && frame.display_options.header_features.length){ 50 | var hfeatures = this.getFeaturesDOM(frame.display_options.header_features, scope, frame, frame.display_options.mode); 51 | } 52 | else var hfeatures = false; 53 | if(frame.display_options.features && frame.display_options.features.length){ 54 | var features = this.getFeaturesDOM(frame.display_options.features, scope, frame, frame.display_options.mode); 55 | } 56 | else var features = false; 57 | var orient = (scope == "object" || scope == "property") ? "page" : "line"; 58 | var ndom = HTMLHelper.getFrameDOM(scope, frame, orient, hfeatures, features); 59 | if(!ndom) return false; 60 | if(this.framedom){ 61 | this.framedom.replaceWith(ndom); 62 | } 63 | this.framedom = ndom; 64 | if(frame.display_options.style){ 65 | this.framedom.setAttribute("style", frame.display_options.style); 66 | } 67 | return this.framedom; 68 | } 69 | 70 | SimpleFrameViewer.prototype.getFeaturesDOM = function(flist, scope, frame, mode){ 71 | var features = document.createElement("span"); 72 | features.setAttribute("class", "terminus-features terminus-" + scope + "-features features-" + featuresToCSS(flist)); 73 | for(var i = 0; i { 207 | this.readInput(); 208 | this.submit(this.qObj); 209 | }); 210 | return actbtn; 211 | } 212 | 213 | TerminusCodeSnippet.prototype.submit = function(){ 214 | alert("Submitted " + JSON.stringify(this.qObj)); 215 | } 216 | 217 | TerminusCodeSnippet.prototype.removeCodeMirror = function(){ 218 | var cm = this.snippet.nextSibling; 219 | if(!cm) return; 220 | if(cm.classList.contains('CodeMirror')) // remove code mirror 221 | HTMLHelper.removeElement(cm); 222 | } 223 | 224 | TerminusCodeSnippet.prototype.stylizeSnippet = function(){ 225 | var dimensions = "query"; 226 | //dimensions.width = "1000";//this.width; 227 | //dimensions.height = "1000";//this.height; 228 | 229 | this.removeCodeMirror(); 230 | if(this.mode == 'view') 231 | UTILS.stylizeCodeDisplay(null, this.snippet, null, 'javascript'); 232 | else UTILS.stylizeEditor(null, this.snippet, dimensions, 'javascript'); // default view is js 233 | } 234 | 235 | TerminusCodeSnippet.prototype.refreshContents = function(qObj){ 236 | qObj = qObj || this.qObj; 237 | HTMLHelper.removeChildren(this.snippet); 238 | if(this.mode == "edit") this.snippet.value == ""; 239 | if(!qObj) return; 240 | var serial = this.serialise(this.qObj, this.format); 241 | if(this.mode == "edit"){ 242 | this.snippet.value = serial; 243 | if(this.snippet.nextSibling){ 244 | this.removeCodeMirror(); 245 | if(this.format == 'js') var mode = 'javascript'; 246 | else var mode = 'application/ld+json'; 247 | UTILS.stylizeEditor(null, 248 | this.snippet, 249 | {width: this.width, height: this.height}, 250 | mode); 251 | } 252 | } 253 | else { 254 | this.snippet.appendChild(document.createTextNode(serial)); 255 | UTILS.stylizeCodeDisplay(null, this.snippet, null, mode); 256 | } 257 | } 258 | 259 | TerminusCodeSnippet.prototype.refreshCodeMirror = function(){ 260 | if(this.snippet.nextSibling){ 261 | this.removeCodeMirror(); 262 | } 263 | if(this.format == 'js') var mode = 'javascript'; 264 | else var mode = 'application/ld+json'; 265 | if(this.mode == "edit"){ 266 | UTILS.stylizeEditor(null, 267 | this.snippet, 268 | {width: this.width, height: this.height}, 269 | mode); 270 | } 271 | else { 272 | UTILS.stylizeCodeDisplay(null, this.snippet, null, mode); 273 | } 274 | 275 | } 276 | 277 | module.exports = TerminusCodeSnippet; 278 | -------------------------------------------------------------------------------- /src/html/stream/SimpleStream.js: -------------------------------------------------------------------------------- 1 | const HTMLHelper = require('../HTMLHelper'); 2 | 3 | function SimpleStream(){ 4 | this.holder = document.createElement("div"); 5 | } 6 | 7 | SimpleStream.prototype.options = function(options){ 8 | for(var k in options){ 9 | this[k] = options[k]; 10 | } 11 | return this; 12 | } 13 | 14 | 15 | SimpleStream.prototype.render = function(stream){ 16 | if(stream) this.stream = stream; 17 | HTMLHelper.removeChildren(this.holder); 18 | //var ctls = this.getControlsDOM(); 19 | //var tab = this.getTableDOM(); 20 | //if(ctls) this.holder.appendChild(ctls) 21 | //this.holder.appendChild(tab); 22 | return this.holder; 23 | } 24 | 25 | module.exports = SimpleStream; -------------------------------------------------------------------------------- /src/html/table/SimpleTable.js: -------------------------------------------------------------------------------- 1 | const HTMLHelper = require('../HTMLHelper'); 2 | 3 | function SimpleTable(){ 4 | this.holder = document.createElement("div"); 5 | this.holder.setAttribute('class', 'terminus-simple-table-holder') 6 | } 7 | 8 | SimpleTable.prototype.options = function(options){ 9 | for(var k in options){ 10 | this[k] = options[k]; 11 | } 12 | return this; 13 | } 14 | 15 | 16 | SimpleTable.prototype.render = function(woqltable){ 17 | if(woqltable) this.woqltable = woqltable; 18 | HTMLHelper.removeChildren(this.holder); 19 | var ctls = this.getControlsDOM(); 20 | var tab = this.getTableDOM(); 21 | if(ctls) this.holder.appendChild(ctls) 22 | this.holder.appendChild(tab); 23 | return this.holder; 24 | } 25 | 26 | SimpleTable.prototype.getControlsDOM = function(result){ 27 | var ctrls = document.createElement("span"); 28 | if(this.woqltable.config.pager()){ 29 | var paging = this.getPaging(result); 30 | if(paging) ctrls.appendChild(paging); 31 | } 32 | return ctrls; 33 | } 34 | 35 | SimpleTable.prototype.getTableDOM = function(){ 36 | const columns = this.woqltable.getColumnsToRender(); 37 | var tab = document.createElement("table"); 38 | tab.setAttribute("class", "terminus-hover-table terminus-simple-table"); 39 | var thead = this.getTableHeader(columns); 40 | tab.appendChild(thead); 41 | var tbody = this.getTableBody(columns); 42 | tab.appendChild(tbody); 43 | return tab; 44 | } 45 | 46 | SimpleTable.prototype.getTableHeader = function(cols){ 47 | var thead = document.createElement("thead"); 48 | var thr = document.createElement("tr"); 49 | for(var i = 0; i 2){ 155 | pdom.appendChild(this.getFirst()); 156 | } 157 | if(pn > 1){ 158 | pdom.appendChild(this.getPrev(pn)); 159 | } 160 | if(this.woqltable.config.page()) pdom.appendChild(this.getPageNumber(pn)); 161 | pdom.appendChild(this.getNext(this.woqltable.result)); 162 | } 163 | return pdom; 164 | } 165 | } 166 | 167 | SimpleTable.prototype.showPaging = function(){ 168 | if(this.woqltable.result.query.isPaged() && this.woqltable.config.pager() && this.woqltable.canChangePage()) return true; 169 | return false; 170 | } 171 | 172 | 173 | SimpleTable.prototype.getPageSize = function(){ 174 | if(this.showPaging()){ 175 | var chunk = document.createElement("span"); 176 | chunk.setAttribute("class", "woql-table-pagesize"); 177 | clabel = document.createElement("span"); 178 | clabel.appendChild(document.createTextNode("Page Size")); 179 | chunk.appendChild(clabel); 180 | if(this.woqltable.config.change_pagesize){ 181 | var ctl = document.createElement("input"); 182 | ctl.setAttribute("size", 6); 183 | var self = this; 184 | ctl.value = this.woqltable.getPageSize(); 185 | ctl.addEventListener("blur", function(){ 186 | var pval = (this.value ? parseInt(this.value) : false); 187 | self.woqltable.setPageSize(pval); 188 | }); 189 | chunk.appendChild(ctl); 190 | } 191 | else { 192 | chunk.appendChild(document.createTextNode(this.woqltable.getPageSize())); 193 | } 194 | return chunk; 195 | } 196 | return false; 197 | } 198 | 199 | SimpleTable.prototype.getPageNumber = function(){ 200 | var ctl = document.createElement("input"); 201 | ctl.setAttribute("size", 4); 202 | ctl.value = this.woqltable.result.query.getPage(); 203 | var self = this; 204 | ctl.addEventListener("blur", function(){ 205 | var pval = (this.value ? parseInt(this.value) : false); 206 | self.woqltable.setPage(pval); 207 | }); 208 | return ctl; 209 | } 210 | 211 | SimpleTable.prototype.getNext = function(result){ 212 | var ctl = document.createElement("button"); 213 | var self = this; 214 | ctl.appendChild(document.createTextNode("next")); 215 | if(!this.woqltable.canAdvancePage(result)){ 216 | ctl.setAttribute("disabled", "disabled"); 217 | } 218 | else { 219 | ctl.addEventListener("click", function(){ 220 | self.woqltable.nextPage(); 221 | }); 222 | } 223 | return ctl; 224 | } 225 | 226 | SimpleTable.prototype.getPrev = function(result){ 227 | var ctl = document.createElement("button"); 228 | ctl.appendChild(document.createTextNode("previous")); 229 | var self = this; 230 | if(!this.woqltable.canRetreatPage(result)){ 231 | ctl.setAttribute("disabled", "disabled"); 232 | } 233 | else { 234 | ctl.addEventListener("click", function(){ 235 | self.woqltable.previousPage(); 236 | }); 237 | } 238 | return ctl; 239 | } 240 | 241 | SimpleTable.prototype.getFirst = function(result){ 242 | var ctl = document.createElement("button"); 243 | ctl.appendChild(document.createTextNode("first")); 244 | var self = this; 245 | if(!this.woqltable.canRetreatPage(result) || this.woqltable.getPage() <= 2){ 246 | ctl.setAttribute("disabled", "disabled"); 247 | } 248 | else { 249 | ctl.addEventListener("click", function(){ 250 | self.woqltable.firstPage(); 251 | }); 252 | } 253 | return ctl; 254 | } 255 | 256 | module.exports = SimpleTable; 257 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Terminus DB Management Dashboard NEW 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 29 | 35 | 36 |
20 | 21 | 23 | 25 | 27 |
28 |
30 |
31 |
32 |
33 |
34 |
37 | 64 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 2 | const TerminusUI = require('./TerminusUI'); 3 | const TerminusViewer =require('./html/TerminusViewer') 4 | module.exports={TerminusUI:TerminusUI, 5 | TerminusViewer:TerminusViewer} 6 | -------------------------------------------------------------------------------- /src/plugins/codemirror.terminus.js: -------------------------------------------------------------------------------- 1 | function Codemirror(text, format, config){ 2 | this.textdom = text; 3 | this.mode = format; 4 | if(objectIsEmpty(config)) this.darkMode = config.darkMode; 5 | if(this.jsonldCheck(format)) this.mode = 'javascript'; 6 | } 7 | // checks if a json object is empty 8 | function objectIsEmpty(arg) { 9 | for (var item in arg) { 10 | return false; 11 | } 12 | return true; 13 | } 14 | 15 | function autocomplete(){ 16 | var orig = CodeMirror.hint.javascript = function (cm) { 17 | var list = [];//"limit()","start()","triple()"];//Session.get(Template.strSessionDistinctFields) || []; 18 | var cursor = cm.getCursor(); 19 | var currentLine = cm.getLine(cursor.line); 20 | var start = cursor.ch; 21 | var end = start; 22 | while (end < currentLine.length && /[\w$]+/.test(currentLine.charAt(end))) ++end; 23 | while (start && /[\w$]+/.test(currentLine.charAt(start - 1))) --start; 24 | var curWord = start != end && currentLine.slice(start, end); 25 | var regex = new RegExp('^' + curWord, 'i'); 26 | var result = { 27 | list: (!curWord ? list : list.filter(function (item) { 28 | return item.match(regex); 29 | })).sort(), 30 | from: CodeMirror.Pos(cursor.line, start), 31 | to: CodeMirror.Pos(cursor.line, end) 32 | }; 33 | return result; 34 | }; 35 | // codeMirror.hint.sql is defined when importing codemirror/addon/hint/sql-hint 36 | // (this is mentioned in codemirror addon documentation) 37 | // Reference the hint function imported here when including other hint addons 38 | // or supply your own 39 | //cm.replaceSelection("."); 40 | //codeMirror.showHint(cm, CodeMirror.hint.javascript, hintOptions); 41 | } 42 | 43 | /* 44 | txtar : editor is attached to textar 45 | mode : format for highlighting, ex: json, html etc. 46 | editable : readOnly false/ nocursor is special value in code editor to set readonly true */ 47 | Codemirror.prototype.colorizeTextArea = function(dimensions){ 48 | //initize auto complete 49 | /*CodeMirror.commands.autocomplete = function(cm) { 50 | cm.showHint({hint: CodeMirror.hint.anyword}); 51 | }*/ 52 | 53 | // initialise code editor on text area 54 | var editor = CodeMirror.fromTextArea(this.textdom, { 55 | mode : this.mode, 56 | firstLineNumber : 1, 57 | lineNumbers : true, 58 | styleActiveLine : true, 59 | lineWrapping : true, 60 | smartIndent : true, 61 | indentWithTabs : true, 62 | newlineAndIndent : true, 63 | autoCloseBrackets : true, 64 | matchBrackets : {afterCursor: true}, 65 | extraKeys : {"Ctrl-F": "find", 66 | //"Tab": "autocomplete", 67 | "Ctrl-Q": function(cm){ cm.foldCode(cm.getCursor()); }}, 68 | refresh : true, 69 | foldGutter : true, 70 | gutters : ["CodeMirror-linenumbers", "CodeMirror-foldgutter"] 71 | }); 72 | editor.foldCode(CodeMirror.Pos(13, 0)); 73 | if(false && !(objectIsEmpty(dimensions))){ 74 | editor.setSize(dimensions.width, dimensions.height); 75 | } 76 | else this.setCodemirrorSize(editor, dimensions); 77 | editor.defaultCharWidth('20px'); 78 | if(true || this.darkMode) editor.setOption("theme", 'erlang-dark'); 79 | else editor.setOption("theme", 'neo'); 80 | return editor; 81 | } // colorizeTextArea() 82 | 83 | /* 84 | set editor size according to screens 85 | editor : code mirror editor Object 86 | mode : editor being viewed from schema/ doc/ query page*/ 87 | Codemirror.prototype.setCodemirrorSize = function(editor, dimensions){ 88 | switch(dimensions){ 89 | case 'query': 90 | editor.setSize('auto', '400'); 91 | break; 92 | case 'schema': 93 | editor.setSize('auto', '1550'); 94 | break; 95 | case 'document': 96 | editor.setSize('765', '500'); 97 | break; 98 | case 'api-doc': 99 | editor.setSize('800', '500'); 100 | break; 101 | case 'doc-json': 102 | editor.setSize('1410', 'auto'); 103 | break; 104 | case 'doc-json-create': 105 | editor.setSize('1410', '500'); 106 | break; 107 | } // switch(dimensions) 108 | } // setCodemirrorSize() 109 | 110 | // updateTextArea(): highlights new changes on editor 111 | Codemirror.prototype.updateTextArea = function(editor){ 112 | editor.save(); 113 | setTimeout(function() { 114 | editor.refresh(); 115 | },1); 116 | // save changes of code mirror editor 117 | editor.on('change', function(){ 118 | editor.save(); 119 | }); 120 | } //updateTextArea() 121 | 122 | /* 123 | colorizePre() to colorise pre tags (read only mode) 124 | text (string) : The document to run through the highlighter. 125 | mode (mode spec) : format to highlight color 126 | output (DOM node): The tokens will be converted to spans as in an editor, 127 | and inserted into the node (through innerHTML).*/ 128 | Codemirror.prototype.colorizePre = function(){ 129 | CodeMirror.runMode(this.textdom.innerText, this.mode, this.textdom); 130 | if(true || this.darkMode) 131 | var theme = 'cm-s-erlang-dark'; 132 | else var theme = 'cm-s-neo'; 133 | this.textdom.setAttribute('class', 'CodeMirror CodeMirror-wrap ' + theme + ' terminus-wrap-text terminus-wrapper-height '); 134 | return this.textdom; 135 | } // colorizePre() 136 | 137 | Codemirror.prototype.jsonldCheck = function(format){ 138 | if(format == 'jsonld') return true; 139 | } 140 | 141 | module.exports=Codemirror 142 | -------------------------------------------------------------------------------- /src/plugins/datatables.terminus.js: -------------------------------------------------------------------------------- 1 | const TerminusClient = require('@terminusdb/terminus-client'); 2 | const HTMLHelper = require('../html/HTMLHelper'); 3 | const UTILS= require('../Utils') 4 | 5 | /*** client side processing ***/ 6 | function CspDatatables(ui){ 7 | this.ui = ui; 8 | } 9 | 10 | CspDatatables.prototype.convertToDatatable = function(tab){ 11 | var dt = this; 12 | var table = jQuery(tab).DataTable({ 13 | searching : false, 14 | pageLength: 25, 15 | lengthMenu: [10, 25, 50, 75, 100], 16 | paging : true, 17 | select : true, 18 | initComplete: function(settings) { 19 | var ict =settings.oInstance.api(); 20 | ict.$('td').each(function(){ 21 | this.setAttribute('title', $(this).html()) 22 | })}, 23 | columnDefs:[{targets:'_all',className:"truncate"}], 24 | createdRow: function(row) { 25 | var td = $(row).find(".truncate"); 26 | td.attr("title", td.html());} 27 | }); //jQuery(tab) 28 | 29 | // on click of row connect to db, on click of 5th column delete db 30 | jQuery(tab, 'tbody').on('click', 'td', function(){ 31 | if(table.cell(this).index().column == 5){ 32 | var dbInfo = table.row(jQuery(this).parents('tr')).data(); 33 | var dbId = UTILS.extractValueFromCell(dbInfo[0]); 34 | dt.ui.deleteDatabase(dbId); 35 | return; 36 | } 37 | else dt.ui.showDBMainPage(); 38 | }); // on click 39 | 40 | tab.setAttribute('class' , 'stripe dataTable terminus-db-size'); 41 | tab.setAttribute('cellpadding', '1'); 42 | tab.setAttribute('cellspacing', '0'); 43 | tab.setAttribute('border' , '0'); 44 | return tab; 45 | } 46 | 47 | CspDatatables.prototype.draw = function(dtResult){ 48 | return(this.convertToDatatable(dtResult)); 49 | } 50 | 51 | /*** server side processing ***/ 52 | function Datatables(wResViewer, qPage){ 53 | this.wrViewer = wResViewer; 54 | this.wQuery = wResViewer.wQuery; 55 | this.ui = wResViewer.ui; 56 | this.qPage = qPage; 57 | this.currDTSettings = wResViewer.settings; 58 | } 59 | 60 | /* 61 | query: new woqlquery with current pagination changes 62 | pageInfo: current drawCallBack page change info 63 | resultDOM: result dom on veiwer page 64 | */ 65 | Datatables.prototype.executeQuery = function(qObj, pageInfo, resultDOM){ 66 | var self = this; 67 | // return this.wQuery.execute(query) 68 | return qObj.execute(this.ui.client) 69 | .then(function(result){ 70 | var dtResult = {}; 71 | var wqRes = new TerminusClient.WOQLResult(result, qObj); 72 | dtResult = self.wrViewer.formatResultsForDatatableDisplay(result.bindings, pageInfo) 73 | return dtResult.data; 74 | }) 75 | .catch(function(err){ 76 | console.error(err); 77 | self.ui.showError(err); 78 | }); 79 | } 80 | 81 | /* get query string based on datatable pagination and current query */ 82 | /*Datatables.prototype.getQueryOnPagination = function(wq, settings){ 83 | switch(settings.query){ 84 | case 'Show_All_Documents': 85 | return wq.getAllDocumentQuery(null, settings.pageLength, settings.start); 86 | break; 87 | case 'Show_All_Data': 88 | return wq.getEverythingQuery(null, settings.pageLength, settings.start); 89 | break; 90 | case 'Show_All_Schema_Elements': 91 | return wq.getElementMetaDataQuery(null, settings.pageLength, settings.start); 92 | break; 93 | case 'Show_Document_Classes': 94 | var sqp = wq.getConcreteDocumentClassPattern("Class"); 95 | return wq.getClassMetaDataQuery(sqp); 96 | break; 97 | case 'Show_All_Properties': 98 | return wq.getPropertyListQuery(null, settings.pageLength, settings.start); 99 | break; 100 | case 'Show_All_Classes': 101 | return wq.getClassMetaDataQuery(null, settings.pageLength, settings.start); 102 | break; 103 | case 'Show_Data_Class': 104 | return wq.getDataOfChosenClassQuery(settings.chosenValue, settings.pageLength, settings.start); 105 | break; 106 | case 'Show_Property_Class': 107 | return wq.getDataOfChosenPropertyQuery(settings.chosenValue, settings.pageLength, settings.start); 108 | break; 109 | case 'Show_Document_Info_by_Id': 110 | return wq.getDocumentQuery(settings.chosenValue, settings.pageLength, settings.start); 111 | break; 112 | case 'Show_All_Document_classes': 113 | return wq.getClassesQuery(settings.pageLength, settings.start); 114 | break; 115 | default: 116 | console.log('Invalid woql option passed'); 117 | break; 118 | 119 | } 120 | } */ 121 | /* 122 | pageInfo: current drawCallBack page change info 123 | */ 124 | Datatables.prototype.generateNewQueryOnPageChange = function(pageInfo){ 125 | if(this.qPage) UTILS.deleteStylizedEditor(this.ui, pageInfo.qTextDom); 126 | var qObj = UTILS.getCurrentWoqlQueryObject(null, pageInfo); 127 | //var query = this.getQueryOnPagination(this.wQuery, pageInfo) 128 | if(this.qPage) { 129 | if(pageInfo.queryMode.value == 'woql') 130 | pageInfo.qTextDom.value = JSON.stringify(qObj.prettyPrint(), undefined, 2); 131 | else pageInfo.qTextDom.value = JSON.stringify(qObj, undefined, 2); 132 | UTILS.stylizeEditor(this.ui, pageInfo.qTextDom, 'query', 'javascript'); 133 | } 134 | //return query; 135 | return qObj; 136 | } 137 | 138 | /* 139 | dt: Datatable reference 140 | len : current number of records to display 141 | */ 142 | Datatables.prototype.getCallbackSettings = function(dt, dtAPIChangeSettings){ 143 | var pageInfo = {}; 144 | pageInfo.pageLength = dtAPIChangeSettings._iDisplayLength; 145 | pageInfo.start = dtAPIChangeSettings._iDisplayStart; 146 | pageInfo.draw = dtAPIChangeSettings.iDraw; 147 | pageInfo.qTextDom = dt.qTextDom; 148 | pageInfo.queryMode = dt.queryMode; 149 | if(this.qPage) pageInfo.query = dt.query; 150 | else pageInfo.query = 'Show_All_Document_classes'; 151 | pageInfo.chosenValue = dt.chosenValue; 152 | return pageInfo; 153 | } 154 | 155 | /* 156 | tab: datatable table dom 157 | settings : settings from woql txt generator 158 | resultDOM: result dom of viewer 159 | */ 160 | Datatables.prototype.setUp = function(tab, settings, resultDOM){ 161 | // delete previous datatable 162 | HTMLHelper.removeChildren(this.dtdom); 163 | this.dtdom = document.createElement('div'); 164 | this.dtdom.appendChild(tab); 165 | resultDOM.appendChild(this.dtdom); 166 | // saving query text box dom to change limit value on change of datatable page length 167 | this.qTextDom = settings.qTextDom; 168 | this.query = settings.query; 169 | this.chosenValue = settings.chosenValue; 170 | this.queryMode = settings.queryMode; 171 | } 172 | 173 | // update datatables settings so it can be reused in WOQLTextboxGenerator to re write query in woql/ jsonld 174 | Datatables.prototype.updateCurrDTSettings = function(pageInfo){ 175 | this.currDTSettings.pageLength = pageInfo.pageLength; 176 | this.currDTSettings.start = pageInfo.start; 177 | } 178 | 179 | Datatables.prototype.getNewDataOnChange = function(drawnTab, aSettings, resultDOM){ 180 | var pageInfo = this.getCallbackSettings(this, aSettings); 181 | this.updateCurrDTSettings(pageInfo); 182 | // var query = this.generateNewQueryOnPageChange(pageInfo); 183 | var qObj = this.generateNewQueryOnPageChange(pageInfo); 184 | return this.executeQuery(qObj, pageInfo, resultDOM); 185 | //return this.executeQuery(query, pageInfo, resultDOM); 186 | //return dtResult.result.data; 187 | } 188 | 189 | Datatables.prototype.getDataFromServer = function(dtResult, resultDOM){ 190 | var dt = this; 191 | var tab = dtResult.tab; 192 | this.setUp(tab, this.wrViewer.settings, resultDOM); 193 | // initialize datatables 194 | var table = jQuery(tab).DataTable({ 195 | searching : false, 196 | pageLength : dt.wrViewer.settings.pageLength, 197 | serverSide : true, 198 | processing : true, 199 | lengthMenu : [25, 50, 75, 100], 200 | dom : 'RBlftip', 201 | columns : dtResult.result.columns, 202 | paging : true, 203 | select : true, 204 | autoWidth : true, 205 | ajax : function (data, callback, settings) { 206 | if(Object.entries(dtResult.result.data).length > 0){ 207 | // first draw is loaded 208 | var res = dtResult.result.data; 209 | dtResult.result.data = {}; 210 | callback(res); 211 | } 212 | else{ 213 | dt.getNewDataOnChange(this, settings, resultDOM) 214 | .then(function(result){ 215 | callback(result); 216 | }) 217 | } 218 | }, 219 | buttons : [{ extend: 'copy', text: 'Copy to clipboard' }, 220 | { extend: 'excel', text: 'Export to Excel' }], 221 | columnDefs : [{ targets:'_all', 222 | className:"truncate"}], 223 | createdRow : function(row){ 224 | var td = $(row).find(".truncate"); 225 | td.attr("title", td.html());}, 226 | scrollX : true 227 | }); //jQuery(tab) 228 | 229 | // on click of doc 230 | jQuery(tab, 'tbody').on('click', 'td', function(){ 231 | if(table.cell(this).data){ 232 | if(this.innerText.substring(0, 4) == "doc:"){ 233 | if(dt.wrViewer.result.ui) { 234 | dt.wrViewer.result.ui.showDocument(this.innerText); 235 | dt.wrViewer.result.ui.redraw(); 236 | dt.wrViewer.selectDocumentNavBar(dt.ui); 237 | } 238 | } 239 | } 240 | }); // on click 241 | 242 | //styling 243 | tab.setAttribute('class' , 'stripe dataTable'); 244 | tab.setAttribute('style' , 'margin: 0!important'); 245 | tab.setAttribute('cellpadding', '1'); 246 | tab.setAttribute('cellspacing', '1'); 247 | tab.setAttribute('border' , '0'); 248 | 249 | return tab; 250 | } 251 | 252 | /* 253 | serverside: true or false 254 | */ 255 | Datatables.prototype.draw = function(dtResult, resultDOM){ 256 | return(this.getDataFromServer(dtResult, resultDOM)); 257 | } 258 | 259 | module.exports={Datatables, CspDatatables} 260 | -------------------------------------------------------------------------------- /src/test.js: -------------------------------------------------------------------------------- 1 | var TerminusDashboard = require('./index.js'); 2 | 3 | var TerminusUI= TerminusDashboard.WOQL; 4 | 5 | console.log(TerminusDashboard.WOQL.limit(10).json()) -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebPackPlugin = require("html-webpack-plugin"); 3 | const CopyWebPackPlugin = require("copy-webpack-plugin"); 4 | require("@babel/register"); 5 | const Dotenv = require('dotenv-webpack'); 6 | var PACKAGE = require('./package.json'); 7 | var version = `v${PACKAGE.version}`; 8 | 9 | 10 | // Webpack Configuration 11 | const config = { 12 | 13 | // Entry 14 | entry: path.resolve(__dirname, 'src/index.js'), 15 | // Output 16 | output: { 17 | path: path.resolve(__dirname, `public_pages/${version}/dist`), 18 | filename: 'terminus-dashboard.min.js', 19 | sourceMapFilename: 'terminus-dashboard.min.js.map', 20 | libraryTarget: 'var', 21 | library: 'TerminusDashboard', 22 | }, 23 | node: { 24 | //process: false 25 | fs: "empty" 26 | }, 27 | // Loaders 28 | 29 | 30 | module: { 31 | rules : [ 32 | // JavaScript/JSX Files 33 | { 34 | test: /\.js$/, 35 | exclude: /node_modules/, 36 | loader: 'babel-loader' 37 | } 38 | ] 39 | }, 40 | devtool :'source-map', 41 | // Plugins 42 | }; 43 | 44 | module.exports = function(env, argv){ 45 | 46 | 47 | if (argv.mode === 'development') { 48 | // webpack-dev-server configuration 49 | config.devServer={ 50 | // Can be omitted unless you are using 'docker' 51 | contentBase: path.resolve(__dirname,'dist'), 52 | // 'Live-reloading' happens when you make changes to code 53 | // dependency pointed to by 'entry' parameter explained earlier. 54 | // To make live-reloading happen even when changes are made 55 | // to the static html pages in 'contentBase', add 56 | // 'watchContentBase' 57 | watchContentBase: true, 58 | compress: true 59 | } 60 | } 61 | 62 | config.plugins= [ 63 | new Dotenv(), 64 | new HtmlWebPackPlugin({ 65 | inject: false, 66 | template: path.resolve(__dirname, 'src/index.html'), 67 | bundleFileName:"terminus-dashboard.min.js" 68 | }), 69 | new CopyWebPackPlugin([ 70 | { from: path.resolve(__dirname, 'src/css'), to: 'css' }, 71 | { from: path.resolve(__dirname, 'src/UIconfig.json'), to:'./' } 72 | ]) 73 | ] 74 | 75 | return config; 76 | }; 77 | 78 | // Exports 79 | //module.exports = config; 80 | --------------------------------------------------------------------------------