├── .gitignore ├── .neutrinorc.js ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── json-joi.png ├── package.json ├── schemas ├── hook-status.json ├── indexed-task-response.json ├── post-artifact-request.json ├── provisioner-response.json └── task.json ├── src ├── common │ └── NormalRow.js ├── components │ ├── JoiSchemaTable │ │ └── index.js │ ├── SchemaTable │ │ ├── index.js │ │ └── styles.css │ └── index.js ├── stories.js └── widgets │ ├── CodeTooltip │ ├── index.js │ └── styles.css │ ├── Container │ ├── index.js │ └── styles.css │ └── Markdown │ └── index.js ├── viewer.png └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # build directory 61 | lib 62 | 63 | # Intellij IDE specific settings 64 | .idea/ 65 | -------------------------------------------------------------------------------- /.neutrinorc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | options: { 3 | port: 5005, 4 | }, 5 | use: ['neutrino-preset-react-components'] 6 | }; 7 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Community Participation Guidelines 2 | 3 | This repository is governed by Mozilla's code of conduct and etiquette guidelines. 4 | For more details, please read the 5 | [Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/). 6 | 7 | ## How to Report 8 | For more information on how to report violations of the Community Participation Guidelines, please read our '[How to Report](https://www.mozilla.org/about/governance/policies/participation/reporting/)' page. 9 | 10 | 16 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We welcome pull requests from everyone. We do expect everyone to adhere to the [Mozilla Community Participation Guidelines][participation]. 4 | 5 | If you're trying to figure out what to work on, here are some places to find suitable projects: 6 | * [Good first bugs][goodfirstbug]: these are scoped to make it easy for first-time contributors to get their feet wet with Taskcluster code. 7 | * [Mentored bugs][bugsahoy]: these are slightly more involved projects that may require insight or guidance from someone on the Taskcluster team. 8 | * [Full list of open issues][issues]: everything else 9 | 10 | If the project you're interested in working on isn't covered by a bug or issue, or you're unsure about how to proceed on an existing issue, it's a good idea to talk to someone on the Taskcluster team before you go too far down a particular path. You can find us in the #taskcluster channel on [Mozilla's IRC server][irc] to discuss. You can also simply add a comment to the issue or bug. 11 | 12 | Once you've found an issue to work on and written a patch, submit a pull request. Some things that will increase the chance that your pull request is accepted: 13 | 14 | * Follow our [best practices][bestpractices]. 15 | * This includes [writing or updating tests][testing]. 16 | * Write a [good commit message][commit]. 17 | 18 | Welcome to the team! 19 | 20 | [participation]: https://www.mozilla.org/en-US/about/governance/policies/participation/ 21 | [issues]: ../../issues 22 | [bugsahoy]: https://www.joshmatthews.net/bugsahoy/?taskcluster=1 23 | [goodfirstbug]: http://www.joshmatthews.net/bugsahoy/?taskcluster=1&simple=1 24 | [irc]: https://wiki.mozilla.org/IRC 25 | [bestpractices]: https://docs.taskcluster.net/docs/manual/design/devel/best-practices 26 | [testing]: https://docs.taskcluster.net/docs/manual/design/devel/best-practices/testing 27 | [commit]: https://docs.taskcluster.net/docs/manual/design/devel/best-practices/commits 28 | 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 📣 This library is no longer maintained. Please use [material-ui-json-schema-viewer](https://github.com/taskcluster/material-ui-json-schema-viewer/) instead. 2 | 3 | --- 4 | 5 | # react-schema-viewer 6 | 7 |

8 | 9 |

10 | 11 | --- 12 | 13 | React Schema Viewer takes a schema as input and uses it to generate comprehensible views. 14 | It has full support for Joi and JSON schema (version 3 and 4). 15 | 16 | ## SchemaTable 17 | 18 | ### Props 19 | | Property | Type | Required? | Description | 20 | |-------------------------|----------------------------|-----------|---------------------------------------------------------------------------------------------------| 21 | | `schema` | Object | ✓ | A JSON schema object. | 22 | | `headerBackgroundColor` | string | - | The header background color given that a schema title is provided. Default: 'rgb(245, 245, 245)'. | 23 | | `maxHeight` | string | - | Max height of the panel. Default: '100%'. | 24 | 25 | ## JoiSchemaTable 26 | 27 | ### Props 28 | | Property | Type | Required? | Description | 29 | |-------------------------|----------------------------|-----------|---------------------------------------------------------------------------------------------------| 30 | | `schema` | Object | ✓ | A Joi schema object. | 31 | | `headerBackgroundColor` | string | - | The header background color given that a schema title is provided. Default: 'rgb(245, 245, 245)'. | 32 | | `maxHeight` | string | - | Max height of the panel. Default: '100%'. | 33 | 34 | ### Usage 35 | 36 | react-schema-viewer is an ES-compatible module, so it can be imported as expected. If you want to use it with CJS require, you'll need to use the .default property to access the default exports: 37 | 38 | _Example: Importing SchemaTable_ 39 | 40 | ```js 41 | // CJS require 42 | const SchemaTable = require('react-schema-viewer/lib/SchemaTable').default; 43 | 44 | // ES module 45 | import SchemaTable from 'react-schema-viewer/lib/SchemaTable'; 46 | ``` 47 | 48 | _Example: Rendering a JSON schema:_ 49 | ```js 50 | import React from 'react'; 51 | import { render } from 'react-dom'; 52 | import SchemaTable from 'react-schema-viewer/lib/SchemaTable'; 53 | 54 | const jsonSchema = { 55 | 'title': 'Person', 56 | 'type': 'object', 57 | 'properties': { 58 | 'firstName': { 59 | 'type': 'string' 60 | }, 61 | 'lastName': { 62 | 'type': 'string' 63 | }, 64 | 'age': { 65 | 'description': 'Age in years', 66 | 'type': 'integer', 67 | 'minimum': 0 68 | } 69 | }, 70 | 'required': ['firstName', 'lastName'] 71 | }; 72 | 73 | render(( 74 | 75 | ), document.getElementById('root')); 76 | ```` 77 | 78 |

