├── .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 | ![ScreenShot](https://raw.githubusercontent.com/recruit-tech/agreed-ui/master/screenshot.png) 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":"gZAaeA,MATf,SAAAC,GAAiC,IACzBC,EADyBD,EAAVE,OACJC,cACjB,OAAOC,EAAAC,EAAAC,cAAA,QAAMC,UAAS,UAAAC,OAAYP,IAAMA,EAAEQ,gBCStCC,EAAc,SAAAV,GAAA,IAAEW,EAAFX,EAAEW,OAAF,OAClBP,EAAAC,EAAAC,cAAA,QAAMC,UAAS,4BAAAC,OAA8BI,KAAKC,MAAMF,EAAO,OAASA,IAOpEG,EAAW,SAAAC,GAAA,IAAGC,EAAHD,EAAGC,MAAH,OACfZ,EAAAC,EAAAC,cAAA,SACEF,EAAAC,EAAAC,cAAA,KAAGW,KAAI,IAAAT,OAAMQ,EAAME,KACjBd,EAAAC,EAAAC,cAACa,EAAD,CAAajB,OAAQc,EAAMI,QAAQlB,SACnCE,EAAAC,EAAAC,cAAA,YAAOU,EAAMK,OAASL,EAAMI,QAAQE,SASpCC,EAAc,SAAAC,GAAA,IAAGR,EAAHQ,EAAGR,MAAH,OAClBZ,EAAAC,EAAAC,cAAA,SACEF,EAAAC,EAAAC,cAAA,KAAGW,KAAI,IAAAT,OAAMQ,EAAME,KACjBd,EAAAC,EAAAC,cAACmB,EAAD,CAAad,OAAQK,EAAMU,SAASf,SACpCP,EAAAC,EAAAC,cAAA,YAAOU,EAAMK,OAAS,eAStBM,EAAU,SAAAC,GAAoB,IAAlBN,EAAkBM,EAAlBN,KAAMO,EAAYD,EAAZC,OAAYC,EACXR,EAAKS,MAAM,KADAC,EAAAC,OAAAC,EAAA,EAAAD,CAAAH,EAAA,GAC3BK,EAD2BH,EAAA,GACrB9B,EADqB8B,EAAA,GAElC,OACE5B,EAAAC,EAAAC,cAAA,WAAS8B,MAAI,GACXhC,EAAAC,EAAAC,cAAA,eACEF,EAAAC,EAAAC,cAACa,EAAD,CAAajB,OAAQA,IACrBE,EAAAC,EAAAC,cAAA,YAAO6B,GACLN,EAAOQ,OAAS,GAAKjC,EAAAC,EAAAC,cAAA,QAAMC,UAAU,SAASsB,EAAOQ,SAEtDR,EAAOS,IAAI,SAACtB,EAAOuB,GAAR,OACVnC,EAAAC,EAAAC,cAACkC,EAAD,CAAaC,IAAKzB,EAAME,GAAIF,MAAOA,QAWvC0B,EAAU,SAAAC,GAAc,IACtBC,EAlEmB,SAACC,GAE1B,IADA,IAAMC,EAAM,GACJP,EAAI,EAAGQ,EAAMF,EAAKR,OAAQE,EAAIQ,EAAKR,IAAK,CAC9C,IAAMS,EAAOH,EAAKN,GACZE,EAAG,GAAAjC,OAAMwC,EAAK5B,QAAQE,KAAnB,KAAAd,OAA2BwC,EAAK5B,QAAQlB,QACjD4C,EAAIL,GAAJR,OAAAgB,EAAA,EAAAhB,CAAgBa,EAAIL,IAAQ,IAA5BjC,OAAA,CAAiCwC,IAEnC,OAAOF,EA2DSI,CADYP,EAAZd,QAEVsB,EAAWlB,OAAOmB,KAAKR,GAC7B,OACExC,EAAAC,EAAAC,cAACF,EAAAC,EAAMgD,SAAP,KACGF,EAASb,IAAI,SAAChB,EAAMiB,GAAP,OAAanC,EAAAC,EAAAC,cAACgD,EAAD,CAASb,IAAKnB,EAAMA,KAAMA,EAAMO,OAAQe,EAAQtB,SAyBlEiC,MAhBf,SAAAC,GAAyC,IAAnB3B,EAAmB2B,EAAnB3B,OAAQe,EAAWY,EAAXZ,QAC5B,OACExC,EAAAC,EAAAC,cAAA,WACIsC,EACExC,EAAAC,EAAAC,cAACmD,EAAD,CAAS5B,OAAQA,IACjBA,EAAOS,IAAI,SAACtB,EAAOuB,GAAR,OAAcnC,EAAAC,EAAAC,cAACoD,EAAD,CAAUjB,IAAKF,EAAGvB,MAAOA,QCrE7C2C,UAhBK,SAAA3D,GAAsC,IAAnCqB,EAAmCrB,EAAnCqB,MAAOuC,EAA4B5D,EAA5B4D,YAAaC,EAAe7D,EAAf6D,SACzC,OACEzD,EAAAC,EAAAC,cAAA,WAASC,UAAU,eACjBH,EAAAC,EAAAC,cAAA,UAAKe,GACJuC,GAAexD,EAAAC,EAAAC,cAAA,SAAIsD,GACnBC,uCCqEQC,sBAvEb,SAAAA,EAAYC,GAAO,IAAAC,EAAA,OAAA/B,OAAAgC,EAAA,EAAAhC,CAAAiC,KAAAJ,IACjBE,EAAA/B,OAAAkC,EAAA,EAAAlC,CAAAiC,KAAAjC,OAAAmC,EAAA,EAAAnC,CAAA6B,GAAAO,KAAAH,KAAMH,KACDO,MAAQ,CAAEC,SAAU,QAFRP,uEAKXO,GACNL,KAAKM,SAAS,CAAED,8CAGmC,IAAAE,EAAAP,KAAAlE,EAAA0E,UAAArC,OAAA,QAAAsC,IAAAD,UAAA,GAAAA,UAAA,GAAZR,KAAKH,MAArCa,EAA4C5E,EAA5C4E,UAAWC,EAAiC7E,EAAjC6E,OAAQC,EAAyB9E,EAAzB8E,SAClBP,EAAaL,KAAKI,MAAlBC,SACR,OACEnE,EAAAC,EAAAC,cAAA,WAASC,UAAU,QACjBH,EAAAC,EAAAC,cAAA,OAAKC,UAAU,eACbH,EAAAC,EAAAC,cAAA,UACEC,UAAWwE,IAAW,YAAa,CACjCC,YAAaH,IAEfI,QAAS,kBAAMR,EAAKQ,QAAQ,SAC5BC,SAAuB,SAAbX,GALZ,QAQCM,GACCzE,EAAAC,EAAAC,cAAA,UACEC,UAAU,YACV0E,QAAS,kBAAMR,EAAKQ,QAAQ,WAC5BC,SAAuB,WAAbX,GAHZ,UAODO,GACC1E,EAAAC,EAAAC,cAAA,UACEC,UAAU,YACV0E,QAAS,kBAAMR,EAAKQ,QAAQ,aAC5BC,SAAuB,aAAbX,GAHZ,aAQU,WAAbA,GACCnE,EAAAC,EAAAC,cAAA,OAAKC,UAAU,QACbH,EAAAC,EAAAC,cAAC6E,EAAA9E,EAAD,CACE+E,KAAMP,EACNQ,iBAAkB,SAACC,EAASF,EAAMG,GAAhB,OAA0BA,EAAQ,MAI5C,aAAbhB,GAA2BnE,EAAAC,EAAAC,cAAA,OAAKC,UAAU,QAAQuE,GACrC,SAAbP,GAECnE,EAAAC,EAAAC,cAAA,OAAKC,UAAU,QACXqE,aAAqB3C,OACnB7B,EAAAC,EAAAC,cAAC6E,EAAA9E,EAAD,CACE+E,KAAMR,EACNS,iBAAkB,SAACC,EAASF,EAAMG,GAAhB,OAA0BA,EAAQ,KAEtDX,WAzDGY,cCkCJC,EAnCC,SAAAzF,GAAc,IAAXoF,EAAWpF,EAAXoF,KACTlF,EAAuEkF,EAAvElF,OAAQoB,EAA+D8D,EAA/D9D,KAAyBoE,EAAsCN,EAAzDO,kBAA4BC,EAA6BR,EAA7BQ,MAAOhB,EAAsBQ,EAAtBR,UAAWC,EAAWO,EAAXP,OACpE,OACEzE,EAAAC,EAAAC,cAAA,WACEF,EAAAC,EAAAC,cAACuF,EAAD,CAAaxE,MAAM,SAASuC,YAAa1D,EAAOO,gBAChDL,EAAAC,EAAAC,cAACuF,EAAD,CAAaxE,MAAM,OAAOuC,YAAatC,IACtCsE,KAAW3D,OAAOmB,KAAKwC,GAAOvD,QAC7BjC,EAAAC,EAAAC,cAACuF,EAAD,CAAaxE,MAAM,SAChBY,OAAO6D,QAAQF,GAAOtD,IAAI,SAAAvB,GAAA,IAAAS,EAAAS,OAAAC,EAAA,EAAAD,CAAAlB,EAAA,GAAEgF,EAAFvE,EAAA,GAAKwE,EAALxE,EAAA,UACzBpB,EAAAC,EAAAC,cAAA,MAAImC,IAAKsD,GACP3F,EAAAC,EAAAC,cAAA,UAAKyF,GACL3F,EAAAC,EAAAC,cAAA,UAAK2F,KAAKC,UAAUF,QAK3BN,KAAazD,OAAOmB,KAAKsC,GAASrD,QACjCjC,EAAAC,EAAAC,cAACuF,EAAD,CAAaxE,MAAM,WAChBY,OAAO6D,QAAQJ,GAASpD,IAAI,SAAAV,GAAA,IAAAe,EAAAV,OAAAC,EAAA,EAAAD,CAAAL,EAAA,GAAEmE,EAAFpD,EAAA,GAAKqD,EAALrD,EAAA,UAC3BvC,EAAAC,EAAAC,cAAA,MAAImC,IAAKsD,GACP3F,EAAAC,EAAAC,cAAA,UAAKyF,GACL3F,EAAAC,EAAAC,cAAA,UAAK2F,KAAKC,UAAUF,QAK3BpB,GAAaxE,EAAAC,EAAAC,cAAC6F,EAAD,CAAMvB,UAAWA,EAAWC,OAAQA,MCVzCuB,EAhBE,SAAApG,GAAc,IAAXoF,EAAWpF,EAAXoF,KACVzE,EAAwCyE,EAAxCzE,OAAQiE,EAAgCQ,EAAhCR,UAAWC,EAAqBO,EAArBP,OAAQC,EAAaM,EAAbN,SACnC,OACE1E,EAAAC,EAAAC,cAAA,WACEF,EAAAC,EAAAC,cAACuF,EAAD,CAAaxE,MAAM,aAAauC,YAAW,GAAApD,OAAKG,KAC/CiE,GACCxE,EAAAC,EAAAC,cAAC6F,EAAD,CAAMvB,UAAWA,EAAWC,OAAQA,EAAQC,SAAUA,MCqB/CuB,UAzBD,SAAArG,GAAe,IAAZgB,EAAYhB,EAAZgB,MACTM,EAAON,EAAMI,QAAQE,KACrBX,EAASK,EAAMU,SAASf,OAC9B,OACEP,EAAAC,EAAAC,cAAA,WAASC,UAAU,QAAQW,GAAIF,EAAME,IACnCd,EAAAC,EAAAC,cAAA,MAAIC,UAAU,SACZH,EAAAC,EAAAC,cAACa,EAAD,CAAajB,OAAQc,EAAMI,QAAQlB,OAAQS,OAAQA,IAClDK,EAAMK,OAASC,GAElBlB,EAAAC,EAAAC,cAAA,OAAKC,UAAU,eACZS,EAAM4C,aAAe,mBAGxBxD,EAAAC,EAAAC,cAAA,qBACAF,EAAAC,EAAAC,cAACgG,EAAD,CAASlB,KAAMpE,EAAMI,UACrBhB,EAAAC,EAAAC,cAAA,sBACAF,EAAAC,EAAAC,cAACiG,EAAD,CAAUnB,KAAMpE,EAAMU,qBCNb8E,MAZf,SAAAxG,GAA4B,IAAV6B,EAAU7B,EAAV6B,OAChB,OACEzB,EAAAC,EAAAC,cAAA,OAAKC,UAAU,YACZsB,EAAOS,IAAI,SAACtB,GAAD,OAAWZ,EAAAC,EAAAC,cAACmG,EAAD,CAAOhE,IAAKzB,EAAME,GAAIF,MAAOA,QCcpD0F,EAAe,SAACC,GAAD,OAAY,SAACC,GAAD,OAAWA,GAASA,EAAMC,QAAQF,IAAW,IAExEG,EAAW,SAACjF,GAAD,OAAYA,EAAOS,IAAI,SAACtB,EAAOuB,GAAR,OAAAN,OAAA8E,EAAA,EAAA9E,CAAA,GAAmBjB,EAAnB,CAA0BE,GAAE,SAAAV,OAAW+B,QAwFhEyE,cArFb,SAAAA,EAAYjD,GAAO,IAAAC,EAAA,OAAA/B,OAAAgC,EAAA,EAAAhC,CAAAiC,KAAA8C,IACjBhD,EAAA/B,OAAAkC,EAAA,EAAAlC,CAAAiC,KAAAjC,OAAAmC,EAAA,EAAAnC,CAAA+E,GAAA3C,KAAAH,KAAMH,KAURkD,aAAe,YATbjD,EAAKM,MAAQ,CACXzC,OAAQ,KACR8E,OAAQ,GACR/D,SAAS,EACTsE,eAAgB,KAChB7F,MAAO,IAPQ2C,mFAaC,IAAAS,EAAAP,KACZ7C,EAlCe,mBAkCP8F,OAAOC,MAA6B,GAAMD,OAAOC,OAAS,GAElExE,EAA8C,SAApCyE,aAAaC,QAAQ,YAAyBpD,KAAKI,MAAM1B,QAIzE,GAFIvB,IAAOkG,SAASlG,MAAQA,GAExBmG,MAAMC,QAAQN,OAAOO,QACvB,OAAOxD,KAAKM,SAAS,CAAEnD,QAAOuB,UAASf,OAAQiF,EAASK,OAAOO,UAGjEC,IACGC,IAAI,UACJC,KAAK,SAAA7H,GAAA,IAAGoF,EAAHpF,EAAGoF,KAAH,OAAcX,EAAKD,SAAS,CAAEnD,QAAOuB,UAASf,OAAQiF,EAAS1B,kDAGtDwB,GACjB1C,KAAKM,SAAS,CACZmC,OAAQC,EACRM,eAlDe,SAACP,EAAQ9E,GAC5B,IAAK8E,EAAQ,OAAO,KAEpB,IAAMmB,EAAQpB,EAAaC,GAE3B,OAAO9E,EAAOkG,OACZ,SAAC/G,GAAD,OACE8G,EAAM9G,EAAMK,QACZyG,EAAM9G,EAAMI,QAAQE,OACpBwG,EAAM9G,EAAMI,QAAQlB,UAyCJ8H,CAAapB,EAAO1C,KAAKI,MAAMzC,iDAIpC+E,GACbS,aAAaY,QAAQ,UAAWrB,GAChC1C,KAAKM,SAAS,CACZ5B,QAASgE,qCAIJ,IAAAsB,EAAAhE,KAAAiE,EACoDjE,KAAKI,MAAxDzC,EADDsG,EACCtG,OAAQqF,EADTiB,EACSjB,eAAgB7F,EADzB8G,EACyB9G,MAAOsF,EADhCwB,EACgCxB,OAAQ/D,EADxCuF,EACwCvF,QAC/C,OAAKf,EAGHzB,EAAAC,EAAAC,cAAA,OAAKC,UAAU,QACbH,EAAAC,EAAAC,cAAA,cACEF,EAAAC,EAAAC,cAAA,UAAKe,GAAS6C,KAAK+C,cAClB5F,GAASjB,EAAAC,EAAAC,cAAA,SAAI4D,KAAK+C,eAErB7G,EAAAC,EAAAC,cAAA,OAAKC,UAAU,aACbH,EAAAC,EAAAC,cAAA,YACEF,EAAAC,EAAAC,cAAC8H,EAAD,CAAQvG,OAAQqF,GAAkBrF,KAEpCzB,EAAAC,EAAAC,cAAA,aACEF,EAAAC,EAAAC,cAAA,wBACAF,EAAAC,EAAAC,cAAA,WAASC,UAAU,UACjBH,EAAAC,EAAAC,cAAA,SACE+H,KAAK,SACL9H,UAAU,gBACV+H,YAAY,SACZ1B,MAAOD,EACP4B,SAAU,SAACC,GAAD,OAAON,EAAKO,mBAAmBD,EAAEE,OAAO9B,UAEpDxG,EAAAC,EAAAC,cAAA,QAAMC,UAAU,iBACdH,EAAAC,EAAAC,cAAA,aACEF,EAAAC,EAAAC,cAAA,SACE+H,KAAK,WACLM,QAAS/F,EACT2F,SAAU,SAACC,GAAD,OAAON,EAAKU,eAAeJ,EAAEE,OAAOC,YAJlD,+BASJvI,EAAAC,EAAAC,cAACuI,EAAD,CAAYjG,QAASA,EAASf,OAAQqF,GAAkBrF,OAhC5C,YA9CN2D,aCrBlBsD,IAASC,OAAO3I,EAAAC,EAAAC,cAAC0I,EAAD,MAASzB,SAAS0B,eAAe","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 this.onClick('body')}\n disabled={selected === 'body'}>\n body\n \n {schema && (\n this.onClick('schema')}\n disabled={selected === 'schema'}>\n schema\n \n )}\n {flowtype && (\n this.onClick('flowtype')}\n disabled={selected === 'flowtype'}>\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
\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 | --------------------------------------------------------------------------------