├── .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 |
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 |
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
--------------------------------------------------------------------------------