├── .DS_Store
├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── .vscode
└── settings.json
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── assets
├── .DS_Store
├── img
│ ├── eeql.png
│ ├── eeql_logo.png
│ └── eeql_logo_copy.png
└── style
│ ├── colors.scss
│ ├── fonts.scss
│ └── global.scss
├── babel.config.js
├── dist
├── main.js
└── main.js.map
├── package-lock.json
├── package.json
├── public
└── electron.js
├── src
├── App.tsx
├── components
│ ├── CodeEditor
│ │ ├── CodeEditor.scss
│ │ ├── CodeEditor.tsx
│ │ ├── options.ts
│ │ └── start.js
│ ├── FileTree
│ │ ├── FileTree.scss
│ │ └── FileTree.tsx
│ ├── FileUpdate
│ │ ├── FileUpdate.scss
│ │ └── FileUpdate.tsx
│ ├── FileUpload
│ │ ├── FileUpload.scss
│ │ └── FileUpload.tsx
│ ├── NavBar
│ │ ├── NavBar.scss
│ │ └── NavBar.tsx
│ ├── PortUpdate
│ │ ├── PortUpdate.scss
│ │ └── PortUpdate.tsx
│ └── TestSuite
│ │ ├── GraphQLEndpoint
│ │ ├── GraphQLEndpoint.scss
│ │ ├── GraphQLEndpoint.tsx
│ │ └── MockSchema.js
│ │ ├── RestEndpoint
│ │ ├── RestEndpoint.scss
│ │ └── RestEndpoint.tsx
│ │ ├── Supertest.js
│ │ ├── TestBuilder
│ │ ├── TestBuilder.scss
│ │ └── TestBuilder.tsx
│ │ ├── TestGeneration
│ │ ├── RestTestCreation.js
│ │ └── graphQLTestCreation.js
│ │ └── server
│ │ ├── db
│ │ ├── markets.dev.json
│ │ ├── markets.js
│ │ └── markets.test.json
│ │ └── index.js
├── index.html
├── index.js
├── pages
│ ├── Home
│ │ ├── Home.scss
│ │ └── Home.tsx
│ ├── Landing
│ │ ├── Landing.scss
│ │ └── Landing.tsx
│ └── Visualize
│ │ ├── Visualize.scss
│ │ └── Visualize.tsx
└── provider
│ ├── DataProvider.tsx
│ ├── StateProvider.tsx
│ └── TestProvider.tsx
├── tsconfig.json
├── webpack.electron.config.js
└── webpack.react.config.js
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/eeQL/efa2296b48eff63e7b0258658ec1a42fb5a7ee36/.DS_Store
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.tsdk": "node_modules/typescript/lib"
3 | }
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | contact@eeql.io.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 OSLabs Beta
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # eeQL
2 |
3 |
4 | _"EEQL is a standalone test creation suite that constructs reliable endpoint tests for both GraphQL and RESTful API's."_.
5 |
6 |
7 |
8 | ## Installation
9 |
10 | Please dive into [eeQL.io](https://www.eeql.io/) to install this application.
11 |
12 | Refer to our [Builds/Resources](https://github.com/oslabs-beta/eeQL/releases) for more information on compatability and previous releases.
13 |
14 |
15 |
16 | ## Usage
17 | ### GETTING STARTED
18 |
19 |
20 |
21 |
22 |
23 | - Input desired port for proper integration into your project
24 | - Upload a project directory (note: a testing folder will be created if none exists).
25 | - eeQL will automatically create, display and locate testing files within your uploaded project to facilitate reliable test creation.
26 |
27 |
28 |
29 | ### TEST CREATION
30 |
31 | REST
32 |
33 |
34 |
35 | - Select the REST button
36 | - Select the request method that you plan on testing
37 | - Upload the server file of your project
38 | - Fill out the requested fields within the _Test Builder Module_
39 | - Press the save button to automatically create a Jest-and-Supertest-based REST test !
40 |
41 |
42 | GRAPHQL
43 |
44 |
45 |
46 | - Select the GraphQL button
47 | - Upload the schema file of your project
48 | - Upload the resolvers file of your project
49 | - Provide a description of the test
50 | - Determine if the operation is a valid or invalid one
51 | - Provide the operation (query/mutation) text
52 | - Determine if the operation is a query or a mutation
53 | - Optionally, provide a mutation object if the operation is a mutation instead of a query
54 | - Press the save button to generate an easyGraphQL-based operation test!
55 |
56 |
57 |
58 |
59 | ## Contributing
60 | Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
61 | Please make sure to update tests as appropriate.
62 |
63 |
64 |
65 | ## Contact and Inquiries
66 | [Contact us](contact@eeql.io) for all other issues/inquiries. If you'd like to follow up on updates with eeQL, please check us out [here](https://www.linkedin.com/company/eeql/about/)!
67 |
68 |
69 |
70 | ## Developers
71 | [Abu Fofanah](https://www.linkedin.com/in/abu-fofanah/) |
72 | [Jason Speare](https://www.linkedin.com/in/jason-speare/) |
73 | [Kimberley Spicer]( https://www.linkedin.com/in/kimberleyspicer/) |
74 | [Ramtin Khoee](https://www.linkedin.com/in/ramtinkhoee/) |
75 |
76 |
77 | ## License
78 | This project is licensed under the [MIT license](https://choosealicense.com/licenses/mit/).
79 |
80 |
81 |
--------------------------------------------------------------------------------
/assets/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/eeQL/efa2296b48eff63e7b0258658ec1a42fb5a7ee36/assets/.DS_Store
--------------------------------------------------------------------------------
/assets/img/eeql.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/eeQL/efa2296b48eff63e7b0258658ec1a42fb5a7ee36/assets/img/eeql.png
--------------------------------------------------------------------------------
/assets/img/eeql_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/eeQL/efa2296b48eff63e7b0258658ec1a42fb5a7ee36/assets/img/eeql_logo.png
--------------------------------------------------------------------------------
/assets/img/eeql_logo_copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/eeQL/efa2296b48eff63e7b0258658ec1a42fb5a7ee36/assets/img/eeql_logo_copy.png
--------------------------------------------------------------------------------
/assets/style/colors.scss:
--------------------------------------------------------------------------------
1 | $eeql-gray: #c2c2c2;
2 | $eeql-white: #fcfbf6;
3 |
4 |
--------------------------------------------------------------------------------
/assets/style/fonts.scss:
--------------------------------------------------------------------------------
1 | @import url(https://fonts.googleapis.com/css2?family=Lora:wght@600&family=Raleway:wght@500&family=Montserrat&display=swap);
2 |
3 | $lora: 'Lora', serif;
4 | $raleway: 'Raleway', sans-serif;
5 | $montserrat: 'Montserrat', sans-serif;
6 |
7 | $eeql-font: Helvetica, sans-serif;
--------------------------------------------------------------------------------
/assets/style/global.scss:
--------------------------------------------------------------------------------
1 | #global {
2 | background-color: #1e1e21;
3 | }
4 |
5 | body {
6 | background-color: #1e1e21;
7 | }
8 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // extending babel - plugins for transpiling code
3 | presets: [
4 | "@babel/preset-env",
5 | "@babel/preset-react",
6 | "@babel/preset-typescript",
7 | ],
8 | };
9 |
--------------------------------------------------------------------------------
/dist/main.js:
--------------------------------------------------------------------------------
1 | /******/ (function(modules) { // webpackBootstrap
2 | /******/ // The module cache
3 | /******/ var installedModules = {};
4 | /******/
5 | /******/ // The require function
6 | /******/ function __webpack_require__(moduleId) {
7 | /******/
8 | /******/ // Check if module is in cache
9 | /******/ if(installedModules[moduleId]) {
10 | /******/ return installedModules[moduleId].exports;
11 | /******/ }
12 | /******/ // Create a new module (and put it into the cache)
13 | /******/ var module = installedModules[moduleId] = {
14 | /******/ i: moduleId,
15 | /******/ l: false,
16 | /******/ exports: {}
17 | /******/ };
18 | /******/
19 | /******/ // Execute the module function
20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
21 | /******/
22 | /******/ // Flag the module as loaded
23 | /******/ module.l = true;
24 | /******/
25 | /******/ // Return the exports of the module
26 | /******/ return module.exports;
27 | /******/ }
28 | /******/
29 | /******/
30 | /******/ // expose the modules object (__webpack_modules__)
31 | /******/ __webpack_require__.m = modules;
32 | /******/
33 | /******/ // expose the module cache
34 | /******/ __webpack_require__.c = installedModules;
35 | /******/
36 | /******/ // define getter function for harmony exports
37 | /******/ __webpack_require__.d = function(exports, name, getter) {
38 | /******/ if(!__webpack_require__.o(exports, name)) {
39 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
40 | /******/ }
41 | /******/ };
42 | /******/
43 | /******/ // define __esModule on exports
44 | /******/ __webpack_require__.r = function(exports) {
45 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
46 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
47 | /******/ }
48 | /******/ Object.defineProperty(exports, '__esModule', { value: true });
49 | /******/ };
50 | /******/
51 | /******/ // create a fake namespace object
52 | /******/ // mode & 1: value is a module id, require it
53 | /******/ // mode & 2: merge all properties of value into the ns
54 | /******/ // mode & 4: return value when already ns object
55 | /******/ // mode & 8|1: behave like require
56 | /******/ __webpack_require__.t = function(value, mode) {
57 | /******/ if(mode & 1) value = __webpack_require__(value);
58 | /******/ if(mode & 8) return value;
59 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
60 | /******/ var ns = Object.create(null);
61 | /******/ __webpack_require__.r(ns);
62 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
63 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
64 | /******/ return ns;
65 | /******/ };
66 | /******/
67 | /******/ // getDefaultExport function for compatibility with non-harmony modules
68 | /******/ __webpack_require__.n = function(module) {
69 | /******/ var getter = module && module.__esModule ?
70 | /******/ function getDefault() { return module['default']; } :
71 | /******/ function getModuleExports() { return module; };
72 | /******/ __webpack_require__.d(getter, 'a', getter);
73 | /******/ return getter;
74 | /******/ };
75 | /******/
76 | /******/ // Object.prototype.hasOwnProperty.call
77 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
78 | /******/
79 | /******/ // __webpack_public_path__
80 | /******/ __webpack_require__.p = "";
81 | /******/
82 | /******/
83 | /******/ // Load entry module and return exports
84 | /******/ return __webpack_require__(__webpack_require__.s = "./public/electron.js");
85 | /******/ })
86 | /************************************************************************/
87 | /******/ ({
88 |
89 | /***/ "./public/electron.js":
90 | /*!****************************!*\
91 | !*** ./public/electron.js ***!
92 | \****************************/
93 | /*! no exports provided */
94 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
95 |
96 | "use strict";
97 | __webpack_require__.r(__webpack_exports__);
98 | /* harmony import */ var electron__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! electron */ "electron");
99 | /* harmony import */ var electron__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(electron__WEBPACK_IMPORTED_MODULE_0__);
100 | /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! path */ "path");
101 | /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__);
102 | /* harmony import */ var url__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! url */ "url");
103 | /* harmony import */ var url__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(url__WEBPACK_IMPORTED_MODULE_2__);
104 |
105 |
106 | // currentWindow represents our current rendered page in electron app
107 |
108 | var currentWindow; // create a function that opens a create a new window
109 |
110 | function newWindow() {
111 | currentWindow = new electron__WEBPACK_IMPORTED_MODULE_0__["BrowserWindow"]({
112 | title: "eeQL",
113 | // to be determined
114 | icon: null,
115 | // eeql-blue
116 | backgroundColor: "##1c90f5",
117 | // starting dimensions of new window
118 | height: 800,
119 | width: 800,
120 | // allow integration of node modules in build.
121 | webPreferences: {
122 | nodeIntegration: true
123 | }
124 | }); // check if dist folder exists by running a test on the node environmnet
125 | // if in development mode, serve the local server to electron
126 |
127 | if (true) {
128 | currentWindow.loadURL("http://localhost:4000");
129 | currentWindow.webContents.openDevTools();
130 | } // otherwise, serve the compile dist folder for render
131 | else {} // set window to null after app is closed.
132 | // create IPC event listener on browserRouter
133 |
134 |
135 | currentWindow.on("closed", function () {
136 | currentWindow = null;
137 | });
138 | } // after IPC event listener is triggered "ready"
139 | // invoke our create new window by invoking "newWindow()"
140 |
141 |
142 | electron__WEBPACK_IMPORTED_MODULE_0__["app"].on("ready", newWindow); // electron, by default, refreshes every navigation
143 | // since we're using node modules outside of our dist folder, we have to disable auto refresh
144 |
145 | electron__WEBPACK_IMPORTED_MODULE_0__["app"].allowRendererProcessReuse = true;
146 |
147 | /***/ }),
148 |
149 | /***/ "electron":
150 | /*!***************************!*\
151 | !*** external "electron" ***!
152 | \***************************/
153 | /*! no static exports found */
154 | /***/ (function(module, exports) {
155 |
156 | module.exports = require("electron");
157 |
158 | /***/ }),
159 |
160 | /***/ "path":
161 | /*!***********************!*\
162 | !*** external "path" ***!
163 | \***********************/
164 | /*! no static exports found */
165 | /***/ (function(module, exports) {
166 |
167 | module.exports = require("path");
168 |
169 | /***/ }),
170 |
171 | /***/ "url":
172 | /*!**********************!*\
173 | !*** external "url" ***!
174 | \**********************/
175 | /*! no static exports found */
176 | /***/ (function(module, exports) {
177 |
178 | module.exports = require("url");
179 |
180 | /***/ })
181 |
182 | /******/ });
183 | //# sourceMappingURL=main.js.map
--------------------------------------------------------------------------------
/dist/main.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./public/electron.js","webpack:///external \"electron\"","webpack:///external \"path\"","webpack:///external \"url\""],"names":["currentWindow","newWindow","BrowserWindow","title","icon","backgroundColor","height","width","webPreferences","nodeIntegration","process","loadURL","webContents","openDevTools","on","app","allowRendererProcessReuse"],"mappings":";QAAA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;;QAEA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;;;QAGA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA,0CAA0C,gCAAgC;QAC1E;QACA;;QAEA;QACA;QACA;QACA,wDAAwD,kBAAkB;QAC1E;QACA,iDAAiD,cAAc;QAC/D;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,yCAAyC,iCAAiC;QAC1E,gHAAgH,mBAAmB,EAAE;QACrI;QACA;;QAEA;QACA;QACA;QACA,2BAA2B,0BAA0B,EAAE;QACvD,iCAAiC,eAAe;QAChD;QACA;QACA;;QAEA;QACA,sDAAsD,+DAA+D;;QAErH;QACA;;;QAGA;QACA;;;;;;;;;;;;;AClFA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;CAGA;;AACA,IAAIA,aAAJ,C,CAEA;;AACA,SAASC,SAAT,GAAqB;AACnBD,eAAa,GAAG,IAAIE,sDAAJ,CAAkB;AAChCC,SAAK,EAAE,MADyB;AAEhC;AACAC,QAAI,EAAE,IAH0B;AAIhC;AACAC,mBAAe,EAAE,UALe;AAMhC;AACAC,UAAM,EAAE,GAPwB;AAQhCC,SAAK,EAAE,GARyB;AAShC;AACAC,kBAAc,EAAE;AAAEC,qBAAe,EAAE;AAAnB;AAVgB,GAAlB,CAAhB,CADmB,CAcnB;AACA;;AACA,MAAIC,IAAJ,EAA4C;AAC1CV,iBAAa,CAACW,OAAd,CAAsB,uBAAtB;AACAX,iBAAa,CAACY,WAAd,CAA0BC,YAA1B;AACD,GAHD,CAIA;AAJA,OAKK,EArBc,CAmCnB;AACA;;;AACAb,eAAa,CAACc,EAAd,CAAiB,QAAjB,EAA2B,YAAM;AAC/Bd,iBAAa,GAAG,IAAhB;AACD,GAFD;AAGD,C,CACD;AACA;;;AACAe,4CAAG,CAACD,EAAJ,CAAO,OAAP,EAAgBb,SAAhB,E,CACA;AACA;;AACAc,4CAAG,CAACC,yBAAJ,GAAgC,IAAhC,C;;;;;;;;;;;ACtDA,qC;;;;;;;;;;;ACAA,iC;;;;;;;;;;;ACAA,gC","file":"main.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./public/electron.js\");\n","import { app, BrowserWindow } from \"electron\";\nimport * as path from \"path\";\nimport * as url from \"url\";\n\n// currentWindow represents our current rendered page in electron app\nlet currentWindow;\n\n// create a function that opens a create a new window\nfunction newWindow() {\n currentWindow = new BrowserWindow({\n title: \"eeQL\",\n // to be determined\n icon: null,\n // eeql-blue\n backgroundColor: \"##1c90f5\",\n // starting dimensions of new window\n height: 800,\n width: 800,\n // allow integration of node modules in build.\n webPreferences: { nodeIntegration: true },\n });\n\n // check if dist folder exists by running a test on the node environmnet\n // if in development mode, serve the local server to electron\n if (process.env.NODE_ENV === \"development\") {\n currentWindow.loadURL(\"http://localhost:4000\");\n currentWindow.webContents.openDevTools();\n }\n // otherwise, serve the compile dist folder for render\n else {\n currentWindow.loadURL(\n // tried implementing WhatWG URL, it's current non-functional, see dicussion reference for more details.\n // https://github.com/nodejs/node/issues/25099\n url.format({\n // allow electron to render a file (html), in our dist folder\n pathname: path.resolve(__dirname, \"../dist/index.html\"),\n // set type\n protocol: \"file:\",\n // allow for propper formating of directory name.\n slashes: true,\n })\n );\n }\n // set window to null after app is closed.\n // create IPC event listener on browserRouter\n currentWindow.on(\"closed\", () => {\n currentWindow = null;\n });\n}\n// after IPC event listener is triggered \"ready\"\n// invoke our create new window by invoking \"newWindow()\"\napp.on(\"ready\", newWindow);\n// electron, by default, refreshes every navigation\n// since we're using node modules outside of our dist folder, we have to disable auto refresh\napp.allowRendererProcessReuse = true;\n","module.exports = require(\"electron\");","module.exports = require(\"path\");","module.exports = require(\"url\");"],"sourceRoot":""}
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eeql",
3 | "version": "1.0.0",
4 | "description": "A tool to help test, visualize and optimize your data.",
5 | "main": "dist/main.js",
6 | "repository": {
7 | "type": "git",
8 | "url": "git+https://github.com/oslabs-beta/eeQL.git"
9 | },
10 | "keywords": [
11 | "testing",
12 | "electron",
13 | "graphQL"
14 | ],
15 | "license": "MIT",
16 | "bugs": {
17 | "url": "https://github.com/oslabs-beta/eeQL/issues"
18 | },
19 | "homepage": "https://github.com/oslabs-beta/eeQL#readme",
20 | "author": "eeQL",
21 | "contributors": [
22 | "Ramtin Khoee",
23 | "Kimberley Spicer",
24 | "Abu Fofanah",
25 | "Jason Speare"
26 | ],
27 | "scripts": {
28 | "prod": "npm run p-react && npm run p-electron",
29 | "p-react": "cross-env NODE_ENV=production webpack --config webpack.react.config.js --mode production",
30 | "p-electron": "cross-env NODE_ENV=production webpack --config webpack.electron.config.js --mode production && electron .",
31 | "dev": " concurrently \"npm run d-electron\" \"npm run d-react\"",
32 | "d-react": "cross-env NODE_ENV=development webpack-dev-server --config webpack.react.config.js --mode development",
33 | "d-electron": "cross-env NODE_ENV=development concurrently \"webpack --config webpack.electron.config.js --mode development\" \"electron .\"",
34 | "e-build": "electron-builder",
35 | "test": "jest --verbose"
36 | },
37 | "jest": {
38 | "globalSetup": "./jest-setup.js",
39 | "globalTeardown": "./jest-teardown.js"
40 | },
41 | "build": {
42 | "directories": {
43 | "output": "build",
44 | "buildResources": "assets"
45 | },
46 | "extends": null,
47 | "files": [
48 | "dist/**/*",
49 | "node_modules/**/*"
50 | ],
51 | "productName": "eeQL",
52 | "appId": "com.electron.pinocchio",
53 | "mac": {
54 | "category": "public.app-category.developer-tools"
55 | },
56 | "dmg": {
57 | "icon": null,
58 | "contents": [
59 | {
60 | "x": 100,
61 | "y": 150
62 | },
63 | {
64 | "x": 300,
65 | "y": 150,
66 | "type": "link",
67 | "path": "/Applications"
68 | }
69 | ]
70 | },
71 | "win": {
72 | "target": [
73 | "nsis"
74 | ],
75 | "icon": null
76 | },
77 | "nsis": {
78 | "oneClick": false,
79 | "allowToChangeInstallationDirectory": true
80 | },
81 | "linux": {
82 | "target": [
83 | "AppImage",
84 | "snap"
85 | ]
86 | }
87 | },
88 | "devDependencies": {
89 | "@babel/core": "^7.9.0",
90 | "@babel/plugin-proposal-decorators": "^7.12.12",
91 | "@babel/preset-env": "^7.9.5",
92 | "@babel/preset-react": "^7.9.4",
93 | "@babel/preset-typescript": "^7.9.0",
94 | "@types/jest": "^26.0.20",
95 | "@types/react": "^16.9.34",
96 | "@types/react-dom": "^16.9.6",
97 | "@types/react-router-dom": "^5.1.7",
98 | "@typescript-eslint/eslint-plugin": "^4.13.0",
99 | "@typescript-eslint/parser": "^4.13.0",
100 | "babel-loader": "^8.1.0",
101 | "css-loader": "^5.0.1",
102 | "electron": "^8.2.2",
103 | "electron-builder": "^22.7.0",
104 | "electron-devtools-installer": "^3.1.1",
105 | "electron-is-dev": "^1.2.0",
106 | "electron-webpack": "^2.8.2",
107 | "eslint": "^7.17.0",
108 | "eslint-config-airbnb": "^18.2.1",
109 | "eslint-plugin-import": "^2.22.1",
110 | "eslint-plugin-jsx-a11y": "^6.4.1",
111 | "eslint-plugin-react": "^7.22.0",
112 | "eslint-plugin-react-hooks": "^4.2.0",
113 | "file-loader": "^6.2.0",
114 | "html-loader": "^1.3.2",
115 | "html-webpack-plugin": "^4.2.0",
116 | "node-sass": "^5.0.0",
117 | "sass": "^1.32.5",
118 | "sass-loader": "^10.1.1",
119 | "style-loader": "^2.0.0",
120 | "svg-url-loader": "^7.1.1",
121 | "ts-jest": "^26.5.3",
122 | "ts-loader": "^8.0.14",
123 | "typescript": "^3.7.2",
124 | "url-loader": "^4.1.1",
125 | "webpack": "^4.46.0",
126 | "webpack-cli": "^3.3.11",
127 | "webpack-dev-server": "^3.10.3"
128 | },
129 | "dependencies": {
130 | "@apollo/client": "^3.3.11",
131 | "@devexpress/dx-react-core": "2.7.5",
132 | "@devexpress/dx-react-grid": "2.7.5",
133 | "@devexpress/dx-react-grid-material-ui": "2.7.5",
134 | "@material-ui/core": "^4.11.3",
135 | "@material-ui/icons": "^4.11.2",
136 | "bluebird": "^3.7.2",
137 | "bootstrap": "^5.0.0-beta2",
138 | "concurrently": "^5.3.0",
139 | "cross-env": "^7.0.3",
140 | "d3": "^5.16.0",
141 | "d3-scale": "^3.2.3",
142 | "graphiql-plus": "^1.0.1",
143 | "graphql": "^15.5.0",
144 | "graphql-matcha": "0.0.6",
145 | "graphql-tools": "^7.0.4",
146 | "monaco-editor": "^0.21.2", "monaco-editor-electron": "^1.0.6",
147 | "monaco-editor-webpack-plugin": "^2.1.0",
148 | "react": "^16.13.1",
149 | "react-awesome-button": "^6.5.1",
150 | "react-d3-graph": "^2.6.0",
151 | "react-dom": "^16.13.1",
152 | "react-grid-layout": "^1.2.2",
153 | "react-monaco-editor": "^0.41.2",
154 | "react-resizable": "^1.11.1",
155 | "react-router-dom": "^5.2.0",
156 | "styled-components": "^5.2.1"
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/public/electron.js:
--------------------------------------------------------------------------------
1 | import { app, BrowserWindow } from "electron";
2 | import * as path from "path";
3 | import * as url from "url";
4 |
5 | // currentWindow represents our current rendered page in electron app
6 | let currentWindow;
7 |
8 | // create a function that opens a create a new window
9 | function newWindow() {
10 | currentWindow = new BrowserWindow({
11 | title: "eeQL",
12 | // to be determined
13 | icon: null,
14 | // eeql-blue
15 | backgroundColor: "##1c90f5",
16 | // starting dimensions of new window
17 | height: 800,
18 | width: 800,
19 | // allow integration of node modules in build.
20 | webPreferences: { nodeIntegration: true },
21 | });
22 |
23 | // check if dist folder exists by running a test on the node environmnet
24 | // if in development mode, serve the local server to electron
25 | if (process.env.NODE_ENV === "development") {
26 | currentWindow.loadURL("http://localhost:4000");
27 | currentWindow.webContents.openDevTools();
28 | }
29 | // otherwise, serve the compile dist folder for render
30 | else {
31 | currentWindow.loadURL(
32 | // tried implementing WhatWG URL, it's current non-functional, see dicussion reference for more details.
33 | // https://github.com/nodejs/node/issues/25099
34 | url.format({
35 | // allow electron to render a file (html), in our dist folder
36 | pathname: path.resolve(__dirname, "../dist/index.html"),
37 | // set type
38 | protocol: "file:",
39 | // allow for propper formating of directory name.
40 | slashes: true,
41 | })
42 | );
43 | }
44 | // set window to null after app is closed.
45 | // create IPC event listener on browserRouter
46 | currentWindow.on("closed", () => {
47 | currentWindow = null;
48 | });
49 | }
50 | // after IPC event listener is triggered "ready"
51 | // invoke our create new window by invoking "newWindow()"
52 | app.on("ready", newWindow);
53 | // electron, by default, refreshes every navigation
54 | // since we're using node modules outside of our dist folder, we have to disable auto refresh
55 | app.allowRendererProcessReuse = true;
56 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState, useEffect } from "react";
2 | import { StateContext } from "./provider/StateProvider";
3 | import { Switch, Route } from "react-router-dom";
4 | import Home from "./pages/Home/Home";
5 | import Landing from "./pages/Landing/Landing";
6 | import Visualize from "./pages/Visualize/Visualize";
7 | import "../assets/style/global.scss";
8 |
9 | const App = () => {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | );
19 | };
20 |
21 | export default App;
22 |
--------------------------------------------------------------------------------
/src/components/CodeEditor/CodeEditor.scss:
--------------------------------------------------------------------------------
1 | .file-tree-item {
2 | font-size: 16px;
3 | background-color: transparent;
4 | color: rgb(255, 214, 163);
5 | border: none;
6 | }
7 |
8 | #file-tree-head {
9 | list-style-type: none !important;
10 | }
11 |
12 | #code-editor-head {
13 | font-family: Arial, Helvetica, sans-serif;
14 | border: solid 2px rgb(255, 214, 163);
15 | padding: 30px 20px 30px 20px;
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/src/components/CodeEditor/CodeEditor.tsx:
--------------------------------------------------------------------------------
1 | import "./CodeEditor.scss";
2 | import React, { useContext, useEffect, useState } from "react";
3 | import { StateContext } from "../../provider/StateProvider";
4 | import MonacoEditor from "react-monaco-editor";
5 | import options from "./options";
6 | const { remote } = window.require("electron");
7 | const electronFs = remote.require("fs");
8 |
9 | const CodeEditor = () => {
10 | //from our glabal state
11 | const { activeFile, fileTree }: any = useContext(StateContext);
12 | //local state
13 | const [getContents, setContents] = useState("");
14 | const getFileContents = (path: String) => {
15 | if (path.length > 0) {
16 | setContents(electronFs.readFileSync(path, "utf8"));
17 | }
18 | };
19 | useEffect(() => {
20 | getFileContents(activeFile);
21 | [activeFile, fileTree];
22 | });
23 |
24 | return (
25 |
36 | );
37 | };
38 |
39 | export default CodeEditor;
40 |
--------------------------------------------------------------------------------
/src/components/CodeEditor/options.ts:
--------------------------------------------------------------------------------
1 | // MONACO OPTIONS PAGE:
2 |
3 | const options: any = {
4 | selectOnLineNumbers: true,
5 | autoIndent: true,
6 | colorDecorators: true,
7 | wrappingIndent: "indent",
8 | wordWrap: "bounded",
9 | automaticLayout: true,
10 | };
11 |
12 | export default options;
13 |
--------------------------------------------------------------------------------
/src/components/CodeEditor/start.js:
--------------------------------------------------------------------------------
1 |
2 | /* __...__
3 | ..-' '.
4 | .-' |
5 | _..' EEQL |
6 | ...--"" .
7 | ..-" __.'
8 | .' ___...--'
9 | : ____....---'
10 | : .'
11 | : : _____
12 | : : _..--""" """--..__
13 | : : ." ""i--.
14 | : '.: : '.
15 | : '--...___i---""""--..___.' :
16 | : ""---...---"" :
17 | '. :
18 | '-. :
19 | '--... .'
20 | : ""---....._____.....---""
21 | '. '.
22 | '-.. '.
23 | '. :
24 | : .'
25 | / :
26 | .' :
27 | .' .--'
28 | '--' */
--------------------------------------------------------------------------------
/src/components/FileTree/FileTree.scss:
--------------------------------------------------------------------------------
1 | * {
2 | list-style-type: none;
3 | }
4 | .file-tree-item {
5 | font-size: 16px;
6 | background-color: transparent;
7 | color: rgb(255, 214, 163);
8 | border: none;
9 | }
10 |
11 | #file-tree-head {
12 | list-style-type: none !important;
13 | }
14 |
15 | #file-tree-head {
16 | font-family: Arial, Helvetica, sans-serif;
17 | border: solid 2px rgb(255, 214, 163);
18 | padding: 20px 120px 50px 30px;
19 | padding-right: 40px;
20 | font-size: 20px;
21 | }
22 |
23 | #file-tree-head-empty {
24 | font-family: Arial, Helvetica, sans-serif;
25 | border: solid 2px rgb(255, 214, 163);
26 | padding: 20px;
27 | padding-right: 20px;
28 | text-align: center;
29 | font-size: 14px;
30 | }
--------------------------------------------------------------------------------
/src/components/FileTree/FileTree.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext, useEffect, useState } from "react";
2 | import { StateContext } from "../../provider/StateProvider";
3 | import "./FileTree.scss";
4 |
5 | // create the file tree and allow a expand/minimize functionality.
6 | // if no files included,
7 | const FileTree = () => {
8 | const [folderView, setFolderView] = useState({});
9 | const { userPath, fileTree, activeFileHandler }: any = useContext(
10 | StateContext
11 | );
12 | const projectName = nameSetter(userPath.split("/"));
13 | const viewValue: {
14 | [key: string]: Boolean;
15 | } = {};
16 |
17 | function nameSetter(name) {
18 | return name[name.length - 1];
19 | }
20 |
21 | const viewHandler = (fileName: string): void => {
22 | folderView[fileName]
23 | ? setFolderView({ ...folderView, [fileName]: false })
24 | : setFolderView({ ...folderView, [fileName]: true });
25 | };
26 |
27 | useEffect(() => {
28 | setFolderView(viewValue);
29 | }, []);
30 |
31 | const createTree = (tree) =>
32 | tree.map((file) => {
33 | let ext = [file.name.split(".")[1], file.name.split(".")[2]];
34 | if (file.files.length || ext[0] === undefined) {
35 | viewValue[file.name] = false;
36 | return (
37 |
38 | -
39 |
46 |
47 | {folderView[file.name] && createTree(file.files)}
48 |
49 | );
50 | } else if (ext[0] == "js" || ext[1] == "js") {
51 | return (
52 |
53 | -
54 |
63 |
64 |
65 | );
66 | } else if (ext[0] == "html") {
67 | return (
68 |
69 | -
70 |
79 |
80 |
81 | );
82 | } else if (ext[0] == "css") {
83 | return (
84 |
85 | -
86 |
95 |
96 |
97 | );
98 | } else if (ext[0] == "test") {
99 | return (
100 |
101 | -
102 |
111 |
112 |
113 | );
114 | } else if (ext[0] == "scss") {
115 | return (
116 |
117 | -
118 |
127 |
128 |
129 | );
130 | } else if (ext[0] == "md") {
131 | return (
132 |
133 | -
134 |
143 |
144 |
145 | );
146 | } else if (ext[1] == "config") {
147 | return (
148 |
149 | -
150 |
159 |
160 |
161 | );
162 | } else if (ext[0] == "json") {
163 | return (
164 |
165 | -
166 |
175 |
176 |
177 | );
178 | } else if (ext[0] == "tsx") {
179 | return (
180 |
181 | -
182 |
191 |
192 |
193 | );
194 | } else if (
195 | ext[0] == "png" ||
196 | ext[0] == "jpeg" ||
197 | ext[0] == "jpg" ||
198 | ext[0] == "svc" ||
199 | ext[0] == "icn"
200 | ) {
201 | return (
202 |
203 | -
204 |
213 |
214 |
215 | );
216 | } else {
217 | return (
218 |
219 | -
220 |
229 |
230 |
231 | );
232 | }
233 | });
234 | if (userPath.length > 1) {
235 | return (
236 |
237 |
238 |
239 | {" " + projectName}
240 |
241 |
{userPath}
242 | {createTree(fileTree)}
243 |
244 | );
245 | } else
246 | return (
247 |
248 |
249 |
250 | {" EMPTY"}
251 |
252 |
253 | );
254 | };
255 |
256 | export default FileTree;
257 |
--------------------------------------------------------------------------------
/src/components/FileUpdate/FileUpdate.scss:
--------------------------------------------------------------------------------
1 | #file-upload-head {
2 | display: block;
3 | margin-left: auto;
4 | margin-right: auto;
5 | }
6 |
7 | .MuiButton-label {
8 | border-bottom: none !important;
9 |
10 | }
11 |
12 | .MuiButton-containedPrimary {
13 | margin-left: 12px !important;
14 | min-width: 20px;
15 |
16 | text-decoration: none !important;
17 | }
18 | .MuiSvgIcon-root {
19 | padding: 4px;
20 | margin-left: 4px;
21 | }
22 |
23 | .MuiButton-containedPrimary {
24 | background-color: #32c2b5 !important;
25 | // color: rgb(52, 52, 52) !important;
26 | display: inline flex !important;
27 | margin: 12px !important ;
28 | // margin: 2px;
29 | }
30 | .MuiInputBase-input {
31 | // margin-right: -90px !important;
32 | box-shadow: none;
33 | color: white !important;
34 | // text-align: right;
35 | }
36 | .MuiInput-underline:after {
37 | border-bottom: 2px solid #ffad3f !important;
38 |
39 | }
40 | .MuiInput-root {
41 | border-bottom: 2px solid #32c2b5 !important;
42 | // padding: 6px 6px !important;
43 | // margin: 8px;
44 | }
45 | .MuiTouchRipple-root {
46 | color: #32c2b5;
47 | }
48 | .aws-btn {
49 | font-family: Arial, Helvetica, sans-serif;
50 | --button-default-height: 50px;
51 | --button-default-font-size: 14px;
52 | --button-default-border-radius: 7px;
53 | --button-horizontal-padding: 25px;
54 | --button-raise-level: 7px;
55 | --button-hover-pressure: 3;
56 | --transform-speed: 0.175s;
57 | --button-primary-color: #32c2b5;
58 | --button-primary-color-dark: #167970;
59 | --button-primary-color-light: #000000;
60 | --button-primary-color-hover: #b1ece6;
61 | --button-primary-border: 0px solid #ffffff;
62 | --button-secondary-color: #f8ac40;
63 | --button-secondary-color-dark: #7e5011;
64 | --button-secondary-color-light: #000000;
65 | --button-secondary-color-hover: #ffd9a3;
66 | --button-secondary-border: none;
67 | --button-anchor-color: #b30000;
68 | --button-anchor-color-dark: #791616;
69 | --button-anchor-color-light: #000000;
70 | --button-anchor-color-hover: #ff0000;
71 | --button-anchor-border: 1px solid #922a2a;
72 | }
--------------------------------------------------------------------------------
/src/components/FileUpdate/FileUpdate.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 | /* eslint-disable import/no-unresolved */ // ! Be careful
3 |
4 | import React, { useContext, useState, useEffect } from "react";
5 | import { StateContext } from "../../provider/StateProvider";
6 | import { Link } from "react-router-dom";
7 | // @ts-ignore
8 | import "react-awesome-button/dist/styles.scss";
9 | import "./FileUpdate.scss";
10 | // @ts-ignore
11 | import { AwesomeButton, AwesomeButtonProgress } from "react-awesome-button";
12 |
13 | const { remote } = window.require("electron");
14 | const fs = remote.require("fs");
15 | let current: string = "";
16 | let directoryArray;
17 | let fileArray;
18 | let cancelled = false;
19 |
20 | const FileUpdate = () => {
21 | function nameSetter(name) {
22 | return name[name.length - 1];
23 | }
24 | const {
25 | userPath,
26 | fileTreeHandler,
27 | pathHandler,
28 | fileTree,
29 | updateTree,
30 | }: any = useContext(StateContext);
31 | const { activePortHandler }: any = useContext(StateContext);
32 | const projectName = nameSetter(userPath.split("/"));
33 |
34 | const setPort = (e) => {
35 | e.preventDefault();
36 | console.log(e.target.value);
37 | activePortHandler(e.target.value);
38 | };
39 | const getPath = () => {
40 | remote.dialog
41 | .showOpenDialog({
42 | properties: ["openDirectory"],
43 | message: "Please choose your project folder",
44 | })
45 | .then((files: any) => {
46 | if (files.cancelled) {
47 | cancelled = true;
48 | } else !files.cancelled;
49 | current = files.filePaths[0];
50 | exportTestFile(current);
51 | pathHandler(files.filePaths[0]);
52 | generateFileTree(current);
53 | });
54 | };
55 | const exportTestFile = (dir) => {
56 | if (!fs.existsSync(`${dir}/__tests__`)) fs.mkdirSync(`${dir}/__tests__`);
57 | };
58 | const generateFileTree = (dir) => {
59 | let getDirectory = (current) => {
60 | directoryArray = fs
61 | .readdirSync(current)
62 | .filter((file) => file !== "node_modules" && file[0] !== ".");
63 | if (directoryArray.filter((file, i) => !file.includes("")) == []) {
64 | return directoryArray;
65 | }
66 | };
67 | getDirectory(dir);
68 |
69 | fileArray = directoryArray.map((name: string) => {
70 | let path = dir;
71 | path = `${path}/${name}`;
72 | const file: any = { path, name, files: [] };
73 |
74 | if (!file.name.includes(".")) {
75 | file.files = generateFileTree(file.path);
76 | }
77 | return file;
78 | });
79 | fileTreeHandler(fileArray);
80 | return fileArray;
81 | };
82 |
83 | return (
84 |
102 | );
103 | };
104 |
105 | export default FileUpdate;
106 |
--------------------------------------------------------------------------------
/src/components/FileUpload/FileUpload.scss:
--------------------------------------------------------------------------------
1 | #file-upload-head {
2 | display: block;
3 | margin-left: auto;
4 | margin-right: auto;
5 | }
6 |
7 | .MuiButton-label {
8 | border-bottom: none !important;
9 |
10 | }
11 |
12 | .MuiButton-containedPrimary {
13 | margin-left: 12px !important;
14 | min-width: 20px;
15 |
16 | text-decoration: none !important;
17 | }
18 | .MuiSvgIcon-root {
19 | padding: 4px;
20 | margin-left: 4px;
21 | }
22 |
23 | .MuiButton-containedPrimary {
24 | background-color: #32c2b5 !important;
25 | // color: rgb(52, 52, 52) !important;
26 | display: inline flex !important;
27 | margin: 12px !important ;
28 | // margin: 2px;
29 | }
30 | .MuiInputBase-input {
31 | // margin-right: -90px !important;
32 | box-shadow: none;
33 | color: white !important;
34 | text-align: center;
35 | }
36 | .MuiInput-underline:after {
37 | border-bottom: 2px solid #ffad3f !important;
38 |
39 | }
40 | .MuiInput-root {
41 | border-bottom: 2px solid #32c2b5 !important;
42 | // padding: 6px 6px !important;
43 | // margin: 8px;
44 | }
45 | .MuiTouchRipple-root {
46 | color: #32c2b5;
47 | }
48 | .aws-btn {
49 | font-family: Arial, Helvetica, sans-serif;
50 | --button-default-height: 50px;
51 | --button-default-font-size: 14px;
52 | --button-default-border-radius: 7px;
53 | --button-horizontal-padding: 25px;
54 | --button-raise-level: 7px;
55 | --button-hover-pressure: 3;
56 | --transform-speed: 0.175s;
57 | --button-primary-color: #32c2b5;
58 | --button-primary-color-dark: #167970;
59 | --button-primary-color-light: #000000;
60 | --button-primary-color-hover: #b1ece6;
61 | --button-primary-border: 0px solid #ffffff;
62 | --button-secondary-color: #f8ac40;
63 | --button-secondary-color-dark: #7e5011;
64 | --button-secondary-color-light: #000000;
65 | --button-secondary-color-hover: #ffd9a3;
66 | --button-secondary-border: none;
67 | --button-anchor-color: #b30000;
68 | --button-anchor-color-dark: #791616;
69 | --button-anchor-color-light: #000000;
70 | --button-anchor-color-hover: #ff0000;
71 | --button-anchor-border: 1px solid #922a2a;
72 | }
--------------------------------------------------------------------------------
/src/components/FileUpload/FileUpload.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | import { StateContext } from "../../provider/StateProvider";
3 | import Input from "../../../node_modules/@material-ui/core/Input";
4 | import { Link } from "react-router-dom";
5 | // @ts-ignore
6 | import "react-awesome-button/dist/styles.scss";
7 | import "./FileUpload.scss";
8 | // @ts-ignore
9 | import { AwesomeButton, AwesomeButtonProgress } from "react-awesome-button";
10 |
11 | const { remote } = window.require("electron");
12 | const fs = remote.require("fs");
13 | let current: string = "";
14 | let directoryArray;
15 | let fileArray;
16 | let cancelled = false;
17 |
18 | const FileUpload = () => {
19 | function nameSetter(name) {
20 | return name[name.length - 1];
21 | }
22 | const { userPath, fileTreeHandler, pathHandler }: any = useContext(
23 | StateContext
24 | );
25 | const { activePortHandler }: any = useContext(StateContext);
26 | const projectName = nameSetter(userPath.split("/"));
27 |
28 | const exportTestFile = (dir) => {
29 | if (!fs.existsSync(`${dir}/__tests__`)) fs.mkdirSync(`${dir}/__tests__`);
30 | };
31 |
32 | const setPort = (e) => {
33 | e.preventDefault();
34 | activePortHandler(e.target.value);
35 | };
36 |
37 | const getPath = () => {
38 | remote.dialog
39 | .showOpenDialog({
40 | properties: ["openDirectory"],
41 | message: "Please choose your project folder",
42 | })
43 | .then((files: any) => {
44 | if (files.cancelled) {
45 | cancelled = true;
46 | } else !files.cancelled;
47 | current = files.filePaths[0];
48 | exportTestFile(current);
49 | pathHandler(files.filePaths[0]);
50 | generateFileTree(current);
51 | });
52 | };
53 |
54 | const generateFileTree = (dir) => {
55 | let getDirectory = (current) => {
56 | directoryArray = fs
57 | .readdirSync(current)
58 | .filter((file) => file !== "node_modules" && file[0] !== ".");
59 | if (directoryArray.filter((file, i) => !file.includes("")) == []) {
60 | return directoryArray;
61 | }
62 | };
63 | getDirectory(dir);
64 |
65 | fileArray = directoryArray.map((name: string) => {
66 | let path = dir;
67 | path = `${path}/${name}`;
68 | const file: any = { path, name, files: [] };
69 |
70 | if (!file.name.includes(".")) {
71 | file.files = generateFileTree(file.path);
72 | }
73 | return file;
74 | });
75 | fileTreeHandler(fileArray);
76 | return fileArray;
77 | };
78 |
79 | if (fileArray) {
80 | return (
81 |
111 | );
112 | } else
113 | return (
114 |
143 | );
144 | };
145 |
146 | export default FileUpload;
147 |
--------------------------------------------------------------------------------
/src/components/NavBar/NavBar.scss:
--------------------------------------------------------------------------------
1 | /* Dropdown Button */
2 | .dropbtn {
3 | color: #1e1e21;
4 | font-size: 12px;
5 | border: none;
6 |
7 | background-color: #1e1e21;
8 | }
9 | #nav-text {
10 | margin-top: 10px;
11 | }
12 | .port {
13 | text-align: right;
14 | color: #ffffff;
15 |
16 |
17 | }
18 |
19 | /* The container - needed to position the dropdown content */
20 | .dropdown {
21 | display: flex;
22 | flex-direction: row;
23 | align-items: center;
24 | justify-content: flex-start;
25 | margin-bottom: 20px;
26 | padding-bottom: 10px;
27 | // border-bottom: solid 4px rgb(75, 162, 155) !important;
28 | }
29 |
--------------------------------------------------------------------------------
/src/components/NavBar/NavBar.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | import { Link } from "react-router-dom";
3 | import "./NavBar.scss";
4 | import PortUpdate from "../../components/PortUpdate/PortUpdate";
5 | import FileUpdate from "../../components/FileUpdate/FileUpdate";
6 | // @ts-ignore
7 | import logo from "../../../assets/img/eeQl_logo.png";
8 | const NavBar = () => {
9 | return (
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | );
22 | };
23 |
24 | export default NavBar;
25 |
--------------------------------------------------------------------------------
/src/components/PortUpdate/PortUpdate.scss:
--------------------------------------------------------------------------------
1 |
2 | .aws-btn {
3 | font-family: Arial, Helvetica, sans-serif;
4 | --button-default-height: 50px;
5 | --button-default-font-size: 14px;
6 | --button-default-border-radius: 7px;
7 | --button-horizontal-padding: 25px;
8 | --button-raise-level: 7px;
9 | --button-hover-pressure: 3;
10 | --transform-speed: 0.175s;
11 | --button-primary-color: #32c2b5;
12 | --button-primary-color-dark: #167970;
13 | --button-primary-color-light: #000000;
14 | --button-primary-color-hover: #b1ece6;
15 | --button-primary-border: 0px solid #ffffff;
16 | --button-secondary-color: #f8ac40;
17 | --button-secondary-color-dark: #7e5011;
18 | --button-secondary-color-light: #000000;
19 | --button-secondary-color-hover: #ffd9a3;
20 | --button-secondary-border: none;
21 | --button-anchor-color: #b30000;
22 | --button-anchor-color-dark: #791616;
23 | --button-anchor-color-light: #000000;
24 | --button-anchor-color-hover: #ff0000;
25 | --button-anchor-border: 1px solid #922a2a;
26 | }
--------------------------------------------------------------------------------
/src/components/PortUpdate/PortUpdate.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 | /* eslint-disable import/no-unresolved */ // ! Be careful
3 |
4 | import React, { useContext, useState } from "react";
5 | import { StateContext } from "../../provider/StateProvider";
6 | import "./PortUpdate.scss";
7 | import { Link } from "react-router-dom";
8 | import Input from "../../../node_modules/@material-ui/core/Input";
9 | // @ts-ignore
10 | import "react-awesome-button/dist/styles.scss";
11 | // @ts-ignore
12 | import { AwesomeButton } from "react-awesome-button";
13 |
14 | const { remote } = window.require("electron");
15 | const fs = remote.require("fs");
16 |
17 | const PortUpdate = () => {
18 | const { activePortHandler, activePort }: any = useContext(StateContext);
19 | const [newPort, newPortHandler] = useState(false);
20 |
21 | let submitPort = () => {
22 | newPortHandler(false);
23 | };
24 |
25 | let updatePort = (e) => {
26 | if (newPort === false) {
27 | newPortHandler(true);
28 | } else {
29 | activePortHandler(e.target.value);
30 | }
31 | };
32 |
33 | if (newPort === false)
34 | return (
35 |
42 | );
43 | else
44 | return (
45 |
59 | );
60 | };
61 |
62 | export default PortUpdate;
63 |
--------------------------------------------------------------------------------
/src/components/TestSuite/GraphQLEndpoint/GraphQLEndpoint.scss:
--------------------------------------------------------------------------------
1 | // h4 {
2 | // font-size: 14px;
3 | // }
4 |
5 | .gql-endpoint {
6 | display: flex;
7 | flex-direction: column;
8 | justify-content: space-evenly;
9 | color: rgb(216, 216, 216);
10 |
11 | }
12 |
13 | #test-title {
14 | padding: 8px;
15 | }
16 |
17 | #server-button {
18 | padding-top: 10px;
19 | padding-bottom: 10px;
20 | }
21 |
22 | // #operationIsMutation {
23 | // color: green;
24 | // background-color: yellow;
25 | // }
26 |
27 | // .file {
28 | // align-self: flex-start;
29 | // }
30 |
31 | // .test {
32 | // align-self: center;
33 | // }
34 |
35 | // .code {
36 | // align-self: flex-end;
37 | // }
--------------------------------------------------------------------------------
/src/components/TestSuite/GraphQLEndpoint/GraphQLEndpoint.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useContext } from "react";
2 | // import GraphQL from "graphql";
3 | // @ts-ignore
4 | import { TestContext } from "../../../provider/TestProvider";
5 | import { StateContext } from "../../../provider/StateProvider";
6 | import Input from "../../../../node_modules/@material-ui/core/Input";
7 | import "./GraphQLEndpoint.scss";
8 | // @ts-ignore
9 | import { AwesomeButtonProgress } from "react-awesome-button";
10 |
11 | import Switch, { SwitchClassKey, SwitchProps } from '@material-ui/core/Switch';
12 | import Grid from '@material-ui/core/Grid';
13 | import { green } from '@material-ui/core/colors'
14 | import { withStyles } from '@material-ui/core/styles'
15 |
16 | const { remote } = window.require("electron");
17 | const GraphQl = () => {
18 | const { test, testHandler }: any = useContext(TestContext);
19 | const { activePort, activeFile, setActiveFile }: any = useContext(
20 | StateContext
21 | );
22 | const [operationIsMutation, setOperationIsMutation] = useState(false);
23 | const [operationIsValid, setOperationIsValid] = useState(false);
24 |
25 | // variable denoting current file in file operations
26 | let current;
27 |
28 |
29 | // handler for adding schema path to state
30 | const getSchemaPath = () => {
31 | remote.dialog
32 | .showOpenDialog({
33 | properties: ["openFile"],
34 | message: "Please choose your schema file",
35 | })
36 | .then((files: any) => {
37 | if (!files.cancelled) {
38 | current = files.filePaths[0];
39 | testHandler("schemaFile", current);
40 | }
41 | });
42 | };
43 |
44 | // handler for adding resolver path to state
45 | const getResolverPath = () => {
46 | remote.dialog
47 | .showOpenDialog({
48 | properties: ["openFile"],
49 | message: "Please choose your resolver file",
50 | })
51 | .then((files: any) => {
52 | if (!files.cancelled) {
53 | current = files.filePaths[0];
54 | testHandler("resolverFile", current);
55 | }
56 | });
57 | };
58 |
59 | // handler for adding data from input fields to state
60 | const inputHandler = (e: React.ChangeEvent
): void => {
61 | if (e == null) {
62 | console.log({ schemaFile: current });
63 | testHandler("schemaFile", current);
64 | } else if (e == undefined) {
65 | console.log({ resolverFile: current });
66 | testHandler("resolverFile", current);
67 | } else testHandler(e.target.id, (e.target as HTMLInputElement).value);
68 | };
69 |
70 | // handler for query/mutation switch
71 | const gqlOperationHandler = (): void => {
72 | setOperationIsMutation(!operationIsMutation)
73 | testHandler("operationIsMutation", operationIsMutation);
74 | }
75 |
76 | // handler for valid/invalid query switch
77 | const validOperationHandler = (): void => {
78 | setOperationIsValid(!operationIsValid)
79 | testHandler("operationIsValid", operationIsValid);
80 | }
81 |
82 | //color change for switch
83 | const GreenSwitch = withStyles({
84 | switchBase: {
85 | color: green[300],
86 | '&$checked': {
87 | color: green[500],
88 | },
89 | '&$checked + $track': {
90 | backgroundColor: green[500],
91 | },
92 | },
93 | checked: {},
94 | track: {},
95 | }
96 | )(Switch)
97 |
98 |
99 |
100 | return (
101 |
102 |
103 |
GraphQL Test Builder
104 |
203 |
204 | );
205 | };
206 |
207 | export default GraphQl;
--------------------------------------------------------------------------------
/src/components/TestSuite/GraphQLEndpoint/MockSchema.js:
--------------------------------------------------------------------------------
1 | import { gql } from "@apollo/client";
2 | //gql function to parse the query string into a query document.
3 |
4 | export const dummyQuery = gql`
5 | query starwars {
6 | people {
7 | id
8 | name
9 | birth_year
10 | films {
11 | title
12 | }
13 | }
14 | }
15 | `;
16 |
17 | export function StarWars({ name }) {
18 | const { loading, error, data } = useQuery(dummyQuery, {
19 | variables: { name },
20 | });
21 | if (loading) return Loading!
;
22 | if (error) return Error ;3
;
23 |
24 | return (
25 |
26 | {data.people.name} was born in {data.people.year}
27 |
28 | );
29 | }
30 |
--------------------------------------------------------------------------------
/src/components/TestSuite/RestEndpoint/RestEndpoint.scss:
--------------------------------------------------------------------------------
1 | // h4 {
2 | // font-size: 14px;
3 | // }
4 |
5 | .rest-endpoint {
6 | display: flex;
7 | flex-direction: column;
8 | justify-content: space-evenly;
9 | color: rgb(216, 216, 216);
10 |
11 | }
12 |
13 | #test-title {
14 | padding: 8px;
15 | }
16 | #server-button {
17 | padding-top: 10px;
18 | padding-bottom: 10px;
19 | }
20 |
21 | // .file {
22 | // align-self: flex-start;
23 | // }
24 |
25 | // .test {
26 | // align-self: center;
27 | // }
28 |
29 | // .code {
30 | // align-self: flex-end;
31 | // }
32 |
33 |
--------------------------------------------------------------------------------
/src/components/TestSuite/RestEndpoint/RestEndpoint.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState } from "react";
2 | import { TestContext } from "../../../provider/TestProvider";
3 | import { StateContext } from "../../../provider/StateProvider";
4 | import "./RestEndpoint.scss";
5 | import Input from "../../../../node_modules/@material-ui/core/Input";
6 | // @ts-ignore
7 | import { AwesomeButtonProgress } from "react-awesome-button";
8 | const { remote } = window.require("electron");
9 |
10 | const RestEndpoint = () => {
11 | const { test, testHandler }: any = useContext(TestContext);
12 | const { activePort, activeFile, setActiveFile }: any = useContext(
13 | StateContext
14 | );
15 | const [local, localhandler] = useState({});
16 | let current;
17 |
18 | //Add methods to methodOptions array, and create options to be rendered in select/dropdown element
19 | const methods = ["GET", "POST", "PUT", "DELETE"];
20 | const methodOptions = [];
21 | for (let a = 0; a < methods.length; a++) {
22 | methodOptions.push(
23 |
26 | );
27 | }
28 | const getPath = () => {
29 | remote.dialog
30 | .showOpenDialog({
31 | properties: ["openFile"],
32 | message: "Please choose your server file",
33 | })
34 | .then((files: any) => {
35 | if (!files.cancelled) {
36 | current = files.filePaths[0];
37 | inputHandler(null);
38 | }
39 | });
40 | };
41 |
42 | //handler for state to reflect entires in a select tag
43 | const selectHandler = (e: any): void => {
44 | const dropdownId = e.target.id;
45 | const dropdown = document.getElementById(dropdownId) as HTMLSelectElement;
46 | const selection = dropdown.options[dropdown.selectedIndex].text;
47 | testHandler(dropdownId, selection);
48 | };
49 |
50 | //handler for state to reflect entries in an input tag
51 | const inputHandler = (e: React.ChangeEvent): void => {
52 | if (e == null) {
53 | console.log({ serverApp: current });
54 | testHandler("serverApp", current);
55 | } else testHandler(e.target.id, (e.target as HTMLInputElement).value);
56 | };
57 |
58 | return (
59 |
60 |
61 |
REST Test Builder
62 |
132 |
133 | );
134 | };
135 |
136 | export default RestEndpoint;
137 |
--------------------------------------------------------------------------------
/src/components/TestSuite/Supertest.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | const request = require("supertest");
3 | const fs = require("fs");
4 | const path = require("path");
5 | // const app = require('app');
6 | import { TestContext } from "../../provider/TestProvider";
7 | import { StateContext } from "../../provider/StateProvider";
8 |
9 | const { test, monacoPoster } = useContext(TestContext);
10 | const { activePort } = useContext(StateContext);
11 | const db = "./db/markets.js";
12 |
13 | // if element selected is strictly equal to POST, the post request test should run
14 | if (test.methodSelect === "POST") {
15 | //POST request test
16 | //describe syntax
17 | describe(`${db}`, () => {
18 | //it syntax
19 | it(`${test.expectedRes}`, (done) => {
20 | //request
21 | request(activePort)
22 | //post method
23 | .post(test.serverApp)
24 | //send method
25 | .send(`value is equivalent to ${outputDropdown.selectedIndex.text}`)
26 | //expect method
27 | .expect(res.status)
28 | .to.be.equal(200)
29 | //done method
30 | .done();
31 | });
32 | });
33 | }
34 |
35 | const str = `${test.expectedRes} `;
36 | monacoPoster(str);
37 | // console.log(str)
38 |
39 | // if element selected is strictly equal to GET, the get request test should run
40 | if (document.getElementById("methodSelect") === "GET") {
41 | //GET request test
42 | //describe syntax
43 | describe(`${db}`, () => {
44 | //it syntax
45 | it(`${test.expectedRes}`, (done) => {
46 | request(activePort)
47 | //get method
48 | .get(test.serverApp)
49 | //set method
50 | .set({
51 | Accept: "application/json",
52 | })
53 | //expect method
54 | .expect({
55 | "Content-Type": "json",
56 | })
57 | //done method
58 | .done();
59 | });
60 | });
61 | }
62 |
63 | // if element selected is strictly equal to PUT, the put request test should run
64 | if (document.getElementById("methodSelect") === "PUT") {
65 | //PUT request test
66 | //describe syntax
67 | describe(`${db}`, () => {
68 | //it syntax
69 | it(`${test.expectedRes}`, (done) => {
70 | request(activePort)
71 | //get method
72 | .put(test.serverApp)
73 | //set method
74 | .set({
75 | Accept: "application/json",
76 | })
77 | //expect method
78 | .expect({
79 | "Content-Type": "json",
80 | })
81 | //done method
82 | .done();
83 | });
84 | });
85 | }
86 |
87 | // if element selected is strictly equal to DELETE, the delete request test should run
88 | if (document.getElementById("methodSelect") === "DELETE") {
89 | //DELETE request test
90 | describe(`${db}`, () => {
91 | //it syntax
92 | it(`${test.expectedRes}`, (done) => {
93 | request(activePort)
94 | //get method
95 | .delete(test.serverApp)
96 | //set method
97 | .set({
98 | Accept: "application/json",
99 | })
100 | //expect method
101 | .expect({
102 | "Content-Type": "json",
103 | })
104 | //done method
105 | .done();
106 | });
107 | });
108 | }
109 |
110 | export default TestSuite;
111 |
--------------------------------------------------------------------------------
/src/components/TestSuite/TestBuilder/TestBuilder.scss:
--------------------------------------------------------------------------------
1 | // h3 {
2 | // font-size: 14px;
3 | // }
4 |
5 | // .test-builder {
6 | // display: grid;
7 | // justify-content: center;
8 | // color: rgb(216, 216, 216);
9 | // width: 15vw;
10 | // }
11 |
12 | // .file {
13 | // align-self: flex-start;
14 | // }
15 |
16 | // .test {
17 | // align-self: center;
18 | // }
19 |
20 | // .code {
21 | // align-self: flex-end;
22 | // }
23 | .test-builder {
24 | font-family: Arial, Helvetica, sans-serif;
25 | border: solid 2px rgb(255, 214, 163);
26 | padding: 40px 40px 40px 40px;
27 | text-align: center;
28 | }
29 |
30 |
31 | .aws-btn {
32 | font-family: Arial, Helvetica, sans-serif;
33 | padding: 2px;
34 | margin: 5px;
35 | --button-default-height: 50px;
36 | --button-default-font-size: 14px;
37 | --button-default-border-radius: 7px;
38 | --button-horizontal-padding: 25px;
39 | --button-raise-level: 7px;
40 | --button-hover-pressure: 3;
41 | --transform-speed: 0.175s;
42 | --button-primary-color: #32c2b5;
43 | --button-primary-color-dark: #167970;
44 | --button-primary-color-light: #000000;
45 | --button-primary-color-hover: #b1ece6;
46 | --button-primary-border: 0px solid #ffffff;
47 | --button-secondary-color: #f8ac40;
48 | --button-secondary-color-dark: #7e5011;
49 | --button-secondary-color-light: #000000;
50 | --button-secondary-color-hover: #ffd9a3;
51 | --button-secondary-border: none;
52 | --button-anchor-color: #b30000;
53 | --button-anchor-color-dark: #791616;
54 | --button-anchor-color-light: #000000;
55 | --button-anchor-color-hover: #ff0000;
56 | --button-anchor-border: 1px solid #922a2a;
57 | }
58 |
--------------------------------------------------------------------------------
/src/components/TestSuite/TestBuilder/TestBuilder.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext, useEffect, useState } from "react";
2 | import { TestContext } from "../../../provider/TestProvider";
3 | import { StateContext } from "../../../provider/StateProvider";
4 | import "./TestBuilder.scss";
5 | import RestEndpoint from "../RestEndpoint/RestEndpoint";
6 | import GraphQl from "../GraphQLEndpoint/GraphQLEndpoint";
7 | import RestTestCreation from "../TestGeneration/RestTestCreation";
8 | import graphQLTestCreation from "../TestGeneration/graphQLTestCreation"
9 | import Input from "../../../../node_modules/@material-ui/core/Input";
10 | import FileUpdate from "../../FileUpdate/FileUpdate"
11 |
12 | // import {ReactDOM, render} from 'react-dom'
13 | // @ts-ignore
14 | import { AwesomeButton, AwesomeButtonProgress } from "react-awesome-button";
15 |
16 |
17 | const { remote } = window.require("electron");
18 | const fs = remote.require("fs");
19 | let directoryArray;
20 | let fileArray;
21 |
22 | const TestBuilder = () => {
23 | const { test, testHandler, resetHandler }: any = useContext(TestContext);
24 | const {
25 | userPath,
26 | activeFile,
27 | activeFileHandler,
28 | updateTreeHandler,
29 | fileTreeHandler,
30 | pathHandler,
31 | fileTree,
32 | updateTree,
33 | }: any = useContext(StateContext);
34 | const [local, localhandler] = useState(true);
35 | const [testName, testNameHandler] = useState('');
36 |
37 | const generateFileTree = (dir) => {
38 | let getDirectory = (current) => {
39 | directoryArray = fs
40 | .readdirSync(current)
41 | .filter((file) => file !== "node_modules" && file[0] !== ".");
42 | if (directoryArray.filter((file, i) => !file.includes("")) == []) {
43 | return directoryArray;
44 | }
45 | };
46 | getDirectory(dir);
47 |
48 | fileArray = directoryArray.map((name: string) => {
49 | let path = dir;
50 | path = `${path}/${name}`;
51 | const file: any = { path, name, files: [] };
52 |
53 | if (!file.name.includes(".")) {
54 | file.files = generateFileTree(file.path);
55 | }
56 | return file;
57 | });
58 | fileTreeHandler(fileArray);
59 | return fileArray;
60 | };
61 |
62 | const clicker = () => {
63 | // gather current value from all fields.
64 | // serverApp, expectedRes, methodSelect, desiredEndpoint, inputData, outputData, headerInfo
65 | let selectFieldsArray = ["methodSelect"];
66 |
67 | let inputFieldsArray = [
68 | "serverApp",
69 | "expectedRes",
70 | "desiredEndpoint",
71 | "inputData",
72 | "outputData",
73 | "headerInfo",
74 | ];
75 | // iterate through all dropdowns (select is the formal name) to extract current selected value, and store that selection in our state
76 | for (let i = 0; i < selectFieldsArray.length; i++) {
77 | const dropDown = document.getElementById(
78 | selectFieldsArray[i]
79 | ) as HTMLSelectElement;
80 | const selection = dropDown.options[dropDown.selectedIndex].text;
81 | testHandler(selectFieldsArray[i], selection);
82 | }
83 | console.log("state after select fields loop", test);
84 |
85 | for (let j = 0; j < inputFieldsArray.length; j++) {
86 | const inputField = document.getElementById(inputFieldsArray[j]);
87 | const inputValue = inputField.innerText ? inputField.innerText : "qwerty";
88 | testHandler(inputFieldsArray[j], inputValue);
89 | }
90 |
91 | console.log(test);
92 | console.log("monaco", activeFile);
93 | };
94 |
95 | const inputHandler = (e: React.ChangeEvent): void => {
96 | // if (e == null) {
97 | // console.log({ serverApp: current });
98 | // testHandler("serverApp", current);
99 | // } else if (e == undefined) {
100 | // console.log({ schemaApp: current });
101 | // testHandler("schemaApp", current);
102 | // } else
103 | testHandler(e.target.id, (e.target as HTMLInputElement).value);
104 | };
105 |
106 | const handleSaveTest = () => {
107 |
108 | const createTest = (local) ? RestTestCreation(test) : graphQLTestCreation(test);
109 | console.log(createTest);
110 | fs.writeFileSync(
111 | `${userPath}/__tests__/${test.testFileName}.js`,
112 | createTest,
113 | {
114 | encoding: "utf8",
115 | }
116 | );
117 | };
118 |
119 | // if (local) {
120 | return (
121 |
122 |
131 |
localhandler(true)}
136 | >
137 | REST
138 |
139 |
localhandler(false)}
144 | >
145 | GRAPHQL
146 |
147 |
148 | {/* conditionally render the form for building Rest or GraphQL tests */}
149 | {
150 | (local) ?
:
151 | }
152 |
153 | {/* save button */}
154 |
{
161 | console.log("Saving Test...");
162 | handleSaveTest();
163 | generateFileTree(userPath);
164 | setTimeout(() => {
165 | next();
166 | }, 1000);
167 | }}
168 | >
169 | SAVE
170 |
171 |
172 | );
173 | };
174 |
175 | export default TestBuilder;
176 |
--------------------------------------------------------------------------------
/src/components/TestSuite/TestGeneration/RestTestCreation.js:
--------------------------------------------------------------------------------
1 | const RestTestCreation = (state) => {
2 | // Sample Representation of Test Output:
3 | `
4 | const supertest = require('supertest');
5 | const app = require('../server/server.js');
6 | const request = supertest(app);
7 | jest.useFakeTimers();
8 |
9 | test('Gets html from root page', async (done) => {
10 | const response = await request
11 | .get('/')
12 | .set({});
13 | expect(response.status).toBe(200);
14 | return done();
15 | });`;
16 |
17 | const serverApp = state.serverApp;
18 | const expectedRes = state.expectedRes;
19 | const methodSelect = state.methodSelect;
20 | const desiredEndpoint = state.desiredEndpoint;
21 | const inputData =
22 | state.methodSelect === "POST" || state.methodSelect === "PUT"
23 | ? `.send(${state.inputData});`
24 | : "";
25 | const headerInfo = state.headerInfo ? `.set(${headerInfo})` : "";
26 | const outputData = state.outputData;
27 |
28 | const test = `
29 | const supertest = require('supertest');
30 | const app = require('${serverApp}');
31 | const request = supertest(app);
32 | jest.useFakeTimers();
33 |
34 | test('${expectedRes}', async (done) => {
35 | const response = await request
36 | .${methodSelect}('${desiredEndpoint}')
37 | ${inputData}
38 | ${headerInfo}
39 | expect(${inputData}).toBe(${outputData});
40 | return done();
41 | });
42 | `;
43 |
44 | return test;
45 | };
46 |
47 | export default RestTestCreation;
48 |
--------------------------------------------------------------------------------
/src/components/TestSuite/TestGeneration/graphQLTestCreation.js:
--------------------------------------------------------------------------------
1 | const graphQLTestCreation = (state) => {
2 |
3 |
4 | const addMutationObject = (state.operationIsMutation !== false) ? "" : `, ${state.mutationObject}`;
5 |
6 | const egqlBoilerplate = (state) =>
7 | `
8 | 'use strict'
9 |
10 | const fs = require('fs')
11 | const path = require('path')
12 | const EasyGraphQLTester = require('easygraphql-tester')
13 |
14 | const schema = fs.readFileSync(path.join(__dirname, "${state.schemaFile}"), 'utf8')
15 | const resolvers = require("${state.resolverFile}")
16 |
17 | describe('Test queries and mutations', () => {
18 | let tester
19 |
20 | beforeEach(() => {
21 | tester = new EasyGraphQLTester(schema, resolvers)
22 | })
23 | describe('${state.expectedRes}', () => {
24 | `
25 |
26 | const queryValidQueryBoilerPlate = (state) =>
27 | `
28 | it('${state.expectedRes}', () => {
29 | const operation = \`${state.gqlOperationText}\`
30 | tester.test(${state.operationIsValid}, operation${addMutationObject})
31 | })
32 | `
33 |
34 | const closingParens = `
35 | })
36 | })
37 | `
38 |
39 | return egqlBoilerplate(state) + queryValidQueryBoilerPlate(state) + closingParens;
40 | };
41 |
42 | export default graphQLTestCreation;
43 |
--------------------------------------------------------------------------------
/src/components/TestSuite/server/db/markets.dev.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "location": "losangeles",
4 | "cards": 6
5 | },
6 | {
7 | "location": "sdfsdf",
8 | "cards": 0
9 | }
10 | ]
--------------------------------------------------------------------------------
/src/components/TestSuite/server/db/markets.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 |
3 | let writeLocation;
4 | let marketList;
5 |
6 | if (process.env.NODE_ENV === 'test') {
7 | writeLocation = `${__dirname}/markets.test.json`;
8 | marketList = JSON.parse(fs.readFileSync(writeLocation));
9 | } else {
10 | writeLocation = `${__dirname}/markets.dev.json`;
11 | marketList = JSON.parse(fs.readFileSync(writeLocation));
12 | }
13 |
14 | const db = {};
15 |
16 |
17 | /**
18 | * #sync - Overwrites the current database with markets list from client
19 | *
20 | * @param {Array} markets - the new market list
21 | * @return {Array} the list of markets
22 | */
23 | db.sync = (markets) => {
24 | if (!Array.isArray(markets)) {
25 | return new Error(`Market list must be an array, received ${typeof markets}`);
26 | }
27 | if (markets.some(m => m.location === undefined || m.cards === undefined)) {
28 | return new Error('Missing fields on some markets');
29 | }
30 | if (markets.some(m => typeof m.location !== 'string')) {
31 | return new Error('TypeError in your market location');
32 | }
33 | if (markets.some(m => typeof m.cards !== 'number')) {
34 | return new Error('TypeError in your market cards');
35 | }
36 | db.write(markets);
37 | db.reset();
38 | return marketList;
39 | };
40 |
41 |
42 | /**
43 | * #find - Returns the entire list of markets from the appropriate
44 | * markets.env.json file.
45 | *
46 | * @return {Array} the list of markets
47 | */
48 | db.find = () => {
49 | db.reset();
50 | return marketList;
51 | };
52 |
53 |
54 | /**
55 | * #drop - Deletes everything from the appropriate markets.env.json file and
56 | * writes an empty array in its place.
57 | */
58 | db.drop = () => {
59 | marketList = [];
60 | db.write(marketList);
61 | };
62 |
63 |
64 | db.write = (data) => {
65 | fs.writeFileSync(writeLocation, JSON.stringify(data, null, 2));
66 | };
67 |
68 |
69 | db.reset = () => {
70 | marketList = JSON.parse(fs.readFileSync(writeLocation));
71 | };
72 |
73 |
74 | module.exports = db;
75 |
--------------------------------------------------------------------------------
/src/components/TestSuite/server/db/markets.test.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "location": "kansascity",
4 | "cards": 17
5 | }
6 | ]
--------------------------------------------------------------------------------
/src/components/TestSuite/server/index.js:
--------------------------------------------------------------------------------
1 | /* eslint no-unused-vars: 0 */
2 | const path = require('path');
3 | const express = require('express');
4 | const db = require('./db/markets');
5 |
6 | const app = express();
7 | const port = process.env.PORT || 3000;
8 |
9 | app.use(express.static(path.resolve(__dirname, '../dist')));
10 | app.use(express.json());
11 |
12 | app.put('/markets', (req, res, next) => {
13 | const syncResult = db.sync(req.body);
14 | if (syncResult instanceof Error) {
15 | return next({ code: 400, error: syncResult });
16 | }
17 | res.json(syncResult);
18 | });
19 |
20 | app.get('/markets', (req, res) => {
21 | res.json(db.find());
22 | });
23 |
24 | app.use(({ code, error }, req, res, next) => {
25 | res.status(code).json({ error });
26 | });
27 |
28 | module.exports = app.listen(port, () => console.log(`Listening on port ${port}`));
29 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 | eeQL
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-unresolved */
2 | // eslint-disable-next-line no-use-before-define //
3 | import React from "react";
4 | import ReactDom from "react-dom";
5 | import { HashRouter } from "react-router-dom";
6 | import StateProvider from "./provider/StateProvider.tsx";
7 | import TestProvider from "./provider/TestProvider.tsx";
8 | import DataProvider from "./provider/TestProvider.tsx";
9 |
10 | import App from "./App";
11 |
12 | ReactDom.render(
13 | // providing hashrouter for electron static application
14 | // need to add providers here v
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | ,
24 | document.getElementById("root")
25 | );
26 |
--------------------------------------------------------------------------------
/src/pages/Home/Home.scss:
--------------------------------------------------------------------------------
1 | .react-resizable {
2 | position: relative;
3 | }
4 | .react-resizable-handle {
5 | position: absolute;
6 | width: 20px;
7 | height: 20px;
8 | background-repeat: no-repeat;
9 | background-origin: content-box;
10 | box-sizing: border-box;
11 | background.react-resizable {
12 | position: relative;
13 | }
14 | .react-resizable-handle {
15 | position: absolute;
16 | width: 20px;
17 | height: 20px;
18 | background-repeat: no-repeat;
19 | background-origin: content-box;
20 | box-sizing: border-box;
21 | background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2IDYiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYwMCIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI2cHgiIGhlaWdodD0iNnB4Ij48ZyBvcGFjaXR5PSIwLjMwMiI+PHBhdGggZD0iTSA2IDYgTCAwIDYgTCAwIDQuMiBMIDQgNC4yIEwgNC4yIDQuMiBMIDQuMiAwIEwgNiAwIEwgNiA2IEwgNiA2IFoiIGZpbGw9IiMwMDAwMDAiLz48L2c+PC9zdmc+');
22 | background-position: bottom right;
23 | padding: 0 3px 3px 0;
24 | }
25 | .react-resizable-handle-sw {
26 | bottom: 0;
27 | left: 0;
28 | cursor: sw-resize;
29 | transform: rotate(90deg);
30 | }
31 | .react-resizable-handle-se {
32 | bottom: 0;
33 | right: 0;
34 | cursor: se-resize;
35 | }
36 | .react-resizable-handle-nw {
37 | top: 0;
38 | left: 0;
39 | cursor: nw-resize;
40 | transform: rotate(180deg);
41 | }
42 | .react-resizable-handle-ne {
43 | top: 0;
44 | right: 0;
45 | cursor: ne-resize;
46 | transform: rotate(270deg);
47 | }
48 | .react-resizable-handle-w {
49 | top: 50%;
50 | margin-top: -10px;
51 | cursor: ew-resize;
52 | left: 0;
53 | transform: rotate(135deg);
54 | }
55 | .react-resizable-handle-e {
56 | top: 50%;
57 | margin-top: -10px;
58 | cursor: ew-resize;
59 | right: 0;
60 | transform: rotate(315deg);
61 | }
62 | .react-resizable-handle-n {
63 | left: 50%;
64 | margin-left: -10px;
65 | cursor: ns-resize;
66 | top: 0;
67 | transform: rotate(225deg);
68 | }
69 | .react-resizable-handle-s {
70 | left: 50%;
71 | margin-left: -10px;
72 | cursor: ns-resize;
73 | bottom: 0;
74 | transform: rotate(45deg);
75 | }
76 | .react-grid-layout {
77 | position: relative;
78 | transition: height 200ms ease;
79 | }
80 | .react-grid-item {
81 | transition: all 200ms ease;
82 | transition-property: left, top;
83 | img {
84 | pointer-events: none;
85 | user-select: none;
86 | }
87 | >.react-resizable-handle {
88 | position: absolute;
89 | width: 20px;
90 | height: 20px;
91 | &::after {
92 | content: "";
93 | position: absolute;
94 | right: 3px;
95 | bottom: 3px;
96 | width: 5px;
97 | height: 5px;
98 | border-right: 2px solid rgba(0, 0, 0, 0.4);
99 | border-bottom: 2px solid rgba(0, 0, 0, 0.4);
100 | }
101 | }
102 | >.react-resizable-handle.react-resizable-handle-sw {
103 | bottom: 0;
104 | left: 0;
105 | cursor: sw-resize;
106 | transform: rotate(90deg);
107 | }
108 | >.react-resizable-handle.react-resizable-handle-se {
109 | bottom: 0;
110 | right: 0;
111 | cursor: se-resize;
112 | }
113 | >.react-resizable-handle.react-resizable-handle-nw {
114 | top: 0;
115 | left: 0;
116 | cursor: nw-resize;
117 | transform: rotate(180deg);
118 | }
119 | >.react-resizable-handle.react-resizable-handle-ne {
120 | top: 0;
121 | right: 0;
122 | cursor: ne-resize;
123 | transform: rotate(270deg);
124 | }
125 | >.react-resizable-handle.react-resizable-handle-w {
126 | top: 50%;
127 | margin-top: -10px;
128 | cursor: ew-resize;
129 | left: 0;
130 | transform: rotate(135deg);
131 | }
132 | >.react-resizable-handle.react-resizable-handle-e {
133 | top: 50%;
134 | margin-top: -10px;
135 | cursor: ew-resize;
136 | right: 0;
137 | transform: rotate(315deg);
138 | }
139 | >.react-resizable-handle.react-resizable-handle-n {
140 | left: 50%;
141 | margin-left: -10px;
142 | cursor: ns-resize;
143 | top: 0;
144 | transform: rotate(225deg);
145 | }
146 | >.react-resizable-handle.react-resizable-handle-s {
147 | left: 50%;
148 | margin-left: -10px;
149 | cursor: ns-resize;
150 | bottom: 0;
151 | transform: rotate(45deg);
152 | }
153 | }
154 | .react-grid-item.cssTransforms {
155 | transition-property: transform;
156 | }
157 | .react-grid-item.resizing {
158 | z-index: 1;
159 | will-change: width, height;
160 | }
161 | .react-grid-item.react-draggable-dragging {
162 | transition: none;
163 | z-index: 3;
164 | will-change: transform;
165 | }
166 | .react-grid-item.dropping {
167 | visibility: hidden;
168 | }
169 | .react-grid-item.react-grid-placeholder {
170 | background: rgb(58, 58, 58);
171 | opacity: 0.2;
172 | transition-duration: 100ms;
173 | z-index: 2;
174 | -webkit-user-select: none;
175 | -moz-user-select: none;
176 | -ms-user-select: none;
177 | -o-user-select: none;
178 | user-select: none;
179 | }
180 | .react-resizable-hide {
181 | >.react-resizable-handle {
182 | display: none;
183 | }
184 | }-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2IDYiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYwMCIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI2cHgiIGhlaWdodD0iNnB4Ij48ZyBvcGFjaXR5PSIwLjMwMiI+PHBhdGggZD0iTSA2IDYgTCAwIDYgTCAwIDQuMiBMIDQgNC4yIEwgNC4yIDQuMiBMIDQuMiAwIEwgNiAwIEwgNiA2IEwgNiA2IFoiIGZpbGw9IiMwMDAwMDAiLz48L2c+PC9zdmc+');
185 | background-position: bottom right;
186 | padding: 0 3px 3px 0;
187 | }
188 | .react-resizable-handle-sw {
189 | bottom: 0;
190 | left: 0;
191 | cursor: sw-resize;
192 | transform: rotate(90deg);
193 | }
194 | .react-resizable-handle-se {
195 | bottom: 0;
196 | right: 0;
197 | cursor: se-resize;
198 | }
199 | .react-resizable-handle-nw {
200 | top: 0;
201 | left: 0;
202 | cursor: nw-resize;
203 | transform: rotate(180deg);
204 | }
205 | .react-resizable-handle-ne {
206 | top: 0;
207 | right: 0;
208 | cursor: ne-resize;
209 | transform: rotate(270deg);
210 | }
211 | .react-resizable-handle-w,
212 | .react-resizable-handle-e {
213 | top: 50%;
214 | margin-top: -10px;
215 | cursor: ew-resize;
216 | }
217 | .react-resizable-handle-w {
218 | left: 0;
219 | transform: rotate(135deg);
220 | }
221 | .react-resizable-handle-e {
222 | right: 0;
223 | transform: rotate(315deg);
224 | }
225 | .react-resizable-handle-n,
226 | .react-resizable-handle-s {
227 | left: 50%;
228 | margin-left: -10px;
229 | cursor: ns-resize;
230 | }
231 | .react-resizable-handle-n {
232 | top: 0;
233 | transform: rotate(225deg);
234 | }
235 | .react-resizable-handle-s {
236 | bottom: 0;
237 | transform: rotate(45deg);
238 | }
239 |
240 | .react-grid-layout {
241 | margin: auto;
242 | transition: height 200ms ease;
243 | }
244 | .react-grid-item {
245 | transition: all 200ms ease;
246 | transition-property: left, top;
247 | }
248 | .react-grid-item img {
249 | pointer-events: none;
250 | user-select: none;
251 | }
252 | .react-grid-item.cssTransforms {
253 | transition-property: transform;
254 | }
255 | .react-grid-item.resizing {
256 | z-index: 1;
257 | will-change: width, height;
258 | }
259 |
260 | .react-grid-item.react-draggable-dragging {
261 | transition: none;
262 | z-index: 3;
263 | will-change: transform;
264 | }
265 |
266 | .react-grid-item.dropping {
267 | visibility: hidden;
268 | }
269 |
270 | .react-grid-item.react-grid-placeholder {
271 | background: red;
272 | opacity: 0.2;
273 | transition-duration: 100ms;
274 | z-index: 2;
275 | -webkit-user-select: none;
276 | -moz-user-select: none;
277 | -ms-user-select: none;
278 | -o-user-select: none;
279 | user-select: none;
280 | }
281 |
282 | .react-grid-item > .react-resizable-handle {
283 | position: absolute;
284 | width: 20px;
285 | height: 20px;
286 | }
287 |
288 | .react-grid-item > .react-resizable-handle::after {
289 | content: "";
290 | position: absolute;
291 | right: 3px;
292 | bottom: 3px;
293 | width: 5px;
294 | height: 5px;
295 | border-right: 2px solid rgba(0, 0, 0, 0.4);
296 | border-bottom: 2px solid rgba(0, 0, 0, 0.4);
297 | }
298 |
299 | .react-resizable-hide > .react-resizable-handle {
300 | display: none;
301 | }
302 |
303 | .react-grid-item > .react-resizable-handle.react-resizable-handle-sw {
304 | bottom: 0;
305 | left: 0;
306 | cursor: sw-resize;
307 | transform: rotate(90deg);
308 | }
309 | .react-grid-item > .react-resizable-handle.react-resizable-handle-se {
310 | bottom: 0;
311 | right: 0;
312 | cursor: se-resize;
313 | }
314 | .react-grid-item > .react-resizable-handle.react-resizable-handle-nw {
315 | top: 0;
316 | left: 0;
317 | cursor: nw-resize;
318 | transform: rotate(180deg);
319 | }
320 | .react-grid-item > .react-resizable-handle.react-resizable-handle-ne {
321 | top: 0;
322 | right: 0;
323 | cursor: ne-resize;
324 | transform: rotate(270deg);
325 | }
326 | .react-grid-item > .react-resizable-handle.react-resizable-handle-w,
327 | .react-grid-item > .react-resizable-handle.react-resizable-handle-e {
328 | top: 50%;
329 | margin-top: -10px;
330 | cursor: ew-resize;
331 | }
332 | .react-grid-item > .react-resizable-handle.react-resizable-handle-w {
333 | left: 0;
334 | transform: rotate(135deg);
335 | }
336 | .react-grid-item > .react-resizable-handle.react-resizable-handle-e {
337 | right: 0;
338 | transform: rotate(315deg);
339 | }
340 | .react-grid-item > .react-resizable-handle.react-resizable-handle-n,
341 | .react-grid-item > .react-resizable-handle.react-resizable-handle-s {
342 | left: 50%;
343 | margin-left: -10px;
344 | cursor: ns-resize;
345 | }
346 | .react-grid-item > .react-resizable-handle.react-resizable-handle-n {
347 | top: 0;
348 | transform: rotate(225deg);
349 | }
350 | .react-grid-item > .react-resizable-handle.react-resizable-handle-s {
351 | bottom: 0;
352 | transform: rotate(45deg);
353 | }
354 |
355 | .grid-border {
356 | display: flex;
357 | flex-direction: row;
358 | flex-wrap: nowrap;
359 | justify-content: space-around;
360 | align-items: center;
361 |
362 | }
363 | .home-border {
364 | margin: 40px !important;
365 | // flex-grow: 2;
366 | background-color: #1e1e21;
367 | color: white;
368 | font-family: Arial, Helvetica, sans-serif;
369 | }
370 |
371 | .file {
372 | padding:5px;
373 | }
374 | .test {
375 | padding:5px;
376 | }
377 | .code {
378 | padding:5px;
379 | }
--------------------------------------------------------------------------------
/src/pages/Home/Home.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | import GridLayout from "react-grid-layout";
3 | import "./Home.scss";
4 |
5 | import CodeEditor from "../../components/CodeEditor/CodeEditor";
6 | import FileTree from "../../components/FileTree/FileTree";
7 | import NavBar from "../../components/NavBar/NavBar";
8 | import TestBuilder from "../../components/TestSuite/TestBuilder/TestBuilder";
9 | import { StateContext } from "../../provider/StateProvider";
10 |
11 | const Home = () => {
12 | //added state context
13 | const { activePortHandler }: any = useContext(StateContext);
14 |
15 | return (
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | );
31 | };
32 |
33 | export default Home;
34 |
--------------------------------------------------------------------------------
/src/pages/Landing/Landing.scss:
--------------------------------------------------------------------------------
1 |
2 | #logo {
3 | display: block;
4 | margin-top: 250px;
5 | margin-left: auto;
6 | margin-right: auto;
7 | width: 50%;
8 | width: 400px;
9 | height: 140px;
10 | }
11 |
12 |
13 | .input {
14 | text-align: center;
15 | }
16 |
17 | .visual {
18 | color: white;
19 | font-family: Arial, Helvetica, sans-serif;
20 | padding: 20px 10px 10px 30px
21 | }
22 | .visualize {
23 | display: flex;
24 | position: absolute !important;
25 | bottom: 100px !important;
26 | width: 100%;
27 | align-items: center;
28 | justify-content: center;
29 | }
30 |
31 | // .darkMode, #global {
32 | // background-color: #201E21 !important;
33 | // }
34 |
35 | // .lightMode, body {
36 | // background-color: white;
37 | // }
38 |
39 |
40 |
41 |
42 | .aws-btn {
43 | font-family: Arial, Helvetica, sans-serif;
44 | padding: 2px;
45 | margin: 5px;
46 | --button-default-height: 50px;
47 | --button-default-font-size: 14px;
48 | --button-default-border-radius: 7px;
49 | --button-horizontal-padding: 25px;
50 | --button-raise-level: 7px;
51 | --button-hover-pressure: 3;
52 | --transform-speed: 0.175s;
53 | --button-primary-color: #32c2b5;
54 | --button-primary-color-dark: #167970;
55 | --button-primary-color-light: #000000;
56 | --button-primary-color-hover: #b1ece6;
57 | --button-primary-border: 0px solid #ffffff;
58 | --button-secondary-color: #f8ac40;
59 | --button-secondary-color-dark: #7e5011;
60 | --button-secondary-color-light: #000000;
61 | --button-secondary-color-hover: #ffd9a3;
62 | --button-secondary-border: none;
63 | --button-anchor-color: #b30000;
64 | --button-anchor-color-dark: #791616;
65 | --button-anchor-color-light: #000000;
66 | --button-anchor-color-hover: #ff0000;
67 | --button-anchor-border: 1px solid #922a2a;
68 | }
69 |
70 |
71 |
--------------------------------------------------------------------------------
/src/pages/Landing/Landing.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState, useEffect } from "react";
2 | import { Link } from "react-router-dom";
3 | import { StateContext } from "../../provider/StateProvider";
4 | // @ts-ignore
5 | import eeQL2 from "../../../assets/img/eeql_logo_copy.png";
6 | import FileUpload from "../../components/FileUpload/FileUpload";
7 | import "react-awesome-button/dist/styles.scss";
8 | import "./Landing.scss";
9 | // @ts-ignore
10 | import { AwesomeButton, AwesomeButtonSocial } from "react-awesome-button";
11 | const shell = require("electron").shell;
12 |
13 |
14 |
15 | const Landing = () => {
16 | return (
17 |
18 |
19 |
20 |
{
24 | window.alert(
25 | "This feature is currently in beta, we appeciate your patience. -eeQL"
26 | );
27 | }}
28 | >
29 | VISUALIZE
30 |
31 |
32 |
{
35 | shell.openExternal("https://github.com/oslabs-beta/eeQL");
36 | }}
37 | >
38 | SOURCE
39 |
40 |
41 |
42 |
43 |
44 |
45 |

