├── .eslintrc.json
├── .gitignore
├── LICENSE
├── README.md
├── bin
└── agreed-ui.js
├── build
├── favicon.png
├── index.html
├── precache-manifest.16323404084df425993dec323fbdcaed.js
└── static
│ ├── css
│ ├── main.99e23d20.chunk.css
│ └── main.99e23d20.chunk.css.map
│ └── js
│ ├── 1.f784af42.chunk.js
│ ├── 1.f784af42.chunk.js.map
│ ├── main.36d30304.chunk.js
│ ├── main.36d30304.chunk.js.map
│ ├── runtime~main.4a686d48.js
│ └── runtime~main.4a686d48.js.map
├── package-lock.json
├── package.json
├── public
├── favicon.png
└── index.html
├── renovate.json
├── screenshot.png
├── scripts
└── build.js
├── server
├── index.js
└── lib
│ └── getAgreements.js
├── src
├── components
│ ├── Agree
│ │ ├── index.js
│ │ └── styles.css
│ ├── Agrees
│ │ ├── index.js
│ │ └── styles.css
│ ├── App
│ │ ├── App.test.js
│ │ ├── index.js
│ │ └── styles.css
│ ├── Body
│ │ ├── index.js
│ │ └── styles.css
│ ├── Definitions
│ │ ├── index.js
│ │ └── styles.css
│ ├── JsonSchemaViewer
│ │ ├── index.js
│ │ └── styles.css
│ ├── MethodLabel
│ │ ├── index.js
│ │ └── styles.css
│ ├── Navigation
│ │ ├── index.js
│ │ └── styles.css
│ ├── Request
│ │ ├── index.js
│ │ └── styles.css
│ └── Response
│ │ ├── index.js
│ │ └── styles.css
├── index.css
└── index.js
└── test
└── agrees
├── agrees.js
├── agrees.json5
├── foo
└── bar.yaml
├── hoge
├── foo.json
└── fuga
│ ├── _agree.json
│ └── request.json
├── index.js
├── notify.js
├── qux
├── request.json
└── response.json
├── schema
└── hi.json
└── sub.js
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "commonjs": true,
5 | "es6": true,
6 | "node": true
7 | },
8 | "extends": ["eslint:recommended", "plugin:react/recommended", "prettier"],
9 | "parserOptions": {
10 | "ecmaFeatures": {
11 | "experimentalObjectRestSpread": true,
12 | "jsx": true
13 | },
14 | "sourceType": "module"
15 | },
16 | "plugins": ["react", "prettier"],
17 | "rules": {
18 | "indent": ["error", 2],
19 | "linebreak-style": ["error", "unix"],
20 | "quotes": ["error", "single"],
21 | "semi": ["error", "never"],
22 | "prettier/prettier": "error"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build/service-worker.js
11 | /build/asset-manifest.json
12 |
13 | # misc
14 | .DS_Store
15 | .env.local
16 | .env.development.local
17 | .env.test.local
18 | .env.production.local
19 |
20 | npm-debug.log*
21 | yarn-debug.log*
22 | yarn-error.log*
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 | Copyright © 2018 Recruit Technologies Co.,Ltd.
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Agreed UI
2 |
3 | UI for [Agreed](https://www.npmjs.com/package/agreed-core)
4 |
5 | 
6 |
7 | # Install
8 |
9 | ```
10 | $ npm install agreed-ui --save-dev
11 | ```
12 |
13 | # Usage
14 |
15 | ```
16 | $ agreed-ui --path ./test/agreed.json --port 3000
17 | ```
18 | Serve with [Express](https://www.npmjs.com/package/express)
19 | Open http://localhost:3000 to view it in the browser.
20 |
21 | ```
22 | $ agreed-ui build --path ./test/agreed.json --dest ./build
23 | ```
24 | Builds the app for static-hosting to the build folder
25 |
26 | # Features
27 |
28 | ## Set title and description to contract
29 |
30 | ```
31 | {
32 | title: 'get store information',
33 | description: 'get store information',
34 | request: {
35 | ...
36 | },
37 | response: {
38 | ...
39 | }
40 | }
41 | ```
42 |
43 | title and descripion will be displayed at naviation and each section's title
44 |
45 | # Development
46 |
47 | `npm run start:dev -- --path=./test/agrees/agrees.js `
--------------------------------------------------------------------------------
/bin/agreed-ui.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | const path = require('path')
3 | const spawn = require('child_process').spawn
4 | const minimist = require('minimist')
5 | const colo = require('colo')
6 | const execArgv = minimist(process.execArgv)
7 | const argv = minimist(process.argv.slice(2))
8 |
9 | function showHelp(exitcode) {
10 | console.log(`
11 | agreed-ui [--path agreed path file (required)][--port request server port default 3000]
12 | agreed-ui build [--path agreed path file (required)][--dest output directory(required)]
13 | agreed-ui --path ./agreed.js --port 4000
14 | agreed-ui build --path ./agreed.js --dest ./build
15 | `)
16 | process.exit(exitcode)
17 | }
18 |
19 | const command = argv['_'][0] || 'start'
20 |
21 | if (argv.help || command === 'help') {
22 | showHelp(0)
23 | }
24 |
25 | if (argv.version || command === 'version') {
26 | const pack = require('../package.json')
27 | console.log(pack.version)
28 | process.exit(0)
29 | }
30 |
31 | if (!argv.path) {
32 | console.error(colo.red('[agreed-ui]: --path option is required'))
33 | showHelp(1)
34 | }
35 |
36 | if (command === 'build' && !argv.dest) {
37 | console.error(colo.red('[agreed-ui]: --dest option is required'))
38 | showHelp(1)
39 | }
40 | const npm = /^win/.test(process.platform) ? 'npm.cmd' : 'npm'
41 |
42 | const child = spawn(
43 | npm,
44 | [
45 | 'run',
46 | command,
47 | '--',
48 | `--path=${path.resolve(process.cwd(), argv.path)}`,
49 | argv.dest && `--dest=${path.resolve(process.cwd(), argv.dest)}`,
50 | argv.port && `--port=${argv.port || 3000}`,
51 | ].filter(Boolean),
52 | { cwd: path.resolve(__dirname, '../') }
53 | )
54 |
55 | child.stdout.on('data', function(data) {
56 | process.stdout.write(data)
57 | })
58 |
59 | child.stderr.on('data', function(data) {
60 | process.stdout.write(data)
61 | })
62 |
--------------------------------------------------------------------------------
/build/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/recruit-tech/agreed-ui/b31b25034d87b0fd78020fd084d2aef17a69f66f/build/favicon.png
--------------------------------------------------------------------------------
/build/index.html:
--------------------------------------------------------------------------------
1 |
Agreed UI
--------------------------------------------------------------------------------
/build/precache-manifest.16323404084df425993dec323fbdcaed.js:
--------------------------------------------------------------------------------
1 | self.__precacheManifest = [
2 | {
3 | "revision": "4a686d48d5a089750c49",
4 | "url": "./static/js/runtime~main.4a686d48.js"
5 | },
6 | {
7 | "revision": "36d30304b2da2a12343c",
8 | "url": "./static/js/main.36d30304.chunk.js"
9 | },
10 | {
11 | "revision": "f784af42c4400c202237",
12 | "url": "./static/js/1.f784af42.chunk.js"
13 | },
14 | {
15 | "revision": "36d30304b2da2a12343c",
16 | "url": "./static/css/main.99e23d20.chunk.css"
17 | },
18 | {
19 | "revision": "2f8d889765d4f9d480eeab823350a5d8",
20 | "url": "./index.html"
21 | }
22 | ];
--------------------------------------------------------------------------------
/build/static/css/main.99e23d20.chunk.css:
--------------------------------------------------------------------------------
1 | @import url(https://fonts.googleapis.com/css?family=Open+Sans:400,400i|PT+Sans);:root{--color:#1a281f;--color-link:rgba(26,40,31,0.7);--color0:#fff;--color1:rgba(26,40,31,0.6);--color2:#635255;--color3:#ce7b91;--color4:#c0e8f9;--color5:#a4bfbd;--color-green:#66bb6a}*{margin:0;padding:0}a{color:rgba(26,40,31,.7);color:var(--color-link)}a:hover{color:#bbb}h1{font-size:1.5rem;margin:2rem 0}h2{font-size:1.2rem;margin:2rem 0 1rem}body{color:#1a281f;color:var(--color);font-family:-apple-system,BlinkMacSystemFont,Helvetica Neue,Segoe UI,sans-serif;min-height:100vh}.wrap,body{display:flex;flex-direction:column}.wrap{align-items:stretch;height:100vh}header{align-items:center;background:#fff;box-shadow:0 0 2.25rem #9da5ab;display:flex;font-family:PT Sans,sans-serif;justify-content:space-between;padding:20px;position:relative;z-index:1}header h1{margin:0}header p{font-weight:700}.container{align-items:stretch;display:flex;flex:1 1}main{flex-grow:3;order:2;padding:20px 0}aside,main{overflow:auto;position:relative}aside{box-shadow:0 0 .5rem #9da5ab;font-weight:300;flex:1 1;order:1;padding:20px;min-width:300px}.search{margin:1rem 0}.search__input{border:none;border-bottom:2px solid #ddd;font-size:1rem;font-weight:300;padding:.5rem 0;-webkit-transition:border-color .1s ease-out;transition:border-color .1s ease-out;width:80%}.search__input:focus{outline:0;display:block;border-bottom:2px solid var(--color5)}.search__group{display:block;font-size:.9rem;margin-top:5px}nav{position:absolute;padding-bottom:20px}nav p{margin:4px 0}details{padding-bottom:7px}summary{color:var(--color5);cursor:pointer;font-size:.9rem;margin-bottom:4px;outline:none}details>p{padding-left:1em;margin-top:3px}details summary::-webkit-details-marker{-webkit-transform:translateY(1px) scale(.7);transform:translateY(1px) scale(.7);opacity:.5}.count{border-radius:8px;border:1px solid var(--color5);background:var(--color5);margin-left:5px;opacity:.6;padding:0 3px;position:relative;top:-1px}.count,.statusLabel{color:var(--color0);display:inline-block;font-size:.5rem}.statusLabel{border-radius:6px;padding:2px 4px;margin-right:.25rem;opacity:.8}.statusLabel--2{background:var(--color-green)}.statusLabel--3{background:var(--color4)}.statusLabel--4{background:var(--color3)}.statusLabel--5{background:var(--color5)}.method{margin-right:5px;font-size:12px;font-weight:300;font-style:normal;border:1px solid #999;color:#999;border-radius:2px;padding:2px 3px;display:inline-block}.method.get{color:#66bb6a;border-color:#66bb6a}.method.delete{color:#999;border-color:#999}.method.put{color:#9e9d24;border-color:#9e9d24}.method.post{color:#f9a825;border-color:#f9a825}.method.patch{color:#9c27b0;border-color:#9c27b0}.definitions{color:var(--color1);margin:1.5em 0}.definitions h1{font-size:1em;color:var(--color5);margin-top:0;margin-bottom:1em;padding-left:0}.definitions>dl,.definitions>p{margin:.25em 1em}.definitions dl dt{color:var(--color3);font-weight:700;font-style:italic}.definitions dl dt:after{content:": "}.definitions dl>*{display:inline-block;margin-right:.5em}button{background-color:initial;border:none;cursor:pointer;outline:none;padding:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}.body{color:var(--color1);padding:0}.body>.buttonGroup{margin-bottom:1em;padding:0 30px}.body>.code{background:#efefef;font-weight:300;font-size:.9rem;max-height:500px;margin:1em 0;overflow:auto;padding:2em}.body>.code ul{background:#efefef!important}.buttonGroup button{margin-right:1em}.tabButton{box-sizing:border-box;color:var(--color5);opacity:.4;font-size:1rem;font-weight:700;padding:0 1px 3px}.tabButton:hover{opacity:1}.tabButton:disabled{color:var(--color5);cursor:auto;opacity:1;border-bottom:2px solid var(--color5)}.onlyButton.tabButton:disabled{border:none}.contents>.agree{padding-top:2rem;margin-bottom:2rem}.contents>.agree:first-child{padding-top:0}.agree .definitions,.agree .description,.agree>h1,.agree>h2,.agree>section{padding:0 30px}.agree h2{color:var(--color);border-left:2px solid #aaa;padding-left:28px}.title{align-items:center;border-left:2px solid var(--color);display:flex;font-family:Open Sans,sans-serif;font-style:italic;margin:0}.title>*{margin-right:.6rem}.description{color:var(--color1);margin:.25rem 0}.contents section h2{color:var(--color);border-left:2px solid #aaa;padding-left:28px}.contents{position:absolute;width:100%}
2 | /*# sourceMappingURL=main.99e23d20.chunk.css.map */
--------------------------------------------------------------------------------
/build/static/css/main.99e23d20.chunk.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["main.99e23d20.chunk.css","/Users/01017830/Projects/agreed-ui/src/index.css","/Users/01017830/Projects/agreed-ui/src/components/App/styles.css","/Users/01017830/Projects/agreed-ui/src/components/Navigation/styles.css","/Users/01017830/Projects/agreed-ui/src/components/MethodLabel/styles.css","/Users/01017830/Projects/agreed-ui/src/components/Definitions/styles.css","/Users/01017830/Projects/agreed-ui/src/components/Body/styles.css","/Users/01017830/Projects/agreed-ui/src/components/Agree/styles.css","/Users/01017830/Projects/agreed-ui/src/components/Agrees/styles.css"],"names":[],"mappings":"AAAA,gFAAgF,ACGhF,MACE,gBAA6B,AAC7B,gCAAoC,AACpC,cAAgB,AAChB,4BAAgC,AAChC,iBAA8B,AAC9B,iBAAiC,AACjC,iBAAiC,AACjC,iBAAiC,AACjC,qBAAuB,CACxB,AAED,EACE,SAAU,AACV,SAAW,CACZ,AAED,EACE,wBAAyB,AAAzB,uBAAyB,CAC1B,AAED,QACE,UAAY,CACb,AAED,GACE,iBAAkB,AAClB,aAAe,CAChB,AAED,GACE,iBAAkB,AAClB,kBAAoB,CACrB,AAED,KACE,cAAoB,AAApB,mBAAoB,AAEpB,gFAAyF,AAEzF,gBAAkB,CACnB,AC5CD,WDwCE,aAAc,AAEd,qBAAuB,CCrCxB,AALD,MACE,oBAAqB,AAGrB,YAAc,CACf,AAED,OACE,mBAAoB,AACpB,gBAAkB,AAClB,+BAAgC,AAChC,aAAc,AACd,+BAAmC,AACnC,8BAA+B,AAC/B,aAAc,AACd,kBAAmB,AACnB,SAAW,CACZ,AAED,UACE,QAAU,CACX,AAED,SACE,eAAkB,CACnB,AAED,WACE,oBAAqB,AACrB,aAAc,AACd,QAAQ,CACT,AAED,KACE,YAAa,AACb,QAAS,AACT,cAAgB,CAGjB,AAED,WAJE,cAAe,AACf,iBAAmB,CAYpB,AATD,MACE,6BAA+B,AAC/B,gBAAiB,AACjB,SAAQ,AACR,QAAS,AAET,aAAc,AAEd,eAAiB,CAClB,AAED,QACE,aAAe,CAChB,AAED,eAEE,YAA8B,AAA9B,6BAA8B,AAC9B,eAAgB,AAChB,gBAAiB,AACjB,gBAAkB,AAClB,6CAAuC,AAAvC,qCAAuC,AACvC,SAAW,CACZ,AAED,qBACE,UAAW,AACX,cAAe,AACf,qCAAuC,CACxC,AAED,eACE,cAAe,AACf,gBAAkB,AAClB,cAAgB,CACjB,AC5ED,IACE,kBAAmB,AACnB,mBAAqB,CACtB,AAED,MACE,YAAc,CACf,AAED,QACE,kBAAoB,CACrB,AAED,QACE,oBAAqB,AACrB,eAAgB,AAChB,gBAAkB,AAClB,kBAAmB,AACnB,YAAc,CACf,AAED,UACE,iBAAkB,AAClB,cAAgB,CACjB,AAED,wCACE,4CAAwC,AAAxC,oCAAwC,AACxC,UAAa,CACd,AAED,OACE,kBAAmB,AACnB,+BAAgC,AAChC,yBAA0B,AAI1B,gBAAiB,AACjB,WAAa,AACb,cAAiB,AACjB,kBAAmB,AACnB,QAAU,CACX,AAED,oBAVE,oBAAqB,AACrB,qBAAsB,AACtB,eAAkB,CAgBnB,AARD,aACE,kBAAmB,AAInB,gBAAiB,AACjB,oBAAsB,AACtB,UAAa,CACd,AAED,gBACE,6BAA+B,CAChC,AAED,gBACE,wBAA0B,CAC3B,AAED,gBACE,wBAA0B,CAC3B,AAED,gBACE,wBAA0B,CAC3B,ACrED,QACE,iBAAkB,AAClB,eAAgB,AAChB,gBAAiB,AACjB,kBAAmB,AACnB,sBAAuB,AACvB,WAAY,AACZ,kBAAmB,AACnB,gBAAiB,AACjB,oBAAsB,CACvB,AACD,YACE,cAAe,AACf,oBAAsB,CACvB,AACD,eACE,WAAY,AACZ,iBAAmB,CACpB,AACD,YACE,cAAe,AACf,oBAAsB,CACvB,AACD,aACE,cAAe,AACf,oBAAsB,CACvB,AACD,cACE,cAAe,AACf,oBAAsB,CACvB,AC9BD,aACE,oBAAqB,AACrB,cAAgB,CACjB,AAED,gBACE,cAAe,AACf,oBAAqB,AACrB,aAAc,AACd,kBAAmB,AACnB,cAAgB,CACjB,AAED,+BAEE,gBAAmB,CACpB,AAED,mBACE,oBAAqB,AACrB,gBAAkB,AAClB,iBAAmB,CACpB,AAED,yBACE,YAAc,CACf,AAED,kBACE,qBAAsB,AACtB,iBAAoB,CACrB,AC/BD,OACE,yBAA8B,AAC9B,YAAa,AACb,eAAgB,AAChB,aAAc,AACd,UAAW,AACX,wBAAiB,AAAjB,qBAAiB,AAAjB,eAAiB,CAClB,AAED,MACE,oBAAqB,AACrB,SAAW,CACZ,AAED,mBACE,kBAAmB,AACnB,cAAgB,CACjB,AAED,YACE,mBAAoB,AACpB,gBAAiB,AACjB,gBAAkB,AAClB,iBAAkB,AAClB,aAAc,AACd,cAAe,AACf,WAAiB,CAClB,AAED,eACE,4BAA+B,CAChC,AAED,oBACE,gBAAkB,CACnB,AAED,WACE,sBAAuB,AACvB,oBAAqB,AACrB,WAAa,AACb,eAAgB,AAChB,gBAAkB,AAClB,iBAAmB,CACpB,AAED,iBACE,SAAW,CACZ,AAED,oBACE,oBAAqB,AACrB,YAAgB,AAChB,UAAW,AACX,qCAAuC,CACxC,AAED,+BACE,WAAa,CACd,AC3DD,iBACE,iBAAkB,AAClB,kBAAoB,CACrB,AAED,6BACE,aAAe,CAChB,AAED,2EAKE,cAAgB,CACjB,AAED,UACE,mBAAoB,AACpB,2BAA4B,AAC5B,iBAAmB,CACpB,AAED,OACE,mBAAoB,AACpB,mCAAoC,AACpC,aAAc,AACd,iCAAqC,AACrC,kBAAmB,AACnB,QAAgB,CACjB,AAED,SACE,kBAAqB,CACtB,AAED,aACE,oBAAqB,AACrB,eAAkB,CACnB,ACvCD,qBACE,mBAAoB,AACpB,2BAA4B,AAC5B,iBAAmB,CACpB,AAED,UACE,kBAAmB,AACnB,UAAY,CACb","file":"main.99e23d20.chunk.css","sourcesContent":["@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,400i|PT+Sans);\n/* RGB */\n:root {\n --color: rgba(26, 40, 31, 1);\n --color-link: rgba(26, 40, 31, 0.7);\n --color0: white;\n --color1: rgba(26, 40, 31, 0.6);\n --color2: rgba(99, 82, 85, 1);\n --color3: rgba(206, 123, 145, 1);\n --color4: rgba(192, 232, 249, 1);\n --color5: rgba(164, 191, 189, 1);\n --color-green: #66BB6A;\n}\n\n* {\n margin: 0;\n padding: 0;\n}\n\na {\n color: rgba(26, 40, 31, 0.7);\n color: var(--color-link);\n}\n\na:hover {\n color: #bbb;\n}\n\nh1 {\n font-size: 1.5rem;\n margin: 2rem 0;\n}\n\nh2 {\n font-size: 1.2rem;\n margin: 2rem 0 1rem;\n}\n\nbody {\n color: rgba(26, 40, 31, 1);\n color: var(--color);\n display: flex;\n font-family: -apple-system, BlinkMacSystemFont, \"Helvetica Neue\", \"Segoe UI\", sans-serif;\n flex-direction: column;\n min-height: 100vh;\n}\n\n\n.wrap {\n align-items: stretch;\n display: flex;\n flex-direction: column;\n height: 100vh;\n}\n\nheader {\n align-items: center;\n background: white;\n box-shadow: 0 0 2.25rem #9da5ab;\n display: flex;\n font-family: 'PT Sans', sans-serif;\n justify-content: space-between;\n padding: 20px;\n position: relative;\n z-index: 1;\n}\n\nheader h1 {\n margin: 0;\n}\n\nheader p {\n font-weight: bold;\n}\n\n.container {\n align-items: stretch;\n display: flex;\n flex: 1 1;\n}\n\nmain {\n flex-grow: 3;\n order: 2;\n padding: 20px 0;\n overflow: auto;\n position: relative;\n}\n\naside {\n box-shadow: 0 0 0.5rem #9da5ab;\n font-weight: 300;\n flex: 1 1;\n order: 1;\n overflow: auto;\n padding: 20px;\n position: relative;\n min-width: 300px;\n}\n\n.search {\n margin: 1rem 0;\n}\n\n.search__input {\n border: none;\n border-bottom: 2px solid #ddd;\n font-size: 1rem;\n font-weight: 300;\n padding: 0.5rem 0;\n -webkit-transition: border-color 0.1s ease-out;\n transition: border-color 0.1s ease-out;\n width: 80%;\n}\n\n.search__input:focus {\n outline: 0;\n display: block;\n border-bottom: 2px solid var(--color5);\n}\n\n.search__group {\n display: block;\n font-size: 0.9rem;\n margin-top: 5px;\n}\n\n\n\nnav {\n position: absolute;\n padding-bottom: 20px;\n}\n\nnav p {\n margin: 4px 0;\n}\n\ndetails {\n padding-bottom: 7px;\n}\n\nsummary {\n color: var(--color5);\n cursor: pointer;\n font-size: 0.9rem;\n margin-bottom: 4px;\n outline: none;\n}\n\ndetails > p {\n padding-left: 1em;\n margin-top: 3px;\n}\n\ndetails summary::-webkit-details-marker {\n -webkit-transform: translate(0, 1px) scale(0.7);\n transform: translate(0, 1px) scale(0.7);\n opacity: 0.5;\n}\n\n.count {\n border-radius: 8px;\n border: 1px solid var(--color5);\n background: var(--color5);\n color: var(--color0);\n display: inline-block;\n font-size: 0.5rem;\n margin-left: 5px;\n opacity: 0.6;\n padding: 0px 3px;\n position: relative;\n top: -1px;\n}\n\n.statusLabel {\n border-radius: 6px;\n color: var(--color0);\n display: inline-block;\n font-size: 0.5rem;\n padding: 2px 4px;\n margin-right: 0.25rem;\n opacity: 0.8;\n}\n\n.statusLabel--2 {\n background: var(--color-green);\n}\n\n.statusLabel--3 {\n background: var(--color4);\n}\n\n.statusLabel--4 {\n background: var(--color3);\n}\n\n.statusLabel--5 {\n background: var(--color5);\n}\n\n\n.method {\n margin-right: 5px;\n font-size: 12px;\n font-weight: 300;\n font-style: normal;\n border: 1px solid #999;\n color: #999;\n border-radius: 2px;\n padding: 2px 3px;\n display: inline-block;\n}\n.method.get {\n color: #66BB6A;\n border-color: #66BB6A;\n}\n.method.delete {\n color: #999;\n border-color: #999;\n}\n.method.put { \n color: #9E9D24;\n border-color: #9E9D24;\n}\n.method.post {\n color: #F9A825;\n border-color: #F9A825;\n}\n.method.patch {\n color: #9C27B0;\n border-color: #9C27B0;\n}\n\n.definitions {\n color: var(--color1);\n margin: 1.5em 0;\n}\n\n.definitions h1 {\n font-size: 1em;\n color: var(--color5);\n margin-top: 0;\n margin-bottom: 1em;\n padding-left: 0;\n}\n\n.definitions > p,\n.definitions > dl {\n margin: 0.25em 1em;\n}\n\n.definitions dl dt {\n color: var(--color3);\n font-weight: bold;\n font-style: italic;\n}\n\n.definitions dl dt:after {\n content: ': ';\n}\n\n.definitions dl > * {\n display: inline-block;\n margin-right: 0.5em;\n}\n\nbutton {\n background-color: transparent;\n border: none;\n cursor: pointer;\n outline: none;\n padding: 0;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n\n.body {\n color: var(--color1);\n padding: 0;\n}\n\n.body > .buttonGroup {\n margin-bottom: 1em;\n padding: 0 30px;\n}\n\n.body > .code {\n background: #efefef;\n font-weight: 300;\n font-size: 0.9rem;\n max-height: 500px;\n margin: 1em 0;\n overflow: auto;\n padding: 2em 2em;\n}\n\n.body > .code ul {\n background: #efefef !important;\n}\n\n.buttonGroup button {\n margin-right: 1em;\n}\n\n.tabButton {\n box-sizing: border-box;\n color: var(--color5);\n opacity: 0.4;\n font-size: 1rem;\n font-weight: bold;\n padding: 0 1px 3px;\n}\n\n.tabButton:hover {\n opacity: 1;\n}\n\n.tabButton:disabled {\n color: var(--color5);\n cursor: auto;\n cursor: initial;\n opacity: 1;\n border-bottom: 2px solid var(--color5);\n}\n\n.onlyButton.tabButton:disabled {\n border: none;\n}\n\n.contents > .agree {\n padding-top: 2rem;\n margin-bottom: 2rem;\n}\n\n.contents > .agree:first-child {\n padding-top: 0;\n}\n\n.agree > h1,\n.agree > h2,\n.agree > section,\n.agree .description,\n.agree .definitions {\n padding: 0 30px;\n}\n\n.agree h2 {\n color: var(--color);\n border-left: 2px #aaa solid;\n padding-left: 28px;\n}\n\n.title {\n align-items: center;\n border-left: 2px var(--color) solid;\n display: flex;\n font-family: 'Open Sans', sans-serif;\n font-style: italic;\n margin: 0 0 0 0;\n}\n\n.title > * {\n margin-right: 0.6rem;\n}\n\n.description {\n color: var(--color1);\n margin: 0.25rem 0;\n}\n\n\n.contents section h2 {\n color: var(--color);\n border-left: 2px #aaa solid;\n padding-left: 28px;\n}\n\n.contents {\n position: absolute;\n width: 100%;\n}\n\n\n\n","@import url('https://fonts.googleapis.com/css?family=Open+Sans:400,400i|PT+Sans');\n\n/* RGB */\n:root {\n --color: rgba(26, 40, 31, 1);\n --color-link: rgba(26, 40, 31, 0.7);\n --color0: white;\n --color1: rgba(26, 40, 31, 0.6);\n --color2: rgba(99, 82, 85, 1);\n --color3: rgba(206, 123, 145, 1);\n --color4: rgba(192, 232, 249, 1);\n --color5: rgba(164, 191, 189, 1);\n --color-green: #66BB6A;\n}\n\n* {\n margin: 0;\n padding: 0;\n}\n\na {\n color: var(--color-link);\n}\n\na:hover {\n color: #bbb;\n}\n\nh1 {\n font-size: 1.5rem;\n margin: 2rem 0;\n}\n\nh2 {\n font-size: 1.2rem;\n margin: 2rem 0 1rem;\n}\n\nbody {\n color: var(--color);\n display: flex;\n font-family: -apple-system, BlinkMacSystemFont, \"Helvetica Neue\", \"Segoe UI\", sans-serif;\n flex-direction: column;\n min-height: 100vh;\n}\n\n",".wrap {\n align-items: stretch;\n display: flex;\n flex-direction: column;\n height: 100vh;\n}\n\nheader {\n align-items: center;\n background: white;\n box-shadow: 0 0 2.25rem #9da5ab;\n display: flex;\n font-family: 'PT Sans', sans-serif;\n justify-content: space-between;\n padding: 20px;\n position: relative;\n z-index: 1;\n}\n\nheader h1 {\n margin: 0;\n}\n\nheader p {\n font-weight: bold;\n}\n\n.container {\n align-items: stretch;\n display: flex;\n flex: 1;\n}\n\nmain {\n flex-grow: 3;\n order: 2;\n padding: 20px 0;\n overflow: auto;\n position: relative;\n}\n\naside {\n box-shadow: 0 0 0.5rem #9da5ab;\n font-weight: 300;\n flex: 1;\n order: 1;\n overflow: auto;\n padding: 20px;\n position: relative;\n min-width: 300px;\n}\n\n.search {\n margin: 1rem 0;\n}\n\n.search__input {\n border: none;\n border-bottom: 2px solid #ddd;\n font-size: 1rem;\n font-weight: 300;\n padding: 0.5rem 0;\n transition: border-color 0.1s ease-out;\n width: 80%;\n}\n\n.search__input:focus {\n outline: 0;\n display: block;\n border-bottom: 2px solid var(--color5);\n}\n\n.search__group {\n display: block;\n font-size: 0.9rem;\n margin-top: 5px;\n}\n\n\n","nav {\n position: absolute;\n padding-bottom: 20px;\n}\n\nnav p {\n margin: 4px 0;\n}\n\ndetails {\n padding-bottom: 7px;\n}\n\nsummary {\n color: var(--color5);\n cursor: pointer;\n font-size: 0.9rem;\n margin-bottom: 4px;\n outline: none;\n}\n\ndetails > p {\n padding-left: 1em;\n margin-top: 3px;\n}\n\ndetails summary::-webkit-details-marker {\n transform: translate(0, 1px) scale(0.7);\n opacity: 0.5;\n}\n\n.count {\n border-radius: 8px;\n border: 1px solid var(--color5);\n background: var(--color5);\n color: var(--color0);\n display: inline-block;\n font-size: 0.5rem;\n margin-left: 5px;\n opacity: 0.6;\n padding: 0px 3px;\n position: relative;\n top: -1px;\n}\n\n.statusLabel {\n border-radius: 6px;\n color: var(--color0);\n display: inline-block;\n font-size: 0.5rem;\n padding: 2px 4px;\n margin-right: 0.25rem;\n opacity: 0.8;\n}\n\n.statusLabel--2 {\n background: var(--color-green);\n}\n\n.statusLabel--3 {\n background: var(--color4);\n}\n\n.statusLabel--4 {\n background: var(--color3);\n}\n\n.statusLabel--5 {\n background: var(--color5);\n}\n\n",".method {\n margin-right: 5px;\n font-size: 12px;\n font-weight: 300;\n font-style: normal;\n border: 1px solid #999;\n color: #999;\n border-radius: 2px;\n padding: 2px 3px;\n display: inline-block;\n}\n.method.get {\n color: #66BB6A;\n border-color: #66BB6A;\n}\n.method.delete {\n color: #999;\n border-color: #999;\n}\n.method.put { \n color: #9E9D24;\n border-color: #9E9D24;\n}\n.method.post {\n color: #F9A825;\n border-color: #F9A825;\n}\n.method.patch {\n color: #9C27B0;\n border-color: #9C27B0;\n}\n",".definitions {\n color: var(--color1);\n margin: 1.5em 0;\n}\n\n.definitions h1 {\n font-size: 1em;\n color: var(--color5);\n margin-top: 0;\n margin-bottom: 1em;\n padding-left: 0;\n}\n\n.definitions > p,\n.definitions > dl {\n margin: 0.25em 1em;\n}\n\n.definitions dl dt {\n color: var(--color3);\n font-weight: bold;\n font-style: italic;\n}\n\n.definitions dl dt:after {\n content: ': ';\n}\n\n.definitions dl > * {\n display: inline-block;\n margin-right: 0.5em;\n}\n","button {\n background-color: transparent;\n border: none;\n cursor: pointer;\n outline: none;\n padding: 0;\n appearance: none;\n}\n\n.body {\n color: var(--color1);\n padding: 0;\n}\n\n.body > .buttonGroup {\n margin-bottom: 1em;\n padding: 0 30px;\n}\n\n.body > .code {\n background: #efefef;\n font-weight: 300;\n font-size: 0.9rem;\n max-height: 500px;\n margin: 1em 0;\n overflow: auto;\n padding: 2em 2em;\n}\n\n.body > .code ul {\n background: #efefef !important;\n}\n\n.buttonGroup button {\n margin-right: 1em;\n}\n\n.tabButton {\n box-sizing: border-box;\n color: var(--color5);\n opacity: 0.4;\n font-size: 1rem;\n font-weight: bold;\n padding: 0 1px 3px;\n}\n\n.tabButton:hover {\n opacity: 1;\n}\n\n.tabButton:disabled {\n color: var(--color5);\n cursor: initial;\n opacity: 1;\n border-bottom: 2px solid var(--color5);\n}\n\n.onlyButton.tabButton:disabled {\n border: none;\n}\n",".contents > .agree {\n padding-top: 2rem;\n margin-bottom: 2rem;\n}\n\n.contents > .agree:first-child {\n padding-top: 0;\n}\n\n.agree > h1,\n.agree > h2,\n.agree > section,\n.agree .description,\n.agree .definitions {\n padding: 0 30px;\n}\n\n.agree h2 {\n color: var(--color);\n border-left: 2px #aaa solid;\n padding-left: 28px;\n}\n\n.title {\n align-items: center;\n border-left: 2px var(--color) solid;\n display: flex;\n font-family: 'Open Sans', sans-serif;\n font-style: italic;\n margin: 0 0 0 0;\n}\n\n.title > * {\n margin-right: 0.6rem;\n}\n\n.description {\n color: var(--color1);\n margin: 0.25rem 0;\n}\n\n",".contents section h2 {\n color: var(--color);\n border-left: 2px #aaa solid;\n padding-left: 28px;\n}\n\n.contents {\n position: absolute;\n width: 100%;\n}\n\n\n"]}
--------------------------------------------------------------------------------
/build/static/js/main.36d30304.chunk.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[0],{111:function(e,t,a){},113:function(e,t,a){},115:function(e,t,a){},117:function(e,t,a){},225:function(e,t,a){},227:function(e,t,a){},229:function(e,t,a){},231:function(e,t,a){"use strict";a.r(t);var n=a(0),r=a.n(n),c=a(79),l=a.n(c),s=(a(89),a(24)),o=a(25),u=a(27),i=a(26),m=a(28),d=a(83),h=a(80),p=a.n(h),E=(a(111),a(19)),f=a(82);a(113),a(115);var g=function(e){var t=e.method.toLowerCase();return r.a.createElement("span",{className:"method ".concat(t)},t.toUpperCase())},v=function(e){var t=e.status;return r.a.createElement("span",{className:"statusLabel statusLabel--".concat(Math.floor(t/100))},t)},b=function(e){var t=e.agree;return r.a.createElement("p",null,r.a.createElement("a",{href:"#".concat(t.id)},r.a.createElement(g,{method:t.request.method}),r.a.createElement("span",null,t.title||t.request.path)))},y=function(e){var t=e.agree;return r.a.createElement("p",null,r.a.createElement("a",{href:"#".concat(t.id)},r.a.createElement(v,{status:t.response.status}),r.a.createElement("span",null,t.title||"no title")))},k=function(e){var t=e.path,a=e.agrees,n=t.split("_"),c=Object(E.a)(n,2),l=c[0],s=c[1];return r.a.createElement("details",{open:!0},r.a.createElement("summary",null,r.a.createElement(g,{method:s}),r.a.createElement("span",null,l),a.length>1&&r.a.createElement("span",{className:"count"},a.length)),a.map(function(e,t){return r.a.createElement(y,{key:e.id,agree:e})}))},N=function(e){var t=function(e){for(var t={},a=0,n=e.length;a0&&void 0!==arguments[0]?arguments[0]:this.props,a=t.formatted,n=t.schema,c=t.flowtype,l=this.state.selected;return r.a.createElement("section",{className:"body"},r.a.createElement("div",{className:"buttonGroup"},r.a.createElement("button",{className:q()("tabButton",{onlyButton:!n}),onClick:function(){return e.onClick("body")},disabled:"body"===l},"body"),n&&r.a.createElement("button",{className:"tabButton",onClick:function(){return e.onClick("schema")},disabled:"schema"===l},"schema"),c&&r.a.createElement("button",{className:"tabButton",onClick:function(){return e.onClick("flowtype")},disabled:"flowtype"===l},"flowtype")),"schema"===l&&r.a.createElement("div",{className:"code"},r.a.createElement(C.a,{data:n,shouldExpandNode:function(e,t,a){return a<2}})),"flowtype"===l&&r.a.createElement("pre",{className:"code"},c),"body"===l&&r.a.createElement("div",{className:"code"},a instanceof Object?r.a.createElement(C.a,{data:a,shouldExpandNode:function(e,t,a){return a<2}}):a))}}]),t}(n.Component)),_=function(e){var t=e.data,a=t.method,n=t.path,c=t.headers_formatted,l=t.query,s=t.formatted,o=t.schema;return r.a.createElement("div",null,r.a.createElement(w,{title:"method",description:a.toUpperCase()}),r.a.createElement(w,{title:"path",description:n}),l&&!!Object.keys(l).length&&r.a.createElement(w,{title:"query"},Object.entries(l).map(function(e){var t=Object(E.a)(e,2),a=t[0],n=t[1];return r.a.createElement("dl",{key:a},r.a.createElement("dt",null,a),r.a.createElement("dd",null,JSON.stringify(n)))})),c&&!!Object.keys(c).length&&r.a.createElement(w,{title:"headers"},Object.entries(c).map(function(e){var t=Object(E.a)(e,2),a=t[0],n=t[1];return r.a.createElement("dl",{key:a},r.a.createElement("dt",null,a),r.a.createElement("dd",null,JSON.stringify(n)))})),s&&r.a.createElement(T,{formatted:s,schema:o}))},x=function(e){var t=e.data,a=t.status,n=t.formatted,c=t.schema,l=t.flowtype;return r.a.createElement("div",null,r.a.createElement(w,{title:"statusCode",description:"".concat(a)}),n&&r.a.createElement(T,{formatted:n,schema:c,flowtype:l}))},F=(a(227),function(e){var t=e.agree,a=t.request.path,n=t.response.status;return r.a.createElement("section",{className:"agree",id:t.id},r.a.createElement("h1",{className:"title"},r.a.createElement(g,{method:t.request.method,status:n}),t.title||a),r.a.createElement("div",{className:"description"},t.description||"no description."),r.a.createElement("h2",null,"Request"),r.a.createElement(_,{data:t.request}),r.a.createElement("h2",null,"Response"),r.a.createElement(x,{data:t.response}))});a(229);var I=function(e){var t=e.agrees;return r.a.createElement("div",{className:"contents"},t.map(function(e){return r.a.createElement(F,{key:e.id,agree:e})}))},A=function(e){return function(t){return t&&t.indexOf(e)>-1}},B=function(e){return e.map(function(e,t){return Object(d.a)({},e,{id:"agree_".concat(t)})})},L=function(e){function t(e){var a;return Object(s.a)(this,t),(a=Object(u.a)(this,Object(i.a)(t).call(this,e))).defaultTitle="Agreed UI",a.state={agrees:null,search:"",grouped:!1,agreesFiltered:null,title:""},a}return Object(m.a)(t,e),Object(o.a)(t,[{key:"componentDidMount",value:function(){var e=this,t='"<%= title %>"'===window.TITLE?"":window.TITLE||"",a="true"===localStorage.getItem("grouped")||this.state.grouped;if(t&&(document.title=t),Array.isArray(window.AGREES))return this.setState({title:t,grouped:a,agrees:B(window.AGREES)});p.a.get("agrees").then(function(n){var r=n.data;return e.setState({title:t,grouped:a,agrees:B(r)})})}},{key:"onSearchTextChange",value:function(e){this.setState({search:e,agreesFiltered:function(e,t){if(!e)return null;var a=A(e);return t.filter(function(e){return a(e.title)||a(e.request.path)||a(e.request.method)})}(e,this.state.agrees)})}},{key:"onFilterChange",value:function(e){localStorage.setItem("grouped",e),this.setState({grouped:e})}},{key:"render",value:function(){var e=this,t=this.state,a=t.agrees,n=t.agreesFiltered,c=t.title,l=t.search,s=t.grouped;return a?r.a.createElement("div",{className:"wrap"},r.a.createElement("header",null,r.a.createElement("h1",null,c||this.defaultTitle),c&&r.a.createElement("p",null,this.defaultTitle)),r.a.createElement("div",{className:"container"},r.a.createElement("main",null,r.a.createElement(I,{agrees:n||a})),r.a.createElement("aside",null,r.a.createElement("p",null,"Navigations"),r.a.createElement("section",{className:"search"},r.a.createElement("input",{type:"search",className:"search__input",placeholder:"Search",value:l,onChange:function(t){return e.onSearchTextChange(t.target.value)}}),r.a.createElement("span",{className:"search__group"},r.a.createElement("label",null,r.a.createElement("input",{type:"checkbox",checked:s,onChange:function(t){return e.onFilterChange(t.target.checked)}}),"\xa0group by request.path"))),r.a.createElement(O,{grouped:s,agrees:n||a})))):null}}]),t}(n.Component);l.a.render(r.a.createElement(L,null),document.getElementById("root"))},84:function(e,t,a){e.exports=a(231)},89:function(e,t,a){}},[[84,2,1]]]);
2 | //# sourceMappingURL=main.36d30304.chunk.js.map
--------------------------------------------------------------------------------
/build/static/js/main.36d30304.chunk.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["components/MethodLabel/index.js","components/Navigation/index.js","components/Definitions/index.js","components/Body/index.js","components/Request/index.js","components/Response/index.js","components/Agree/index.js","components/Agrees/index.js","components/App/index.js","index.js"],"names":["MethodLabel","_ref","m","method","toLowerCase","react_default","a","createElement","className","concat","toUpperCase","StatusLabel","status","Math","floor","NaviItem","_ref2","agree","href","id","components_MethodLabel","request","title","path","GroupedItem","_ref3","Navigation_StatusLabel","response","Details","_ref4","agrees","_path$split","split","_path$split2","Object","slicedToArray","name","open","length","map","i","Navigation_GroupedItem","key","Grouped","_ref5","grouped","list","ret","len","item","toConsumableArray","groupByRequestPath","pathList","keys","Fragment","Navigation_Details","Navigation","_ref6","Navigation_Grouped","Navigation_NaviItem","Definitions","description","children","Body","props","_this","classCallCheck","this","possibleConstructorReturn","getPrototypeOf","call","state","selected","setState","_this2","arguments","undefined","formatted","schema","flowtype","classNames","onlyButton","onClick","disabled","lib_default","data","shouldExpandNode","keyName","level","Component","Request","headers","headers_formatted","query","components_Definitions","entries","k","v","JSON","stringify","components_Body","Response","Agree","components_Request","components_Response","Agrees","components_Agree","shoudDisplay","search","value","indexOf","insertId","objectSpread","App","defaultTitle","agreesFiltered","window","TITLE","localStorage","getItem","document","Array","isArray","AGREES","axios","get","then","check","filter","filterAgrees","setItem","_this3","_this$state","components_Agrees","type","placeholder","onChange","e","onSearchTextChange","target","checked","onFilterChange","components_Navigation","ReactDOM","render","components_App","getElementById"],"mappings":"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","file":"static/js/main.36d30304.chunk.js","sourcesContent":["import React from 'react'\nimport PropTypes from 'prop-types'\nimport './styles.css'\n\nfunction MethodLabel({ method }) {\n const m = method.toLowerCase()\n return {m.toUpperCase()}\n}\n\nMethodLabel.propTypes = {\n method: PropTypes.string.isRequired,\n}\n\nexport default MethodLabel\n","import React from 'react'\nimport PropTypes from 'prop-types'\nimport './styles.css'\nimport MethodLabel from '../MethodLabel'\n\nconst groupByRequestPath = (list) => {\n const ret = {}\n for(let i = 0, len = list.length; i < len; i++) {\n const item = list[i]\n const key = `${item.request.path}_${item.request.method}`\n ret[key] = [...(ret[key] || []), item]\n }\n return ret\n}\n\nconst StatusLabel = ({status}) => (\n {status}\n)\n\nStatusLabel.propTypes = {\n status: PropTypes.number.isRequired,\n}\n\nconst NaviItem = ({ agree }) => (\n \n \n \n {agree.title || agree.request.path}\n \n
\n)\n\nNaviItem.propTypes = {\n agree: PropTypes.object.isRequired,\n}\n\nconst GroupedItem = ({ agree }) => (\n \n \n \n {agree.title || 'no title'}\n \n
\n)\n\nGroupedItem.propTypes = {\n agree: PropTypes.object.isRequired,\n}\n\nconst Details = ({path, agrees}) => { \n const [name, method] = path.split('_')\n return (\n \n \n \n {name}\n { agrees.length > 1 && {agrees.length}}\n
\n {agrees.map((agree, i) =>\n \n )}\n \n )\n}\n\nDetails.propTypes = {\n path: PropTypes.string.isRequired,\n agrees: PropTypes.array.isRequired,\n}\n\nconst Grouped = ({agrees}) => {\n const grouped = groupByRequestPath(agrees)\n const pathList = Object.keys(grouped)\n return (\n \n {pathList.map((path, i) => )}\n \n )\n}\n\nGrouped.propTypes = {\n agrees: PropTypes.array.isRequired,\n}\n\nfunction Navigation({ agrees, grouped }) {\n return (\n \n )\n}\n\nNavigation.propTypes = {\n agrees: PropTypes.array.isRequired,\n grouped: PropTypes.bool.isRequired,\n}\n\nexport default Navigation\n","import React from 'react'\nimport PropTypes from 'prop-types'\nimport './styles.css'\n\nconst Definitions = ({ title, description, children }) => {\n return (\n \n {title}
\n {description && {description}
}\n {children}\n \n )\n}\n\nDefinitions.propTypes = {\n title: PropTypes.string.isRequired,\n description: PropTypes.string,\n children: PropTypes.any,\n}\n\nexport default Definitions\n","import React, { Component } from 'react'\nimport PropTypes from 'prop-types'\nimport JSONTree from 'react-json-tree'\nimport classNames from 'classnames'\nimport './styles.css'\n\nclass Body extends Component {\n constructor(props) {\n super(props)\n this.state = { selected: 'body' }\n }\n\n onClick(selected) {\n this.setState({ selected })\n }\n\n render({ formatted, schema, flowtype } = this.props) {\n const { selected } = this.state\n return (\n \n \n \n {schema && (\n \n )}\n {flowtype && (\n \n )}\n
\n {selected === 'schema' && (\n \n level < 2}\n />\n
\n )}\n {selected === 'flowtype' && {flowtype}
}\n {selected === 'body' && (\n\n \n {(formatted instanceof Object)\n ? level < 2}\n />\n : formatted\n }\n
\n )}\n \n )\n }\n}\n\nBody.propTypes = {\n formatted: PropTypes.any.isRequired,\n schema: PropTypes.object,\n flowtype: PropTypes.any,\n}\n\nexport default Body\n","import React from 'react'\nimport PropTypes from 'prop-types'\nimport Definitions from '../Definitions'\nimport Body from '../Body'\n\nconst Request = ({ data }) => {\n const { method, path, headers_formatted: headers, query, formatted, schema } = data\n return (\n \n
\n
\n {query && !!Object.keys(query).length && (\n
\n {Object.entries(query).map(([k, v]) => (\n \n - {k}
\n - {JSON.stringify(v)}
\n
\n ))}\n \n )}\n {headers && !!Object.keys(headers).length && (\n
\n {Object.entries(headers).map(([k, v]) => (\n \n - {k}
\n - {JSON.stringify(v)}
\n
\n ))}\n \n )}\n {formatted &&
}\n \n )\n}\n\nRequest.propTypes = {\n data: PropTypes.object.isRequired,\n}\n\nexport default Request\n","import React from 'react'\nimport PropTypes from 'prop-types'\nimport Definitions from '../Definitions'\nimport Body from '../Body'\n\nconst Response = ({ data }) => {\n const { status, formatted, schema, flowtype } = data\n return (\n \n \n {formatted && (\n
\n )}\n \n )\n}\n\nResponse.propTypes = {\n data: PropTypes.object.isRequired,\n}\n\nexport default Response\n","import React from 'react'\nimport PropTypes from 'prop-types'\nimport Request from '../Request'\nimport Response from '../Response'\nimport MethodLabel from '../MethodLabel'\nimport './styles.css'\n\nconst Agree = ({ agree }) => {\n const path = agree.request.path\n const status = agree.response.status\n return (\n \n \n \n {agree.title || path}\n
\n \n {agree.description || 'no description.'}\n
\n\n Request
\n \n Response
\n \n \n )\n}\n\nAgree.propTypes = {\n agree: PropTypes.object.isRequired,\n}\n\nexport default Agree\n","import React from 'react'\nimport PropTypes from 'prop-types'\nimport Agree from '../Agree'\nimport './styles.css'\n\nfunction Agrees({ agrees }) {\n return (\n \n {agrees.map((agree) =>
)}\n
\n )\n}\n\nAgrees.propTypes = {\n agrees: PropTypes.array.isRequired,\n}\n\nexport default Agrees\n","import React, { Component } from 'react'\nimport axios from 'axios'\nimport './styles.css'\n\nimport Navigation from '../Navigation'\nimport Agrees from '../Agrees'\n\nconst titlePlaceHolder = '\"<%= title %>\"'\n\nconst filterAgrees = (search, agrees) => {\n if (!search) return null\n\n const check = shoudDisplay(search)\n\n return agrees.filter(\n (agree) =>\n check(agree.title) ||\n check(agree.request.path) ||\n check(agree.request.method),\n )\n}\n\nconst shoudDisplay = (search) => (value) => value && value.indexOf(search) > -1\n\nconst insertId = (agrees) => agrees.map((agree, i) => ({...agree, id: `agree_${i}`}))\n\nclass App extends Component {\n constructor(props) {\n super(props)\n this.state = {\n agrees: null,\n search: '',\n grouped: false,\n agreesFiltered: null,\n title: '',\n }\n }\n\n defaultTitle = 'Agreed UI'\n\n componentDidMount() {\n const title = window.TITLE === titlePlaceHolder ? '' : (window.TITLE || '')\n\n const grouped = localStorage.getItem('grouped') === 'true' || this.state.grouped\n\n if (title) document.title = title\n\n if (Array.isArray(window.AGREES)) {\n return this.setState({ title, grouped, agrees: insertId(window.AGREES) })\n }\n\n axios\n .get('agrees')\n .then(({ data }) => this.setState({ title, grouped, agrees: insertId(data) }))\n }\n\n onSearchTextChange(value) {\n this.setState({\n search: value,\n agreesFiltered: filterAgrees(value, this.state.agrees),\n })\n }\n\n onFilterChange(value) {\n localStorage.setItem('grouped', value)\n this.setState({\n grouped: value,\n })\n }\n\n render() {\n const { agrees, agreesFiltered, title, search, grouped } = this.state\n if (!agrees) return null\n\n return (\n \n
\n {title || this.defaultTitle}
\n {title && {this.defaultTitle}
}\n \n
\n
\n )\n }\n}\n\nexport default App\n","import React from 'react'\nimport ReactDOM from 'react-dom'\nimport './index.css'\nimport App from './components/App'\n\nReactDOM.render(, document.getElementById('root'))\n"],"sourceRoot":""}
--------------------------------------------------------------------------------
/build/static/js/runtime~main.4a686d48.js:
--------------------------------------------------------------------------------
1 | !function(e){function r(r){for(var n,f,i=r[0],l=r[1],a=r[2],c=0,s=[];c0.2%",
45 | "not dead",
46 | "not ie <= 11",
47 | "not op_mini all"
48 | ]
49 | }
50 |
--------------------------------------------------------------------------------
/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/recruit-tech/agreed-ui/b31b25034d87b0fd78020fd084d2aef17a69f66f/public/favicon.png
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 | Agreed UI
14 |
15 |
16 |
19 |
20 |
24 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "config:base"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/recruit-tech/agreed-ui/b31b25034d87b0fd78020fd084d2aef17a69f66f/screenshot.png
--------------------------------------------------------------------------------
/scripts/build.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const fse = require('fs-extra')
3 | const path = require('path')
4 | const minimist = require('minimist')
5 | const serialize = require('serialize-javascript')
6 | const template = require('lodash.template')
7 |
8 | const argv = minimist(process.argv.slice(2))
9 | const getAgreements = require('../server/lib/getAgreements')
10 |
11 | const agreesPath = argv.path
12 | const agrees = getAgreements({ path: agreesPath })
13 | const serialized = serialize(agrees)
14 |
15 | const srcPath = path.resolve(__dirname, '../build/index.html')
16 | const destPath = path.resolve(argv.dest, 'index.html')
17 |
18 | const html = fs.readFileSync(srcPath, 'utf8')
19 |
20 | fse.copySync(path.dirname(srcPath), path.dirname(destPath))
21 |
22 | fs.writeFileSync(
23 | destPath,
24 | template(html, { interpolate: /"<%=([\s\S]+?)%>"/g })({
25 | agrees: serialized,
26 | title: argv.title,
27 | }),
28 | )
29 |
--------------------------------------------------------------------------------
/server/index.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const path = require('path')
3 | const minimist = require('minimist')
4 | const serialize = require('serialize-javascript')
5 | const express = require('express')
6 | const template = require('lodash.template')
7 |
8 | const argv = minimist(process.argv.slice(2))
9 | const getAgreements = require('./lib/getAgreements')
10 |
11 | const port = parseInt(argv.port, 10) || 3000
12 | const agreesPath = argv.path
13 |
14 | const app = express()
15 |
16 | app.get('/agrees', (req, res) => {
17 | const agrees = getAgreements({ path: agreesPath })
18 | res.send(agrees)
19 | })
20 |
21 | app.get('/', (req, res) => {
22 | const agrees = getAgreements({ path: agreesPath })
23 | const serialized = serialize(agrees)
24 |
25 | const srcPath = path.resolve(__dirname, '../build/index.html')
26 | const html = fs.readFileSync(srcPath, 'utf8')
27 | res.send(
28 | template(html, { interpolate: /"<%=([\s\S]+?)%>"/g })({
29 | agrees: serialized,
30 | title: argv.title,
31 | })
32 | )
33 | })
34 |
35 | app.use(express.static(path.resolve(__dirname, '../build')))
36 |
37 | app.listen(port, (err) => {
38 | if (err) throw err
39 | console.log(`> Ready on http://localhost:${port}`) // eslint-disable-line
40 | })
41 |
--------------------------------------------------------------------------------
/server/lib/getAgreements.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const path = require('path')
4 | const register = require('agreed-core/lib/register')
5 | const completion = require('agreed-core/lib/check/completion')
6 | const requireUncached = require('agreed-core/lib/require_hook/requireUncached')
7 | const format = require('agreed-core/lib/template/format')
8 | const { parseSchema } = require('json-schema-to-flow-type')
9 |
10 | module.exports = function(options) {
11 | const agreesPath = path.resolve(options.path)
12 | const base = path.dirname(agreesPath)
13 |
14 | register()
15 |
16 | const agrees = [].concat(requireUncached(agreesPath))
17 | return agrees.map((agree) => completion(agree, base)).map((agree) => {
18 | agree.request.headers_formatted = format(
19 | agree.request.headers,
20 | agree.request.values
21 | )
22 | agree.request.formatted = format(agree.request.body, agree.request.values)
23 |
24 | agree.response.formatted = format(
25 | agree.response.body,
26 | agree.response.values
27 | )
28 |
29 | if (agree.response.schema) {
30 | agree.response.flowtype = parseSchema(agree.response.schema)
31 | }
32 |
33 | return agree
34 | })
35 | }
36 |
--------------------------------------------------------------------------------
/src/components/Agree/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import Request from '../Request'
4 | import Response from '../Response'
5 | import MethodLabel from '../MethodLabel'
6 | import './styles.css'
7 |
8 | const Agree = ({ agree }) => {
9 | const path = agree.request.path
10 | const status = agree.response.status
11 | return (
12 |
13 |
14 |
15 | {agree.title || path}
16 |
17 |
18 | {agree.description || 'no description.'}
19 |
20 |
21 | Request
22 |
23 | Response
24 |
25 |
26 | )
27 | }
28 |
29 | Agree.propTypes = {
30 | agree: PropTypes.object.isRequired,
31 | }
32 |
33 | export default Agree
34 |
--------------------------------------------------------------------------------
/src/components/Agree/styles.css:
--------------------------------------------------------------------------------
1 | .contents > .agree {
2 | padding-top: 2rem;
3 | margin-bottom: 2rem;
4 | }
5 |
6 | .contents > .agree:first-child {
7 | padding-top: 0;
8 | }
9 |
10 | .agree > h1,
11 | .agree > h2,
12 | .agree > section,
13 | .agree .description,
14 | .agree .definitions {
15 | padding: 0 30px;
16 | }
17 |
18 | .agree h2 {
19 | color: var(--color);
20 | border-left: 2px #aaa solid;
21 | padding-left: 28px;
22 | }
23 |
24 | .title {
25 | align-items: center;
26 | border-left: 2px var(--color) solid;
27 | display: flex;
28 | font-family: 'Open Sans', sans-serif;
29 | font-style: italic;
30 | margin: 0 0 0 0;
31 | }
32 |
33 | .title > * {
34 | margin-right: 0.6rem;
35 | }
36 |
37 | .description {
38 | color: var(--color1);
39 | margin: 0.25rem 0;
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/src/components/Agrees/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import Agree from '../Agree'
4 | import './styles.css'
5 |
6 | function Agrees({ agrees }) {
7 | return (
8 |
9 | {agrees.map((agree) =>
)}
10 |
11 | )
12 | }
13 |
14 | Agrees.propTypes = {
15 | agrees: PropTypes.array.isRequired,
16 | }
17 |
18 | export default Agrees
19 |
--------------------------------------------------------------------------------
/src/components/Agrees/styles.css:
--------------------------------------------------------------------------------
1 | .contents section h2 {
2 | color: var(--color);
3 | border-left: 2px #aaa solid;
4 | padding-left: 28px;
5 | }
6 |
7 | .contents {
8 | position: absolute;
9 | width: 100%;
10 | }
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/components/App/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render(, div);
8 | ReactDOM.unmountComponentAtNode(div);
9 | });
10 |
--------------------------------------------------------------------------------
/src/components/App/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import axios from 'axios'
3 | import './styles.css'
4 |
5 | import Navigation from '../Navigation'
6 | import Agrees from '../Agrees'
7 |
8 | const titlePlaceHolder = '"<%= title %>"'
9 |
10 | const filterAgrees = (search, agrees) => {
11 | if (!search) return null
12 |
13 | const check = shoudDisplay(search)
14 |
15 | return agrees.filter(
16 | (agree) =>
17 | check(agree.title) ||
18 | check(agree.request.path) ||
19 | check(agree.request.method),
20 | )
21 | }
22 |
23 | const shoudDisplay = (search) => (value) => value && value.indexOf(search) > -1
24 |
25 | const insertId = (agrees) => agrees.map((agree, i) => ({...agree, id: `agree_${i}`}))
26 |
27 | class App extends Component {
28 | constructor(props) {
29 | super(props)
30 | this.state = {
31 | agrees: null,
32 | search: '',
33 | grouped: false,
34 | agreesFiltered: null,
35 | title: '',
36 | }
37 | }
38 |
39 | defaultTitle = 'Agreed UI'
40 |
41 | componentDidMount() {
42 | const title = window.TITLE === titlePlaceHolder ? '' : (window.TITLE || '')
43 |
44 | const grouped = localStorage.getItem('grouped') === 'true' || this.state.grouped
45 |
46 | if (title) document.title = title
47 |
48 | if (Array.isArray(window.AGREES)) {
49 | return this.setState({ title, grouped, agrees: insertId(window.AGREES) })
50 | }
51 |
52 | axios
53 | .get('agrees')
54 | .then(({ data }) => this.setState({ title, grouped, agrees: insertId(data) }))
55 | }
56 |
57 | onSearchTextChange(value) {
58 | this.setState({
59 | search: value,
60 | agreesFiltered: filterAgrees(value, this.state.agrees),
61 | })
62 | }
63 |
64 | onFilterChange(value) {
65 | localStorage.setItem('grouped', value)
66 | this.setState({
67 | grouped: value,
68 | })
69 | }
70 |
71 | render() {
72 | const { agrees, agreesFiltered, title, search, grouped } = this.state
73 | if (!agrees) return null
74 |
75 | return (
76 |
77 |
78 | {title || this.defaultTitle}
79 | {title && {this.defaultTitle}
}
80 |
81 |
82 |
83 |
84 |
85 |
107 |
108 |
109 | )
110 | }
111 | }
112 |
113 | export default App
114 |
--------------------------------------------------------------------------------
/src/components/App/styles.css:
--------------------------------------------------------------------------------
1 | .wrap {
2 | align-items: stretch;
3 | display: flex;
4 | flex-direction: column;
5 | height: 100vh;
6 | }
7 |
8 | header {
9 | align-items: center;
10 | background: white;
11 | box-shadow: 0 0 2.25rem #9da5ab;
12 | display: flex;
13 | font-family: 'PT Sans', sans-serif;
14 | justify-content: space-between;
15 | padding: 20px;
16 | position: relative;
17 | z-index: 1;
18 | }
19 |
20 | header h1 {
21 | margin: 0;
22 | }
23 |
24 | header p {
25 | font-weight: bold;
26 | }
27 |
28 | .container {
29 | align-items: stretch;
30 | display: flex;
31 | flex: 1;
32 | }
33 |
34 | main {
35 | flex-grow: 3;
36 | order: 2;
37 | padding: 20px 0;
38 | overflow: auto;
39 | position: relative;
40 | }
41 |
42 | aside {
43 | box-shadow: 0 0 0.5rem #9da5ab;
44 | font-weight: 300;
45 | flex: 1;
46 | order: 1;
47 | overflow: auto;
48 | padding: 20px;
49 | position: relative;
50 | min-width: 300px;
51 | }
52 |
53 | .search {
54 | margin: 1rem 0;
55 | }
56 |
57 | .search__input {
58 | border: none;
59 | border-bottom: 2px solid #ddd;
60 | font-size: 1rem;
61 | font-weight: 300;
62 | padding: 0.5rem 0;
63 | transition: border-color 0.1s ease-out;
64 | width: 80%;
65 | }
66 |
67 | .search__input:focus {
68 | outline: 0;
69 | display: block;
70 | border-bottom: 2px solid var(--color5);
71 | }
72 |
73 | .search__group {
74 | display: block;
75 | font-size: 0.9rem;
76 | margin-top: 5px;
77 | }
78 |
79 |
80 |
--------------------------------------------------------------------------------
/src/components/Body/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import PropTypes from 'prop-types'
3 | import JSONTree from 'react-json-tree'
4 | import classNames from 'classnames'
5 | import './styles.css'
6 |
7 | class Body extends Component {
8 | constructor(props) {
9 | super(props)
10 | this.state = { selected: 'body' }
11 | }
12 |
13 | onClick(selected) {
14 | this.setState({ selected })
15 | }
16 |
17 | render({ formatted, schema, flowtype } = this.props) {
18 | const { selected } = this.state
19 | return (
20 |
21 |
22 |
30 | {schema && (
31 |
37 | )}
38 | {flowtype && (
39 |
45 | )}
46 |
47 | {selected === 'schema' && (
48 |
49 | level < 2}
52 | />
53 |
54 | )}
55 | {selected === 'flowtype' && {flowtype}
}
56 | {selected === 'body' && (
57 |
58 |
59 | {(formatted instanceof Object)
60 | ? level < 2}
63 | />
64 | : formatted
65 | }
66 |
67 | )}
68 |
69 | )
70 | }
71 | }
72 |
73 | Body.propTypes = {
74 | formatted: PropTypes.any.isRequired,
75 | schema: PropTypes.object,
76 | flowtype: PropTypes.any,
77 | }
78 |
79 | export default Body
80 |
--------------------------------------------------------------------------------
/src/components/Body/styles.css:
--------------------------------------------------------------------------------
1 | button {
2 | background-color: transparent;
3 | border: none;
4 | cursor: pointer;
5 | outline: none;
6 | padding: 0;
7 | appearance: none;
8 | }
9 |
10 | .body {
11 | color: var(--color1);
12 | padding: 0;
13 | }
14 |
15 | .body > .buttonGroup {
16 | margin-bottom: 1em;
17 | padding: 0 30px;
18 | }
19 |
20 | .body > .code {
21 | background: #efefef;
22 | font-weight: 300;
23 | font-size: 0.9rem;
24 | max-height: 500px;
25 | margin: 1em 0;
26 | overflow: auto;
27 | padding: 2em 2em;
28 | }
29 |
30 | .body > .code ul {
31 | background: #efefef !important;
32 | }
33 |
34 | .buttonGroup button {
35 | margin-right: 1em;
36 | }
37 |
38 | .tabButton {
39 | box-sizing: border-box;
40 | color: var(--color5);
41 | opacity: 0.4;
42 | font-size: 1rem;
43 | font-weight: bold;
44 | padding: 0 1px 3px;
45 | }
46 |
47 | .tabButton:hover {
48 | opacity: 1;
49 | }
50 |
51 | .tabButton:disabled {
52 | color: var(--color5);
53 | cursor: initial;
54 | opacity: 1;
55 | border-bottom: 2px solid var(--color5);
56 | }
57 |
58 | .onlyButton.tabButton:disabled {
59 | border: none;
60 | }
61 |
--------------------------------------------------------------------------------
/src/components/Definitions/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import './styles.css'
4 |
5 | const Definitions = ({ title, description, children }) => {
6 | return (
7 |
8 | {title}
9 | {description && {description}
}
10 | {children}
11 |
12 | )
13 | }
14 |
15 | Definitions.propTypes = {
16 | title: PropTypes.string.isRequired,
17 | description: PropTypes.string,
18 | children: PropTypes.any,
19 | }
20 |
21 | export default Definitions
22 |
--------------------------------------------------------------------------------
/src/components/Definitions/styles.css:
--------------------------------------------------------------------------------
1 | .definitions {
2 | color: var(--color1);
3 | margin: 1.5em 0;
4 | }
5 |
6 | .definitions h1 {
7 | font-size: 1em;
8 | color: var(--color5);
9 | margin-top: 0;
10 | margin-bottom: 1em;
11 | padding-left: 0;
12 | }
13 |
14 | .definitions > p,
15 | .definitions > dl {
16 | margin: 0.25em 1em;
17 | }
18 |
19 | .definitions dl dt {
20 | color: var(--color3);
21 | font-weight: bold;
22 | font-style: italic;
23 | }
24 |
25 | .definitions dl dt:after {
26 | content: ': ';
27 | }
28 |
29 | .definitions dl > * {
30 | display: inline-block;
31 | margin-right: 0.5em;
32 | }
33 |
--------------------------------------------------------------------------------
/src/components/JsonSchemaViewer/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import PropTypes from 'prop-types'
3 | import JSONSchemaView from 'json-schema-view-js'
4 | import 'json-schema-view-js/dist/style.css'
5 | import './styles.css'
6 |
7 | class JsonSchemaViewer extends Component {
8 | mountViewer(el, schema) {
9 | el.appendChild(new JSONSchemaView(schema, 1).render())
10 | }
11 |
12 | render({ schema } = this.props) {
13 | return (
14 | {
17 | if (el) this.mountViewer(el, schema)
18 | }}
19 | />
20 | )
21 | }
22 | }
23 |
24 | JsonSchemaViewer.propTypes = {
25 | schema: PropTypes.object,
26 | }
27 |
28 | export default JsonSchemaViewer
29 |
--------------------------------------------------------------------------------
/src/components/JsonSchemaViewer/styles.css:
--------------------------------------------------------------------------------
1 | .schemaViewer {
2 | opacity: 0.6;
3 | }
4 |
--------------------------------------------------------------------------------
/src/components/MethodLabel/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import './styles.css'
4 |
5 | function MethodLabel({ method }) {
6 | const m = method.toLowerCase()
7 | return
{m.toUpperCase()}
8 | }
9 |
10 | MethodLabel.propTypes = {
11 | method: PropTypes.string.isRequired,
12 | }
13 |
14 | export default MethodLabel
15 |
--------------------------------------------------------------------------------
/src/components/MethodLabel/styles.css:
--------------------------------------------------------------------------------
1 | .method {
2 | margin-right: 5px;
3 | font-size: 12px;
4 | font-weight: 300;
5 | font-style: normal;
6 | border: 1px solid #999;
7 | color: #999;
8 | border-radius: 2px;
9 | padding: 2px 3px;
10 | display: inline-block;
11 | }
12 | .method.get {
13 | color: #66BB6A;
14 | border-color: #66BB6A;
15 | }
16 | .method.delete {
17 | color: #999;
18 | border-color: #999;
19 | }
20 | .method.put {
21 | color: #9E9D24;
22 | border-color: #9E9D24;
23 | }
24 | .method.post {
25 | color: #F9A825;
26 | border-color: #F9A825;
27 | }
28 | .method.patch {
29 | color: #9C27B0;
30 | border-color: #9C27B0;
31 | }
32 |
--------------------------------------------------------------------------------
/src/components/Navigation/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import './styles.css'
4 | import MethodLabel from '../MethodLabel'
5 |
6 | const groupByRequestPath = (list) => {
7 | const ret = {}
8 | for(let i = 0, len = list.length; i < len; i++) {
9 | const item = list[i]
10 | const key = `${item.request.path}_${item.request.method}`
11 | ret[key] = [...(ret[key] || []), item]
12 | }
13 | return ret
14 | }
15 |
16 | const StatusLabel = ({status}) => (
17 |
{status}
18 | )
19 |
20 | StatusLabel.propTypes = {
21 | status: PropTypes.number.isRequired,
22 | }
23 |
24 | const NaviItem = ({ agree }) => (
25 |
26 |
27 |
28 | {agree.title || agree.request.path}
29 |
30 |
31 | )
32 |
33 | NaviItem.propTypes = {
34 | agree: PropTypes.object.isRequired,
35 | }
36 |
37 | const GroupedItem = ({ agree }) => (
38 |
39 |
40 |
41 | {agree.title || 'no title'}
42 |
43 |
44 | )
45 |
46 | GroupedItem.propTypes = {
47 | agree: PropTypes.object.isRequired,
48 | }
49 |
50 | const Details = ({path, agrees}) => {
51 | const [name, method] = path.split('_')
52 | return (
53 |
54 |
55 |
56 | {name}
57 | { agrees.length > 1 && {agrees.length}}
58 |
59 | {agrees.map((agree, i) =>
60 |
61 | )}
62 |
63 | )
64 | }
65 |
66 | Details.propTypes = {
67 | path: PropTypes.string.isRequired,
68 | agrees: PropTypes.array.isRequired,
69 | }
70 |
71 | const Grouped = ({agrees}) => {
72 | const grouped = groupByRequestPath(agrees)
73 | const pathList = Object.keys(grouped)
74 | return (
75 |
76 | {pathList.map((path, i) => )}
77 |
78 | )
79 | }
80 |
81 | Grouped.propTypes = {
82 | agrees: PropTypes.array.isRequired,
83 | }
84 |
85 | function Navigation({ agrees, grouped }) {
86 | return (
87 |
93 | )
94 | }
95 |
96 | Navigation.propTypes = {
97 | agrees: PropTypes.array.isRequired,
98 | grouped: PropTypes.bool.isRequired,
99 | }
100 |
101 | export default Navigation
102 |
--------------------------------------------------------------------------------
/src/components/Navigation/styles.css:
--------------------------------------------------------------------------------
1 | nav {
2 | position: absolute;
3 | padding-bottom: 20px;
4 | }
5 |
6 | nav p {
7 | margin: 4px 0;
8 | }
9 |
10 | details {
11 | padding-bottom: 7px;
12 | }
13 |
14 | summary {
15 | color: var(--color5);
16 | cursor: pointer;
17 | font-size: 0.9rem;
18 | margin-bottom: 4px;
19 | outline: none;
20 | }
21 |
22 | details > p {
23 | padding-left: 1em;
24 | margin-top: 3px;
25 | }
26 |
27 | details summary::-webkit-details-marker {
28 | transform: translate(0, 1px) scale(0.7);
29 | opacity: 0.5;
30 | }
31 |
32 | .count {
33 | border-radius: 8px;
34 | border: 1px solid var(--color5);
35 | background: var(--color5);
36 | color: var(--color0);
37 | display: inline-block;
38 | font-size: 0.5rem;
39 | margin-left: 5px;
40 | opacity: 0.6;
41 | padding: 0px 3px;
42 | position: relative;
43 | top: -1px;
44 | }
45 |
46 | .statusLabel {
47 | border-radius: 6px;
48 | color: var(--color0);
49 | display: inline-block;
50 | font-size: 0.5rem;
51 | padding: 2px 4px;
52 | margin-right: 0.25rem;
53 | opacity: 0.8;
54 | }
55 |
56 | .statusLabel--2 {
57 | background: var(--color-green);
58 | }
59 |
60 | .statusLabel--3 {
61 | background: var(--color4);
62 | }
63 |
64 | .statusLabel--4 {
65 | background: var(--color3);
66 | }
67 |
68 | .statusLabel--5 {
69 | background: var(--color5);
70 | }
71 |
72 |
--------------------------------------------------------------------------------
/src/components/Request/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import Definitions from '../Definitions'
4 | import Body from '../Body'
5 |
6 | const Request = ({ data }) => {
7 | const { method, path, headers_formatted: headers, query, formatted, schema } = data
8 | return (
9 |
10 |
11 |
12 | {query && !!Object.keys(query).length && (
13 |
14 | {Object.entries(query).map(([k, v]) => (
15 |
16 | - {k}
17 | - {JSON.stringify(v)}
18 |
19 | ))}
20 |
21 | )}
22 | {headers && !!Object.keys(headers).length && (
23 |
24 | {Object.entries(headers).map(([k, v]) => (
25 |
26 | - {k}
27 | - {JSON.stringify(v)}
28 |
29 | ))}
30 |
31 | )}
32 | {formatted &&
}
33 |
34 | )
35 | }
36 |
37 | Request.propTypes = {
38 | data: PropTypes.object.isRequired,
39 | }
40 |
41 | export default Request
42 |
--------------------------------------------------------------------------------
/src/components/Request/styles.css:
--------------------------------------------------------------------------------
1 | .definitions {
2 | color: var(--color1);
3 | margin: 1.5em 0;
4 | }
5 |
6 | .definitions h1 {
7 | font-size: 1em;
8 | color: var(--color5);
9 | margin-top: 0;
10 | margin-bottom: 1em;
11 | padding-left: 0;
12 | }
13 |
14 | .definitions > p,
15 | .definitions > dl {
16 | margin: 0.25em 1em;
17 | }
18 |
19 | .definitions dl dt {
20 | color: var(--color3);
21 | font-weight: bold;
22 | font-style: italic;
23 | }
24 |
25 | .definitions dl dt:after {
26 | content: ': ';
27 | }
28 |
29 | .definitions dl > * {
30 | display: inline-block;
31 | margin-right: 0.5em;
32 | }
33 |
--------------------------------------------------------------------------------
/src/components/Response/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | import Definitions from '../Definitions'
4 | import Body from '../Body'
5 |
6 | const Response = ({ data }) => {
7 | const { status, formatted, schema, flowtype } = data
8 | return (
9 |
10 |
11 | {formatted && (
12 |
13 | )}
14 |
15 | )
16 | }
17 |
18 | Response.propTypes = {
19 | data: PropTypes.object.isRequired,
20 | }
21 |
22 | export default Response
23 |
--------------------------------------------------------------------------------
/src/components/Response/styles.css:
--------------------------------------------------------------------------------
1 | .definitions {
2 | color: var(--color1);
3 | margin: 1.5em 0;
4 | }
5 |
6 | .definitions h1 {
7 | font-size: 1em;
8 | color: var(--color5);
9 | margin-top: 0;
10 | margin-bottom: 1em;
11 | padding-left: 0;
12 | }
13 |
14 | .definitions > p,
15 | .definitions > dl {
16 | margin: 0.25em 1em;
17 | }
18 |
19 | .definitions dl dt {
20 | color: var(--color3);
21 | font-weight: bold;
22 | font-style: italic;
23 | }
24 |
25 | .definitions dl dt:after {
26 | content: ': ';
27 | }
28 |
29 | .definitions dl > * {
30 | display: inline-block;
31 | margin-right: 0.5em;
32 | }
33 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Open+Sans:400,400i|PT+Sans');
2 |
3 | /* RGB */
4 | :root {
5 | --color: rgba(26, 40, 31, 1);
6 | --color-link: rgba(26, 40, 31, 0.7);
7 | --color0: white;
8 | --color1: rgba(26, 40, 31, 0.6);
9 | --color2: rgba(99, 82, 85, 1);
10 | --color3: rgba(206, 123, 145, 1);
11 | --color4: rgba(192, 232, 249, 1);
12 | --color5: rgba(164, 191, 189, 1);
13 | --color-green: #66BB6A;
14 | }
15 |
16 | * {
17 | margin: 0;
18 | padding: 0;
19 | }
20 |
21 | a {
22 | color: var(--color-link);
23 | }
24 |
25 | a:hover {
26 | color: #bbb;
27 | }
28 |
29 | h1 {
30 | font-size: 1.5rem;
31 | margin: 2rem 0;
32 | }
33 |
34 | h2 {
35 | font-size: 1.2rem;
36 | margin: 2rem 0 1rem;
37 | }
38 |
39 | body {
40 | color: var(--color);
41 | display: flex;
42 | font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Segoe UI", sans-serif;
43 | flex-direction: column;
44 | min-height: 100vh;
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import './index.css'
4 | import App from './components/App'
5 |
6 | ReactDOM.render(, document.getElementById('root'))
7 |
--------------------------------------------------------------------------------
/test/agrees/agrees.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | {
3 | title: 'getHogeFuga',
4 | description: 'hogefuga',
5 | request: {
6 | path: '/hoge/fuga',
7 | method: 'GET',
8 | query: {
9 | q: 'foo',
10 | },
11 | },
12 | response: {
13 | headers: {
14 | 'x-csrf-token': 'csrf-token',
15 | },
16 | body: {
17 | message: 'hello world',
18 | },
19 | },
20 | },
21 | './hoge/foo.json',
22 | './foo/bar.yaml',
23 | {
24 | request: require('./qux/request.json'),
25 | response: require('./qux/response.json'),
26 | },
27 | {
28 | request: {
29 | path: '/path/:id',
30 | method: 'GET',
31 | // value for test client
32 | values: {
33 | id: 'yosuke',
34 | },
35 | },
36 | response: {
37 | headers: {
38 | 'x-csrf-token': 'csrf-token',
39 | },
40 | body: {
41 | // :id is for request value
42 | message: 'hello {:id}',
43 | },
44 | },
45 | },
46 | {
47 | request: {
48 | path: '/path/:id',
49 | method: 'POST',
50 | // query embed data, any query is ok.
51 | query: {
52 | meta: "{:meta}",
53 | },
54 | body: {
55 | message: "{:message}"
56 | },
57 | // value for test client
58 | values: {
59 | id: 'yosuke',
60 | meta: true,
61 | message: 'foobarbaz'
62 | },
63 | },
64 | response: {
65 | headers: {
66 | 'x-csrf-token': 'csrf-token',
67 | },
68 | body: {
69 | // :id is for request value
70 | message: 'hello {:id}, {:meta}, {:message}',
71 | },
72 | },
73 | },
74 | {
75 | request: {
76 | // if no method then GET
77 | path: '/nyan/:id',
78 | query: {
79 | meta: "{:meta}",
80 | },
81 | // value for test client
82 | values: {
83 | id: 'yosuke',
84 | meta: false,
85 | },
86 | },
87 | response: {
88 | headers: {
89 | 'x-csrf-token': 'csrf-token',
90 | },
91 | body: {
92 | // :id is for request value
93 | message: 'hello {:id}, {:meta}',
94 | },
95 | },
96 | },
97 | {
98 | request: {
99 | path: '/embed/from/response/:id',
100 | method: 'POST',
101 | query: {
102 | meta: "{:meta}",
103 | },
104 | body: {
105 | message: '{:message}'
106 | },
107 | // value for test client
108 | values: {
109 | id: 'yosuke',
110 | meta: false,
111 | message: 'this is a message',
112 | },
113 | },
114 | response: {
115 | headers: {
116 | 'x-csrf-token': 'csrf-token',
117 | },
118 | body: {
119 | // embed template from response values
120 | image: '{:image}',
121 | topics: '{:topics}',
122 | message: 'hello {:id} {:meta} {:message}',
123 | },
124 | values: {
125 | image: 'http://imgfp.hotp.jp/SYS/cmn/images/front_002/logo_hotopepper_264x45.png',
126 | topics: [
127 | {
128 | a: 'a'
129 | }, {
130 | b: 'b'
131 | }
132 | ],
133 | }
134 | },
135 | },
136 | {
137 | request: {
138 | path: '/images/:id',
139 | method: 'GET',
140 | query: {
141 | q: '{:someQueryStrings}',
142 | },
143 | values: {
144 | id: 'yosuke',
145 | someQueryStrings: 'foo'
146 | },
147 | },
148 | response: {
149 | headers: {
150 | 'x-csrf-token': 'csrf-token',
151 | },
152 | body: {
153 | message: '{:greeting} {:id} {:someQueryStrings}',
154 | images: '{:images}',
155 | themes: '{:themes}',
156 | },
157 | values: {
158 | greeting: 'hello',
159 | images: [
160 | 'http://example.com/foo.jpg',
161 | 'http://example.com/bar.jpg',
162 | ],
163 | themes: {
164 | name: 'green',
165 | },
166 | }
167 | },
168 | },
169 | {
170 | request: {
171 | path: '/list/:index',
172 | method: 'GET',
173 | values: {
174 | index: 1
175 | }
176 | },
177 | response: {
178 | body: {
179 | result : '{:list[:index]}'
180 | },
181 | values: {
182 | list: [
183 | 'hello',
184 | 'hi',
185 | 'dunke',
186 | ]
187 | }
188 | },
189 | },
190 | {
191 | request: {
192 | path: '/useschema/:index',
193 | method: 'GET',
194 | values: {
195 | index: 1
196 | }
197 | },
198 | response: {
199 | body: {
200 | result : '{:list[:index]}'
201 | },
202 | schema: {
203 | type: 'object',
204 | properties: {
205 | result: {
206 | type: 'string'
207 | }
208 | },
209 | },
210 | values: {
211 | list: [
212 | 'hello',
213 | 'hi',
214 | 'dunke',
215 | ]
216 | }
217 | },
218 | },
219 | {
220 | request: {
221 | path: '/useschema/withstring/:index',
222 | method: 'GET',
223 | values: {
224 | index: 1
225 | }
226 | },
227 | response: {
228 | body: {
229 | result : '{:list[:index]}'
230 | },
231 | schema: './schema/hi.json',
232 | values: {
233 | list: [
234 | 'hello',
235 | 'hi',
236 | 'dunke',
237 | ]
238 | }
239 | },
240 | },
241 | {
242 | request: {
243 | path: '/headers/:index',
244 | method: 'GET',
245 | headers: {
246 | 'x-token': '{:token}',
247 | 'x-api-key': '{:apiKey}',
248 | },
249 | values: {
250 | index: 2,
251 | token: 'nyan',
252 | apiKey: 'nyaaan'
253 | },
254 | },
255 | response: {
256 | body: {
257 | result : '{:list[:index]} {:token} {:apiKey}'
258 | },
259 | values: {
260 | list: [
261 | 'hello',
262 | 'hi',
263 | 'dunke',
264 | ]
265 | }
266 | },
267 | },
268 | {
269 | request: {
270 | path: '/headers/:index',
271 | method: 'GET',
272 | values: {
273 | index: 1,
274 | },
275 | },
276 | response: {
277 | body: {
278 | result : '{:list[:index]}'
279 | },
280 | values: {
281 | list: [
282 | 'hello',
283 | 'hi',
284 | 'dunke',
285 | ]
286 | }
287 | },
288 | },
289 | {
290 | request: {
291 | path: '/headers/test/:index',
292 | method: 'GET',
293 | headers: {
294 | 'x-test-token': '{:xTestToken}'
295 | },
296 | values: {
297 | index: 1,
298 | xTestToken: 'fdajfdsaoijfdoajofdjaoj',
299 | },
300 | },
301 | response: {
302 | body: {
303 | result : '{:list[:index]}'
304 | },
305 | values: {
306 | list: [
307 | 'hello',
308 | 'hi',
309 | 'dunke',
310 | ]
311 | }
312 | },
313 | },
314 | ]
315 |
--------------------------------------------------------------------------------
/test/agrees/agrees.json5:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | request: {
4 | path: '/hoge/fuga',
5 | method: 'GET',
6 | query: {
7 | q: 'foo',
8 | },
9 | },
10 | response: {
11 | headers: {
12 | 'x-csrf-token': 'csrf-token',
13 | },
14 | body: {
15 | message: 'hello world',
16 | },
17 | },
18 | },
19 | './hoge/foo.json',
20 | './foo/bar.yaml',
21 | {
22 | request: './qux/request.json',
23 | response: './qux/response.json',
24 | },
25 | {
26 | request: {
27 | path: '/path/:id',
28 | method: 'GET',
29 | // value for test client
30 | values: {
31 | id: 'yosuke',
32 | },
33 | },
34 | response: {
35 | headers: {
36 | 'x-csrf-token': 'csrf-token',
37 | },
38 | body: {
39 | // :id is for request value
40 | message: 'hello {:id}',
41 | },
42 | },
43 | },
44 | {
45 | request: {
46 | path: '/path/:id',
47 | method: 'POST',
48 | // query embed data, any query is ok.
49 | query: {
50 | meta: "{:meta}",
51 | },
52 | body: {
53 | message: "{:message}"
54 | },
55 | // value for test client
56 | values: {
57 | id: 'yosuke',
58 | meta: true,
59 | message: 'foobarbaz'
60 | },
61 | },
62 | response: {
63 | headers: {
64 | 'x-csrf-token': 'csrf-token',
65 | },
66 | body: {
67 | // :id is for request value
68 | message: 'hello {:id}, {:meta}, {:message}',
69 | },
70 | },
71 | },
72 | {
73 | request: {
74 | path: '/path/header/format',
75 | method: 'GET',
76 | },
77 | response: {
78 | headers: {
79 | 'access-control-allow-origin': '{:acao}'
80 | },
81 | body: {
82 | message: 'hello',
83 | },
84 | values: {
85 | 'acao': '*'
86 | }
87 | },
88 | },
89 | {
90 | request: {
91 | path: '/path/default/header/',
92 | method: 'GET',
93 | },
94 | response: {
95 | body: {
96 | message: 'hello',
97 | },
98 | },
99 | },
100 | {
101 | request: {
102 | path: '/path/default/request/header/',
103 | method: 'GET',
104 | headers: {
105 | 'x-forwarded-for': 'forward'
106 | },
107 | },
108 | response: {
109 | body: {
110 | message: 'forward',
111 | },
112 | },
113 | },
114 | {
115 | request: {
116 | path: '/test/case/insensitive/headers',
117 | method: 'GET',
118 | headers: {
119 | 'This-Headers-Should-Be-Lower-Case': 'true'
120 | },
121 | },
122 | response: {
123 | body: {
124 | message: 'hello case insensitive headers',
125 | },
126 | },
127 | },
128 | {
129 | request: {
130 | path: '/test/null/agreed/values',
131 | },
132 | response: {
133 | body: {
134 | messages: [
135 | { message: '{:messages.0.message}' },
136 | '{:messages.1-last}'
137 | ],
138 | },
139 | values: {
140 | messages: [
141 | { message: null },
142 | { message: 'test' },
143 | ]
144 | },
145 | },
146 | },
147 | {
148 | request: {
149 | path: '/test/randomstring/agreed/values',
150 | },
151 | response: {
152 | body: {
153 | random: '{randomString:random}'
154 | },
155 | values: {
156 | random: 8
157 | },
158 | },
159 | },
160 | {
161 | request: {
162 | path: '/test/randomint/agreed/values',
163 | },
164 | response: {
165 | body: {
166 | random: '{randomInt:random}'
167 | },
168 | values: {
169 | random: '1-1000'
170 | },
171 | },
172 | },
173 | {
174 | request: {
175 | path: '/test/parseint/agreed/values/:id',
176 | },
177 | response: {
178 | body: {
179 | id: '{parseInt:id}'
180 | },
181 | },
182 | },
183 | {
184 | request: {
185 | path: '/test/agreed/messages',
186 | method: 'POST',
187 | body: {
188 | messages: [
189 | { message: '{:messages.0.message}' },
190 | '{:messages.1-last}'
191 | ]
192 | },
193 | values: {
194 | messages: [
195 | { message: null },
196 | { message: 'test' },
197 | ]
198 | }
199 | },
200 | response: {
201 | status: 201,
202 | body: {
203 | results: '{:messages}'
204 | },
205 | values: {
206 | messages: [
207 | { message: '{:message0}' },
208 | { message: 'test' },
209 | ]
210 | }
211 | },
212 | },
213 | {
214 | request: {
215 | path: '/test/agreed/use/null/obj',
216 | method: 'POST',
217 | body: {
218 | test: '{:test}'
219 | },
220 | values: {
221 | test: null,
222 | }
223 | },
224 | response: {
225 | status: 201,
226 | body: {
227 | results: '{:test}'
228 | },
229 | },
230 | },
231 | {
232 | request: {
233 | path: '/test/bind/nest/object',
234 | method: 'POST',
235 | body: {
236 | time: {
237 | start: '{:time.start}',
238 | end: '{:time.end}',
239 | break: {
240 | start: '{:time.break.start}',
241 | end: '{:time.break.end}',
242 | }
243 | },
244 | members: [
245 | {
246 | id: '{:members.0.id}'
247 | },
248 | '{:members.1-last}'
249 | ]
250 | }
251 | },
252 | response: {
253 | body: {
254 | time: {
255 | start: '{:time.start}',
256 | end: '{:time.end}'
257 | },
258 | break: {
259 | start: '{:time.break.start}',
260 | end: '{:time.break.end}'
261 | },
262 | members: [
263 | {
264 | id: '{:id}'
265 | },
266 | '{:members.1-last}'
267 | ]
268 | },
269 | },
270 | },
271 | {
272 | request: {
273 | path: '/test/unixtime/agreed/values',
274 | },
275 | response: {
276 | body: {
277 | unixtime: '{unixtime:time}',
278 | },
279 | values: {
280 | time: 12344556677,
281 | }
282 | },
283 | },
284 | ]
285 |
--------------------------------------------------------------------------------
/test/agrees/foo/bar.yaml:
--------------------------------------------------------------------------------
1 | request:
2 | path: '/foo/:bar'
3 | method: 'PUT'
4 | body:
5 | a: 'b'
6 | c: 'd'
7 | response:
8 | headers:
9 | Content-Type: 'text'
10 | body: 'hello put'
11 |
12 |
--------------------------------------------------------------------------------
/test/agrees/hoge/foo.json:
--------------------------------------------------------------------------------
1 | {
2 | 'request': {
3 | method: 'POST',
4 | path: '/hoge/:foo',
5 | body: {
6 | message: 'foobarbaz',
7 | },
8 | },
9 | response: {
10 | body: {
11 | message: 'hello post',
12 | },
13 | },
14 | }
15 |
--------------------------------------------------------------------------------
/test/agrees/hoge/fuga/_agree.json:
--------------------------------------------------------------------------------
1 | {
2 | request: {
3 | method: 'GET',
4 | },
5 | response: {
6 | status: 200, // default is 200
7 | body: {
8 | message: 'hello world'
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/test/agrees/hoge/fuga/request.json:
--------------------------------------------------------------------------------
1 | {
2 | }
3 |
--------------------------------------------------------------------------------
/test/agrees/index.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | './hoge/foo.json',
3 | './foo/bar.yaml'
4 | ]
5 |
--------------------------------------------------------------------------------
/test/agrees/notify.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | {
3 | request: {
4 | path: '/messages',
5 | method: 'POST',
6 | body: {
7 | message: '{:message}'
8 | },
9 | values: {
10 | message: 'test',
11 | },
12 | },
13 | response: {
14 | body: {
15 | result : '{:message}'
16 | },
17 | values: {
18 | message: 'test',
19 | },
20 | notify: {
21 | event: 'message2',
22 | body: {
23 | message: 'message! {:message}'
24 | }
25 | }
26 | },
27 | },
28 | {
29 | request: {
30 | path: '/messages2',
31 | method: 'POST',
32 | body: {
33 | message: '{:message}'
34 | },
35 | values: {
36 | message: 'test',
37 | },
38 | },
39 | response: {
40 | body: {
41 | result : '{:message}'
42 | },
43 | values: {
44 | message: 'test',
45 | },
46 | notify: {
47 | body: {
48 | message: 'message2 {:message}'
49 | }
50 | }
51 | },
52 | },
53 | ];
54 |
--------------------------------------------------------------------------------
/test/agrees/qux/request.json:
--------------------------------------------------------------------------------
1 | {
2 | path: '/qux/fuga',
3 | method: 'DELETE',
4 | }
5 |
--------------------------------------------------------------------------------
/test/agrees/qux/response.json:
--------------------------------------------------------------------------------
1 | {
2 | status: 204,
3 | }
4 |
--------------------------------------------------------------------------------
/test/agrees/schema/hi.json:
--------------------------------------------------------------------------------
1 | {
2 | type: 'object',
3 | properties: {
4 | result: {
5 | type: 'string'
6 | }
7 | },
8 | }
9 |
--------------------------------------------------------------------------------
/test/agrees/sub.js:
--------------------------------------------------------------------------------
1 | module.exports = (a, b) => a - b
2 |
--------------------------------------------------------------------------------