79 | 80 |

81 | 82 | _Example: Rendering a Joi object schema:_ 83 | ```js 84 | import React from 'react'; 85 | import { render } from 'react-dom'; 86 | import JoiSchemaTable from 'react-schema-viewer/lib/JoiSchemaTable'; 87 | 88 | joi.object({ 89 | firstName: joi.string().required(), 90 | lastName: joi.string().required(), 91 | age: joi.number().integer().min(0).description('Age in years'), 92 | }).label('Person'); 93 | 94 | render(( 95 | 96 | ), document.getElementById('root')); 97 | ```` 98 | 99 |

100 | 101 |

102 | 103 | ## Development and Contributing 104 | 105 | This repository uses [Neutrino](https://neutrino.js.org) and [neutrino-preset-react-components](https://github.com/eliperelman/neutrino-preset-react-components/) for developing, previewing, and building React components. To get started: 106 | 107 | - Fork and clone this repo. 108 | - Install the dependencies with `yarn`. 109 | - Start the development servers with `yarn start`. 110 | - Use CTRL-C to exit the development server. 111 | - Use `yarn build` to generate the compiled component for publishing to npm. 112 | 113 | Feel free to open an issue, submit a pull request, or contribute however you would like. Understand that this 114 | documentation is still a work in progress, so file an issue or submit a PR to ask questions or make improvements. 115 | Thanks! 116 | 117 | ## License 118 | 119 | react-schema-viewer is released as [MPL 2.0](http://mozilla.org/MPL/2.0/). 120 | -------------------------------------------------------------------------------- /json-joi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taskcluster/react-schema-viewer/fc1d4e6c1dadb609a28911f29253c6999eefd7f0/json-joi.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-schema-viewer", 3 | "version": "3.2.3", 4 | "description": "React Schema Viewer", 5 | "license": "MPL-2.0", 6 | "scripts": { 7 | "build": "neutrino build", 8 | "start": "neutrino start", 9 | "test": "neutrino build" 10 | }, 11 | "repository": "taskcluster/react-schema-viewer", 12 | "main": "lib/index.js", 13 | "files": [ 14 | "lib" 15 | ], 16 | "keywords": [ 17 | "react", 18 | "json", 19 | "joi", 20 | "validation", 21 | "schema", 22 | "table", 23 | "jsonschema", 24 | "viewer" 25 | ], 26 | "dependencies": { 27 | "bootstrap": "^3.3.7", 28 | "joi-to-json-schema": "^3.0.0", 29 | "markdown-it": "^8.4.0", 30 | "prop-types": "^15.6.0", 31 | "react-bootstrap": "^0.31.3", 32 | "react-hot-loader": "3.0.0-beta.7" 33 | }, 34 | "devDependencies": { 35 | "joi-browser": "^10.6.1", 36 | "neutrino": "^7.1.0", 37 | "neutrino-preset-react-components": "^2.1.3", 38 | "react": "^15.5.4", 39 | "react-addons-css-transition-group": "^15.6.2", 40 | "react-dom": "^15.5.4" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /schemas/hook-status.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "A snapshot of the current status of a hook.\n", 3 | "title": "Hook status response", 4 | "additionalProperties": false, 5 | "$schema": "http://json-schema.org/draft-06/schema#", 6 | "required": [ 7 | "lastFire" 8 | ], 9 | "type": "object", 10 | "properties": { 11 | "nextScheduledDate": { 12 | "type": "string", 13 | "description": "The next time this hook's task is scheduled to be created. This property\nis only present if there is a scheduled next time. Some hooks don't have\nany schedules.\n", 14 | "format": "date-time" 15 | }, 16 | "lastFire": { 17 | "oneOf": [ 18 | { 19 | "description": "Information about a successful firing of the hook", 20 | "title": "Successful Fire", 21 | "additionalProperties": false, 22 | "required": [ 23 | "result", 24 | "taskId", 25 | "time" 26 | ], 27 | "type": "object", 28 | "properties": { 29 | "result": { 30 | "enum": [ 31 | "success" 32 | ], 33 | "type": "string" 34 | }, 35 | "taskId": { 36 | "pattern": "^[A-Za-z0-9_-]{8}[Q-T][A-Za-z0-9_-][CGKOSWaeimquy26-][A-Za-z0-9_-]{10}[AQgw]$", 37 | "type": "string", 38 | "description": "The task created" 39 | }, 40 | "time": { 41 | "type": "string", 42 | "description": "The time the task was created. This will not necessarily match `task.created`.\n", 43 | "format": "date-time" 44 | } 45 | } 46 | }, 47 | { 48 | "description": "Information about an unsuccessful firing of the hook", 49 | "title": "Failed Fire", 50 | "additionalProperties": false, 51 | "required": [ 52 | "result", 53 | "error", 54 | "time" 55 | ], 56 | "type": "object", 57 | "properties": { 58 | "error": { 59 | "type": "object", 60 | "description": "The error that occurred when firing the task. This is typically,\nbut not always, an API error message.\n" 61 | }, 62 | "result": { 63 | "enum": [ 64 | "error" 65 | ], 66 | "type": "string" 67 | }, 68 | "time": { 69 | "type": "string", 70 | "description": "The time the task was created. This will not necessarily match `task.created`.\n", 71 | "format": "date-time" 72 | } 73 | } 74 | }, 75 | { 76 | "description": "Information about no firing of the hook (e.g., a new hook)", 77 | "title": "No Fire", 78 | "additionalProperties": false, 79 | "required": [ 80 | "result" 81 | ], 82 | "type": "object", 83 | "properties": { 84 | "result": { 85 | "enum": [ 86 | "no-fire" 87 | ], 88 | "type": "string" 89 | } 90 | } 91 | } 92 | ], 93 | "description": "Information about the last time this hook fired. This property is only present\nif the hook has fired at least once.\n" 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /schemas/indexed-task-response.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Representation of an indexed task.\n", 3 | "title": "Indexed Task Response", 4 | "additionalProperties": false, 5 | "$schema": "http://json-schema.org/draft-04/schema#", 6 | "$id": "https://tc.example.com/schemas/index/v1/tsak-response.json#", 7 | "required": [ 8 | "namespace", 9 | "taskId", 10 | "rank", 11 | "data", 12 | "expires" 13 | ], 14 | "type": "object", 15 | "properties": { 16 | "namespace": { 17 | "title": "Namespace", 18 | "type": "string", 19 | "description": "Namespace of the indexed task, used to find the indexed task in the index.\n", 20 | "maxLength": 255 21 | }, 22 | "expires": { 23 | "title": "Expiration", 24 | "type": "string", 25 | "description": "Date at which this entry expires from the task index.\n", 26 | "format": "date-time" 27 | }, 28 | "data": { 29 | "type": "object", 30 | "description": "Data that was reported with the task. This is an arbitrary JSON object.\n", 31 | "title": "Task Specific Data" 32 | }, 33 | "taskId": { 34 | "pattern": "^[A-Za-z0-9_-]{8}[Q-T][A-Za-z0-9_-][CGKOSWaeimquy26-][A-Za-z0-9_-]{10}[AQgw]$", 35 | "type": "string", 36 | "description": "Unique task identifier, this is UUID encoded as\n[URL-safe base64](http://tools.ietf.org/html/rfc4648#section-5) and\nstripped of `=` padding.\n", 37 | "title": "Task Identifier" 38 | }, 39 | "rank": { 40 | "type": "number", 41 | "description": "If multiple tasks are indexed with the same `namespace` the task with the\nhighest `rank` will be stored and returned in later requests. If two tasks\nhas the same `rank` the latest task will be stored.\n", 42 | "title": "Rank" 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /schemas/post-artifact-request.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-06/schema#", 3 | "title": "Post Artifact Request", 4 | "oneOf": [ 5 | { 6 | "description": "Request a list of requests in a generalized format which can be run to\nupload an artifact to storage managed by the queue.\n", 7 | "title": "Blob Artifact Request", 8 | "additionalProperties": false, 9 | "required": [ 10 | "storageType", 11 | "expires", 12 | "contentType", 13 | "contentSha256", 14 | "contentLength" 15 | ], 16 | "type": "object", 17 | "properties": { 18 | "contentType": { 19 | "type": "string", 20 | "description": "Artifact mime-type, when uploading artifact to the signed\n`PUT` URL returned from this request this must given with the\n `ContentType` header. Please, provide correct mime-type,\n this make tooling a lot easier, specifically,\n always using `application/json` for JSON artifacts.\n", 21 | "maxLength": 255 22 | }, 23 | "storageType": { 24 | "enum": [ 25 | "blob" 26 | ], 27 | "type": "string", 28 | "description": "Artifact storage type, in this case `'blob'`" 29 | }, 30 | "contentLength": { 31 | "minimum": 0, 32 | "type": "integer", 33 | "description": "The number of bytes of the entire artifact. This must be the number\nof bytes in the file to be uploaded. For single part uploads, the\nupload will fail if the number of bytes uploaded does not match this\nvalue. A single part upload (e.g. no parts list) may be at most 5GB.\nThis limit is enforced in the code because it is not possible to\nrepresent all of the restrictions in a json-schema. A multipart\nupload may be at most 5TB, with each part other than the last being\nbetween 5MB and 5GB in size.\n" 34 | }, 35 | "expires": { 36 | "type": "string", 37 | "description": "Date-time after which the artifact should be deleted. Note, that\nthese will be collected over time, and artifacts may remain\navailable after expiration. S3 based artifacts are identified in\nazure table storage and explicitly deleted on S3 after expiration.\n", 38 | "format": "date-time" 39 | }, 40 | "contentEncoding": { 41 | "type": "string", 42 | "description": "Optionally provide an encoding type which should be set as the HTTP\nContent-Encoding header for this artifact.\n", 43 | "maxLength": 255 44 | }, 45 | "transferSha256": { 46 | "pattern": "^[a-fA-F0-9]{64}$", 47 | "type": "string", 48 | "description": "This is the sha256 of the bytes transfered across the wire to the\nbacking datastore. If specified, it represents the\npost-content-encoding sha256 value\n" 49 | }, 50 | "parts": { 51 | "minLength": 1, 52 | "type": "array", 53 | "description": "A list of parts for a multipart upload. The presence of this list is\nhow a multipart upload is differentiated from a single part upload.\nThe items in this list represent individual parts for upload. For a\nmultipart upload, the sha256 values provided here must match the\nsha256 value that S3 internally computes for the upload to be\nconsidered a success. The overall sha256 value is not checked\nexplicitly because the S3 API does not allow for that, but the same\ncode that is responsible for generating the parts hashes would also\nbe generating the overall hash, which makes this less of a concern.\nThe worst case is that we have artifacts which incorrectly do not\nvalidate, which is not as big of a security concern.\n", 54 | "items": { 55 | "additionalProperties": false, 56 | "type": "object", 57 | "properties": { 58 | "sha256": { 59 | "pattern": "^[a-fA-F0-9]{64}$", 60 | "type": "string", 61 | "description": "The sha256 hash of the part.\n", 62 | "minLength": 64, 63 | "maxLength": 64 64 | }, 65 | "size": { 66 | "minimum": 0, 67 | "type": "integer", 68 | "description": "The number of bytes in this part. Keep in mind for S3 that\nall but the last part must be minimum 5MB and the maximum for\na single part is 5GB. The overall size may not exceed 5TB\n" 69 | } 70 | }, 71 | "title": "Multipart Part" 72 | } 73 | }, 74 | "contentSha256": { 75 | "pattern": "^[a-fA-F0-9]{64}$", 76 | "type": "string", 77 | "description": "The complete SHA256 value of the entire artifact. This must be the\nSHA256 of the file which is to be uploaded. For single part uploads,\nthe upload will fail if the SHA256 value of what is uploaded does not\nmatch this value\n" 78 | }, 79 | "transferLength": { 80 | "minimum": 0, 81 | "type": "integer", 82 | "description": "The number of bytes transfered across the wire to the backing\ndatastore. If specified, it represents the post-content-encoding\nbyte count\n" 83 | } 84 | } 85 | }, 86 | { 87 | "description": "Request for a signed PUT URL that will allow you to upload an artifact\nto an S3 bucket managed by the queue.\n", 88 | "title": "S3 Artifact Request", 89 | "additionalProperties": false, 90 | "required": [ 91 | "storageType", 92 | "expires", 93 | "contentType" 94 | ], 95 | "type": "object", 96 | "properties": { 97 | "storageType": { 98 | "enum": [ 99 | "s3" 100 | ], 101 | "type": "string", 102 | "description": "Artifact storage type, in this case `'s3'`\n" 103 | }, 104 | "expires": { 105 | "type": "string", 106 | "description": "Date-time after which the artifact should be deleted. Note, that\nthese will be collected over time, and artifacts may remain\navailable after expiration. S3 based artifacts are identified in\nazure table storage and explicitly deleted on S3 after expiration.\n", 107 | "format": "date-time" 108 | }, 109 | "contentType": { 110 | "type": "string", 111 | "description": "Artifact mime-type, when uploading artifact to the signed\n`PUT` URL returned from this request this must given with the\n `ContentType` header. Please, provide correct mime-type,\n this make tooling a lot easier, specifically,\n always using `application/json` for JSON artifacts.\n", 112 | "maxLength": 255 113 | } 114 | } 115 | }, 116 | { 117 | "description": "Request for an Azure Shared Access Signature (SAS) that will allow\nyou to upload an artifact to an Azure blob storage container managed\nby the queue.\n", 118 | "title": "Azure Artifact Request", 119 | "additionalProperties": false, 120 | "required": [ 121 | "storageType", 122 | "expires", 123 | "contentType" 124 | ], 125 | "type": "object", 126 | "properties": { 127 | "storageType": { 128 | "enum": [ 129 | "azure" 130 | ], 131 | "type": "string", 132 | "description": "Artifact storage type, in this case `azure`\n" 133 | }, 134 | "expires": { 135 | "type": "string", 136 | "description": "Date-time after which the artifact should be deleted.\nNote, that these will be collected over time, and artifacts may\nremain available after expiration. Azure based artifacts are\nidentified in azure table storage and explicitly deleted in the\nazure storage container after expiration.\n", 137 | "format": "date-time" 138 | }, 139 | "contentType": { 140 | "type": "string", 141 | "description": "Artifact mime-type, when uploading artifact please use the same\n`Content-Type`, consistently using the correct mime-type make\ntooling a lot easier, specifically, always using `application/json`\nfor JSON artifacts.\n", 142 | "maxLength": 255 143 | } 144 | } 145 | }, 146 | { 147 | "description": "Request the queue to redirect to a URL for a given artifact.\nThis allows you to reference artifacts that aren't managed by the queue.\nThe queue will still authenticate the request, so depending on the level\nof secrecy required, secret URLs **might** work. Note, this is mainly\nuseful for public artifacts, for example temporary files directly\nstored on the worker host and only available there for a specific\namount of time.\n", 148 | "title": "Redirect Artifact Request", 149 | "additionalProperties": false, 150 | "required": [ 151 | "storageType", 152 | "expires", 153 | "url", 154 | "contentType" 155 | ], 156 | "type": "object", 157 | "properties": { 158 | "storageType": { 159 | "enum": [ 160 | "reference" 161 | ], 162 | "type": "string", 163 | "description": "Artifact storage type, in this case `reference`\n" 164 | }, 165 | "url": { 166 | "type": "string", 167 | "description": "URL to which the queue should redirect using a `303` (See other)\nredirect.\n", 168 | "format": "uri" 169 | }, 170 | "expires": { 171 | "type": "string", 172 | "description": "Date-time after which the queue should no longer redirect to this URL.\nNote, that the queue will and cannot delete the resource your URL\nreferences, you are responsible for doing that yourself.\n", 173 | "format": "date-time" 174 | }, 175 | "contentType": { 176 | "type": "string", 177 | "description": "Artifact mime-type for the resource to which the queue should\nredirect. Please use the same `Content-Type`, consistently using\nthe correct mime-type make tooling a lot easier, specifically,\nalways using `application/json` for JSON artifacts.\n", 178 | "maxLength": 255 179 | } 180 | } 181 | }, 182 | { 183 | "description": "Request the queue to reply `424` (Failed Dependency) with `reason` and \n`message` to any `GET` request for this artifact. This is mainly useful\nas a way for a task to declare that it failed to provide an artifact it\nwanted to upload.\n", 184 | "title": "Error Artifact Request", 185 | "additionalProperties": false, 186 | "required": [ 187 | "storageType", 188 | "expires", 189 | "reason", 190 | "message" 191 | ], 192 | "type": "object", 193 | "properties": { 194 | "storageType": { 195 | "enum": [ 196 | "error" 197 | ], 198 | "type": "string", 199 | "description": "Artifact storage type, in this case `error`\n" 200 | }, 201 | "reason": { 202 | "enum": [ 203 | "file-missing-on-worker", 204 | "invalid-resource-on-worker", 205 | "too-large-file-on-worker" 206 | ], 207 | "type": "string", 208 | "description": "Reason why the artifact doesn't exist.\n" 209 | }, 210 | "expires": { 211 | "type": "string", 212 | "description": "Date-time after which the queue should stop replying with the error\nand forget about the artifact.\n", 213 | "format": "date-time" 214 | }, 215 | "message": { 216 | "type": "string", 217 | "description": "Human readable explanation of why the artifact is missing\n", 218 | "maxLength": 4096 219 | } 220 | } 221 | } 222 | ], 223 | "description": "Request a authorization to put and artifact or posting of a URL as an artifact. Note that the `storageType` property is referenced in the response as well." 224 | } 225 | -------------------------------------------------------------------------------- /schemas/provisioner-response.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Response containing information about a provisioner.\n", 3 | "title": "Provisioner Response", 4 | "additionalProperties": false, 5 | "$schema": "http://json-schema.org/draft-06/schema#", 6 | "required": [ 7 | "provisionerId", 8 | "description", 9 | "actions", 10 | "stability", 11 | "expires", 12 | "lastDateActive" 13 | ], 14 | "type": "object", 15 | "properties": { 16 | "stability": { 17 | "enum": [ 18 | "experimental", 19 | "stable", 20 | "deprecated" 21 | ], 22 | "type": "string", 23 | "description": "This is the stability of the provisioner. Accepted values:\n * `experimental`\n * `stable`\n * `deprecated`\n", 24 | "title": "Stability" 25 | }, 26 | "provisionerId": { 27 | "minLength": 1, 28 | "title": "Provisioner ID", 29 | "type": "string", 30 | "pattern": "^([a-zA-Z0-9-_]*)$", 31 | "maxLength": 22 32 | }, 33 | "description": { 34 | "type": "string", 35 | "description": "Description of the provisioner.\n", 36 | "title": "Description" 37 | }, 38 | "expires": { 39 | "title": "Provisioner Expiration", 40 | "type": "string", 41 | "description": "Date and time after which the provisioner will be automatically\ndeleted by the queue.\n", 42 | "format": "date-time" 43 | }, 44 | "lastDateActive": { 45 | "title": "Provisioner Last Date Active", 46 | "type": "string", 47 | "description": "Date of the last time this provisioner was seen active. `lastDateActive` is updated every 6 hours\nbut may be off by up-to 6 hours. Nonetheless, `lastDateActive` is a good indicator\nof when the provisioner was last seen active.\n", 48 | "format": "date-time" 49 | }, 50 | "actions": { 51 | "$ref": "actions.json#" 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /schemas/task.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Definition of a task that can be scheduled\n", 3 | "title": "Task Definition Response", 4 | "additionalProperties": false, 5 | "$schema": "http://json-schema.org/draft-06/schema#", 6 | "required": [ 7 | "provisionerId", 8 | "workerType", 9 | "schedulerId", 10 | "taskGroupId", 11 | "dependencies", 12 | "requires", 13 | "routes", 14 | "priority", 15 | "retries", 16 | "created", 17 | "deadline", 18 | "scopes", 19 | "payload", 20 | "metadata", 21 | "tags", 22 | "extra" 23 | ], 24 | "type": "object", 25 | "properties": { 26 | "taskGroupId": { 27 | "pattern": "^[A-Za-z0-9_-]{8}[Q-T][A-Za-z0-9_-][CGKOSWaeimquy26-][A-Za-z0-9_-]{10}[AQgw]$", 28 | "type": "string", 29 | "description": "Identifier for a group of tasks scheduled together with this task.\nGenerally, all tasks related to a single event such as a version-control\npush or a nightly build have the same `taskGroupId`. This property\ndefaults to `taskId` if it isn't specified. Tasks with `taskId` equal to\nthe `taskGroupId` are, [by convention](/docs/manual/using/task-graph),\ndecision tasks.\n", 30 | "title": "Task-Group Identifier" 31 | }, 32 | "extra": { 33 | "default": {}, 34 | "type": "object", 35 | "description": "Object with properties that can hold any kind of extra data that should be\nassociated with the task. This can be data for the task which doesn't\nfit into `payload`, or it can supplementary data for use in services\nlistening for events from this task. For example this could be details to\ndisplay on _treeherder_, or information for indexing the task. Please, try\nto put all related information under one property, so `extra` data keys\nfor treeherder reporting and task indexing don't conflict, hence, we have\nreusable services. **Warning**, do not stuff large data-sets in here --\ntask definitions should not take-up multiple MiBs.\n", 36 | "title": "Extra Data" 37 | }, 38 | "expires": { 39 | "title": "Expiration", 40 | "type": "string", 41 | "description": "Task expiration, time at which task definition and status is deleted.\nNotice that all artifacts for the task must have an expiration that is no\nlater than this. If this property isn't it will be set to `deadline`\nplus one year (this default may change).\n", 42 | "format": "date-time" 43 | }, 44 | "schedulerId": { 45 | "pattern": "^([a-zA-Z0-9-_]*)$", 46 | "description": "All tasks in a task group must have the same `schedulerId`. This is used for several purposes:\n\n* it can represent the entity that created the task;\n* it can limit addition of new tasks to a task group: the caller of\n `createTask` must have a scope related to the `schedulerId` of the task\n group;\n* it controls who can manipulate tasks, again by requiring\n `schedulerId`-related scopes; and\n* it appears in the routing key for Pulse messages about the task.\n", 47 | "title": "Scheduler Identifier", 48 | "default": "-", 49 | "minLength": 1, 50 | "maxLength": 22, 51 | "type": "string" 52 | }, 53 | "deadline": { 54 | "title": "Deadline", 55 | "description": "Deadline of the task, `pending` and `running` runs are resolved as **exception** if not resolved by other means before the deadline. Note, deadline cannot be more than 5 days into the future", 56 | "type": "string", 57 | "format": "date-time" 58 | }, 59 | "payload": { 60 | "type": "object", 61 | "description": "Task-specific payload following worker-specific format.\nRefer to the documentation for the worker implementing\n`/` for details.\n", 62 | "title": "Task Payload" 63 | }, 64 | "provisionerId": { 65 | "description": "Unique identifier for a provisioner, that can supply specified\n`workerType`\n", 66 | "title": "Provisioner Id", 67 | "pattern": "^([a-zA-Z0-9-_]*)$", 68 | "maxLength": 22, 69 | "type": "string", 70 | "minLength": 1 71 | }, 72 | "workerType": { 73 | "description": "Unique identifier for a worker-type within a specific provisioner\n", 74 | "title": "Worker Type", 75 | "pattern": "^([a-zA-Z0-9-_]*)$", 76 | "maxLength": 22, 77 | "type": "string", 78 | "minLength": 1 79 | }, 80 | "retries": { 81 | "minimum": 0, 82 | "description": "Number of times to retry the task in case of infrastructure issues.\nAn _infrastructure issue_ is a worker node that crashes or is shutdown,\nthese events are to be expected.\n", 83 | "title": "Retries", 84 | "default": 5, 85 | "type": "integer", 86 | "maximum": 49 87 | }, 88 | "created": { 89 | "title": "Created", 90 | "description": "Creation time of task", 91 | "type": "string", 92 | "format": "date-time" 93 | }, 94 | "tags": { 95 | "default": {}, 96 | "additionalProperties": { 97 | "type": "string", 98 | "maxLength": 4096 99 | }, 100 | "type": "object", 101 | "description": "Arbitrary key-value tags (only strings limited to 4k). These can be used\nto attach informal metadata to a task. Use this for informal tags that\ntasks can be classified by. You can also think of strings here as\ncandidates for formal metadata. Something like\n`purpose: 'build' || 'test'` is a good example.\n", 102 | "title": "Tags" 103 | }, 104 | "priority": { 105 | "default": "lowest", 106 | "enum": [ 107 | "highest", 108 | "very-high", 109 | "high", 110 | "medium", 111 | "low", 112 | "very-low", 113 | "lowest", 114 | "normal" 115 | ], 116 | "type": "string", 117 | "description": "Priority of task. This defaults to `lowest` and the scope\n`queue:create-task://` is required\nto define a task with ``. The `normal` priority is treated as\n`lowest`.\n", 118 | "title": "Task Priority" 119 | }, 120 | "dependencies": { 121 | "uniqueItems": true, 122 | "description": "List of dependent tasks. These must either be _completed_ or _resolved_\nbefore this task is scheduled. See `requires` for semantics.\n", 123 | "maxItems": 100, 124 | "title": "Task Dependencies", 125 | "default": [], 126 | "items": { 127 | "pattern": "^[A-Za-z0-9_-]{8}[Q-T][A-Za-z0-9_-][CGKOSWaeimquy26-][A-Za-z0-9_-]{10}[AQgw]$", 128 | "type": "string", 129 | "description": "The `taskId` of a task that must be resolved before this task is\nscheduled.\n", 130 | "title": "Task Dependency" 131 | }, 132 | "type": "array" 133 | }, 134 | "routes": { 135 | "uniqueItems": true, 136 | "description": "List of task-specific routes. Pulse messages about the task will be CC'ed to\n`route.` for each `` in this array.\n", 137 | "maxItems": 64, 138 | "title": "Task Specific Routes", 139 | "default": [], 140 | "items": { 141 | "minLength": 1, 142 | "title": "Task Specific Route", 143 | "type": "string", 144 | "description": "A task specific route.\n", 145 | "maxLength": 249 146 | }, 147 | "type": "array" 148 | }, 149 | "scopes": { 150 | "items": { 151 | "type": "string", 152 | "name": "Scope", 153 | "description": "A single scope. A scope must be composed of printable ASCII characters and spaces. Scopes ending in more than one `*` character are forbidden.", 154 | "pattern": "^[\\x20-\\x7e]*$" 155 | }, 156 | "type": "array", 157 | "description": "List of scopes that the task is authorized to use during its execution.\n", 158 | "title": "Scopes" 159 | }, 160 | "requires": { 161 | "default": "all-completed", 162 | "enum": [ 163 | "all-completed", 164 | "all-resolved" 165 | ], 166 | "type": "string", 167 | "description": "The tasks relation to its dependencies. This property specifies the\nsemantics of the `task.dependencies` property.\nIf `all-completed` is given the task will be scheduled when all\ndependencies are resolved _completed_ (successful resolution).\nIf `all-resolved` is given the task will be scheduled when all dependencies\nhave been resolved, regardless of what their resolution is.\n", 168 | "title": "Dependency Requirement Semantics" 169 | }, 170 | "metadata": { 171 | "$ref": "task-metadata.json#" 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/common/NormalRow.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Markdown from '../widgets/Markdown'; 3 | import CodeTooltip from '../widgets/CodeTooltip'; 4 | import styles from '../components/SchemaTable/styles.css'; 5 | 6 | export default class NormalRow extends React.PureComponent { 7 | limits(schema) { 8 | const isNumber = prop => typeof prop === 'number'; 9 | 10 | const min = (isNumber(schema.minLength) && schema.minLength) || 11 | (isNumber(schema.minItems) && schema.minItems) || 12 | (isNumber(schema.minimum) && schema.minimum); 13 | 14 | const max = (isNumber(schema.maxLength) && schema.maxLength) 15 | || (isNumber(schema.maxItems) && schema.maxItems) 16 | || (isNumber(schema.maximum) && schema.maximum); 17 | 18 | if (isNumber(min) || isNumber(max)) { 19 | return `[${min || 0}:${max || '∞'}]`; 20 | } 21 | } 22 | 23 | formatField(schema) { 24 | if (schema.pattern) { 25 | return ; 26 | } else if (schema.format) { 27 | return {schema.format}; 28 | } else if (schema.enum) { 29 | return ( 30 |
    31 | {schema.enum.map(val => ( 32 |
  • 33 | 34 |
  • 35 | ))} 36 |
