├── .DS_Store ├── .babelrc ├── .eslintrc.json ├── .github └── workflows │ └── main.yml ├── .gitignore ├── .history ├── client │ └── components │ │ └── Nav_20220815123138.jsx └── server │ ├── aws │ └── getMetrics_20220815123138.js │ └── controllers │ └── authController_20220815123138.js ├── LICENSE ├── README.md ├── client ├── .DS_Store ├── App.jsx ├── assets │ ├── .DS_Store │ ├── Lumos_Logo.png │ ├── README │ │ ├── IAMSetup.png │ │ ├── IAMSetupPermissions.png │ │ ├── iamadduser.png │ │ └── iampermissions.png │ ├── lotties │ │ ├── alertIcon.json │ │ ├── cost.json │ │ ├── dashboardIcon.json │ │ ├── duration.json │ │ ├── errors.json │ │ ├── lambda-funcs.json │ │ ├── landing.json │ │ └── logsIcon.json │ └── styles.css ├── components │ ├── .DS_Store │ ├── Cards │ │ └── MetricCard.jsx │ ├── Charts.jsx │ ├── Errors.jsx │ ├── Footer.jsx │ ├── Header.jsx │ ├── LandingPage.jsx │ ├── Login.jsx │ ├── Metrics.jsx │ ├── Nav.jsx │ ├── Sidebar.jsx │ ├── SignIn.jsx │ ├── Signout.jsx │ ├── Usage.jsx │ ├── charts │ │ ├── Latency.jsx │ │ ├── TestChart.jsx │ │ └── UsageDoughnut.jsx │ ├── dateButton.jsx │ ├── dayButton.jsx │ ├── fetchMetrics.jsx │ ├── monthButton.jsx │ └── weekButton.jsx ├── containers │ └── MainContainer.jsx ├── index.html └── index.jsx ├── gitFlow.md ├── package-lock.json ├── package.json ├── server ├── aws │ ├── cloudFormation.js │ ├── cloudWatch.js │ ├── getEC2.js │ ├── getEC2Metrics.js │ ├── getLambdaFuncs.js │ ├── getLogs.js │ └── getMetrics.js ├── bcrypt.js ├── controllers │ ├── authController.js │ ├── metricController.js │ └── userController.js ├── lumos_postgres_create.sql ├── models │ ├── .gitignore │ ├── .vscode │ │ └── settings.json │ ├── UserModels.js │ └── amplify │ │ ├── .config │ │ └── project-config.json │ │ ├── backend │ │ ├── backend-config.json │ │ ├── tags.json │ │ └── types │ │ │ └── amplify-dependent-resources-ref.d.ts │ │ ├── cli.json │ │ └── team-provider-info.json ├── routes │ ├── metricRoute.js │ └── userRoute.js └── server.js └── webpack.config.js /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Lumos/4c0a1009065e0991c74dd32847e52ce70d98f72f/.DS_Store -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false 7 | } 8 | ], 9 | "@babel/preset-react" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true, 5 | "node": true 6 | }, 7 | "extends": ["plugin:react/recommended", "airbnb"], 8 | "parserOptions": { 9 | "ecmaFeatures": { 10 | "jsx": true 11 | }, 12 | "ecmaVersion": "latest", 13 | "sourceType": "module" 14 | }, 15 | "plugins": ["react"], 16 | "rules": { 17 | "import/extensions": [, "never" | "always" | "ignorePackages"] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: 3 | push: 4 | branches: 5 | - 'backend' 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - 11 | name: Checkout 12 | uses: actions/checkout@v3 13 | - 14 | name: Login to Docker Hub 15 | uses: docker/login-action@v2 16 | with: 17 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 18 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 19 | - 20 | name: Set up Docker Buildx 21 | uses: docker/setup-buildx-action@v2 22 | - 23 | name: Build and push 24 | uses: docker/build-push-action@v3 25 | with: 26 | context: . 27 | file: ./Dockerfile 28 | push: true 29 | tags: ${{ secrets.DOCKER_HUB_USERNAME }}/lumos:latest 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | .history -------------------------------------------------------------------------------- /.history/client/components/Nav_20220815123138.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable linebreak-style */ 2 | import React ,{useContext} from 'react'; 3 | import { Box } from '@mui/material'; 4 | import Login from '../components/Login.jsx'; 5 | import Sign from '../components/SignIn.jsx'; 6 | import { InfoContext } from "../containers/MainContainer.jsx"; 7 | // import Logo from '../assets/Lumos_Logo.png' 8 | 9 | 10 | function Nav() { 11 | // const logo = require('../assets/Lumos_Logo.png') 12 | const [userInfo, setUserInfo] = useContext(InfoContext); 13 | return ( 14 | 15 | 16 | 17 | 18 | 19 | 20 | {/* { userInfo.loggedIn === false && 21 | <> */} 22 | 23 | 24 | 25 | 26 | {/* 27 | } */} 28 | 29 | ); 30 | } 31 | 32 | export default Nav; 33 | -------------------------------------------------------------------------------- /.history/server/aws/getMetrics_20220815123138.js: -------------------------------------------------------------------------------- 1 | const { 2 | ListMetricsCommand, 3 | GetMetricDataCommand, 4 | GetMetricStatisticsCommand, 5 | CloudWatchClient, 6 | } = require("@aws-sdk/client-cloudwatch"); 7 | const getLambdaFuncs = require("./getLambdaFuncs.js"); 8 | 9 | const getMetrics = async ( 10 | startTime, 11 | endTime, 12 | metricName, 13 | period = 60, 14 | funcName = undefined, 15 | metricStat = "Sum" 16 | ) => { 17 | try { 18 | const client = await new CloudWatchClient({ region: "us-east-1" }); 19 | if (funcName === undefined) { 20 | const funcNames = await getLambdaFuncs(); 21 | const queries = []; 22 | 23 | funcNames.forEach((func, index) => { 24 | const query = [{ 25 | Id: `m${Math.floor(Math.random() * 812903819023)}`, 26 | Label: `Lambda ${metricName} ${func}`, 27 | MetricStat: { 28 | Metric: { 29 | Namespace: `AWS/Lambda`, 30 | MetricName: `${metricName}`, 31 | Dimensions: [ 32 | { 33 | Name: `FunctionName`, 34 | Value: `${func}`, 35 | }, 36 | ], 37 | }, 38 | Period: `${period}`, 39 | Stat: `${metricStat}`, 40 | }, 41 | }, 42 | { 43 | Id: `m${Math.floor(Math.random() * 897123891273)}`, 44 | Label: `Lambda Errors ${func}`, 45 | MetricStat: { 46 | Metric: { 47 | Namespace: `AWS/Lambda`, 48 | MetricName: `Errors`, 49 | Dimensions: [ 50 | { 51 | Name: `FunctionName`, 52 | Value: `${func}`, 53 | }, 54 | ], 55 | }, 56 | Period: `${period}`, 57 | Stat: `${metricStat}`, 58 | }, 59 | } 60 | ]; 61 | // console.log(query) 62 | queries.push(query); 63 | }); 64 | 65 | // console.log(queries); 66 | 67 | const res = []; 68 | 69 | for (let i = 0; i < queries.length; i += 1) { 70 | const data = await client.send( 71 | new GetMetricDataCommand({ 72 | StartTime: new Date(startTime), 73 | EndTime: new Date(endTime), 74 | MetricDataQueries: queries[i], 75 | }) 76 | ); 77 | 78 | res.push({ 79 | funcName: queries[i][0].MetricStat.Metric.Dimensions[0].Value, // label 80 | totalInvocations: data.MetricDataResults[0].Values.reduce((a, b) => a + b, 0), // total sum 81 | totalErrors: data.MetricDataResults[1].Values.reduce((a, b) => a + b, 0), 82 | timestamps: data.MetricDataResults[0].Timestamps, 83 | funcValues: data.MetricDataResults[0].Values, 84 | }); 85 | } 86 | // console.log('res: ', res.MetricDataResults); 87 | return res; 88 | } else { 89 | 90 | const data = await client.send( 91 | new GetMetricDataCommand({ 92 | StartTime: new Date(startTime), //new Date("August 6, 2022 13:30:30"), <- needs variable where we can send in a start date from frontend 93 | EndTime: new Date(endTime), //new Date("August 6, 2022 16:00:00"),<- needs variable where we can send in a start date from frontend 94 | MetricDataQueries: [ 95 | { 96 | Id: "test", 97 | MetricStat: { 98 | Metric: { 99 | MetricName: metricName, 100 | Namespace: "AWS/Lambda", 101 | Dimensions: [ 102 | { 103 | Name: "FunctionName", 104 | Value: funcName, 105 | }, 106 | ], 107 | }, 108 | Period: period, 109 | Stat: metricStat, 110 | }, 111 | }, 112 | ], 113 | }) 114 | ); 115 | 116 | return { 117 | funcName: funcName, 118 | totalInvocations: data.MetricDataResults[0].Values.reduce((a, b) => a + b, 0), 119 | timeStamps: data.MetricDataResults[0].Timestamps, 120 | funcValues: data.MetricDataResults[0].Values 121 | }; 122 | } 123 | } catch (err) { 124 | return err; 125 | } 126 | }; 127 | 128 | getMetrics( 129 | "August 1, 2022 15:30:30", 130 | "August 10, 2022 18:00:00", 131 | "Invocations", 132 | period = 60, 133 | ); 134 | 135 | // // we need this getMetrics in a controller function so we can invoke this from a frontend route 136 | 137 | // const getMetrics = async(startTime, endTime, metricName, period = 60, funcName = undefined) => { 138 | // const client = await new CloudWatchClient({region: "us-east-1"}) 139 | // try { 140 | // if (!funcName) { 141 | // const funcNames = getLambdaFuncs(); 142 | // // funcNames.forEach((func) => { 143 | // // const data = await client.send( 144 | // // new GetMetricDataCommand({ 145 | // // StartTime: new Date(startTime), //new Date("August 6, 2022 13:30:30"), <- needs variable where we can send in a start date from frontend 146 | // // EndTime: new Date(endTime), //new Date("August 6, 2022 16:00:00"),<- needs variable where we can send in a start date from frontend 147 | // // MetricDataQueries: [ 148 | // // { 149 | // // Id: "test", 150 | // // // Expression: 'SELECT SUM(Invocations) FROM SCHEMA("AWS/Lambda", FunctionName) GROUP BY FunctionName ORDER BY SUM() DESC', 151 | // // MetricStat: { 152 | // // Metric: { 153 | // // MetricName: metricName, //"Errors", 154 | // // Namespace: "AWS/Lambda", 155 | // // Dimensions: [{ 156 | // // Name: 'FunctionName', 157 | // // Value: func 158 | // // }] 159 | // // }, 160 | // // Period: period, 161 | // // Stat: 'Sum', 162 | // // }, 163 | // // }, 164 | // // ], 165 | 166 | // // }) 167 | // // ); 168 | // // }) 169 | 170 | // return data.MetricDataResults; 171 | // } else { 172 | // const data = await client.send( 173 | // new GetMetricDataCommand({ 174 | // StartTime: new Date(startTime), //new Date("August 6, 2022 13:30:30"), <- needs variable where we can send in a start date from frontend 175 | // EndTime: new Date(endTime), //new Date("August 6, 2022 16:00:00"),<- needs variable where we can send in a start date from frontend 176 | // MetricDataQueries: [ 177 | // { 178 | // Id: "test", 179 | // // Expression: 'SELECT SUM(Invocations) FROM SCHEMA("AWS/Lambda", FunctionName) GROUP BY FunctionName ORDER BY SUM() DESC', 180 | // MetricStat: { 181 | // Metric: { 182 | // MetricName: metricName, //"Errors", 183 | // Namespace: "AWS/Lambda", 184 | // Dimensions: [{ 185 | // Name: 'FunctionName', 186 | // Value: funcName 187 | // }] 188 | // }, 189 | // Period: period, 190 | // Stat: 'Sum', 191 | // }, 192 | // }, 193 | // ], 194 | 195 | // })) 196 | // } 197 | // } catch (err) { 198 | // return err 199 | // } 200 | // } 201 | 202 | // getMetrics(new Date("August 1, 2022 15:30:30"), new Date("August 10, 2022 18:00:00"), "Invocations", 60); 203 | 204 | // const date = new Date(); 205 | 206 | // date.setHours(5) 207 | 208 | // console.log(date) 209 | 210 | module.exports = getMetrics; 211 | -------------------------------------------------------------------------------- /.history/server/controllers/authController_20220815123138.js: -------------------------------------------------------------------------------- 1 | const jwt = require('jsonwebtoken'); 2 | 3 | // Hide this later in env file 4 | const JWT_SECRET = 'f2960658fe4135e6ab6e4f173b522c558c98d43cafb1a5ef8f8015f375529e31f91f05cde7b7d2ea730a45032a5653fe7d70ddb1a2bee093e87a5fc68afed5ad' 5 | 6 | const authController = {}; 7 | 8 | authController.sendToken = async (req, res, next) => { 9 | const token = jwt.sign(res.locals.password, JWT_SECRET); 10 | res.send(token); 11 | }; 12 | 13 | authController.verifyToken = async (req, res, next) => { 14 | try { 15 | const header = req.headers['authorization']; 16 | const token = header && header.split(' ')[1]; 17 | 18 | if (token === null) { 19 | return next({ 20 | log: "Error occurred in authController.verifyToken", 21 | status: 401, 22 | message: err, 23 | }) 24 | } else { 25 | jwt.verify(token, JWT_SECRET, (error, result) => { 26 | if (err) return next(error) 27 | req.user = result; 28 | return next(); 29 | }) 30 | } 31 | } catch (err) { 32 | return next(err) 33 | } 34 | }; 35 | 36 | module.exports = authController; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 OSLabs Beta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | Lumos Logo 5 |

Lumos Lambda Metrics Visualizer

6 |
7 | 8 | 9 |
10 | Table of Contents 11 |
    12 |
  1. About Lumos
  2. 13 |
  3. Techologies Used
  4. 14 |
  5. Getting Started
  6. 15 |
  7. Key Lambda Metrics
  8. 16 |
  9. How to Contribute
  10. 17 |
  11. License
  12. 18 |
  13. Contributors
  14. 19 |
20 |
21 | 22 | 23 | 24 | ## About Lumos 25 | 26 | Serverless architecture is an integral benefit of cloud computing which allows developers to build and run services without having to manage the underlying infrastructure. Amazon Web Services' (AWS) Lambda is the dominant service in the serverless market and is relied upon by the world's largest companies due to its cost-effective, event-driven service that runs code in response to events and automatically manages the computing resources required by that code. 27 | 28 | One drawback to using AWS's services is that navigating the AWS console can be quite challenging. Additionally, lack of descriptive documentation pertaining to AWS's Lambda service makes it difficult to visualize key function metrics at a glance. To solve this, we built Lumos, a free and open-source AWS lambda monitoring tool that allows users to connect their AWS account to track and visualize their key lambda metrics on a visually appealing UI. 29 | 30 | ## Technologies Used 31 | 32 | - [React](https://reactjs.org/) 33 | - [Material-UI](https://material-ui.com) 34 | - [Chart.js](https://www.chartjs.org/) 35 | - [AWS Lambda](https://aws.amazon.com/lambda/) 36 | - [AWS SDK](https://aws.amazon.com/sdk-for-javascript/) 37 | - [AWS STS](https://docs.aws.amazon.com/STS/latest/APIReference/welcome.html) 38 | - [AWS CloudWatch](https://aws.amazon.com/cloudwatch/) 39 | - [Node](https://nodejs.org/en/) 40 | - [Express](https://expressjs.com) 41 | - [PostgreSQL](https://postgresql.org) 42 | - [Webpack](https://webpack.js.org/) 43 | - [Bcrypt](https://www.npmjs.com/package/bcrypt) 44 | - [JSON Web Token](https://jwt.io/) 45 | 46 | 47 | 48 | ## Getting Started 49 | 50 | Lumos requires access keys to sign programmatic requests to the AWS SDK. It is best practice to create an IAM user with permanent long-term credentials to interact with AWS services directly. 51 | 52 | 1. In your AWS console, create an new IAM user. Make sure to check off "Access key - Programmatic access" when selecting an AWS credential type. Save these keys in a secure location. **_They cannot be retrieved after you've completed your IAM setup!_** If you lose your key, you will have to delete the access key and create a new one. 53 | 54 | - 55 | 56 | 2. Attach two existing policies directly to your IAM user's security policy: 57 | 58 | - 59 | 60 | 3. [Download and install the AWS CLI.](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) 61 | 62 | 4. From your terminal, access the AWS CLI by typing in 63 | `aws configure`. Follow the steps on your screen and input your access key ID and secret access key. 64 | 65 | 66 | 67 | ## Key Lambda Metrics 68 | 69 | The key lambda metrics we found to be of most interest to users were invocations, durations, and errors. One can visualize their lambda functions metrics across three different time periods: 24 hours, 1 week, or 1 month. Users can visualize their insights through two charts: donut and line. A donut chart will give an overview of all active invocations relating to the functions. The line chart will give a visualization of the number of times each lambda function has been invoked across selected time periods. Lumos also approximates the total cost of a user's lambda functions based on the function's duration and memory usage. 70 | 71 | 72 | 73 | ## How to Contribute 74 | 75 | At Lumos, we open-sourced the project with the intention of having amazing people iterate on our project. 76 | 77 | If you have any suggestions on how to improve Lumos, please follow the steps below: 78 | 79 | 1. Fork Lumos 80 | 2. Create your Feature Branch (`git checkout -b feature/YourFeature`) 81 | 3. Add your changes using (`git add .`) 82 | 4. Commit your Changes (`git commit -m 'Add Your Feature'`) 83 | 5. Push to the Branch (`git push origin feature/YourFeature`) 84 | 6. Open a Pull Request 85 | 7. Hit the star button!! 86 | 87 | Thank you and we truly appreciate all your contributions! 88 | 89 | 90 | 91 | ## License 92 | 93 | Distributed under the MIT License. 94 | 95 | 96 | 97 | ## Contributors 98 | 99 | - Adithya Chandrashekar [Github](https://github.com/addychandrashekar) | [Linkedin](https://www.linkedin.com/in/addyc/) 100 | - Adnan Pervez [Github](https://github.com/apervez) | [Linkedin](https://www.linkedin.com/in/adnan-pervez) 101 | - Carmen Hu [Github](https://github.com/BadWithNames) | [Linkedin](https://www.linkedin.com/in/hu-carmen) 102 | - Mario Arraya [Github](https://github.com/marioarraya) | [Linkedin](https://www.linkedin.com/in/mario-arraya/) 103 | - Michael Negron [Github](https://github.com/InternalShadow) | [Linkedin](https://www.linkedin.com/in/MichaelVNegron) 104 | -------------------------------------------------------------------------------- /client/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Lumos/4c0a1009065e0991c74dd32847e52ce70d98f72f/client/.DS_Store -------------------------------------------------------------------------------- /client/App.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable linebreak-style */ 2 | import React from 'react'; 3 | import MainContainer from './containers/MainContainer.jsx'; 4 | 5 | function App() { 6 | return ( 7 | <> 8 | 9 | 10 | ); 11 | } 12 | 13 | export default App; 14 | -------------------------------------------------------------------------------- /client/assets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Lumos/4c0a1009065e0991c74dd32847e52ce70d98f72f/client/assets/.DS_Store -------------------------------------------------------------------------------- /client/assets/Lumos_Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Lumos/4c0a1009065e0991c74dd32847e52ce70d98f72f/client/assets/Lumos_Logo.png -------------------------------------------------------------------------------- /client/assets/README/iamadduser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Lumos/4c0a1009065e0991c74dd32847e52ce70d98f72f/client/assets/README/iamadduser.png -------------------------------------------------------------------------------- /client/assets/README/iampermissions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Lumos/4c0a1009065e0991c74dd32847e52ce70d98f72f/client/assets/README/iampermissions.png -------------------------------------------------------------------------------- /client/assets/lotties/dashboardIcon.json: -------------------------------------------------------------------------------- 1 | { 2 | "v": "5.8.1", 3 | "fr": 24, 4 | "ip": 0, 5 | "op": 48, 6 | "w": 500, 7 | "h": 500, 8 | "nm": "467-dashboard-gauge-gradient", 9 | "ddd": 0, 10 | "assets": [ 11 | { 12 | "id": "comp_0", 13 | "nm": "mask", 14 | "fr": 24, 15 | "layers": [ 16 | { 17 | "ddd": 0, 18 | "ind": 1, 19 | "ty": 4, 20 | "nm": "outline 3", 21 | "sr": 1, 22 | "ks": { 23 | "o": { "a": 0, "k": 100, "ix": 11 }, 24 | "r": { 25 | "a": 1, 26 | "k": [ 27 | { 28 | "i": { "x": [0.833], "y": [0.833] }, 29 | "o": { "x": [0.333], "y": [0] }, 30 | "t": 0, 31 | "s": [-29] 32 | }, 33 | { 34 | "i": { "x": [0.833], "y": [0.833] }, 35 | "o": { "x": [0.167], "y": [0.167] }, 36 | "t": 11, 37 | "s": [92] 38 | }, 39 | { 40 | "i": { "x": [0.833], "y": [0.833] }, 41 | "o": { "x": [0.167], "y": [0.167] }, 42 | "t": 13, 43 | "s": [84] 44 | }, 45 | { 46 | "i": { "x": [0.833], "y": [0.833] }, 47 | "o": { "x": [0.167], "y": [0.167] }, 48 | "t": 15, 49 | "s": [92] 50 | }, 51 | { 52 | "i": { "x": [0.833], "y": [0.833] }, 53 | "o": { "x": [0.167], "y": [0.167] }, 54 | "t": 17, 55 | "s": [84] 56 | }, 57 | { 58 | "i": { "x": [0.833], "y": [0.833] }, 59 | "o": { "x": [0.167], "y": [0.167] }, 60 | "t": 19, 61 | "s": [92] 62 | }, 63 | { 64 | "i": { "x": [0.833], "y": [0.833] }, 65 | "o": { "x": [0.167], "y": [0.167] }, 66 | "t": 21, 67 | "s": [84] 68 | }, 69 | { 70 | "i": { "x": [0.833], "y": [0.833] }, 71 | "o": { "x": [0.167], "y": [0.167] }, 72 | "t": 23, 73 | "s": [92] 74 | }, 75 | { 76 | "i": { "x": [0.833], "y": [0.833] }, 77 | "o": { "x": [0.167], "y": [0.167] }, 78 | "t": 25, 79 | "s": [84] 80 | }, 81 | { 82 | "i": { "x": [0.833], "y": [0.833] }, 83 | "o": { "x": [0.167], "y": [0.167] }, 84 | "t": 27, 85 | "s": [92] 86 | }, 87 | { 88 | "i": { "x": [0.26], "y": [1] }, 89 | "o": { "x": [0.167], "y": [0.167] }, 90 | "t": 29, 91 | "s": [84] 92 | }, 93 | { "t": 47, "s": [-29] } 94 | ], 95 | "ix": 10 96 | }, 97 | "p": { "a": 0, "k": [250, 315.045, 0], "ix": 2, "l": 2 }, 98 | "a": { "a": 0, "k": [0, 65.045, 0], "ix": 1, "l": 2 }, 99 | "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } 100 | }, 101 | "ao": 0, 102 | "shapes": [ 103 | { 104 | "ty": "gr", 105 | "it": [ 106 | { 107 | "ind": 0, 108 | "ty": "sh", 109 | "ix": 1, 110 | "ks": { 111 | "a": 0, 112 | "k": { 113 | "i": [ 114 | [0, 0], 115 | [0, 0] 116 | ], 117 | "o": [ 118 | [0, 0], 119 | [0, 0] 120 | ], 121 | "v": [ 122 | [0, 65.045], 123 | [0, 65.045] 124 | ], 125 | "c": false 126 | }, 127 | "ix": 2 128 | }, 129 | "nm": "Path 1", 130 | "mn": "ADBE Vector Shape - Group", 131 | "hd": false 132 | }, 133 | { 134 | "ty": "st", 135 | "c": { 136 | "a": 0, 137 | "k": [0.070588238537, 0.074509806931, 0.192156866193, 1], 138 | "ix": 3 139 | }, 140 | "o": { "a": 0, "k": 100, "ix": 4 }, 141 | "w": { 142 | "a": 0, 143 | "k": 12, 144 | "ix": 5, 145 | "x": "var $bm_rt;\n$bm_rt = $bm_mul($bm_div(value, 70), comp('467-dashboard-gauge-gradient').layer('Color & Stroke Change').effect('Stroke')('Slider'));" 146 | }, 147 | "lc": 2, 148 | "lj": 2, 149 | "bm": 0, 150 | "nm": "Stroke 1", 151 | "mn": "ADBE Vector Graphic - Stroke", 152 | "hd": false 153 | }, 154 | { 155 | "ty": "tr", 156 | "p": { "a": 0, "k": [0, 0], "ix": 2 }, 157 | "a": { "a": 0, "k": [0, 0], "ix": 1 }, 158 | "s": { "a": 0, "k": [100, 100], "ix": 3 }, 159 | "r": { "a": 0, "k": 0, "ix": 6 }, 160 | "o": { "a": 0, "k": 100, "ix": 7 }, 161 | "sk": { "a": 0, "k": 0, "ix": 4 }, 162 | "sa": { "a": 0, "k": 0, "ix": 5 }, 163 | "nm": "Transform" 164 | } 165 | ], 166 | "nm": "Group 1", 167 | "np": 2, 168 | "cix": 2, 169 | "bm": 0, 170 | "ix": 1, 171 | "mn": "ADBE Vector Group", 172 | "hd": false 173 | } 174 | ], 175 | "ip": 0, 176 | "op": 120, 177 | "st": 0, 178 | "bm": 0 179 | }, 180 | { 181 | "ddd": 0, 182 | "ind": 2, 183 | "ty": 4, 184 | "nm": "outline 2", 185 | "sr": 1, 186 | "ks": { 187 | "o": { "a": 0, "k": 100, "ix": 11 }, 188 | "r": { "a": 0, "k": 0, "ix": 10 }, 189 | "p": { "a": 0, "k": [250, 251, 0], "ix": 2, "l": 2 }, 190 | "a": { "a": 0, "k": [0, 1, 0], "ix": 1, "l": 2 }, 191 | "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } 192 | }, 193 | "ao": 0, 194 | "shapes": [ 195 | { 196 | "ty": "gr", 197 | "it": [ 198 | { 199 | "ind": 0, 200 | "ty": "sh", 201 | "ix": 1, 202 | "ks": { 203 | "a": 0, 204 | "k": { 205 | "i": [ 206 | [0, -88.43], 207 | [2.1, -10.344], 208 | [0, 0], 209 | [0, 10.968], 210 | [-88.43, 0] 211 | ], 212 | "o": [ 213 | [0, 10.968], 214 | [0, 0], 215 | [-2.1, -10.344], 216 | [0, -88.43], 217 | [88.43, 0] 218 | ], 219 | "v": [ 220 | [160.119, 65.045], 221 | [156.915, 97.074], 222 | [-156.915, 97.074], 223 | [-160.119, 65.045], 224 | [0, -95.074] 225 | ], 226 | "c": true 227 | }, 228 | "ix": 2 229 | }, 230 | "nm": "Path 1", 231 | "mn": "ADBE Vector Shape - Group", 232 | "hd": false 233 | }, 234 | { 235 | "ind": 1, 236 | "ty": "sh", 237 | "ix": 2, 238 | "ks": { 239 | "a": 0, 240 | "k": { 241 | "i": [ 242 | [0, 0], 243 | [0, 0] 244 | ], 245 | "o": [ 246 | [0, 0], 247 | [0, 0] 248 | ], 249 | "v": [ 250 | [65.392, -48.218], 251 | [51.653, -24.421] 252 | ], 253 | "c": false 254 | }, 255 | "ix": 2 256 | }, 257 | "nm": "Path 2", 258 | "mn": "ADBE Vector Shape - Group", 259 | "hd": false 260 | }, 261 | { 262 | "ind": 2, 263 | "ty": "sh", 264 | "ix": 3, 265 | "ks": { 266 | "a": 0, 267 | "k": { 268 | "i": [ 269 | [0, 0], 270 | [0, 0] 271 | ], 272 | "o": [ 273 | [0, 0], 274 | [0, 0] 275 | ], 276 | "v": [ 277 | [113.263, -0.347], 278 | [89.466, 13.392] 279 | ], 280 | "c": false 281 | }, 282 | "ix": 2 283 | }, 284 | "nm": "Path 3", 285 | "mn": "ADBE Vector Shape - Group", 286 | "hd": false 287 | }, 288 | { 289 | "ind": 3, 290 | "ty": "sh", 291 | "ix": 4, 292 | "ks": { 293 | "a": 0, 294 | "k": { 295 | "i": [ 296 | [0, 0], 297 | [0, 0] 298 | ], 299 | "o": [ 300 | [0, 0], 301 | [0, 0] 302 | ], 303 | "v": [ 304 | [130.785, 65.045], 305 | [103.306, 65.045] 306 | ], 307 | "c": false 308 | }, 309 | "ix": 2 310 | }, 311 | "nm": "Path 4", 312 | "mn": "ADBE Vector Shape - Group", 313 | "hd": false 314 | }, 315 | { 316 | "ind": 4, 317 | "ty": "sh", 318 | "ix": 5, 319 | "ks": { 320 | "a": 0, 321 | "k": { 322 | "i": [ 323 | [0, 0], 324 | [0, 0] 325 | ], 326 | "o": [ 327 | [0, 0], 328 | [0, 0] 329 | ], 330 | "v": [ 331 | [-130.785, 65.045], 332 | [-103.306, 65.045] 333 | ], 334 | "c": false 335 | }, 336 | "ix": 2 337 | }, 338 | "nm": "Path 5", 339 | "mn": "ADBE Vector Shape - Group", 340 | "hd": false 341 | }, 342 | { 343 | "ind": 5, 344 | "ty": "sh", 345 | "ix": 6, 346 | "ks": { 347 | "a": 0, 348 | "k": { 349 | "i": [ 350 | [0, 0], 351 | [0, 0] 352 | ], 353 | "o": [ 354 | [0, 0], 355 | [0, 0] 356 | ], 357 | "v": [ 358 | [-113.263, -0.347], 359 | [-89.466, 13.392] 360 | ], 361 | "c": false 362 | }, 363 | "ix": 2 364 | }, 365 | "nm": "Path 6", 366 | "mn": "ADBE Vector Shape - Group", 367 | "hd": false 368 | }, 369 | { 370 | "ind": 6, 371 | "ty": "sh", 372 | "ix": 7, 373 | "ks": { 374 | "a": 0, 375 | "k": { 376 | "i": [ 377 | [0, 0], 378 | [0, 0] 379 | ], 380 | "o": [ 381 | [0, 0], 382 | [0, 0] 383 | ], 384 | "v": [ 385 | [-65.392, -48.218], 386 | [-51.653, -24.421] 387 | ], 388 | "c": false 389 | }, 390 | "ix": 2 391 | }, 392 | "nm": "Path 7", 393 | "mn": "ADBE Vector Shape - Group", 394 | "hd": false 395 | }, 396 | { 397 | "ind": 7, 398 | "ty": "sh", 399 | "ix": 8, 400 | "ks": { 401 | "a": 0, 402 | "k": { 403 | "i": [ 404 | [0, 0], 405 | [0, 0] 406 | ], 407 | "o": [ 408 | [0, 0], 409 | [0, 0] 410 | ], 411 | "v": [ 412 | [0, -65.739], 413 | [0, -38.261] 414 | ], 415 | "c": false 416 | }, 417 | "ix": 2 418 | }, 419 | "nm": "Path 8", 420 | "mn": "ADBE Vector Shape - Group", 421 | "hd": false 422 | }, 423 | { 424 | "ty": "st", 425 | "c": { 426 | "a": 0, 427 | "k": [0.070588238537, 0.074509806931, 0.192156866193, 1], 428 | "ix": 3 429 | }, 430 | "o": { "a": 0, "k": 100, "ix": 4 }, 431 | "w": { 432 | "a": 0, 433 | "k": 12, 434 | "ix": 5, 435 | "x": "var $bm_rt;\n$bm_rt = $bm_mul($bm_div(value, 70), comp('467-dashboard-gauge-gradient').layer('Color & Stroke Change').effect('Stroke')('Slider'));" 436 | }, 437 | "lc": 2, 438 | "lj": 2, 439 | "bm": 0, 440 | "nm": "Stroke 1", 441 | "mn": "ADBE Vector Graphic - Stroke", 442 | "hd": false 443 | }, 444 | { 445 | "ty": "tr", 446 | "p": { "a": 0, "k": [0, 0], "ix": 2 }, 447 | "a": { "a": 0, "k": [0, 0], "ix": 1 }, 448 | "s": { "a": 0, "k": [100, 100], "ix": 3 }, 449 | "r": { "a": 0, "k": 0, "ix": 6 }, 450 | "o": { "a": 0, "k": 100, "ix": 7 }, 451 | "sk": { "a": 0, "k": 0, "ix": 4 }, 452 | "sa": { "a": 0, "k": 0, "ix": 5 }, 453 | "nm": "Transform" 454 | } 455 | ], 456 | "nm": "Group 1", 457 | "np": 9, 458 | "cix": 2, 459 | "bm": 0, 460 | "ix": 1, 461 | "mn": "ADBE Vector Group", 462 | "hd": false 463 | } 464 | ], 465 | "ip": 0, 466 | "op": 120, 467 | "st": 0, 468 | "bm": 0 469 | }, 470 | { 471 | "ddd": 0, 472 | "ind": 3, 473 | "ty": 4, 474 | "nm": "outline", 475 | "parent": 1, 476 | "sr": 1, 477 | "ks": { 478 | "o": { "a": 0, "k": 100, "ix": 11 }, 479 | "r": { "a": 0, "k": -60, "ix": 10 }, 480 | "p": { "a": 0, "k": [-18.488, 33.023, 0], "ix": 2, "l": 2 }, 481 | "a": { "a": 0, "k": [18.488, 33.023, 0], "ix": 1, "l": 2 }, 482 | "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } 483 | }, 484 | "ao": 0, 485 | "shapes": [ 486 | { 487 | "ty": "gr", 488 | "it": [ 489 | { 490 | "ind": 0, 491 | "ty": "sh", 492 | "ix": 1, 493 | "ks": { 494 | "a": 0, 495 | "k": { 496 | "i": [ 497 | [0, 0], 498 | [0, 0] 499 | ], 500 | "o": [ 501 | [0, 0], 502 | [0, 0] 503 | ], 504 | "v": [ 505 | [36.977, 1], 506 | [0, 65.045] 507 | ], 508 | "c": false 509 | }, 510 | "ix": 2 511 | }, 512 | "nm": "Path 1", 513 | "mn": "ADBE Vector Shape - Group", 514 | "hd": false 515 | }, 516 | { 517 | "ty": "st", 518 | "c": { 519 | "a": 0, 520 | "k": [0.070588238537, 0.074509806931, 0.192156866193, 1], 521 | "ix": 3 522 | }, 523 | "o": { "a": 0, "k": 100, "ix": 4 }, 524 | "w": { 525 | "a": 0, 526 | "k": 12, 527 | "ix": 5, 528 | "x": "var $bm_rt;\n$bm_rt = $bm_mul($bm_div(value, 70), comp('467-dashboard-gauge-gradient').layer('Color & Stroke Change').effect('Stroke')('Slider'));" 529 | }, 530 | "lc": 2, 531 | "lj": 2, 532 | "bm": 0, 533 | "nm": "Stroke 1", 534 | "mn": "ADBE Vector Graphic - Stroke", 535 | "hd": false 536 | }, 537 | { 538 | "ty": "tr", 539 | "p": { "a": 0, "k": [0, 0], "ix": 2 }, 540 | "a": { "a": 0, "k": [0, 0], "ix": 1 }, 541 | "s": { "a": 0, "k": [100, 100], "ix": 3 }, 542 | "r": { "a": 0, "k": 0, "ix": 6 }, 543 | "o": { "a": 0, "k": 100, "ix": 7 }, 544 | "sk": { "a": 0, "k": 0, "ix": 4 }, 545 | "sa": { "a": 0, "k": 0, "ix": 5 }, 546 | "nm": "Transform" 547 | } 548 | ], 549 | "nm": "Group 1", 550 | "np": 2, 551 | "cix": 2, 552 | "bm": 0, 553 | "ix": 1, 554 | "mn": "ADBE Vector Group", 555 | "hd": false 556 | } 557 | ], 558 | "ip": 0, 559 | "op": 120, 560 | "st": 0, 561 | "bm": 0 562 | } 563 | ] 564 | } 565 | ], 566 | "layers": [ 567 | { 568 | "ddd": 0, 569 | "ind": 1, 570 | "ty": 4, 571 | "nm": "watermark", 572 | "sr": 1, 573 | "ks": { 574 | "o": { 575 | "a": 0, 576 | "k": 100, 577 | "ix": 11, 578 | "x": "var $bm_rt;\nvar checkbox = thisComp.layer('02092020').effect('02092020002')('Checkbox');\nif (checkbox == 1) {\n $bm_rt = 20;\n} else {\n $bm_rt = 0;\n}\n;" 579 | }, 580 | "r": { "a": 0, "k": 0, "ix": 10 }, 581 | "p": { "a": 0, "k": [249.934, 481.369, 0], "ix": 2, "l": 2 }, 582 | "a": { "a": 0, "k": [79.934, 0.369, 0], "ix": 1, "l": 2 }, 583 | "s": { "a": 0, "k": [265.159, 265.159, 100], "ix": 6, "l": 2 } 584 | }, 585 | "ao": 0, 586 | "shapes": [ 587 | { 588 | "ind": 0, 589 | "ty": "sh", 590 | "ix": 1, 591 | "ks": { 592 | "a": 0, 593 | "k": { 594 | "i": [ 595 | [0, 0], 596 | [0, 0], 597 | [0, 0], 598 | [0, 0], 599 | [0, 0], 600 | [0, 0] 601 | ], 602 | "o": [ 603 | [0, 0], 604 | [0, 0], 605 | [0, 0], 606 | [0, 0], 607 | [0, 0], 608 | [0, 0] 609 | ], 610 | "v": [ 611 | [1.415, 0], 612 | [11.014, 0], 613 | [11.014, -2.523], 614 | [4.656, -2.523], 615 | [4.656, -14.809], 616 | [1.415, -14.809] 617 | ], 618 | "c": true 619 | }, 620 | "ix": 2 621 | }, 622 | "nm": "l", 623 | "mn": "ADBE Vector Shape - Group", 624 | "hd": false 625 | }, 626 | { 627 | "ind": 1, 628 | "ty": "sh", 629 | "ix": 2, 630 | "ks": { 631 | "a": 0, 632 | "k": { 633 | "i": [ 634 | [0, -3.938], 635 | [-1.62, -1.723], 636 | [-1.949, 0], 637 | [-1.641, 1.846], 638 | [0, 2.154], 639 | [1.579, 1.805], 640 | [1.579, 0] 641 | ], 642 | "o": [ 643 | [0, 1.354], 644 | [1.354, 1.415], 645 | [1.231, 0], 646 | [1.21, -1.354], 647 | [0, -1.456], 648 | [-1.456, -1.641], 649 | [-5.333, 0] 650 | ], 651 | "v": [ 652 | [11.167, -7.199], 653 | [12.992, -1.661], 654 | [18.243, 0.369], 655 | [23.514, -1.743], 656 | [25.381, -7.548], 657 | [23.494, -13.127], 658 | [18.284, -15.137] 659 | ], 660 | "c": true 661 | }, 662 | "ix": 2 663 | }, 664 | "nm": "o", 665 | "mn": "ADBE Vector Shape - Group", 666 | "hd": false 667 | }, 668 | { 669 | "ind": 2, 670 | "ty": "sh", 671 | "ix": 3, 672 | "ks": { 673 | "a": 0, 674 | "k": { 675 | "i": [ 676 | [0, 1.415], 677 | [-0.841, 1.026], 678 | [-1.19, 0], 679 | [-0.615, -1.825], 680 | [0, -0.718], 681 | [0.492, -0.738], 682 | [1.292, 0], 683 | [0.451, 0.615] 684 | ], 685 | "o": [ 686 | [0, -1.682], 687 | [0.595, -0.759], 688 | [1.518, 0], 689 | [0.308, 0.902], 690 | [0, 2.359], 691 | [-0.595, 0.923], 692 | [-1.477, 0], 693 | [-0.882, -1.149] 694 | ], 695 | "v": [ 696 | [14.49, -7.302], 697 | [15.577, -11.609], 698 | [18.305, -12.86], 699 | [21.689, -10.235], 700 | [22.058, -7.589], 701 | [21.053, -3.343], 702 | [18.284, -1.969], 703 | [15.597, -3.159] 704 | ], 705 | "c": true 706 | }, 707 | "ix": 2 708 | }, 709 | "nm": "o", 710 | "mn": "ADBE Vector Shape - Group", 711 | "hd": false 712 | }, 713 | { 714 | "ind": 3, 715 | "ty": "sh", 716 | "ix": 4, 717 | "ks": { 718 | "a": 0, 719 | "k": { 720 | "i": [ 721 | [0, 0], 722 | [0, 0], 723 | [0, 0], 724 | [0, 0], 725 | [-0.287, -0.841], 726 | [-0.144, -0.82], 727 | [0, 0], 728 | [0.164, 0.656], 729 | [0.226, 1.743], 730 | [2.236, 0.205], 731 | [0, 2.769], 732 | [0.923, 0.8], 733 | [1.641, -0.021], 734 | [0, 0] 735 | ], 736 | "o": [ 737 | [0, 0], 738 | [0, 0], 739 | [0, 0], 740 | [0.533, 0], 741 | [0.205, 0.574], 742 | [0, 0], 743 | [-0.164, -0.246], 744 | [-0.103, -0.41], 745 | [-0.267, -1.928], 746 | [0.718, -0.205], 747 | [0, -0.964], 748 | [-1.19, -1.026], 749 | [0, 0], 750 | [0, 0] 751 | ], 752 | "v": [ 753 | [27.381, 0], 754 | [30.622, 0], 755 | [30.622, -5.989], 756 | [33.411, -5.989], 757 | [35.011, -5.148], 758 | [35.811, 0], 759 | [39.318, 0], 760 | [38.867, -1.067], 761 | [38.416, -3.938], 762 | [35.749, -7.343], 763 | [38.847, -10.973], 764 | [37.554, -13.824], 765 | [33.063, -14.829], 766 | [27.381, -14.829] 767 | ], 768 | "c": true 769 | }, 770 | "ix": 2 771 | }, 772 | "nm": "r", 773 | "mn": "ADBE Vector Shape - Group", 774 | "hd": false 775 | }, 776 | { 777 | "ind": 4, 778 | "ty": "sh", 779 | "ix": 5, 780 | "ks": { 781 | "a": 0, 782 | "k": { 783 | "i": [ 784 | [0, 0], 785 | [0, 0], 786 | [-0.492, -0.349], 787 | [0, -1.005], 788 | [0.226, -0.164], 789 | [0.369, 0], 790 | [0, 0] 791 | ], 792 | "o": [ 793 | [0, 0], 794 | [1.005, 0], 795 | [0.287, 0.185], 796 | [0, 1.046], 797 | [-0.513, 0.41], 798 | [0, 0], 799 | [0, 0] 800 | ], 801 | "v": [ 802 | [30.519, -12.491], 803 | [32.652, -12.491], 804 | [34.744, -12.142], 805 | [35.524, -10.481], 806 | [34.703, -8.758], 807 | [33.083, -8.348], 808 | [30.519, -8.348] 809 | ], 810 | "c": true 811 | }, 812 | "ix": 2 813 | }, 814 | "nm": "r", 815 | "mn": "ADBE Vector Shape - Group", 816 | "hd": false 817 | }, 818 | { 819 | "ind": 5, 820 | "ty": "sh", 821 | "ix": 6, 822 | "ks": { 823 | "a": 0, 824 | "k": { 825 | "i": [ 826 | [0, 0], 827 | [0, 0], 828 | [-0.554, 0.103], 829 | [0, 4.553], 830 | [1.866, 1.374], 831 | [0.82, 0], 832 | [0, 0] 833 | ], 834 | "o": [ 835 | [0, 0], 836 | [1.497, 0], 837 | [2.81, -0.513], 838 | [0, -2.113], 839 | [-1.784, -1.313], 840 | [0, 0], 841 | [0, 0] 842 | ], 843 | "v": [ 844 | [41.068, 0], 845 | [45.683, 0], 846 | [48.349, -0.164], 847 | [53.6, -7.609], 848 | [51.077, -13.434], 849 | [45.97, -14.768], 850 | [41.068, -14.788] 851 | ], 852 | "c": true 853 | }, 854 | "ix": 2 855 | }, 856 | "nm": "d", 857 | "mn": "ADBE Vector Shape - Group", 858 | "hd": false 859 | }, 860 | { 861 | "ind": 6, 862 | "ty": "sh", 863 | "ix": 7, 864 | "ks": { 865 | "a": 0, 866 | "k": { 867 | "i": [ 868 | [0, 0], 869 | [-0.656, -0.185], 870 | [0, -2.092], 871 | [1.251, -1.251], 872 | [1.354, 0], 873 | [0.349, 0.021] 874 | ], 875 | "o": [ 876 | [1.825, -0.082], 877 | [1.99, 0.554], 878 | [0, 0.718], 879 | [-0.923, 0.923], 880 | [-0.369, 0], 881 | [0, 0] 882 | ], 883 | "v": [ 884 | [44.288, -12.388], 885 | [47.611, -12.183], 886 | [50.318, -7.609], 887 | [48.985, -3.425], 888 | [45.539, -2.4], 889 | [44.288, -2.441] 890 | ], 891 | "c": true 892 | }, 893 | "ix": 2 894 | }, 895 | "nm": "d", 896 | "mn": "ADBE Vector Shape - Group", 897 | "hd": false 898 | }, 899 | { 900 | "ind": 7, 901 | "ty": "sh", 902 | "ix": 8, 903 | "ks": { 904 | "a": 0, 905 | "k": { 906 | "i": [ 907 | [0, 0], 908 | [0, 0], 909 | [0, 0], 910 | [0, 0] 911 | ], 912 | "o": [ 913 | [0, 0], 914 | [0, 0], 915 | [0, 0], 916 | [0, 0] 917 | ], 918 | "v": [ 919 | [55.669, 0], 920 | [58.849, 0], 921 | [58.849, -14.87], 922 | [55.669, -14.87] 923 | ], 924 | "c": true 925 | }, 926 | "ix": 2 927 | }, 928 | "nm": "i", 929 | "mn": "ADBE Vector Shape - Group", 930 | "hd": false 931 | }, 932 | { 933 | "ind": 8, 934 | "ty": "sh", 935 | "ix": 9, 936 | "ks": { 937 | "a": 0, 938 | "k": { 939 | "i": [ 940 | [0, 0], 941 | [3.241, 0], 942 | [0, -4.697], 943 | [-5.107, 0], 944 | [-1.313, 1.354], 945 | [-0.062, 0.882], 946 | [0, 0], 947 | [1.333, 0], 948 | [0, 0.882], 949 | [-2.359, 0], 950 | [-0.062, -0.513] 951 | ], 952 | "o": [ 953 | [0, -2.954], 954 | [-4.164, 0], 955 | [0, 3.671], 956 | [1.354, 0], 957 | [1.19, -1.231], 958 | [0, 0], 959 | [-0.062, 1.969], 960 | [-3.097, 0], 961 | [0, -3.056], 962 | [2.154, 0], 963 | [0, 0] 964 | ], 965 | "v": [ 966 | [73.104, -9.989], 967 | [67.587, -14.911], 968 | [60.798, -7.097], 969 | [67.566, 0.349], 970 | [71.894, -1.313], 971 | [73.227, -4.799], 972 | [69.884, -4.799], 973 | [67.218, -1.99], 974 | [64.121, -7.076], 975 | [67.464, -12.593], 976 | [69.864, -9.989] 977 | ], 978 | "c": true 979 | }, 980 | "ix": 2 981 | }, 982 | "nm": "c", 983 | "mn": "ADBE Vector Shape - Group", 984 | "hd": false 985 | }, 986 | { 987 | "ind": 9, 988 | "ty": "sh", 989 | "ix": 10, 990 | "ks": { 991 | "a": 0, 992 | "k": { 993 | "i": [ 994 | [0, -3.938], 995 | [-1.62, -1.723], 996 | [-1.949, 0], 997 | [-1.641, 1.846], 998 | [0, 2.154], 999 | [1.579, 1.805], 1000 | [1.579, 0] 1001 | ], 1002 | "o": [ 1003 | [0, 1.354], 1004 | [1.354, 1.415], 1005 | [1.231, 0], 1006 | [1.21, -1.354], 1007 | [0, -1.456], 1008 | [-1.456, -1.641], 1009 | [-5.333, 0] 1010 | ], 1011 | "v": [ 1012 | [74.546, -7.199], 1013 | [76.372, -1.661], 1014 | [81.622, 0.369], 1015 | [86.894, -1.743], 1016 | [88.76, -7.548], 1017 | [86.873, -13.127], 1018 | [81.663, -15.137] 1019 | ], 1020 | "c": true 1021 | }, 1022 | "ix": 2 1023 | }, 1024 | "nm": "o", 1025 | "mn": "ADBE Vector Shape - Group", 1026 | "hd": false 1027 | }, 1028 | { 1029 | "ind": 10, 1030 | "ty": "sh", 1031 | "ix": 11, 1032 | "ks": { 1033 | "a": 0, 1034 | "k": { 1035 | "i": [ 1036 | [0, 1.415], 1037 | [-0.841, 1.026], 1038 | [-1.19, 0], 1039 | [-0.615, -1.825], 1040 | [0, -0.718], 1041 | [0.492, -0.738], 1042 | [1.292, 0], 1043 | [0.451, 0.615] 1044 | ], 1045 | "o": [ 1046 | [0, -1.682], 1047 | [0.595, -0.759], 1048 | [1.518, 0], 1049 | [0.308, 0.902], 1050 | [0, 2.359], 1051 | [-0.595, 0.923], 1052 | [-1.477, 0], 1053 | [-0.882, -1.149] 1054 | ], 1055 | "v": [ 1056 | [77.869, -7.302], 1057 | [78.956, -11.609], 1058 | [81.684, -12.86], 1059 | [85.068, -10.235], 1060 | [85.437, -7.589], 1061 | [84.432, -3.343], 1062 | [81.663, -1.969], 1063 | [78.977, -3.159] 1064 | ], 1065 | "c": true 1066 | }, 1067 | "ix": 2 1068 | }, 1069 | "nm": "o", 1070 | "mn": "ADBE Vector Shape - Group", 1071 | "hd": false 1072 | }, 1073 | { 1074 | "ind": 11, 1075 | "ty": "sh", 1076 | "ix": 12, 1077 | "ks": { 1078 | "a": 0, 1079 | "k": { 1080 | "i": [ 1081 | [0, 0], 1082 | [0, 0], 1083 | [0, 0], 1084 | [0, 0], 1085 | [0, 0], 1086 | [0, 0], 1087 | [0, 0], 1088 | [0, 0], 1089 | [0, 0], 1090 | [0, 0] 1091 | ], 1092 | "o": [ 1093 | [0, 0], 1094 | [0, 0], 1095 | [0, 0], 1096 | [0, 0], 1097 | [0, 0], 1098 | [0, 0], 1099 | [0, 0], 1100 | [0, 0], 1101 | [0, 0], 1102 | [0, 0] 1103 | ], 1104 | "v": [ 1105 | [91.007, 0], 1106 | [94.001, 0], 1107 | [94.001, -12.306], 1108 | [99.744, 0], 1109 | [104.113, 0], 1110 | [104.113, -14.829], 1111 | [101.159, -14.829], 1112 | [101.159, -3.159], 1113 | [95.601, -14.829], 1114 | [91.007, -14.829] 1115 | ], 1116 | "c": true 1117 | }, 1118 | "ix": 2 1119 | }, 1120 | "nm": "n", 1121 | "mn": "ADBE Vector Shape - Group", 1122 | "hd": false 1123 | }, 1124 | { 1125 | "ind": 12, 1126 | "ty": "sh", 1127 | "ix": 13, 1128 | "ks": { 1129 | "a": 0, 1130 | "k": { 1131 | "i": [ 1132 | [0, 0], 1133 | [0, 0], 1134 | [0, 0], 1135 | [0, 0] 1136 | ], 1137 | "o": [ 1138 | [0, 0], 1139 | [0, 0], 1140 | [0, 0], 1141 | [0, 0] 1142 | ], 1143 | "v": [ 1144 | [106.893, 0], 1145 | [109.497, 0], 1146 | [109.497, -2.728], 1147 | [106.893, -2.728] 1148 | ], 1149 | "c": true 1150 | }, 1151 | "ix": 2 1152 | }, 1153 | "nm": ".", 1154 | "mn": "ADBE Vector Shape - Group", 1155 | "hd": false 1156 | }, 1157 | { 1158 | "ind": 13, 1159 | "ty": "sh", 1160 | "ix": 14, 1161 | "ks": { 1162 | "a": 0, 1163 | "k": { 1164 | "i": [ 1165 | [0, 0], 1166 | [3.241, 0], 1167 | [0, -4.697], 1168 | [-5.107, 0], 1169 | [-1.313, 1.354], 1170 | [-0.062, 0.882], 1171 | [0, 0], 1172 | [1.333, 0], 1173 | [0, 0.882], 1174 | [-2.359, 0], 1175 | [-0.062, -0.513] 1176 | ], 1177 | "o": [ 1178 | [0, -2.954], 1179 | [-4.164, 0], 1180 | [0, 3.671], 1181 | [1.354, 0], 1182 | [1.19, -1.231], 1183 | [0, 0], 1184 | [-0.062, 1.969], 1185 | [-3.097, 0], 1186 | [0, -3.056], 1187 | [2.154, 0], 1188 | [0, 0] 1189 | ], 1190 | "v": [ 1191 | [124.04, -9.989], 1192 | [118.523, -14.911], 1193 | [111.734, -7.097], 1194 | [118.502, 0.349], 1195 | [122.83, -1.313], 1196 | [124.163, -4.799], 1197 | [120.82, -4.799], 1198 | [118.154, -1.99], 1199 | [115.057, -7.076], 1200 | [118.4, -12.593], 1201 | [120.8, -9.989] 1202 | ], 1203 | "c": true 1204 | }, 1205 | "ix": 2 1206 | }, 1207 | "nm": "c", 1208 | "mn": "ADBE Vector Shape - Group", 1209 | "hd": false 1210 | }, 1211 | { 1212 | "ind": 14, 1213 | "ty": "sh", 1214 | "ix": 15, 1215 | "ks": { 1216 | "a": 0, 1217 | "k": { 1218 | "i": [ 1219 | [0, -3.938], 1220 | [-1.62, -1.723], 1221 | [-1.949, 0], 1222 | [-1.641, 1.846], 1223 | [0, 2.154], 1224 | [1.579, 1.805], 1225 | [1.579, 0] 1226 | ], 1227 | "o": [ 1228 | [0, 1.354], 1229 | [1.354, 1.415], 1230 | [1.231, 0], 1231 | [1.21, -1.354], 1232 | [0, -1.456], 1233 | [-1.456, -1.641], 1234 | [-5.333, 0] 1235 | ], 1236 | "v": [ 1237 | [125.482, -7.199], 1238 | [127.308, -1.661], 1239 | [132.558, 0.369], 1240 | [137.829, -1.743], 1241 | [139.696, -7.548], 1242 | [137.809, -13.127], 1243 | [132.599, -15.137] 1244 | ], 1245 | "c": true 1246 | }, 1247 | "ix": 2 1248 | }, 1249 | "nm": "o", 1250 | "mn": "ADBE Vector Shape - Group", 1251 | "hd": false 1252 | }, 1253 | { 1254 | "ind": 15, 1255 | "ty": "sh", 1256 | "ix": 16, 1257 | "ks": { 1258 | "a": 0, 1259 | "k": { 1260 | "i": [ 1261 | [0, 1.415], 1262 | [-0.841, 1.026], 1263 | [-1.19, 0], 1264 | [-0.615, -1.825], 1265 | [0, -0.718], 1266 | [0.492, -0.738], 1267 | [1.292, 0], 1268 | [0.451, 0.615] 1269 | ], 1270 | "o": [ 1271 | [0, -1.682], 1272 | [0.595, -0.759], 1273 | [1.518, 0], 1274 | [0.308, 0.902], 1275 | [0, 2.359], 1276 | [-0.595, 0.923], 1277 | [-1.477, 0], 1278 | [-0.882, -1.149] 1279 | ], 1280 | "v": [ 1281 | [128.805, -7.302], 1282 | [129.892, -11.609], 1283 | [132.62, -12.86], 1284 | [136.004, -10.235], 1285 | [136.373, -7.589], 1286 | [135.368, -3.343], 1287 | [132.599, -1.969], 1288 | [129.912, -3.159] 1289 | ], 1290 | "c": true 1291 | }, 1292 | "ix": 2 1293 | }, 1294 | "nm": "o", 1295 | "mn": "ADBE Vector Shape - Group", 1296 | "hd": false 1297 | }, 1298 | { 1299 | "ind": 16, 1300 | "ty": "sh", 1301 | "ix": 17, 1302 | "ks": { 1303 | "a": 0, 1304 | "k": { 1305 | "i": [ 1306 | [0, 0], 1307 | [0, 0], 1308 | [0, 0], 1309 | [0, 0], 1310 | [0, 0], 1311 | [0, 0], 1312 | [0, 0], 1313 | [0, 0], 1314 | [0, 0], 1315 | [0, 0], 1316 | [0, 0], 1317 | [0, 0], 1318 | [0, 0] 1319 | ], 1320 | "o": [ 1321 | [0, 0], 1322 | [0, 0], 1323 | [0, 0], 1324 | [0, 0], 1325 | [0, 0], 1326 | [0, 0], 1327 | [0, 0], 1328 | [0, 0], 1329 | [0, 0], 1330 | [0, 0], 1331 | [0, 0], 1332 | [0, 0], 1333 | [0, 0] 1334 | ], 1335 | "v": [ 1336 | [141.696, 0], 1337 | [144.67, 0], 1338 | [144.67, -12.716], 1339 | [148.629, 0], 1340 | [151.254, 0], 1341 | [155.295, -12.716], 1342 | [155.295, 0], 1343 | [158.453, 0], 1344 | [158.453, -14.829], 1345 | [153.408, -14.829], 1346 | [150.024, -4.041], 1347 | [146.885, -14.829], 1348 | [141.696, -14.829] 1349 | ], 1350 | "c": true 1351 | }, 1352 | "ix": 2 1353 | }, 1354 | "nm": "m", 1355 | "mn": "ADBE Vector Shape - Group", 1356 | "hd": false 1357 | }, 1358 | { 1359 | "ty": "fl", 1360 | "c": { "a": 0, "k": [0, 0, 0, 1], "ix": 4 }, 1361 | "o": { "a": 0, "k": 100, "ix": 5 }, 1362 | "r": 1, 1363 | "bm": 0, 1364 | "nm": "Fill 1", 1365 | "mn": "ADBE Vector Graphic - Fill", 1366 | "hd": false 1367 | } 1368 | ], 1369 | "ip": 1, 1370 | "op": 10, 1371 | "st": 0, 1372 | "bm": 0 1373 | }, 1374 | { 1375 | "ddd": 0, 1376 | "ind": 2, 1377 | "ty": 3, 1378 | "nm": "02092020", 1379 | "sr": 1, 1380 | "ks": { 1381 | "o": { "a": 0, "k": 0, "ix": 11 }, 1382 | "r": { "a": 0, "k": 0, "ix": 10 }, 1383 | "p": { "a": 0, "k": [-105, 15, 0], "ix": 2, "l": 2 }, 1384 | "a": { "a": 0, "k": [60, 60, 0], "ix": 1, "l": 2 }, 1385 | "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } 1386 | }, 1387 | "ao": 0, 1388 | "ef": [ 1389 | { 1390 | "ty": 5, 1391 | "nm": "02092020002", 1392 | "np": 3, 1393 | "mn": "ADBE Checkbox Control", 1394 | "ix": 1, 1395 | "en": 1, 1396 | "ef": [ 1397 | { 1398 | "ty": 7, 1399 | "nm": "Checkbox", 1400 | "mn": "ADBE Checkbox Control-0001", 1401 | "ix": 1, 1402 | "v": { "a": 0, "k": 0, "ix": 1 } 1403 | } 1404 | ] 1405 | } 1406 | ], 1407 | "ip": 0, 1408 | "op": 120, 1409 | "st": 0, 1410 | "bm": 0 1411 | }, 1412 | { 1413 | "ddd": 0, 1414 | "ind": 3, 1415 | "ty": 3, 1416 | "nm": "Color & Stroke Change", 1417 | "sr": 1, 1418 | "ks": { 1419 | "o": { "a": 0, "k": 0, "ix": 11 }, 1420 | "r": { "a": 0, "k": 0, "ix": 10 }, 1421 | "p": { 1422 | "a": 0, 1423 | "k": [250, 250, 0], 1424 | "ix": 2, 1425 | "l": 2, 1426 | "x": "var $bm_rt;\n$bm_rt = effect('Axis')('Point');" 1427 | }, 1428 | "a": { "a": 0, "k": [0, 0, 0], "ix": 1, "l": 2 }, 1429 | "s": { 1430 | "a": 0, 1431 | "k": [100, 100, 100], 1432 | "ix": 6, 1433 | "l": 2, 1434 | "x": "var $bm_rt;\nvar temp;\ntemp = effect('Scale')('Slider');\n$bm_rt = [\n temp,\n temp\n];" 1435 | } 1436 | }, 1437 | "ao": 0, 1438 | "ef": [ 1439 | { 1440 | "ty": 5, 1441 | "nm": "Stroke", 1442 | "np": 3, 1443 | "mn": "ADBE Slider Control", 1444 | "ix": 1, 1445 | "en": 1, 1446 | "ef": [ 1447 | { 1448 | "ty": 0, 1449 | "nm": "Slider", 1450 | "mn": "ADBE Slider Control-0001", 1451 | "ix": 1, 1452 | "v": { "a": 0, "k": 70, "ix": 1 } 1453 | } 1454 | ] 1455 | }, 1456 | { 1457 | "ty": 5, 1458 | "nm": "Axis", 1459 | "np": 3, 1460 | "mn": "ADBE Point Control", 1461 | "ix": 2, 1462 | "en": 1, 1463 | "ef": [ 1464 | { 1465 | "ty": 3, 1466 | "nm": "Point", 1467 | "mn": "ADBE Point Control-0001", 1468 | "ix": 1, 1469 | "v": { "a": 0, "k": [250, 250], "ix": 1 } 1470 | } 1471 | ] 1472 | }, 1473 | { 1474 | "ty": 5, 1475 | "nm": "Scale", 1476 | "np": 3, 1477 | "mn": "ADBE Slider Control", 1478 | "ix": 3, 1479 | "en": 1, 1480 | "ef": [ 1481 | { 1482 | "ty": 0, 1483 | "nm": "Slider", 1484 | "mn": "ADBE Slider Control-0001", 1485 | "ix": 1, 1486 | "v": { "a": 0, "k": 100, "ix": 1 } 1487 | } 1488 | ] 1489 | }, 1490 | { 1491 | "ty": 5, 1492 | "nm": "Primary", 1493 | "np": 3, 1494 | "mn": "ADBE Color Control", 1495 | "ix": 4, 1496 | "en": 1, 1497 | "ef": [ 1498 | { 1499 | "ty": 2, 1500 | "nm": "Color", 1501 | "mn": "ADBE Color Control-0001", 1502 | "ix": 1, 1503 | "v": { "a": 0, "k": [0.847, 0.4, 0.075], "ix": 1 } 1504 | } 1505 | ] 1506 | }, 1507 | { 1508 | "ty": 5, 1509 | "nm": "Secondary", 1510 | "np": 3, 1511 | "mn": "ADBE Color Control", 1512 | "ix": 5, 1513 | "en": 1, 1514 | "ef": [ 1515 | { 1516 | "ty": 2, 1517 | "nm": "Color", 1518 | "mn": "ADBE Color Control-0001", 1519 | "ix": 1, 1520 | "v": { "a": 0, "k": [0.91, 0.549, 0.188], "ix": 1 } 1521 | } 1522 | ] 1523 | } 1524 | ], 1525 | "ip": 0, 1526 | "op": 120, 1527 | "st": 0, 1528 | "bm": 0 1529 | }, 1530 | { 1531 | "ddd": 0, 1532 | "ind": 4, 1533 | "ty": 0, 1534 | "nm": "mask", 1535 | "parent": 3, 1536 | "td": 1, 1537 | "refId": "comp_0", 1538 | "sr": 1, 1539 | "ks": { 1540 | "o": { "a": 0, "k": 100, "ix": 11 }, 1541 | "r": { "a": 0, "k": 0, "ix": 10 }, 1542 | "p": { "a": 0, "k": [0, 0, 0], "ix": 2, "l": 2 }, 1543 | "a": { "a": 0, "k": [250, 250, 0], "ix": 1, "l": 2 }, 1544 | "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } 1545 | }, 1546 | "ao": 0, 1547 | "w": 500, 1548 | "h": 500, 1549 | "ip": 0, 1550 | "op": 120, 1551 | "st": 0, 1552 | "bm": 0 1553 | }, 1554 | { 1555 | "ddd": 0, 1556 | "ind": 5, 1557 | "ty": 4, 1558 | "nm": "gradient", 1559 | "parent": 3, 1560 | "tt": 1, 1561 | "sr": 1, 1562 | "ks": { 1563 | "o": { "a": 0, "k": 100, "ix": 11 }, 1564 | "r": { 1565 | "a": 1, 1566 | "k": [ 1567 | { 1568 | "i": { "x": [0.4], "y": [1] }, 1569 | "o": { "x": [0.333], "y": [0] }, 1570 | "t": 0, 1571 | "s": [-94] 1572 | }, 1573 | { "t": 48, "s": [266] } 1574 | ], 1575 | "ix": 10 1576 | }, 1577 | "p": { "a": 0, "k": [21.941, 20.46, 0], "ix": 2, "l": 2 }, 1578 | "a": { "a": 0, "k": [0, 0, 0], "ix": 1, "l": 2 }, 1579 | "s": { "a": 0, "k": [240, 240, 100], "ix": 6, "l": 2 } 1580 | }, 1581 | "ao": 0, 1582 | "ef": [ 1583 | { 1584 | "ty": 29, 1585 | "nm": "Gaussian Blur", 1586 | "np": 5, 1587 | "mn": "ADBE Gaussian Blur 2", 1588 | "ix": 1, 1589 | "en": 1, 1590 | "ef": [ 1591 | { 1592 | "ty": 0, 1593 | "nm": "Blurriness", 1594 | "mn": "ADBE Gaussian Blur 2-0001", 1595 | "ix": 1, 1596 | "v": { "a": 0, "k": 175, "ix": 1 } 1597 | }, 1598 | { 1599 | "ty": 7, 1600 | "nm": "Blur Dimensions", 1601 | "mn": "ADBE Gaussian Blur 2-0002", 1602 | "ix": 2, 1603 | "v": { "a": 0, "k": 1, "ix": 2 } 1604 | }, 1605 | { 1606 | "ty": 7, 1607 | "nm": "Repeat Edge Pixels", 1608 | "mn": "ADBE Gaussian Blur 2-0003", 1609 | "ix": 3, 1610 | "v": { "a": 0, "k": 1, "ix": 3 } 1611 | } 1612 | ] 1613 | } 1614 | ], 1615 | "shapes": [ 1616 | { 1617 | "ty": "gr", 1618 | "it": [ 1619 | { 1620 | "ind": 0, 1621 | "ty": "sh", 1622 | "ix": 1, 1623 | "ks": { 1624 | "a": 0, 1625 | "k": { 1626 | "i": [ 1627 | [-97.478, 0], 1628 | [0, -97.478], 1629 | [97.478, 0], 1630 | [30.894, 26.574], 1631 | [0, 53.531] 1632 | ], 1633 | "o": [ 1634 | [97.478, 0], 1635 | [0, 97.478], 1636 | [-43.948, 0], 1637 | [-37.631, -32.369], 1638 | [0, -97.478] 1639 | ], 1640 | "v": [ 1641 | [0, -176.5], 1642 | [176.5, 0], 1643 | [0, 176.5], 1644 | [-105.29, 115.869], 1645 | [-176.5, 0] 1646 | ], 1647 | "c": true 1648 | }, 1649 | "ix": 2 1650 | }, 1651 | "nm": "Path 1", 1652 | "mn": "ADBE Vector Shape - Group", 1653 | "hd": false 1654 | }, 1655 | { 1656 | "ty": "fl", 1657 | "c": { 1658 | "a": 0, 1659 | "k": [0.796078443527, 0.368627458811, 0.933333337307, 1], 1660 | "ix": 4, 1661 | "x": "var $bm_rt;\n$bm_rt = comp('467-dashboard-gauge-gradient').layer('Color & Stroke Change').effect('Secondary')('Color');" 1662 | }, 1663 | "o": { "a": 0, "k": 100, "ix": 5 }, 1664 | "r": 1, 1665 | "bm": 0, 1666 | "nm": "Fill 1", 1667 | "mn": "ADBE Vector Graphic - Fill", 1668 | "hd": false 1669 | }, 1670 | { 1671 | "ty": "tr", 1672 | "p": { "a": 0, "k": [113.242, -118.884], "ix": 2 }, 1673 | "a": { "a": 0, "k": [0, 0], "ix": 1 }, 1674 | "s": { "a": 0, "k": [100, 100], "ix": 3 }, 1675 | "r": { "a": 0, "k": 0, "ix": 6 }, 1676 | "o": { "a": 0, "k": 100, "ix": 7 }, 1677 | "sk": { "a": 0, "k": 0, "ix": 4 }, 1678 | "sa": { "a": 0, "k": 0, "ix": 5 }, 1679 | "nm": "Transform" 1680 | } 1681 | ], 1682 | "nm": "primary.design", 1683 | "np": 2, 1684 | "cix": 2, 1685 | "bm": 0, 1686 | "ix": 1, 1687 | "mn": "ADBE Vector Group", 1688 | "hd": false, 1689 | "cl": "design" 1690 | }, 1691 | { 1692 | "ty": "gr", 1693 | "it": [ 1694 | { 1695 | "d": 1, 1696 | "ty": "el", 1697 | "s": { "a": 0, "k": [500, 500], "ix": 2 }, 1698 | "p": { "a": 0, "k": [0, 0], "ix": 3 }, 1699 | "nm": "Ellipse Path 1", 1700 | "mn": "ADBE Vector Shape - Ellipse", 1701 | "hd": false 1702 | }, 1703 | { 1704 | "ty": "fl", 1705 | "c": { 1706 | "a": 0, 1707 | "k": [0.29411765933, 0.882352948189, 0.92549020052, 1], 1708 | "ix": 4, 1709 | "x": "var $bm_rt;\n$bm_rt = comp('467-dashboard-gauge-gradient').layer('Color & Stroke Change').effect('Primary')('Color');" 1710 | }, 1711 | "o": { "a": 0, "k": 100, "ix": 5 }, 1712 | "r": 1, 1713 | "bm": 0, 1714 | "nm": "Fill 1", 1715 | "mn": "ADBE Vector Graphic - Fill", 1716 | "hd": false 1717 | }, 1718 | { 1719 | "ty": "tr", 1720 | "p": { "a": 0, "k": [0, 0], "ix": 2 }, 1721 | "a": { "a": 0, "k": [0, 0], "ix": 1 }, 1722 | "s": { "a": 0, "k": [100, 100], "ix": 3 }, 1723 | "r": { "a": 0, "k": 0, "ix": 6 }, 1724 | "o": { "a": 0, "k": 100, "ix": 7 }, 1725 | "sk": { "a": 0, "k": 0, "ix": 4 }, 1726 | "sa": { "a": 0, "k": 0, "ix": 5 }, 1727 | "nm": "Transform" 1728 | } 1729 | ], 1730 | "nm": "secondary.design", 1731 | "np": 2, 1732 | "cix": 2, 1733 | "bm": 0, 1734 | "ix": 2, 1735 | "mn": "ADBE Vector Group", 1736 | "hd": false, 1737 | "cl": "design" 1738 | } 1739 | ], 1740 | "ip": 0, 1741 | "op": 120, 1742 | "st": 0, 1743 | "bm": 0 1744 | } 1745 | ], 1746 | "markers": [ 1747 | { "tm": 13, "cm": "1", "dr": 0 }, 1748 | { "tm": 34, "cm": "2", "dr": 0 }, 1749 | { "tm": 48, "cm": "4", "dr": 0 } 1750 | ], 1751 | "features": ["states"] 1752 | } 1753 | -------------------------------------------------------------------------------- /client/assets/styles.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500&display=swap"); 2 | 3 | .outerContainer { 4 | background: #ececec; 5 | height: 98vh; 6 | display: grid !important; 7 | grid-template-columns: 160px 1fr 1fr 1fr; 8 | grid-template-rows: 80px 1fr 1fr 1fr 1fr 1fr 80px; 9 | gap: 30px; 10 | grid-template-areas: 11 | "Nav Nav Nav Nav" 12 | "Sidebar Metrics Metrics Errors" 13 | "Sidebar Metrics Metrics Errors" 14 | "Sidebar Charts Charts Usage" 15 | "Sidebar Charts Charts Usage" 16 | "Sidebar Charts Charts Usage" 17 | "Footer Footer Footer Footer"; 18 | padding: 30px; 19 | } 20 | 21 | .outerContainerLandingPage { 22 | background: #ececec; 23 | height: 98vh; 24 | display: grid !important; 25 | grid-template-columns: 1fr 1fr; 26 | grid-template-rows: 80px 1fr 80px; 27 | gap: 30px; 28 | grid-template-areas: 29 | "Nav Nav" 30 | "Hero Hero" 31 | "Footer Footer"; 32 | padding: 30px; 33 | } 34 | 35 | .HeroContainer { 36 | grid-area: Hero; 37 | display: grid !important; 38 | grid-template-columns: 1fr 1fr; 39 | gap: 30px; 40 | padding: 0px 10%; 41 | } 42 | 43 | ul.HeroTechStack li { 44 | list-style: none; 45 | } 46 | 47 | ul.HeroTechStack li a { 48 | padding: 0; 49 | text-decoration: none; 50 | color: gray; 51 | } 52 | 53 | ul.HeroTechStack li a:hover { 54 | color: #d86613; 55 | } 56 | 57 | ul.HeroTechStack { 58 | padding: 0; 59 | } 60 | 61 | .Hero { 62 | width: 100%; 63 | margin: auto; 64 | } 65 | 66 | .Hero h1 { 67 | font-weight: 300; 68 | font-size: 3em; 69 | letter-spacing: 5px; 70 | } 71 | 72 | .Hero h6 { 73 | margin-bottom: 10px; 74 | text-transform: uppercase; 75 | } 76 | 77 | .Hero p { 78 | text-transform: none; 79 | } 80 | 81 | /* Center CSS */ 82 | 83 | .Header, 84 | .Usage, 85 | .Charts, 86 | .Sidebar, 87 | .Footer, 88 | .HeroContainer { 89 | font-family: Roboto; 90 | font-weight: 300; 91 | text-transform: uppercase; 92 | letter-spacing: 1px; 93 | display: grid; 94 | justify-content: center; 95 | align-items: center; 96 | border-radius: 20px; 97 | background-color: whitesmoke; 98 | box-shadow: 9px 9px 16px rgb(163, 177, 198, 0.2), 99 | -9px -9px 16px rgba(255, 255, 255, 0.3); 100 | height: 100%; 101 | } 102 | 103 | .Nav { 104 | display: grid; 105 | grid-template-columns: 160px 1fr; 106 | grid-template-rows: 1fr; 107 | gap: 0px 0px; 108 | grid-template-areas: ". . ."; 109 | grid-area: Nav; 110 | border-radius: 20px; 111 | background: whitesmoke; 112 | box-shadow: 9px 9px 16px rgb(163, 177, 198, 0.2), 113 | -9px -9px 16px rgba(255, 255, 255, 0.3); 114 | } 115 | 116 | .Logo { 117 | font-family: Roboto; 118 | font-weight: 300; 119 | text-transform: uppercase; 120 | letter-spacing: 3px; 121 | display: grid; 122 | justify-content: center; 123 | align-items: center; 124 | } 125 | 126 | .LumosLogoBox { 127 | display: flex; 128 | justify-content: center; 129 | align-items: center; 130 | } 131 | 132 | .LumosLogoBox h2 { 133 | font-weight: 300; 134 | letter-spacing: 2px; 135 | } 136 | 137 | .LumosLogo { 138 | height: 100%; 139 | width: 150%; 140 | } 141 | 142 | .LumosLogoBox img { 143 | max-height: 70px; 144 | max-width: 100px; 145 | } 146 | 147 | .Login { 148 | background: #efc9ef; 149 | padding: 10px; 150 | color: white; 151 | font-family: Roboto; 152 | font-weight: 300; 153 | letter-spacing: 2px; 154 | margin-right: 20px; 155 | border-radius: 15px; 156 | } 157 | 158 | .loginButton { 159 | background: #d86613 !important; 160 | color: white !important; 161 | } 162 | 163 | .ButtonContainer { 164 | display: flex; 165 | justify-self: flex-end; 166 | } 167 | 168 | .SidebarButtonContainer { 169 | display: grid; 170 | } 171 | 172 | .LumosButton { 173 | font-family: Roboto !important; 174 | font-weight: 400 !important; 175 | letter-spacing: 2px !important; 176 | background-color: white !important; 177 | display: grid !important; 178 | justify-self: center !important; 179 | align-self: center !important; 180 | height: 45px !important; 181 | margin-right: 20px !important; 182 | border-radius: 25px !important; 183 | padding: 0px 40px !important; 184 | box-shadow: 1px 0px 20px #00000008; 185 | color: #4d4d4d !important; 186 | } 187 | 188 | .LumosButton:hover { 189 | box-shadow: 1px 0px 20px #d8661394; 190 | transition: 1.5s; 191 | } 192 | 193 | .timeButtonContainer { 194 | display: flex; 195 | } 196 | 197 | .LoginModal { 198 | margin: auto; 199 | display: grid; 200 | justify-self: center; 201 | align-self: center; 202 | text-align: center; 203 | background: white; 204 | height: 50vh; 205 | width: 85vw; 206 | } 207 | 208 | .ModalButton { 209 | font-family: Roboto !important; 210 | font-weight: 400 !important; 211 | letter-spacing: 2px !important; 212 | background-color: #d86613 !important; 213 | height: 45px !important; 214 | border-radius: 25px !important; 215 | padding: 0px 40px !important; 216 | box-shadow: 1px 0px 20px #00000008; 217 | color: #ffffff !important; 218 | } 219 | 220 | .ModalButton:hover { 221 | box-shadow: 1px 0px 20px #d8661394; 222 | transition: 1.5s; 223 | } 224 | 225 | .usageChartContainer { 226 | height: 85%; 227 | width: 42vh; 228 | } 229 | 230 | .latencyChartContainer { 231 | height: 80%; 232 | width: 50vw; 233 | } 234 | 235 | .Header { 236 | grid-area: Header; 237 | } 238 | 239 | .Metrics { 240 | grid-template-columns: 1fr 1fr; 241 | grid-template-rows: 1fr 1fr; 242 | gap: 20px; 243 | grid-template-areas: 244 | "Active-Functions Total-Errors" 245 | "Avg-Cost Avg-Duration"; 246 | grid-area: Metrics; 247 | font-family: Roboto; 248 | font-weight: 300; 249 | text-transform: uppercase; 250 | letter-spacing: 1px; 251 | display: grid; 252 | justify-content: center; 253 | align-items: center; 254 | height: 100%; 255 | } 256 | 257 | .metricCard { 258 | font-family: Roboto; 259 | font-weight: 300; 260 | text-transform: uppercase; 261 | letter-spacing: 1px; 262 | display: grid; 263 | justify-content: center; 264 | align-items: center; 265 | border-radius: 20px; 266 | background-color: whitesmoke; 267 | box-shadow: 9px 9px 16px rgb(163, 177, 198, 0.2), 268 | -9px -9px 16px rgba(255, 255, 255, 0.3); 269 | grid-template-columns: 1fr 1fr 1fr; 270 | grid-template-areas: "Stats Stats cardIcon"; 271 | gap: 0px; 272 | height: 100%; 273 | overflow: hidden; 274 | } 275 | 276 | .iconWrapper { 277 | display: flex; 278 | max-height: 5em; 279 | } 280 | 281 | /* .metricContainer { 282 | } */ 283 | 284 | .cardStats { 285 | grid-area: Stats; 286 | justify-self: center; 287 | } 288 | .statsNumber, 289 | .cardPercentage { 290 | display: flex; 291 | justify-content: center; 292 | align-items: stretch; 293 | padding: 2px; 294 | overflow: hidden; 295 | } 296 | 297 | .statsNumber { 298 | font-size: 28px; 299 | } 300 | 301 | .cardIcon { 302 | grid-area: cardIcon; 303 | } 304 | 305 | .Usage { 306 | grid-area: Usage; 307 | } 308 | .Charts { 309 | grid-area: Charts; 310 | } 311 | .Errors { 312 | grid-template-columns: 1fr; 313 | gap: 0px 0px; 314 | grid-area: Errors; 315 | font-family: Roboto; 316 | font-weight: 300; 317 | text-transform: uppercase; 318 | letter-spacing: 3px; 319 | display: grid; 320 | border-radius: 20px; 321 | background-color: whitesmoke; 322 | box-shadow: 9px 9px 16px rgb(163, 177, 198, 0.2), 323 | -9px -9px 16px rgba(255, 255, 255, 0.3); 324 | height: 100%; 325 | } 326 | 327 | .errorsContainer { 328 | padding: 20px; 329 | /* overflow: scroll !important; */ 330 | } 331 | 332 | .errHeader { 333 | font-family: Roboto; 334 | font-weight: 300; 335 | font-size: 12px; 336 | margin: 0px 0px 10px 0px !important; 337 | padding: 10px 10px; 338 | box-shadow: 1px 0px 15px #00000015; 339 | border-radius: 15px; 340 | } 341 | 342 | .Errors.children { 343 | background-color: whitesmoke; 344 | height: 100%; 345 | /* display: grid; */ 346 | /* overflow: scroll !important; */ 347 | } 348 | .errA, 349 | .errB { 350 | align-items: center; 351 | } 352 | .ErrorsChildrenContainer { 353 | border-bottom: 1px dotted rgba(0, 0, 0, 0.15); 354 | margin: 0px !important; 355 | padding: 10px 0px !important; 356 | overflow: hidden; 357 | /* text-align: center; */ 358 | } 359 | .Errors.Code, 360 | .Errors.Time, 361 | .Errors.Count { 362 | text-align: center !important; 363 | } 364 | 365 | .err { 366 | grid-area: err; 367 | } 368 | .start { 369 | grid-area: start; 370 | } 371 | .end { 372 | grid-area: end; 373 | } 374 | .type { 375 | grid-area: type; 376 | } 377 | .cost { 378 | grid-area: cost; 379 | } 380 | .rowErr { 381 | grid-area: rowErr; 382 | } 383 | .rowStart { 384 | grid-area: rowStart; 385 | } 386 | .rowEnd { 387 | grid-area: rowEnd; 388 | } 389 | .rowType { 390 | grid-area: rowType; 391 | } 392 | .rowCost { 393 | grid-area: rowCost; 394 | } 395 | 396 | .Sidebar { 397 | grid-area: Sidebar; 398 | align-items: baseline; 399 | /* overflow: scroll !important; 400 | height: 104.5% !important; */ 401 | } 402 | .sidebarLambda { 403 | padding-top: 20px; 404 | } 405 | 406 | .sidebarIcon { 407 | max-width: 30%; 408 | margin: 25px auto; 409 | border-radius: 50px; 410 | padding: 10px 12px; 411 | box-shadow: 1px 0px 15px #00000015; 412 | font-size: 12px; 413 | letter-spacing: 0px; 414 | text-align: center; 415 | } 416 | .sidebarIcon:hover { 417 | cursor: pointer; 418 | color: #d86613; 419 | background-color: #f3f3f3; 420 | box-shadow: 1px 0px 25px #00000015; 421 | transition: 1s; 422 | } 423 | 424 | .sideBarLottie { 425 | max-height: 40px; 426 | margin-top: -5px; 427 | } 428 | 429 | .sidebarIcon img { 430 | max-height: 35px; 431 | margin: auto; 432 | } 433 | 434 | .sidebarMainIcon { 435 | background: #d86613 !important; 436 | padding: 16px 13px; 437 | border-radius: 50px; 438 | text-align: center; 439 | width: 30%; 440 | margin: 10px auto 20px auto; 441 | } 442 | 443 | .Footer { 444 | grid-area: Footer; 445 | font-size: 12px; 446 | height: 80px; 447 | justify-content: normal; 448 | } 449 | 450 | .footer-inner-container { 451 | display: grid; 452 | grid-template-columns: 1fr 1fr 1fr; 453 | padding: 0px 30px; 454 | } 455 | 456 | .footer-left { 457 | text-align: left; 458 | } 459 | 460 | .footer-left a { 461 | color: gray; 462 | text-decoration: none; 463 | } 464 | 465 | .footer-left a:hover { 466 | color: #d86613; 467 | text-decoration: none; 468 | } 469 | .footer-right { 470 | text-align: right; 471 | } 472 | 473 | .footer-middle { 474 | text-align: center; 475 | } 476 | 477 | /* Metric Cards CSS */ 478 | 479 | .Active-Functions { 480 | grid-area: Active-Functions; 481 | } 482 | .Total-Errors { 483 | grid-area: Total-Errors; 484 | } 485 | .Avg-Cost { 486 | grid-area: Avg-Cost; 487 | } 488 | 489 | .superSet span { 490 | vertical-align: super; 491 | font-size: 50%; 492 | } 493 | 494 | .Avg-Duration { 495 | grid-area: Avg-Duration; 496 | } 497 | 498 | .Credentials { 499 | position: absolute; 500 | top: 50%; 501 | left: 50%; 502 | margin-right: -50%; 503 | transform: translate(-50%, -50%); 504 | border-radius: 50px; 505 | padding: 10px; 506 | } 507 | 508 | /* media query for 13"+ laptops with retina */ 509 | 510 | @media (min-width: 1921px) { 511 | .iconWrapper { 512 | max-height: 80px; 513 | } 514 | } 515 | 516 | /* 517 | 518 | 519 | 520 | query = 'INSERT into users hi' 521 | query = 'DELETE FROM users where id = ${id}' 522 | query = */ 523 | -------------------------------------------------------------------------------- /client/components/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Lumos/4c0a1009065e0991c74dd32847e52ce70d98f72f/client/components/.DS_Store -------------------------------------------------------------------------------- /client/components/Cards/MetricCard.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { 3 | Box, 4 | Card, 5 | CardContent, 6 | Divider, 7 | Typography, 8 | CardHeader, 9 | Badge, 10 | } from "@mui/material"; 11 | import Lottie from "lottie-react"; 12 | import lambdaFuncAnimation from "../../assets/lotties/lambda-funcs.json"; 13 | import errorsAnimation from "../../assets/lotties/errors.json"; 14 | import costAnimation from "../../assets/lotties/cost.json"; 15 | import durationAnimation from "../../assets/lotties/duration.json"; 16 | import { InfoContext } from "../../containers/MainContainer.jsx"; 17 | 18 | export default function MetricCard() { 19 | const [userInfo, setUserInfo] = useContext(InfoContext); 20 | return ( 21 | <> 22 | 23 |
24 |
{userInfo.lambdaActiveInvocations}
25 | {/*
+5%
*/} 26 |
Active Invocations
27 |
28 |
29 |
30 | 31 |
32 |
33 |
34 | 35 |
36 |
{userInfo.lambdaTotalErrors}
37 | {/*
+5%
*/} 38 |
Total Errors
39 |
40 |
41 |
42 | 43 |
44 |
45 |
46 | 47 |
48 |
49 | {userInfo.lambdaTotalCost.toFixed(10)} 50 |
51 | {/*
+5%
*/} 52 |
53 | Total Cost (10^3) 54 |
55 |
56 |
57 |
58 | 59 |
60 |
61 |
62 | 63 |
64 |
65 | {( 66 | userInfo.lambdaAvgDuration / userInfo.lambdaActiveInvocations 67 | ).toFixed(2)} 68 |
69 | {/*
+5%
*/} 70 |
Avg Duration (ms)
71 |
72 |
73 |
74 | 75 |
76 |
77 |
78 | 79 | ); 80 | } 81 | -------------------------------------------------------------------------------- /client/components/Charts.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable linebreak-style */ 2 | import React from "react"; 3 | import { Box } from "@mui/material"; 4 | import Latency from "../components/charts/Latency.jsx"; 5 | import LineChart from "../components/charts/TestChart.jsx"; 6 | 7 | function Charts() { 8 | return ( 9 | 10 |
11 | 12 |
13 |
14 | ); 15 | } 16 | 17 | export default Charts; 18 | -------------------------------------------------------------------------------- /client/components/Errors.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable linebreak-style */ 2 | import React, { useContext, useEffect } from "react"; 3 | import { Box, Grid } from "@mui/material"; 4 | import { InfoContext } from "../containers/MainContainer.jsx"; 5 | 6 | // :) 7 | function Errors() { 8 | const [userInfo] = useContext(InfoContext); 9 | let ar = []; 10 | 11 | for (let i = 0; i < userInfo.lambdaFuncs.length; i += 1) { 12 | const func = userInfo.lambdaFuncs[i]; 13 | const label = func.funcName; 14 | const value = func.totalErrors; 15 | const timestamp = func.formattedTimeStamps 16 | ? func.formattedTimeStamps[0] 17 | : 0; 18 | if (value > 0) { 19 | ar.push({ 20 | Label: label, 21 | Status: "500", 22 | Value: value, 23 | Timestamp: timestamp, 24 | }); 25 | } 26 | } 27 | return ( 28 | 29 |
30 | 31 | 32 | Label 33 | 34 | 40 | Errors 41 | 42 | 48 | Time 49 | 50 | 51 | 52 | {ar.map((a) => ( 53 | 60 | 66 | {a.Label} 67 | 68 | 74 | {a.Value} 75 | 76 | 82 | {a.Timestamp} 83 | 84 | 85 | ))} 86 |
87 |
88 | ); 89 | // 90 | } 91 | // new Date("August 6, 2022 13:30:30") <- needs to be sent to the backend 92 | const today = new Date(); 93 | let date = 94 | today.getMonth() + 95 | 1 + 96 | "-" + 97 | today.getDate() + 98 | "-" + 99 | today.getFullYear() + 100 | " T " + 101 | today.getHours() + 102 | ":" + 103 | today.getMinutes() + 104 | ":" + 105 | today.getSeconds(); 106 | /* 107 | label = function that was called 108 | value = amount of error/ less is best 109 | timestamp = when function status occurred 110 | */ 111 | 112 | const rows = [ 113 | { 114 | Label: "why", 115 | Status: "Complete", 116 | Value: 34, 117 | Timestamp: date, 118 | Cost: 4.0, 119 | }, 120 | { 121 | Label: "why", 122 | Status: "Complete", 123 | Value: 34, 124 | Timestamp: date, 125 | Cost: 4.0, 126 | }, 127 | { 128 | Label: "why", 129 | Status: "Complete", 130 | Value: 34, 131 | Timestamp: date, 132 | Cost: 4.0, 133 | }, 134 | ]; 135 | export default Errors; 136 | -------------------------------------------------------------------------------- /client/components/Footer.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable linebreak-style */ 2 | import React from "react"; 3 | import { Box } from "@mui/material"; 4 | 5 | function Footer() { 6 | return ( 7 | 8 |
9 |
10 | 11 | Github 12 | {" "} 13 | | LinkedIn{" "} 14 | | Medium 15 |
16 |
17 | Accelerated by OS Labs as an 18 | open-source project. 19 |
20 |
2022 © Lumos Tools
21 |
22 |
23 | ); 24 | } 25 | 26 | export default Footer; 27 | -------------------------------------------------------------------------------- /client/components/Header.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable linebreak-style */ 2 | import React from "react"; 3 | import { Grid, Box } from "@mui/material"; 4 | import DayButton from "./dayButton.jsx"; 5 | import WeekButton from "./weekButton.jsx"; 6 | import MonthButton from "./monthButton.jsx"; 7 | 8 | function Header() { 9 | return ( 10 | 11 | ); 12 | } 13 | 14 | export default Header; 15 | -------------------------------------------------------------------------------- /client/components/LandingPage.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, createContext, useContext } from "react"; 2 | import { Box, Paper } from "@mui/material"; 3 | import Login from "../components/Login.jsx"; 4 | import Sign from "../components/SignIn.jsx"; 5 | import Footer from "../components/Footer.jsx"; 6 | 7 | // lottie icons 8 | import Lottie from "lottie-react"; 9 | import landingAnimation from "../assets/lotties/landing.json"; 10 | 11 | export default function LandingPage() { 12 | return ( 13 | <> 14 | 15 | 16 |

