├── .DS_Store ├── .gitignore ├── LICENSE ├── README.md ├── __tests__ ├── __mocks__ │ ├── fileMock.js │ └── styleMock.js ├── enzyme │ └── loginPage.js └── reducerTests │ └── mainReducerTest.js ├── babel.config.js ├── client └── src │ ├── Actions │ └── actions.js │ ├── App.jsx │ ├── Constants │ └── actionTypes.js │ ├── Dashboard │ ├── assets │ │ ├── css │ │ │ └── material-dashboard-react.css │ │ ├── github │ │ │ ├── angular.png │ │ │ ├── chrome.png │ │ │ ├── dashboard.jpg │ │ │ ├── edge.png │ │ │ ├── firefox.png │ │ │ ├── html.png │ │ │ ├── map.jpg │ │ │ ├── md-react.gif │ │ │ ├── notifications.jpg │ │ │ ├── opera.png │ │ │ ├── opt_md_angular_thumbnail.jpg │ │ │ ├── opt_md_thumbnail.jpg │ │ │ ├── opt_md_vue_thumbnail.jpg │ │ │ ├── opt_mdr_thumbnail.jpg │ │ │ ├── react.svg │ │ │ ├── safari.png │ │ │ ├── tables.jpg │ │ │ ├── userprofile.jpg │ │ │ └── vuejs.png │ │ ├── img │ │ │ ├── app-icon.png │ │ │ ├── apple-icon.png │ │ │ ├── cover.jpeg │ │ │ ├── faces │ │ │ │ └── marc.jpg │ │ │ ├── favicon.png │ │ │ ├── gifs │ │ │ │ ├── Clip 3 - Dashboard.gif:Zone.Identifier │ │ │ │ ├── Clip-1-Sign-Up.gif │ │ │ │ ├── Clip-2-Copy-Arn.gif │ │ │ │ ├── Clip-3-Dashboard.gif │ │ │ │ ├── Clip-4-Logs.gif │ │ │ │ ├── Clip-5-API-Gateway.gif │ │ │ │ └── Clip-6-Account-Settings.gif │ │ │ ├── helios-black-logo-t.png │ │ │ ├── helios-blue-logo-t.png │ │ │ ├── helios-logo-background.jpg │ │ │ ├── helios-logo-tr.png │ │ │ ├── mask.png │ │ │ ├── new-app-logo.png │ │ │ ├── new_logo.png │ │ │ ├── reactlogo.png │ │ │ ├── sidebar-1.jpg │ │ │ ├── sidebar-2.jpg │ │ │ ├── sidebar-3.jpg │ │ │ ├── sidebar-4.jpg │ │ │ └── tim_80x80.png │ │ ├── jss │ │ │ ├── material-dashboard-react.js │ │ │ └── material-dashboard-react │ │ │ │ ├── cardImagesStyles.js │ │ │ │ ├── checkboxAdnRadioStyle.js │ │ │ │ ├── components │ │ │ │ ├── buttonStyle.js │ │ │ │ ├── cardAvatarStyle.js │ │ │ │ ├── cardBodyStyle.js │ │ │ │ ├── cardFooterStyle.js │ │ │ │ ├── cardHeaderStyle.js │ │ │ │ ├── cardIconStyle.js │ │ │ │ ├── cardStyle.js │ │ │ │ ├── customInputStyle.js │ │ │ │ ├── customTabsStyle.js │ │ │ │ ├── footerStyle.js │ │ │ │ ├── headerLinksStyle.js │ │ │ │ ├── headerStyle.js │ │ │ │ ├── logTableStyle.js │ │ │ │ ├── rtlHeaderLinksStyle.js │ │ │ │ ├── sidebarStyle.js │ │ │ │ ├── snackbarContentStyle.js │ │ │ │ ├── tableStyle.js │ │ │ │ ├── tasksStyle.js │ │ │ │ └── typographyStyle.js │ │ │ │ ├── dropdownStyle.js │ │ │ │ ├── layouts │ │ │ │ ├── adminStyle.js │ │ │ │ └── rtlStyle.js │ │ │ │ ├── tooltipStyle.js │ │ │ │ └── views │ │ │ │ ├── apiStyle.js │ │ │ │ ├── dashboardStyle.js │ │ │ │ ├── iconsStyle.js │ │ │ │ ├── logsStyle.js │ │ │ │ └── rtlStyle.js │ │ └── scss │ │ │ └── chart_legend.scss │ ├── components │ │ ├── APIList │ │ │ └── APIList.js │ │ ├── Card │ │ │ ├── Card.js │ │ │ ├── CardAvatar.js │ │ │ ├── CardBody.js │ │ │ ├── CardFooter.js │ │ │ ├── CardHeader.js │ │ │ ├── CardIcon.js │ │ │ └── LogCard.js │ │ ├── CustomButtons │ │ │ └── Button.js │ │ ├── CustomInput │ │ │ └── CustomInput.js │ │ ├── CustomTabs │ │ │ └── CustomTabs.js │ │ ├── FetchTime │ │ │ └── FetchTime.js │ │ ├── Footer │ │ │ └── Footer.js │ │ ├── Grid │ │ │ ├── GridContainer.js │ │ │ └── GridItem.js │ │ ├── LambdaList │ │ │ └── LambdaList.js │ │ ├── LambdaListMetrics │ │ │ └── LambdaListMetrics.js │ │ ├── Navbars │ │ │ ├── AdminNavbarLinks.js │ │ │ └── Navbar.js │ │ ├── Sidebar │ │ │ └── Sidebar.js │ │ ├── Snackbar │ │ │ ├── Snackbar.js │ │ │ └── SnackbarContent.js │ │ ├── Table │ │ │ ├── LogTable.js │ │ │ └── Table.js │ │ └── Typography │ │ │ ├── Danger.js │ │ │ ├── Info.js │ │ │ ├── Muted.js │ │ │ ├── Primary.js │ │ │ ├── Quote.js │ │ │ ├── Success.js │ │ │ └── Warning.js │ ├── hooks │ │ ├── index.js │ │ └── useRouteName.js │ ├── layouts │ │ └── Admin.js │ ├── routes.js │ ├── variables │ │ ├── metricAllFuncBarChart.js │ │ ├── metricByFuncBarChart.js │ │ ├── regions.js │ │ └── spinner.js │ └── views │ │ ├── APIGateway │ │ └── APIGateway.js │ │ ├── Dashboard │ │ ├── ChartByFunction │ │ │ └── ChartsByFunction.js │ │ └── Dashboard.js │ │ ├── Logs │ │ └── Logs.js │ │ ├── TableList │ │ └── LambdaMetrics.js │ │ └── UserProfile │ │ └── UserProfile.js │ ├── Pages │ ├── forgotPassword.jsx │ ├── login.jsx │ ├── register.jsx │ └── signup.jsx │ ├── Reducers │ ├── apiReducer.js │ ├── awsReducer.js │ ├── awsReducerbyFunc.js │ ├── index.js │ └── mainReducer.js │ ├── index.js │ ├── indexedDB │ ├── clearIDB.js │ ├── getArnArrayIDB.js │ ├── getRegionIDB.js │ ├── getUserInfo.js │ ├── mainIdb.js │ ├── updateArnIDB.js │ ├── updateRegionIDB.js │ └── updateUserInfoIDB.js │ └── store.js ├── jest-setup.js ├── jest-teardown.js ├── package-lock.json ├── package.json ├── public ├── electron.js ├── index.html └── updatedCloudformationHelios.yaml ├── server ├── Models │ └── userModel.js ├── controllers │ ├── aws │ │ ├── APIGateway │ │ │ ├── getAPI.js │ │ │ ├── getAPIMetrics.js │ │ │ ├── updateAPIMetrics.js │ │ │ └── utils │ │ │ │ └── APIUtilFunc.js │ │ ├── Credentials │ │ │ ├── getCreds.js │ │ │ └── libs │ │ │ │ └── stsClient.js │ │ ├── Logs │ │ │ ├── getLogs.js │ │ │ └── updateLogs.js │ │ └── Metrics │ │ │ ├── getLambdaFuncs.js │ │ │ ├── getMetricsAllFunc.js │ │ │ ├── getMetricsByFunc.js │ │ │ └── utils │ │ │ └── AWSUtilFunc.js │ ├── user │ │ └── nodemailer.js │ └── userController.js ├── routes │ ├── aws.js │ └── user.js └── server.js └── webpack.config.js /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log* 2 | node_modules/ 3 | dist/bundle.js 4 | _*.js 5 | temp.js 6 | package-lock.json 7 | temp/*.* 8 | yarn.lock 9 | build/* 10 | build/ 11 | *.env -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /__tests__/__mocks__/fileMock.js: -------------------------------------------------------------------------------- 1 | module.exports = 'test-file-stub'; 2 | -------------------------------------------------------------------------------- /__tests__/__mocks__/styleMock.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /__tests__/enzyme/loginPage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { configure, shallow, mount, render } from 'enzyme'; 3 | import Adapter from 'enzyme-adapter-react-16'; 4 | import UserProfile from '../../client/src/Dashboard/views/UserProfile/UserProfile'; 5 | import toJson from 'enzyme-to-json'; 6 | import renderer from 'react-test-renderer'; 7 | import configureStore from 'redux-mock-store'; 8 | import SignIn from '../../client/src/Pages/login'; 9 | 10 | configure({ adapter: new Adapter() }); 11 | 12 | describe('SignIn page tests', () => { 13 | const initialState = { 14 | email: '', 15 | firstName: '', 16 | arn: '', 17 | region: '', 18 | credentials: null, 19 | credentialsLoading: false, 20 | }; 21 | const mockStore = configureStore(); 22 | let store; 23 | 24 | describe('SignIn', () => { 25 | let wrapper; 26 | 27 | beforeAll(() => { 28 | store = mockStore(initialState); 29 | wrapper = shallow().dive(); 30 | global.fetch = jest.fn(); 31 | }); 32 | 33 | it('Renders a ', () => { 34 | expect(wrapper.find('WithStyles(ForwardRef(Container))')).toHaveLength(1); 35 | expect(wrapper.find('div')).toHaveLength(1); 36 | }); 37 | 38 | it('Renders the logo image', () => { 39 | expect(wrapper.find('img')).toHaveLength(1); 40 | expect(wrapper.find('img').props().alt).toEqual('Helios Logo'); 41 | }); 42 | 43 | it('Renders the Sign in header', () => { 44 | expect(wrapper.find('WithStyles(ForwardRef(Typography))')).toHaveLength( 45 | 1 46 | ); 47 | expect( 48 | wrapper.find('WithStyles(ForwardRef(Typography))').props().variant 49 | ).toEqual('h5'); 50 | expect(wrapper.find('WithStyles(ForwardRef(Typography))').text()).toMatch( 51 | 'Sign in' 52 | ); 53 | }); 54 | 55 | it('Renders TextFields for email and password', () => { 56 | expect(wrapper.find('WithStyles(ForwardRef(TextField))')).toHaveLength(2); 57 | expect( 58 | wrapper.find('WithStyles(ForwardRef(TextField))#email').props().name 59 | ).toEqual('email'); 60 | expect( 61 | wrapper.find('WithStyles(ForwardRef(TextField))#email').props().label 62 | ).toEqual('Email Address'); 63 | expect( 64 | wrapper.find('WithStyles(ForwardRef(TextField))#password').props().name 65 | ).toEqual('password'); 66 | expect( 67 | wrapper.find('WithStyles(ForwardRef(TextField))#password').props().label 68 | ).toEqual('Password'); 69 | expect( 70 | wrapper.find('WithStyles(ForwardRef(TextField))#password').props().type 71 | ).toEqual('password'); 72 | }); 73 | 74 | it("The TextFields' values change when typed into", () => { 75 | expect( 76 | wrapper.find('WithStyles(ForwardRef(TextField))#email').props().value 77 | ).toEqual(''); 78 | wrapper 79 | .find('WithStyles(ForwardRef(TextField))#email') 80 | .simulate('change', { target: { value: 'test' } }); 81 | expect( 82 | wrapper.find('WithStyles(ForwardRef(TextField))#email').props().value 83 | ).toEqual('test'); 84 | expect( 85 | wrapper.find('WithStyles(ForwardRef(TextField))#password').props().value 86 | ).toEqual(''); 87 | wrapper 88 | .find('WithStyles(ForwardRef(TextField))#password') 89 | .simulate('change', { target: { value: 'test' } }); 90 | expect( 91 | wrapper.find('WithStyles(ForwardRef(TextField))#password').props().value 92 | ).toEqual('test'); 93 | }); 94 | 95 | it('Should send a fetch when Sign In button is clicked', () => { 96 | fetch.mockImplementation(() => { 97 | return Promise.resolve({ 98 | status: 200, 99 | json: () => { 100 | return Promise.resolve({ 101 | confirmed: true, 102 | userInfo: { 103 | firstName: 'TestName', 104 | email: 'test@test.com', 105 | arn: 'testARN', 106 | region: 'us-test-1', 107 | }, 108 | }); 109 | }, 110 | }); 111 | }); 112 | wrapper.find('WithStyles(ForwardRef(Button))').simulate('click'); 113 | expect(fetch).toHaveBeenCalledTimes(1); 114 | }); 115 | }); 116 | }); 117 | 118 | // constant look up time 119 | // lightweight 120 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | '@babel/preset-env', 5 | { 6 | targets: { 7 | node: 'current', 8 | }, 9 | }, 10 | ], 11 | '@babel/preset-react', 12 | ], 13 | // ignore: ['node_modules', 'build'], 14 | env: { 15 | test: { 16 | presets: [ 17 | // A Babel preset that can automatically determine the Babel plugins and polyfills 18 | // https://github.com/babel/babel-preset-env 19 | [ 20 | '@babel/preset-env', 21 | { 22 | targets: { 23 | node: 'current', 24 | }, 25 | modules: 'commonjs', 26 | useBuiltIns: false, 27 | debug: false, 28 | }, 29 | ], 30 | ], 31 | plugins: ['@babel/plugin-transform-modules-commonjs'], 32 | }, 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /client/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { HashRouter as Router, Switch, Route, Link } from 'react-router-dom'; 3 | import SignIn from './Pages/login.jsx'; 4 | import SignUp from './Pages/signup.jsx'; 5 | import Register from './Pages/register.jsx'; 6 | import Admin from './Dashboard/layouts/Admin'; 7 | import ForgotPassword from './Pages/forgotPassword'; 8 | 9 | class App extends Component { 10 | constructor(props) { 11 | super(props); 12 | } 13 | 14 | render() { 15 | return ( 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |
27 | ); 28 | } 29 | } 30 | 31 | export default App; 32 | -------------------------------------------------------------------------------- /client/src/Constants/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const ADD_USER_INFO = 'ADD_USER_INFO'; 2 | export const ADD_AWS_ACCOUNT = 'ADD_AWS_ACCOUNT'; 3 | export const ADD_LOGIN_INFO = 'ADD_LOGIN_INFO'; 4 | export const ADD_CREDENTIALS = 'ADD_CREDENTIALS'; 5 | export const ADD_CREDENTIALS_STARTED = 'ADD_CREDENTIALS_STARTED'; 6 | //############################################### 7 | //AWS Reducer All Functions 8 | //############################################### 9 | 10 | export const UPDATE_DASHBOARD_LOADING = 'UPDATE_DASHBOARD_LOADING'; 11 | export const UPDATE_BY_FUNCTION_LOADING = 'UPDATE_BY_FUNCTION_LOADING'; 12 | export const ADD_LAMBDA = 'ADD_LAMBDA'; 13 | export const ADD_LAMBDA_STARTED = 'ADD_LAMBDA_STARTED'; 14 | export const ADD_FUNCTION_LOGS = 'ADD_FUNCTION_LOGS'; 15 | export const REMOVE_FUNCTION_LOGS = 'REMOVE_FUNCTION_LOGS'; 16 | export const ADD_INVOCATIONS_ALLDATA = 'ADD_INVOCATIONS_ALLDATA'; 17 | export const ADD_ERRORS_ALLDATA = 'ADD_ERRORS_ALLDATA'; 18 | export const ADD_THROTTLES_ALLDATA = 'ADD_THROTTLES_ALLDATA'; 19 | export const UPDATE_RENDER = 'UPDATE_RENDER'; 20 | export const UPDATE_FETCH_TIME = 'UPDATE_FETCH_TIME'; 21 | export const UPDATE_FUNCTION_LOGS = 'UPDATE_FUNCTION_LOGS'; 22 | 23 | //############################################### 24 | //AWS Reducer By Function 25 | //############################################### 26 | 27 | export const UPDATE_FETCH_TIME_BYFUNC = 'UPDATE_FETCH_TIME_BYFUNC'; 28 | export const UPDATE_RENDER_BYFUNC = 'UPDATE_RENDER_BYFUNC'; 29 | export const JUST_UPDATE_BY_FUNC_RENDER = 'JUST_UPDATE_BY_FUNC_RENDER'; 30 | export const ADD_INVOCATIONS_BYFUNCDATA = 'ADD_INVOCATIONS_BYFUNCDATA'; 31 | export const ADD_ERRORS_BYFUNCDATA = 'ADD_ERRORS_BYFUNCDATA'; 32 | export const ADD_THROTTLES_BYFUNCDATA = 'ADD_THROTTLES_BYFUNCDATA'; 33 | export const HANDLE_LOGOUT = 'HANDLE_LOGOUT'; 34 | export const ADD_API_GATEWAYS = 'ADD_API_GATEWAYS'; 35 | export const ADD_API_METRIC_CHARTS = 'ADD_API_METRIC_CHARTS'; 36 | export const REMOVE_API_METRIC_CHARTS = 'REMOVE_API_METRIC_CHARTS'; 37 | export const UPDATE_API_METRIC_CHARTS = 'UPDATE_API_METRIC_CHARTS'; 38 | export const ADD_REGION = 'ADD_REGION'; 39 | export const UPDATE_EMAIL = 'UPDATE_EMAIL'; 40 | export const UPDATE_USER_DETAILS_AFTER_PROFILE_UPDATE = 41 | 'UPDATE_USER_DETAILS_AFTER_PROFILE_UPDATE'; 42 | export const UPDATE_NAME = 'UPDATE_NAME'; 43 | export const UPDATE_ARN = 'UPDATE_ARN'; 44 | export const UPDATE_LOGS_RENDER = 'UPDATE_LOGS_RENDER'; 45 | export const UPDATE_API_RENDER = 'UPDATE_API_RENDER'; 46 | export const ADD_API_GATEWAYS_STARTED = 'ADD_API_GATEWAYS_STARTED'; 47 | export const ADD_API_GATEWAYS_SUCCESS = 'ADD_API_GATEWAYS_SUCCESS'; 48 | export const UPDATE_DASHBOARD_TIME_PERIOD = 'UPDATE_DASHBOARD_TIME_PERIOD'; 49 | export const UPDATE_LOGS_TIME_PERIOD = 'UPDATE_LOGS_TIME_PERIOD'; 50 | export const UPDATE_API_TIME_PERIOD = 'UPDATE_API_TIME_PERIOD'; 51 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/github/angular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/github/angular.png -------------------------------------------------------------------------------- /client/src/Dashboard/assets/github/chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/github/chrome.png -------------------------------------------------------------------------------- /client/src/Dashboard/assets/github/dashboard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/github/dashboard.jpg -------------------------------------------------------------------------------- /client/src/Dashboard/assets/github/edge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/github/edge.png -------------------------------------------------------------------------------- /client/src/Dashboard/assets/github/firefox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/github/firefox.png -------------------------------------------------------------------------------- /client/src/Dashboard/assets/github/html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/github/html.png -------------------------------------------------------------------------------- /client/src/Dashboard/assets/github/map.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/github/map.jpg -------------------------------------------------------------------------------- /client/src/Dashboard/assets/github/md-react.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/github/md-react.gif -------------------------------------------------------------------------------- /client/src/Dashboard/assets/github/notifications.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/github/notifications.jpg -------------------------------------------------------------------------------- /client/src/Dashboard/assets/github/opera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/github/opera.png -------------------------------------------------------------------------------- /client/src/Dashboard/assets/github/opt_md_angular_thumbnail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/github/opt_md_angular_thumbnail.jpg -------------------------------------------------------------------------------- /client/src/Dashboard/assets/github/opt_md_thumbnail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/github/opt_md_thumbnail.jpg -------------------------------------------------------------------------------- /client/src/Dashboard/assets/github/opt_md_vue_thumbnail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/github/opt_md_vue_thumbnail.jpg -------------------------------------------------------------------------------- /client/src/Dashboard/assets/github/opt_mdr_thumbnail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/github/opt_mdr_thumbnail.jpg -------------------------------------------------------------------------------- /client/src/Dashboard/assets/github/react.svg: -------------------------------------------------------------------------------- 1 | 2 | React Logo 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/github/safari.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/github/safari.png -------------------------------------------------------------------------------- /client/src/Dashboard/assets/github/tables.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/github/tables.jpg -------------------------------------------------------------------------------- /client/src/Dashboard/assets/github/userprofile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/github/userprofile.jpg -------------------------------------------------------------------------------- /client/src/Dashboard/assets/github/vuejs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/github/vuejs.png -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/app-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/app-icon.png -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/apple-icon.png -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/cover.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/cover.jpeg -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/faces/marc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/faces/marc.jpg -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/favicon.png -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/gifs/Clip 3 - Dashboard.gif:Zone.Identifier: -------------------------------------------------------------------------------- 1 | [ZoneTransfer] 2 | ZoneId=3 3 | HostUrl=https://files.slack.com/files-pri/T01V0N825N3-F02AATLS02E/download/updated_clip_3_-_dashboard__1_.gif 4 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/gifs/Clip-1-Sign-Up.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/gifs/Clip-1-Sign-Up.gif -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/gifs/Clip-2-Copy-Arn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/gifs/Clip-2-Copy-Arn.gif -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/gifs/Clip-3-Dashboard.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/gifs/Clip-3-Dashboard.gif -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/gifs/Clip-4-Logs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/gifs/Clip-4-Logs.gif -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/gifs/Clip-5-API-Gateway.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/gifs/Clip-5-API-Gateway.gif -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/gifs/Clip-6-Account-Settings.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/gifs/Clip-6-Account-Settings.gif -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/helios-black-logo-t.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/helios-black-logo-t.png -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/helios-blue-logo-t.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/helios-blue-logo-t.png -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/helios-logo-background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/helios-logo-background.jpg -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/helios-logo-tr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/helios-logo-tr.png -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/mask.png -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/new-app-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/new-app-logo.png -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/new_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/new_logo.png -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/reactlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/reactlogo.png -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/sidebar-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/sidebar-1.jpg -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/sidebar-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/sidebar-2.jpg -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/sidebar-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/sidebar-3.jpg -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/sidebar-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/sidebar-4.jpg -------------------------------------------------------------------------------- /client/src/Dashboard/assets/img/tim_80x80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Helios/079c5350a4c65e7d3a41692807601f280cc82d5b/client/src/Dashboard/assets/img/tim_80x80.png -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/cardImagesStyles.js: -------------------------------------------------------------------------------- 1 | const cardImagesStyles = { 2 | cardImgTop: { 3 | width: "100%", 4 | borderTopLeftRadius: "calc(.25rem - 1px)", 5 | borderTopRightRadius: "calc(.25rem - 1px)", 6 | }, 7 | cardImgBottom: { 8 | width: "100%", 9 | borderBottomRightRadius: "calc(.25rem - 1px)", 10 | borderBottomLeftRadius: "calc(.25rem - 1px)", 11 | }, 12 | cardImgOverlay: { 13 | position: "absolute", 14 | top: "0", 15 | right: "0", 16 | bottom: "0", 17 | left: "0", 18 | padding: "1.25rem", 19 | }, 20 | cardImg: { 21 | width: "100%", 22 | borderRadius: "calc(.25rem - 1px)", 23 | }, 24 | }; 25 | 26 | export default cardImagesStyles; 27 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/checkboxAdnRadioStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | primaryColor, 3 | blackColor, 4 | hexToRgb, 5 | } from '../material-dashboard-react.js'; 6 | 7 | const checkboxAdnRadioStyle = { 8 | root: { 9 | padding: '13px', 10 | '&:hover': { 11 | backgroundColor: 'unset', 12 | }, 13 | }, 14 | labelRoot: { 15 | marginLeft: '-14px', 16 | }, 17 | checked: { 18 | color: primaryColor[0] + '!important', 19 | }, 20 | checkedIcon: { 21 | width: '20px', 22 | height: '20px', 23 | border: '1px solid rgba(' + hexToRgb(blackColor) + ', .54)', 24 | borderRadius: '3px', 25 | }, 26 | uncheckedIcon: { 27 | width: '0px', 28 | height: '0px', 29 | padding: '10px', 30 | border: '1px solid rgba(' + hexToRgb(blackColor) + ', .54)', 31 | borderRadius: '3px', 32 | }, 33 | radio: { 34 | color: primaryColor[0] + '!important', 35 | }, 36 | radioChecked: { 37 | width: '20px', 38 | height: '20px', 39 | border: '1px solid ' + primaryColor[0], 40 | borderRadius: '50%', 41 | }, 42 | radioUnchecked: { 43 | width: '0px', 44 | height: '0px', 45 | padding: '10px', 46 | border: '1px solid rgba(' + hexToRgb(blackColor) + ', .54)', 47 | borderRadius: '50%', 48 | }, 49 | }; 50 | 51 | export default checkboxAdnRadioStyle; 52 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/components/cardAvatarStyle.js: -------------------------------------------------------------------------------- 1 | import { hexToRgb, blackColor } from '../../material-dashboard-react.js'; 2 | 3 | const cardAvatarStyle = { 4 | cardAvatar: { 5 | '&$cardAvatarProfile img': { 6 | width: '100%', 7 | height: 'auto', 8 | }, 9 | }, 10 | cardAvatarProfile: { 11 | maxWidth: '180px', 12 | maxHeight: '150px', 13 | margin: '-50px auto 0', 14 | borderRadius: '5%', 15 | overflow: 'visible', 16 | padding: '0', 17 | boxShadow: 18 | '0 16px 38px -12px rgba(' + 19 | hexToRgb(blackColor) + 20 | ', 0.56), 0 4px 25px 0px rgba(' + 21 | hexToRgb(blackColor) + 22 | ', 0.12), 0 8px 10px -5px rgba(' + 23 | hexToRgb(blackColor) + 24 | ', 0.2)', 25 | // '&$cardAvatarPlain': { 26 | // marginTop: '0', 27 | // }, 28 | }, 29 | cardAvatarPlain: {}, 30 | }; 31 | 32 | export default cardAvatarStyle; 33 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/components/cardBodyStyle.js: -------------------------------------------------------------------------------- 1 | const cardBodyStyle = { 2 | cardBody: { 3 | padding: '0.9375rem 20px', 4 | flex: '1 1 auto', 5 | WebkitBoxFlex: '1', 6 | position: 'relative', 7 | }, 8 | cardBodyPlain: { 9 | paddingLeft: '5px', 10 | paddingRight: '5px', 11 | }, 12 | cardBodyProfile: { 13 | marginTop: '15px', 14 | }, 15 | }; 16 | 17 | export default cardBodyStyle; 18 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/components/cardFooterStyle.js: -------------------------------------------------------------------------------- 1 | import { grayColor } from '../../material-dashboard-react.js'; 2 | 3 | const cardFooterStyle = { 4 | cardFooter: { 5 | padding: '0', 6 | paddingTop: '10px', 7 | margin: '0 15px 10px', 8 | borderRadius: '0', 9 | justifyContent: 'space-between', 10 | alignItems: 'center', 11 | display: 'flex', 12 | backgroundColor: 'transparent', 13 | border: '0', 14 | }, 15 | cardFooterProfile: { 16 | marginTop: '-15px', 17 | }, 18 | cardFooterPlain: { 19 | paddingLeft: '5px', 20 | paddingRight: '5px', 21 | backgroundColor: 'transparent', 22 | }, 23 | cardFooterStats: { 24 | borderTop: '1px solid ' + grayColor[10], 25 | marginTop: '20px', 26 | '& svg': { 27 | position: 'relative', 28 | top: '4px', 29 | marginRight: '3px', 30 | marginLeft: '3px', 31 | width: '16px', 32 | height: '16px', 33 | }, 34 | '& .fab,& .fas,& .far,& .fal,& .material-icons': { 35 | fontSize: '16px', 36 | position: 'relative', 37 | top: '4px', 38 | marginRight: '3px', 39 | marginLeft: '3px', 40 | }, 41 | }, 42 | cardFooterChart: { 43 | borderTop: '1px solid ' + grayColor[10], 44 | }, 45 | }; 46 | 47 | export default cardFooterStyle; 48 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/components/cardHeaderStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | warningCardHeader, 3 | successCardHeader, 4 | dangerCardHeader, 5 | infoCardHeader, 6 | primaryCardHeader, 7 | roseCardHeader, 8 | whiteColor, 9 | } from '../../material-dashboard-react.js'; 10 | 11 | const cardHeaderStyle = { 12 | cardHeader: { 13 | padding: '0.75rem 1.25rem', 14 | marginBottom: '0', 15 | borderBottom: 'none', 16 | background: 'transparent', 17 | zIndex: '3 !important', 18 | '&$cardHeaderPlain,&$cardHeaderIcon,&$cardHeaderStats,&$warningCardHeader,&$successCardHeader,&$dangerCardHeader,&$infoCardHeader,&$primaryCardHeader,&$roseCardHeader': 19 | { 20 | margin: '0 15px', 21 | padding: '0', 22 | position: 'relative', 23 | color: whiteColor, 24 | }, 25 | '&:first-child': { 26 | borderRadius: 'calc(.25rem - 1px) calc(.25rem - 1px) 0 0', 27 | }, 28 | '&$warningCardHeader,&$successCardHeader,&$dangerCardHeader,&$infoCardHeader,&$primaryCardHeader,&$roseCardHeader': 29 | { 30 | '&:not($cardHeaderIcon)': { 31 | borderRadius: '3px', 32 | marginTop: '-20px', 33 | padding: '15px', 34 | }, 35 | }, 36 | '&$cardHeaderStats svg': { 37 | fontSize: '36px', 38 | lineHeight: '56px', 39 | textAlign: 'center', 40 | width: '36px', 41 | height: '36px', 42 | margin: '10px 10px 4px', 43 | }, 44 | '&$cardHeaderStats i,&$cardHeaderStats .material-icons': { 45 | fontSize: '36px', 46 | lineHeight: '56px', 47 | width: '56px', 48 | height: '56px', 49 | textAlign: 'center', 50 | overflow: 'unset', 51 | marginBottom: '1px', 52 | }, 53 | '&$cardHeaderStats$cardHeaderIcon': { 54 | textAlign: 'right', 55 | }, 56 | }, 57 | cardHeaderPlain: { 58 | marginLeft: '0px !important', 59 | marginRight: '0px !important', 60 | }, 61 | cardHeaderStats: { 62 | '& $cardHeaderIcon': { 63 | textAlign: 'right', 64 | }, 65 | '& h1,& h2,& h3,& h4,& h5,& h6': { 66 | margin: '0 !important', 67 | }, 68 | }, 69 | cardHeaderIcon: { 70 | '&$warningCardHeader,&$successCardHeader,&$dangerCardHeader,&$infoCardHeader,&$primaryCardHeader,&$roseCardHeader': 71 | { 72 | background: 'transparent', 73 | boxShadow: 'none', 74 | }, 75 | '& i,& .material-icons': { 76 | width: '33px', 77 | height: '33px', 78 | textAlign: 'center', 79 | lineHeight: '33px', 80 | }, 81 | '& svg': { 82 | width: '24px', 83 | height: '24px', 84 | textAlign: 'center', 85 | lineHeight: '33px', 86 | margin: '5px 4px 0px', 87 | }, 88 | }, 89 | warningCardHeader: { 90 | color: whiteColor, 91 | '&:not($cardHeaderIcon)': { 92 | ...warningCardHeader, 93 | }, 94 | }, 95 | successCardHeader: { 96 | color: whiteColor, 97 | '&:not($cardHeaderIcon)': { 98 | ...successCardHeader, 99 | }, 100 | }, 101 | dangerCardHeader: { 102 | color: whiteColor, 103 | '&:not($cardHeaderIcon)': { 104 | ...dangerCardHeader, 105 | }, 106 | }, 107 | infoCardHeader: { 108 | color: whiteColor, 109 | '&:not($cardHeaderIcon)': { 110 | ...infoCardHeader, 111 | }, 112 | }, 113 | primaryCardHeader: { 114 | color: whiteColor, 115 | '&:not($cardHeaderIcon)': { 116 | ...primaryCardHeader, 117 | }, 118 | }, 119 | roseCardHeader: { 120 | color: whiteColor, 121 | '&:not($cardHeaderIcon)': { 122 | ...roseCardHeader, 123 | }, 124 | }, 125 | }; 126 | 127 | export default cardHeaderStyle; 128 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/components/cardIconStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | warningCardHeader, 3 | successCardHeader, 4 | dangerCardHeader, 5 | infoCardHeader, 6 | primaryCardHeader, 7 | roseCardHeader, 8 | grayColor, 9 | } from '../../material-dashboard-react.js'; 10 | 11 | const cardIconStyle = { 12 | cardIcon: { 13 | '&$warningCardHeader,&$successCardHeader,&$dangerCardHeader,&$infoCardHeader,&$primaryCardHeader,&$roseCardHeader': 14 | { 15 | borderRadius: '3px', 16 | backgroundColor: grayColor[0], 17 | padding: '15px', 18 | marginTop: '-20px', 19 | marginRight: '15px', 20 | float: 'left', 21 | }, 22 | }, 23 | warningCardHeader, 24 | successCardHeader, 25 | dangerCardHeader, 26 | infoCardHeader, 27 | primaryCardHeader, 28 | roseCardHeader, 29 | }; 30 | 31 | export default cardIconStyle; 32 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/components/cardStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | blackColor, 3 | whiteColor, 4 | hexToRgb, 5 | } from '../../material-dashboard-react.js'; 6 | 7 | const cardStyle = { 8 | card: { 9 | border: '0', 10 | marginBottom: '30px', 11 | marginTop: '30px', 12 | borderRadius: '6px', 13 | color: 'rgba(' + hexToRgb(blackColor) + ', 0.87)', 14 | background: whiteColor, 15 | width: '100%', 16 | boxShadow: '0 1px 4px 0 rgba(' + hexToRgb(blackColor) + ', 0.14)', 17 | position: 'relative', 18 | display: 'flex', 19 | flexDirection: 'column', 20 | minWidth: '0', 21 | wordWrap: 'break-word', 22 | fontSize: '.875rem', 23 | }, 24 | cardPlain: { 25 | background: 'transparent', 26 | boxShadow: 'none', 27 | }, 28 | cardProfile: { 29 | marginTop: '30px', 30 | textAlign: 'center', 31 | }, 32 | cardChart: { 33 | height: '410px', 34 | '& p': { 35 | marginTop: '0px', 36 | paddingTop: '0px', 37 | }, 38 | }, 39 | }; 40 | 41 | export default cardStyle; 42 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/components/customInputStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | primaryColor, 3 | dangerColor, 4 | successColor, 5 | grayColor, 6 | defaultFont, 7 | infoColor, 8 | } from '../../material-dashboard-react.js'; 9 | 10 | const customInputStyle = { 11 | disabled: { 12 | '&:before': { 13 | backgroundColor: 'transparent !important', 14 | }, 15 | }, 16 | underline: { 17 | '&:hover:not($disabled):before,&:before': { 18 | borderColor: grayColor[4] + ' !important', 19 | borderWidth: '1px !important', 20 | }, 21 | '&:after': { 22 | borderColor: infoColor[0], 23 | }, 24 | }, 25 | underlineError: { 26 | '&:after': { 27 | borderColor: dangerColor[0], 28 | }, 29 | }, 30 | underlineSuccess: { 31 | '&:after': { 32 | borderColor: successColor[0], 33 | }, 34 | }, 35 | labelRoot: { 36 | ...defaultFont, 37 | color: grayColor[3] + ' !important', 38 | fontWeight: '400', 39 | fontSize: '14px', 40 | lineHeight: '1.42857', 41 | letterSpacing: 'unset', 42 | }, 43 | labelRootError: { 44 | color: dangerColor[0], 45 | }, 46 | labelRootSuccess: { 47 | color: successColor[0], 48 | }, 49 | feedback: { 50 | position: 'absolute', 51 | top: '18px', 52 | right: '0', 53 | zIndex: '2', 54 | display: 'block', 55 | width: '24px', 56 | height: '24px', 57 | textAlign: 'center', 58 | pointerEvents: 'none', 59 | }, 60 | marginTop: { 61 | marginTop: '16px', 62 | }, 63 | formControl: { 64 | paddingBottom: '10px', 65 | margin: '27px 0 0 0', 66 | position: 'relative', 67 | verticalAlign: 'unset', 68 | }, 69 | labelRTL: { 70 | right: 0, 71 | transition: 'all 200ms cubic-bezier(0.0, 0, 0.2, 1) 0ms', 72 | '&.MuiInputLabel-shrink': { 73 | transform: 'translate(0, 1.5px)', 74 | }, 75 | }, 76 | }; 77 | 78 | export default customInputStyle; 79 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/components/customTabsStyle.js: -------------------------------------------------------------------------------- 1 | import { hexToRgb, whiteColor } from '../../material-dashboard-react.js'; 2 | 3 | const customTabsStyle = { 4 | cardTitle: { 5 | float: 'left', 6 | padding: '10px 10px 10px 0px', 7 | lineHeight: '24px', 8 | }, 9 | cardTitleRTL: { 10 | float: 'right', 11 | padding: '10px 0px 10px 10px !important', 12 | }, 13 | displayNone: { 14 | display: 'none !important', 15 | }, 16 | tabsRoot: { 17 | minHeight: 'unset !important', 18 | overflowX: 'visible', 19 | '& $tabRootButton': { 20 | fontSize: '0.875rem', 21 | }, 22 | }, 23 | tabRootButton: { 24 | minHeight: 'unset !important', 25 | minWidth: 'unset !important', 26 | width: 'unset !important', 27 | height: 'unset !important', 28 | maxWidth: 'unset !important', 29 | maxHeight: 'unset !important', 30 | padding: '10px 15px', 31 | borderRadius: '3px', 32 | lineHeight: '24px', 33 | border: '0 !important', 34 | color: whiteColor + ' !important', 35 | marginLeft: '4px', 36 | '&:last-child': { 37 | marginLeft: '0px', 38 | }, 39 | }, 40 | tabSelected: { 41 | backgroundColor: 'rgba(' + hexToRgb(whiteColor) + ', 0.2)', 42 | transition: '0.2s background-color 0.1s', 43 | }, 44 | tabWrapper: { 45 | display: 'inline-block', 46 | minHeight: 'unset !important', 47 | minWidth: 'unset !important', 48 | width: 'unset !important', 49 | height: 'unset !important', 50 | maxWidth: 'unset !important', 51 | maxHeight: 'unset !important', 52 | fontWeight: '500', 53 | fontSize: '12px', 54 | marginTop: '1px', 55 | '& > svg,& > .material-icons': { 56 | verticalAlign: 'middle', 57 | margin: '-1px 5px 0 0 !important', 58 | }, 59 | }, 60 | }; 61 | 62 | export default customTabsStyle; 63 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/components/footerStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | defaultFont, 3 | container, 4 | primaryColor, 5 | grayColor, 6 | } from '../../material-dashboard-react.js'; 7 | 8 | const footerStyle = { 9 | block: { 10 | color: 'inherit', 11 | padding: '15px', 12 | textTransform: 'uppercase', 13 | borderRadius: '3px', 14 | textDecoration: 'none', 15 | position: 'relative', 16 | display: 'block', 17 | ...defaultFont, 18 | fontWeight: '500', 19 | fontSize: '12px', 20 | }, 21 | left: { 22 | float: 'left!important', 23 | display: 'block', 24 | }, 25 | right: { 26 | padding: '15px 0', 27 | margin: '0', 28 | fontSize: '14px', 29 | float: 'right!important', 30 | }, 31 | footer: { 32 | bottom: '0', 33 | borderTop: '1px solid ' + grayColor[11], 34 | padding: '15px 0', 35 | ...defaultFont, 36 | }, 37 | container, 38 | a: { 39 | color: primaryColor, 40 | textDecoration: 'none', 41 | backgroundColor: 'transparent', 42 | }, 43 | list: { 44 | marginBottom: '0', 45 | padding: '0', 46 | marginTop: '0', 47 | }, 48 | inlineBlock: { 49 | display: 'inline-block', 50 | padding: '0px', 51 | width: 'auto', 52 | }, 53 | }; 54 | export default footerStyle; 55 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/components/headerLinksStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | defaultFont, 3 | dangerColor, 4 | whiteColor, 5 | } from '../../material-dashboard-react.js'; 6 | 7 | import dropdownStyle from '../../material-dashboard-react/dropdownStyle.js'; 8 | 9 | const headerLinksStyle = (theme) => ({ 10 | ...dropdownStyle(theme), 11 | search: { 12 | '& > div': { 13 | marginTop: '0', 14 | }, 15 | [theme.breakpoints.down('sm')]: { 16 | margin: '10px 15px !important', 17 | float: 'none !important', 18 | paddingTop: '1px', 19 | paddingBottom: '1px', 20 | padding: '0!important', 21 | width: '60%', 22 | marginTop: '40px', 23 | '& input': { 24 | color: whiteColor, 25 | }, 26 | }, 27 | }, 28 | linkText: { 29 | zIndex: '4', 30 | ...defaultFont, 31 | fontSize: '14px', 32 | margin: '0px', 33 | }, 34 | buttonLink: { 35 | [theme.breakpoints.down('sm')]: { 36 | display: 'flex', 37 | margin: '10px 15px 0', 38 | width: '-webkit-fill-available', 39 | '& svg': { 40 | width: '24px', 41 | height: '30px', 42 | marginRight: '15px', 43 | marginLeft: '-15px', 44 | }, 45 | '& .fab,& .fas,& .far,& .fal,& .material-icons': { 46 | fontSize: '24px', 47 | lineHeight: '30px', 48 | width: '24px', 49 | height: '30px', 50 | marginRight: '15px', 51 | marginLeft: '-15px', 52 | }, 53 | '& > span': { 54 | justifyContent: 'flex-start', 55 | width: '100%', 56 | }, 57 | }, 58 | }, 59 | searchButton: { 60 | [theme.breakpoints.down('sm')]: { 61 | top: '-50px !important', 62 | marginRight: '22px', 63 | float: 'right', 64 | }, 65 | }, 66 | margin: { 67 | zIndex: '4', 68 | margin: '0', 69 | }, 70 | searchIcon: { 71 | width: '17px', 72 | zIndex: '4', 73 | }, 74 | notifications: { 75 | zIndex: '4', 76 | [theme.breakpoints.up('md')]: { 77 | position: 'absolute', 78 | top: '2px', 79 | border: '1px solid ' + whiteColor, 80 | right: '4px', 81 | fontSize: '9px', 82 | background: dangerColor[0], 83 | color: whiteColor, 84 | minWidth: '16px', 85 | height: '16px', 86 | borderRadius: '10px', 87 | textAlign: 'center', 88 | lineHeight: '16px', 89 | verticalAlign: 'middle', 90 | display: 'block', 91 | }, 92 | [theme.breakpoints.down('sm')]: { 93 | ...defaultFont, 94 | fontSize: '14px', 95 | marginRight: '8px', 96 | }, 97 | }, 98 | manager: { 99 | [theme.breakpoints.down('sm')]: { 100 | width: '100%', 101 | }, 102 | display: 'inline-block', 103 | }, 104 | searchWrapper: { 105 | [theme.breakpoints.down('sm')]: { 106 | width: '-webkit-fill-available', 107 | margin: '10px 15px 0', 108 | }, 109 | display: 'inline-block', 110 | }, 111 | }); 112 | 113 | export default headerLinksStyle; 114 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/components/headerStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | container, 3 | defaultFont, 4 | primaryColor, 5 | defaultBoxShadow, 6 | infoColor, 7 | successColor, 8 | warningColor, 9 | dangerColor, 10 | whiteColor, 11 | grayColor, 12 | } from '../../material-dashboard-react.js'; 13 | 14 | const headerStyle = () => ({ 15 | appBar: { 16 | backgroundColor: 'transparent', 17 | boxShadow: 'none', 18 | borderBottom: '0', 19 | marginBottom: '0', 20 | position: 'absolute', 21 | width: '100%', 22 | paddingTop: '10px', 23 | zIndex: '1029', 24 | color: grayColor[7], 25 | border: '0', 26 | borderRadius: '3px', 27 | padding: '10px 0', 28 | transition: 'all 150ms ease 0s', 29 | minHeight: '50px', 30 | display: 'block', 31 | }, 32 | container: { 33 | ...container, 34 | minHeight: '50px', 35 | }, 36 | flex: { 37 | flex: 1, 38 | }, 39 | title: { 40 | ...defaultFont, 41 | letterSpacing: 'unset', 42 | lineHeight: '30px', 43 | fontSize: '18px', 44 | borderRadius: '3px', 45 | textTransform: 'none', 46 | color: 'inherit', 47 | margin: '0', 48 | '&:hover,&:focus': { 49 | background: 'transparent', 50 | }, 51 | }, 52 | appResponsive: { 53 | top: '8px', 54 | }, 55 | primary: { 56 | backgroundColor: primaryColor[0], 57 | color: whiteColor, 58 | ...defaultBoxShadow, 59 | }, 60 | info: { 61 | backgroundColor: infoColor[0], 62 | color: whiteColor, 63 | ...defaultBoxShadow, 64 | }, 65 | success: { 66 | backgroundColor: successColor[0], 67 | color: whiteColor, 68 | ...defaultBoxShadow, 69 | }, 70 | warning: { 71 | backgroundColor: warningColor[0], 72 | color: whiteColor, 73 | ...defaultBoxShadow, 74 | }, 75 | danger: { 76 | backgroundColor: dangerColor[0], 77 | color: whiteColor, 78 | ...defaultBoxShadow, 79 | }, 80 | }); 81 | 82 | export default headerStyle; 83 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/components/logTableStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | warningColor, 3 | primaryColor, 4 | dangerColor, 5 | successColor, 6 | infoColor, 7 | roseColor, 8 | grayColor, 9 | defaultFont, 10 | } from '../../material-dashboard-react.js'; 11 | 12 | const tableStyle = (theme) => ({ 13 | warningTableHeader: { 14 | color: warningColor[0], 15 | }, 16 | primaryTableHeader: { 17 | color: primaryColor[0], 18 | }, 19 | dangerTableHeader: { 20 | color: dangerColor[0], 21 | }, 22 | successTableHeader: { 23 | color: successColor[0], 24 | }, 25 | infoTableHeader: { 26 | color: infoColor[0], 27 | }, 28 | roseTableHeader: { 29 | color: roseColor[0], 30 | }, 31 | grayTableHeader: { 32 | color: grayColor[0], 33 | }, 34 | table: { 35 | marginBottom: '0', 36 | width: '100%', 37 | maxWidth: '100%', 38 | backgroundColor: 'transparent', 39 | borderSpacing: '0', 40 | borderCollapse: 'collapse', 41 | }, 42 | tableHeadCell: { 43 | color: 'inherit', 44 | ...defaultFont, 45 | '&, &$tableCell': { 46 | fontSize: '1em', 47 | }, 48 | // minWidth: '30px', 49 | // maxWidth: '30px' 50 | }, 51 | dateCell: { 52 | color: 'inherit', 53 | ...defaultFont, 54 | fontSize: '1em', 55 | width: '50px', 56 | fontWeight: 'bold', 57 | }, 58 | streamCell: { 59 | color: 'inherit', 60 | ...defaultFont, 61 | fontSize: '1em', 62 | width: '70px', 63 | fontWeight: 'bold', 64 | }, 65 | msgCell: { 66 | color: 'inherit', 67 | ...defaultFont, 68 | fontSize: '1em', 69 | width: '200px', 70 | fontWeight: 'bold', 71 | }, 72 | tableCell: { 73 | ...defaultFont, 74 | lineHeight: '1.42857143', 75 | padding: '12px 8px', 76 | verticalAlign: 'middle', 77 | fontSize: '0.8125rem', 78 | }, 79 | tableResponsive: { 80 | // width: '100%', 81 | marginTop: theme.spacing(3), 82 | overflowX: 'auto', 83 | }, 84 | tableHeadRow: { 85 | height: '56px', 86 | color: 'inherit', 87 | display: 'table-row', 88 | outline: 'none', 89 | verticalAlign: 'middle', 90 | }, 91 | tableBodyRow: { 92 | height: '48px', 93 | color: 'inherit', 94 | display: 'table-row', 95 | outline: 'none', 96 | verticalAlign: 'middle', 97 | }, 98 | errorTableBodyRow: { 99 | height: '48px', 100 | color: 'inherit', 101 | display: 'table-row', 102 | outline: 'none', 103 | verticalAlign: 'middle', 104 | backgroundColor: dangerColor[0], 105 | }, 106 | }); 107 | 108 | export default tableStyle; 109 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/components/rtlHeaderLinksStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | defaultFont, 3 | dangerColor, 4 | whiteColor, 5 | } from '../../material-dashboard-react.js'; 6 | 7 | import dropdownStyle from '../../material-dashboard-react/dropdownStyle.js'; 8 | 9 | const headerLinksStyle = (theme) => ({ 10 | ...dropdownStyle(theme), 11 | search: { 12 | '& > div': { 13 | marginTop: '0', 14 | }, 15 | [theme.breakpoints.down('sm')]: { 16 | margin: '10px 15px !important', 17 | float: 'none !important', 18 | paddingTop: '1px', 19 | paddingBottom: '1px', 20 | padding: '0!important', 21 | width: '60%', 22 | marginTop: '40px', 23 | '& input': { 24 | color: whiteColor, 25 | }, 26 | }, 27 | }, 28 | linkText: { 29 | zIndex: '4', 30 | ...defaultFont, 31 | fontSize: '14px', 32 | margin: '0px', 33 | }, 34 | buttonLink: { 35 | [theme.breakpoints.down('sm')]: { 36 | display: 'flex', 37 | margin: '10px 15px 0', 38 | width: '-webkit-fill-available', 39 | '& svg': { 40 | width: '24px', 41 | height: '30px', 42 | marginRight: '15px', 43 | marginLeft: '-15px', 44 | }, 45 | '& .fab,& .fas,& .far,& .fal,& .material-icons': { 46 | fontSize: '24px', 47 | lineHeight: '30px', 48 | width: '24px', 49 | height: '30px', 50 | marginRight: '15px', 51 | marginLeft: '-15px', 52 | }, 53 | '& > span': { 54 | justifyContent: 'flex-start', 55 | width: '100%', 56 | }, 57 | }, 58 | }, 59 | searchButton: { 60 | [theme.breakpoints.down('sm')]: { 61 | top: '-50px !important', 62 | marginRight: '22px', 63 | float: 'right', 64 | }, 65 | }, 66 | margin: { 67 | zIndex: '4', 68 | margin: '0', 69 | }, 70 | searchIcon: { 71 | width: '17px', 72 | zIndex: '4', 73 | }, 74 | notifications: { 75 | zIndex: '4', 76 | [theme.breakpoints.up('md')]: { 77 | position: 'absolute', 78 | top: '2px', 79 | border: '1px solid ' + whiteColor, 80 | right: '4px', 81 | fontSize: '9px', 82 | background: dangerColor[0], 83 | color: whiteColor, 84 | minWidth: '16px', 85 | height: '16px', 86 | borderRadius: '10px', 87 | textAlign: 'center', 88 | lineHeight: '16px', 89 | verticalAlign: 'middle', 90 | display: 'block', 91 | }, 92 | [theme.breakpoints.down('sm')]: { 93 | ...defaultFont, 94 | fontSize: '14px', 95 | marginRight: '8px', 96 | }, 97 | }, 98 | manager: { 99 | [theme.breakpoints.down('sm')]: { 100 | width: '100%', 101 | }, 102 | display: 'inline-block', 103 | }, 104 | searchWrapper: { 105 | [theme.breakpoints.down('sm')]: { 106 | width: '-webkit-fill-available', 107 | margin: '10px 15px 0', 108 | }, 109 | display: 'inline-block', 110 | }, 111 | }); 112 | 113 | export default headerLinksStyle; 114 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/components/snackbarContentStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | defaultFont, 3 | primaryBoxShadow, 4 | infoBoxShadow, 5 | successBoxShadow, 6 | warningBoxShadow, 7 | dangerBoxShadow, 8 | roseBoxShadow, 9 | whiteColor, 10 | blackColor, 11 | grayColor, 12 | infoColor, 13 | successColor, 14 | dangerColor, 15 | roseColor, 16 | primaryColor, 17 | warningColor, 18 | hexToRgb, 19 | } from '../../material-dashboard-react.js'; 20 | 21 | const snackbarContentStyle = { 22 | root: { 23 | ...defaultFont, 24 | flexWrap: 'unset', 25 | position: 'relative', 26 | padding: '20px 15px', 27 | lineHeight: '20px', 28 | marginBottom: '20px', 29 | fontSize: '14px', 30 | backgroundColor: whiteColor, 31 | color: grayColor[7], 32 | borderRadius: '3px', 33 | minWidth: 'unset', 34 | maxWidth: 'unset', 35 | boxShadow: 36 | '0 12px 20px -10px rgba(' + 37 | hexToRgb(whiteColor) + 38 | ', 0.28), 0 4px 20px 0px rgba(' + 39 | hexToRgb(blackColor) + 40 | ', 0.12), 0 7px 8px -5px rgba(' + 41 | hexToRgb(whiteColor) + 42 | ', 0.2)', 43 | }, 44 | top20: { 45 | top: '20px', 46 | }, 47 | top40: { 48 | top: '40px', 49 | }, 50 | info: { 51 | backgroundColor: infoColor[3], 52 | color: whiteColor, 53 | ...infoBoxShadow, 54 | }, 55 | success: { 56 | backgroundColor: successColor[3], 57 | color: whiteColor, 58 | ...successBoxShadow, 59 | }, 60 | warning: { 61 | backgroundColor: warningColor[3], 62 | color: whiteColor, 63 | ...warningBoxShadow, 64 | }, 65 | danger: { 66 | backgroundColor: dangerColor[3], 67 | color: whiteColor, 68 | ...dangerBoxShadow, 69 | }, 70 | primary: { 71 | backgroundColor: primaryColor[3], 72 | color: whiteColor, 73 | ...primaryBoxShadow, 74 | }, 75 | rose: { 76 | backgroundColor: roseColor[3], 77 | color: whiteColor, 78 | ...roseBoxShadow, 79 | }, 80 | message: { 81 | padding: '0', 82 | display: 'block', 83 | maxWidth: '89%', 84 | }, 85 | close: { 86 | width: '11px', 87 | height: '11px', 88 | }, 89 | iconButton: { 90 | width: '24px', 91 | height: '24px', 92 | padding: '0px', 93 | }, 94 | icon: { 95 | display: 'block', 96 | left: '15px', 97 | position: 'absolute', 98 | top: '50%', 99 | marginTop: '-15px', 100 | width: '30px', 101 | height: '30px', 102 | }, 103 | infoIcon: { 104 | color: infoColor[3], 105 | }, 106 | successIcon: { 107 | color: successColor[3], 108 | }, 109 | warningIcon: { 110 | color: warningColor[3], 111 | }, 112 | dangerIcon: { 113 | color: dangerColor[3], 114 | }, 115 | primaryIcon: { 116 | color: primaryColor[3], 117 | }, 118 | roseIcon: { 119 | color: roseColor[3], 120 | }, 121 | iconMessage: { 122 | paddingLeft: '50px', 123 | display: 'block', 124 | }, 125 | actionRTL: { 126 | marginLeft: '-8px', 127 | marginRight: 'auto', 128 | }, 129 | }; 130 | 131 | export default snackbarContentStyle; 132 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/components/tableStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | warningColor, 3 | primaryColor, 4 | dangerColor, 5 | successColor, 6 | infoColor, 7 | roseColor, 8 | grayColor, 9 | defaultFont, 10 | } from '../../material-dashboard-react.js'; 11 | 12 | const tableStyle = (theme) => ({ 13 | warningTableHeader: { 14 | color: warningColor[0], 15 | }, 16 | primaryTableHeader: { 17 | color: primaryColor[0], 18 | }, 19 | dangerTableHeader: { 20 | color: dangerColor[0], 21 | }, 22 | successTableHeader: { 23 | color: successColor[0], 24 | }, 25 | infoTableHeader: { 26 | color: infoColor[0], 27 | }, 28 | roseTableHeader: { 29 | color: roseColor[0], 30 | }, 31 | grayTableHeader: { 32 | color: grayColor[0], 33 | }, 34 | table: { 35 | marginBottom: '0', 36 | width: '100%', 37 | maxWidth: '100%', 38 | backgroundColor: 'transparent', 39 | borderSpacing: '0', 40 | borderCollapse: 'collapse', 41 | }, 42 | tableHeadCell: { 43 | color: 'inherit', 44 | ...defaultFont, 45 | '&, &$tableCell': { 46 | fontSize: '1em', 47 | }, 48 | }, 49 | tableCell: { 50 | ...defaultFont, 51 | lineHeight: '1.42857143', 52 | padding: '12px 8px', 53 | verticalAlign: 'middle', 54 | fontSize: '0.8125rem', 55 | }, 56 | tableResponsive: { 57 | width: '100%', 58 | marginTop: theme.spacing(3), 59 | overflowX: 'auto', 60 | }, 61 | tableHeadRow: { 62 | height: '56px', 63 | color: 'inherit', 64 | display: 'table-row', 65 | outline: 'none', 66 | verticalAlign: 'middle', 67 | }, 68 | tableBodyRow: { 69 | height: '48px', 70 | color: 'inherit', 71 | display: 'table-row', 72 | outline: 'none', 73 | verticalAlign: 'middle', 74 | }, 75 | }); 76 | 77 | export default tableStyle; 78 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/components/tasksStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | defaultFont, 3 | primaryColor, 4 | dangerColor, 5 | grayColor, 6 | successColor, 7 | } from '../../material-dashboard-react.js'; 8 | import tooltipStyle from '../tooltipStyle.js'; 9 | import checkboxAdnRadioStyle from '../checkboxAdnRadioStyle.js'; 10 | const tasksStyle = { 11 | ...tooltipStyle, 12 | ...checkboxAdnRadioStyle, 13 | table: { 14 | marginBottom: '0', 15 | overflow: 'visible', 16 | }, 17 | tableRow: { 18 | position: 'relative', 19 | borderBottom: '1px solid ' + grayColor[5], 20 | }, 21 | tableActions: { 22 | display: 'flex', 23 | border: 'none', 24 | padding: '12px 8px !important', 25 | verticalAlign: 'middle', 26 | }, 27 | tableCell: { 28 | ...defaultFont, 29 | padding: '8px', 30 | verticalAlign: 'middle', 31 | border: 'none', 32 | lineHeight: '1.42857143', 33 | fontSize: '14px', 34 | }, 35 | tableCellRTL: { 36 | textAlign: 'right', 37 | }, 38 | tableActionButton: { 39 | width: '27px', 40 | height: '27px', 41 | padding: '0', 42 | }, 43 | tableActionButtonIcon: { 44 | width: '17px', 45 | height: '17px', 46 | }, 47 | edit: { 48 | backgroundColor: 'transparent', 49 | color: primaryColor[0], 50 | boxShadow: 'none', 51 | }, 52 | close: { 53 | backgroundColor: 'transparent', 54 | color: dangerColor[0], 55 | boxShadow: 'none', 56 | }, 57 | // loader: { 58 | // color: successColor[0], 59 | // height: '50px', 60 | // width: '50px', 61 | // }, 62 | }; 63 | export default tasksStyle; 64 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/components/typographyStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | defaultFont, 3 | primaryColor, 4 | infoColor, 5 | successColor, 6 | warningColor, 7 | dangerColor, 8 | grayColor, 9 | } from '../../material-dashboard-react.js'; 10 | 11 | const typographyStyle = { 12 | defaultFontStyle: { 13 | ...defaultFont, 14 | fontSize: '14px', 15 | }, 16 | defaultHeaderMargins: { 17 | marginTop: '20px', 18 | marginBottom: '10px', 19 | }, 20 | quote: { 21 | padding: '10px 20px', 22 | margin: '0 0 20px', 23 | fontSize: '17.5px', 24 | borderLeft: '5px solid ' + grayColor[10], 25 | }, 26 | quoteText: { 27 | margin: '0 0 10px', 28 | fontStyle: 'italic', 29 | }, 30 | quoteAuthor: { 31 | display: 'block', 32 | fontSize: '80%', 33 | lineHeight: '1.42857143', 34 | color: grayColor[1], 35 | }, 36 | mutedText: { 37 | color: grayColor[1], 38 | }, 39 | primaryText: { 40 | color: primaryColor[0], 41 | }, 42 | infoText: { 43 | color: infoColor[0], 44 | }, 45 | successText: { 46 | color: successColor[0], 47 | }, 48 | warningText: { 49 | color: warningColor[0], 50 | }, 51 | dangerText: { 52 | color: dangerColor[0], 53 | }, 54 | }; 55 | 56 | export default typographyStyle; 57 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/dropdownStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | primaryColor, 3 | whiteColor, 4 | primaryBoxShadow, 5 | defaultFont, 6 | blackColor, 7 | grayColor, 8 | hexToRgb, 9 | } from '../material-dashboard-react.js'; 10 | 11 | const dropdownStyle = (theme) => ({ 12 | buttonLink: { 13 | [theme.breakpoints.down('md')]: { 14 | display: 'flex', 15 | marginLeft: '30px', 16 | width: 'auto', 17 | }, 18 | }, 19 | links: { 20 | width: '20px', 21 | height: '20px', 22 | zIndex: '4', 23 | [theme.breakpoints.down('md')]: { 24 | display: 'block', 25 | width: '30px', 26 | height: '30px', 27 | color: grayColor[9], 28 | marginRight: '15px', 29 | }, 30 | }, 31 | linkText: { 32 | zIndex: '4', 33 | ...defaultFont, 34 | fontSize: '14px', 35 | }, 36 | popperClose: { 37 | pointerEvents: 'none', 38 | }, 39 | popperResponsive: { 40 | [theme.breakpoints.down('md')]: { 41 | zIndex: '1640', 42 | position: 'static', 43 | float: 'none', 44 | width: 'auto', 45 | marginTop: '0', 46 | backgroundColor: 'transparent', 47 | border: '0', 48 | WebkitBoxShadow: 'none', 49 | boxShadow: 'none', 50 | color: 'black', 51 | }, 52 | }, 53 | popperNav: { 54 | [theme.breakpoints.down('sm')]: { 55 | position: 'static !important', 56 | left: 'unset !important', 57 | top: 'unset !important', 58 | transform: 'none !important', 59 | willChange: 'unset !important', 60 | '& > div': { 61 | boxShadow: 'none !important', 62 | marginLeft: '0rem', 63 | marginRight: '0rem', 64 | transition: 'none !important', 65 | marginTop: '0px !important', 66 | marginBottom: '0px !important', 67 | padding: '0px !important', 68 | backgroundColor: 'transparent !important', 69 | '& ul li': { 70 | color: whiteColor + ' !important', 71 | margin: '10px 15px 0!important', 72 | padding: '10px 15px !important', 73 | '&:hover': { 74 | backgroundColor: 'hsla(0,0%,78%,.2)', 75 | boxShadow: 'none', 76 | }, 77 | }, 78 | }, 79 | }, 80 | }, 81 | dropdown: { 82 | borderRadius: '3px', 83 | border: '0', 84 | boxShadow: '0 2px 5px 0 rgba(' + hexToRgb(blackColor) + ', 0.26)', 85 | top: '100%', 86 | zIndex: '1000', 87 | minWidth: '160px', 88 | padding: '5px 0', 89 | margin: '2px 0 0', 90 | fontSize: '14px', 91 | textAlign: 'left', 92 | listStyle: 'none', 93 | backgroundColor: whiteColor, 94 | WebkitBackgroundClip: 'padding-box', 95 | backgroundClip: 'padding-box', 96 | }, 97 | dropdownItem: { 98 | ...defaultFont, 99 | fontSize: '13px', 100 | padding: '10px 20px', 101 | margin: '0 5px', 102 | borderRadius: '2px', 103 | WebkitTransition: 'all 150ms linear', 104 | MozTransition: 'all 150ms linear', 105 | OTransition: 'all 150ms linear', 106 | MsTransition: 'all 150ms linear', 107 | transition: 'all 150ms linear', 108 | display: 'block', 109 | clear: 'both', 110 | fontWeight: '400', 111 | lineHeight: '1.42857143', 112 | color: grayColor[8], 113 | whiteSpace: 'nowrap', 114 | height: 'unset', 115 | minHeight: 'unset', 116 | '&:hover': { 117 | backgroundColor: primaryColor[0], 118 | color: whiteColor, 119 | ...primaryBoxShadow, 120 | }, 121 | }, 122 | }); 123 | 124 | export default dropdownStyle; 125 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/layouts/adminStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | drawerWidth, 3 | transition, 4 | container, 5 | } from '../../material-dashboard-react.js'; 6 | 7 | const appStyle = (theme) => ({ 8 | wrapper: { 9 | position: 'relative', 10 | top: '0', 11 | height: '100vh', 12 | }, 13 | mainPanel: { 14 | [theme.breakpoints.up('md')]: { 15 | width: `calc(100% - ${drawerWidth}px)`, 16 | }, 17 | overflow: 'auto', 18 | position: 'relative', 19 | float: 'right', 20 | ...transition, 21 | maxHeight: '100%', 22 | width: '100%', 23 | overflowScrolling: 'touch', 24 | }, 25 | content: { 26 | marginTop: '70px', 27 | padding: '30px 15px', 28 | minHeight: 'calc(100vh - 123px)', 29 | }, 30 | container, 31 | map: { 32 | marginTop: '70px', 33 | }, 34 | }); 35 | 36 | export default appStyle; 37 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/layouts/rtlStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | drawerWidth, 3 | transition, 4 | container, 5 | } from '../../material-dashboard-react.js'; 6 | 7 | const appStyle = (theme) => ({ 8 | wrapper: { 9 | position: 'relative', 10 | top: '0', 11 | height: '100vh', 12 | direction: 'rtl', 13 | }, 14 | mainPanel: { 15 | [theme.breakpoints.up('md')]: { 16 | width: `calc(100% - ${drawerWidth}px)`, 17 | }, 18 | overflow: 'auto', 19 | position: 'relative', 20 | float: 'left', 21 | ...transition, 22 | maxHeight: '100%', 23 | width: '100%', 24 | overflowScrolling: 'touch', 25 | }, 26 | content: { 27 | marginTop: '70px', 28 | padding: '30px 15px', 29 | minHeight: 'calc(100vh - 123px)', 30 | }, 31 | container, 32 | map: { 33 | marginTop: '70px', 34 | }, 35 | }); 36 | 37 | export default appStyle; 38 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/tooltipStyle.js: -------------------------------------------------------------------------------- 1 | import { blackColor, hexToRgb } from '../material-dashboard-react.js'; 2 | 3 | const tooltipStyle = { 4 | tooltip: { 5 | padding: '10px 15px', 6 | minWidth: '130px', 7 | lineHeight: '1.7em', 8 | border: 'none', 9 | borderRadius: '3px', 10 | boxShadow: 11 | '0 8px 10px 1px rgba(' + 12 | hexToRgb(blackColor) + 13 | ', 0.14), 0 3px 14px 2px rgba(' + 14 | hexToRgb(blackColor) + 15 | ', 0.12), 0 5px 5px -3px rgba(' + 16 | hexToRgb(blackColor) + 17 | ', 0.2)', 18 | maxWidth: '200px', 19 | textAlign: 'center', 20 | fontFamily: '"Helvetica Neue",Helvetica,Arial,sans-serif', 21 | fontSize: '12px', 22 | fontStyle: 'normal', 23 | fontWeight: '400', 24 | textShadow: 'none', 25 | textTransform: 'none', 26 | letterSpacing: 'normal', 27 | wordBreak: 'normal', 28 | wordSpacing: 'normal', 29 | wordWrap: 'normal', 30 | whiteSpace: 'normal', 31 | lineBreak: 'auto', 32 | }, 33 | }; 34 | export default tooltipStyle; 35 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/views/apiStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | successColor, 3 | whiteColor, 4 | grayColor, 5 | hexToRgb, 6 | } from '../../material-dashboard-react.js'; 7 | 8 | const apiStyle = { 9 | successText: { 10 | color: successColor[0], 11 | }, 12 | upArrowCardCategory: { 13 | width: '16px', 14 | height: '16px', 15 | }, 16 | sortBy: { 17 | color: grayColor[0], 18 | display: 'inline-flex', 19 | fontSize: '14px', 20 | lineHeight: '22px', 21 | '& svg': { 22 | top: '4px', 23 | width: '18px', 24 | height: '18px', 25 | position: 'relative', 26 | marginRight: '3px', 27 | marginLeft: '3px', 28 | }, 29 | '& .fab,& .fas,& .far,& .fal,& .material-icons': { 30 | top: '4px', 31 | fontSize: '16px', 32 | position: 'relative', 33 | marginRight: '3px', 34 | marginLeft: '3px', 35 | }, 36 | }, 37 | timeRange: { 38 | width: '160px', 39 | fontSize: '14px', 40 | }, 41 | 42 | dateSpec: { 43 | fontSize: '14px', 44 | color: grayColor[0], 45 | }, 46 | cardCategory: { 47 | color: grayColor[0], 48 | margin: '0', 49 | fontSize: '14px', 50 | marginTop: '0', 51 | paddingTop: '10px', 52 | marginBottom: '0', 53 | }, 54 | cardCategoryWhite: { 55 | color: 'rgba(' + hexToRgb(whiteColor) + ',.62)', 56 | margin: '0', 57 | fontSize: '14px', 58 | marginTop: '0', 59 | marginBottom: '0', 60 | }, 61 | cardTitle: { 62 | color: grayColor[2], 63 | marginTop: '0px', 64 | minHeight: 'auto', 65 | fontWeight: '300', 66 | fontFamily: "'Roboto', 'Helvetica', 'Arial', sans-serif", 67 | marginBottom: '3px', 68 | textDecoration: 'none', 69 | '& small': { 70 | color: grayColor[1], 71 | fontWeight: '400', 72 | lineHeight: '1', 73 | }, 74 | }, 75 | cardTitleWhite: { 76 | color: whiteColor, 77 | marginTop: '0px', 78 | minHeight: 'auto', 79 | fontWeight: '300', 80 | fontFamily: "'Roboto', 'Helvetica', 'Arial', sans-serif", 81 | marginBottom: '3px', 82 | textDecoration: 'none', 83 | '& small': { 84 | color: grayColor[1], 85 | fontWeight: '400', 86 | lineHeight: '1', 87 | }, 88 | }, 89 | root: { 90 | width: '100%', 91 | maxWidth: 360, 92 | // backgroundColor: theme.palette.background.paper, 93 | }, 94 | nested: { 95 | // paddingLeft: theme.spacing(4), 96 | }, 97 | }; 98 | 99 | export default apiStyle; 100 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/views/dashboardStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | successColor, 3 | whiteColor, 4 | grayColor, 5 | hexToRgb, 6 | } from '../../material-dashboard-react.js'; 7 | 8 | const dashboardStyle = { 9 | successText: { 10 | color: successColor[0], 11 | }, 12 | timeRange: { 13 | width: '160px', 14 | fontSize: '14px', 15 | }, 16 | 17 | dateSpec: { 18 | fontSize: '14px', 19 | color: grayColor[0], 20 | }, 21 | upArrowCardCategory: { 22 | width: '16px', 23 | height: '16px', 24 | }, 25 | stats: { 26 | color: grayColor[0], 27 | display: 'inline-flex', 28 | fontSize: '12px', 29 | lineHeight: '22px', 30 | '& svg': { 31 | top: '4px', 32 | width: '16px', 33 | height: '16px', 34 | position: 'relative', 35 | marginRight: '3px', 36 | marginLeft: '3px', 37 | }, 38 | '& .fab,& .fas,& .far,& .fal,& .material-icons': { 39 | top: '4px', 40 | fontSize: '16px', 41 | position: 'relative', 42 | marginRight: '3px', 43 | marginLeft: '3px', 44 | }, 45 | }, 46 | cardCategory: { 47 | color: grayColor[0], 48 | margin: '0', 49 | fontSize: '14px', 50 | marginTop: '0', 51 | paddingTop: '10px', 52 | marginBottom: '0', 53 | }, 54 | cardCategoryWhite: { 55 | color: 'rgba(' + hexToRgb(whiteColor) + ',.62)', 56 | margin: '0', 57 | fontSize: '14px', 58 | marginTop: '0', 59 | marginBottom: '0', 60 | }, 61 | cardTitle: { 62 | color: grayColor[2], 63 | marginTop: '0px', 64 | minHeight: 'auto', 65 | fontWeight: '300', 66 | fontFamily: "'Roboto', 'Helvetica', 'Arial', sans-serif", 67 | marginBottom: '3px', 68 | textDecoration: 'none', 69 | '& small': { 70 | color: grayColor[1], 71 | fontWeight: '400', 72 | lineHeight: '1', 73 | }, 74 | }, 75 | cardTitleWhite: { 76 | color: whiteColor, 77 | marginTop: '0px', 78 | minHeight: 'auto', 79 | fontWeight: '300', 80 | fontFamily: "'Roboto', 'Helvetica', 'Arial', sans-serif", 81 | marginBottom: '3px', 82 | textDecoration: 'none', 83 | '& small': { 84 | color: grayColor[1], 85 | fontWeight: '400', 86 | lineHeight: '1', 87 | }, 88 | }, 89 | }; 90 | 91 | export default dashboardStyle; 92 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/views/iconsStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | boxShadow, 3 | whiteColor, 4 | grayColor, 5 | hexToRgb, 6 | } from '../../material-dashboard-react.js'; 7 | 8 | const iconsStyle = { 9 | iframe: { 10 | width: '100%', 11 | height: '500px', 12 | border: '0', 13 | ...boxShadow, 14 | }, 15 | iframeContainer: { 16 | margin: '0 -20px 0', 17 | }, 18 | cardCategoryWhite: { 19 | '&,& a,& a:hover,& a:focus': { 20 | color: 'rgba(' + hexToRgb(whiteColor) + ',.62)', 21 | margin: '0', 22 | fontSize: '14px', 23 | marginTop: '0', 24 | marginBottom: '0', 25 | }, 26 | '& a,& a:hover,& a:focus': { 27 | color: whiteColor, 28 | }, 29 | }, 30 | cardTitleWhite: { 31 | color: whiteColor, 32 | marginTop: '0px', 33 | minHeight: 'auto', 34 | fontWeight: '300', 35 | fontFamily: "'Roboto', 'Helvetica', 'Arial', sans-serif", 36 | marginBottom: '3px', 37 | textDecoration: 'none', 38 | '& small': { 39 | color: grayColor[1], 40 | fontWeight: '400', 41 | lineHeight: '1', 42 | }, 43 | }, 44 | }; 45 | 46 | export default iconsStyle; 47 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/views/logsStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | successColor, 3 | whiteColor, 4 | grayColor, 5 | hexToRgb, 6 | } from '../../material-dashboard-react.js'; 7 | 8 | const logStyle = { 9 | successText: { 10 | color: successColor[0], 11 | }, 12 | upArrowCardCategory: { 13 | width: '16px', 14 | height: '16px', 15 | }, 16 | sortBy: { 17 | color: grayColor[0], 18 | display: 'inline-flex', 19 | fontSize: '14px', 20 | lineHeight: '22px', 21 | '& svg': { 22 | top: '4px', 23 | width: '18px', 24 | height: '18px', 25 | position: 'relative', 26 | marginRight: '3px', 27 | marginLeft: '3px', 28 | }, 29 | '& .fab,& .fas,& .far,& .fal,& .material-icons': { 30 | top: '4px', 31 | fontSize: '16px', 32 | position: 'relative', 33 | marginRight: '3px', 34 | marginLeft: '3px', 35 | }, 36 | 37 | }, 38 | timeRange: { 39 | width: '160px', 40 | fontSize: '14px', 41 | }, 42 | 43 | dateSpec: { 44 | fontSize: '14px', 45 | color: grayColor[0] 46 | }, 47 | cardCategory: { 48 | color: grayColor[0], 49 | margin: '0', 50 | fontSize: '14px', 51 | marginTop: '0', 52 | paddingTop: '10px', 53 | marginBottom: '0', 54 | }, 55 | cardCategoryWhite: { 56 | color: 'rgba(' + hexToRgb(whiteColor) + ',.62)', 57 | margin: '0', 58 | fontSize: '14px', 59 | marginTop: '0', 60 | marginBottom: '0', 61 | }, 62 | cardTitle: { 63 | color: grayColor[2], 64 | marginTop: '0px', 65 | minHeight: 'auto', 66 | fontWeight: '300', 67 | fontFamily: "'Roboto', 'Helvetica', 'Arial', sans-serif", 68 | marginBottom: '3px', 69 | textDecoration: 'none', 70 | '& small': { 71 | color: grayColor[1], 72 | fontWeight: '400', 73 | lineHeight: '1', 74 | }, 75 | }, 76 | cardTitleWhite: { 77 | color: whiteColor, 78 | marginTop: '0px', 79 | minHeight: 'auto', 80 | fontWeight: '300', 81 | fontFamily: "'Roboto', 'Helvetica', 'Arial', sans-serif", 82 | marginBottom: '3px', 83 | textDecoration: 'none', 84 | '& small': { 85 | color: grayColor[1], 86 | fontWeight: '400', 87 | lineHeight: '1', 88 | }, 89 | }, 90 | }; 91 | 92 | export default logStyle; 93 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/jss/material-dashboard-react/views/rtlStyle.js: -------------------------------------------------------------------------------- 1 | import { 2 | successColor, 3 | whiteColor, 4 | grayColor, 5 | hexToRgb, 6 | } from '../../material-dashboard-react.js'; 7 | 8 | const rtlStyle = { 9 | successText: { 10 | color: successColor[0], 11 | }, 12 | upArrowCardCategory: { 13 | width: '16px', 14 | height: '16px', 15 | }, 16 | stats: { 17 | color: grayColor[0], 18 | display: 'inline-flex', 19 | fontSize: '12px', 20 | lineHeight: '22px', 21 | '& svg': { 22 | top: '4px', 23 | width: '16px', 24 | height: '16px', 25 | position: 'relative', 26 | marginRight: '3px', 27 | marginLeft: '3px', 28 | }, 29 | '& .fab,& .fas,& .far,& .fal,& .material-icons': { 30 | top: '4px', 31 | fontSize: '16px', 32 | position: 'relative', 33 | marginRight: '3px', 34 | marginLeft: '3px', 35 | }, 36 | }, 37 | cardCategory: { 38 | color: grayColor[0], 39 | margin: '0', 40 | fontSize: '14px', 41 | marginTop: '0', 42 | paddingTop: '10px', 43 | marginBottom: '0', 44 | }, 45 | cardCategoryWhite: { 46 | color: 'rgba(' + hexToRgb(whiteColor) + ',.62)', 47 | margin: '0', 48 | fontSize: '14px', 49 | marginTop: '0', 50 | marginBottom: '0', 51 | '& a': { 52 | color: whiteColor, 53 | }, 54 | }, 55 | cardTitle: { 56 | color: grayColor[2], 57 | marginTop: '0px', 58 | minHeight: 'auto', 59 | fontWeight: '300', 60 | fontFamily: "'Roboto', 'Helvetica', 'Arial', sans-serif", 61 | marginBottom: '3px', 62 | textDecoration: 'none', 63 | '& small': { 64 | color: grayColor[1], 65 | fontWeight: '400', 66 | lineHeight: '1', 67 | }, 68 | }, 69 | cardTitleWhite: { 70 | color: whiteColor, 71 | marginTop: '0px', 72 | minHeight: 'auto', 73 | fontWeight: '300', 74 | fontFamily: "'Roboto', 'Helvetica', 'Arial', sans-serif", 75 | marginBottom: '3px', 76 | textDecoration: 'none', 77 | '& small': { 78 | color: grayColor[1], 79 | fontWeight: '400', 80 | lineHeight: '1', 81 | }, 82 | }, 83 | }; 84 | 85 | export default rtlStyle; 86 | -------------------------------------------------------------------------------- /client/src/Dashboard/assets/scss/chart_legend.scss: -------------------------------------------------------------------------------- 1 | // .ct-legend { 2 | // position: relative; 3 | // z-index: 10; 4 | 5 | // li { 6 | // position: relative; 7 | // padding-left: 23px; 8 | // margin-bottom: 3px; 9 | // } 10 | 11 | // li:before { 12 | // width: 12px; 13 | // height: 12px; 14 | // position: absolute; 15 | // left: 0; 16 | // content: ''; 17 | // border: 3px solid transparent; 18 | // border-radius: 2px; 19 | // } 20 | 21 | // li.inactive:before { 22 | // background: transparent; 23 | // } 24 | 25 | // &.ct-legend-inside { 26 | // position: absolute; 27 | // top: 0; 28 | // right: 0; 29 | // } 30 | 31 | // // @for $i from 0 to length($ct-series-colors) { 32 | // // .ct-series-#{$i}:before { 33 | // // background-color: nth($ct-series-colors, $i + 1); 34 | // // border-color: nth($ct-series-colors, $i + 1); 35 | // // } 36 | // // } 37 | // } -------------------------------------------------------------------------------- /client/src/Dashboard/components/Card/Card.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | // nodejs library that concatenates classes 3 | import classNames from 'classnames'; 4 | // nodejs library to set properties for components 5 | import PropTypes from 'prop-types'; 6 | // @material-ui/core components 7 | import { makeStyles } from '@material-ui/core/styles'; 8 | // @material-ui/icons 9 | 10 | // core components 11 | import styles from '../../assets/jss/material-dashboard-react/components/cardStyle.js'; 12 | 13 | const useStyles = makeStyles(styles); 14 | 15 | export default function Card(props) { 16 | const classes = useStyles(); 17 | const { className, children, plain, profile, chart, ...rest } = props; 18 | const cardClasses = classNames({ 19 | [classes.card]: true, 20 | [classes.cardPlain]: plain, 21 | [classes.cardProfile]: profile, 22 | [classes.cardChart]: chart, 23 | [className]: className !== undefined, 24 | }); 25 | return ( 26 |
27 | {children} 28 |
29 | ); 30 | } 31 | 32 | Card.propTypes = { 33 | className: PropTypes.string, 34 | plain: PropTypes.bool, 35 | profile: PropTypes.bool, 36 | chart: PropTypes.bool, 37 | children: PropTypes.node, 38 | }; 39 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Card/CardAvatar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | // nodejs library that concatenates classes 3 | import classNames from 'classnames'; 4 | // nodejs library to set properties for components 5 | import PropTypes from 'prop-types'; 6 | // @material-ui/core components 7 | import { makeStyles } from '@material-ui/core/styles'; 8 | // @material-ui/icons 9 | // core components 10 | 11 | import styles from '../../assets/jss/material-dashboard-react/components/cardAvatarStyle.js'; 12 | 13 | const useStyles = makeStyles(styles); 14 | 15 | export default function CardAvatar(props) { 16 | const classes = useStyles(); 17 | const { children, className, plain, profile, ...rest } = props; 18 | const cardAvatarClasses = classNames({ 19 | [classes.cardAvatar]: true, 20 | [classes.cardAvatarProfile]: profile, 21 | [classes.cardAvatarPlain]: plain, 22 | [className]: className !== undefined, 23 | }); 24 | return ( 25 |
26 | {children} 27 |
28 | ); 29 | } 30 | 31 | CardAvatar.propTypes = { 32 | children: PropTypes.node.isRequired, 33 | className: PropTypes.string, 34 | profile: PropTypes.bool, 35 | plain: PropTypes.bool, 36 | }; 37 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Card/CardBody.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | // nodejs library that concatenates classes 3 | import classNames from 'classnames'; 4 | // nodejs library to set properties for components 5 | import PropTypes from 'prop-types'; 6 | // @material-ui/core components 7 | import { makeStyles } from '@material-ui/core/styles'; 8 | // @material-ui/icons 9 | 10 | // core components 11 | import styles from '../../assets/jss/material-dashboard-react/components/cardBodyStyle.js'; 12 | 13 | const useStyles = makeStyles(styles); 14 | 15 | export default function CardBody(props) { 16 | const classes = useStyles(); 17 | const { className, children, plain, profile, ...rest } = props; 18 | const cardBodyClasses = classNames({ 19 | [classes.cardBody]: true, 20 | [classes.cardBodyPlain]: plain, 21 | [classes.cardBodyProfile]: profile, 22 | [className]: className !== undefined, 23 | }); 24 | return ( 25 |
26 | {children} 27 |
28 | ); 29 | } 30 | 31 | CardBody.propTypes = { 32 | className: PropTypes.string, 33 | plain: PropTypes.bool, 34 | profile: PropTypes.bool, 35 | children: PropTypes.node, 36 | }; 37 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Card/CardFooter.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | // nodejs library that concatenates classes 3 | import classNames from 'classnames'; 4 | // nodejs library to set properties for components 5 | import PropTypes from 'prop-types'; 6 | // @material-ui/core components 7 | import { makeStyles } from '@material-ui/core/styles'; 8 | // @material-ui/icons 9 | 10 | // core components 11 | import styles from '../../assets/jss/material-dashboard-react/components/cardFooterStyle.js'; 12 | 13 | const useStyles = makeStyles(styles); 14 | 15 | export default function CardFooter(props) { 16 | const classes = useStyles(); 17 | const { className, children, plain, profile, stats, chart, ...rest } = props; 18 | const cardFooterClasses = classNames({ 19 | [classes.cardFooter]: true, 20 | [classes.cardFooterPlain]: plain, 21 | [classes.cardFooterProfile]: profile, 22 | [classes.cardFooterStats]: stats, 23 | [classes.cardFooterChart]: chart, 24 | [className]: className !== undefined, 25 | }); 26 | return ( 27 |
28 | {children} 29 |
30 | ); 31 | } 32 | 33 | CardFooter.propTypes = { 34 | className: PropTypes.string, 35 | plain: PropTypes.bool, 36 | profile: PropTypes.bool, 37 | stats: PropTypes.bool, 38 | chart: PropTypes.bool, 39 | children: PropTypes.node, 40 | }; 41 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Card/CardHeader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | // nodejs library that concatenates classes 3 | import classNames from 'classnames'; 4 | // nodejs library to set properties for components 5 | import PropTypes from 'prop-types'; 6 | // @material-ui/core components 7 | import { makeStyles } from '@material-ui/core/styles'; 8 | // @material-ui/icons 9 | 10 | // core components 11 | import styles from '../../assets/jss/material-dashboard-react/components/cardHeaderStyle.js'; 12 | 13 | const useStyles = makeStyles(styles); 14 | 15 | export default function CardHeader(props) { 16 | const classes = useStyles(); 17 | const { className, children, color, plain, stats, icon, ...rest } = props; 18 | const cardHeaderClasses = classNames({ 19 | [classes.cardHeader]: true, 20 | [classes[color + 'CardHeader']]: color, 21 | [classes.cardHeaderPlain]: plain, 22 | [classes.cardHeaderStats]: stats, 23 | [classes.cardHeaderIcon]: icon, 24 | [className]: className !== undefined, 25 | }); 26 | return ( 27 |
28 | {children} 29 |
30 | ); 31 | } 32 | 33 | CardHeader.propTypes = { 34 | className: PropTypes.string, 35 | color: PropTypes.oneOf([ 36 | 'warning', 37 | 'success', 38 | 'danger', 39 | 'info', 40 | 'primary', 41 | 'rose', 42 | ]), 43 | plain: PropTypes.bool, 44 | stats: PropTypes.bool, 45 | icon: PropTypes.bool, 46 | children: PropTypes.node, 47 | }; 48 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Card/CardIcon.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | // nodejs library that concatenates classes 3 | import classNames from 'classnames'; 4 | // nodejs library to set properties for components 5 | import PropTypes from 'prop-types'; 6 | // @material-ui/core components 7 | import { makeStyles } from '@material-ui/core/styles'; 8 | // @material-ui/icons 9 | 10 | // core components 11 | import styles from '../../assets/jss/material-dashboard-react/components/cardIconStyle.js'; 12 | 13 | const useStyles = makeStyles(styles); 14 | 15 | export default function CardIcon(props) { 16 | const classes = useStyles(); 17 | const { className, children, color, ...rest } = props; 18 | const cardIconClasses = classNames({ 19 | [classes.cardIcon]: true, 20 | [classes[color + 'CardHeader']]: color, 21 | [className]: className !== undefined, 22 | }); 23 | return ( 24 |
25 | {children} 26 |
27 | ); 28 | } 29 | 30 | CardIcon.propTypes = { 31 | className: PropTypes.string, 32 | color: PropTypes.oneOf([ 33 | 'warning', 34 | 'success', 35 | 'danger', 36 | 'info', 37 | 'primary', 38 | 'rose', 39 | ]), 40 | children: PropTypes.node, 41 | }; 42 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Card/LogCard.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | // nodejs library that concatenates classes 3 | import classNames from 'classnames'; 4 | // nodejs library to set properties for components 5 | import PropTypes from 'prop-types'; 6 | // @material-ui/core components 7 | import { makeStyles } from '@material-ui/core/styles'; 8 | // @material-ui/icons 9 | 10 | // core components 11 | import styles from '../../assets/jss/material-dashboard-react/components/cardStyle.js'; 12 | 13 | const useStyles = makeStyles(styles); 14 | 15 | export default function LogCard(props) { 16 | const classes = useStyles(); 17 | const { className, children, plain, profile, chart, ...rest } = props; 18 | const cardClasses = classNames({ 19 | [classes.card]: true, 20 | [classes.cardPlain]: plain, 21 | [classes.cardProfile]: profile, 22 | [classes.cardChart]: chart, 23 | [className]: className !== undefined, 24 | }); 25 | return ( 26 |
27 | {children} 28 |
29 | ); 30 | } 31 | 32 | LogCard.propTypes = { 33 | className: PropTypes.string, 34 | plain: PropTypes.bool, 35 | profile: PropTypes.bool, 36 | chart: PropTypes.bool, 37 | children: PropTypes.node, 38 | }; 39 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/CustomButtons/Button.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | // nodejs library that concatenates classes 3 | import classNames from 'classnames'; 4 | // nodejs library to set properties for components 5 | import PropTypes from 'prop-types'; 6 | 7 | // material-ui components 8 | import { makeStyles } from '@material-ui/core/styles'; 9 | import Button from '@material-ui/core/Button'; 10 | 11 | import styles from '../../assets/jss/material-dashboard-react/components/buttonStyle.js'; 12 | 13 | const useStyles = makeStyles(styles); 14 | 15 | export default function RegularButton(props) { 16 | const classes = useStyles(); 17 | const { 18 | color, 19 | round, 20 | children, 21 | disabled, 22 | simple, 23 | size, 24 | block, 25 | link, 26 | justIcon, 27 | className, 28 | muiClasses, 29 | ...rest 30 | } = props; 31 | const btnClasses = classNames({ 32 | [classes.button]: true, 33 | [classes[size]]: size, 34 | [classes[color]]: color, 35 | [classes.round]: round, 36 | [classes.disabled]: disabled, 37 | [classes.simple]: simple, 38 | [classes.block]: block, 39 | [classes.link]: link, 40 | [classes.justIcon]: justIcon, 41 | [className]: className, 42 | }); 43 | return ( 44 | 47 | ); 48 | } 49 | 50 | RegularButton.propTypes = { 51 | color: PropTypes.oneOf([ 52 | 'primary', 53 | 'info', 54 | 'success', 55 | 'warning', 56 | 'danger', 57 | 'rose', 58 | 'white', 59 | 'transparent', 60 | ]), 61 | size: PropTypes.oneOf(['sm', 'lg']), 62 | simple: PropTypes.bool, 63 | round: PropTypes.bool, 64 | disabled: PropTypes.bool, 65 | block: PropTypes.bool, 66 | link: PropTypes.bool, 67 | justIcon: PropTypes.bool, 68 | className: PropTypes.string, 69 | // use this to pass the classes props from Material-UI 70 | muiClasses: PropTypes.object, 71 | children: PropTypes.node, 72 | }; 73 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/CustomInput/CustomInput.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import PropTypes from 'prop-types'; 4 | // @material-ui/core components 5 | import { makeStyles } from '@material-ui/core/styles'; 6 | import FormControl from '@material-ui/core/FormControl'; 7 | import InputLabel from '@material-ui/core/InputLabel'; 8 | import Input from '@material-ui/core/Input'; 9 | // @material-ui/icons 10 | import Clear from '@material-ui/icons/Clear'; 11 | import Check from '@material-ui/icons/Check'; 12 | // core components 13 | import styles from '../../assets/jss/material-dashboard-react/components/customInputStyle.js'; 14 | 15 | const useStyles = makeStyles(styles); 16 | 17 | export default function CustomInput(props) { 18 | const classes = useStyles(); 19 | const { 20 | formControlProps, 21 | labelText, 22 | id, 23 | labelProps, 24 | inputProps, 25 | error, 26 | success, 27 | rtlActive, 28 | type, 29 | } = props; 30 | 31 | const labelClasses = classNames({ 32 | [' ' + classes.labelRootError]: error, 33 | [' ' + classes.labelRootSuccess]: success && !error, 34 | [' ' + classes.labelRTL]: rtlActive, 35 | }); 36 | const underlineClasses = classNames({ 37 | [classes.underlineError]: error, 38 | [classes.underlineSuccess]: success && !error, 39 | [classes.underline]: true, 40 | }); 41 | const marginTop = classNames({ 42 | [classes.marginTop]: labelText === undefined, 43 | }); 44 | let newInputProps = { 45 | maxLength: 46 | inputProps && inputProps.maxLength ? inputProps.maxLength : undefined, 47 | minLength: 48 | inputProps && inputProps.minLength ? inputProps.minLength : undefined, 49 | step: inputProps && inputProps.step ? inputProps.step : undefined, 50 | }; 51 | return ( 52 | 56 | {labelText !== undefined ? ( 57 | 62 | {labelText} 63 | 64 | ) : null} 65 | 76 | {error ? ( 77 | 78 | ) : success ? ( 79 | 80 | ) : null} 81 | 82 | ); 83 | } 84 | 85 | CustomInput.propTypes = { 86 | labelText: PropTypes.node, 87 | labelProps: PropTypes.object, 88 | id: PropTypes.string, 89 | inputProps: PropTypes.object, 90 | formControlProps: PropTypes.object, 91 | error: PropTypes.bool, 92 | success: PropTypes.bool, 93 | rtlActive: PropTypes.bool, 94 | }; 95 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/CustomTabs/CustomTabs.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | // nodejs library that concatenates classes 3 | import classNames from 'classnames'; 4 | // nodejs library to set properties for components 5 | import PropTypes from 'prop-types'; 6 | 7 | // material-ui components 8 | import { makeStyles } from '@material-ui/core/styles'; 9 | import Tabs from '@material-ui/core/Tabs'; 10 | import Tab from '@material-ui/core/Tab'; 11 | // core components 12 | import Card from '../Card/Card.js'; 13 | import CardBody from '../Card/CardBody.js'; 14 | import CardHeader from '../Card/CardHeader.js'; 15 | 16 | import styles from '../../assets/jss/material-dashboard-react/components/customTabsStyle.js'; 17 | 18 | const useStyles = makeStyles(styles); 19 | 20 | export default function CustomTabs(props) { 21 | const [value, setValue] = React.useState(0); 22 | const handleChange = (event, value) => { 23 | setValue(value); 24 | }; 25 | const classes = useStyles(); 26 | const { headerColor, plainTabs, tabs, title, rtlActive } = props; 27 | const cardTitle = classNames({ 28 | [classes.cardTitle]: true, 29 | [classes.cardTitleRTL]: rtlActive, 30 | }); 31 | return ( 32 | 33 | 34 | {title !== undefined ?
{title}
: null} 35 | 46 | {tabs.map((prop, key) => { 47 | var icon = {}; 48 | if (prop.tabIcon) { 49 | icon = { 50 | icon: , 51 | }; 52 | } 53 | return ( 54 | 64 | ); 65 | })} 66 | 67 |
68 | 69 | {tabs.map((prop, key) => { 70 | if (key === value) { 71 | return
{prop.tabContent}
; 72 | } 73 | return null; 74 | })} 75 |
76 |
77 | ); 78 | } 79 | 80 | CustomTabs.propTypes = { 81 | headerColor: PropTypes.oneOf([ 82 | 'warning', 83 | 'success', 84 | 'danger', 85 | 'info', 86 | 'primary', 87 | 'rose', 88 | ]), 89 | title: PropTypes.string, 90 | tabs: PropTypes.arrayOf( 91 | PropTypes.shape({ 92 | tabName: PropTypes.string.isRequired, 93 | tabIcon: PropTypes.object, 94 | tabContent: PropTypes.node.isRequired, 95 | }) 96 | ), 97 | rtlActive: PropTypes.bool, 98 | plainTabs: PropTypes.bool, 99 | }; 100 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/FetchTime/FetchTime.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useEffect, useState } from 'react'; 3 | import AccessTime from '@material-ui/icons/AccessTime'; 4 | import { makeStyles } from '@material-ui/core/styles'; 5 | import styles from '../../assets/jss/material-dashboard-react/views/dashboardStyle.js'; 6 | import moment from 'moment'; 7 | 8 | const useStyles = makeStyles(styles); 9 | 10 | export default function FetchTime(props) { 11 | const classes = useStyles(); 12 | 13 | const [fetchTime, setFetchTime] = useState(moment(props.lastMetricFetchTime).fromNow()) 14 | useEffect(() => { 15 | 16 | const interval = setInterval(() => { 17 | 18 | setFetchTime(moment(props.lastMetricFetchTime).fromNow()) 19 | 20 | }, 1000) 21 | 22 | return () => clearInterval(interval); 23 | 24 | 25 | 26 | }, [props.lastMetricFetchTime]); 27 | 28 | return ( 29 |
30 | Last fetched {fetchTime} 31 |
32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Footer/Footer.js: -------------------------------------------------------------------------------- 1 | /*eslint-disable*/ 2 | import React from 'react'; 3 | import PropTypes from 'prop-types'; 4 | // @material-ui/core components 5 | import { makeStyles } from '@material-ui/core/styles'; 6 | import ListItem from '@material-ui/core/ListItem'; 7 | import List from '@material-ui/core/List'; 8 | // core components 9 | import styles from '../../assets/jss/material-dashboard-react/components/footerStyle.js'; 10 | 11 | const useStyles = makeStyles(styles); 12 | 13 | export default function Footer(props) { 14 | const classes = useStyles(); 15 | return ( 16 | 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Grid/GridContainer.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | // nodejs library to set properties for components 3 | import PropTypes from "prop-types"; 4 | // @material-ui/core components 5 | import { makeStyles } from "@material-ui/core/styles"; 6 | import Grid from "@material-ui/core/Grid"; 7 | 8 | const styles = { 9 | grid: { 10 | margin: "0 -15px !important", 11 | width: "unset", 12 | }, 13 | }; 14 | 15 | const useStyles = makeStyles(styles); 16 | 17 | export default function GridContainer(props) { 18 | const classes = useStyles(); 19 | const { children, ...rest } = props; 20 | return ( 21 | 22 | {children} 23 | 24 | ); 25 | } 26 | 27 | GridContainer.propTypes = { 28 | children: PropTypes.node, 29 | }; 30 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Grid/GridItem.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | // nodejs library to set properties for components 3 | import PropTypes from "prop-types"; 4 | // @material-ui/core components 5 | import { makeStyles } from "@material-ui/core/styles"; 6 | import Grid from "@material-ui/core/Grid"; 7 | 8 | const styles = { 9 | grid: { 10 | padding: "0 15px !important", 11 | }, 12 | }; 13 | 14 | const useStyles = makeStyles(styles); 15 | 16 | export default function GridItem(props) { 17 | const classes = useStyles(); 18 | const { children, ...rest } = props; 19 | return ( 20 | 21 | {children} 22 | 23 | ); 24 | } 25 | 26 | GridItem.propTypes = { 27 | children: PropTypes.node, 28 | }; 29 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/LambdaList/LambdaList.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useEffect, useState } from 'react'; 3 | import PropTypes from 'prop-types'; 4 | import classnames from 'classnames'; 5 | // @material-ui/core components 6 | import { makeStyles } from '@material-ui/core/styles'; 7 | import Checkbox from '@material-ui/core/Checkbox'; 8 | import Tooltip from '@material-ui/core/Tooltip'; 9 | import IconButton from '@material-ui/core/IconButton'; 10 | import Table from '@material-ui/core/Table'; 11 | import TableRow from '@material-ui/core/TableRow'; 12 | import TableBody from '@material-ui/core/TableBody'; 13 | import TableCell from '@material-ui/core/TableCell'; 14 | // @material-ui/icons 15 | import Edit from '@material-ui/icons/Edit'; 16 | import Close from '@material-ui/icons/Close'; 17 | import Check from '@material-ui/icons/Check'; 18 | // core components 19 | import styles from '../../assets/jss/material-dashboard-react/components/tasksStyle.js'; 20 | import { trackPromise } from 'react-promise-tracker'; 21 | import { usePromiseTracker } from 'react-promise-tracker'; 22 | import { Spinner } from '../../variables/spinner'; 23 | import Loader from 'react-loader-spinner'; 24 | import 'react-loader-spinner/dist/loader/css/react-spinner-loader.css'; 25 | 26 | const useStyles = makeStyles(styles); 27 | 28 | export default function LambdaList(props) { 29 | const classes = useStyles(); 30 | 31 | // checked holds the current Lambda Functions checked 32 | const [checked, setChecked] = useState([...props.logsShown]); 33 | 34 | // When a fetch is in progress, creates a loading icon 35 | const { promiseInProgress } = usePromiseTracker(); 36 | 37 | // when a Lambda Function is clicked 38 | const handleToggle = (funcName) => { 39 | const currentIndex = checked.indexOf(funcName); 40 | const newChecked = [...checked]; 41 | // if function isn't already clicked, add it and fetch the logs from AWS 42 | if (currentIndex === -1) { 43 | newChecked.push(funcName); 44 | const reqParams = { 45 | method: 'POST', 46 | headers: { 'Content-Type': 'application/json' }, 47 | body: JSON.stringify({ 48 | function: funcName, 49 | credentials: props.credentials, 50 | region: props.region, 51 | timePeriod: props.timePeriod, 52 | }), 53 | }; 54 | 55 | // track this promise and unti it's fulfilled, trackPromise shows a loading icon 56 | trackPromise(fetch('/aws/getLogs', reqParams)) 57 | .then((res) => res.json()) 58 | .then((logs) => { 59 | // if we get logs back add to state 60 | if (logs && !logs.err) { 61 | props.addFunctionLogs(logs); 62 | } 63 | }); 64 | // if the function already existed on the checked array, then we want to remove it to signal the uncheck 65 | } else { 66 | newChecked.splice(currentIndex, 1); 67 | props.removeFunctionLogs(funcName); 68 | } 69 | // update the checked array with new contents 70 | setChecked(newChecked); 71 | }; 72 | const { rtlActive } = props; 73 | const tableCellClasses = classnames(classes.tableCell, { 74 | [classes.tableCellRTL]: rtlActive, 75 | }); 76 | return ( 77 |
78 | {/* Loading icon that shows when a promise is in progress */} 79 | {promiseInProgress || props.updatePromise ? ( 80 |
81 | 88 |
89 | ) : null} 90 | 91 | {/* Table of the list of Lambda Functions associated with user's account */} 92 | 93 | 94 | {props.functions.map((funcName, i) => ( 95 | 96 | 97 | handleToggle(funcName)} 101 | checkedIcon={} 102 | icon={} 103 | classes={{ 104 | checked: classes.checked, 105 | root: classes.root, 106 | }} 107 | /> 108 | 109 | {funcName} 110 | 111 | ))} 112 | 113 |
114 |
115 | ); 116 | } 117 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/LambdaListMetrics/LambdaListMetrics.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useEffect, useState } from 'react'; 3 | import PropTypes from 'prop-types'; 4 | import classnames from 'classnames'; 5 | // @material-ui/core components 6 | import { makeStyles } from '@material-ui/core/styles'; 7 | import Checkbox from '@material-ui/core/Checkbox'; 8 | import Tooltip from '@material-ui/core/Tooltip'; 9 | import IconButton from '@material-ui/core/IconButton'; 10 | import Table from '@material-ui/core/Table'; 11 | import TableRow from '@material-ui/core/TableRow'; 12 | import TableBody from '@material-ui/core/TableBody'; 13 | import TableCell from '@material-ui/core/TableCell'; 14 | // @material-ui/icons 15 | import Edit from '@material-ui/icons/Edit'; 16 | import Close from '@material-ui/icons/Close'; 17 | import Check from '@material-ui/icons/Check'; 18 | // core components 19 | import styles from '../../assets/jss/material-dashboard-react/components/tasksStyle.js'; 20 | import { trackPromise } from 'react-promise-tracker'; 21 | import { usePromiseTracker } from 'react-promise-tracker'; 22 | import { Spinner } from '../../variables/spinner'; 23 | import Loader from 'react-loader-spinner'; 24 | import 'react-loader-spinner/dist/loader/css/react-spinner-loader.css'; 25 | 26 | const useStyles = makeStyles(styles); 27 | 28 | export default function LambdaList(props) { 29 | const classes = useStyles(); 30 | const [checked, setChecked] = useState([...props.checkedIndexes]); 31 | const { promiseInProgress } = usePromiseTracker(); 32 | 33 | const handleToggle = (value) => { 34 | const currentIndex = checked.indexOf(value); 35 | const newChecked = [...checked]; 36 | if (currentIndex === -1) { 37 | newChecked.push(value); 38 | props.addFunctionMetrics(props.tasks[value]) 39 | 40 | } else { 41 | newChecked.splice(currentIndex, 1); 42 | props.removeFunctionMetrics(props.tasks[value]); 43 | } 44 | setChecked(newChecked); 45 | }; 46 | const { tasksIndexes, tasks, rtlActive } = props; 47 | const tableCellClasses = classnames(classes.tableCell, { 48 | [classes.tableCellRTL]: rtlActive, 49 | }); 50 | return ( 51 |
52 | {promiseInProgress || props.updatePromise ? ( 53 |
54 | 61 |
62 | ) : null} 63 | 64 | 65 | {tasksIndexes.map((value) => ( 66 | 67 | 68 | handleToggle(value)} 72 | checkedIcon={} 73 | icon={} 74 | classes={{ 75 | checked: classes.checked, 76 | root: classes.root, 77 | }} 78 | /> 79 | 80 | {tasks[value]} 81 | 82 | ))} 83 | 84 |
85 |
86 | ); 87 | } 88 | 89 | LambdaList.propTypes = { 90 | tasksIndexes: PropTypes.arrayOf(PropTypes.number), 91 | tasks: PropTypes.arrayOf(PropTypes.node), 92 | rtlActive: PropTypes.bool, 93 | checkedIndexes: PropTypes.array, 94 | }; 95 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Navbars/AdminNavbarLinks.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { useHistory, Link } from 'react-router-dom'; 4 | import classNames from 'classnames'; 5 | // @material-ui/core components 6 | import { makeStyles } from '@material-ui/core/styles'; 7 | import MenuItem from '@material-ui/core/MenuItem'; 8 | import MenuList from '@material-ui/core/MenuList'; 9 | import Grow from '@material-ui/core/Grow'; 10 | import Paper from '@material-ui/core/Paper'; 11 | import ClickAwayListener from '@material-ui/core/ClickAwayListener'; 12 | import Hidden from '@material-ui/core/Hidden'; 13 | import Poppers from '@material-ui/core/Popper'; 14 | import Divider from '@material-ui/core/Divider'; 15 | import Typography from '@material-ui/core/Typography'; 16 | // @material-ui/icons 17 | import Person from '@material-ui/icons/Person'; 18 | import Notifications from '@material-ui/icons/Notifications'; 19 | import Dashboard from '@material-ui/icons/Dashboard'; 20 | import Search from '@material-ui/icons/Search'; 21 | import EditLocation from '@material-ui/icons/EditLocation'; 22 | // core components 23 | import CustomInput from '../../components/CustomInput/CustomInput.js'; 24 | import Button from '../../components/CustomButtons/Button.js'; 25 | import { handleLogout } from '../../../Actions/actions'; 26 | import clearIDB from '../../../indexedDB/clearIDB'; 27 | import { regions } from '../../variables/regions.js'; 28 | import styles from '../../assets/jss/material-dashboard-react/components/headerLinksStyle.js'; 29 | 30 | const useStyles = makeStyles(styles); 31 | 32 | const mapDispatchToProps = (dispatch) => ({ 33 | handleLogout: () => dispatch(handleLogout()), 34 | }); 35 | 36 | const mapStateToProps = (state) => ({ 37 | region: state.main.region, 38 | }); 39 | 40 | function AdminNavbarLinks(props) { 41 | const classes = useStyles(); 42 | 43 | const [openProfile, setOpenProfile] = React.useState(null); 44 | 45 | const handleClickProfile = (event) => { 46 | if (openProfile && openProfile.contains(event.target)) { 47 | setOpenProfile(null); 48 | } else { 49 | setOpenProfile(event.currentTarget); 50 | } 51 | }; 52 | const handleCloseProfile = () => { 53 | setOpenProfile(null); 54 | }; 55 | const handleRouteToProfile = () => { 56 | setOpenProfile(null); 57 | history.push('/admin/user'); 58 | }; 59 | 60 | const handleLogoutAndChange = () => { 61 | setOpenProfile(null); 62 | props.handleLogout(); 63 | clearIDB(); 64 | history.push('/'); 65 | }; 66 | const history = useHistory(); 67 | return ( 68 |
69 | {/* Display current region selected and navigate to the User Profile page if clicked 70 | where they can update the region */} 71 | 72 |
73 | Region: {regions[props.region]} 74 | 83 |
84 | 85 | 86 | {/* Button to navigate back to the main dashboard page */} 87 | 88 | 100 | 101 | 102 | {/* The profile button on NavBar which opens up to give the option to navigate to User Profile page and/or logout */} 103 |
104 | 118 | 129 | {({ TransitionProps, placement }) => ( 130 | 138 | 139 | 140 | 141 | 145 | Profile 146 | 147 | 148 | 152 | Logout 153 | 154 | 155 | 156 | 157 | 158 | )} 159 | 160 |
161 |
162 | ); 163 | } 164 | export default connect(mapStateToProps, mapDispatchToProps)(AdminNavbarLinks); 165 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Navbars/Navbar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import PropTypes from 'prop-types'; 4 | // @material-ui/core components 5 | import { makeStyles } from '@material-ui/core/styles'; 6 | import AppBar from '@material-ui/core/AppBar'; 7 | import Toolbar from '@material-ui/core/Toolbar'; 8 | import IconButton from '@material-ui/core/IconButton'; 9 | import Hidden from '@material-ui/core/Hidden'; 10 | // @material-ui/icons 11 | import Menu from '@material-ui/icons/Menu'; 12 | // core components 13 | import AdminNavbarLinks from './AdminNavbarLinks.js'; 14 | import Button from '../../components/CustomButtons/Button.js'; 15 | 16 | //hooks 17 | import { useRouteName } from '../../hooks'; 18 | 19 | import styles from '../../assets/jss/material-dashboard-react/components/headerStyle.js'; 20 | 21 | const useStyles = makeStyles(styles); 22 | 23 | export default function Header(props) { 24 | const classes = useStyles(); 25 | const routeName = useRouteName(); 26 | const { color } = props; 27 | const appBarClasses = classNames({ 28 | [' ' + classes[color]]: color, 29 | }); 30 | return ( 31 | 32 | 33 |
34 | {/* Here we create navbar brand, based on route name */} 35 | 38 |
39 | 40 | 41 | 42 | 43 | 48 | 49 | 50 | 51 | 52 | 53 | ); 54 | } 55 | 56 | Header.propTypes = { 57 | color: PropTypes.oneOf(['primary', 'info', 'success', 'warning', 'danger']), 58 | rtlActive: PropTypes.bool, 59 | handleDrawerToggle: PropTypes.func, 60 | routes: PropTypes.arrayOf(PropTypes.object), 61 | }; 62 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Sidebar/Sidebar.js: -------------------------------------------------------------------------------- 1 | /*eslint-disable*/ 2 | import React from 'react'; 3 | import classNames from 'classnames'; 4 | import PropTypes from 'prop-types'; 5 | import { NavLink, useLocation } from 'react-router-dom'; 6 | // @material-ui/core components 7 | import { makeStyles } from '@material-ui/core/styles'; 8 | import Drawer from '@material-ui/core/Drawer'; 9 | import Hidden from '@material-ui/core/Hidden'; 10 | import List from '@material-ui/core/List'; 11 | import ListItem from '@material-ui/core/ListItem'; 12 | import ListItemText from '@material-ui/core/ListItemText'; 13 | import Icon from '@material-ui/core/Icon'; 14 | import HeliosLogo from '../../assets/img/helios-logo-tr.png'; 15 | // core components 16 | import AdminNavbarLinks from '../../components/Navbars/AdminNavbarLinks.js'; 17 | 18 | import styles from '../../assets/jss/material-dashboard-react/components/sidebarStyle.js'; 19 | 20 | const useStyles = makeStyles(styles); 21 | 22 | export default function Sidebar(props) { 23 | const classes = useStyles(); 24 | let location = useLocation(); 25 | // verifies if routeName is the one active (in browser input) 26 | function activeRoute(routeName) { 27 | return location.pathname === routeName; 28 | } 29 | const { color, logo, image, logoText, routes } = props; 30 | var links = ( 31 | 32 | {routes.map((prop, key) => { 33 | var activePro = ' '; 34 | var listItemClasses; 35 | if (prop.path === '/upgrade-to-pro') { 36 | activePro = classes.activePro + ' '; 37 | listItemClasses = classNames({ 38 | [' ' + classes[color]]: true, 39 | }); 40 | } else { 41 | listItemClasses = classNames({ 42 | [' ' + classes[color]]: activeRoute(prop.layout + prop.path), 43 | }); 44 | } 45 | const whiteFontClasses = classNames({ 46 | [' ' + classes.whiteFont]: activeRoute(prop.layout + prop.path), 47 | }); 48 | return ( 49 | 55 | 56 | {typeof prop.icon === 'string' ? ( 57 | 62 | {prop.icon} 63 | 64 | ) : ( 65 | 70 | )} 71 | 78 | 79 | 80 | ); 81 | })} 82 | 83 | ); 84 | var brand = ( 85 | 98 | ); 99 | return ( 100 |
101 | 102 | 116 | {brand} 117 |
118 | 119 | {links} 120 |
121 | {image !== undefined ? ( 122 |
126 | ) : null} 127 | 128 | 129 | 130 | 140 | {brand} 141 |
{links}
142 | {image !== undefined ? ( 143 |
147 | ) : null} 148 | 149 | 150 |
151 | ); 152 | } 153 | 154 | Sidebar.propTypes = { 155 | rtlActive: PropTypes.bool, 156 | handleDrawerToggle: PropTypes.func, 157 | bgColor: PropTypes.oneOf(['purple', 'blue', 'green', 'orange', 'red']), 158 | logo: PropTypes.string, 159 | image: PropTypes.string, 160 | routes: PropTypes.arrayOf(PropTypes.object), 161 | open: PropTypes.bool, 162 | }; 163 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Snackbar/Snackbar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import PropTypes from 'prop-types'; 4 | // @material-ui/core components 5 | import { makeStyles } from '@material-ui/core/styles'; 6 | import Snack from '@material-ui/core/Snackbar'; 7 | import IconButton from '@material-ui/core/IconButton'; 8 | // @material-ui/icons 9 | import Close from '@material-ui/icons/Close'; 10 | // core components 11 | import styles from '../../assets/jss/material-dashboard-react/components/snackbarContentStyle.js'; 12 | 13 | const useStyles = makeStyles(styles); 14 | 15 | export default function Snackbar(props) { 16 | const classes = useStyles(); 17 | const { message, color, close, icon, place, open, rtlActive } = props; 18 | var action = []; 19 | const messageClasses = classNames({ 20 | [classes.iconMessage]: icon !== undefined, 21 | }); 22 | if (close !== undefined) { 23 | action = [ 24 | props.closeNotification()} 30 | > 31 | 32 | , 33 | ]; 34 | } 35 | return ( 36 | 49 | {icon !== undefined ? : null} 50 | {message} 51 |
52 | } 53 | action={action} 54 | ContentProps={{ 55 | classes: { 56 | root: classes.root + ' ' + classes[color], 57 | message: classes.message, 58 | action: classNames({ [classes.actionRTL]: rtlActive }), 59 | }, 60 | }} 61 | /> 62 | ); 63 | } 64 | 65 | Snackbar.propTypes = { 66 | message: PropTypes.node.isRequired, 67 | color: PropTypes.oneOf(['info', 'success', 'warning', 'danger', 'primary']), 68 | close: PropTypes.bool, 69 | icon: PropTypes.object, 70 | place: PropTypes.oneOf(['tl', 'tr', 'tc', 'br', 'bl', 'bc']), 71 | open: PropTypes.bool, 72 | rtlActive: PropTypes.bool, 73 | closeNotification: PropTypes.func, 74 | }; 75 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Snackbar/SnackbarContent.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import classNames from 'classnames'; 4 | // @material-ui/core components 5 | import { makeStyles } from '@material-ui/core/styles'; 6 | import Snack from '@material-ui/core/SnackbarContent'; 7 | import IconButton from '@material-ui/core/IconButton'; 8 | // @material-ui/icons 9 | import Close from '@material-ui/icons/Close'; 10 | // core components 11 | import styles from '../../assets/jss/material-dashboard-react/components/snackbarContentStyle.js'; 12 | 13 | const useStyles = makeStyles(styles); 14 | 15 | export default function SnackbarContent(props) { 16 | const classes = useStyles(); 17 | const { message, color, close, icon, rtlActive } = props; 18 | var action = []; 19 | const messageClasses = classNames({ 20 | [classes.iconMessage]: icon !== undefined, 21 | }); 22 | if (close !== undefined) { 23 | action = [ 24 | 30 | 31 | , 32 | ]; 33 | } 34 | return ( 35 | 38 | {icon !== undefined ? : null} 39 | {message} 40 |
41 | } 42 | classes={{ 43 | root: classes.root + ' ' + classes[color], 44 | message: classes.message, 45 | action: classNames({ [classes.actionRTL]: rtlActive }), 46 | }} 47 | action={action} 48 | /> 49 | ); 50 | } 51 | 52 | SnackbarContent.propTypes = { 53 | message: PropTypes.node.isRequired, 54 | color: PropTypes.oneOf(['info', 'success', 'warning', 'danger', 'primary']), 55 | close: PropTypes.bool, 56 | icon: PropTypes.object, 57 | rtlActive: PropTypes.bool, 58 | }; 59 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Table/LogTable.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | // @material-ui/core components 4 | import { makeStyles } from '@material-ui/core/styles'; 5 | import Table from '@material-ui/core/Table'; 6 | import TableHead from '@material-ui/core/TableHead'; 7 | import TableRow from '@material-ui/core/TableRow'; 8 | import TableBody from '@material-ui/core/TableBody'; 9 | import TableCell from '@material-ui/core/TableCell'; 10 | // core components 11 | import styles from '../../assets/jss/material-dashboard-react/components/logTableStyle.js'; 12 | 13 | const useStyles = makeStyles(styles); 14 | 15 | // table to show the logs for Lambda Functions 16 | export default function LogTable(props) { 17 | const classes = useStyles(); 18 | const { tableHead, tableData, tableHeaderColor, status } = props; 19 | return ( 20 |
21 | 22 | {tableHead !== undefined ? ( 23 | 24 | 25 | Log Stream 26 | Date 27 | Message 28 | 29 | 30 | ) : null} 31 | 32 | {tableData.map((prop, key) => { 33 | // If the log is an error, update the color to be red 34 | if ( 35 | prop[2].slice(0, 13).toLowerCase().trim() === 'invoke error' && 36 | status !== 'errors' 37 | ) { 38 | return ( 39 | 40 | {prop.map((prop, key) => { 41 | return ( 42 | 43 | {prop} 44 | 45 | ); 46 | })} 47 | 48 | ); 49 | // if not an error, map through normally 50 | } else { 51 | return ( 52 | 53 | {prop.map((prop, key) => { 54 | return ( 55 | 56 | {prop} 57 | 58 | ); 59 | })} 60 | 61 | ); 62 | } 63 | })} 64 | 65 |
66 |
67 | ); 68 | } 69 | 70 | LogTable.defaultProps = { 71 | tableHeaderColor: 'gray', 72 | }; 73 | 74 | LogTable.propTypes = { 75 | tableHeaderColor: PropTypes.oneOf([ 76 | 'warning', 77 | 'primary', 78 | 'danger', 79 | 'success', 80 | 'info', 81 | 'rose', 82 | 'gray', 83 | ]), 84 | tableHead: PropTypes.arrayOf(PropTypes.string), 85 | tableData: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)), 86 | }; 87 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Table/Table.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | // @material-ui/core components 4 | import { makeStyles } from '@material-ui/core/styles'; 5 | import Table from '@material-ui/core/Table'; 6 | import TableHead from '@material-ui/core/TableHead'; 7 | import TableRow from '@material-ui/core/TableRow'; 8 | import TableBody from '@material-ui/core/TableBody'; 9 | import TableCell from '@material-ui/core/TableCell'; 10 | // core components 11 | import styles from '../../assets/jss/material-dashboard-react/components/tableStyle.js'; 12 | 13 | const useStyles = makeStyles(styles); 14 | 15 | export default function CustomTable(props) { 16 | const classes = useStyles(); 17 | const { tableHead, tableData, tableHeaderColor } = props; 18 | return ( 19 |
20 | 21 | {tableHead !== undefined ? ( 22 | 23 | 24 | {tableHead.map((prop, key) => { 25 | return ( 26 | 30 | {prop} 31 | 32 | ); 33 | })} 34 | 35 | 36 | ) : null} 37 | 38 | {tableData.map((prop, key) => { 39 | if (prop[3].slice(0, 3) === 'Nig') { 40 | return ( 41 | 42 | {prop.map((prop, key) => { 43 | return ( 44 | 45 | {prop} 46 | 47 | ); 48 | })} 49 | 50 | ); 51 | } else { 52 | return ( 53 | 54 | {prop.map((prop, key) => { 55 | return ( 56 | 57 | {prop} 58 | 59 | ); 60 | })} 61 | 62 | ); 63 | } 64 | })} 65 | 66 |
67 |
68 | ); 69 | } 70 | 71 | CustomTable.defaultProps = { 72 | tableHeaderColor: 'gray', 73 | }; 74 | 75 | CustomTable.propTypes = { 76 | tableHeaderColor: PropTypes.oneOf([ 77 | 'warning', 78 | 'primary', 79 | 'danger', 80 | 'success', 81 | 'info', 82 | 'rose', 83 | 'gray', 84 | ]), 85 | tableHead: PropTypes.arrayOf(PropTypes.string), 86 | tableData: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)), 87 | }; 88 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Typography/Danger.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | // @material-ui/core components 4 | import { makeStyles } from '@material-ui/core/styles'; 5 | // core components 6 | import styles from '../../assets/jss/material-dashboard-react/components/typographyStyle.js'; 7 | 8 | const useStyles = makeStyles(styles); 9 | 10 | export default function Danger(props) { 11 | const classes = useStyles(); 12 | const { children } = props; 13 | return ( 14 |
15 | {children} 16 |
17 | ); 18 | } 19 | 20 | Danger.propTypes = { 21 | children: PropTypes.node, 22 | }; 23 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Typography/Info.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | // @material-ui/core components 4 | import { makeStyles } from '@material-ui/core/styles'; 5 | // core components 6 | import styles from '../../assets/jss/material-dashboard-react/components/typographyStyle.js'; 7 | 8 | const useStyles = makeStyles(styles); 9 | 10 | export default function Info(props) { 11 | const classes = useStyles(); 12 | const { children } = props; 13 | return ( 14 |
15 | {children} 16 |
17 | ); 18 | } 19 | 20 | Info.propTypes = { 21 | children: PropTypes.node, 22 | }; 23 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Typography/Muted.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | // @material-ui/core components 4 | import { makeStyles } from '@material-ui/core/styles'; 5 | // core components 6 | import styles from '../../assets/jss/material-dashboard-react/components/typographyStyle.js'; 7 | 8 | const useStyles = makeStyles(styles); 9 | 10 | export default function Muted(props) { 11 | const classes = useStyles(); 12 | const { children } = props; 13 | return ( 14 |
15 | {children} 16 |
17 | ); 18 | } 19 | 20 | Muted.propTypes = { 21 | children: PropTypes.node, 22 | }; 23 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Typography/Primary.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | // @material-ui/core components 4 | import { makeStyles } from '@material-ui/core/styles'; 5 | // core components 6 | import styles from '../../assets/jss/material-dashboard-react/components/typographyStyle.js'; 7 | 8 | const useStyles = makeStyles(styles); 9 | 10 | export default function Primary(props) { 11 | const classes = useStyles(); 12 | const { children } = props; 13 | return ( 14 |
15 | {children} 16 |
17 | ); 18 | } 19 | 20 | Primary.propTypes = { 21 | children: PropTypes.node, 22 | }; 23 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Typography/Quote.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | // @material-ui/core components 4 | import { makeStyles } from '@material-ui/core/styles'; 5 | // core components 6 | import styles from '../../assets/jss/material-dashboard-react/components/typographyStyle.js'; 7 | 8 | const useStyles = makeStyles(styles); 9 | 10 | export default function Quote(props) { 11 | const classes = useStyles(); 12 | const { text, author } = props; 13 | return ( 14 |
15 |