46 |
47 |
48 |
49 |
50 |
51 | );
52 | };
53 |
54 | export default Landing;
55 |
--------------------------------------------------------------------------------
/src/pages/Visualize/Visualize.scss:
--------------------------------------------------------------------------------
1 | #graph {
2 | display: inline-flex;
3 | margin-left: 550px;
4 | margin-top: 250px;
5 | }
--------------------------------------------------------------------------------
/src/pages/Visualize/Visualize.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | import { Graph } from "react-d3-graph";
3 | import { Link } from "react-router-dom";
4 | import { DataContext } from "../../provider/DataProvider";
5 | import "./Visualize.scss";
6 |
7 | const Visualize = () => {
8 | const { database }: any = useContext(DataContext);
9 | console.log(database);
10 | const data = {
11 | nodes: [{ id: "Harry" }, { id: "Sally" }, { id: "Alice" }],
12 | focusedNodeId: "nodeIdToTriggerZoomAnimation",
13 | links: [
14 | { source: "Harry", target: "Sally" },
15 | { source: "Harry", target: "Alice" },
16 | ],
17 | };
18 |
19 | const myConfig = {
20 | automaticRearrangeAfterDropNode: false,
21 | collapsible: true,
22 | directed: false,
23 | focusAnimationDuration: 0.75,
24 | focusZoom: 1,
25 | freezeAllDragEvents: false,
26 | height: 400,
27 | highlightDegree: 1,
28 | highlightOpacity: 1,
29 | linkHighlightBehavior: false,
30 | maxZoom: 8,
31 | minZoom: 0.1,
32 | nodeHighlightBehavior: false,
33 | panAndZoom: false,
34 | staticGraph: false,
35 | staticGraphWithDragAndDrop: false,
36 | width: 800,
37 | d3: {
38 | alphaTarget: 0.05,
39 | gravity: -100,
40 | linkLength: 100,
41 | linkStrength: 1,
42 | disableLinkForce: false,
43 | },
44 | node: {
45 | color: "#32c2b5",
46 | fontColor: "white",
47 | fontSize: 10,
48 | fontWeight: "normal",
49 | highlightColor: "SAME",
50 | highlightFontSize: 8,
51 | highlightFontWeight: "normal",
52 | highlightStrokeColor: "SAME",
53 | highlightStrokeWidth: "SAME",
54 | labelProperty: "id",
55 | mouseCursor: "pointer",
56 | opacity: 1,
57 | renderLabel: true,
58 | size: 200,
59 | strokeColor: "none",
60 | strokeWidth: 1.5,
61 | svg: "",
62 | symbolType: "circle",
63 | },
64 | link: {
65 | color: "#d3d3d3",
66 | fontColor: "black",
67 | fontSize: 8,
68 | fontWeight: "normal",
69 | highlightColor: "SAME",
70 | highlightFontSize: 8,
71 | highlightFontWeight: "normal",
72 | labelProperty: "label",
73 | mouseCursor: "pointer",
74 | opacity: 1,
75 | renderLabel: false,
76 | semanticStrokeWidth: false,
77 | strokeWidth: 1.5,
78 | markerHeight: 6,
79 | markerWidth: 6,
80 | strokeDasharray: 0,
81 | strokeDashoffset: 0,
82 | strokeLinecap: "butt",
83 | },
84 | };
85 |
86 | const onClickNode = function(nodeId) {
87 | console.log(`Clicked node ${nodeId}`);
88 | };
89 |
90 | const onClickLink = function(source, target) {
91 | console.log(`Clicked link between ${source} and ${target}`);
92 | };
93 |
94 | return (
95 |
96 |
103 | ;
104 |
105 |
106 |
107 |
108 | );
109 | };
110 |
111 | export default Visualize;
112 |
--------------------------------------------------------------------------------
/src/provider/DataProvider.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 |
3 | //create init state w/ empty object
4 | export const DataContext = React.createContext({});
5 | //create handler that can edit state w/ user input
6 |
7 | //initial state
8 | const DataProviders = ({ children }: any) => {
9 | const [database, setData] = useState("test");
10 |
11 | //handler for all states with k-v's that are added/updated
12 | const dataHandler = (ref) => {
13 | setData(ref);
14 | };
15 |
16 | return (
17 |
23 | {children}
24 |
25 | );
26 | };
27 |
28 | export default DataProviders;
29 |
--------------------------------------------------------------------------------
/src/provider/StateProvider.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 |
3 | // set a variable to export state/handlers into components
4 | export const StateContext = React.createContext({});
5 |
6 | const StateProvider = ({ children }: any) => {
7 |
8 | const [darkMode, setDarkMode] = useState(true)
9 | const darkModeHandler = () => {
10 | setDarkMode(!darkMode)
11 | }
12 |
13 | // update and set state for user active chosen file
14 | const [updateTree, setUpdateTree] = useState(false)
15 | const updateTreeHandler = () => {
16 | setUpdateTree(!updateTree)
17 | }
18 | const [activePort, setActivePort] = useState('')
19 | const activePortHandler = (port: string): void => {
20 | setActivePort(port)
21 | }
22 | const [activeFile, setActiveFile] = useState('');
23 | const activeFileHandler = (chosen: string): void => {
24 | setActiveFile(chosen) };
25 | // update and set the current directory for the user's chosen project
26 | const [userPath, setUserPath] = useState('');
27 | const pathHandler = (pathValue: string):void => {
28 | setUserPath(pathValue) };
29 | // update the on/off of the file tree set below
30 | const [toggleFileTree, setToggleFileTree] = useState(true);
31 | const handleToggleFileTree = (): void => {
32 | setToggleFileTree(!toggleFileTree) };
33 | // update and set the file tree for the directory
34 | const [fileTree, setFileTree] = useState([]);
35 | const fileTreeHandler = (tree: any): void => {
36 | setFileTree(tree) };
37 | // update and set the name of the file that is being exported to the user's fs
38 | const [testFileName, setTestFileName] = useState('');
39 |
40 | // return a wrapped component with the values of state and the functions to change them.
41 | return (
42 |
52 | { children }
53 |
54 | )}
55 |
56 | // export the stateProvider to be accessed when wrapping the head of our react application
57 | export default StateProvider;
--------------------------------------------------------------------------------
/src/provider/TestProvider.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 |
3 | //create init state w/ empty object
4 | export const TestContext = React.createContext({});
5 | //create handler that can edit state w/ user input
6 |
7 | const initialState = {
8 | operationIsValid : true,
9 | }
10 |
11 | //initial state
12 | const TestProviders = ({ children }: any) => {
13 | const [test, setTest] = useState(initialState);
14 |
15 | const [monaco, monacoPoster] = useState('');
16 |
17 | //handler for all states with k-v's that are added/updated
18 | const testHandler = (altKey: string, altValue: any) => {
19 | setTest({ ...test, [altKey]: altValue });
20 | console.log(altKey, altValue, 'updatedState: ',test);
21 | };
22 |
23 | const resetHandler = () =>{
24 | setTest({});
25 | }
26 |
27 | return (
28 |
37 | {children}
38 |
39 | );
40 | };
41 |
42 | export default TestProviders;
43 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | // strict mode if off to prevent strong type errors
4 | "strict": false,
5 | // transpilation method to help interact with node.js
6 | "module": "commonjs",
7 | // importing document object model and previous ES libraries
8 | "lib": ["ES2015", "ES2016", "ES2017", "ES2018", "dom"],
9 | // sets the browser transpilation type
10 | "target": "es5",
11 |
12 | // set to true to allow imported JSX files in TSX modules.
13 | "allowJs": true,
14 | "jsx": "react",
15 |
16 | // set to true to allow editing of previously compiled ts files.
17 | // further serve importing between JSX and TSX files.
18 | "sourceMap": true,
19 | "esModuleInterop": true,
20 | "allowSyntheticDefaultImports": true,
21 |
22 | // export conditions to webpack build folder
23 | "outDir": "./dist"
24 | },
25 | // applies to:
26 | "include": ["./src", "public"],
27 | "exclude": ["node_modules", "dist"]
28 | }
29 |
--------------------------------------------------------------------------------
/webpack.electron.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 |
3 | module.exports = {
4 | // build details
5 | entry: "./public/electron.js",
6 | // resolve imports missing extensions
7 | resolve: { extensions: [".tsx", ".ts", ".js", ".jsx"] },
8 | // allow for use of node modules without altername name in minification
9 | node: {
10 | __dirname: false,
11 | },
12 | // electron build output location
13 | output: {
14 | path: path.resolve(__dirname, "./dist"),
15 | filename: "main.js",
16 | },
17 | // compiles electron when set
18 | target: "electron-main",
19 | devtool: "source-map",
20 | module: {
21 | // define type and loader method
22 | rules: [
23 | {
24 | test: /\.(js|ts|tsx|jsx)$/,
25 | // exclude transpilations of node modules
26 | exclude: /node_modules/,
27 | use: "babel-loader",
28 | },
29 | ],
30 | },
31 | };
32 |
--------------------------------------------------------------------------------
/webpack.react.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const HtmlWebpackPlugin = require("html-webpack-plugin");
3 | const MonacoWebpackPlugin = require("monaco-editor-webpack-plugin");
4 |
5 | const monacoEditor = path.resolve(__dirname, "./node_modules/monaco-editor");
6 | const semanticUI = path.resolve(__dirname, "./node_modules/semantic-ui-react");
7 |
8 | module.exports = {
9 | entry: "./src/index.js",
10 | // performance, allow for tsx editing after transpilation
11 | // create dev server conditions
12 | devtool: "source-map",
13 | devServer: {
14 | contentBase: path.join(__dirname, "./dist"),
15 | // allow fallback to origin
16 | historyApiFallback: true,
17 | compress: true,
18 | hot: true,
19 | port: 4000,
20 | // help serve assets to app
21 | publicPath: "/",
22 | },
23 | // switched target from node to electron renderer. Was receiving errors in monaco client
24 | target: "electron-renderer",
25 | // describe compilation environment
26 | // resolve missing extensions and allow import of node modules
27 | resolve: {
28 | extensions: [".tsx", ".ts", ".js", ".jsx", ".css"],
29 | mainFields: ["main", "module", "browser"],
30 | },
31 | // allow use of code editor and html render plugins
32 | plugins: [
33 | new HtmlWebpackPlugin({
34 | template: path.join(__dirname, "./src/index.html"),
35 | }),
36 | new MonacoWebpackPlugin(),
37 | ],
38 | // define type and loader methods
39 | module: {
40 | rules: [
41 | {
42 | test: /\.ttf$/,
43 | use: "file-loader",
44 | },
45 | {
46 | test: /\.(png|jpe?g|gif)$/i,
47 | use: "file-loader",
48 | },
49 | {
50 | test: /\.(js|ts|tsx|jsx)$/,
51 | exclude: /node_modules/,
52 | use: "babel-loader",
53 | },
54 | {
55 | test: /\.s[ac]ss$/i,
56 | use: ["style-loader", "css-loader", "sass-loader"],
57 | },
58 | {
59 | test: /\.css$/,
60 | include: [monacoEditor, semanticUI],
61 | use: ["style-loader", "css-loader"],
62 | },
63 | {
64 | test: /\.html$/i,
65 | loader: "html-loader",
66 | },
67 | {
68 | test: /\.svg$/,
69 | use: [
70 | {
71 | loader: "svg-url-loader",
72 | options: {
73 | limit: 10000,
74 | },
75 | },
76 | ],
77 | },
78 | {
79 | test: /\.tsx?$/,
80 | use: [{ loader: "ts-loader", options: { happyPackMode: true } }],
81 | },
82 | ],
83 | },
84 |
85 | output: {
86 | path: path.resolve(__dirname, "./dist"),
87 | filename: "index.js",
88 | // altered to allow for access to public files
89 | publicPath: "./",
90 | },
91 | };
92 |
--------------------------------------------------------------------------------