├── .gitattributes ├── .gitignore ├── .vscode ├── launch.json └── settings.json ├── LICENCE ├── README.md ├── autocoder-api ├── go.mod ├── go.sum ├── main.go └── obd.go └── ui ├── .browserslistrc ├── .editorconfig ├── .gitignore ├── README.md ├── angular.json ├── karma.conf.js ├── license.txt ├── main.js ├── package-lock.json ├── package.json ├── src ├── app │ ├── app-routing.module.ts │ ├── app.component.html │ ├── app.component.scss │ ├── app.component.spec.ts │ ├── app.component.ts │ ├── app.module.ts │ ├── components │ │ └── round-gauge │ │ │ ├── round-gauge.component.html │ │ │ ├── round-gauge.component.scss │ │ │ ├── round-gauge.component.spec.ts │ │ │ └── round-gauge.component.ts │ ├── home │ │ ├── home.component.html │ │ ├── home.component.scss │ │ ├── home.component.spec.ts │ │ └── home.component.ts │ ├── material │ │ └── material.module.ts │ ├── services │ │ ├── menu.service.spec.ts │ │ ├── menu.service.ts │ │ ├── storage.service.spec.ts │ │ └── storage.service.ts │ └── settings │ │ ├── settings.component.html │ │ ├── settings.component.scss │ │ ├── settings.component.spec.ts │ │ └── settings.component.ts ├── assets │ ├── .gitkeep │ ├── ezConsoleLogo.png │ └── pr.svg ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── main.ts ├── polyfills.ts ├── styles.scss └── test.ts ├── tsconfig.app.json ├── tsconfig.json └── tsconfig.spec.json /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | autocoder-api/__debug_bin.exe 3 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch file", 9 | "type": "go", 10 | "request": "launch", 11 | "mode": "debug", 12 | "program": "${workspaceFolder}/autocoder-api/main.go" 13 | }, 14 | { 15 | "type": "pwa-chrome", 16 | "request": "launch", 17 | "name": "Launch Chrome against localhost", 18 | "url": "http://localhost:4200", 19 | "webRoot": "${workspaceFolder}/ui" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "git.ignoreLimitWarning": true, 3 | "cSpell.words": [ 4 | "autocoder" 5 | ] 6 | } -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AutoCoder 2 | An open source in car head unit 3 | 4 | ## Getting Started 5 | To start the app run 6 | 7 | ~~~ 8 | go run autocoder-api/main.go 9 | ~~~ 10 | 11 | To start the OBD connection send a POST request to 12 | ~~~ 13 | 127.0.0.1:8080/start-obd 14 | ~~~ 15 | 16 | To get car data send a GET request to 17 | ~~~ 18 | 127.0.0.1:8080/all-car-data 19 | ~~~ 20 | 21 | ### For OBD connection 22 | This project uses a modified version of https://github.com/rzetterberg/elmobd 23 | As the library for talking to the ELM OBD device 24 | 25 | Can be tested by running elm emulator 26 | https://github.com/Ircama/ELM327-emulator 27 | ~~~ 28 | python -m elm -s car -n 35000 -l 29 | ~~~ 30 | -------------------------------------------------------------------------------- /autocoder-api/go.mod: -------------------------------------------------------------------------------- 1 | module autocoder-api 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/gorilla/mux v1.8.0 7 | github.com/greenchapel-dev/elmobd v0.0.0-20230328063457-dcececf7697b 8 | ) 9 | 10 | require ( 11 | github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 // indirect 12 | golang.org/x/sys v0.6.0 // indirect 13 | ) 14 | -------------------------------------------------------------------------------- /autocoder-api/go.sum: -------------------------------------------------------------------------------- 1 | github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= 2 | github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= 3 | github.com/greenchapel-dev/elmobd v0.0.0-20230328063457-dcececf7697b h1:8lCfdPENP4t1Qv5G+t6TmwcBj2eVqYwDLx8vepNiGcI= 4 | github.com/greenchapel-dev/elmobd v0.0.0-20230328063457-dcececf7697b/go.mod h1:wDYc9dS0ygPlCjUyggPsIyG7sPp1lo0u36ps45IoCbA= 5 | github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 h1:UyzmZLoiDWMRywV4DUYb9Fbt8uiOSooupjTq10vpvnU= 6 | github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= 7 | golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= 8 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 9 | -------------------------------------------------------------------------------- /autocoder-api/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | // "autocoder-api/obd_device" 5 | "encoding/json" 6 | "flag" 7 | "fmt" 8 | "net/http" 9 | "time" 10 | 11 | "github.com/gorilla/mux" 12 | "github.com/greenchapel-dev/elmobd" // modified from https://github.com/rzetterberg/elmobd 13 | ) 14 | 15 | // Struct for holding all the data from the car and for returning as json 16 | type CarData struct { 17 | RPM string `json:"rpm"` 18 | CoolantTemp string `json:"coolantTemp"` 19 | } 20 | 21 | var obdDevice *elmobd.Device 22 | var rpm *elmobd.EngineRPM 23 | var carData CarData 24 | var obdRunning = false 25 | var addr *string 26 | var debug *bool 27 | 28 | // Create the API layer 29 | func createAPI() { 30 | r := mux.NewRouter() 31 | // all data from the car 32 | r.HandleFunc("/all-car-data", GetCarData).Methods("GET") 33 | r.HandleFunc("/start-obd", PostStartOBD).Methods("POST") 34 | http.ListenAndServe(":8080", r) 35 | } 36 | 37 | // Get all the data from the car 38 | func GetCarData(w http.ResponseWriter, r *http.Request) { 39 | w.Header().Set("Content-Type", "application/json") 40 | if obdRunning == false { 41 | // status not ok 42 | w.WriteHeader(http.StatusNotFound) 43 | } else { 44 | w.WriteHeader(http.StatusOK) 45 | json.NewEncoder(w).Encode(carData) 46 | } 47 | } 48 | 49 | // function with post request to start the obd 50 | func PostStartOBD(w http.ResponseWriter, r *http.Request) { 51 | w.Header().Set("Content-Type", "application/json") 52 | if obdRunning == false { 53 | // start the obd 54 | obdRunning = true 55 | // Create a new device 56 | dev, err := elmobd.NewDevice(*addr, *debug) 57 | if err != nil { 58 | fmt.Println("error", err) 59 | return 60 | } 61 | obdDevice = dev 62 | 63 | // Create the API 64 | // checkSupportedObdCommands() 65 | go getFastData() 66 | go getSlowData() 67 | w.WriteHeader(http.StatusOK) 68 | } else { 69 | // obd already running 70 | w.WriteHeader(http.StatusNotFound) 71 | } 72 | } 73 | 74 | // MAIN 75 | func main() { 76 | // command line flags 77 | addr = flag.String( 78 | "addr", 79 | // "test:///dev/ttyUSB0", 80 | // "tcp://127.0.0.1:35000", 81 | "serial:///dev/ttyS3", 82 | "Address of the ELM327 device to use (use either test://, tcp://ip:port or serial:///dev/ttyS0)", 83 | ) 84 | debug = flag.Bool( 85 | "debug", 86 | true, 87 | "Enable debug outputs", 88 | ) 89 | flag.Parse() 90 | 91 | // start the API layer 92 | createAPI() 93 | } 94 | 95 | // / move to own file 96 | // Check the car has these commands 97 | func checkSupportedObdCommands() { 98 | supported, err := obdDevice.CheckSupportedCommands() 99 | 100 | if err != nil { 101 | fmt.Println("Failed to check supported commands", err) 102 | return 103 | } 104 | 105 | rpm = elmobd.NewEngineRPM() 106 | 107 | if supported.IsSupported(rpm) { 108 | fmt.Println("The car supports checking RPM") 109 | } else { 110 | fmt.Println("The car does NOT supports checking RPM") 111 | } 112 | } 113 | 114 | // Thread for getting the fast data from the car on a regular interval 115 | func getFastData() { 116 | // create a ticker for every 100ms 117 | ticker := time.NewTicker(500 * time.Millisecond) 118 | // run forever 119 | for { 120 | select { 121 | case <-ticker.C: 122 | // get the rpm 123 | GetRPM() 124 | } 125 | } 126 | } 127 | 128 | // Thread for getting the slow data from the car on a regular interval 129 | func getSlowData() { 130 | // create a ticker for every 1000ms 131 | ticker := time.NewTicker(2000 * time.Millisecond) 132 | // run forever 133 | for { 134 | select { 135 | case <-ticker.C: 136 | // get the rpm 137 | GetCoolantTemp() 138 | } 139 | } 140 | } 141 | 142 | // Get RPM 143 | func GetRPM() string { 144 | rpm = elmobd.NewEngineRPM() 145 | rmpRes, err := obdDevice.RunOBDCommand(rpm) 146 | if err != nil { 147 | fmt.Println("error", err) 148 | return "error: " + err.Error() 149 | } 150 | rpmVal := rmpRes.ValueAsLit() 151 | carData.RPM = rpmVal 152 | return rpmVal 153 | } 154 | 155 | // Get Engine coolent temp 156 | func GetCoolantTemp() string { 157 | coolantTemp := elmobd.NewCoolantTemperature() 158 | coolantTempRes, err := obdDevice.RunOBDCommand(coolantTemp) 159 | if err != nil { 160 | fmt.Println("error", err) 161 | return "error: " + err.Error() 162 | } 163 | coolantTempVal := coolantTempRes.ValueAsLit() 164 | carData.CoolantTemp = coolantTempVal 165 | return coolantTempVal 166 | } 167 | -------------------------------------------------------------------------------- /autocoder-api/obd.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // modified from https://github.com/rzetterberg/elmobd 4 | 5 | // // Check the car has these commands 6 | // func checkSupportedObdCommands() { 7 | // supported, err := obdDevice.CheckSupportedCommands() 8 | 9 | // if err != nil { 10 | // fmt.Println("Failed to check supported commands", err) 11 | // return 12 | // } 13 | 14 | // rpm = elmobd.NewEngineRPM() 15 | 16 | // if supported.IsSupported(rpm) { 17 | // fmt.Println("The car supports checking RPM") 18 | // } else { 19 | // fmt.Println("The car does NOT supports checking RPM") 20 | // } 21 | // } 22 | 23 | // // Thread for getting the fast data from the car on a regular interval 24 | // func getFastData() { 25 | // // create a ticker for every 100ms 26 | // ticker := time.NewTicker(100 * time.Millisecond) 27 | // // run forever 28 | // for { 29 | // select { 30 | // case <-ticker.C: 31 | // // get the rpm 32 | // GetRPM() 33 | // } 34 | // } 35 | // } 36 | 37 | // // Thread for getting the slow data from the car on a regular interval 38 | // func getSlowData() { 39 | // // create a ticker for every 1000ms 40 | // ticker := time.NewTicker(1000 * time.Millisecond) 41 | // // run forever 42 | // for { 43 | // select { 44 | // case <-ticker.C: 45 | // // get the rpm 46 | // GetCoolantTemp() 47 | // } 48 | // } 49 | // } 50 | 51 | // // Get RPM 52 | // func GetRPM() string { 53 | // rpm = elmobd.NewEngineRPM() 54 | // rmpRes, err := obdDevice.RunOBDCommand(rpm) 55 | // if err != nil { 56 | // fmt.Println("error", err) 57 | // return "error: " + err.Error() 58 | // } 59 | // rpmVal := rmpRes.ValueAsLit() 60 | // carData.RPM = rpmVal 61 | // return rpmVal 62 | // } 63 | 64 | // // Get Engine coolent temp 65 | // func GetCoolantTemp() string { 66 | // coolantTemp := elmobd.NewCoolantTemperature() 67 | // coolantTempRes, err := obdDevice.RunOBDCommand(coolantTemp) 68 | // if err != nil { 69 | // fmt.Println("error", err) 70 | // return "error: " + err.Error() 71 | // } 72 | // coolantTempVal := coolantTempRes.ValueAsLit() 73 | // carData.CoolantTemp = coolantTempVal 74 | // return coolantTempVal 75 | // } 76 | -------------------------------------------------------------------------------- /ui/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line. 18 | -------------------------------------------------------------------------------- /ui/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /ui/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events*.json 15 | 16 | # IDEs and editors 17 | /.idea 18 | .project 19 | .classpath 20 | .c9/ 21 | *.launch 22 | .settings/ 23 | *.sublime-workspace 24 | 25 | # IDE - VSCode 26 | .vscode/* 27 | !.vscode/settings.json 28 | !.vscode/tasks.json 29 | !.vscode/launch.json 30 | !.vscode/extensions.json 31 | .history/* 32 | 33 | # misc 34 | /.sass-cache 35 | /connect.lock 36 | /coverage 37 | /libpeerconnection.log 38 | npm-debug.log 39 | yarn-error.log 40 | testem.log 41 | /typings 42 | 43 | # System Files 44 | .DS_Store 45 | Thumbs.db 46 | -------------------------------------------------------------------------------- /ui/README.md: -------------------------------------------------------------------------------- 1 | # AutoCoderApp 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.2.7. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. 28 | -------------------------------------------------------------------------------- /ui/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "AutoCoderApp": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:component": { 10 | "style": "scss" 11 | }, 12 | "@schematics/angular:application": { 13 | "strict": true 14 | } 15 | }, 16 | "root": "", 17 | "sourceRoot": "src", 18 | "prefix": "app", 19 | "architect": { 20 | "build": { 21 | "builder": "@angular-devkit/build-angular:browser", 22 | "options": { 23 | "outputPath": "dist/AutoCoderApp", 24 | "index": "src/index.html", 25 | "main": "src/main.ts", 26 | "polyfills": "src/polyfills.ts", 27 | "tsConfig": "tsconfig.app.json", 28 | "inlineStyleLanguage": "scss", 29 | "assets": [ 30 | "src/favicon.ico", 31 | "src/assets" 32 | ], 33 | "styles": [ 34 | "src/styles.scss" 35 | ], 36 | "scripts": [] 37 | }, 38 | "configurations": { 39 | "production": { 40 | "budgets": [ 41 | { 42 | "type": "initial", 43 | "maximumWarning": "2mb", 44 | "maximumError": "300mb" 45 | }, 46 | { 47 | "type": "anyComponentStyle", 48 | "maximumWarning": "2kb", 49 | "maximumError": "400kb" 50 | } 51 | ], 52 | "fileReplacements": [ 53 | { 54 | "replace": "src/environments/environment.ts", 55 | "with": "src/environments/environment.prod.ts" 56 | } 57 | ], 58 | "outputHashing": "all" 59 | }, 60 | "development": { 61 | "buildOptimizer": false, 62 | "optimization": false, 63 | "vendorChunk": true, 64 | "extractLicenses": false, 65 | "sourceMap": true, 66 | "namedChunks": true 67 | } 68 | }, 69 | "defaultConfiguration": "production" 70 | }, 71 | "serve": { 72 | "builder": "@angular-devkit/build-angular:dev-server", 73 | "configurations": { 74 | "production": { 75 | "browserTarget": "AutoCoderApp:build:production" 76 | }, 77 | "development": { 78 | "browserTarget": "AutoCoderApp:build:development" 79 | } 80 | }, 81 | "defaultConfiguration": "development" 82 | }, 83 | "extract-i18n": { 84 | "builder": "@angular-devkit/build-angular:extract-i18n", 85 | "options": { 86 | "browserTarget": "AutoCoderApp:build" 87 | } 88 | }, 89 | "test": { 90 | "builder": "@angular-devkit/build-angular:karma", 91 | "options": { 92 | "main": "src/test.ts", 93 | "polyfills": "src/polyfills.ts", 94 | "tsConfig": "tsconfig.spec.json", 95 | "karmaConfig": "karma.conf.js", 96 | "inlineStyleLanguage": "scss", 97 | "assets": [ 98 | "src/favicon.ico", 99 | "src/assets" 100 | ], 101 | "styles": [ 102 | "src/styles.scss" 103 | ], 104 | "scripts": [] 105 | } 106 | } 107 | } 108 | } 109 | }, 110 | "defaultProject": "AutoCoderApp" 111 | } 112 | -------------------------------------------------------------------------------- /ui/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | jasmine: { 17 | // you can add configuration options for Jasmine here 18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html 19 | // for example, you can disable the random execution with `random: false` 20 | // or set a specific seed with `seed: 4321` 21 | }, 22 | clearContext: false // leave Jasmine Spec Runner output visible in browser 23 | }, 24 | jasmineHtmlReporter: { 25 | suppressAll: true // removes the duplicated traces 26 | }, 27 | coverageReporter: { 28 | dir: require('path').join(__dirname, './coverage/AutoCoderApp'), 29 | subdir: '.', 30 | reporters: [ 31 | { type: 'html' }, 32 | { type: 'text-summary' } 33 | ] 34 | }, 35 | reporters: ['progress', 'kjhtml'], 36 | port: 9876, 37 | colors: true, 38 | logLevel: config.LOG_INFO, 39 | autoWatch: true, 40 | browsers: ['Chrome'], 41 | singleRun: false, 42 | restartOnFileChange: true 43 | }); 44 | }; 45 | -------------------------------------------------------------------------------- /ui/license.txt: -------------------------------------------------------------------------------- 1 | End-User License Agreement ("Agreement") 2 | = 3 | 4 | Last updated: May 12, 2022 5 | 6 | Please read this End-User License Agreement carefully before clicking the "I 7 | Agree" button, downloading or using AutoCoder. 8 | 9 | Interpretation and Definitions 10 | ============================== 11 | 12 | Interpretation 13 | -------------- 14 | 15 | The words of which the initial letter is capitalized have meanings defined 16 | under the following conditions. The following definitions shall have the same 17 | meaning regardless of whether they appear in singular or in plural. 18 | 19 | Definitions 20 | ----------- 21 | 22 | For the purposes of this End-User License Agreement: 23 | 24 | * Agreement means this End-User License Agreement that forms the entire 25 | agreement between You and the Company regarding the use of the 26 | Application. This Agreement has been created with the help of the [EULA 27 | Generator](https://www.termsfeed.com/eula-generator/). 28 | 29 | * Application means the software program provided by the Company downloaded 30 | by You to a Device, named GreenChapel Dev 31 | 32 | * Company (referred to as either "the Company", "We", "Us" or "Our" in this 33 | Agreement) refers to GreenChapel Dev, Cambridge, UK. 34 | 35 | * Content refers to content such as text, images, or other information that 36 | can be posted, uploaded, linked to or otherwise made available by You, 37 | regardless of the form of that content. 38 | 39 | * Country refers to: United Kingdom 40 | 41 | * Device means any device that can access the Application such as a 42 | computer, a cellphone or a digital tablet. 43 | 44 | * Third-Party Services means any services or content (including data, 45 | information, applications and other products services) provided by a 46 | third-party that may be displayed, included or made available by the 47 | Application. 48 | 49 | * You means the individual accessing or using the Application or the 50 | company, or other legal entity on behalf of which such individual is 51 | accessing or using the Application, as applicable. 52 | 53 | 54 | Acknowledgment 55 | ============== 56 | 57 | By clicking the "I Agree" button, downloading or using the Application, You 58 | are agreeing to be bound by the terms and conditions of this Agreement. If You 59 | do not agree to the terms of this Agreement, do not click on the "I Agree" 60 | button, do not download or do not use the Application. 61 | 62 | This Agreement is a legal document between You and the Company and it governs 63 | your use of the Application made available to You by the Company. 64 | 65 | The Application is licensed, not sold, to You by the Company for use strictly 66 | in accordance with the terms of this Agreement. 67 | 68 | License 69 | ======= 70 | 71 | Scope of License 72 | ---------------- 73 | 74 | The Company grants You a revocable, non-exclusive, non-transferable, limited 75 | license to download, install and use the Application strictly in accordance 76 | with the terms of this Agreement. 77 | 78 | The license that is granted to You by the Company is solely for your personal, 79 | non-commercial purposes strictly in accordance with the terms of this 80 | Agreement. 81 | 82 | Third-Party Services 83 | ==================== 84 | 85 | The Application may display, include or make available third-party content 86 | (including data, information, applications and other products services) or 87 | provide links to third-party websites or services. 88 | 89 | You acknowledge and agree that the Company shall not be responsible for any 90 | Third-party Services, including their accuracy, completeness, timeliness, 91 | validity, copyright compliance, legality, decency, quality or any other aspect 92 | thereof. The Company does not assume and shall not have any liability or 93 | responsibility to You or any other person or entity for any Third-party 94 | Services. 95 | 96 | You must comply with applicable Third parties' Terms of agreement when using 97 | the Application. Third-party Services and links thereto are provided solely as 98 | a convenience to You and You access and use them entirely at your own risk and 99 | subject to such third parties' Terms and conditions. 100 | 101 | Term and Termination 102 | ==================== 103 | 104 | This Agreement shall remain in effect until terminated by You or the Company. 105 | The Company may, in its sole discretion, at any time and for any or no reason, 106 | suspend or terminate this Agreement with or without prior notice. 107 | 108 | This Agreement will terminate immediately, without prior notice from the 109 | Company, in the event that you fail to comply with any provision of this 110 | Agreement. You may also terminate this Agreement by deleting the Application 111 | and all copies thereof from your Device or from your computer. 112 | 113 | Upon termination of this Agreement, You shall cease all use of the Application 114 | and delete all copies of the Application from your Device. 115 | 116 | Termination of this Agreement will not limit any of the Company's rights or 117 | remedies at law or in equity in case of breach by You (during the term of this 118 | Agreement) of any of your obligations under the present Agreement. 119 | 120 | Indemnification 121 | =============== 122 | 123 | You agree to indemnify and hold the Company and its parents, subsidiaries, 124 | affiliates, officers, employees, agents, partners and licensors (if any) 125 | harmless from any claim or demand, including reasonable attorneys' fees, due 126 | to or arising out of your: (a) use of the Application; (b) violation of this 127 | Agreement or any law or regulation; or (c) violation of any right of a third 128 | party. 129 | 130 | No Warranties 131 | ============= 132 | 133 | The Application is provided to You "AS IS" and "AS AVAILABLE" and with all 134 | faults and defects without warranty of any kind. To the maximum extent 135 | permitted under applicable law, the Company, on its own behalf and on behalf 136 | of its affiliates and its and their respective licensors and service 137 | providers, expressly disclaims all warranties, whether express, implied, 138 | statutory or otherwise, with respect to the Application, including all implied 139 | warranties of merchantability, fitness for a particular purpose, title and 140 | non-infringement, and warranties that may arise out of course of dealing, 141 | course of performance, usage or trade practice. Without limitation to the 142 | foregoing, the Company provides no warranty or undertaking, and makes no 143 | representation of any kind that the Application will meet your requirements, 144 | achieve any intended results, be compatible or work with any other software, 145 | applications, systems or services, operate without interruption, meet any 146 | performance or reliability standards or be error free or that any errors or 147 | defects can or will be corrected. 148 | 149 | Without limiting the foregoing, neither the Company nor any of the company's 150 | provider makes any representation or warranty of any kind, express or implied: 151 | (i) as to the operation or availability of the Application, or the 152 | information, content, and materials or products included thereon; (ii) that 153 | the Application will be uninterrupted or error-free; (iii) as to the accuracy, 154 | reliability, or currency of any information or content provided through the 155 | Application; or (iv) that the Application, its servers, the content, or 156 | e-mails sent from or on behalf of the Company are free of viruses, scripts, 157 | trojan horses, worms, malware, timebombs or other harmful components. 158 | 159 | Some jurisdictions do not allow the exclusion of certain types of warranties 160 | or limitations on applicable statutory rights of a consumer, so some or all of 161 | the above exclusions and limitations may not apply to You. But in such a case 162 | the exclusions and limitations set forth in this section shall be applied to 163 | the greatest extent enforceable under applicable law. To the extent any 164 | warranty exists under law that cannot be disclaimed, the Company shall be 165 | solely responsible for such warranty. 166 | 167 | Limitation of Liability 168 | ======================= 169 | 170 | Notwithstanding any damages that You might incur, the entire liability of the 171 | Company and any of its suppliers under any provision of this Agreement and 172 | your exclusive remedy for all of the foregoing shall be limited to the amount 173 | actually paid by You for the Application or through the Application or 100 USD 174 | if You haven't purchased anything through the Application. 175 | 176 | To the maximum extent permitted by applicable law, in no event shall the 177 | Company or its suppliers be liable for any special, incidental, indirect, or 178 | consequential damages whatsoever (including, but not limited to, damages for 179 | loss of profits, loss of data or other information, for business interruption, 180 | for personal injury, loss of privacy arising out of or in any way related to 181 | the use of or inability to use the Application, third-party software and/or 182 | third-party hardware used with the Application, or otherwise in connection 183 | with any provision of this Agreement), even if the Company or any supplier has 184 | been advised of the possibility of such damages and even if the remedy fails 185 | of its essential purpose. 186 | 187 | Some states/jurisdictions do not allow the exclusion or limitation of 188 | incidental or consequential damages, so the above limitation or exclusion may 189 | not apply to You. 190 | 191 | Severability and Waiver 192 | ======================= 193 | 194 | Severability 195 | ------------ 196 | 197 | If any provision of this Agreement is held to be unenforceable or invalid, 198 | such provision will be changed and interpreted to accomplish the objectives of 199 | such provision to the greatest extent possible under applicable law and the 200 | remaining provisions will continue in full force and effect. 201 | 202 | Waiver 203 | ------ 204 | 205 | Except as provided herein, the failure to exercise a right or to require 206 | performance of an obligation under this Agreement shall not effect a party's 207 | ability to exercise such right or require such performance at any time 208 | thereafter nor shall the waiver of a breach constitute a waiver of any 209 | subsequent breach. 210 | 211 | Product Claims 212 | ============== 213 | 214 | The Company does not make any warranties concerning the Application. 215 | 216 | United States Legal Compliance 217 | ============================== 218 | 219 | You represent and warrant that (i) You are not located in a country that is 220 | subject to the United States government embargo, or that has been designated 221 | by the United States government as a "terrorist supporting" country, and (ii) 222 | You are not listed on any United States government list of prohibited or 223 | restricted parties. 224 | 225 | Changes to this Agreement 226 | ========================= 227 | 228 | The Company reserves the right, at its sole discretion, to modify or replace 229 | this Agreement at any time. If a revision is material we will provide at least 230 | 30 days' notice prior to any new terms taking effect. What constitutes a 231 | material change will be determined at the sole discretion of the Company. 232 | 233 | By continuing to access or use the Application after any revisions become 234 | effective, You agree to be bound by the revised terms. If You do not agree to 235 | the new terms, You are no longer authorized to use the Application. 236 | 237 | Governing Law 238 | ============= 239 | 240 | The laws of the Country, excluding its conflicts of law rules, shall govern 241 | this Agreement and your use of the Application. Your use of the Application 242 | may also be subject to other local, state, national, or international laws. 243 | 244 | Entire Agreement 245 | ================ 246 | 247 | The Agreement constitutes the entire agreement between You and the Company 248 | regarding your use of the Application and supersedes all prior and 249 | contemporaneous written or oral agreements between You and the Company. 250 | 251 | You may be subject to additional terms and conditions that apply when You use 252 | or purchase other Company's services, which the Company will provide to You at 253 | the time of such use or purchase. 254 | 255 | Contact Us 256 | ========== 257 | 258 | If you have any questions about this Agreement, You can contact Us: 259 | 260 | * By email: greenchapeljohn@gmail.com 261 | 262 | * By visiting this page on our website: 263 | [greenchapeljohn@gmail.com](greenchapeljohn@gmail.com) 264 | 265 | 266 | -------------------------------------------------------------------------------- /ui/main.js: -------------------------------------------------------------------------------- 1 | 2 | const { app, BrowserWindow } = require('electron') 3 | 4 | let win; 5 | 6 | function createWindow () { 7 | // Create the browser window. 8 | // require('@electron/remote/main').initialize() 9 | 10 | win = new BrowserWindow({ 11 | width: 711, 12 | height: 500, 13 | icon: `file://${__dirname}/dist/assets/logo.png` 14 | }) 15 | 16 | win.loadURL(`file://${__dirname}/dist/AutoCoderApp/index.html`) 17 | 18 | // uncomment below to open the DevTools. 19 | // win.webContents.openDevTools() 20 | 21 | // Event when the window is closed. 22 | win.on('closed', function () { 23 | win = null 24 | }) 25 | 26 | win.setMenu(null); 27 | } 28 | 29 | // Create window on electron intialization 30 | app.on('ready', createWindow) 31 | 32 | // Quit when all windows are closed. 33 | app.on('window-all-closed', function () { 34 | 35 | // On macOS specific close process 36 | if (process.platform !== 'darwin') { 37 | app.quit() 38 | } 39 | }) 40 | 41 | app.on('activate', function () { 42 | // macOS specific close process 43 | if (win === null) { 44 | createWindow() 45 | } 46 | }) 47 | 48 | // for updates later 49 | // https://www.electronjs.org/docs/latest/tutorial/updates 50 | -------------------------------------------------------------------------------- /ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AutoCoderApp", 3 | "productName": "AutoCoder", 4 | "description": "Ui for AutoCoder, a head unit display application for your car", 5 | "version": "0.1.0", 6 | "main": "main.js", 7 | "author": "Mr. Green ", 8 | "copyright": "© 2022, GreenChapel Dev.", 9 | "homepage": "http://greenchapel.dev", 10 | "scripts": { 11 | "ng": "ng", 12 | "start": "ng serve", 13 | "build": "ng build", 14 | "watch": "ng build --watch --configuration development", 15 | "test": "ng test", 16 | "electron": "electron .", 17 | "electron-build": "ng build --prod && npm run electron .", 18 | "electron-build-installer": "electron-builder" 19 | }, 20 | "build": { 21 | "appId": "AutoCoder", 22 | "files": [ 23 | "**/*", 24 | "dist/**/*" 25 | ], 26 | "directories": { 27 | "buildResources": "dist" 28 | }, 29 | "win": { 30 | "target": [ 31 | "nsis" 32 | ], 33 | "icon": "src/favicon.ico" 34 | }, 35 | "nsis": { 36 | "installerIcon": "src/favicon.ico", 37 | "uninstallerIcon": "src/favicon.ico", 38 | "uninstallDisplayName": "AutoCoder", 39 | "license": "license.txt", 40 | "oneClick": false, 41 | "allowToChangeInstallationDirectory": true 42 | } 43 | }, 44 | "private": true, 45 | "dependencies": { 46 | "@angular/animations": "~12.2.0", 47 | "@angular/cdk": "^12.2.8", 48 | "@angular/common": "~12.2.0", 49 | "@angular/compiler": "~12.2.0", 50 | "@angular/core": "~12.2.0", 51 | "@angular/forms": "~12.2.0", 52 | "@angular/material": "^12.2.8", 53 | "@angular/platform-browser": "~12.2.0", 54 | "@angular/platform-browser-dynamic": "~12.2.0", 55 | "@angular/router": "~12.2.0", 56 | "@aws-sdk/client-cloudformation": "^3.85.0", 57 | "@aws-sdk/client-cloudwatch": "^3.118.1", 58 | "@aws-sdk/client-cloudwatch-logs": "^3.118.1", 59 | "@aws-sdk/client-codecommit": "^3.34.0", 60 | "@ionic/storage-angular": "^3.0.6", 61 | "angular-diff-match-patch": "github:amweiss/angular-diff-match-patch", 62 | "aws-regions": "^2.3.1", 63 | "chart.js": "^4.2.1", 64 | "dynamic-mat-table": "^1.4.16", 65 | "lodash": "^4.17.21", 66 | "ngx-text-diff": "^0.6.0", 67 | "rxjs": "~6.6.0", 68 | "tslib": "^2.3.0", 69 | "zone.js": "~0.11.4" 70 | }, 71 | "devDependencies": { 72 | "electron-builder": "^22.14.13", 73 | "@angular-devkit/build-angular": "~12.2.7", 74 | "@angular/cli": "~12.2.7", 75 | "@angular/compiler-cli": "~12.2.0", 76 | "@types/diff-match-patch": "^1.0.32", 77 | "@types/jasmine": "~3.8.0", 78 | "@types/lodash": "^4.14.180", 79 | "@types/node": "^12.11.1", 80 | "electron": "^15.0.0", 81 | "electron-packager": "^15.4.0", 82 | "jasmine-core": "~3.8.0", 83 | "karma": "~6.3.0", 84 | "karma-chrome-launcher": "~3.1.0", 85 | "karma-coverage": "~2.0.3", 86 | "karma-jasmine": "~4.0.0", 87 | "karma-jasmine-html-reporter": "~1.7.0", 88 | "typescript": "~4.3.5" 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /ui/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { Component, NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { HomeComponent } from './home/home.component'; 4 | import { SettingsComponent } from './settings/settings.component'; 5 | 6 | 7 | const routes: Routes = [ 8 | { 9 | path: '', 10 | redirectTo: '/home', 11 | pathMatch: 'full' 12 | }, 13 | { 14 | path: 'home', 15 | component: HomeComponent, 16 | data: {authenticated: false, menuName: 'Home', menuIcon: 'home', mainMenu: true} 17 | }, 18 | 19 | 20 | { 21 | path: 'settings', 22 | component: SettingsComponent, 23 | data: {authenticated: true, menuName: 'Settings', menuIcon: 'account_circle', mainMenu: true} 24 | }, 25 | 26 | { 27 | path: '**', 28 | redirectTo: '' 29 | }, 30 | 31 | ]; 32 | 33 | @NgModule({ 34 | imports: [RouterModule.forRoot(routes)], 35 | exports: [RouterModule] 36 | }) 37 | export class AppRoutingModule { } 38 | -------------------------------------------------------------------------------- /ui/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 12 |
13 | 14 | 15 | 39 | 40 | 41 | 42 |
43 | 44 |
45 | 46 |
47 |
48 | 51 |
52 |
53 | 54 |
55 |
56 |
57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /ui/src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | 2 | .main { 3 | height: 100vh; 4 | width: 100vw; 5 | } 6 | 7 | .content { 8 | height: auto; 9 | border-radius: 10px; 10 | margin: 16px; 11 | margin-left: 32px; 12 | margin-top: 35px; 13 | 14 | display: flex; 15 | justify-content: center; 16 | align-items: center; 17 | font-size: 20px; 18 | } 19 | 20 | 21 | 22 | .sideButton { 23 | width: auto; 24 | padding-left: 8px; 25 | } 26 | .sideTopSection { 27 | width: auto; 28 | } 29 | 30 | .expandedBtn { 31 | width: auto; 32 | padding-left: 8px; 33 | padding-right: 10px; 34 | } 35 | 36 | .settingsBtn { 37 | position: absolute; 38 | top:2px; 39 | right: 0px 40 | } 41 | 42 | .logoCont { 43 | position: absolute; 44 | top: 10px; 45 | left: 10px; 46 | z-index: 2; 47 | } 48 | 49 | 50 | 51 | @media (max-width: 750px) { 52 | .content { 53 | margin-left: 16px; 54 | } 55 | 56 | .back { 57 | left: 16px; 58 | } 59 | } 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /ui/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async () => { 7 | await TestBed.configureTestingModule({ 8 | imports: [ 9 | RouterTestingModule 10 | ], 11 | declarations: [ 12 | AppComponent 13 | ], 14 | }).compileComponents(); 15 | }); 16 | 17 | it('should create the app', () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.componentInstance; 20 | expect(app).toBeTruthy(); 21 | }); 22 | 23 | it(`should have as title 'AutoCoderApp'`, () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | const app = fixture.componentInstance; 26 | expect(app.title).toEqual('AutoCoderApp'); 27 | }); 28 | 29 | it('should render title', () => { 30 | const fixture = TestBed.createComponent(AppComponent); 31 | fixture.detectChanges(); 32 | const compiled = fixture.nativeElement as HTMLElement; 33 | expect(compiled.querySelector('.content span')?.textContent).toContain('AutoCoderApp app is running!'); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /ui/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import { StorageService } from 'src/app/services/storage.service'; 4 | import {Location} from '@angular/common'; 5 | import { MatIconRegistry } from "@angular/material/icon"; 6 | import { DomSanitizer } from '@angular/platform-browser'; 7 | import { MenuIF, MenuService } from './services/menu.service'; 8 | 9 | @Component({ 10 | selector: 'app-root', 11 | templateUrl: './app.component.html', 12 | styleUrls: ['./app.component.scss'] 13 | }) 14 | export class AppComponent implements OnInit { 15 | sidenavOpened = false; 16 | title = 'AutoCoderApp'; 17 | 18 | 19 | menus: MenuIF[] = []; 20 | 21 | constructor(private router: Router, 22 | private storageService: StorageService, 23 | private location: Location, 24 | private matIconRegistry: MatIconRegistry, 25 | private domSanitizer: DomSanitizer, 26 | private menuService: MenuService, 27 | ) { 28 | this.router.navigate(['']); 29 | 30 | this.matIconRegistry.addSvgIcon( 31 | "git-pull-request", 32 | this.domSanitizer.bypassSecurityTrustResourceUrl("assets/pr.svg") 33 | ); 34 | 35 | 36 | } 37 | 38 | async ngOnInit(): Promise { 39 | console.log('init app') 40 | // start the storage service first 41 | await this.storageService.init(); 42 | this.menus = await this.menuService.init(); 43 | 44 | } 45 | 46 | async ngAfterViewInit() { 47 | 48 | } 49 | 50 | toggleSideNav() { 51 | this.sidenavOpened = !this.sidenavOpened; 52 | } 53 | 54 | OnGotoSettings() { 55 | this.router.navigate(['/settings']); 56 | } 57 | 58 | OnBack() { 59 | this.location.back() 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /ui/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { HttpClientModule } from '@angular/common/http'; 2 | import { NgModule } from '@angular/core'; 3 | import { BrowserModule } from '@angular/platform-browser'; 4 | import { IonicStorageModule } from '@ionic/storage-angular'; 5 | import { NgxTextDiffModule } from 'ngx-text-diff'; 6 | 7 | import { AppRoutingModule } from './app-routing.module'; 8 | import { AppComponent } from './app.component'; 9 | import { MaterialModule } from './material/material.module'; 10 | import { SettingsComponent } from './settings/settings.component'; 11 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 12 | import { HomeComponent } from './home/home.component'; 13 | import { RoundGaugeComponent } from './components/round-gauge/round-gauge.component'; 14 | 15 | 16 | @NgModule({ 17 | declarations: [ 18 | AppComponent, 19 | SettingsComponent, 20 | HomeComponent, 21 | RoundGaugeComponent 22 | ], 23 | imports: [ 24 | BrowserModule, 25 | AppRoutingModule, 26 | MaterialModule, 27 | HttpClientModule, 28 | IonicStorageModule.forRoot(), 29 | NgxTextDiffModule, 30 | BrowserAnimationsModule, 31 | ], 32 | providers: [], 33 | bootstrap: [AppComponent], 34 | exports: [MaterialModule] 35 | }) 36 | export class AppModule { } 37 | -------------------------------------------------------------------------------- /ui/src/app/components/round-gauge/round-gauge.component.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenchapel-dev/AutoCoder/fd386def4446c7700432a199067a6e529974a28d/ui/src/app/components/round-gauge/round-gauge.component.html -------------------------------------------------------------------------------- /ui/src/app/components/round-gauge/round-gauge.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenchapel-dev/AutoCoder/fd386def4446c7700432a199067a6e529974a28d/ui/src/app/components/round-gauge/round-gauge.component.scss -------------------------------------------------------------------------------- /ui/src/app/components/round-gauge/round-gauge.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { RoundGaugeComponent } from './round-gauge.component'; 4 | 5 | describe('RoundGaugeComponent', () => { 6 | let component: RoundGaugeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ RoundGaugeComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(RoundGaugeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /ui/src/app/components/round-gauge/round-gauge.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-round-gauge', 5 | templateUrl: './round-gauge.component.html', 6 | styleUrls: ['./round-gauge.component.scss'] 7 | }) 8 | export class RoundGaugeComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ui/src/app/home/home.component.html: -------------------------------------------------------------------------------- 1 | Home Page Works! 2 | 3 | -------------------------------------------------------------------------------- /ui/src/app/home/home.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenchapel-dev/AutoCoder/fd386def4446c7700432a199067a6e529974a28d/ui/src/app/home/home.component.scss -------------------------------------------------------------------------------- /ui/src/app/home/home.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HomeComponent } from './home.component'; 4 | 5 | describe('HomeComponent', () => { 6 | let component: HomeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ HomeComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(HomeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /ui/src/app/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnDestroy, OnInit } from '@angular/core'; 2 | 3 | 4 | @Component({ 5 | selector: 'app-home', 6 | templateUrl: './home.component.html', 7 | styleUrls: ['./home.component.scss'] 8 | }) 9 | export class HomeComponent implements OnInit, OnDestroy { 10 | 11 | constructor() { } 12 | 13 | 14 | async ngOnInit(): Promise { 15 | 16 | } 17 | 18 | ngOnDestroy(): void { 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ui/src/app/material/material.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {A11yModule} from '@angular/cdk/a11y'; 3 | import {ClipboardModule} from '@angular/cdk/clipboard'; 4 | import {DragDropModule} from '@angular/cdk/drag-drop'; 5 | import {PortalModule} from '@angular/cdk/portal'; 6 | import {ScrollingModule} from '@angular/cdk/scrolling'; 7 | import {CdkStepperModule} from '@angular/cdk/stepper'; 8 | import {CdkTableModule} from '@angular/cdk/table'; 9 | import {CdkTreeModule} from '@angular/cdk/tree'; 10 | import {MatAutocompleteModule} from '@angular/material/autocomplete'; 11 | import {MatBadgeModule} from '@angular/material/badge'; 12 | import {MatBottomSheetModule} from '@angular/material/bottom-sheet'; 13 | import {MatButtonModule} from '@angular/material/button'; 14 | import {MatButtonToggleModule} from '@angular/material/button-toggle'; 15 | import {MatCardModule} from '@angular/material/card'; 16 | import {MatCheckboxModule} from '@angular/material/checkbox'; 17 | import {MatChipsModule} from '@angular/material/chips'; 18 | import {MatStepperModule} from '@angular/material/stepper'; 19 | import {MatDatepickerModule} from '@angular/material/datepicker'; 20 | import {MatDialogModule} from '@angular/material/dialog'; 21 | import {MatDividerModule} from '@angular/material/divider'; 22 | import {MatExpansionModule} from '@angular/material/expansion'; 23 | import {MatGridListModule} from '@angular/material/grid-list'; 24 | import {MatIconModule} from '@angular/material/icon'; 25 | import {MatInputModule} from '@angular/material/input'; 26 | import {MatListModule} from '@angular/material/list'; 27 | import {MatMenuModule} from '@angular/material/menu'; 28 | import {MatNativeDateModule, MatRippleModule} from '@angular/material/core'; 29 | import {MatPaginatorModule} from '@angular/material/paginator'; 30 | import {MatProgressBarModule} from '@angular/material/progress-bar'; 31 | import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; 32 | import {MatRadioModule} from '@angular/material/radio'; 33 | import {MatSelectModule} from '@angular/material/select'; 34 | import {MatSidenavModule} from '@angular/material/sidenav'; 35 | import {MatSliderModule} from '@angular/material/slider'; 36 | import {MatSlideToggleModule} from '@angular/material/slide-toggle'; 37 | import {MatSnackBarModule} from '@angular/material/snack-bar'; 38 | import {MatSortModule} from '@angular/material/sort'; 39 | import {MatTableModule} from '@angular/material/table'; 40 | import {MatTabsModule} from '@angular/material/tabs'; 41 | import {MatToolbarModule} from '@angular/material/toolbar'; 42 | import {MatTooltipModule} from '@angular/material/tooltip'; 43 | import {MatTreeModule} from '@angular/material/tree'; 44 | import {OverlayModule} from '@angular/cdk/overlay'; 45 | import {FormsModule, ReactiveFormsModule} from '@angular/forms'; 46 | 47 | @NgModule({ 48 | exports: [ 49 | A11yModule, 50 | ClipboardModule, 51 | CdkStepperModule, 52 | CdkTableModule, 53 | CdkTreeModule, 54 | DragDropModule, 55 | MatAutocompleteModule, 56 | MatBadgeModule, 57 | MatBottomSheetModule, 58 | MatButtonModule, 59 | MatButtonToggleModule, 60 | MatCardModule, 61 | MatCheckboxModule, 62 | MatChipsModule, 63 | MatStepperModule, 64 | MatDatepickerModule, 65 | MatDialogModule, 66 | MatDividerModule, 67 | MatExpansionModule, 68 | MatGridListModule, 69 | MatIconModule, 70 | MatInputModule, 71 | MatListModule, 72 | MatMenuModule, 73 | MatNativeDateModule, 74 | MatPaginatorModule, 75 | MatProgressBarModule, 76 | MatProgressSpinnerModule, 77 | MatRadioModule, 78 | MatRippleModule, 79 | MatSelectModule, 80 | MatSidenavModule, 81 | MatSliderModule, 82 | MatSlideToggleModule, 83 | MatSnackBarModule, 84 | MatSortModule, 85 | MatTableModule, 86 | MatTabsModule, 87 | MatToolbarModule, 88 | MatTooltipModule, 89 | MatTreeModule, 90 | OverlayModule, 91 | PortalModule, 92 | ScrollingModule, 93 | FormsModule, 94 | ReactiveFormsModule 95 | ] 96 | }) 97 | export class MaterialModule {} 98 | 99 | -------------------------------------------------------------------------------- /ui/src/app/services/menu.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { MenuService } from './menu.service'; 4 | 5 | describe('MenuService', () => { 6 | let service: MenuService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(MenuService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /ui/src/app/services/menu.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | 4 | export interface MenuIF { 5 | path: string; 6 | name: string; 7 | tool: string; 8 | menuIcon: string; 9 | svgIcon: boolean; 10 | } 11 | 12 | @Injectable({ 13 | providedIn: 'root' 14 | }) 15 | export class MenuService { 16 | mainMenuItems: MenuIF[] = []; 17 | 18 | constructor(private router: Router) { 19 | } 20 | 21 | init() { 22 | this.mainMenuItems = []; 23 | console.log('configured routes: ', this.router.config); 24 | this.router.config.forEach(route => { 25 | if ( route.data === undefined) { 26 | return; 27 | } 28 | else { 29 | if( route.data.mainMenu) { 30 | const newManuItem: MenuIF = { 31 | name: route.data.menuName, 32 | menuIcon: route.data.menuIcon, 33 | svgIcon: route.data.svgIcon === true, 34 | path: route.path!, 35 | tool: route.data.tool, 36 | }; 37 | this.mainMenuItems.push(newManuItem); 38 | } 39 | } 40 | 41 | }); 42 | console.log('main menus: ', this.mainMenuItems); 43 | return this.mainMenuItems; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ui/src/app/services/storage.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { StorageService } from './storage.service'; 4 | 5 | describe('StorageService', () => { 6 | let service: StorageService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(StorageService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /ui/src/app/services/storage.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | import { Storage } from '@ionic/storage-angular'; 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class StorageService { 9 | private _storage: Storage | null = null; 10 | 11 | constructor(private storage: Storage) { 12 | } 13 | 14 | async init() { 15 | // If using, define drivers here: await this.storage.defineDriver(/*...*/); 16 | const storage = await this.storage.create(); 17 | this._storage = storage; 18 | } 19 | 20 | // Create and expose methods that users of this service can 21 | // call, for example: 22 | public set(key: string, value: any) { 23 | this._storage?.set(key, value); 24 | } 25 | 26 | public get(key: string) { 27 | return this._storage?.get(key); 28 | } 29 | 30 | public remove(key: string) { 31 | this._storage?.remove(key); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ui/src/app/settings/settings.component.html: -------------------------------------------------------------------------------- 1 | Settings Works -------------------------------------------------------------------------------- /ui/src/app/settings/settings.component.scss: -------------------------------------------------------------------------------- 1 | .main{ 2 | display: flex; 3 | flex-direction: column; 4 | row-gap: 10px; 5 | max-width: 250px; 6 | } 7 | 8 | .credentials { 9 | max-width: 100%; 10 | button{ 11 | width: 100%; 12 | } 13 | } 14 | 15 | .settings { 16 | width: 100%; 17 | button{ 18 | width: 100%; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ui/src/app/settings/settings.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SettingsComponent } from './settings.component'; 4 | 5 | describe('SettingsComponent', () => { 6 | let component: SettingsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ SettingsComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SettingsComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /ui/src/app/settings/settings.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import { Subscription } from 'rxjs'; 4 | 5 | @Component({ 6 | selector: 'app-settings', 7 | templateUrl: './settings.component.html', 8 | styleUrls: ['./settings.component.scss'] 9 | }) 10 | export class SettingsComponent implements OnInit, OnDestroy { 11 | 12 | 13 | 14 | constructor(private router: Router) { 15 | 16 | } 17 | 18 | async ngOnInit(): Promise { 19 | } 20 | 21 | ngOnDestroy(): void { 22 | } 23 | 24 | Done() { 25 | this.router.navigate(['home']); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ui/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenchapel-dev/AutoCoder/fd386def4446c7700432a199067a6e529974a28d/ui/src/assets/.gitkeep -------------------------------------------------------------------------------- /ui/src/assets/ezConsoleLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenchapel-dev/AutoCoder/fd386def4446c7700432a199067a6e529974a28d/ui/src/assets/ezConsoleLogo.png -------------------------------------------------------------------------------- /ui/src/assets/pr.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /ui/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /ui/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenchapel-dev/AutoCoder/fd386def4446c7700432a199067a6e529974a28d/ui/src/favicon.ico -------------------------------------------------------------------------------- /ui/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AutoCoderApp 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /ui/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /ui/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** 22 | * IE11 requires the following for NgClass support on SVG elements 23 | */ 24 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 25 | 26 | /** 27 | * Web Animations `@angular/platform-browser/animations` 28 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 29 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 30 | */ 31 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 32 | 33 | /** 34 | * By default, zone.js will patch all possible macroTask and DomEvents 35 | * user can disable parts of macroTask/DomEvents patch by setting following flags 36 | * because those flags need to be set before `zone.js` being loaded, and webpack 37 | * will put import in the top of bundle, so user need to create a separate file 38 | * in this directory (for example: zone-flags.ts), and put the following flags 39 | * into that file, and then add the following code before importing zone.js. 40 | * import './zone-flags'; 41 | * 42 | * The flags allowed in zone-flags.ts are listed here. 43 | * 44 | * The following flags will work for all browsers. 45 | * 46 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 47 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 48 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 49 | * 50 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 51 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 52 | * 53 | * (window as any).__Zone_enable_cross_context_check = true; 54 | * 55 | */ 56 | 57 | /*************************************************************************************************** 58 | * Zone JS is required by default for Angular itself. 59 | */ 60 | import 'zone.js'; // Included with Angular CLI. 61 | 62 | 63 | /*************************************************************************************************** 64 | * APPLICATION IMPORTS 65 | */ 66 | -------------------------------------------------------------------------------- /ui/src/styles.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Generated theme by Material Theme Generator 3 | * https://materialtheme.arcsine.dev 4 | * Fork at: https://materialtheme.arcsine.dev/?c=YHBhbGV0dGU$YHByaW1hcnk$YF48IzJjMzk0YiIsIj9lcjwjYzBjNGM5IiwiO2VyPCMxYjI0MzN$LCIlPmBePCMwZWFkNDMiLCI~ZXI8I2I3ZTZjNyIsIjtlcjwjMDg5MzJjfiwid2Fybj5gXjwjZmY0YzI5IiwiP2VyPCNmZmM5YmYiLCI7ZXI8I2ZmMzMxOX4sIj9UZXh0PCMwMDAwMDAiLCI~PTwjZmFmYWZhIiwiO1RleHQ8I2ZmZmZmZiIsIjs9PCMzMzQ3NTZ$LCJmb250cz5bYEA8KC00fixgQDwoLTN$LGBAPCgtMn4sYEA8KC0xfixgQDxoZWFkbGluZX4sYEA8dGl0bGV$LGBAPHN1YiktMn4sYEA8c3ViKS0xfixgQDxib2R5LTJ$LGBAPGJvZHktMX4sYEA8YnV0dG9ufixgQDxjYXB0aW9ufixgQDxpbnB1dCIsInNpemU$bnVsbH1dLCJpY29uczxGaWxsZWQiLCI~bmVzcz5mYWxzZSwidmVyc2lvbj4xMX0= 5 | */ 6 | 7 | @import '~@angular/material/theming'; 8 | 9 | // Include the common styles for Angular Material. We include this here so that you only 10 | // have to load a single css file for Angular Material in your app. 11 | 12 | // Fonts 13 | @import 'https://fonts.googleapis.com/css?family=Material+Icons'; 14 | @import url('https://fonts.googleapis.com/css?family=Roboto:300,400,500'); 15 | 16 | $fontConfig: ( 17 | display-4: mat-typography-level(112px, 112px, 300, 'Roboto', -0.0134em), 18 | display-3: mat-typography-level(56px, 56px, 400, 'Roboto', -0.0089em), 19 | display-2: mat-typography-level(45px, 48px, 400, 'Roboto', 0.0000em), 20 | display-1: mat-typography-level(34px, 40px, 400, 'Roboto', 0.0074em), 21 | headline: mat-typography-level(24px, 32px, 400, 'Roboto', 0.0000em), 22 | title: mat-typography-level(20px, 32px, 500, 'Roboto', 0.0075em), 23 | subheading-2: mat-typography-level(16px, 28px, 400, 'Roboto', 0.0094em), 24 | subheading-1: mat-typography-level(15px, 24px, 500, 'Roboto', 0.0067em), 25 | body-2: mat-typography-level(14px, 24px, 500, 'Roboto', 0.0179em), 26 | body-1: mat-typography-level(14px, 20px, 400, 'Roboto', 0.0179em), 27 | button: mat-typography-level(14px, 14px, 500, 'Roboto', 0.0893em), 28 | caption: mat-typography-level(12px, 20px, 400, 'Roboto', 0.0333em), 29 | input: mat-typography-level(inherit, 1.125, 400, 'Roboto', 1.5px) 30 | ); 31 | 32 | // Foreground Elements 33 | 34 | // Light Theme Text 35 | $dark-text: #000000; 36 | $dark-primary-text: rgba($dark-text, 0.87); 37 | $dark-accent-text: rgba($dark-primary-text, 0.54); 38 | $dark-disabled-text: rgba($dark-primary-text, 0.38); 39 | $dark-dividers: rgba($dark-primary-text, 0.12); 40 | $dark-focused: rgba($dark-primary-text, 0.12); 41 | 42 | $mat-light-theme-foreground: ( 43 | base: black, 44 | divider: $dark-dividers, 45 | dividers: $dark-dividers, 46 | disabled: $dark-disabled-text, 47 | disabled-button: rgba($dark-text, 0.26), 48 | disabled-text: $dark-disabled-text, 49 | elevation: black, 50 | secondary-text: $dark-accent-text, 51 | hint-text: $dark-disabled-text, 52 | accent-text: $dark-accent-text, 53 | icon: $dark-accent-text, 54 | icons: $dark-accent-text, 55 | text: $dark-primary-text, 56 | slider-min: $dark-primary-text, 57 | slider-off: rgba($dark-text, 0.26), 58 | slider-off-active: $dark-disabled-text, 59 | ); 60 | 61 | // Dark Theme text 62 | $light-text: #ffffff; 63 | $light-primary-text: $light-text; 64 | $light-accent-text: rgba($light-primary-text, 0.7); 65 | $light-disabled-text: rgba($light-primary-text, 0.5); 66 | $light-dividers: rgba($light-primary-text, 0.12); 67 | $light-focused: rgba($light-primary-text, 0.12); 68 | 69 | $mat-dark-theme-foreground: ( 70 | base: $light-text, 71 | divider: $light-dividers, 72 | dividers: $light-dividers, 73 | disabled: $light-disabled-text, 74 | disabled-button: rgba($light-text, 0.3), 75 | disabled-text: $light-disabled-text, 76 | elevation: black, 77 | hint-text: $light-disabled-text, 78 | secondary-text: $light-accent-text, 79 | accent-text: $light-accent-text, 80 | icon: $light-text, 81 | icons: $light-text, 82 | text: $light-text, 83 | slider-min: $light-text, 84 | slider-off: rgba($light-text, 0.3), 85 | slider-off-active: rgba($light-text, 0.3), 86 | ); 87 | 88 | // Background config 89 | // Light bg 90 | $light-background: #fafafa; 91 | $light-bg-darker-5: darken($light-background, 5%); 92 | $light-bg-darker-10: darken($light-background, 10%); 93 | $light-bg-darker-20: darken($light-background, 20%); 94 | $light-bg-darker-30: darken($light-background, 30%); 95 | $light-bg-lighter-5: lighten($light-background, 5%); 96 | $dark-bg-tooltip: lighten(#334756, 20%); 97 | $dark-bg-alpha-4: rgba(#334756, 0.04); 98 | $dark-bg-alpha-12: rgba(#334756, 0.12); 99 | 100 | $mat-light-theme-background: ( 101 | background: $light-background, 102 | status-bar: $light-bg-darker-20, 103 | app-bar: $light-bg-darker-5, 104 | hover: $dark-bg-alpha-4, 105 | card: $light-bg-lighter-5, 106 | dialog: $light-bg-lighter-5, 107 | tooltip: $dark-bg-tooltip, 108 | disabled-button: $dark-bg-alpha-12, 109 | raised-button: $light-bg-lighter-5, 110 | focused-button: $dark-focused, 111 | selected-button: $light-bg-darker-20, 112 | selected-disabled-button: $light-bg-darker-30, 113 | disabled-button-toggle: $light-bg-darker-10, 114 | unselected-chip: $light-bg-darker-10, 115 | disabled-list-option: $light-bg-darker-10, 116 | ); 117 | 118 | // Dark bg 119 | $dark-background: #334756; 120 | $dark-bg-lighter-5: lighten($dark-background, 5%); 121 | $dark-bg-lighter-10: lighten($dark-background, 10%); 122 | $dark-bg-lighter-20: lighten($dark-background, 20%); 123 | $dark-bg-lighter-30: lighten($dark-background, 30%); 124 | $light-bg-alpha-4: rgba(#fafafa, 0.04); 125 | $light-bg-alpha-12: rgba(#fafafa, 0.12); 126 | 127 | // Background palette for dark themes. 128 | $mat-dark-theme-background: ( 129 | background: $dark-background, 130 | status-bar: $dark-bg-lighter-20, 131 | app-bar: $dark-bg-lighter-5, 132 | hover: $light-bg-alpha-4, 133 | card: $dark-bg-lighter-5, 134 | dialog: $dark-bg-lighter-5, 135 | tooltip: $dark-bg-lighter-20, 136 | disabled-button: $light-bg-alpha-12, 137 | raised-button: $dark-bg-lighter-5, 138 | focused-button: $light-focused, 139 | selected-button: $dark-bg-lighter-20, 140 | selected-disabled-button: $dark-bg-lighter-30, 141 | disabled-button-toggle: $dark-bg-lighter-10, 142 | unselected-chip: $dark-bg-lighter-20, 143 | disabled-list-option: $dark-bg-lighter-10, 144 | ); 145 | 146 | // Compute font config 147 | @include mat-core($fontConfig); 148 | 149 | // Theme Config 150 | 151 | body { 152 | --primary-color: #2c394b; 153 | --primary-lighter-color: #c0c4c9; 154 | --primary-darker-color: #1b2433; 155 | --text-primary-color: #{$light-primary-text}; 156 | --text-primary-lighter-color: #{$dark-primary-text}; 157 | --text-primary-darker-color: #{$light-primary-text}; 158 | } 159 | $mat-primary: ( 160 | main: white, 161 | lighter: #c0c4c9, 162 | darker: #1b2433, 163 | 200: #2c394b, // For slide toggle, 164 | contrast : ( 165 | main: $light-primary-text, 166 | lighter: $dark-primary-text, 167 | darker: $light-primary-text, 168 | ) 169 | ); 170 | $theme-primary: mat-palette($mat-primary, main, lighter, darker); 171 | 172 | 173 | body { 174 | --accent-color: #0ead43; 175 | --accent-lighter-color: #b7e6c7; 176 | --accent-darker-color: #08932c; 177 | --text-accent-color: #{$light-primary-text}; 178 | --text-accent-lighter-color: #{$dark-primary-text}; 179 | --text-accent-darker-color: #{$light-primary-text}; 180 | } 181 | $mat-accent: ( 182 | main: #0ead43, 183 | lighter: #b7e6c7, 184 | darker: #08932c, 185 | 200: #0ead43, // For slide toggle, 186 | contrast : ( 187 | main: $light-primary-text, 188 | lighter: $dark-primary-text, 189 | darker: $light-primary-text, 190 | ) 191 | ); 192 | $theme-accent: mat-palette($mat-accent, main, lighter, darker); 193 | 194 | 195 | body { 196 | --warn-color: #ff4c29; 197 | --warn-lighter-color: #ffc9bf; 198 | --warn-darker-color: #ff3319; 199 | --text-warn-color: #{$light-primary-text}; 200 | --text-warn-lighter-color: #{$dark-primary-text}; 201 | --text-warn-darker-color: #{$light-primary-text}; 202 | } 203 | $mat-warn: ( 204 | main: #ff4c29, 205 | lighter: #ffc9bf, 206 | darker: #ff3319, 207 | 200: #ff4c29, // For slide toggle, 208 | contrast : ( 209 | main: $light-primary-text, 210 | lighter: $dark-primary-text, 211 | darker: $light-primary-text, 212 | ) 213 | ); 214 | $theme-warn: mat-palette($mat-warn, main, lighter, darker); 215 | ; 216 | 217 | $theme: mat-dark-theme($theme-primary, $theme-accent, $theme-warn); 218 | $altTheme: mat-light-theme($theme-primary, $theme-accent, $theme-warn); 219 | 220 | // Theme Init 221 | @include angular-material-theme($theme); 222 | 223 | .theme-alternate { 224 | @include angular-material-theme($altTheme); 225 | } 226 | 227 | // Specific component overrides, pieces that are not in line with the general theming 228 | 229 | // Handle buttons appropriately, with respect to line-height 230 | .mat-raised-button, .mat-stroked-button, .mat-flat-button { 231 | padding: 0 1.15em; 232 | margin: 0 .65em; 233 | min-width: 3em; 234 | line-height: 36.4px; 235 | border: 2px solid transparent; 236 | } 237 | 238 | .mat-raised-button { 239 | border: 2px solid transparent !important; 240 | 241 | } 242 | .mat-raised-button:hover { 243 | transition: all 0.2s ease-out; 244 | border: 2px solid #0ead43 !important; 245 | // top: -4px; 246 | } 247 | 248 | .mat-standard-chip { 249 | padding: .5em .85em; 250 | min-height: 2.5em; 251 | } 252 | 253 | .material-icons { 254 | font-size: 24px; 255 | font-family: 'Material Icons', 'Material Icons'; 256 | .mat-badge-content { 257 | font-family: 'Roboto'; 258 | } 259 | } 260 | 261 | .mat-sidenav { 262 | margin: 16px; 263 | width: 200px; 264 | border-right: none; 265 | color: white; 266 | border-radius: 10px; 267 | padding: 16px; 268 | text-align: center; 269 | } 270 | 271 | .mat-sidenav-container { 272 | height: calc(100vh - 65px); 273 | } 274 | 275 | .mat-option.mat-selected:not(.mat-option-disabled) { 276 | font-weight: bold; 277 | } 278 | 279 | .mat-form-field-appearance-fill .mat-form-field-underline::before { 280 | background-color: #0ead43; 281 | } 282 | .mat-form-field-appearance-fill .mat-form-field-underline::after { 283 | background-color: #0ead43; 284 | } 285 | 286 | .mat-form-field-ripple { 287 | background-color: #08932c; 288 | } 289 | .mat-form-field.mat-focused .mat-form-field-ripple { 290 | background-color: #08932c; 291 | } 292 | 293 | .mat-tab-group.mat-primary .mat-ink-bar { 294 | background-color: #08932c; 295 | } 296 | 297 | .mat-drawer { 298 | background-color: #08932c; 299 | // min-width: 60px; 300 | overflow-x: hidden; 301 | } 302 | 303 | .mat-row { 304 | white-space: pre-wrap; 305 | word-break: break-word; 306 | overflow-wrap: anywhere; 307 | .mat-cell { 308 | margin-right: 20px; 309 | } 310 | } 311 | 312 | .mat-header-row{ 313 | position: sticky; 314 | } 315 | 316 | body { 317 | margin: 0px; 318 | } 319 | 320 | .example-spacer { 321 | flex: 1 1 auto; 322 | } 323 | 324 | .clickCard { 325 | min-width: 50vw; 326 | cursor: pointer; 327 | border: 2px solid transparent; 328 | } 329 | 330 | .clickCard:hover { 331 | transition: all 0.2s ease-out; 332 | border: 2px solid #0ead43; 333 | // top: -4px; 334 | } 335 | 336 | 337 | .td-toolbar{ 338 | } 339 | .td-container{ 340 | background-color: transparent!important; 341 | border: none!important; 342 | } 343 | .td-compare-row{ 344 | background-color: transparent!important; 345 | } 346 | .td-btn-group-toggle{ 347 | } 348 | .td-table{ 349 | border: none!important; 350 | width: 80vw!important; 351 | .line-number-col, .line-number-col-left{ 352 | color: white!important; 353 | background-color: #424242!important; 354 | } 355 | .delete-row{ 356 | color: white!important; 357 | background-color: #ff4c29!important; 358 | } 359 | .insert-row{ 360 | color: white!important; 361 | background-color: green!important; 362 | 363 | .highlight{ 364 | color: white!important; 365 | background-color: orange!important; 366 | } 367 | } 368 | 369 | } 370 | 371 | router-outlet + * { 372 | width: 100%; 373 | } 374 | 375 | -------------------------------------------------------------------------------- /ui/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: { 11 | context(path: string, deep?: boolean, filter?: RegExp): { 12 | keys(): string[]; 13 | (id: string): T; 14 | }; 15 | }; 16 | 17 | // First, initialize the Angular testing environment. 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting(), 21 | { teardown: { destroyAfterEach: true }}, 22 | ); 23 | 24 | // Then we find all the tests. 25 | const context = require.context('./', true, /\.spec\.ts$/); 26 | // And load the modules. 27 | context.keys().map(context); 28 | -------------------------------------------------------------------------------- /ui/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "noImplicitReturns": true, 10 | "noFallthroughCasesInSwitch": true, 11 | "sourceMap": true, 12 | "declaration": false, 13 | "downlevelIteration": true, 14 | "experimentalDecorators": true, 15 | "moduleResolution": "node", 16 | "importHelpers": true, 17 | "target": "es2017", 18 | "module": "es2020", 19 | "lib": [ 20 | "es2018", 21 | "dom" 22 | ] 23 | }, 24 | "angularCompilerOptions": { 25 | "enableI18nLegacyMessageIdFormat": false, 26 | "strictInjectionParameters": true, 27 | "strictInputAccessModifiers": true, 28 | "strictTemplates": true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ui/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | --------------------------------------------------------------------------------