{text}

16 | {author} 17 |
18 | ); 19 | } 20 | 21 | Quote.propTypes = { 22 | text: PropTypes.node, 23 | author: PropTypes.node, 24 | }; 25 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Typography/Success.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | // @material-ui/core components 4 | import { makeStyles } from '@material-ui/core/styles'; 5 | // core components 6 | import styles from '../../assets/jss/material-dashboard-react/components/typographyStyle.js'; 7 | 8 | const useStyles = makeStyles(styles); 9 | 10 | export default function Success(props) { 11 | const classes = useStyles(); 12 | const { children } = props; 13 | return ( 14 |
15 | {children} 16 |
17 | ); 18 | } 19 | 20 | Success.propTypes = { 21 | children: PropTypes.node, 22 | }; 23 | -------------------------------------------------------------------------------- /client/src/Dashboard/components/Typography/Warning.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | // @material-ui/core components 4 | import { makeStyles } from '@material-ui/core/styles'; 5 | // core components 6 | import styles from '../../assets/jss/material-dashboard-react/components/typographyStyle.js'; 7 | 8 | const useStyles = makeStyles(styles); 9 | 10 | export default function Warning(props) { 11 | const classes = useStyles(); 12 | const { children } = props; 13 | return ( 14 |
15 | {children} 16 |
17 | ); 18 | } 19 | 20 | Warning.propTypes = { 21 | children: PropTypes.node, 22 | }; 23 | -------------------------------------------------------------------------------- /client/src/Dashboard/hooks/index.js: -------------------------------------------------------------------------------- 1 | export * from "./useRouteName"; 2 | -------------------------------------------------------------------------------- /client/src/Dashboard/hooks/useRouteName.js: -------------------------------------------------------------------------------- 1 | import routes from '../routes'; 2 | 3 | export const useRouteName = () => { 4 | let name = ''; 5 | routes.forEach((route) => { 6 | if (window.location.href.indexOf(route.layout + route.path) !== -1) { 7 | name = routes.rtlActive ? route.rtlName : route.name; 8 | } 9 | }); 10 | return name; 11 | }; 12 | -------------------------------------------------------------------------------- /client/src/Dashboard/layouts/Admin.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Switch, Route, Redirect } from 'react-router-dom'; 3 | // creates a beautiful scrollbar 4 | import PerfectScrollbar from 'perfect-scrollbar'; 5 | import 'perfect-scrollbar/css/perfect-scrollbar.css'; 6 | // @material-ui/core components 7 | import { makeStyles } from '@material-ui/core/styles'; 8 | // core components 9 | import Navbar from '../components/Navbars/Navbar.js'; 10 | import Footer from '../components/Footer/Footer.js'; 11 | import Sidebar from '../components/Sidebar/Sidebar.js'; 12 | 13 | import routes from '../routes'; 14 | 15 | import styles from '../assets/jss/material-dashboard-react/layouts/adminStyle.js'; 16 | 17 | import bgImage from '../assets/img/sidebar-2.jpg'; 18 | import logo from '../assets/img/reactlogo.png'; 19 | 20 | let ps; 21 | 22 | const switchRoutes = ( 23 | 24 | {routes.map((prop, key) => { 25 | if (prop.layout === '/admin') { 26 | return ( 27 | 32 | ); 33 | } 34 | return null; 35 | })} 36 | 37 | 38 | ); 39 | 40 | const useStyles = makeStyles(styles); 41 | 42 | export default function Admin({ ...rest }) { 43 | // styles 44 | const classes = useStyles(); 45 | // ref to help us initialize PerfectScrollbar on windows devices 46 | const mainPanel = React.createRef(); 47 | // states and functions 48 | const [image, setImage] = React.useState(bgImage); 49 | const [color, setColor] = React.useState('blue'); 50 | const [fixedClasses, setFixedClasses] = React.useState('dropdown show'); 51 | const [mobileOpen, setMobileOpen] = React.useState(false); 52 | const handleImageClick = (image) => { 53 | setImage(image); 54 | }; 55 | const handleColorClick = (color) => { 56 | setColor(color); 57 | }; 58 | const handleFixedClick = () => { 59 | if (fixedClasses === 'dropdown') { 60 | setFixedClasses('dropdown show'); 61 | } else { 62 | setFixedClasses('dropdown'); 63 | } 64 | }; 65 | const handleDrawerToggle = () => { 66 | setMobileOpen(!mobileOpen); 67 | }; 68 | const getRoute = () => { 69 | return window.location.pathname !== '/admin/maps'; 70 | }; 71 | const resizeFunction = () => { 72 | if (window.innerWidth >= 960) { 73 | setMobileOpen(false); 74 | } 75 | }; 76 | // initialize and destroy the PerfectScrollbar plugin 77 | React.useEffect(() => { 78 | if (navigator.platform.indexOf('Win') > -1) { 79 | ps = new PerfectScrollbar(mainPanel.current, { 80 | suppressScrollX: true, 81 | suppressScrollY: false, 82 | }); 83 | document.body.style.overflow = 'hidden'; 84 | } 85 | window.addEventListener('resize', resizeFunction); 86 | // Specify how to clean up after this effect: 87 | return function cleanup() { 88 | if (navigator.platform.indexOf('Win') > -1) { 89 | ps.destroy(); 90 | } 91 | window.removeEventListener('resize', resizeFunction); 92 | }; 93 | }, [mainPanel]); 94 | return ( 95 |
96 | 106 |
107 | 112 | {/* On the /maps route we want the map to be on full screen - this is not possible if the content and conatiner classes are present because they have some paddings which would make the map smaller */} 113 | {getRoute() ? ( 114 |
115 |
{switchRoutes}
116 |
117 | ) : ( 118 |
{switchRoutes}
119 | )} 120 | {getRoute() ?
: null} 121 |
122 |
123 | ); 124 | } 125 | -------------------------------------------------------------------------------- /client/src/Dashboard/routes.js: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | ========================================================= 4 | * Material Dashboard React - v1.10.0 5 | ========================================================= 6 | 7 | * Product Page: https://www.creative-tim.com/product/material-dashboard-react 8 | * Copyright 2021 Creative Tim (https://www.creative-tim.com) 9 | * Licensed under MIT (https://github.com/creativetimofficial/material-dashboard-react/blob/master/LICENSE.md) 10 | 11 | * Coded by Creative Tim 12 | 13 | ========================================================= 14 | 15 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 16 | 17 | */ 18 | // @material-ui/icons 19 | import Dashboard from '@material-ui/icons/Dashboard'; 20 | import Person from '@material-ui/icons/Person'; 21 | import LibraryBooks from '@material-ui/icons/LibraryBooks'; 22 | import CallSplit from '@material-ui/icons/CallSplit'; 23 | 24 | // core components/views for Admin layout 25 | import DashboardPage from './views/Dashboard/Dashboard.js'; 26 | import UserProfile from './views/UserProfile/UserProfile.js'; 27 | 28 | import Logs from './views/Logs/Logs'; 29 | import APIGateway from './views/APIGateway/APIGateway.js'; 30 | // core components/views for RTL layout 31 | 32 | const dashboardRoutes = [ 33 | { 34 | path: '/dashboard', 35 | name: 'AWS Lambda Metrics', 36 | icon: Dashboard, 37 | component: DashboardPage, 38 | layout: '/admin', 39 | }, 40 | { 41 | path: '/logs', 42 | name: 'Logs', 43 | icon: LibraryBooks, 44 | component: Logs, 45 | layout: '/admin', 46 | }, 47 | { 48 | path: '/apiGateway', 49 | name: 'API Gateway', 50 | icon: CallSplit, 51 | component: APIGateway, 52 | layout: '/admin', 53 | }, 54 | { 55 | path: '/user', 56 | name: 'User Profile', 57 | icon: Person, 58 | component: UserProfile, 59 | layout: '/admin', 60 | }, 61 | ]; 62 | 63 | export default dashboardRoutes; 64 | -------------------------------------------------------------------------------- /client/src/Dashboard/variables/metricAllFuncBarChart.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | // ############################## 4 | // Function : 5 | // Fetch AWS Lambda Metrics (Totals) 6 | // Update the AWS Reducers 7 | // 8 | // ############################# 9 | 10 | const metricAllFuncBarChart = (props, timePeriod, region) => { 11 | 12 | const reqParams = { 13 | method: 'POST', 14 | headers: { 'Content-Type': 'application/json' }, 15 | body: JSON.stringify({ 16 | credentials: props.credentials, 17 | timePeriod: timePeriod, 18 | region: region, 19 | }), 20 | }; 21 | 22 | props.addLambda(reqParams); 23 | 24 | //Invocations 25 | //********************************************************* */ 26 | fetch('/aws/getMetricsAllfunc/Invocations', reqParams) 27 | .then((res) => res.json()) 28 | .then((invocationData) => { 29 | props.addInvocationsAlldata(invocationData); 30 | }) 31 | .catch((err) => console.error(err)); 32 | 33 | //Errors 34 | //********************************************************* */ 35 | fetch('/aws/getMetricsAllfunc/Errors', reqParams) 36 | .then((res) => res.json()) 37 | .then((errorData) => { 38 | props.addErrorsAlldata(errorData); 39 | }) 40 | .catch((err) => console.error(err)); 41 | 42 | //Throttles 43 | //********************************************************* */ 44 | 45 | fetch('/aws/getMetricsAllfunc/Throttles', reqParams) 46 | .then((res) => res.json()) 47 | .then((throttleData) => { 48 | props.addThrottlesAlldata(throttleData); 49 | 50 | props.updateFetchTime(); 51 | }) 52 | .catch((err) => console.error(err)); 53 | }; 54 | 55 | export default metricAllFuncBarChart; 56 | -------------------------------------------------------------------------------- /client/src/Dashboard/variables/metricByFuncBarChart.js: -------------------------------------------------------------------------------- 1 | // ############################## 2 | // Function : 3 | // Fetch AWS Lambda Metrics By Function 4 | // Update the AWS Reducers by Function 5 | // 6 | // ############################# 7 | 8 | const metricByFuncBarChart = (props, timePeriod, region) => { 9 | 10 | const reqParams = { 11 | method: 'POST', 12 | headers: { 'Content-Type': 'application/json' }, 13 | body: JSON.stringify({ 14 | credentials: props.credentials, 15 | timePeriod: timePeriod, 16 | funcNames: props.aws.functions, 17 | region: region, 18 | 19 | }), 20 | }; 21 | 22 | //Invocations 23 | //********************************************************* */ 24 | fetch('/aws/getMetricsByFunc/Invocations', reqParams) 25 | .then((res) => res.json()) 26 | .then((invocationData) => { 27 | props.addInvocationsByFuncData(invocationData); 28 | }) 29 | .catch((err) => console.error(err)); 30 | 31 | //Errors 32 | //********************************************************* */ 33 | fetch('/aws/getMetricsByFunc/Errors', reqParams) 34 | .then((res) => res.json()) 35 | .then((errorData) => { 36 | props.addErrorsByFuncData(errorData); 37 | }) 38 | .catch((err) => console.error(err)); 39 | 40 | // //Throttles 41 | // //********************************************************* */ 42 | 43 | fetch('/aws/getMetricsByFunc/Throttles', reqParams) 44 | .then((res) => res.json()) 45 | .then((throttleData) => { 46 | props.addThrottlesByFuncData(throttleData); 47 | }) 48 | .catch((err) => console.error(err)); 49 | }; 50 | 51 | export default metricByFuncBarChart; 52 | -------------------------------------------------------------------------------- /client/src/Dashboard/variables/regions.js: -------------------------------------------------------------------------------- 1 | // allow the region's actual name to be displayed 2 | const regions = { 3 | 'us-east-2': 'US East (Ohio)', 4 | 'us-east-1': 'US East (N. Virginia)', 5 | 'us-west-1': 'US West (N. California)', 6 | 'us-west-2': 'US West (Oregon)', 7 | 'af-south-1': 'Africa (Cape Town)', 8 | 'ap-east-1': 'Asia Pacific (Hong Kong)', 9 | 'ap-south-1': 'Asia Pacific (Mumbai)', 10 | 'ap-northeast-3': 'Asia Pacific (Osaka)', 11 | 'ap-northeast-2': 'Asia Pacific (Seoul)', 12 | 'ap-southeast-1': 'Asia Pacific (Singapore)', 13 | 'ap-southeast-2': 'Asia Pacific (Sydney)', 14 | 'ap-northeast-1': 'Asia Pacific (Tokyo)', 15 | 'ca-central-1': 'Canada (Central)', 16 | 'eu-central-1': 'Europe (Frankfurt)', 17 | 'eu-west-1': 'Europe (Ireland)', 18 | 'eu-west-2': 'Europe (London)', 19 | 'eu-south-1': 'Europe (Milan)', 20 | 'eu-west-3': 'Europe (Paris)', 21 | 'eu-north-1': 'Europe (Stockholm)', 22 | 'me-south-1': 'Middle East (Bahrain)', 23 | 'sa-east-1': 'South America (São Paulo)', 24 | 'us-gov-east-1': 'AWS GovCloud (US-East)', 25 | 'us-gov-west-1': 'AWS GovCloud (US-West)', 26 | }; 27 | 28 | module.exports = { regions }; 29 | -------------------------------------------------------------------------------- /client/src/Dashboard/variables/spinner.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { usePromiseTracker } from 'react-promise-tracker'; 3 | import Loader from 'react-loader-spinner'; 4 | 5 | export const Spinner = (props) => { 6 | const { promiseInProgress } = usePromiseTracker(); 7 | 8 | return ( 9 |
10 | 11 |
12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /client/src/Dashboard/views/TableList/LambdaMetrics.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { DataGrid } from '@material-ui/data-grid'; 3 | 4 | const columns = [ 5 | { field: 'id', headerName: 'ID', width: 90, hide: true }, 6 | { 7 | field: 'functionName', 8 | headerName: 'Lambda Function Name', 9 | width: 250, 10 | editable: true, 11 | }, 12 | { 13 | field: 'throttles', 14 | headerName: 'Throttles', 15 | type: 'number', 16 | width: 150, 17 | editable: true, 18 | }, 19 | { 20 | field: 'invocations', 21 | headerName: 'Invocations', 22 | type: 'number', 23 | width: 150, 24 | editable: true, 25 | }, 26 | { 27 | field: 'errors', 28 | headerName: 'Errors', 29 | type: 'number', 30 | width: 150, 31 | editable: true, 32 | }, 33 | ]; 34 | 35 | export default function DataTable(props) { 36 | let rows = []; 37 | 38 | let invocationsArr = props.invocations.series.map( 39 | (funcData) => funcData.total 40 | ); 41 | let throttlesArr = props.throttles.series.map((funcData) => funcData.total); 42 | let errorsArr = props.errors.series.map((funcData) => funcData.total); 43 | 44 | props.funcNames.forEach((func, index) => { 45 | let rowData = { 46 | id: index, 47 | functionName: func, 48 | invocations: invocationsArr[index], 49 | throttles: throttlesArr[index], 50 | errors: errorsArr[index], 51 | }; 52 | rows.push(rowData); 53 | }); 54 | 55 | return ( 56 |
57 | 63 |
64 | ); 65 | } 66 | -------------------------------------------------------------------------------- /client/src/Pages/login.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useState } from 'react'; 3 | import { useHistory, Link } from 'react-router-dom'; 4 | import { connect } from 'react-redux'; 5 | import Avatar from '@material-ui/core/Avatar'; 6 | import Button from '@material-ui/core/Button'; 7 | import CssBaseline from '@material-ui/core/CssBaseline'; 8 | import TextField from '@material-ui/core/TextField'; 9 | import logo from '../Dashboard/assets/img/helios-blue-logo-t.png'; 10 | import FormControlLabel from '@material-ui/core/FormControlLabel'; 11 | import Checkbox from '@material-ui/core/Checkbox'; 12 | // import Link from '@material-ui/core/Link'; 13 | import Grid from '@material-ui/core/Grid'; 14 | import Box from '@material-ui/core/Box'; 15 | import Typography from '@material-ui/core/Typography'; 16 | import { makeStyles } from '@material-ui/core/styles'; 17 | import Container from '@material-ui/core/Container'; 18 | // import { addLoginInfo } from '../Actions/actions'; 19 | import * as actions from '../Actions/actions'; 20 | import updateUserInfoIDB from '../indexedDB/updateUserInfoIDB'; 21 | import updateArnIDB from '../indexedDB/updateArnIDB'; 22 | import updateRegionIDB from '../indexedDB/updateRegionIDB'; 23 | 24 | function Copyright() { 25 | return ( 26 | 27 | {'Copyright © '} 28 | 29 | Helios 30 | 31 | {' ' + new Date().getFullYear()} 32 | {'.'} 33 | 34 | ); 35 | } 36 | 37 | const useStyles = makeStyles((theme) => ({ 38 | paper: { 39 | marginTop: theme.spacing(8), 40 | display: 'flex', 41 | flexDirection: 'column', 42 | alignItems: 'center', 43 | }, 44 | logoImg: { 45 | width: '410px', 46 | }, 47 | avatar: { 48 | margin: theme.spacing(1), 49 | backgroundColor: theme.palette.secondary.main, 50 | }, 51 | form: { 52 | width: '100%', // Fix IE 11 issue. 53 | marginTop: theme.spacing(1), 54 | }, 55 | submit: { 56 | margin: theme.spacing(3, 0, 2), 57 | backgroundColor: '#2A3C4A', 58 | color: '#FFFFFF', 59 | }, 60 | pageText: { 61 | color: '#2A3C4A', 62 | }, 63 | })); 64 | 65 | const mapDispatchToProps = (dispatch) => ({ 66 | addLoginInfo: (userInfo) => dispatch(actions.addLoginInfo(userInfo)), 67 | }); 68 | 69 | function SignIn(props) { 70 | const classes = useStyles(); 71 | const history = useHistory(); 72 | const [unconfirmed, setConfirmed] = useState(false); 73 | const [email, setEmail] = useState(''); 74 | const [password, setPassword] = useState(''); 75 | 76 | // handles login request 77 | // makes sure password matches provided email and then adds details to state + IndexedDB and pushes them to the dashboard 78 | function handleSubmit() { 79 | const reqParams = { 80 | method: 'POST', 81 | headers: { 'Content-Type': 'application/json' }, 82 | body: JSON.stringify({ email, password }), 83 | }; 84 | 85 | fetch('/user/login', reqParams) 86 | .then((res) => res.json()) 87 | .then((confirmation) => { 88 | if (confirmation.confirmed) { 89 | props.addLoginInfo(confirmation.userInfo); 90 | 91 | const { firstName, email, arn, region } = confirmation.userInfo; 92 | 93 | updateArnIDB({ arn }).catch((error) => { 94 | console.error('error while updating login arn', error); 95 | }); 96 | 97 | updateUserInfoIDB({ firstName, email }).catch((error) => { 98 | console.error('error while updating login user info', error); 99 | }); 100 | 101 | updateRegionIDB({ region }).catch((error) => { 102 | console.error('error while updating region info', error); 103 | }); 104 | history.push('/admin'); 105 | } else { 106 | setConfirmed(true); 107 | password.value = ''; 108 | email.value = ''; 109 | } 110 | }); 111 | } 112 | 113 | return ( 114 | 115 | 116 |
117 | Helios Logo 118 | 119 | 120 | Sign in 121 | 122 | {unconfirmed && ( 123 | 124 | Please double-check your email and/or password or create a new 125 | account. 126 | 127 | )} 128 | { 140 | setEmail(e.target.value); 141 | }} 142 | /> 143 | { 155 | setPassword(e.target.value); 156 | }} 157 | /> 158 | 167 | 168 | 169 | 174 | Forgot password? 175 | 176 | 177 | 178 | 183 | {"Don't have an account? Sign Up"} 184 | 185 | 186 | 187 |
188 | 189 | 190 | 191 |
192 | ); 193 | } 194 | 195 | export default connect(null, mapDispatchToProps)(SignIn); 196 | -------------------------------------------------------------------------------- /client/src/Reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import mainReducer from './mainReducer.js'; 3 | import awsReducer from './awsReducer'; 4 | import awsReducerByFunc from './awsReducerbyFunc' 5 | import apiReducer from './apiReducer.js'; 6 | 7 | const reducers = combineReducers({ 8 | main: mainReducer, 9 | aws: awsReducer, 10 | awsByFunc: awsReducerByFunc, 11 | api: apiReducer, 12 | }); 13 | 14 | export default reducers; 15 | -------------------------------------------------------------------------------- /client/src/Reducers/mainReducer.js: -------------------------------------------------------------------------------- 1 | import * as types from '../Constants/actionTypes'; 2 | 3 | const initialState = { 4 | email: '', 5 | firstName: '', 6 | arn: '', 7 | region: '', 8 | credentials: null, 9 | credentialsLoading: false, 10 | }; 11 | 12 | const mainReducer = (state = initialState, action) => { 13 | let email; 14 | let firstName; 15 | let arn; 16 | let credentials; 17 | let region; 18 | let credentialsLoading; 19 | 20 | switch (action.type) { 21 | // after signup adds new user's email and firstName to state 22 | case types.ADD_USER_INFO: { 23 | email = action.payload.email; 24 | firstName = action.payload.firstName; 25 | return { 26 | ...state, 27 | email, 28 | firstName, 29 | }; 30 | } 31 | 32 | // after registration page, adds details to state 33 | case types.ADD_AWS_ACCOUNT: { 34 | arn = action.payload.arn; 35 | region = action.payload.region; 36 | return { 37 | ...state, 38 | arn, 39 | region, 40 | }; 41 | } 42 | 43 | // if region is reset on User Profile page, updaes region in state 44 | case types.ADD_REGION: { 45 | region = action.payload; 46 | return { 47 | ...state, 48 | region, 49 | }; 50 | } 51 | 52 | // after login verification, adds user details to state 53 | case types.ADD_LOGIN_INFO: { 54 | email = action.payload.email; 55 | firstName = action.payload.firstName; 56 | arn = action.payload.arn; 57 | region = action.payload.region; 58 | return { 59 | email, 60 | firstName, 61 | arn, 62 | region, 63 | }; 64 | } 65 | 66 | // after refreshes, adds AWS credentials to state 67 | case types.ADD_CREDENTIALS: { 68 | credentials = action.payload; 69 | credentialsLoading = false; 70 | return { 71 | ...state, 72 | credentials, 73 | credentialsLoading, 74 | }; 75 | } 76 | 77 | // signals the promise for fetching credentials has started 78 | case types.ADD_CREDENTIALS_STARTED: { 79 | credentialsLoading = true; 80 | return { 81 | ...state, 82 | credentialsLoading, 83 | }; 84 | } 85 | 86 | // if logout is clicked, resets state 87 | case types.HANDLE_LOGOUT: { 88 | return { 89 | ...initialState, 90 | }; 91 | } 92 | 93 | // if email is updated on User Profile page, updates it in state too 94 | case types.UPDATE_EMAIL: { 95 | email = action.payload; 96 | return { 97 | ...state, 98 | email, 99 | }; 100 | } 101 | 102 | // if ARN is updated on User Profile page, updates it in state too 103 | case types.UPDATE_ARN: { 104 | arn = action.payload; 105 | return { 106 | ...state, 107 | arn, 108 | }; 109 | } 110 | 111 | // if a refresh happens, re-adds name to state 112 | case types.UPDATE_NAME: { 113 | firstName = action.payload; 114 | return { 115 | ...state, 116 | firstName, 117 | }; 118 | } 119 | 120 | // if refresh happens, readds details to state 121 | case types.UPDATE_USER_DETAILS_AFTER_PROFILE_UPDATE: { 122 | email = action.payload.email; 123 | firstName = action.payload.firstName; 124 | arn = action.payload.arn; 125 | return { 126 | ...state, 127 | email, 128 | firstName, 129 | arn, 130 | }; 131 | } 132 | 133 | default: { 134 | return state; 135 | } 136 | } 137 | }; 138 | 139 | export default mainReducer; 140 | -------------------------------------------------------------------------------- /client/src/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { render } from 'react-dom'; 3 | import { Provider } from 'react-redux'; 4 | import App from './App.jsx'; 5 | import store from './store.js'; 6 | import './indexedDB/mainIdb'; 7 | 8 | import './Dashboard/assets/css/material-dashboard-react.css'; 9 | import './Dashboard/assets/scss/chart_legend.scss'; 10 | //import 'assets/css/material-dashboard-react.scss'; 11 | 12 | render( 13 | 14 | 15 | , 16 | document.getElementById('root') 17 | ); 18 | -------------------------------------------------------------------------------- /client/src/indexedDB/clearIDB.js: -------------------------------------------------------------------------------- 1 | import db from './mainIdb'; 2 | 3 | async function clearIDB() { 4 | await db.arnRegistry.clear().catch((error) => { 5 | console.error('error deleting existing arn from storage', error); 6 | throw error; 7 | }); 8 | await db.accountRegion.clear().catch((error) => { 9 | console.error('error deleting existing region from storage', error); 10 | throw error; 11 | }); 12 | await db.userInfo.clear().catch((error) => { 13 | console.error('error deleting existing userInfo from storage', error); 14 | throw error; 15 | }); 16 | } 17 | 18 | export default clearIDB; 19 | -------------------------------------------------------------------------------- /client/src/indexedDB/getArnArrayIDB.js: -------------------------------------------------------------------------------- 1 | import db from './mainIdb'; 2 | 3 | function getArnArrayIDB() { 4 | return db.arnRegistry.toArray().catch((error) => { 5 | console.error('error while getting ARNs', error); 6 | throw error; 7 | }); 8 | } 9 | 10 | export default getArnArrayIDB; 11 | -------------------------------------------------------------------------------- /client/src/indexedDB/getRegionIDB.js: -------------------------------------------------------------------------------- 1 | import db from './mainIdb'; 2 | 3 | function getRegionIDB() { 4 | return db.accountRegion.toArray().catch((error) => { 5 | console.error('error while getting ARNs', error); 6 | throw error; 7 | }); 8 | } 9 | 10 | export default getRegionIDB; 11 | -------------------------------------------------------------------------------- /client/src/indexedDB/getUserInfo.js: -------------------------------------------------------------------------------- 1 | import db from './mainIdb'; 2 | 3 | function getUserInfoArrayIDB() { 4 | return db.userInfo.toArray().catch((error) => { 5 | console.error('error while getting ARNs', error); 6 | throw error; 7 | }); 8 | } 9 | 10 | export default getUserInfoArrayIDB; 11 | -------------------------------------------------------------------------------- /client/src/indexedDB/mainIdb.js: -------------------------------------------------------------------------------- 1 | import Dexie from 'dexie'; 2 | 3 | let db = new Dexie('Helios'); 4 | 5 | db.version(1).stores({ 6 | userInfo: '++id, firstName, email', 7 | arnRegistry: '++id, arn', 8 | accountRegion: '++id, region', 9 | }); 10 | 11 | db.open().catch(function (e) { 12 | console.error('error' + e); 13 | }); 14 | 15 | export default db; 16 | -------------------------------------------------------------------------------- /client/src/indexedDB/updateArnIDB.js: -------------------------------------------------------------------------------- 1 | import db from './mainIdb'; 2 | 3 | async function updateArnIDB({ arn }) { 4 | await db.arnRegistry.clear().catch((error) => { 5 | console.error('error deleting existing arn from storage', error); 6 | throw error; 7 | }); 8 | 9 | return db.arnRegistry.put({ arn }); 10 | } 11 | 12 | export default updateArnIDB; 13 | -------------------------------------------------------------------------------- /client/src/indexedDB/updateRegionIDB.js: -------------------------------------------------------------------------------- 1 | import db from './mainIdb'; 2 | 3 | async function updateRegionIDB({ region }) { 4 | await db.accountRegion.clear().catch((error) => { 5 | console.error('error deleting existing region from storage', error); 6 | throw error; 7 | }); 8 | return db.accountRegion.put({ region }); 9 | } 10 | 11 | export default updateRegionIDB; 12 | -------------------------------------------------------------------------------- /client/src/indexedDB/updateUserInfoIDB.js: -------------------------------------------------------------------------------- 1 | import db from "./mainIdb"; 2 | 3 | async function updateUserInfoIDB({ firstName, email }) { 4 | await db.userInfo.clear().catch((error) => { 5 | console.error("error deleting existing userInfo from storage", error); 6 | throw error; 7 | }); 8 | 9 | return db.userInfo.put({ firstName, email }); 10 | } 11 | 12 | export default updateUserInfoIDB; 13 | -------------------------------------------------------------------------------- /client/src/store.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose } from 'redux'; 2 | import { composeWithDevTools } from 'redux-devtools-extension'; 3 | import reducers from './Reducers/index.js'; 4 | import thunk from 'redux-thunk'; 5 | 6 | const composedEnhancer = composeWithDevTools(applyMiddleware(thunk)); 7 | 8 | const store = createStore(reducers, composedEnhancer); 9 | 10 | export default store; 11 | -------------------------------------------------------------------------------- /jest-setup.js: -------------------------------------------------------------------------------- 1 | import 'regenerator-runtime/runtime'; 2 | module.exports = async () => { 3 | global.testServer = await require('./server/server'); 4 | }; 5 | -------------------------------------------------------------------------------- /jest-teardown.js: -------------------------------------------------------------------------------- 1 | import 'regenerator-runtime/runtime'; 2 | 3 | module.exports = async (globalConfig) => { 4 | await testServer.close(); 5 | }; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Helios", 3 | "version": "1.0.0", 4 | "description": "An affordable and easy-to-use monitoring tool for your AWS serverless applications.", 5 | "main": "public/electron.js", 6 | "homepage": "./", 7 | "jest": { 8 | "testEnvironment": "jsdom", 9 | "setupFiles": [ 10 | "fake-indexeddb/auto" 11 | ], 12 | "moduleNameMapper": { 13 | "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/__tests__/__mocks__/fileMock.js", 14 | "\\.(css|less)$": "/__tests__/__mocks__/styleMock.js" 15 | }, 16 | "testPathIgnorePatterns": [ 17 | "/__tests__/__mocks__/styleMock.js", 18 | "/__tests__/__mocks__/fileMock.js" 19 | ], 20 | "verbose": true, 21 | "transformIgnorePatterns": [ 22 | "/node_modules/(?!test-component).+\\.js$" 23 | ] 24 | }, 25 | "scripts": { 26 | "test": "jest", 27 | "build": "NODE_ENV=production webpack", 28 | "start": "cross-env NODE_ENV=production electron .", 29 | "dev": "cross-env NODE_ENV=development concurrently \"NODE_ENV=development webpack serve --open\" \"NODE_ENV=development nodemon server/server.js\"", 30 | "electron:serve": "concurrently -k \"cross-env BROWSER=none yarn run dev\" \"yarn electron:start\"", 31 | "electron:build": "", 32 | "electron:start": "wait-on tcp:8080 && electron .", 33 | "pack": "electron-builder --dir", 34 | "dist": "electron-builder" 35 | }, 36 | "build": { 37 | "appId": "helios.v.1", 38 | "mac": { 39 | "category": "public.app-category.developer-tools", 40 | "icon": "client/src/Dashboard/assets/img/new-app-logo.png", 41 | "asar": false 42 | }, 43 | "files": [ 44 | "build/**/*", 45 | "dist/**/*", 46 | "node_modules/**/*", 47 | "package.json", 48 | "public/**/*", 49 | "server/**/*" 50 | ], 51 | "extends": null 52 | }, 53 | "nodemonConfig": { 54 | "ignore": [ 55 | "build", 56 | "src" 57 | ] 58 | }, 59 | "author": "Jackie Douglass, Prasad Pulaguntla, and Thein Gi Deva", 60 | "license": "MIT", 61 | "dependencies": { 62 | "@aws-sdk/client-api-gateway": "^3.23.0", 63 | "@aws-sdk/client-cloudwatch": "^3.22.0", 64 | "@aws-sdk/client-cloudwatch-logs": "^3.22.0", 65 | "@aws-sdk/client-dynamodb": "^3.21.0", 66 | "@aws-sdk/client-lambda": "^3.21.0", 67 | "@aws-sdk/client-sts": "^3.21.0", 68 | "@aws-sdk/credential-provider-ini": "^3.20.0", 69 | "@aws-sdk/credential-provider-node": "^3.21.0", 70 | "@aws-sdk/types": "^3.20.0", 71 | "@babel/core": "^7.14.8", 72 | "@babel/plugin-transform-async-to-generator": "^7.14.5", 73 | "@babel/plugin-transform-runtime": "^7.14.5", 74 | "@babel/preset-env": "^7.14.7", 75 | "@babel/preset-react": "^7.14.5", 76 | "@babel/runtime": "^7.14.8", 77 | "@electron/remote": "^1.2.0", 78 | "@material-ui/core": "^4.12.1", 79 | "@material-ui/data-grid": "^4.0.0-alpha.34", 80 | "@material-ui/icons": "^4.11.2", 81 | "babel-core": "^6.26.3", 82 | "babel-jest": "^27.0.6", 83 | "babel-loader": "^8.2.2", 84 | "babel-polyfill": "^6.26.0", 85 | "bcryptjs": "^2.4.3", 86 | "chartist": "^0.11.4", 87 | "chartist-plugin-tooltip": "0.0.11", 88 | "chartist-plugin-tooltips": "^0.0.17", 89 | "chartist-plugin-tooltips-updated": "^0.1.4", 90 | "classnames": "^2.3.1", 91 | "concurrently": "^6.2.0", 92 | "cross-env": "^7.0.3", 93 | "css-loader": "^6.0.0", 94 | "dexie": "^3.2.0-beta-2", 95 | "dexie-export-import": "^1.0.3", 96 | "dexie-observable": "^3.0.0-beta.11", 97 | "dexie-react-hooks": "^1.0.7", 98 | "dotenv": "^8.2.0", 99 | "enzyme": "^3.11.0", 100 | "enzyme-adapter-react-16": "^1.15.6", 101 | "enzyme-to-json": "^3.6.2", 102 | "express": "^4.17.1", 103 | "image-minimizer-webpack-plugin": "^2.2.0", 104 | "jest": "^26.6.3", 105 | "moment": "^2.29.1", 106 | "mongodb": "^4.0.0", 107 | "mongoose": "^5.13.3", 108 | "node-sass": "^6.0.1", 109 | "nodemailer": "^6.6.3", 110 | "nodemon": "^2.0.11", 111 | "perfect-scrollbar": "^1.5.1", 112 | "prop-types": "^15.7.2", 113 | "react": "^17.0.2", 114 | "react-chartist": "^0.14.4", 115 | "react-dom": "^17.0.2", 116 | "react-loader-spinner": "^4.0.0", 117 | "react-promise-tracker": "^2.1.0", 118 | "react-redux": "^7.2.4", 119 | "react-router": "^5.2.0", 120 | "react-router-dom": "^5.2.0", 121 | "react-scripts": "^4.0.3", 122 | "react-swipeable-views": "^0.14.0", 123 | "react-test-renderer": "^17.0.2", 124 | "redux": "^4.1.0", 125 | "redux-devtools-extension": "^2.13.9", 126 | "redux-mock-store": "^1.5.4", 127 | "redux-thunk": "^2.3.0", 128 | "sass-loader": "^12.1.0", 129 | "stream-to-blob": "^2.0.1", 130 | "style-loader": "^3.1.0", 131 | "url-loader": "^4.1.1", 132 | "wait-on": "^6.0.0", 133 | "webpack": "^5.44.0", 134 | "webpack-cli": "^4.7.2" 135 | }, 136 | "devDependencies": { 137 | "babel-loader": "^8.2.2", 138 | "electron": "^13.1.7", 139 | "electron-builder": "^22.11.7", 140 | "electron-notarize": "^1.0.1", 141 | "fake-indexeddb": "^3.1.3", 142 | "file-loader": "^6.2.0", 143 | "imagemin-gifsicle": "^7.0.0", 144 | "imagemin-jpegtran": "^7.0.0", 145 | "imagemin-optipng": "^8.0.0", 146 | "imagemin-svgo": "^9.0.0", 147 | "webpack-dev-server": "^3.11.2" 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /public/electron.js: -------------------------------------------------------------------------------- 1 | const { app, BrowserWindow, protocol } = require('electron'); 2 | require('../server/server.js'); 3 | require('@electron/remote/main').initialize(); 4 | 5 | let mainWindow; 6 | 7 | function createWindow() { 8 | mainWindow = new BrowserWindow({ 9 | width: 1400, 10 | height: 1200, 11 | title: 'Helios', 12 | webPreferences: { 13 | nodeIntegration: true, 14 | nodeIntegrationInWorker: true, 15 | enableRemoteModule: true, 16 | worldSafeExecuteJavaScript: true, 17 | contextIsolation: true, 18 | // webSecurity: false, 19 | }, 20 | }); 21 | 22 | mainWindow.loadURL('http://localhost:4242'); 23 | } 24 | 25 | app.on('ready', () => { 26 | createWindow(); 27 | }); 28 | 29 | app.on('window-all-closed', function () { 30 | if (process.platform !== 'darwin') { 31 | app.quit(); 32 | } 33 | }); 34 | 35 | app.on('activate', function () { 36 | if (BrowserWindow.getAllWindows().length === 0) createWindow(); 37 | }); 38 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Helios 8 | 12 | 16 | 17 | 18 | 22 | 26 | 30 | 31 | 32 |
33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /public/updatedCloudformationHelios.yaml: -------------------------------------------------------------------------------- 1 | Description: 'CloudFormation Stack for Delegating a Helios Role' 2 | Resources: 3 | HeliosDelegationRole: 4 | Type: 'AWS::IAM::Role' 5 | Properties: 6 | AssumeRolePolicyDocument: 7 | Version: 2012-10-17 8 | Statement: 9 | - Effect: Allow 10 | Principal: 11 | AWS: 12 | # change ARN to applicable AWS account 13 | - arn:aws:iam::176938549867:root 14 | Action: 15 | - 'sts:AssumeRole' 16 | Path: / 17 | RoleName: HeliosDelegationRole 18 | Policies: 19 | - PolicyName: Resources 20 | PolicyDocument: 21 | Version: 2012-10-17 22 | Statement: 23 | - Effect: Allow 24 | Action: 'apigateway:GET' 25 | Resource: '*' 26 | - Effect: Allow 27 | Action: 'apigateway:HEAD' 28 | Resource: '*' 29 | - Effect: Allow 30 | Action: 'apigateway:OPTIONS' 31 | Resource: '*' 32 | - Effect: Allow 33 | Action: 'appsync:get*' 34 | Resource: '*' 35 | - Effect: Allow 36 | Action: 'appsync:list*' 37 | Resource: '*' 38 | - Effect: Allow 39 | Action: 'batch:describe*' 40 | Resource: '*' 41 | - Effect: Allow 42 | Action: 'cloudformation:describe*' 43 | Resource: '*' 44 | - Effect: Allow 45 | Action: 'cloudformation:get*' 46 | Resource: '*' 47 | - Effect: Allow 48 | Action: 'cloudformation:list*' 49 | Resource: '*' 50 | - Effect: Allow 51 | Action: 'cloudfront:get*' 52 | Resource: '*' 53 | - Effect: Allow 54 | Action: 'cloudfront:list*' 55 | Resource: '*' 56 | - Effect: Allow 57 | Action: 'cloudwatch:describe*' 58 | Resource: '*' 59 | - Effect: Allow 60 | Action: 'cloudwatch:list*' 61 | Resource: '*' 62 | - Effect: Allow 63 | Action: 'dynamodb:describe*' 64 | Resource: '*' 65 | - Effect: Allow 66 | Action: 'dynamodb:list*' 67 | Resource: '*' 68 | - Effect: Allow 69 | Action: 'events:describe*' 70 | Resource: '*' 71 | - Effect: Allow 72 | Action: 'events:list*' 73 | Resource: '*' 74 | - Effect: Allow 75 | Action: 'lambda:listFunctions' 76 | Resource: '*' 77 | - Effect: Allow 78 | Action: 'lambda:listTags' 79 | Resource: '*' 80 | - Effect: Allow 81 | Action: 'rds:describe*' 82 | Resource: '*' 83 | - Effect: Allow 84 | Action: 'rds:list*' 85 | Resource: '*' 86 | - Effect: Allow 87 | Action: 'route53:list*' 88 | Resource: '*' 89 | - Effect: Allow 90 | Action: 'route53:get*' 91 | Resource: '*' 92 | - Effect: Allow 93 | Action: 's3:getBucket*' 94 | Resource: '*' 95 | - Effect: Allow 96 | Action: 's3:list*' 97 | Resource: '*' 98 | - Effect: Allow 99 | Action: 'sdb:domainMetadata' 100 | Resource: '*' 101 | - Effect: Allow 102 | Action: 'sdb:get*' 103 | Resource: '*' 104 | - Effect: Allow 105 | Action: 'sdb:list*' 106 | Resource: '*' 107 | - Effect: Allow 108 | Action: 'tag:get*' 109 | Resource: '*' 110 | - PolicyName: Logs 111 | PolicyDocument: 112 | Version: 2012-10-17 113 | Statement: 114 | - Effect: Allow 115 | Action: 'logs:deleteSubscriptionFilter' 116 | Resource: '*' 117 | - Effect: Allow 118 | Action: 'logs:describeLogStreams' 119 | Resource: '*' 120 | - Effect: Allow 121 | Action: 'logs:describeSubscriptionFilters' 122 | Resource: '*' 123 | - Effect: Allow 124 | Action: 'logs:filterLogEvents' 125 | Resource: '*' 126 | - Effect: Allow 127 | Action: 'logs:putSubscriptionFilter' 128 | Resource: '*' 129 | - Effect: Allow 130 | Action: 'logs:startQuery' 131 | Resource: '*' 132 | - Effect: Allow 133 | Action: 'logs:stopQuery' 134 | Resource: '*' 135 | - PolicyName: Metrics 136 | PolicyDocument: 137 | Version: 2012-10-17 138 | Statement: 139 | - Effect: Allow 140 | Action: 'cloudwatch:get*' 141 | Resource: '*' 142 | - PolicyName: Traces 143 | PolicyDocument: 144 | Version: 2012-10-17 145 | Statement: 146 | - Effect: Allow 147 | Action: 'xray:batch*' 148 | Resource: '*' 149 | - Effect: Allow 150 | Action: 'xray:get*' 151 | Resource: '*' 152 | 153 | Outputs: 154 | Version: 155 | Description: Helios CloudFormation Template 156 | Value: 2021-07-09 157 | HeliosRoleArn: 158 | Description: 'Helios ARN' 159 | Value: !GetAtt # name of role to be produced 160 | - HeliosDelegationRole 161 | - Arn 162 | -------------------------------------------------------------------------------- /server/Models/userModel.js: -------------------------------------------------------------------------------- 1 | const dotenv = require('dotenv'); 2 | const mongoose = require('mongoose'); 3 | const Schema = mongoose.Schema; 4 | 5 | dotenv.config(); 6 | 7 | const userName = process.env.MONGO_DB_USERNAME; 8 | const password = process.env.MONGO_DB_PASSWORD; 9 | const mongoDBName = process.env.MONGO_DB_NAME; 10 | const uriDomain = process.env.MONGO_URI_DOMAIN; 11 | 12 | const mongoURI = `mongodb+srv://${userName}:${password}@${uriDomain}/${mongoDBName}?retryWrites=true&w=majority`; 13 | 14 | mongoose 15 | .connect(mongoURI, { 16 | dbName: mongoDBName, 17 | useNewUrlParser: true, 18 | useUnifiedTopology: true, 19 | useFindAndModify: false, 20 | }) 21 | .then(() => console.log('Connected to MongoDB')) 22 | .catch((err) => console.error(err)); 23 | 24 | const SALT_WORK_FACTOR = 10; 25 | const bcrypt = require('bcryptjs'); 26 | 27 | // user model 28 | const userSchema = new Schema({ 29 | email: { type: String, required: true, unique: true }, 30 | password: { type: String, required: true }, 31 | firstName: { type: String, required: true }, 32 | lastName: { type: String, required: true }, 33 | arn: { type: String }, 34 | region: { type: String, default: 'us-east-2', required: true }, 35 | }); 36 | 37 | // hash the password before it's saved in database 38 | userSchema.pre('save', function (next) { 39 | const user = this; 40 | bcrypt.hash(user.password, SALT_WORK_FACTOR, function (err, hash) { 41 | if (err) console.error(err); 42 | user.password = hash; 43 | return next(); 44 | }); 45 | }); 46 | 47 | // the method to compare the hashed password with the one the user provided during login 48 | userSchema.methods.comparePassword = async function (potentialPass) { 49 | const user = this; 50 | return await bcrypt.compare(potentialPass, user.password); 51 | }; 52 | 53 | const User = mongoose.model('User', userSchema); 54 | 55 | // schema for resetting password 56 | const resetPasswordSchema = new Schema( 57 | { 58 | user: { type: Schema.Types.ObjectId, ref: 'User', required: true }, 59 | token: { type: String, required: true }, 60 | }, 61 | { timestamps: true } 62 | ); 63 | 64 | // it expires after ten minutes if they haven't continued with process 65 | resetPasswordSchema.index({ updatedAt: 1 }, { expireAfterSeconds: 600 }); 66 | 67 | const PasswordReset = mongoose.model('PasswordReset', resetPasswordSchema); 68 | 69 | module.exports = { User, PasswordReset }; 70 | -------------------------------------------------------------------------------- /server/controllers/aws/APIGateway/getAPI.js: -------------------------------------------------------------------------------- 1 | const { 2 | APIGatewayClient, 3 | GetRestApisCommand, 4 | GetResourcesCommand, 5 | GetIntegrationCommand, 6 | GetUsagePlansCommand, 7 | } = require('@aws-sdk/client-api-gateway'); 8 | 9 | const getAPIData = async (req, res, next) => { 10 | const client = new APIGatewayClient({ 11 | region: req.body.region, 12 | credentials: req.body.credentials, 13 | }); 14 | const apiData = []; 15 | // Retrieves list of Rest APIs and their names, i.e. 'Crypto' and 'WildRydes' plus their ids 16 | try { 17 | const restAPIs = await client.send(new GetRestApisCommand({})); 18 | // push each existing API, their ID, and an empty array to later store their resources to the apiData array which is what we'll send to frontend at the end 19 | restAPIs.items.forEach((api) => { 20 | apiObj = { name: api.name, apiId: api.id, resources: [] }; 21 | apiData.push(apiObj); 22 | }); 23 | 24 | // loop through the APIs and send a request to get each of their resources 25 | for (let i = 0; i < apiData.length; i += 1) { 26 | const resources = await client.send( 27 | new GetResourcesCommand({ restApiId: apiData[i].apiId }) 28 | ); 29 | // loop through array that AWS returns 30 | for (let j = 0; j < resources.items.length; j += 1) { 31 | // create object to store each resource's details on it 32 | const resourceEl = { 33 | resourceId: resources.items[j].id, 34 | path: resources.items[j].path, 35 | }; 36 | // create an array that holds the methods existing on the resource (e.g. GET, POST, OPTIONS) - needed for later request to AWS 37 | if (resources.items[j].resourceMethods) { 38 | resourceEl.methodsArr = Object.keys( 39 | resources.items[j].resourceMethods 40 | ); 41 | // if there are no methods on the resource, set it to undefined 42 | } else { 43 | resourceEl.methodsArr = undefined; 44 | } 45 | // push resources into the applicable resources array in apiData 46 | apiData[i].resources.push(resourceEl); 47 | } 48 | } 49 | 50 | // loop through apiData again 51 | for (let j = 0; j < apiData.length; j += 1) { 52 | const currApi = apiData[j]; 53 | // loop through resources that exist on specific API 54 | for (let k = 0; k < currApi.resources.length; k += 1) { 55 | const currResource = currApi.resources[k]; 56 | // if they have methods 57 | if (currResource.methodsArr) { 58 | currResource.methods = []; 59 | // loop through the existing methods 60 | for (let m = 0; m < currResource.methodsArr.length; m += 1) { 61 | const currHttpMethod = currResource.methodsArr[m]; 62 | // if it's not 'OPTIONS': 63 | if (currHttpMethod !== 'OPTIONS') { 64 | // request from AWS the details of what that method does 65 | // e.g. a POST request to a Lambda Function 66 | try { 67 | const integrationData = await client.send( 68 | new GetIntegrationCommand({ 69 | restApiId: currApi.apiId, 70 | resourceId: currResource.resourceId, 71 | httpMethod: currHttpMethod, 72 | }) 73 | ); 74 | // create object to store on methods array holding details about what the method does and where it drives to 75 | currMethodObj = { 76 | method: currHttpMethod, 77 | type: integrationData.type, 78 | }; 79 | if (integrationData.uri.includes('lambda')) { 80 | const cutString = integrationData.uri.slice( 81 | integrationData.uri.indexOf('function:') 82 | ); 83 | const lambdaFunc = cutString.slice(9).slice(0, -12); 84 | currMethodObj.service = 'Lambda'; 85 | currMethodObj.endPoint = lambdaFunc; 86 | } else if (integrationData.uri.includes('dynamodb')) { 87 | currMethodObj.service = 'DynamoDB'; 88 | } 89 | // push it onto the current method object (which exists within apiData) 90 | currResource.methods.push(currMethodObj); 91 | } catch (err) { 92 | console.error('Error after integration attempt: ', err.stack); 93 | } 94 | } 95 | } 96 | } 97 | // if OPTIONS was the only existing method and methods doesn't have any content, delete it to clean up for frontend 98 | if (!currResource.methods || currResource.methods.length === 0) { 99 | delete currResource.methods; 100 | } 101 | } 102 | } 103 | } catch (err) { 104 | console.error('Error after try/catch in getAPI.js: ', err); 105 | } 106 | // send to frontend 107 | res.locals.apiData = apiData; 108 | return next(); 109 | }; 110 | 111 | module.exports = getAPIData; 112 | -------------------------------------------------------------------------------- /server/controllers/aws/APIGateway/utils/APIUtilFunc.js: -------------------------------------------------------------------------------- 1 | //The following assumes that User Inputs the time timeRange (either in min, hours, days) 2 | 3 | //input time range period for aggregating the metrics 4 | //for e.g. if the time range selected on the front end is minutes, metrics from CloudWatch would be 5 | // aggregated by 1 minute (60 seconds) 6 | 7 | const timeRangePeriod = { 8 | minutes: 60, //60 seconds 9 | hours: 300, //300 secs 10 | days: 3600, // 1 hour 11 | }; 12 | 13 | //rouding parameters for defining the EndTime 14 | 15 | const timeRoundMultiplier = { 16 | minutes: 5, //the EndTime time stamps will be rounded to nearest 5 minutes 17 | hours: 15, //rounded to nearest 15 minutes 18 | days: 60, // rounded to nearest hour 19 | }; 20 | 21 | //to compute the startTime 22 | 23 | const timeRangeMultiplier = { 24 | minutes: 60, //the EndTime time stamps will be rounded to nearest 5 minutes 25 | hours: 3600, //rounded to nearest 15 minutes 26 | days: 86400, // rounded to nearest hour 27 | }; 28 | 29 | const APIUtilFunc = {}; 30 | 31 | APIUtilFunc.getAPIMetrics = ( 32 | timeRangeNum, 33 | timeRangeUnits, 34 | apiName, 35 | metricName, 36 | stat = 'Sum' 37 | ) => { 38 | const timeRound = timeRoundMultiplier[timeRangeUnits]; 39 | //define the End and Start times in UNIX time Stamp format for getMetricsData method 40 | //Rounded off to nearest timeRoundMultiplier 41 | const EndTime = 42 | Math.round(new Date().getTime() / 1000 / 60 / timeRound) * 60 * timeRound; //current time in Unix TimeStamp 43 | const StartTime = 44 | EndTime - timeRangeNum * timeRangeMultiplier[timeRangeUnits]; 45 | 46 | const period = timeRangePeriod[timeRangeUnits]; 47 | 48 | //initialize the parameters 49 | const metricParamsBaseAllFunc = { 50 | StartTime: new Date(StartTime * 1000), 51 | EndTime: new Date(EndTime * 1000), 52 | LabelOptions: { 53 | Timezone: '-0400', 54 | }, 55 | }; 56 | 57 | const metricDataQueryAllfunc = [ 58 | { 59 | Id: `m_API_Gateway_${metricName}`, 60 | Label: `${apiName} API ${metricName}`, 61 | MetricStat: { 62 | Metric: { 63 | Namespace: 'AWS/ApiGateway', 64 | MetricName: metricName, 65 | Dimensions: [{ Name: 'ApiName', Value: apiName }], 66 | }, 67 | Period: period, 68 | Stat: stat, 69 | }, 70 | }, 71 | ]; 72 | 73 | const metricParamsAllfunc = { 74 | ...metricParamsBaseAllFunc, 75 | MetricDataQueries: metricDataQueryAllfunc, 76 | }; 77 | 78 | return metricParamsAllfunc; 79 | }; 80 | 81 | module.exports = APIUtilFunc; 82 | -------------------------------------------------------------------------------- /server/controllers/aws/Credentials/getCreds.js: -------------------------------------------------------------------------------- 1 | // import { stsClient, REGION } from '../libs/stsClient.js'; 2 | const { stsClient } = require('./libs/stsClient.js'); 3 | const AWSUtilFunc = require('../Metrics/utils/AWSUtilFunc.js'); 4 | 5 | const { AssumeRoleCommand } = require('@aws-sdk/client-sts'); 6 | const { 7 | Lambda, 8 | LambdaClient, 9 | ListFunctionsCommand, 10 | } = require('@aws-sdk/client-lambda'); 11 | 12 | const { 13 | CloudWatchClient, 14 | GetMetricDataCommand, 15 | } = require('@aws-sdk/client-cloudwatch'); 16 | 17 | //Async Function to Assume role of the Client and pull metrics 18 | 19 | const getCredentials = async (req, res, next) => { 20 | const roleParams = { 21 | RoleArn: req.body.arn, 22 | RoleSessionName: 'HeliosSession', 23 | }; 24 | 25 | try { 26 | const assumedRole = await stsClient.send(new AssumeRoleCommand(roleParams)); 27 | const accessKeyId = assumedRole.Credentials.AccessKeyId; 28 | const secretAccessKey = assumedRole.Credentials.SecretAccessKey; 29 | const sessionToken = assumedRole.Credentials.SessionToken; 30 | res.locals.credentials = { accessKeyId, secretAccessKey, sessionToken }; 31 | return next(); 32 | } catch (err) { 33 | if (err) { 34 | console.error(err); 35 | return next(err); 36 | } 37 | } 38 | }; 39 | 40 | module.exports = getCredentials; 41 | -------------------------------------------------------------------------------- /server/controllers/aws/Credentials/libs/stsClient.js: -------------------------------------------------------------------------------- 1 | const dotenv = require('dotenv'); 2 | // const { fromIni } = require('@aws-sdk/credential-provider-ini'); 3 | const { STSClient } = require('@aws-sdk/client-sts'); 4 | 5 | dotenv.config(); 6 | 7 | // root user credentials 8 | const credentials = { 9 | accessKeyId: process.env.AWS_ACCESS_KEY_ID, 10 | secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, 11 | }; 12 | const region = process.env.AWS_REGION; 13 | 14 | // Create an Amazon CloudWatch Logs service client object. 15 | const stsClient = new STSClient({ 16 | region: region, 17 | credentials: credentials, 18 | }); 19 | 20 | module.exports = { 21 | stsClient, 22 | }; 23 | -------------------------------------------------------------------------------- /server/controllers/aws/Metrics/getLambdaFuncs.js: -------------------------------------------------------------------------------- 1 | const { 2 | Lambda, 3 | LambdaClient, 4 | ListFunctionsCommand, 5 | } = require('@aws-sdk/client-lambda'); 6 | 7 | //Extract Lambda Functions for the Assumed Role 8 | //***********************Begin************************ */ 9 | 10 | const getFunctions = async (req, res, next) => { 11 | const lambdaClient = new LambdaClient({ 12 | region: req.body.region, 13 | credentials: req.body.credentials, 14 | }); 15 | 16 | const lamParams = { FunctionVersion: 'ALL' }; 17 | let funcNames = []; 18 | try { 19 | const functions = await lambdaClient.send( 20 | new ListFunctionsCommand(lamParams) 21 | ); 22 | funcNames = functions.Functions.map((el) => el.FunctionName); 23 | res.locals.functions = funcNames; 24 | return next(); 25 | } catch (err) { 26 | console.error('Error in Lambda List Functions: ', err); 27 | return next(err); 28 | } 29 | }; 30 | //***********************End************************ */ 31 | module.exports = getFunctions; 32 | -------------------------------------------------------------------------------- /server/controllers/aws/Metrics/getMetricsAllFunc.js: -------------------------------------------------------------------------------- 1 | const AWSUtilFunc = require('./utils/AWSUtilFunc.js'); 2 | const { 3 | CloudWatchClient, 4 | GetMetricDataCommand, 5 | } = require('@aws-sdk/client-cloudwatch'); 6 | 7 | //Extract the CloudWatch Metrics for the Lambda Functions 8 | //***********************Begin************************ */ 9 | 10 | const getMetricsAllFunc = async (req, res, next) => { 11 | const cwClient = new CloudWatchClient({ 12 | region: req.body.region, 13 | credentials: req.body.credentials, 14 | }); 15 | 16 | //initialize the variables for creating the inputs for AWS request 17 | let graphPeriod, graphUnits, graphMetricName, graphMetricStat; 18 | 19 | graphMetricName = req.params.metricName; 20 | 21 | if (req.body.timePeriod === '30min') { 22 | [graphPeriod, graphUnits] = [30, 'minutes']; 23 | } else if (req.body.timePeriod === '1hr') { 24 | [graphPeriod, graphUnits] = [60, 'minutes']; 25 | } else if (req.body.timePeriod === '24hr') { 26 | [graphPeriod, graphUnits] = [24, 'hours']; 27 | } else if (req.body.timePeriod === '7d') { 28 | [graphPeriod, graphUnits] = [7, 'days']; 29 | } else if (req.body.timePeriod === '14d') { 30 | [graphPeriod, graphUnits] = [14, 'days']; 31 | } else if (req.body.timePeriod === '30d') { 32 | [graphPeriod, graphUnits] = [30, 'days']; 33 | } 34 | 35 | if (!req.body.metricStat) graphMetricStat = 'Sum'; 36 | else graphMetricStat = req.body.metricStat; 37 | 38 | //Metrics for All Functions (combined) 39 | //Prepare the input parameters for the AWS getMetricsData API Query 40 | const metricAllFuncInputParams = AWSUtilFunc.prepCwMetricQueryLambdaAllFunc( 41 | graphPeriod, 42 | graphUnits, 43 | graphMetricName, 44 | graphMetricStat 45 | ); 46 | 47 | try { 48 | const metricAllFuncResult = await cwClient.send( 49 | new GetMetricDataCommand(metricAllFuncInputParams) 50 | ); 51 | 52 | //Format of the MetricDataResults 53 | //******************************* */ 54 | // "MetricDataResults": [ 55 | // { 56 | // "Id": "m0", 57 | // "Label": "Lambda Invocations CryptoRefreshProfits", 58 | // "Timestamps": [ 59 | // "2021-07-17T02:54:00.000Z", 60 | // "2021-07-17T01:54:00.000Z" 61 | // ], 62 | // "Values": [ 63 | // 1400, 64 | // 34 65 | // ], 66 | // "StatusCode": "Complete", 67 | // "Messages": [] 68 | // }, 69 | // ] 70 | //******************************* */ 71 | 72 | const metricAllFuncData = 73 | metricAllFuncResult.MetricDataResults[0].Timestamps.map( 74 | (timeStamp, index) => { 75 | return { 76 | x: timeStamp, 77 | y: metricAllFuncResult.MetricDataResults[0].Values[index], 78 | }; 79 | } 80 | ); 81 | const metricMaxValue = Math.max( 82 | ...metricAllFuncResult.MetricDataResults[0].Values, 83 | 0 84 | ); 85 | 86 | //Request response JSON Object send to the FrontEnd 87 | 88 | res.locals.metricAllFuncData = { 89 | title: metricAllFuncResult.MetricDataResults[0].Label, 90 | data: metricAllFuncData.reverse(), 91 | options: { 92 | startTime: metricAllFuncInputParams.StartTime, 93 | endTime: metricAllFuncInputParams.EndTime, 94 | graphPeriod, 95 | graphUnits, 96 | metricMaxValue, 97 | }, 98 | }; 99 | 100 | return next(); 101 | } catch (err) { 102 | console.error('Error in CW getMetricsData All Functions', err); 103 | } 104 | }; 105 | 106 | module.exports = getMetricsAllFunc; 107 | -------------------------------------------------------------------------------- /server/controllers/aws/Metrics/getMetricsByFunc.js: -------------------------------------------------------------------------------- 1 | const AWSUtilFunc = require('./utils/AWSUtilFunc.js'); 2 | const { 3 | CloudWatchClient, 4 | GetMetricDataCommand, 5 | } = require('@aws-sdk/client-cloudwatch'); 6 | 7 | //Extract the CloudWatch Metrics for the Lambda Functions 8 | //***********************Begin************************ */ 9 | 10 | const getMetricsByFunc = async (req, res, next) => { 11 | const cwClient = new CloudWatchClient({ 12 | region: req.body.region, 13 | credentials: req.body.credentials, 14 | }); 15 | 16 | //initialize the variables for creating the inputs for AWS request 17 | let graphPeriod, graphUnits, graphMetricName, funcNames, graphMetricStat; 18 | 19 | funcNames = req.body.funcNames; 20 | 21 | graphMetricName = req.params.metricName; 22 | 23 | if (req.body.timePeriod === '30min') { 24 | [graphPeriod, graphUnits] = [30, 'minutes']; 25 | } else if (req.body.timePeriod === '1hr') { 26 | [graphPeriod, graphUnits] = [60, 'minutes']; 27 | } else if (req.body.timePeriod === '24hr') { 28 | [graphPeriod, graphUnits] = [24, 'hours']; 29 | } else if (req.body.timePeriod === '7d') { 30 | [graphPeriod, graphUnits] = [7, 'days']; 31 | } else if (req.body.timePeriod === '14d') { 32 | [graphPeriod, graphUnits] = [14, 'days']; 33 | } else if (req.body.timePeriod === '30d') { 34 | [graphPeriod, graphUnits] = [30, 'days']; 35 | } 36 | 37 | if (!req.body.metricStat) graphMetricStat = 'Sum'; 38 | else graphMetricStat = req.body.metricStat; 39 | 40 | //Metrics for By Lambda Function 41 | //Prepare the input parameters for the AWS getMetricsData API Query 42 | 43 | const metricByFuncInputParams = AWSUtilFunc.prepCwMetricQueryLambdaByFunc( 44 | graphPeriod, 45 | graphUnits, 46 | graphMetricName, 47 | graphMetricStat, 48 | funcNames 49 | ); 50 | 51 | try { 52 | const metricByFuncResult = await cwClient.send( 53 | new GetMetricDataCommand(metricByFuncInputParams) 54 | ); 55 | 56 | //Format of the MetricDataResults 57 | //******************************* */ 58 | // "MetricDataResults": [ 59 | // { 60 | // "Id": "m0", 61 | // "Label": "Lambda Invocations CryptoRefreshProfits", 62 | // "Timestamps": [ 63 | // "2021-07-22T21:00:00.000Z", 64 | // "2021-07-22T20:00:00.000Z", 65 | // "2021-07-22T00:00:00.000Z" 66 | // ], 67 | // "Values": [ 68 | // 19, 69 | // 6, 70 | // 5 71 | // ], 72 | // "StatusCode": "Complete", 73 | // "Messages": [] 74 | // }, 75 | // { 76 | // "Id": "m1", 77 | // "Label": "Lambda Invocations RequestUnicorn2", 78 | // "Timestamps": [], 79 | // "Values": [], 80 | // "StatusCode": "Complete", 81 | // "Messages": [] 82 | // }, 83 | // { 84 | // "Id": "m2", 85 | // "Label": "Lambda Invocations CryptoLogin", 86 | // "Timestamps": [ 87 | // "2021-07-23T15:00:00.000Z", 88 | // "2021-07-22T21:00:00.000Z", 89 | // "2021-07-22T20:00:00.000Z", 90 | // "2021-07-22T00:00:00.000Z", 91 | // "2021-07-19T13:00:00.000Z", 92 | // "2021-07-18T02:00:00.000Z" 93 | // ], 94 | // "Values": [ 95 | // 1, 96 | // 1, 97 | // 3, 98 | // 1, 99 | // 1, 100 | // 3 101 | // ], 102 | // "StatusCode": "Complete", 103 | // "Messages": [] 104 | // }, 105 | // ] 106 | //******************************* */ 107 | 108 | const metricByFuncData = metricByFuncResult.MetricDataResults.map( 109 | (metricDataResult) => { 110 | let metricName = metricDataResult.Label; 111 | let timeStamps = metricDataResult.Timestamps.reverse(); 112 | let values = metricDataResult.Values.reverse(); 113 | let metricData = timeStamps.map((timeStamp, index) => { 114 | return { 115 | x: timeStamp, 116 | y: values[index], 117 | }; 118 | }); 119 | 120 | let maxValue = Math.max(0, Math.max(...values)); 121 | let total = values.reduce((accum, curr) => accum + curr, 0); 122 | 123 | return { 124 | name: metricName, 125 | data: metricData, 126 | maxVaue: maxValue, 127 | total: total, 128 | }; 129 | } 130 | ); 131 | 132 | const metricMaxValueAllFunc = metricByFuncData.reduce( 133 | (maxValue, dataByFunc) => { 134 | return Math.max(maxValue, dataByFunc.maxVaue); 135 | }, 136 | 0 137 | ); 138 | 139 | //Request response JSON Object send to the FrontEnd 140 | 141 | res.locals.metricByFuncData = { 142 | title: `Lambda ${graphMetricName}`, 143 | series: metricByFuncData, 144 | options: { 145 | startTime: metricByFuncInputParams.StartTime, 146 | endTime: metricByFuncInputParams.EndTime, 147 | graphPeriod, 148 | graphUnits, 149 | metricMaxValueAllFunc, 150 | funcNames: funcNames, 151 | }, 152 | }; 153 | 154 | return next(); 155 | } catch (err) { 156 | console.error('Error in CW getMetricsData By Functions', err); 157 | } 158 | }; 159 | 160 | module.exports = getMetricsByFunc; 161 | -------------------------------------------------------------------------------- /server/controllers/aws/Metrics/utils/AWSUtilFunc.js: -------------------------------------------------------------------------------- 1 | //The following assumes that User Inputs the time timeRange (either in min, hours, days) 2 | const moment = require('moment'); 3 | //input time range period for aggregating the metrics 4 | //for e.g. if the time range selected on the front end is minutes, metrics from CloudWatch would be 5 | // aggregated by 1 minute (60 seconds) 6 | 7 | const timeRangePeriod = { 8 | minutes: 60, //60 seconds 9 | hours: 300, //300 secs 10 | days: 3600, // 1 hour 11 | }; 12 | 13 | //rouding parameters for defining the EndTime 14 | 15 | const timeRoundMultiplier = { 16 | minutes: 5, //the EndTime time stamps will be rounded to nearest 5 minutes 17 | hours: 15, //rounded to nearest 15 minutes 18 | days: 60, // rounded to nearest hour 19 | }; 20 | 21 | //to compute the startTime 22 | 23 | const timeRangeMultiplier = { 24 | minutes: 60, //the EndTime time stamps will be rounded to nearest 5 minutes 25 | hours: 3600, //rounded to nearest 15 minutes 26 | days: 86400, // rounded to nearest hour 27 | }; 28 | 29 | const AWSUtilFunc = {}; 30 | 31 | AWSUtilFunc.prepCwMetricQueryLambdaAllFunc = ( 32 | timeRangeNum, 33 | timeRangeUnits, 34 | metricName, 35 | metricStat 36 | ) => { 37 | const timeRound = timeRoundMultiplier[timeRangeUnits]; 38 | //define the End and Start times in UNIX time Stamp format for getMetricsData method 39 | //Rounded off to nearest timeRoundMultiplier 40 | const EndTime = 41 | Math.round(new Date().getTime() / 1000 / 60 / timeRound) * 60 * timeRound; //current time in Unix TimeStamp 42 | const StartTime = 43 | EndTime - timeRangeNum * timeRangeMultiplier[timeRangeUnits]; 44 | 45 | const period = timeRangePeriod[timeRangeUnits]; 46 | 47 | //initialize the parameters 48 | const metricParamsBaseAllFunc = { 49 | StartTime: new Date(StartTime * 1000), 50 | EndTime: new Date(EndTime * 1000), 51 | LabelOptions: { 52 | Timezone: '-0400', 53 | }, 54 | // MetricDataQueries: [], 55 | }; 56 | 57 | const metricDataQueryAllfunc = [ 58 | { 59 | Id: `m${metricName}_AllLambdaFunc`, 60 | Label: `Lambda ${metricName} All Functions`, 61 | MetricStat: { 62 | Metric: { 63 | Namespace: 'AWS/Lambda', 64 | MetricName: `${metricName}`, 65 | }, 66 | Period: period, 67 | Stat: metricStat, 68 | }, 69 | }, 70 | ]; 71 | 72 | const metricParamsAllfunc = { 73 | ...metricParamsBaseAllFunc, 74 | MetricDataQueries: metricDataQueryAllfunc, 75 | }; 76 | 77 | return metricParamsAllfunc; 78 | }; 79 | 80 | AWSUtilFunc.prepCwMetricQueryLambdaByFunc = ( 81 | timeRangeNum, 82 | timeRangeUnits, 83 | metricName, 84 | metricStat, 85 | funcNames 86 | ) => { 87 | const timeRound = timeRoundMultiplier[timeRangeUnits]; 88 | //define the End and Start times in UNIX time Stamp format for getMetricsData method 89 | //Rounded off to nearest timeRoundMultiplier 90 | const EndTime = 91 | Math.round(new Date().getTime() / 1000 / 60 / timeRound) * 60 * timeRound; //current time in Unix TimeStamp 92 | const StartTime = 93 | EndTime - timeRangeNum * timeRangeMultiplier[timeRangeUnits]; 94 | 95 | const period = timeRangePeriod[timeRangeUnits]; 96 | 97 | //initialize the parameters 98 | const metricParamsBaseByFunc = { 99 | StartTime: new Date(StartTime * 1000), 100 | EndTime: new Date(EndTime * 1000), 101 | LabelOptions: { 102 | Timezone: '-0400', 103 | }, 104 | // MetricDataQueries: [], 105 | }; 106 | 107 | const metricDataQueryByFunc = []; 108 | 109 | funcNames.forEach((func, index) => { 110 | let metricDataQuery = { 111 | Id: `m${index}`, 112 | Label: `Lambda ${metricName} ${func}`, 113 | MetricStat: { 114 | Metric: { 115 | Namespace: `AWS/Lambda`, 116 | MetricName: `${metricName}`, 117 | Dimensions: [ 118 | { 119 | Name: `FunctionName`, 120 | Value: `${func}`, 121 | }, 122 | ], 123 | }, 124 | Period: period, 125 | Stat: metricStat, 126 | }, 127 | }; 128 | 129 | metricDataQueryByFunc.push(metricDataQuery); 130 | }); 131 | 132 | const metricParamsByFunc = { 133 | ...metricParamsBaseByFunc, 134 | MetricDataQueries: metricDataQueryByFunc, 135 | }; 136 | return metricParamsByFunc; 137 | }; 138 | 139 | // export default AWSUtilFunc; 140 | 141 | module.exports = AWSUtilFunc; 142 | -------------------------------------------------------------------------------- /server/controllers/user/nodemailer.js: -------------------------------------------------------------------------------- 1 | const nodemailer = require('nodemailer'); 2 | const dotenv = require('dotenv'); 3 | 4 | dotenv.config(); 5 | 6 | const sendEmail = (type, recipient, resetToken) => { 7 | // link to your email to be the "sender" 8 | const Transport = nodemailer.createTransport({ 9 | service: 'Gmail', 10 | auth: { 11 | user: process.env.NODEMAILER_EMAIL, 12 | pass: process.env.NODEMAILER_PASSWORD, 13 | }, 14 | }); 15 | let mailOptions; 16 | let sender = 'Helios'; 17 | let content; 18 | // email content for changing email 19 | if (type === 'emailChange') { 20 | content = `

Your email associated with Helios has been successfully updated.

Thank you for choosing Helios to monitor your serverless application!

From now on, your login will be associated with the new email you provided us.

- The Helios Team

`; 21 | mailOptions = { 22 | from: sender, 23 | to: recipient, 24 | subject: 'Your Email Has Been Updated', 25 | html: content, 26 | }; 27 | // email content for changing password 28 | } else if (type === 'passwordChange') { 29 | content = `

Your password associated with Helios has been successfully updated.

Thank you for choosing Helios to monitor your serverless application!

From now on, your login will be associated with the new password you provided us.

- The Helios Team

`; 30 | mailOptions = { 31 | from: sender, 32 | to: recipient, 33 | subject: 'Your Password Has Been Updated', 34 | html: content, 35 | }; 36 | } else if (type === 'passwordReset') { 37 | content = `

A password reset has been requested.

Thank you for choosing Helios to monitor your serverless application!

Please copy the below code to reset your account password:

${resetToken}

- The Helios Team

`; 38 | mailOptions = { 39 | from: sender, 40 | to: recipient, 41 | subject: 'Reset Your Password', 42 | html: content, 43 | }; 44 | } 45 | // send the email 46 | Transport.sendMail(mailOptions, function (error, response) { 47 | if (error) { 48 | console.error(error); 49 | return { status: false, error: error }; 50 | } else { 51 | console.log('Message Sent'); 52 | return { status: true }; 53 | } 54 | }); 55 | }; 56 | 57 | module.exports = sendEmail; 58 | -------------------------------------------------------------------------------- /server/routes/aws.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | 4 | //AWS specific details 5 | const getCredentials = require('../controllers/aws/Credentials/getCreds'); 6 | const getFunctions = require('../controllers/aws/Metrics/getLambdaFuncs'); 7 | const getMetricsAllFunc = require('../controllers/aws/Metrics/getMetricsAllFunc'); 8 | const getMetricsByFunc = require('../controllers/aws/Metrics/getMetricsByFunc'); 9 | const getLogs = require('../controllers/aws/Logs/getLogs'); 10 | const updateLogs = require('../controllers/aws/Logs/updateLogs'); 11 | const getAPIData = require('../controllers/aws/APIGateway/getAPI'); 12 | const getApiMetrics = require('../controllers/aws/APIGateway/getAPIMetrics'); 13 | const updateApiMetrics = require('../controllers/aws/APIGateway/updateAPIMetrics'); 14 | 15 | //AWS Assumed Role Credentials 16 | router.route('/getCreds').post(getCredentials, (req, res) => { 17 | res.status(200).json(res.locals.credentials); 18 | }); 19 | 20 | //Returing Lambda Functions List 21 | router.route('/getLambdaFunctions').post(getFunctions, (req, res) => { 22 | res.status(200).json(res.locals.functions); 23 | }); 24 | 25 | //Returing Lambda Functions Metric Totals (All functions): by metricName 26 | router 27 | .route('/getMetricsAllfunc/:metricName') 28 | .post(getMetricsAllFunc, (req, res) => { 29 | res.status(200).json(res.locals.metricAllFuncData); 30 | }); 31 | 32 | //Returing Lambda Functions Logs 33 | router.route('/getLogs').post(getLogs, (req, res) => { 34 | res.status(200).json(res.locals.functionLogs); 35 | }); 36 | 37 | //Updating Lambda Function Logs 38 | router.route('/updateLogs').post(updateLogs, (req, res) => { 39 | res.status(200).json(res.locals.updatedLogs); 40 | }); 41 | 42 | router 43 | .route('/getMetricsByFunc/:metricName') 44 | .post(getMetricsByFunc, (req, res) => { 45 | res.status(200).json(res.locals.metricByFuncData); 46 | }); 47 | 48 | // API Gateway data - list of APIs existing on user account 49 | router.route('/apiGateway').post(getAPIData, (req, res) => { 50 | res.status(200).json(res.locals.apiData); 51 | }); 52 | 53 | // handle getting an APIs metrics when requested 54 | router.route('/getApiMetrics').post(getApiMetrics, (req, res) => { 55 | res.status(200).json(res.locals.apiMetrics); 56 | }); 57 | 58 | // if time period is updated, fetches updated API metric data 59 | router.route('/updateApiMetrics').post(updateApiMetrics, (req, res) => { 60 | res.status(200).json(res.locals.apiMetrics); 61 | }); 62 | 63 | module.exports = router; 64 | -------------------------------------------------------------------------------- /server/routes/user.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | 4 | const userController = require('../controllers/userController'); 5 | 6 | // handle signup requests 7 | router.route('/signup').post(userController.createUser, (req, res) => { 8 | res.status(200).json(res.locals.confirmation); 9 | }); 10 | 11 | // handle login requests 12 | router.route('/login').post(userController.verifyUser, (req, res) => { 13 | res.status(200).json(res.locals.confirmation); 14 | }); 15 | 16 | // handle registration requests 17 | router.route('/register').post(userController.addArn, (req, res) => { 18 | res.sendStatus(200); 19 | }); 20 | 21 | // handle when a user requests to update their region 22 | router.route('/updateRegion').post(userController.updateRegion, (req, res) => { 23 | res.status(200).json(res.locals.confirmation); 24 | }); 25 | 26 | // handle when a user requests to update their ARN 27 | router.route('/updateArn').post(userController.updateArn, (req, res) => { 28 | res.status(200).json(res.locals.confirmation); 29 | }); 30 | 31 | // handle when a user requests to update their email 32 | router.route('/updateEmail').post(userController.updateEmail, (req, res) => { 33 | res.status(200).json(res.locals.confirmation); 34 | }); 35 | 36 | // handle when a user requests to change their email 37 | router 38 | .route('/updatePassword') 39 | .post(userController.updatePassword, (req, res) => { 40 | res.status(200).json(res.locals.confirmation); 41 | }); 42 | 43 | // handle when a user starts the "Forgot Password" process 44 | router 45 | .route('/forgotPassword') 46 | .post(userController.forgotPassword, (req, res) => { 47 | res.status(200).json(res.locals.confirmation); 48 | }); 49 | 50 | // handles accepting and verifying the verification code the user sends to continue changing password 51 | router 52 | .route('/verifyAccount') 53 | .post(userController.checkVerificationCode, (req, res) => { 54 | res.status(200).json(res.locals.confirmation); 55 | }); 56 | 57 | // handles actually resetting the user's password 58 | router 59 | .route('/resetPassword') 60 | .post(userController.resetPassword, (req, res) => { 61 | res.status(200).json(res.locals.confirmation); 62 | }); 63 | 64 | module.exports = router; 65 | -------------------------------------------------------------------------------- /server/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | const path = require('path'); 4 | const mongoose = require('mongoose'); 5 | 6 | const awsRouter = require('./routes/aws.js'); 7 | const userRouter = require('./routes/user.js'); 8 | 9 | const PORT = 4242; 10 | 11 | app.use(express.json()); 12 | app.use(express.urlencoded({ extended: true })); 13 | 14 | app.use(express.static(path.resolve(__dirname, '../client/src/Dashboard'))); 15 | app.use(express.static(path.resolve(__dirname, '../client/src'))); 16 | 17 | app.use('/build', express.static(path.resolve(__dirname, '../build'))); 18 | //Route all User related requests to User Router 19 | app.use('/user', userRouter); 20 | 21 | //Route all AWS requests to AWS router 22 | app.use('/aws', awsRouter); 23 | 24 | //server index.html for the root call 25 | app.get('/', (req, res) => { 26 | return res 27 | .status(200) 28 | .sendFile(path.resolve(__dirname, '../public/index.html')); 29 | }); 30 | 31 | // catch-all route handler for any requests 32 | app.use((req, res) => { 33 | res.sendStatus(404); 34 | }); 35 | 36 | //global error handler 37 | app.use((err, req, res, next) => { 38 | const defaultErr = { 39 | log: 'Express error handler caught unknown middleware error', 40 | status: 400, 41 | message: { err: 'An error occurred' }, 42 | }; 43 | const errObj = Object.assign(defaultErr, err); 44 | console.error('Error: ', errObj.log); 45 | res.status(errObj.status).send(errObj.message); 46 | }); 47 | 48 | module.exports = app.listen(PORT, () => { 49 | console.log(`Listening on port ${PORT}`); 50 | }); 51 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin'); 3 | 4 | module.exports = { 5 | entry: ['babel-polyfill', './client/src/index.js'], 6 | devServer: { 7 | // contentBase: __dirname + '/client/src/', 8 | publicPath: './build', 9 | proxy: { 10 | '/': 'http://localhost:4242', 11 | }, 12 | }, 13 | target: 'electron-main', 14 | mode: process.env.NODE_ENV, 15 | module: { 16 | rules: [ 17 | { 18 | test: /\.jsx?/, 19 | exclude: /(node_modules)/, 20 | use: { 21 | loader: 'babel-loader', 22 | options: { 23 | presets: ['@babel/preset-env', '@babel/preset-react'], 24 | plugins: [ 25 | '@babel/plugin-transform-runtime', 26 | '@babel/transform-async-to-generator', 27 | ], 28 | }, 29 | }, 30 | }, 31 | { 32 | test: /\.(scss|css|sass)$/i, 33 | use: ['style-loader', 'css-loader', 'sass-loader'], 34 | }, 35 | { 36 | test: /\.(png|svg|jpg|jpeg|gif)$/i, 37 | use: [ 38 | { 39 | loader: 'url-loader', 40 | options: { 41 | limit: 8192, 42 | }, 43 | }, 44 | ], 45 | }, 46 | ], 47 | }, 48 | output: { 49 | path: path.resolve(__dirname, 'build'), 50 | publicPath: '/build/', 51 | filename: 'bundle.js', 52 | }, 53 | plugins: [ 54 | new ImageMinimizerPlugin({ 55 | minimizerOptions: { 56 | // Lossless optimization with custom option 57 | // Feel free to experiment with options for better result for you 58 | plugins: [ 59 | ['gifsicle', { interlaced: true }], 60 | ['jpegtran', { progressive: true }], 61 | ['optipng', { optimizationLevel: 5 }], 62 | [ 63 | 'svgo', 64 | { 65 | plugins: [ 66 | { 67 | removeViewBox: false, 68 | }, 69 | ], 70 | }, 71 | ], 72 | ], 73 | }, 74 | }), 75 | ], 76 | resolve: { 77 | // Enable importing JS / JSX files without specifying their extension 78 | extensions: ['.js', '.jsx'], 79 | }, 80 | }; 81 | --------------------------------------------------------------------------------