├── .babelrc
├── .eslintignore
├── .eslintrc.json
├── .gitignore
├── .travis.yml
├── README.md
├── __test__
├── index.test.js
├── schema.js
└── server.js
├── database
├── pgClient.js
└── queryString.js
├── dist
├── bundle.js
└── c022c33dc0ce3c799f135353a8ab8365.png
├── package-lock.json
├── package.json
├── public
├── bluegenesis.jpg
├── genQLdemo.mp4
├── genQLdemo_FINAL.gif
├── genesis.png
├── genesisCrop.png
├── genesisql.PNG
├── genesiswhite.png
├── index.html
└── searchicon.png
├── server
├── app.js
├── generatedApolloServer.js
├── server.js
└── utils
│ ├── create_templates
│ └── schema.js
│ ├── models
│ └── mongodb.js
│ ├── searchController.js
│ └── userController.js
├── src
├── App.jsx
├── components
│ ├── codeOutput.jsx
│ ├── dataView.jsx
│ ├── form.jsx
│ ├── inputField.jsx
│ ├── navBar.jsx
│ └── search.jsx
├── containers
│ ├── mainContainer.jsx
│ ├── productionContainer.jsx
│ └── schemaBuilderContainer.jsx
├── index.js
└── style.css
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/env", "@babel/preset-react"]
3 | }
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | !.eslintrc.js
2 | /node_modules
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "commonjs": true,
5 | "es6": true
6 | },
7 | "extends": [
8 | "airbnb"
9 | ],
10 | "globals": {
11 | "Atomics": "readonly",
12 | "SharedArrayBuffer": "readonly"
13 | },
14 | "parserOptions": {
15 | "ecmaFeatures": {
16 | "jsx": true
17 | },
18 | "ecmaVersion": 2018
19 | },
20 | "plugins": [
21 | "react"
22 | ],
23 | "rules": {
24 | }
25 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 |
84 | # Gatsby files
85 | .cache/
86 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
87 | # https://nextjs.org/blog/next-9-1#public-directory-support
88 | # public
89 |
90 | # vuepress build output
91 | .vuepress/dist
92 |
93 | # Serverless directories
94 | .serverless/
95 |
96 | # FuseBox cache
97 | .fusebox/
98 |
99 | # DynamoDB Local files
100 | .dynamodb/
101 |
102 | # TernJS port file
103 | .tern-port
104 |
105 | # courtesy of https://github.com/github/gitignore/blob/master/Node.gitignore
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "node"
4 | env:
5 | - PG_URI=postgres://juqdonnj:URk1eALCbIPa5tgs29o2Tzs9YkvgL_yx@salt.db.elephantsql.com:5432/juqdonnj
6 | - MONGO_URI=mongodb+srv://fake:pass@cluster0-8hzwr.mongodb.net/test
7 | # secure: "e0NIYT4SkfIaprrl6OXwtjD8LVsyvYUQIY1+YJebqio1guXnYrNXLK9O2etTDpnv4BBcivsuH/f8d1W/4Q8kfT4M9i8kwfhpbpczlqJ5E2ww8z0F22yXiqt5OgMQAHmObc7zEwCOXBUYX9t0wy/uv4zqU6As5eGBq3tP2FQcuvII4NXvVtfVuv09i2QoWZxrCNiX09ZxyLqhbA1rpZcGq9iDgFMySk4mYlTTXKoJsjNoQkyXmu6ToRUHr0J9ixSYIjx9KDes6ZMDhckQDCK1ncJa0Tru6XetUhXrjQxtZ77RJA44QT1uJOmCfIF4xK5JV8Rl8JK9Bx800Rrs3C+IqYCr99Xa6v7f/PJN39wFGzchiwIOa+s+WpJ5Kbjrh6cIheAKIAnV6oF1HcwNE7vIJ2u5upmK1dqGx19AYM1e935CtEwKjGajrv5prSCVcSeXslSCyDOoNr2rvawZUd/8H/N06DIdjRUOVoEbRxjakqj5rhYlJm7UV/3++ngOdsVV61YY18+dePDPOILfeV3/pPtC2QA/TJ9GPRH18ydR6c0ciL6fS24Sz7TTFJffkEv0nqXMPlf77T9BTBVCMWr5shLjnkioAZc+iFgpDoo+KULvwLZwmCikF8amqHX9h3QYDJCcSviw+idkXDnZ5YZ1GQmMue/M33oeCjl+f3sNYw4="
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | #
4 | [](https://lbesson.mit-license.org/)
5 | [](https://travis-ci.org/badges/badgerbadgerbadger)
6 | [](https://GitHub.com/Naereen/StrapDown.js/releases/)
7 | [](https://github.com/ellerbrock/open-source-badges/)
8 |
9 | # genesisQL
10 | [genesisQL](http://www.genesisql.com/) is **an open-source web-application that enables rapid schema-prototyping of GraphQL applications**, making your development process easier & faster. Made for developers, by developers.
11 |
12 | Created by [Adam Goren](https://github.com/adamgoren), [Tom Herrmann](https://github.com/TomHerrmann), [Xose Manolo](https://github.com/xosemanolo), and [Andrew Paisner](https://github.com/apaisner).
13 |
14 |
15 |
16 | See the full demo video here: [genesisQL Walkthrough](https://vimeo.com/374757326)
17 |
18 | ## Features
19 | - Generate graphQL schemas, types, and queries, through an intuitive graphical user interface (GUI)
20 | - Easily select which fields you'd like to use in your schema, from an automatically generated dropdown menu
21 | - Ability to specify whether fields are required or not
22 | - View data retrieved from API urls with a single search, in app
23 | - Copy generated schema code to clipboard with a single button click
24 | - Outputted code can be used to set-up/run a functional apollo-server, and access the graphQL playground
25 |
26 | ## Usage
27 | 1) Visit our website: [genesisQL Beta](http://www.genesisql.com/)
28 | 2) Enter an endpoint to retrieve your data from (e.g. https://swapi.co/api/people/2/)
29 | 3) Enter a name for your object type, and select input field names & types from the dropdown menu. Toggle if needed
30 | 4) Use the '+' button to add more fields as needed
31 | 5) Press submit to generate your schema output
32 | 6) Use the copy button to quickly select the outputted code, and paste it into your project folder as a new file
33 | 7) Install apollo server using a package manager of your choice: e.g. 'npm i apollo-server --save'
34 | 8) Simply run the new file, and the graphQL playground will appear
35 |
36 | ## Example Code Output
37 | ```javascript
38 | const { ApolloServer, gql } = require('apollo-server');
39 |
40 | const typeDefs = gql`
41 |
42 | type starwars_traits {
43 | name: String!
44 | mass: Int
45 | homeworld: String
46 | }
47 |
48 | type Query {
49 | getAllstarwars_traits: [starwars_traits]
50 | getstarwars_traitsById(id: ID!): starwars_traits
51 | }
52 |
53 | type Mutation {
54 | addstarwars_traits(name: String!, mass: Int, homeworld: String, ): Boolean
55 | updatestarwars_traits(name: String!, mass: Int, homeworld: String, ): Boolean
56 | deletestarwars_traits(id: ID): Boolean
57 | }
58 |
59 | `;
60 |
61 | const resolvers = {
62 | };
63 |
64 | const port = process.env.PORT || 4000; // defaults to port 4000
65 | const server = new ApolloServer({ typeDefs, resolvers });
66 |
67 | server.listen({ port }).then(({ url }) => {
68 | console.log(`🚀 Server listening at ${url}`);
69 | });
70 | ```
71 |
72 | ## Contributing
73 |
74 | > To get started...
75 |
76 | ### Step 1
77 |
78 | - **Option 1**
79 | - 🍴 Fork this repo!
80 |
81 | - **Option 2**
82 | - 👯 Clone this repo to your local machine using `https://github.com/joanaz/HireDot2.git`
83 |
84 | ### Step 2
85 |
86 | - **HACK AWAY!** 🔨🔨🔨
87 |
88 | ### Step 3
89 |
90 | - 🔃 Create a new pull request using `https://github.com/oslabs-beta/genesisQL/compare`.
91 |
--------------------------------------------------------------------------------
/__test__/index.test.js:
--------------------------------------------------------------------------------
1 | require('./schema.js');
2 | require('./server.js');
3 |
--------------------------------------------------------------------------------
/__test__/schema.js:
--------------------------------------------------------------------------------
1 | let schemaGen = require('../server/utils/create_templates/schema.js');
2 |
3 | function sum(a, b) {
4 | return a + b;
5 | }
6 | // console.log(schemaGen);
7 |
8 | // for testing purposes
9 |
10 |
11 | // const objectTypes;
12 |
13 | // const objectType1 = {
14 | // objTypeName: 'User',
15 | // fieldNames: ['id', 'name'],
16 | // fieldTypes: ['Int', 'String'],
17 | // };
18 | // const objectType2 = {
19 | // objTypeName: 'Pet',
20 | // fieldNames: ['id', 'name'],
21 | // fieldTypes: ['Int', 'String'],
22 | // };
23 |
24 | // objectTypes = [objectType1, objectType2];
25 | describe('Schema Generator Unit Tests', () => {
26 | let objectTypes;
27 | beforeEach( ()=> {
28 | const objectType1 = {
29 | objTypeName: 'User',
30 | fieldNames: ['id', 'name'],
31 | fieldTypes: ['Int', 'String'],
32 | };
33 | const objectType2 = {
34 | objTypeName: 'Pet',
35 | fieldNames: ['id', 'name'],
36 | fieldTypes: ['Int', 'String'],
37 | };
38 |
39 | objectTypes = [objectType1, objectType2];
40 | })
41 |
42 | it('Testing type output of schema gen function', () => {
43 | // console.log(schemaGen);
44 | expect(schemaGen(objectTypes)).toEqual(expect.stringMatching(/.*type.*/));
45 | });
46 | })
--------------------------------------------------------------------------------
/__test__/server.js:
--------------------------------------------------------------------------------
1 |
2 | const request = require("supertest");
3 | const assert = require("assert");
4 | const app = require("../server/server.js");
5 | // const request = supertest(app);
6 |
7 | describe('Test the root path', () => {
8 | it('It should response the GET method', () => {
9 | return request(app).get('/').expect(200);
10 | });
11 | })
--------------------------------------------------------------------------------
/database/pgClient.js:
--------------------------------------------------------------------------------
1 | const { Pool } = require('pg');
2 | const queryString = require('./queryString.js')
3 |
4 | const myURI = 'postgres://juqdonnj:URk1eALCbIPa5tgs29o2Tzs9YkvgL_yx@salt.db.elephantsql.com:5432/juqdonnj';
5 |
6 | const URI = process.env.PG_URI || myURI;
7 |
8 | const pool = new Pool({ connectionString: URI });
9 |
10 | // creates users table
11 | pool.query(queryString.createUserTable, (err, result) => {
12 |
13 | if(err) console.error('FIRST error', err);
14 | else {
15 | // console.log('TABLE users EXISTS')
16 | }
17 | });
18 |
19 | module.exports = pool;
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/database/queryString.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | createUserTable: `CREATE TABLE IF NOT EXISTS users (_id SERIAL PRIMARY KEY, username VARCHAR, password VARCHAR)`,
3 | createSearchTable: `CREATE TABLE IF NOT EXISTS searches (_id SERIAL PRIMARY KEY, url VARCHAR, result VARCHAR)`,
4 | postSearchTable: `INSERT INTO searches (url, result) VALUES($1, $2)`,
5 | queryLogging: function (){
6 | console.log('\n*********** visitsController.createVisit ****************', `\nMETHOD: ${req.method} \nENDPOINT: '${req.url}' \nBODY: ${JSON.stringify(req.body)} \nLOCALS: ${JSON.stringify(res.locals)} `);
7 | }
8 |
9 | }
--------------------------------------------------------------------------------
/dist/c022c33dc0ce3c799f135353a8ab8365.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/genesisQL/141351af4caaf730c6111e3c66a25d1676c22893/dist/c022c33dc0ce3c799f135353a8ab8365.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "genesisql",
3 | "version": "1.0.0",
4 | "description": "Generates GraphQL schema WITH EASE",
5 | "main": "index.js",
6 | "scripts": {
7 | "serve": "nodemon server/server.js",
8 | "dev": "npm run serve & webpack-dev-server --mode development --open",
9 | "start": "node server/server.js",
10 | "build": "webpack --mode production",
11 | "test": "mocha __test__/server.js"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/oslabs-beta/GenesisQL.git"
16 | },
17 | "keywords": [
18 | "GraphQL",
19 | "schema"
20 | ],
21 | "author": "",
22 | "license": "ISC",
23 | "bugs": {
24 | "url": "https://github.com/oslabs-beta/GenesisQL/issues"
25 | },
26 | "homepage": "https://github.com/oslabs-beta/GenesisQL#readme",
27 | "devDependencies": {
28 | "@babel/cli": "^7.10.3",
29 | "@babel/core": "^7.10.3",
30 | "@babel/preset-env": "^7.10.3",
31 | "@babel/preset-react": "^7.10.1",
32 | "babel-cli": "^6.26.0",
33 | "babel-loader": "^8.1.0",
34 | "babel-preset-env": "^1.7.0",
35 | "css-loader": "^3.6.0",
36 | "eslint": "^6.6.0",
37 | "eslint-config-airbnb": "^18.2.0",
38 | "eslint-plugin-import": "^2.21.2",
39 | "eslint-plugin-jsx-a11y": "^6.3.1",
40 | "eslint-plugin-react": "^7.20.0",
41 | "eslint-plugin-react-hooks": "^1.7.0",
42 | "file-loader": "^4.2.0",
43 | "jest": "^24.9.0",
44 | "jshint": "^2.11.1",
45 | "mocha": "^6.2.3",
46 | "nodemon": "^1.19.4",
47 | "style-loader": "^1.2.1",
48 | "superagent": "^5.2.2",
49 | "supertest": "^4.0.2",
50 | "webpack": "^4.43.0",
51 | "webpack-cli": "^3.3.12",
52 | "webpack-dev-server": "^3.11.0"
53 | },
54 | "dependencies": {
55 | "@material-ui/core": "^4.10.2",
56 | "@material-ui/icons": "^4.9.1",
57 | "@material-ui/lab": "^4.0.0-alpha.56",
58 | "apollo-server": "^2.15.0",
59 | "body-parser": "^1.19.0",
60 | "cookie-parser": "^1.4.5",
61 | "dotenv": "^8.2.0",
62 | "express": "^4.17.1",
63 | "express-graphql": "^0.9.0",
64 | "graphql": "^14.6.0",
65 | "jest": "^24.9.0",
66 | "mongodb": "^3.5.9",
67 | "mongoose": "^5.9.20",
68 | "node-fetch": "^2.6.0",
69 | "notistack": "^0.9.17",
70 | "pg": "^7.18.2",
71 | "react": "^16.13.1",
72 | "react-copy-to-clipboard": "^5.0.2",
73 | "react-dom": "^16.13.1",
74 | "react-hot-loader": "^4.12.21",
75 | "react-toasts": "^3.0.6",
76 | "typeface-roboto": "0.0.75"
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/public/bluegenesis.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/genesisQL/141351af4caaf730c6111e3c66a25d1676c22893/public/bluegenesis.jpg
--------------------------------------------------------------------------------
/public/genQLdemo.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/genesisQL/141351af4caaf730c6111e3c66a25d1676c22893/public/genQLdemo.mp4
--------------------------------------------------------------------------------
/public/genQLdemo_FINAL.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/genesisQL/141351af4caaf730c6111e3c66a25d1676c22893/public/genQLdemo_FINAL.gif
--------------------------------------------------------------------------------
/public/genesis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/genesisQL/141351af4caaf730c6111e3c66a25d1676c22893/public/genesis.png
--------------------------------------------------------------------------------
/public/genesisCrop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/genesisQL/141351af4caaf730c6111e3c66a25d1676c22893/public/genesisCrop.png
--------------------------------------------------------------------------------
/public/genesisql.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/genesisQL/141351af4caaf730c6111e3c66a25d1676c22893/public/genesisql.PNG
--------------------------------------------------------------------------------
/public/genesiswhite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/genesisQL/141351af4caaf730c6111e3c66a25d1676c22893/public/genesiswhite.png
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | GraphQL Schema Generator - Data Graph Prototyping - genesisQL
7 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/public/searchicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/genesisQL/141351af4caaf730c6111e3c66a25d1676c22893/public/searchicon.png
--------------------------------------------------------------------------------
/server/app.js:
--------------------------------------------------------------------------------
1 | // require in libraries
2 | const express = require('express');
3 | const { ApolloServer } = require('apollo-server');
4 | const path = require('path');
5 | const fetch = require('node-fetch');
6 | const bodyParser = require('body-parser');
7 | const cookieParser = require('cookie-parser');
8 | const searchController = require('./utils/searchController.js');
9 | const schemaGen = require('./utils/create_templates/schema.js');
10 |
11 | const graphQLschema = require('./utils/create_templates/schema.js');
12 |
13 | require('dotenv').config();
14 |
15 | // console.log('PROCESS ENV', process.env);
16 |
17 | // create our server
18 | const app = express();
19 | const port = process.env.PORT || 3000;
20 |
21 | // handle incoming objects
22 | app.use(bodyParser());
23 | app.use(cookieParser());
24 | app.use(express.json());
25 | // handles post data
26 | app.use(bodyParser.urlencoded({ extended: true }));
27 |
28 | /* Handles getting data and send it back to clients */
29 |
30 | app.post(
31 | '/search',
32 | searchController.fetch,
33 | /* searchController.post, */ (req, res) => {
34 | // console.log('RESPONSE LOCALS FETCHED DATA', res.locals.fetch);
35 | // const { fetch } = res.locals
36 | res.status(200).send(res.locals.fetch);
37 | }
38 | );
39 |
40 | // TO GENERATE CODE app.post('/code', )
41 | app.post('/code', (req, res) => {
42 | const { objectTypes } = req.body;
43 |
44 | // console.log(req.body);
45 |
46 | // console.log(req.body);
47 |
48 | res.set('Content-Type', 'application/json');
49 | res.send(JSON.stringify(schemaGen(objectTypes)));
50 | });
51 |
52 | // serves PRODUCTION bundle
53 | app.use('/dist', express.static(path.resolve(__dirname, '../dist')));
54 |
55 | // serves static developemnt files (/public) - DEV
56 | app.use('/', (req, res, next) => {
57 | res.sendFile(path.resolve(__dirname, '../public/index.html'));
58 | });
59 |
60 | module.exports = {
61 | app,
62 | port,
63 | };
64 |
--------------------------------------------------------------------------------
/server/generatedApolloServer.js:
--------------------------------------------------------------------------------
1 | const { ApolloServer, gql } = require('apollo-server');
2 |
3 | const typeDefs = gql`
4 |
5 | type people {
6 | name: String
7 | mass: Int
8 | }
9 |
10 | type Query {
11 | getAllpeople: [people]
12 | getpeopleById(id: ID!): people
13 | }
14 |
15 | type Mutation {
16 | addpeople(name: String, mass: Int, ): Boolean
17 | updatepeople(name: String, mass: Int, ): Boolean
18 | deletepeople(id: ID): Boolean
19 | }
20 |
21 | `;
22 |
23 | const resolvers = {
24 | };
25 |
26 | const port = process.env.PORT || 4000; // defaults to port 4000
27 | const server = new ApolloServer({ typeDefs, resolvers });
28 |
29 | server.listen({ port }).then(({ url }) => {
30 | console.log(`🚀 Server listening at ${url}`);
31 | });
32 |
--------------------------------------------------------------------------------
/server/server.js:
--------------------------------------------------------------------------------
1 | const { app, port } = require('./app');
2 | // sets development port
3 | const server = app.listen(port, () => console.log(`listening on port ${port}`));
4 |
5 | module.exports = server;
6 |
--------------------------------------------------------------------------------
/server/utils/create_templates/schema.js:
--------------------------------------------------------------------------------
1 | const tab = ' ';
2 |
3 | // may need to sanitize user inputs for types (e.g. string -> String, number -> Int)
4 | function createSchema(objectTypes) {
5 | let result = '';
6 |
7 | // create import string, start type def with backtick (`)
8 | result += importApolloServer();
9 |
10 | // create object type strings
11 | for (const objectType of objectTypes) {
12 | result += createObjType(objectType);
13 | }
14 |
15 | // create query strings
16 | result += `${tab}type Query {\n`;
17 | for (const objectType of objectTypes) {
18 | result += createRootQuery(objectType);
19 | }
20 | result += `${tab}}\n\n`;
21 |
22 | // create mutation strings
23 | result += `${tab}type Mutation {\n`;
24 | for (const objectType of objectTypes) {
25 | result += createMutation(objectType);
26 | }
27 | result += `${tab}}\n\n`;
28 |
29 | // create resolver string
30 | result += createResolvers();
31 |
32 | // close typedef with backtick (`), create server string
33 | result += createApolloServer();
34 |
35 | // return final fully concatenated string
36 | return result;
37 | }
38 | // console.log(createSchema(objectTypes));
39 |
40 | function createRootQuery(objectType) {
41 | const { objTypeName, fieldNames, fieldTypes } = objectType;
42 | let result = '';
43 | result += `${tab}${tab}getAll${objTypeName}: [${objTypeName}]\n`;
44 | result += `${tab}${tab}get${objTypeName}ById(id: ID!): ${objTypeName}\n`;
45 | return result;
46 | }
47 | // console.log(createRootQuery(objectType));
48 |
49 | function createMutation(objectType) {
50 | const { objTypeName, fieldNames, fieldTypes } = objectType;
51 | let result = '';
52 | let args = '';
53 | for (let i = 0; i < fieldNames.length; i++) {
54 | args += `${fieldNames[i]}: ${fieldTypes[i]}, `;
55 | }
56 | result += `${tab}${tab}add${objTypeName}(${args}): Boolean\n`;
57 | result += `${tab}${tab}update${objTypeName}(${args}): Boolean\n`;
58 | result += `${tab}${tab}delete${objTypeName}(id: ID): Boolean\n`;
59 | return result;
60 | }
61 | // console.log(createMutation(objectType));
62 |
63 | function createObjType(objectType) {
64 | let result = '';
65 | const { objTypeName, fieldNames, fieldTypes } = objectType;
66 | result += `${tab}type ${objTypeName} {\n`;
67 | for (let i = 0; i < fieldNames.length; i++) {
68 | result += `${tab}${tab}${fieldNames[i]}: ${fieldTypes[i]}\n`;
69 | }
70 | result += `${tab}}\n\n`;
71 | return result;
72 | }
73 |
74 | function createResolvers() {
75 | let result = '';
76 | result += `${tab}\`; \n\n`;
77 | result += `${tab}const resolvers = {\n`;
78 | // result += `${tab}${tab}fieldName: (parent, args, context, info) => data;\n`;
79 | result += `${tab}};\n\n`;
80 | return result;
81 | }
82 |
83 | // importing our apollo server
84 | function importApolloServer() {
85 | let result = '';
86 | result += `${tab}const { ApolloServer, gql } = require('apollo-server');\n\n`;
87 | result += `${tab}const typeDefs = gql\` \n\n`;
88 | return result;
89 | }
90 |
91 | // creating our apollo server
92 | function createApolloServer() {
93 | let result = '';
94 | result += `${tab}const port = process.env.PORT || 4000; // defaults to port 4000 \n`;
95 | result += `${tab}const server = new ApolloServer({ typeDefs, resolvers });\n\n`;
96 | result += `${tab}server.listen({ port }).then(({ url }) => {\n`;
97 | result += `${tab}${tab}console.log(\`🚀 Server listening at \${url}\`);\n`;
98 | result += `${tab}});`;
99 | return result;
100 | }
101 |
102 | // console.log(createObjType(objectType));
103 |
104 | module.exports = createSchema;
105 |
--------------------------------------------------------------------------------
/server/utils/models/mongodb.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 |
3 | const myURI = 'mongodb+srv://fake:pass@cluster0-8hzwr.mongodb.net/test';
4 |
5 | mongoose.connect(myURI, { useNewUrlParser: true, useUnifiedTopology: true });
6 |
7 | mongoose.connection.once('open', () => {
8 | console.log('Connected to DB');
9 | })
10 |
11 | // const testSchema = new mongoose.Schema({ test: { type: 'String' } });
12 | // const testModel = mongoose.model('Test', testSchema);
13 | // new testModel({ test: '1' }).save()
--------------------------------------------------------------------------------
/server/utils/searchController.js:
--------------------------------------------------------------------------------
1 | const fetch = require('node-fetch');
2 | const pgClient = require('../../database/pgClient.js');
3 | const queryString = require('../../database/queryString.js');
4 |
5 | const searchController = {};
6 | // searchController is the express middleware that handles the req
7 | // from the searchbar
8 |
9 | pgClient.query(queryString.createSearchTable, (err, result) => {
10 | if (err) console.error('FIRST error', err);
11 | else {
12 | // console.log('TABLE searches EXISTS');
13 | }
14 | });
15 |
16 | searchController.fetch = (req, res, next) => {
17 | const { url } = req.body;
18 | // console.log(url);
19 | fetch(url)
20 | .then((data) =>
21 | // console.log(data);
22 | data.json())
23 | .then((result) => {
24 | // console.log('RESULT IN THE SERVER CONTROLLER', result);
25 | res.locals.fetch = result;
26 | return next();
27 | })
28 | .catch((err) => next(err));
29 | };
30 | // Unit test for fetch func
31 | // TODO: move to test file
32 | // let req = {}
33 | // req.body = {url: 'https://swapi.co/api/people/1/'}
34 | // let res = {};
35 | // res.locals = {};
36 | // searchController.fetch(req, res, () => {});
37 |
38 | searchController.post = (req, res, next) => {
39 | const { url } = req.body;
40 | const values = [`${url}`, `${res.locals.fetch}`];
41 | pgClient.query(queryString.postSearchTable, values, (err, result) => {
42 | console.log(values);
43 | if (err) next(err);
44 | else {
45 | // console.log(`Cached Response from URL: ${url}`);
46 | res.send('Complete');
47 | return next();
48 | }
49 | });
50 | };
51 |
52 | // searchController.post(req, res, () => {});
53 | module.exports = searchController;
54 |
--------------------------------------------------------------------------------
/server/utils/userController.js:
--------------------------------------------------------------------------------
1 | const pgClient = require('../../database/pgClient.js');
2 | // import queryString from '../../database/queryString.js';
3 |
4 | function createNewUser (req, res, next) {
5 | const { username, password } = req.body;
6 | const text = `INSERT INTO users (username, password) VALUES($1, $2)`;
7 | const values = [`${username}`, `${password}`];
8 | pgClient.query(text, values, (err, result) => {
9 | if(err) next(err);
10 | next();
11 | console.log('users', result.rows[0]);
12 | })
13 | }
14 |
15 | let req = {};
16 | req.body = {
17 | username: 'bob',
18 | password: 'frank'
19 | }
20 |
21 | createNewUser(req, undefined ,() => {})
22 |
23 | function checkPassword (req, res, next){
24 | const { username, password } = req.body;
25 | // const values = [];
26 | const text = `SELECT * FROM users WHERE username='${username}' AND password='${password}'`;
27 | pgClient.query(text, [], (err, result) => {
28 | if(err) next(err);
29 | if(result.rowCount === 0){
30 | //send message when we have wrong username or password
31 | res.send('wrong username or password')
32 | }else{
33 | next();
34 | }
35 | })
36 | }
37 | // let req = {};
38 | // req.body = {
39 | // username: 'bobs',
40 | // password: 'frank'
41 | // }
42 |
43 | // checkPassword(req, undefined ,() => {})
44 |
45 | function updateUser (req, res, next) {
46 | const { username, password } = req.body;
47 | const text = `UPDATE users SET password= $2 WHERE username= $1`;
48 | const values = [`${username}`, `${password}`];
49 | pgClient.query(text, values, (err, result) => {
50 | if(err) next(err);
51 | // console.log('inside and deep')
52 | next();
53 | })
54 | }
55 | // let req = {};
56 | // req.body = {
57 | // username: 'bob',
58 | // password: 'franks'
59 | // }
60 |
61 | // updateUser(req, undefined,() => {})
62 |
63 | function deleteUser (req, res, next) {
64 | const { username } = req.body;
65 | const text = `DELETE FROM users WHERE username=$1`;
66 | const value = [`${username}`];
67 | pgClient.query(text, value, (err, result) => {
68 | if(err) next(err);
69 | console.log('deleted')
70 | })
71 | }
72 | // let req = {};
73 | // req.body = {
74 | // username: 'bob',
75 | // password: 'frank'
76 | // }
77 |
78 | // deleteUser(req, undefined ,() => {})
79 |
80 |
--------------------------------------------------------------------------------
/src/App.jsx:
--------------------------------------------------------------------------------
1 | /**
2 | * ***********************************
3 | *
4 | * @module App
5 | * @author Tom Herrmann and Adam Goren
6 | * @date 10/29/2019
7 | * @description Top-level app component that renders Search and MainContainer Components
8 | *
9 | * ***********************************
10 | */
11 |
12 | import React, { Component } from 'react';
13 | import { hot } from 'react-hot-loader';
14 | import './style.css';
15 | import Icon from '@material-ui/core/Icon';
16 |
17 | // component imports
18 | import { json } from 'body-parser';
19 | import Search from './components/search';
20 | import MainContainer from './containers/mainContainer';
21 | import InputField from './components/inputField';
22 |
23 |
24 | class App extends Component {
25 | constructor(props) {
26 | super(props);
27 | // defines App state
28 | this.state = {
29 | dataViewContent: '',
30 | currentTab: 'schemaBuilderTab',
31 | loading: false,
32 | inputFields: [],
33 | formSwitches: [false],
34 | codeGeneratedString: '',
35 | };
36 | // binding methods to constructor
37 | this.dataPOSTRequest = this.dataPOSTRequest.bind(this);
38 | this.changeCurrentTab = this.changeCurrentTab.bind(this);
39 | this.handleNewFields = this.handleNewFields.bind(this);
40 | this.handleSwitchChange = this.handleSwitchChange.bind(this);
41 | this.handleFormSubmitButton = this.handleFormSubmitButton.bind(this);
42 | }
43 |
44 | changeCurrentTab(event, value) {
45 | switch (value) {
46 | case 'schemaBuilderTab':
47 | this.setState({ currentTab: 'schemaBuilderTab' });
48 | // console.log('CHANGING CURRENT TAB TO SCB');
49 | break;
50 | case 'codeOutputTab':
51 | this.setState({ currentTab: 'codeOutputTab' });
52 | // console.log('CHANGING CURRENT TAB TO CO');
53 | break;
54 | default:
55 | this.setState({ currentTab: 'schemaBuilderTab' });
56 | }
57 | }
58 |
59 | // methods to pass as props
60 | dataPOSTRequest(data) {
61 | if (!data) return;
62 | this.setState({ loading: true });
63 | // console.log('dataPOSTRequest INPUT FIELD', data);
64 | // console.log('JSON DATA', JSON.stringify(data))
65 | fetch('/search', {
66 | method: 'POST',
67 | headers: {
68 | 'Content-Type': 'application/json',
69 | },
70 | body: JSON.stringify({ url: data }),
71 | })
72 | .then((data) =>
73 | // console.log('data', data)
74 | data.json())
75 | .then((result) => {
76 | this.setState({ dataViewContent: result, loading: false });
77 | // console.log(result)
78 | })
79 | .catch((err) => (console.log('ERROR', err)));
80 | }
81 |
82 | handleNewFields() {
83 | const newFieldIndex = this.state.inputFields.length + 1;
84 |
85 | const inputFieldsCopy = this.state.inputFields.slice(0);
86 | inputFieldsCopy.push();
87 |
88 | const formSwitchesCopy = this.state.formSwitches.slice(0);
89 | formSwitchesCopy.push(false);
90 |
91 | this.setState({ inputFields: inputFieldsCopy, formSwitches: formSwitchesCopy });
92 | }
93 |
94 | handleSwitchChange(event, value) {
95 | const switchIndex = Number(event.target.name.split('-')[1]);
96 | const formSwitchesCopy = this.state.formSwitches.slice(0);
97 | formSwitchesCopy[switchIndex] = value;
98 | this.setState({ formSwitches: formSwitchesCopy });
99 | }
100 |
101 | handleFormSubmitButton() {
102 | const objectType = document.querySelector('.objectType').value;
103 |
104 | const fieldNames = [];
105 | document.querySelectorAll('.fieldNames').forEach(
106 | (el) => fieldNames.push(el.value),
107 | );
108 | const fieldTypes = [];
109 | document.querySelectorAll('.fieldTypes').forEach(
110 | (el, index) => {
111 | // console.log('ELEMENT IN FIELD TYPE LOOP -->', el.value, index)
112 | if (this.state.formSwitches[index] === true) fieldTypes.push(`${el.value}!`);
113 | else fieldTypes.push(el.value);
114 | },
115 | );
116 |
117 | // CREATE PAYLOAD OBJECT TO SEND TO CODE-GENERATOR SERVER-SIDE
118 | const codeGenPayload = {
119 | objectTypes: [
120 | {
121 | objTypeName: objectType,
122 | fieldNames,
123 | fieldTypes,
124 | },
125 | ],
126 | };
127 | // console.log('codeGenPayload:', codeGenPayload);
128 |
129 | // SEND FETCH REQUEST TO CODE-GEN ENDPOINT, WITH PAYLOAD
130 | fetch('/code', {
131 | method: 'POST',
132 | headers: {
133 | 'Content-Type': 'application/json',
134 | Accept: 'application/json',
135 | },
136 | body: JSON.stringify(codeGenPayload),
137 | })
138 | .then((data) => data.json())
139 | .then((data) => {
140 | // console.log('data', data);
141 | // SETTING STATE
142 | this.setState({ codeGeneratedString: data, currentTab: 'codeOutputTab' });
143 | // console.log('state is:', this.state);
144 | });
145 | }
146 |
147 | render() {
148 | console.log('FORM SWITHC ARRAY IN APP -->', this.state.formSwitches);
149 | return (
150 |
151 |
})
152 |
153 |
165 |
166 | );
167 | }
168 | }
169 |
170 | export default hot(module)(App);
171 |
--------------------------------------------------------------------------------
/src/components/codeOutput.jsx:
--------------------------------------------------------------------------------
1 | /**
2 | * ***********************************
3 | *
4 | * @module CodeOutput
5 | * @author Tom Herrmann and Adam Goren
6 | * @date 10/29/2019
7 | * @description Schema code output based on form inputs
8 | *
9 | * ***********************************
10 | */
11 |
12 | import React, { Component } from 'react';
13 | import { CopyToClipboard } from 'react-copy-to-clipboard';
14 |
15 | import FileCopyIcon from '@material-ui/icons/FileCopy';
16 | import Fab from '@material-ui/core/Fab';
17 |
18 | import { withSnackbar } from 'notistack';
19 |
20 | class CodeOutput extends Component {
21 | render() {
22 | return (
23 |
24 |
25 |
{this.props.codeGeneratedString}
26 |
27 |
28 |
29 | { this.props.enqueueSnackbar('Schema copied!'); }}
35 | >
36 |
37 |
38 |
39 |
40 |
41 | );
42 | }
43 | }
44 |
45 | export default withSnackbar(CodeOutput);
46 |
--------------------------------------------------------------------------------
/src/components/dataView.jsx:
--------------------------------------------------------------------------------
1 | /**
2 | * ***********************************
3 | *
4 | * @module DataView
5 | * @author Tom Herrmann and Adam Goren
6 | * @date 10/29/2019
7 | * @description Display of data fetched from data collection
8 | *
9 | * ***********************************
10 | */
11 |
12 | import React, { Component } from 'react';
13 | import CircularProgress from '@material-ui/core/CircularProgress';
14 |
15 | class DataView extends Component {
16 | constructor(props) {
17 | super(props);
18 | }
19 |
20 | render() {
21 | // console.log('loading exists', this.props.loading);
22 | // console.log('DISPLAY CONTENT', this.props.displayContent);
23 | return (
24 |
25 |
28 |
29 |
{this.props.loading ? : this.props.dataViewContent ? JSON.stringify(this.props.dataViewContent, null, 2) : null}
30 |
31 |
32 | );
33 | }
34 | }
35 |
36 | export default DataView;
37 |
--------------------------------------------------------------------------------
/src/components/form.jsx:
--------------------------------------------------------------------------------
1 | /**
2 | * ***********************************
3 | *
4 | * @module Form
5 | * @author Tom Herrmann and Adam Goren
6 | * @date 10/29/2019
7 | * @description Form for selecting which data is submitted in schema
8 | * @dataListSource https://blog.teamtreehouse.com/creating-autocomplete-dropdowns-datalist-element
9 | * ***********************************
10 | */
11 |
12 | import React, { Component } from 'react';
13 | import InputField from './inputField';
14 | import Fab from '@material-ui/core/Fab';
15 | import AddIcon from '@material-ui/icons/Add';
16 | import Button from '@material-ui/core/Button';
17 |
18 | class Form extends Component {
19 | constructor(props) {
20 | super(props);
21 | }
22 |
23 | render() {
24 | return (
25 |
59 | );
60 | }
61 | }
62 |
63 | export default Form;
64 |
--------------------------------------------------------------------------------
/src/components/inputField.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Switch from '@material-ui/core/Switch';
3 |
4 | class InputField extends Component {
5 | constructor(props) {
6 | super(props);
7 | }
8 |
9 | render() {
10 | console.log('FIELD INDEX FROM INPUT FIELD COMPONENT -->', this.props.fieldIndex)
11 | const formDataTypes = {};
12 | const { dataViewContent } = this.props;
13 | for (const key in dataViewContent) {
14 | let type = '';
15 | switch (typeof dataViewContent[key]) {
16 | case 'string':
17 | type = 'String';
18 | break;
19 | case 'number':
20 | type = 'Int';
21 | break;
22 | case 'boolean':
23 | type = 'Boolean';
24 | break;
25 | case 'object':
26 | type = 'Custom';
27 | break;
28 | }
29 | formDataTypes[key] = type;
30 | }
31 |
32 | const formDataTypesKeys = Object.keys(formDataTypes);
33 | const graphQLTypes = ['String', 'Int', 'Boolean', 'Custom Type'];
34 |
35 | const formInputOptions = [];
36 | for (let i = 0; i < formDataTypesKeys.length; i++) {
37 | formInputOptions.push();
38 | }
39 | const formTypesOptions = [];
40 | for (let i = 0; i < graphQLTypes.length; i++) {
41 | formTypesOptions.push();
42 | }
43 | return (
44 | // https://reactjs.org/docs/forms.html
45 |
46 |
52 |
58 |
69 |
70 | )
71 | }
72 | }
73 | export default InputField
74 |
--------------------------------------------------------------------------------
/src/components/navBar.jsx:
--------------------------------------------------------------------------------
1 | /**
2 | * ***********************************
3 | *
4 | * @module NavBar
5 | * @author Tom Herrmann and Adam Goren
6 | * @date 10/29/2019
7 | * @description Select what to display in the production container by clicking a series of buttons
8 | *
9 | * ***********************************
10 | */
11 |
12 | import React, { Component } from 'react';
13 | import Tabs from '@material-ui/core/Tabs';
14 | import Tab from '@material-ui/core/Tab';
15 |
16 | class NavBar extends Component {
17 | constructor(props) {
18 | super(props);
19 | }
20 |
21 | render() {
22 | return (
23 |
24 |
25 |
31 |
32 |
33 |
34 |
35 |
36 | );
37 | }
38 | }
39 |
40 | export default NavBar;
41 |
--------------------------------------------------------------------------------
/src/components/search.jsx:
--------------------------------------------------------------------------------
1 | /**
2 | * ***********************************
3 | *
4 | * @module Search
5 | * @author Tom Herrmann and Adam Goren
6 | * @date 10/29/2019
7 | * @description Search bar to perform GET requests on various data collections
8 | *
9 | * ***********************************
10 | */
11 |
12 | import React, { Component } from 'react';
13 | import Button from '@material-ui/core/Button';
14 |
15 | class Search extends Component {
16 | constructor(props) {
17 | super(props);
18 | }
19 |
20 | render() {
21 | return (
22 |
23 |
37 |
38 | {/*
52 |
53 | );
54 | }
55 | }
56 |
57 | export default Search;
58 |
--------------------------------------------------------------------------------
/src/containers/mainContainer.jsx:
--------------------------------------------------------------------------------
1 | /**
2 | * ***********************************
3 | *
4 | * @module MainContainer
5 | * @author Tom Herrmann and Adam Goren
6 | * @date 10/29/2019
7 | * @description Main app container, rendering all components for creating GraphQL schema
8 | *
9 | * ***********************************
10 | */
11 |
12 | import React, { Component } from 'react';
13 |
14 | // component imports
15 | import NavBar from '../components/navBar';
16 | import ProductionContainer from './productionContainer';
17 |
18 |
19 | class MainContainer extends Component {
20 | constructor(props) {
21 | super(props);
22 | }
23 |
24 | // changes the current tab state to swich displays from SchemaBuilderContainer to CodeOutput
25 |
26 |
27 | // when user clicks submit button in 'Form', sends data to back-end
28 |
29 |
30 | render() {
31 | return (
32 |
33 | {/*
'MainContainer Component'
*/}
34 |
38 |
48 |
49 | );
50 | }
51 | }
52 |
53 | export default MainContainer;
54 |
--------------------------------------------------------------------------------
/src/containers/productionContainer.jsx:
--------------------------------------------------------------------------------
1 | /**
2 | * ***********************************
3 | *
4 | * @module ProductionContainer
5 | * @author Tom Herrmann and Adam Goren
6 | * @date 10/29/2019
7 | * @description Container displaying fields based on tab menu selection from NavBar
8 | *
9 | * ***********************************
10 | */
11 |
12 | import React, { Component } from 'react';
13 | import SchemaBuilderContainer from './schemaBuilderContainer';
14 | import CodeOutput from '../components/codeOutput';
15 |
16 | class ProductionContainer extends Component {
17 | constructor(props) {
18 | super(props);
19 | }
20 |
21 | render() {
22 | let currentTab;
23 | // console.log('code gen', this.props.codeGeneratedString);
24 | // console.log('Production Container', this.props.dataViewContent);
25 | switch (this.props.currentTab) {
26 | case 'schemaBuilderTab':
27 | currentTab = (
28 |
36 | );
37 | // console.log('CHANGING CURRENT TAB TO SCB');
38 | break;
39 | case 'codeOutputTab':
40 | currentTab = (
41 |
44 | );
45 | // console.log('CHANGING CURRENT TAB TO CO');
46 | break;
47 | default:
48 | currentTab = (
49 |
57 | );
58 | }
59 | return (
60 |
61 | {currentTab}
62 |
63 | );
64 | }
65 | }
66 |
67 | export default ProductionContainer;
68 |
--------------------------------------------------------------------------------
/src/containers/schemaBuilderContainer.jsx:
--------------------------------------------------------------------------------
1 | /**
2 | * ***********************************
3 | *
4 | * @module SchemaBuilderContainer
5 | * @author Tom Herrmann and Adam Goren
6 | * @date 10/29/2019
7 | * @description Displays the fields required to build GraphQL schema ~~~versitile container for rendering several componenets.
8 | * Currently holds DataView and Form, but could be updated to contain CodeOutput and more~~~~
9 | *
10 | * ***********************************
11 | */
12 | import React, { Component } from 'react';
13 |
14 | // component imports
15 | import DataView from '../components/dataView';
16 | import Form from '../components/form';
17 |
18 | class SchemaBuilderContainer extends Component {
19 | constructor(props) {
20 | super(props);
21 | }
22 |
23 | render() {
24 | return (
25 |
26 | {/*
'Schema Builder Container'
*/}
27 |
31 |
38 |
39 | );
40 | }
41 | }
42 |
43 | export default SchemaBuilderContainer;
44 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { MuiThemeProvider, createMuiTheme } from '@material-ui/core';
4 | import { SnackbarProvider } from 'notistack';
5 | import App from './App';
6 |
7 | const theme = createMuiTheme({
8 | palette: {
9 | primary: {
10 | main: '#124e96',
11 | },
12 | secondary: {
13 | main: '#f35588',
14 | },
15 | },
16 | });
17 |
18 | ReactDOM.render(
19 |
20 |
21 |
22 |
23 | ,
24 | document.getElementById('root'),
25 | );
26 | /*
27 | Co-authored-by: adamgoren
28 | Co-authored-by: apaisner
29 | Co-authored-by: xosemanolo
30 | Co-authored by: tomherrmann
31 | */
32 |
--------------------------------------------------------------------------------
/src/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body,
3 | #root {
4 | display: flex;
5 | flex-direction: column;
6 | align-items: center;
7 | justify-content: flex-start;
8 | margin: 0;
9 | padding: 0;
10 | height: 100%;
11 | width: 100%;
12 | font-family: 'roboto', 'Times New Roman', 'Times', 'serif';
13 | }
14 | p {
15 | margin: 10px;
16 | }
17 | .App {
18 | display: flex;
19 | flex-direction: column;
20 | align-items: center;
21 | height: 100%;
22 | width: 100%;
23 | background-color: #0d8abc;
24 | }
25 | #logo {
26 | width: 250px;
27 | height: auto;
28 | }
29 | #searchContainer {
30 | display: flex;
31 | flex-direction: column;
32 | margin-bottom: 10px;
33 | width: 50%;
34 | }
35 | #search {
36 | margin-bottom: 1%;
37 | }
38 | #searchButton {
39 | width: 15%;
40 | margin-bottom: 10px;
41 | }
42 | #searchInput {
43 | height: 30px;
44 | width: 100%;
45 | padding-left: 20px;
46 | margin-top: -10px;
47 | margin-bottom: 5px;
48 | border-radius: 200px;
49 | box-shadow: 2px 4px 5px lightslategrey;
50 | border: 1px solid lightslategray;
51 | background-color: #f8f8f8;
52 | }
53 | #searchInput:focus {
54 | outline: none;
55 | border: 1px solid #bb0d6c;
56 | }
57 | #searchButtonContainer {
58 | display: flex;
59 | justify-content: center;
60 | margin-top: 10px;
61 | margin-bottom: 7px;
62 | }
63 | #searchButton {
64 | width: 145px;
65 | box-shadow: 2px 4px 5px lightslategrey;
66 | }
67 | #mainContainer {
68 | display: flex;
69 | flex-direction: column;
70 | margin-bottom: 1.3%;
71 | width: 62%;
72 | height: 70%;
73 | }
74 | #navBar {
75 | display: flex;
76 | flex-direction: row;
77 | height: fit-content;
78 | }
79 | #tabsContainer {
80 | border-top-right-radius: 22px;
81 | border-top-left-radius: 22px;
82 | height: -webkit-fill-available;
83 | width: -webkit-fill-available;
84 | background-color: #124e96;
85 | }
86 |
87 | .MuiButtonBase-root:focus {
88 | /* background: #0f407c; */
89 | }
90 | .MuiTab-wrapper {
91 | color: whitesmoke;
92 | font-size: 20;
93 | }
94 | .MuiButtonBase-root.MuiTab-root.MuiTab-textColorPrimary.Mui-selected {
95 | padding: 0;
96 | }
97 | .tab {
98 | height: -webkit-fill-available;
99 | width: 50%;
100 | }
101 | #productionContainer {
102 | display: flex;
103 | flex-direction: row;
104 | height: -webkit-fill-available;
105 | width: -webkit-fill-available;
106 | background-color: #f8f8f8;
107 | }
108 | #schemaBuilderContainer {
109 | display: flex;
110 | flex-direction: row;
111 | width: -webkit-fill-available;
112 | }
113 | #codeOutput {
114 | display: flex;
115 | flex-direction: column;
116 | width: -webkit-fill-available;
117 | background-color: #f8f8f8;
118 | overflow: auto;
119 | }
120 | #dataViewContainer {
121 | display: flex;
122 | flex-direction: column;
123 | width: 50%;
124 | max-height: 775px;
125 | background-color: #f8f8f8;
126 | }
127 | #dataView {
128 | background-color: whitesmoke;
129 | margin: 0 0 20px 20px;
130 | padding: 10px;
131 | border: 1px solid gray;
132 | border-radius: 40px;
133 | height: 80%;
134 | overflow: auto;
135 | }
136 | #loadSpinner {
137 | margin-top: 30%;
138 | margin-left: 43%;
139 | }
140 | #formContainer {
141 | display: flex;
142 | flex-direction: column;
143 | justify-content: space-between;
144 | width: 50%;
145 | max-height: 745px;
146 | background-color: #f8f8f8;
147 | }
148 | #form {
149 | display: flex;
150 | flex-direction: column;
151 | justify-content: space-between;
152 | overflow: auto;
153 | }
154 | #formSubmit {
155 | height: 4%;
156 | width: 30%;
157 | margin-top: 3%;
158 | }
159 | h1 {
160 | font-family: 'Oswald', sans-serif;
161 | color: #f8f8f8;
162 | text-shadow: 3px 1px #000000cf;
163 | font-size: 40px;
164 | letter-spacing: 5px;
165 | }
166 | /* header: https://www.w3schools.com/howto/howto_css_style_header.asp */
167 | .sbTitle {
168 | margin: 0px;
169 | margin-bottom: 16px;
170 | padding: 8px;
171 | text-align: center;
172 | color: grey;
173 | font-size: 30px;
174 | font-weight: 500;
175 | }
176 | #dataViewTitle {
177 | margin-bottom: 0;
178 | }
179 | #inputContainer {
180 | padding: 10px;
181 | }
182 | .fieldTypes,
183 | .fieldNames,
184 | .objectType {
185 | border: none;
186 | border-bottom: 1px solid;
187 | margin-bottom: 10px;
188 | margin-left: 20px;
189 | background-color: #f8f8f8;
190 | font-size: medium;
191 | }
192 |
193 | .formSwitch {
194 | color: grey;
195 | margin-bottom: 10px;
196 | margin-left: 20px;
197 | }
198 |
199 | .fieldTypes:focus,
200 | .fieldNames:focus,
201 | .objectType:focus {
202 | outline: none;
203 | border-bottom: 2px solid #ff008e;
204 | }
205 |
206 | /* Material UI is weird - this edits the field input boxes */
207 | .MuiFormControl-root.formControl {
208 | margin-right: 15px;
209 | }
210 | .MuiInputBase-root.MuiInput-root.MuiInput-underline.MuiInputBase-formControl.MuiInput-formControl {
211 | width: 150px;
212 | margin-bottom: 15px;
213 | color: #ff008e;
214 | }
215 | #addNewField {
216 | margin-top: 15px;
217 | margin-left: 20px;
218 | }
219 | #formSubmit {
220 | height: auto;
221 | width: auto;
222 | margin-left: 20px;
223 | }
224 |
225 | #submitContainer {
226 | display: flex;
227 | justify-content: flex-end;
228 | margin: 25px;
229 | margin-top: 0;
230 | }
231 |
232 | #productionContainer {
233 | border-bottom-right-radius: 22px;
234 | border-bottom-left-radius: 22px;
235 | box-shadow: 10px 10px 15px lightslategray;
236 | height: 75%;
237 | overflow: auto;
238 | }
239 | #display {
240 | display: flex;
241 | justify-content: space-between;
242 | margin: 10px;
243 | width: 100%;
244 | }
245 |
246 | #copyOutputContainer {
247 | display: flex;
248 | flex-direction: row;
249 | justify-content: flex-end;
250 | margin: 25px;
251 | }
252 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const webpack = require('webpack');
3 |
4 | module.exports = {
5 | entry: './src/index.js',
6 | mode: 'development',
7 | module: {
8 | rules: [
9 | {
10 | test: /\.(js|jsx)$/,
11 | exclude: /(node_modules|bower_components)/,
12 | loader: 'babel-loader',
13 | options: { presets: ['@babel/env'] },
14 | },
15 | {
16 | test: /\.css$/,
17 | use: ['style-loader', 'css-loader'],
18 | },
19 | {
20 | test: /\.(png|svg|jpg|gif)$/,
21 | use: ['file-loader'],
22 | },
23 | ],
24 | },
25 | resolve: { extensions: ['*', '.js', '.jsx'] },
26 | output: {
27 | path: path.resolve(__dirname, 'dist/'),
28 | publicPath: '/dist/',
29 | filename: 'bundle.js',
30 | },
31 | devServer: {
32 | contentBase: path.join(__dirname, 'dist/'),
33 | port: 8080,
34 | publicPath: 'http://localhost:8080/dist/',
35 | hotOnly: true,
36 | // sends all endpoint requests from 8080 to 3000
37 | proxy: {
38 | '/': {
39 | target: 'http://localhost:3000/',
40 | changeOrigin: true,
41 | },
42 | },
43 | },
44 | plugins: [new webpack.HotModuleReplacementPlugin()],
45 | };
46 |
--------------------------------------------------------------------------------