Welcome to Lumos

17 |

18 |

About Lumos
19 | Lumos is an open-source offering that provides a solution by merging 20 | analytics with polished UI integrations to improve end-users 21 | interaction with Lambda metrics — resulting in a user-friendly 22 | experience. 23 |

24 |

25 |

59 |

60 |
61 | 62 |
63 | 64 | ); 65 | } 66 | -------------------------------------------------------------------------------- /client/components/Login.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable linebreak-style */ 2 | import React, { useState, setOpen, useContext } from "react"; 3 | import { Button, TextField, Modal, Slide } from "@mui/material"; 4 | import { InfoContext } from "../containers/MainContainer.jsx"; 5 | // import ModalUnstyled from '@mui/base/ModalUnstyled' 6 | 7 | export default function Login() { 8 | //modal state 9 | const [open, setOpen] = useState(false); 10 | const handleOpen = () => setOpen(true); 11 | const handleClose = () => setOpen(false); 12 | //container info 13 | const [userInfo, setUserInfo] = useContext(InfoContext); 14 | //register user state 15 | const [data, setData] = useState({ 16 | email: "", 17 | password: "", 18 | firstname: "", 19 | lastname: "", 20 | }); 21 | 22 | //register user handle change event 23 | const handleChange = (e) => { 24 | setData({ ...data, [e.target.name]: e.target.value }); 25 | }; 26 | 27 | //register user on submit 28 | const submitHandler = (e) => { 29 | e.preventDefault(); 30 | const { email, password, firstname, lastname } = data; 31 | if ( 32 | email === "" || 33 | password === "" || 34 | firstname === "" || 35 | lastname === "" 36 | ) { 37 | setData({ 38 | email: "", 39 | password: "", 40 | firstname: "", 41 | lastname: "", 42 | }); 43 | handleClose(); 44 | window.alert("Cannot process request. All fields need to be completed"); 45 | } 46 | if ( 47 | email !== "" && 48 | password !== "" && 49 | firstname !== "" && 50 | lastname !== "" 51 | ) { 52 | console.log("this is what you're getting back: ", data); 53 | window.alert( 54 | `Thanks for registering ${data.firstname}. Click anywhere to close.` 55 | ); 56 | 57 | const result = { 58 | email: email, 59 | password: password, 60 | firstname: firstname, 61 | lastname: lastname, 62 | }; 63 | 64 | // post to user endPoint passing result to DB 65 | fetch("/user/register", { 66 | method: "POST", 67 | headers: { 68 | "Content-Type": "application/json", 69 | }, 70 | body: JSON.stringify(result), 71 | }).then((h) => console.log("added", { h })); 72 | // */ 73 | 74 | handleClose(); 75 | } 76 | }; 77 | // onclick event makes a post request for register 78 | return ( 79 | <> 80 | 84 | 85 | 93 |
94 | 102 | 112 | 120 | 128 | 135 | 136 |
137 | 138 | ); 139 | } 140 | -------------------------------------------------------------------------------- /client/components/Metrics.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable linebreak-style */ 2 | import React from 'react'; 3 | import { Box } from '@mui/material'; 4 | import MetricCard from '../components/Cards/MetricCard.jsx' 5 | 6 | function Metrics() { 7 | return ( 8 | 9 | 10 | 11 | ); 12 | } 13 | 14 | export default Metrics; -------------------------------------------------------------------------------- /client/components/Nav.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable linebreak-style */ 2 | import React, { useContext } from "react"; 3 | import { Box } from "@mui/material"; 4 | import Login from "../components/Login.jsx"; 5 | import Sign from "../components/SignIn.jsx"; 6 | import Signout from "../components/Signout.jsx"; 7 | import { InfoContext } from "../containers/MainContainer.jsx"; 8 | 9 | function Nav() { 10 | const [userInfo, setUserInfo] = useContext(InfoContext); 11 | return ( 12 | 13 | 14 | 15 | 19 | 20 | 21 | {/* 22 | 23 | */} 24 | {userInfo.loggedIn === false ? ( 25 | <> 26 | 27 | 28 | 29 | 30 | 31 | ) : ( 32 | <> 33 | 34 | 35 |

36 | Welcome to Lumos {userInfo.first_name} {userInfo.last_name} 37 |

38 |
39 |
40 | 41 | 42 | 43 | 44 | )} 45 |
46 | ); 47 | } 48 | 49 | export default Nav; 50 | -------------------------------------------------------------------------------- /client/components/Sidebar.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable linebreak-style */ 2 | import React from "react"; 3 | import { Box, Button, Drawer, Typography } from "@mui/material"; 4 | 5 | // sidebar buttons 6 | import DayButton from "./dayButton.jsx"; 7 | import WeekButton from "./weekButton.jsx"; 8 | import MonthButton from "./monthButton.jsx"; 9 | 10 | // lottie icons 11 | import Lottie from "lottie-react"; 12 | import dashboardIcon from "../assets/lotties/dashboardIcon.json"; 13 | import alertIcon from "../assets/lotties/alertIcon.json"; 14 | import logsIcon from "../assets/lotties/logsIcon.json"; 15 | 16 | function Sidebar() { 17 | return ( 18 | 19 |
20 |
21 | 22 |
23 |
24 | 25 | 26 | 27 |
28 |
29 |
30 | ); 31 | } 32 | 33 | export default Sidebar; 34 | -------------------------------------------------------------------------------- /client/components/SignIn.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable linebreak-style */ 2 | import React, { useState, setOpen, useContext, useEffect } from "react"; 3 | import { Button, TextField, Modal } from "@mui/material"; 4 | import { InfoContext } from "../containers/MainContainer.jsx"; 5 | 6 | export default function Sign() { 7 | //use effect hook on successful login get all metrics 8 | const [userInfo, setUserInfo] = useContext(InfoContext); 9 | const [metrics, setMetrics] = useState([]); 10 | 11 | //modal state 12 | const [open, setOpen] = useState(false); 13 | const handleOpen = () => setOpen(true); 14 | const handleClose = () => setOpen(false); 15 | 16 | //register user state 17 | const [data, setData] = useState({ 18 | email: "", 19 | password: "", 20 | }); 21 | 22 | //register user handle change event 23 | const handleChange = (e) => { 24 | setData({ ...data, [e.target.name]: e.target.value }); 25 | }; 26 | 27 | // onclick event make a post request for login 28 | const submitHandler = (e) => { 29 | e.preventDefault(); 30 | 31 | //make a post request to somewhere with this data 32 | const { email, password } = data; 33 | 34 | const result = { 35 | email: email, 36 | password: password, 37 | }; 38 | 39 | fetch("/user/login", { 40 | method: "POST", 41 | headers: { 42 | "Content-Type": "application/json", 43 | }, 44 | body: JSON.stringify(result), 45 | }) 46 | .then((response) => response.json()) 47 | .then((loginData) => { 48 | const { verifiedUser, firstName, lastName } = loginData; 49 | 50 | if (verifiedUser == true) { 51 | window.alert(`You're signed in ${data.email}`); 52 | //set flag to true 53 | setUserInfo({ 54 | timePeriod: "day", 55 | loggedIn: true, 56 | user_name: "", 57 | first_name: firstName, 58 | last_name: lastName, 59 | user_id: "", 60 | lambdaFuncs: [ 61 | { 62 | funcName: "", 63 | totalInvocations: 0, 64 | totalErrors: 0, 65 | timeStamps: [], 66 | funcValues: [], 67 | }, 68 | ], 69 | lambdaActiveInvocations: 0, 70 | lambdaTotalErrors: 0, 71 | lambdaTotalCost: 0, 72 | lambdaAvgDuration: 0, 73 | }); 74 | } else { 75 | window.alert( 76 | "Email is not registered or the password is incorrect, please try again." 77 | ); 78 | } 79 | }) 80 | .catch((err) => console.log(err)); 81 | 82 | handleClose(); 83 | }; 84 | 85 | return ( 86 | <> 87 | 95 | 103 |
104 | 112 | 121 | 127 | 128 |
129 | 130 | ); 131 | } 132 | -------------------------------------------------------------------------------- /client/components/Signout.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, setOpen, useContext, useEffect } from "react"; 2 | import { Button, TextField, Modal } from "@mui/material"; 3 | import { InfoContext } from "../containers/MainContainer.jsx"; 4 | 5 | export default function Signout() { 6 | const [userInfo, setUserInfo] = useContext(InfoContext); 7 | const [metrics, setMetrics] = useState([]); 8 | 9 | //register user state 10 | const [data, setData] = useState({ 11 | email: "", 12 | password: "", 13 | }); 14 | 15 | //register user handle change event 16 | 17 | // onclick event make a post request for login 18 | const submitHandler = () => { 19 | setData({ 20 | email: "", 21 | password: "", 22 | }); 23 | localStorage.clear(); 24 | window.location.reload(); 25 | }; 26 | return ( 27 | 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /client/components/Usage.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable linebreak-style */ 2 | import React from "react"; 3 | import { Box } from "@mui/material"; 4 | import UsageDoughnut from "../components/charts/UsageDoughnut.jsx"; 5 | 6 | function Usage() { 7 | return ( 8 | 9 |
10 | 11 |
12 |
13 | ); 14 | } 15 | 16 | export default Usage; 17 | -------------------------------------------------------------------------------- /client/components/charts/Latency.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect } from "react"; 2 | import { InfoContext } from "../../containers/MainContainer.jsx"; 3 | 4 | import { Paper, Box, Typography } from "@mui/material"; 5 | import { 6 | Chart as ChartJS, 7 | CategoryScale, 8 | LinearScale, 9 | PointElement, 10 | LineElement, 11 | Title, 12 | Tooltip, 13 | Legend, 14 | } from "chart.js"; 15 | import { Line } from "react-chartjs-2"; 16 | // import moment from "moment"; 17 | 18 | ChartJS.register( 19 | CategoryScale, 20 | LinearScale, 21 | PointElement, 22 | LineElement, 23 | Title, 24 | Tooltip, 25 | Legend 26 | ); 27 | 28 | const options = { 29 | responsive: true, 30 | maintainAspectRatio: false, 31 | plugins: { 32 | legend: { 33 | position: "top", 34 | }, 35 | }, 36 | // scales: { 37 | // y: { 38 | // type: "time", 39 | // time: { 40 | // displayFormats: { 41 | // // 42 | // }, 43 | // }, 44 | // }, 45 | // x: { 46 | // type: "time", 47 | // time: { 48 | // displayFormats: { 49 | // // 50 | // }, 51 | // }, 52 | // }, 53 | // }, 54 | // }, 55 | }; 56 | // x-axis, this needs to be updated depending on the .length of the timestamps array 57 | 58 | // this all gets done AFTER state object has been populated from Login's successful verification 59 | // we'll need 3 buttons created at the Header for 24 Hour / 7 Day / 30 Day time frames that each make fetch calls with different start/end dates 60 | 61 | 62 | function Latency() { 63 | const [userInfo, setUserInfo] = useContext(InfoContext); 64 | 65 | console.log(userInfo); 66 | 67 | const labels = [ 68 | // "8/5", // 50 invocations 69 | // "8/6", 70 | // "8/7", 71 | // "8/8", 72 | // "8/9", 73 | // "8/10", 74 | // "8/11" 75 | ]; 76 | 77 | //lambdaMetrics: [], // { invocations: "", 78 | 79 | const data = { 80 | labels, 81 | datasets: [ 82 | // new datasets object needs to be created depending on how many Lambda funcs we get back 83 | // { 84 | // // update this name to lambda name 85 | // label: userInfo.lambdaFuncs[1].funcName, 86 | // // we gotta update array of values here 87 | // data: userInfo.lambdaFuncs[1].funcValues, 88 | // // let's change these weird ass colors xD okay;) ( ͡° ͜ʖ ͡°) 89 | // borderColor: "rgba(123, 31, 162)", 90 | // backgroundColor: "rgba(123, 31, 162, 0.5)", 91 | // borderWidth: 1, 92 | // }, 93 | // { 94 | // label: "us_east_func_multiply", 95 | // // ( ͡° ͜ʖ ͡°) 96 | // data: [1, 2, 4, 9, 4, 1, 5, 6, 4, 9, 5, 4, 1, 9], 97 | // borderColor: "rgb(255, 125, 69)", 98 | // backgroundColor: "rgb(255, 125, 69, 0.5)", 99 | // borderWidth: 1, 100 | // }, 101 | ], 102 | }; 103 | 104 | let testLabels = []; 105 | 106 | if (userInfo.timePeriod === "month") { 107 | const date = new Date(); 108 | const year = date.getFullYear(); 109 | const month = date.getMonth() + 1; 110 | const lastDay = new Date(year, month, 0).getDate(); 111 | 112 | for (let i = 1; i <= lastDay; i += 1) { 113 | testLabels.push(`${month}/${i}`); 114 | } 115 | 116 | data.labels = testLabels; 117 | } 118 | 119 | userInfo.lambdaFuncs.forEach((el) => { 120 | const borderColor = `rgb(${Math.floor(Math.random() * 256)}, ${Math.floor( 121 | Math.random() * 256 122 | )}, ${Math.floor(Math.random() * 256)})`; 123 | const backgroundColor = `rgba(${borderColor.slice( 124 | 4, 125 | borderColor.length - 1 126 | )}, 0.5)`; 127 | 128 | let resultArr = []; 129 | for (let x in Object.keys(data.labels)) { 130 | const keys = data.labels[x]; 131 | for (let y = 0; y < el.formattedTimeStamps.length; y++) { 132 | const time = el.formattedTimeStamps[y]; 133 | console.log( 134 | el.funcName, 135 | "looking @ timestamp", 136 | time, 137 | keys, 138 | "match ?", 139 | time === keys 140 | ); 141 | 142 | if (time === keys) { 143 | resultArr.push(10); 144 | } 145 | if (time !== keys) { 146 | resultArr.push(-1); 147 | } 148 | } 149 | } 150 | 151 | data.datasets.push({ 152 | label: el.funcName, 153 | data: [el.totalInvocations], 154 | borderColor: borderColor, 155 | backgroundColor: backgroundColor, 156 | borderWidth: 1, 157 | spanGaps: true, 158 | }); 159 | }); 160 | 161 | useEffect(() => {}, [userInfo]); 162 | 163 | return ; 164 | } 165 | 166 | export default Latency; 167 | -------------------------------------------------------------------------------- /client/components/charts/TestChart.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect } from "react"; 2 | import { InfoContext } from "../../containers/MainContainer.jsx"; 3 | import { 4 | Chart as ChartJS, 5 | CategoryScale, 6 | LinearScale, 7 | PointElement, 8 | LineElement, 9 | Title, 10 | Tooltip, 11 | Legend, 12 | TimeScale, 13 | } from "chart.js"; 14 | import { Line } from "react-chartjs-2"; 15 | import "chartjs-adapter-date-fns"; 16 | 17 | ChartJS.register( 18 | CategoryScale, 19 | LinearScale, 20 | PointElement, 21 | LineElement, 22 | Title, 23 | Tooltip, 24 | Legend, 25 | TimeScale 26 | ); 27 | 28 | function TestChart() { 29 | const [userInfo] = useContext(InfoContext); 30 | useEffect(() => {}, [userInfo]); 31 | 32 | const options = { 33 | responsive: true, 34 | maintainAspectRatio: false, 35 | plugins: { 36 | legend: { 37 | position: "top", 38 | }, 39 | }, 40 | scales: { 41 | yAxes: { 42 | beginAtZero: true, 43 | }, 44 | }, 45 | }; 46 | 47 | const date = new Date(); 48 | const year = date.getFullYear(); 49 | const month = date.getMonth(); 50 | const lastDay = new Date(year, month, 0).getDate(); 51 | 52 | const getLabels = () => { 53 | console.log("labels inside getLabels: ", labels); 54 | if (userInfo.timePeriod === "month") { 55 | return Array.from(Array(lastDay)).map((_, i) => 56 | new Date(year, month, (i += 1)).toLocaleDateString() 57 | ); 58 | } 59 | if (userInfo.timePeriod === "week") { 60 | const lastWeek = new Date(year, month, date.getDate()); 61 | const lastWeekArr = []; 62 | for (let i = 0; i < 7; i += 1) { 63 | const lastWeekDate = lastWeek.getDate(); 64 | lastWeekArr.push( 65 | new Date(year, month, lastWeekDate - i).toLocaleDateString() 66 | ); 67 | } 68 | return lastWeekArr.reverse(); 69 | } 70 | if (userInfo.timePeriod === "day") { 71 | const dayArr = []; 72 | 73 | for (let i = 0; i < 24; i++) { 74 | const date = new Date() - i * 3600 * 1000; 75 | dayArr.push( 76 | new Date(date).toLocaleTimeString([], { 77 | hour: "2-digit", 78 | }) 79 | ); 80 | } 81 | 82 | return dayArr.reverse(); 83 | } 84 | }; 85 | 86 | const labels = getLabels(); 87 | const datasets = []; 88 | 89 | for (let i = 0; i < userInfo.lambdaFuncs.length; i += 1) { 90 | const func = userInfo.lambdaFuncs[i]; 91 | const data = []; 92 | 93 | for (let i = 0; i < labels.length; i += 1) { 94 | const time = labels[i]; 95 | 96 | if (userInfo.timePeriod !== "day") { 97 | if (func.formattedTimeStamps.includes(time)) { 98 | let sum = 0; 99 | 100 | for (let i = 0; i < func.formattedTimeStamps.length; i++) { 101 | if (func.formattedTimeStamps[i] === time) { 102 | sum += func.invocationsArray[i]; 103 | } 104 | } 105 | 106 | data.push({ x: time, y: sum }); 107 | } else { 108 | data.push({ x: time, y: 0 }); 109 | } 110 | } else { 111 | if (func.formattedTime && func.formattedTime.includes(time)) { 112 | let sum = 0; 113 | 114 | for (let i = 0; i < func.formattedTime.length; i++) { 115 | if (func.formattedTime[i] === time) { 116 | sum += func.invocationsArray[i]; 117 | } 118 | } 119 | 120 | data.push({ x: time, y: sum }); 121 | } else { 122 | data.push({ x: time, y: 0 }); 123 | } 124 | } 125 | } 126 | 127 | const borderColor = `rgb(${Math.floor(Math.random() * 256)}, ${Math.floor( 128 | Math.random() * 256 129 | )}, ${Math.floor(Math.random() * 256)})`; 130 | const backgroundColor = `rgba(${borderColor.slice( 131 | 4, 132 | borderColor.length - 1 133 | )}, 0.5)`; 134 | 135 | datasets.push({ 136 | label: func.funcName, 137 | data: data, 138 | borderColor: borderColor, 139 | backgroundColor: backgroundColor, 140 | spanGaps: true, 141 | tension: 0.5, 142 | }); 143 | } 144 | 145 | console.log("datasets: ", datasets); 146 | const data = { 147 | labels: labels, 148 | datasets: datasets, 149 | }; 150 | 151 | return ; 152 | } 153 | 154 | export default TestChart; 155 | -------------------------------------------------------------------------------- /client/components/charts/UsageDoughnut.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { Chart as ChartJS, ArcElement, Tooltip, Legend } from "chart.js"; 3 | import { Doughnut } from "react-chartjs-2"; 4 | import { InfoContext } from "../../containers/MainContainer.jsx"; 5 | 6 | ChartJS.register(ArcElement, Tooltip, Legend); 7 | 8 | function UsageDoughnut() { 9 | const [userInfo, setUserInfo] = useContext(InfoContext); 10 | 11 | let funcNames = []; 12 | let funcInvocations = []; 13 | 14 | userInfo.lambdaFuncs.forEach((el) => { 15 | funcNames.push(el.funcName); 16 | funcInvocations.push(el.totalInvocations); 17 | }); 18 | 19 | const borderColor1 = `rgb(${Math.floor(Math.random() * 256)}, ${Math.floor( 20 | Math.random() * 256 21 | )}, ${Math.floor(Math.random() * 256)})`; 22 | 23 | const borderColor2 = `rgb(${Math.floor(Math.random() * 256)}, ${Math.floor( 24 | Math.random() * 256 25 | )}, ${Math.floor(Math.random() * 256)})`; 26 | 27 | const borderColor3 = `rgb(${Math.floor(Math.random() * 256)}, ${Math.floor( 28 | Math.random() * 256 29 | )}, ${Math.floor(Math.random() * 256)})`; 30 | 31 | const borderColor4 = `rgb(${Math.floor(Math.random() * 256)}, ${Math.floor( 32 | Math.random() * 256 33 | )}, ${Math.floor(Math.random() * 256)})`; 34 | 35 | const data = { 36 | labels: funcNames, 37 | datasets: [ 38 | { 39 | label: "# of Invocations", 40 | data: funcInvocations, 41 | backgroundColor: [ 42 | borderColor1, 43 | borderColor2, 44 | borderColor3, 45 | borderColor4, 46 | ], 47 | borderColor: [borderColor1, borderColor2, borderColor3, borderColor4], 48 | borderWidth: 1, 49 | }, 50 | ], 51 | }; 52 | 53 | const options = { 54 | responsive: true, 55 | maintainAspectRatio: false, 56 | plugins: { 57 | legend: { 58 | position: "top", 59 | }, 60 | }, 61 | }; 62 | 63 | return ; 64 | } 65 | 66 | export default UsageDoughnut; 67 | -------------------------------------------------------------------------------- /client/components/dateButton.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {FormControl, Button} from '@mui/material' 3 | 4 | export default function dateButton() { 5 | //needs an onchange handler for whatever button state we are looking at 6 | //form control is all about handling state I'm not sure if it's needed for the button. 7 | 8 | return ( 9 | 10 |
11 | 12 |
13 | ) 14 | } 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /client/components/dayButton.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect } from "react"; 2 | import { Button } from "@mui/material"; 3 | // gain access to context 4 | import { InfoContext } from "../containers/MainContainer.jsx"; 5 | 6 | // lottie icons 7 | import Lottie from "lottie-react"; 8 | import dashboardIcon from "../assets/lotties/dashboardIcon.json"; 9 | 10 | export default function DayButton() { 11 | const [userInfo, setUserInfo] = useContext(InfoContext); 12 | 13 | const submitHandler = (e) => { 14 | e.preventDefault(); 15 | let start = new Date(Math.round(new Date().getTime() - 24 * 3600 * 1000)); 16 | start.toISOString(); 17 | const end = new Date(); 18 | 19 | fetch("/metric", { 20 | method: "POST", 21 | headers: { "Content-Type": "application/json" }, 22 | body: JSON.stringify({ 23 | startTime: start, 24 | endTime: end, 25 | period: 60, 26 | }), 27 | }) 28 | .then((response) => response.json()) 29 | .then((data) => { 30 | console.log("RESPONSE DATA: ", data); 31 | console.log("RESPONSE DATA TYPE: ", typeof data); 32 | // update state obj with data values 33 | let activeInvocations = 0; 34 | let totalErrors = 0; 35 | let totalDuration = 0; 36 | let totalCost = 0; 37 | data.metrics.forEach((el) => { 38 | activeInvocations += el.totalInvocations; 39 | totalErrors += el.totalErrors; 40 | totalDuration += el.totalDuration; 41 | totalCost += el.totalCost; 42 | }); 43 | 44 | setUserInfo({ 45 | loggedIn: true, 46 | timePeriod: "day", 47 | lambdaFuncs: data.metrics, 48 | lambdaActiveInvocations: activeInvocations, 49 | lambdaTotalErrors: totalErrors, 50 | lambdaAvgThrottle: 41, 51 | lambdaTotalCost: totalCost, 52 | lambdaAvgDuration: totalDuration, 53 | }); 54 | }); 55 | return false; 56 | }; 57 | return ( 58 | <> 59 |
60 |
61 | 66 |
67 | Day 68 |
69 | 70 | ); 71 | } 72 | -------------------------------------------------------------------------------- /client/components/fetchMetrics.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable linebreak-style */ 2 | import React from 'react'; 3 | 4 | export default function GetAllMetrics() { 5 | return fetch('/metrics') 6 | .then(data => data.json()) 7 | } 8 | -------------------------------------------------------------------------------- /client/components/monthButton.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { Button } from "@mui/material"; 3 | import { InfoContext } from "../containers/MainContainer.jsx"; 4 | 5 | // lottie icons 6 | import Lottie from "lottie-react"; 7 | import dashboardIcon from "../assets/lotties/dashboardIcon.json"; 8 | 9 | export default function MonthButton() { 10 | const [userInfo, setUserInfo] = useContext(InfoContext); 11 | //run a fetch request to metric router time period 24hr 12 | let start = new Date( 13 | Math.round(new Date().getTime()) - 24 * 30 * 3600 * 1000 14 | ); 15 | start.toISOString(); 16 | const end = new Date(); 17 | //if userInfo.loggedIn !== return 'you must be signed in' else submithandler 18 | const submitHandler = (e) => { 19 | e.preventDefault(); 20 | fetch("/metric", { 21 | method: "POST", 22 | headers: { "Content-Type": "application/json" }, 23 | body: JSON.stringify({ startTime: start, endTime: end }), 24 | }) 25 | .then((response) => response.json()) 26 | .then((data) => { 27 | // update state obj with data values 28 | let activeInvocations = 0; 29 | let totalErrors = 0; 30 | let totalDuration = 0; 31 | let totalCost = 0; 32 | data.metrics.forEach((el) => { 33 | activeInvocations += el.totalInvocations; 34 | totalErrors += el.totalErrors; 35 | totalDuration += el.totalDuration; 36 | totalCost += el.totalCost; 37 | }); 38 | 39 | setUserInfo({ 40 | loggedIn: true, 41 | timePeriod: "month", 42 | lambdaFuncs: data.metrics, 43 | lambdaActiveInvocations: activeInvocations, 44 | lambdaTotalErrors: totalErrors, 45 | lambdaAvgThrottle: 41, 46 | lambdaTotalCost: totalCost, 47 | lambdaAvgDuration: totalDuration, 48 | }); 49 | }); 50 | }; 51 | return ( 52 |
53 |
54 | 59 |
60 | Month 61 |
62 | ); 63 | } 64 | -------------------------------------------------------------------------------- /client/components/weekButton.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { Button } from "@mui/material"; 3 | import { InfoContext } from "../containers/MainContainer.jsx"; 4 | 5 | // lottie icons 6 | import Lottie from "lottie-react"; 7 | import dashboardIcon from "../assets/lotties/dashboardIcon.json"; 8 | 9 | export default function WeekButton() { 10 | const [userInfo, setUserInfo] = useContext(InfoContext); 11 | 12 | //run a fetch request to metric router time period 24hr 13 | let start = new Date(Math.round(new Date().getTime()) - 24 * 7 * 3600 * 1000); 14 | start.toISOString(); 15 | const end = new Date(); 16 | const submitHandler = (e) => { 17 | e.preventDefault(); 18 | // fetch to metric endpoint 19 | fetch("/metric", { 20 | method: "POST", 21 | headers: { "Content-Type": "application/json" }, 22 | body: JSON.stringify({ startTime: start, endTime: end, period: 86400 }), 23 | }) 24 | .then((response) => response.json()) 25 | .then((data) => { 26 | let activeInvocations = 0; 27 | let totalErrors = 0; 28 | let totalDuration = 0; 29 | let totalCost = 0; 30 | data.metrics.forEach((el) => { 31 | activeInvocations += el.totalInvocations; 32 | totalErrors += el.totalErrors; 33 | totalDuration += el.totalDuration; 34 | totalCost += el.totalCost; 35 | }); 36 | 37 | setUserInfo({ 38 | loggedIn: true, 39 | timePeriod: "week", 40 | lambdaFuncs: data.metrics, 41 | lambdaActiveInvocations: activeInvocations, 42 | lambdaTotalErrors: totalErrors, 43 | lambdaAvgThrottle: 41, 44 | lambdaTotalCost: totalCost, 45 | lambdaAvgDuration: totalDuration, 46 | }); 47 | }); 48 | }; 49 | return ( 50 |
51 |
52 | 57 |
58 | Week 59 |
60 | ); 61 | } 62 | -------------------------------------------------------------------------------- /client/containers/MainContainer.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable linebreak-style */ 2 | import React, { useState, useEffect, createContext, useContext } from "react"; 3 | import { Grid, Box } from "@mui/material"; 4 | import Header from "../components/Header.jsx"; 5 | import Footer from "../components/Footer.jsx"; 6 | import Nav from "../components/Nav.jsx"; 7 | import Sidebar from "../components/Sidebar.jsx"; 8 | import Metrics from "../components/Metrics.jsx"; 9 | // import MetricCard from '../components/Cards/MetricCard.jsx'; 10 | import Usage from "../components/Usage.jsx"; 11 | import Charts from "../components/Charts.jsx"; 12 | import Errors from "../components/Errors.jsx"; 13 | import Landing from "../components/LandingPage.jsx"; 14 | // import Card from '@mui/material'; 15 | import "../assets/styles.css"; 16 | // import '../assets/outerContainer.css'; 17 | 18 | import TestChart from "../components/charts/TestChart.jsx"; 19 | 20 | export const InfoContext = createContext(); 21 | 22 | function MainContainer() { 23 | // const [userInfo, setUserInfo] = useContext(InfoContext); 24 | 25 | const [userInfo, setUserInfo] = useState({ 26 | loggedIn: false, 27 | user_name: "", 28 | first_name: "", 29 | last_name: "", 30 | user_id: "", 31 | timePeriod: "day", 32 | lambdaFuncs: [ 33 | { 34 | funcName: "", 35 | totalInvocations: 0, 36 | totalErrors: 0, 37 | timeStamps: [], 38 | funcValues: [], 39 | invocationsArray: [], 40 | formattedTimeStamps: [], 41 | formattedTime: [], 42 | }, 43 | ], 44 | lambdaActiveInvocations: 0, 45 | lambdaTotalErrors: 0, 46 | lambdaAvgDuration: 0, 47 | lambdaTotalCost: 0, 48 | }); 49 | 50 | useEffect(() => console.log("Current State", userInfo), [userInfo]); 51 | 52 | return ( 53 | //implement grid template outer container 54 | 55 | {userInfo.loggedIn === false ? ( 56 | <> 57 | 58 |