37 | ); 38 | } 39 | } 40 | 41 | render() { 42 | const {schema, name, type, reqSet} = this.props; 43 | const required = reqSet && reqSet.has(name); 44 | 45 | return ( 46 | 47 | 48 | 49 | 50 | {name} 51 | {required && ' *'} 52 | 53 | 54 | 55 | 56 | {type || schema.type}{this.limits(schema)} 57 |
58 | {schema.default && default: {JSON.stringify(schema.default)}} 59 | 60 | 61 | {this.formatField(schema)} 62 | 63 | 64 | {schema.description} 65 | 66 | 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/components/JoiSchemaTable/index.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import joiToJson from 'joi-to-json-schema'; 3 | import SchemaTable from '../SchemaTable'; 4 | 5 | export default class JoiSchemaTable extends PureComponent { 6 | render() { 7 | const schema = joiToJson(this.props.schema); 8 | 9 | return ; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/components/SchemaTable/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Table } from 'react-bootstrap'; 3 | import { object, bool, oneOf, string } from 'prop-types'; 4 | import Container from '../../widgets/Container'; 5 | import NormalRow from '../../common/NormalRow'; 6 | import styles from './styles.css'; 7 | 8 | export default class SchemaTable extends React.PureComponent { 9 | static propTypes = { 10 | schema: object.isRequired, 11 | headerBackgroundColor: string, 12 | maxHeight: string, 13 | type: string 14 | }; 15 | 16 | static defaultProps = { 17 | headerBackgroundColor: '#f5f5f5', 18 | maxHeight: '100%', 19 | type: 'json' 20 | }; 21 | 22 | objectTable(schema, name, reqSet, key) { 23 | let res = []; 24 | 25 | if (schema.properties) { 26 | res = Object.entries(schema.properties).map(([name, prop]) => { 27 | return this.schemaTable(prop, name, reqSet, `${key}-${name}`); 28 | }); 29 | 30 | if (schema.additionalProperties) { 31 | res.push(( 32 | 33 | 34 | 35 | Additional properties are permitted... 36 | 37 | 38 | 39 | )); 40 | } 41 | } else if (schema.additionalProperties){ 42 | res = this.schemaTable(schema.additionalProperties, null, '', reqSet) 43 | } else { 44 | res = ( 45 | 46 | 47 | 48 | Anything ¯\_(ツ)_/¯ 49 | 50 | 51 | 52 | ); 53 | } 54 | return name ? ( 55 | 56 | 57 | 58 | 59 | 60 | {res} 61 |
62 | 63 | 64 | 65 | ) : res; 66 | } 67 | 68 | combination(schema, things, name, type, key) { 69 | return ( 70 | 71 | 72 | 73 | 74 | 75 | {things.map((thing, i) => { 76 | return this.schemaTable(thing, thing.title, null, `${key}-${i}`); 77 | })} 78 |
79 | 80 | 81 | 82 | ); 83 | } 84 | 85 | schemaTable(schema, name, reqSet, key) { 86 | reqSet = new Set(schema.required || reqSet || []); 87 | key = `${key}-${name}`; 88 | 89 | if (schema.anyOf) { 90 | return this.combination(schema, schema.anyOf, name, 'Any of', key); 91 | } else if (schema.allOf) { 92 | return this.combination(schema, schema.allOf, name, 'All of', key); 93 | } else if (schema.oneOf) { 94 | return this.combination(schema, schema.oneOf, name, 'One of', key); 95 | } 96 | 97 | const renderArray = () => ( 98 | 99 | 100 | 101 | 102 | 103 | {this.schemaTable( 104 | schema.items, 105 | schema.items.title, 106 | reqSet, 107 | `${key}-${schema.items.title}` 108 | )} 109 |
110 | 111 | 112 | 113 | ); 114 | const renderObject = () => this.objectTable(schema, name, reqSet, key); 115 | 116 | switch (schema.type) { 117 | case 'object': return renderObject(); 118 | case 'array': { 119 | if (schema.items) { 120 | return renderArray(); 121 | } 122 | } 123 | case undefined: 124 | if (schema.properties) { 125 | return renderObject(); 126 | } else if (schema.items) { 127 | return renderArray(); 128 | } 129 | default: return ( 130 | 131 | 132 | 133 | ); 134 | } 135 | } 136 | 137 | render() { 138 | const { schema } = this.props; 139 | 140 | return ( 141 | 145 | 148 | {this.schemaTable(schema, null, null, schema.$id ? schema.$id : schema.id)} 149 |
150 |
151 | ); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/components/SchemaTable/styles.css: -------------------------------------------------------------------------------- 1 | .parentTable { 2 | font-family: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 3 | font-size: 0.8em; 4 | } 5 | 6 | .parentTable tbody:first-child tr td { 7 | border: 0; 8 | } 9 | 10 | .childTable tbody tr td { 11 | border: 0; 12 | } 13 | 14 | .parentTable tr td { 15 | white-space: nowrap; 16 | } 17 | 18 | .parentTable tr td:nth-child(4) { 19 | font-family: Open Sans,sans-serif; 20 | white-space: normal; 21 | } 22 | 23 | .joined > tr:first-child { 24 | border-bottom: none; 25 | } 26 | 27 | .joined > tr:last-child { 28 | border-top: none; 29 | } 30 | 31 | .joined > :last-child td { 32 | padding-left: 2em; 33 | } 34 | 35 | .required { 36 | color: red; 37 | vertical-align: super; 38 | font-size: 0.7em; 39 | } 40 | 41 | .list { 42 | padding-left: 0; 43 | list-style-position: inside; 44 | } 45 | 46 | .parentTable tbody table { 47 | background-color: initial !important; 48 | } 49 | -------------------------------------------------------------------------------- /src/components/index.js: -------------------------------------------------------------------------------- 1 | import SchemaTable from './SchemaTable'; 2 | import JoiSchemaTable from './JoiSchemaTable'; 3 | 4 | export { 5 | SchemaTable, 6 | JoiSchemaTable, 7 | }; 8 | -------------------------------------------------------------------------------- /src/stories.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-dom'; 3 | import { AppContainer } from 'react-hot-loader'; 4 | import { Stories, Story, Props } from 'neutrino-preset-react-components/lib'; 5 | import SchemaTable from './components/SchemaTable'; 6 | import JoiSchemaTable from './components/JoiSchemaTable'; 7 | import joi from 'joi-browser'; 8 | import 'bootstrap/dist/css/bootstrap.min.css'; 9 | 10 | const root = document.getElementById('root'); 11 | 12 | const load = async () => { 13 | const hookStatus = require('../schemas/hook-status.json'); 14 | const taskDef = require('../schemas/task.json'); 15 | const indexedTask = require('../schemas/indexed-task-response.json'); 16 | const oneOf = await require('../schemas/post-artifact-request.json'); 17 | const otherProps = require('../schemas/provisioner-response.json'); 18 | const joiSchema = joi.object({ 19 | client_id: joi.string().optional(), 20 | addon_version: joi.string().required(), 21 | locale: joi.string().required(), 22 | session_id: joi.string(), 23 | page: joi.string().valid(["about:home", "about:newtab", "unknown"]), 24 | user_prefs: joi.number().integer().required() 25 | }); 26 | 27 | render( 28 | ( 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | ), root 44 | ); 45 | }; 46 | 47 | if (module.hot) { 48 | module.hot.accept(['./components/SchemaTable', './components/JoiSchemaTable'], load); 49 | } 50 | 51 | load(); 52 | -------------------------------------------------------------------------------- /src/widgets/CodeTooltip/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Popover, OverlayTrigger } from 'react-bootstrap'; 3 | import styles from './styles.css'; 4 | 5 | const PATTERN_MAX = 15; 6 | const Pattern = ({ pattern }) => { 7 | if (!(pattern.length > PATTERN_MAX)) { 8 | return {pattern} 9 | } 10 | 11 | return ( 12 | 14 | {pattern} 15 | 16 | )}> 17 | 18 | {pattern.slice(0, PATTERN_MAX)} 19 | ... 20 | 21 | 22 | ); 23 | }; 24 | 25 | export default Pattern; 26 | -------------------------------------------------------------------------------- /src/widgets/CodeTooltip/styles.css: -------------------------------------------------------------------------------- 1 | .short { 2 | white-space: nowrap; 3 | overflow: hidden; 4 | } 5 | 6 | .dots { 7 | font-size: 0.5em; 8 | } 9 | 10 | .popover { 11 | max-width: 90vw; 12 | position: absolute; 13 | z-index: 1500; 14 | } 15 | -------------------------------------------------------------------------------- /src/widgets/Container/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Markdown from '../Markdown'; 3 | import styles from './styles.css'; 4 | 5 | export default class Container extends React.PureComponent { 6 | constructor(props) { 7 | super(props); 8 | 9 | this.state = { 10 | jsonView: false 11 | } 12 | } 13 | 14 | handleViewToggle = () => { 15 | this.setState({ 16 | jsonView: !this.state.jsonView 17 | }); 18 | }; 19 | 20 | renderHeader = () => { 21 | const { schema, backgroundColor } = this.props; 22 | return ( 23 |
24 |

25 | {schema.title} {( 26 | 27 | {this.state.jsonView ? 'hide' : 'show'} source 28 | 29 | )} 30 |

31 | {schema.description} 32 |
33 | ); 34 | }; 35 | 36 | render() { 37 | const { maxHeight, schema } = this.props; 38 | 39 | return ( 40 |
41 |
42 | {schema.title && this.renderHeader()} 43 |
44 |
45 | {!this.state.jsonView ? this.props.children : ( 46 |
47 |               {JSON.stringify(schema, undefined, 2)}
48 |             
49 | )} 50 |
51 |
52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/widgets/Container/styles.css: -------------------------------------------------------------------------------- 1 | .container { 2 | overflow-y: auto; 3 | } 4 | 5 | .headerContainer { 6 | padding: 10px 8px; 7 | } 8 | 9 | .title { 10 | margin-top: 0; 11 | } 12 | 13 | .source { 14 | font-size: 0.7em; 15 | } 16 | 17 | .preJsonView code { 18 | white-space: inherit; 19 | } 20 | -------------------------------------------------------------------------------- /src/widgets/Markdown/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { string } from 'prop-types'; 3 | import markdown from 'markdown-it'; 4 | 5 | export default class Markdown extends React.PureComponent { 6 | render() { 7 | return ( 8 | 13 | ); 14 | } 15 | } 16 | 17 | Markdown.propTypes = { 18 | children: string.isRequired 19 | }; 20 | 21 | Markdown.defaultProps = { 22 | children: '' 23 | }; 24 | -------------------------------------------------------------------------------- /viewer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taskcluster/react-schema-viewer/fc1d4e6c1dadb609a28911f29253c6999eefd7f0/viewer.png --------------------------------------------------------------------------------