├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── VERSION ├── api └── README.md ├── assets └── images │ ├── edgex-ui-go-overview.png │ └── gentelella-overview.jpeg ├── bin └── edgex-ui-go-launch.sh ├── cmd └── edgex-ui-go │ └── main.go ├── configs └── const.go ├── deployments ├── README.md └── initmongo.js ├── docker-file └── Dockerfile ├── docs └── README.md ├── glide.yaml ├── initial └── init.go ├── version.go └── web ├── app ├── common │ ├── filter.go │ ├── proxyhandler.go │ └── util.go ├── component │ ├── mqtt.go │ └── websocket.go ├── controller │ ├── auth.go │ ├── export.go │ ├── gateway.go │ ├── profile.go │ └── user.go ├── domain │ ├── addressable.go │ ├── gateway.go │ └── user.go ├── repository │ ├── gateway.go │ ├── mm │ │ ├── gateway.go │ │ ├── mm.go │ │ └── user.go │ ├── mongo │ │ ├── gateway.go │ │ ├── mongo.go │ │ └── user.go │ └── user.go ├── router.go └── service │ ├── gateway.go │ └── user.go ├── static ├── css │ ├── devices │ │ ├── device.css │ │ ├── deviceProfile.css │ │ └── deviceService.css │ ├── export.css │ ├── gateway.css │ ├── index.css │ ├── login.css │ ├── main.css │ ├── multimedia.css │ ├── ruleengine.css │ └── userinfo.css ├── data │ └── menu.json ├── index.html ├── js │ ├── common.js │ ├── index.js │ ├── login.js │ ├── main.js │ └── pages │ │ ├── devices │ │ ├── device.js │ │ ├── deviceProfile.js │ │ └── deviceService.js │ │ ├── export.js │ │ ├── gateway.js │ │ └── ruleengine.js ├── login.html ├── pages │ ├── devices │ │ ├── device.html │ │ ├── deviceProfile.html │ │ └── deviceService.html │ ├── export.html │ ├── gateway.html │ ├── multimedia.html │ ├── ruleengine.html │ └── userInfo.html └── vendors │ ├── bootstrap │ ├── css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap-theme.min.css.map │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ └── bootstrap.min.css.map │ └── js │ │ ├── bootstrap.js │ │ ├── bootstrap.min.js │ │ └── npm.js │ ├── echarts │ ├── echarts.min.js │ └── theme │ │ └── wonderland.js │ ├── font-awesome-4.7.0 │ ├── HELP-US-OUT.txt │ ├── css │ │ ├── font-awesome.css │ │ └── font-awesome.min.css │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ └── fontawesome-webfont.woff2 │ ├── less │ │ ├── animated.less │ │ ├── bordered-pulled.less │ │ ├── core.less │ │ ├── fixed-width.less │ │ ├── font-awesome.less │ │ ├── icons.less │ │ ├── larger.less │ │ ├── list.less │ │ ├── mixins.less │ │ ├── path.less │ │ ├── rotated-flipped.less │ │ ├── screen-reader.less │ │ ├── stacked.less │ │ └── variables.less │ └── scss │ │ ├── _animated.scss │ │ ├── _bordered-pulled.scss │ │ ├── _core.scss │ │ ├── _fixed-width.scss │ │ ├── _icons.scss │ │ ├── _larger.scss │ │ ├── _list.scss │ │ ├── _mixins.scss │ │ ├── _path.scss │ │ ├── _rotated-flipped.scss │ │ ├── _screen-reader.scss │ │ ├── _stacked.scss │ │ ├── _variables.scss │ │ └── font-awesome.scss │ └── jquery │ └── jquery.min.js └── templates └── profileTemplate.yml /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | vendor 3 | *.exe 4 | glide.lock 5 | *.DS_Store 6 | cmd/edgex-ui-go/edgex-ui-go -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to EdgeX Web UI Golang Project 2 | 3 | > Reference : [edgex-go's CONTRIBUTING documentation](https://github.com/edgexfoundry/edgex-go/blob/master/CONTRIBUTING.md) 4 | 5 | The following is a set of guidelines for contributing to EdgeX Foundry and its libraries, which are 6 | hosted in the [EdgeX Foundry Organization](https://github.com/edgexfoundry) on GitHub. 7 | 8 | This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0). 9 | By participating, you are expected to uphold this code. 10 | 11 | ## Reporting issues 12 | 13 | Reporting issues is a great way to contribute to the project. We always appreciate a well-written, 14 | thorough bug reports. 15 | 16 | Prior to raising a new issue, check out [our issue 17 | list](https://github.com/edgexfoundry-holding/edgex-ui-go/issues) to determine whether it already includes the 18 | problem you are facing. 19 | 20 | A good bug report shouldn't leave others needing to chase you up for more information. Please try to 21 | be as detailed as possible. The following questions might serve as a template for writing a detailed 22 | reports: 23 | 24 | - What were you trying to achieve? 25 | - What are the expected results? 26 | - What are the received results? 27 | - What are the steps to reproduce the issue? 28 | - In what environment did you encounter the issue? 29 | 30 | ## Pull requests 31 | 32 | Good pull requests (e.g. patches, improvements, new features) are a fantastic help. They should 33 | remain focused in scope and avoid containing unrelated commits. 34 | 35 | **Please ask first** before embarking any significant pull request (e.g. implementing new features, 36 | refactoring code etc.), otherwise you risk spending a lot of time working on something that the 37 | maintainers might not want to merge into the project. 38 | 39 | Please adhere to the coding conventions used throughout the project. If in doubt, consult the 40 | [Effective Go](https://golang.org/doc/effective_go.html) style guide. 41 | 42 | Adhering to the following process is the best way to get your work included in the project: 43 | 44 | 1. [Fork](https://help.github.com/articles/fork-a-repo/) the project, clone your fork, and configure 45 | the remotes: 46 | 47 | ```bash 48 | # Clone your fork of the repo into the current directory 49 | git clone https://github.com//edgex-ui-go.git 50 | 51 | # Navigate to the newly cloned directory 52 | cd edgex-ui-go 53 | 54 | # Assign the original repo to a remote called "upstream" 55 | git remote add upstream https://github.com/edgexfoundry-holding/edgex-ui-go.git 56 | ``` 57 | 58 | 2. If you cloned a while ago, get the latest changes from upstream: 59 | 60 | ```bash 61 | git checkout master 62 | git pull --rebase upstream master 63 | ``` 64 | 65 | 3. Create a new topic branch from `master` using the naming convention `EUG-[issue-number]` to 66 | help us keep track of your contribution scope: 67 | 68 | ```bash 69 | git checkout -b EUG-[issue-number] 70 | ``` 71 | 72 | 4. Commit your changes in logical chunks. When you are ready to commit, make sure to write a Good 73 | Commit Message™. Consult the [Erlang's contributing guide](https://github.com/erlang/otp/wiki/Writing-good-commit-messages) 74 | if you're not sure what constitutes a Good Commit Message™. Use [interactive rebase](https://help.github.com/articles/about-git-rebase) 75 | to group your commits into logical units of working before making them public. 76 | 77 | Note that every commit you make must be signed. By signing off your work you indicate that you 78 | are accepting the [Developer Certificate of Origin](https://developercertificate.org/). 79 | 80 | Use your real name (sorry, no pseudonyms or anonymous contributions). If you set your `user.name` 81 | and `user.email` git configs, you can sign your commit automatically with `git commit -s`. 82 | 83 | 5. Locally merge (or rebase) the upstream development branch into your topic branch: 84 | 85 | ```bash 86 | git pull --rebase upstream master 87 | ``` 88 | 89 | 6. Push your topic branch up to your fork: 90 | 91 | ```bash 92 | git push origin EUG-[issue-number] 93 | ``` 94 | 95 | 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title 96 | and detailed description. 97 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018 Tencent 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | # 6 | 7 | .PHONY: build clean test run 8 | 9 | GO=CGO_ENABLED=0 go 10 | GOCGO=CGO_ENABLED=1 go 11 | 12 | MICROSERVICES=cmd/edgex-ui-go/edgex-ui-go 13 | .PHONY: $(MICROSERVICES) 14 | 15 | VERSION=$(shell cat ./VERSION) 16 | 17 | GOFLAGS=-ldflags "-X github.com/edgexfoundry-holding/edgex-ui-go.Version=$(VERSION)" 18 | 19 | GIT_SHA=$(shell git rev-parse --short HEAD) 20 | 21 | build: $(MICROSERVICES) 22 | go build ./... 23 | 24 | cmd/edgex-ui-go/edgex-ui-go: 25 | $(GO) build $(GOFLAGS) -o $@ ./cmd/edgex-ui-go 26 | 27 | clean: 28 | rm -f $(MICROSERVICES) 29 | 30 | test: 31 | go test -cover ./... 32 | go vet ./... 33 | 34 | prepare: 35 | glide install 36 | 37 | run: 38 | cd bin && ./edgex-ui-go-launch.sh -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Please move to https://github.com/edgexfoundry/edgex-ui-go , this repository is no longer supported for maintenance 2 | # edgex-ui-go 3 | [![Go Report Card](https://goreportcard.com/badge/github.com/edgexfoundry-holding/edgex-ui-go)](https://goreportcard.com/report/github.com/edgexfoundry-holding/edgex-ui-go) [![license](https://img.shields.io/badge/license-Apache%20v2.0-blue.svg)](LICENSE) 4 | > Go implementation of EdgeX Web UI. 5 | 6 |

7 | 8 |

9 | 10 | Effect picture after refactoring frontend ui (to be done): 11 | 12 |

13 | 14 |

15 | 16 | ## Running in docker 17 | 18 | ``` 19 | docker pull badboyqiao/edgex-ui-go:0.1 20 | 21 | docker run -it -d -p 4000:4000 --name edgex-ui-go badboyqiao/edgex-ui-go:0.1 22 | ``` 23 | 24 | ## Install and Deploy 25 | 26 | To fetch the code and compile the web-based UI: 27 | 28 | Using `go get`: 29 | ``` 30 | go get github.com/edgexfoundry-holding/edgex-ui-go 31 | cd $GOPATH/src/github.com/edgexfoundry-holding/edgex-ui-go 32 | glide install 33 | make build 34 | ``` 35 | 36 | Using Git: 37 | ``` 38 | cd $GOPATH/src 39 | git clone http://github.com/edgexfoundry-holding/edgex-ui-go.git github.com/edgexfoundry-holding/edgex-ui-go 40 | cd $GOPATH/src/github.com/edgexfoundry-holding/edgex-ui-go 41 | glide install 42 | make build 43 | ``` 44 | 45 | To rebuild after making changes to source: 46 | 47 | ``` 48 | make clean 49 | make build 50 | ``` 51 | 52 | To test the web-based UI: 53 | 54 | ``` 55 | make test 56 | ``` 57 | 58 | Before starting the web-based UI for the first time, you'll need to initialize the Mongo database and ensure that the settings are pointing to your MongoDB instance. 59 | Without Mongo, the project defaults to using an in-memory database. 60 | 61 | To initialize Mongo from the root of the project directory: 62 | 63 | ``` 64 | mongo deployments/initmongo.js 65 | ``` 66 | 67 | Mongo settings can be found under `web/app/repository/mongo/mongo.go`. 68 | 69 | To start the application and the web-based UI: 70 | 71 | ``` 72 | make run 73 | ``` 74 | 75 | ## Using the application 76 | 77 | ### Logging in 78 | 79 | With a modern browser, navigate to http://localhost:4000. 80 | The default user credentials are: 81 | 82 | ``` 83 | Username : admin 84 | Password : admin 85 | ``` 86 | 87 | ## Displaying EdgeX Go Microservices Data on the UI 88 | 89 | > prepare : make sure you have installed Docker and its stable version. 90 | 91 | ### Starting EdgeX with Docker 92 | 93 | To start all the EdgeX Go microservices in Docker, run the following command in the root of the EdgeX Go directory: 94 | 95 | ``` 96 | make run_docker 97 | ``` 98 | 99 | For more information and detailed instructions on using EdgeX, please reference [the main EdgeX documentation.](https://nexus.edgexfoundry.org/content/sites/docs/staging/master/docs/_build/html/#) 100 | 101 | ## Community 102 | - Chat: https://chat.edgexfoundry.org/home 103 | - Mainling lists: https://lists.edgexfoundry.org/mailman/listinfo 104 | 105 | ## License 106 | [Apache-2.0](LICENSE) 107 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.0.1 -------------------------------------------------------------------------------- /api/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgexfoundry-holding/edgex-ui-go/4ad3a354d2e6f1274db1c93da4902db60649c3b7/api/README.md -------------------------------------------------------------------------------- /assets/images/edgex-ui-go-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgexfoundry-holding/edgex-ui-go/4ad3a354d2e6f1274db1c93da4902db60649c3b7/assets/images/edgex-ui-go-overview.png -------------------------------------------------------------------------------- /assets/images/gentelella-overview.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgexfoundry-holding/edgex-ui-go/4ad3a354d2e6f1274db1c93da4902db60649c3b7/assets/images/gentelella-overview.jpeg -------------------------------------------------------------------------------- /bin/edgex-ui-go-launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (c) 2018 4 | # Tencent 5 | # 6 | # SPDX-License-Identifier: Apache-2.0 7 | # 8 | 9 | DIR=$PWD 10 | CMD=../cmd 11 | 12 | # Kill all edgex-ui-go* stuff 13 | function cleanup { 14 | pkill edgex-ui-go 15 | } 16 | 17 | cd $CMD/edgex-ui-go 18 | exec -a edgex-ui-go ./edgex-ui-go & 19 | cd $DIR 20 | 21 | trap cleanup EXIT 22 | 23 | while : ; do sleep 1 ; done -------------------------------------------------------------------------------- /cmd/edgex-ui-go/main.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | *******************************************************************************/ 14 | 15 | package main 16 | 17 | import ( 18 | "github.com/edgexfoundry-holding/edgex-ui-go/initial" 19 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app" 20 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/common" 21 | "log" 22 | "net/http" 23 | _ "net/http/pprof" 24 | "time" 25 | ) 26 | 27 | func main() { 28 | initial.Initialize() 29 | 30 | r := app.InitRestRoutes() 31 | 32 | server := &http.Server{ 33 | Handler: common.GeneralFilter(r), 34 | Addr: ":4000", 35 | WriteTimeout: 15 * time.Second, 36 | ReadTimeout: 15 * time.Second, 37 | } 38 | 39 | log.Println("EdgeX ui server listen at " + server.Addr) 40 | 41 | log.Fatal(server.ListenAndServe()) 42 | } 43 | -------------------------------------------------------------------------------- /configs/const.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 Tencent 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | package configs 8 | 9 | const ( 10 | ReadBufferSize = 1024 11 | WriteBufferSize = 1024 12 | SessionTokenKey = "X-Session-Token" 13 | HttpProtocol = "http" 14 | CoreDataPath = "/core-data" 15 | CoreDataPort = "48080" 16 | CoreMetadataPath = "/core-metadata" 17 | CoreMetadataPort = "48081" 18 | CoreCommandPath = "/core-command" 19 | CoreCommandPort = "48082" 20 | CoreExportPath = "/core-export" 21 | CoreExportPort = "48071" 22 | RuleEnginePath = "/rule-engine" 23 | RuleEnginePort = "48075" 24 | WebDirName = "web" 25 | ContentTypeKey = "Content-Type" 26 | JsonContentType = "application/json" 27 | RedirectHttpCode = 302 28 | ) 29 | -------------------------------------------------------------------------------- /deployments/README.md: -------------------------------------------------------------------------------- 1 | # deploy component 2 | 3 | > This documentation describe the components which edgex-ui-go may depend on. 4 | 5 | ## MongoDB 6 | 7 | > MongoDB is one of the databases supported by edgex-ui-go. 8 | 9 | To install mongodb (for Mac OS x): 10 | 11 | brew install mongodb 12 | 13 | > make sure the HomeBrew is installed before 14 | 15 | To start mongodb (for Mac OS x): 16 | 17 | brew services start mongodb 18 | 19 | > default port is : 27017 20 | 21 | To init mongodb with seed data: 22 | 23 | mongo deployments/initmongo.js 24 | 25 | > make sure the MongoDB has been started before -------------------------------------------------------------------------------- /deployments/initmongo.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | (function init(){ 17 | db=db.getSiblingDB('admin'); 18 | try { 19 | db.createUser({ 20 | user : 'root', 21 | pwd : 'root', 22 | roles : [ 23 | { 24 | role : 'userAdminAnyDatabase', 25 | db : 'admin' 26 | } 27 | ] 28 | }); 29 | } catch(e){ 30 | return; 31 | } 32 | 33 | db.auth('root','root'); 34 | db=db.getSiblingDB('edgex-ui-go'); 35 | db.createUser({ 36 | user : 'su', 37 | pwd : 'su', 38 | roles : [ 39 | { 40 | role : 'readWrite', 41 | db : 'edgex-ui-go' 42 | } 43 | ] 44 | }); 45 | 46 | db.auth('su','su'); 47 | db.createCollection('user'); 48 | db.createCollection('gateway'); 49 | ts = Date.now(); 50 | db.user.insertOne({ 51 | name : 'admin', 52 | password : 'admin', 53 | created : ts, 54 | modified : ts 55 | }); 56 | })(); 57 | -------------------------------------------------------------------------------- /docker-file/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.9-alpine AS builder 2 | MAINTAINER huaqiao zhang 3 | 4 | RUN cp /etc/apk/repositories /etc/apk/repositories.bak 5 | RUN echo "https://mirrors.ustc.edu.cn/alpine/v3.6/main" > /etc/apk/repositories 6 | RUN echo "https://mirrors.ustc.edu.cn/alpine/v3.6/community" >> /etc/apk/repositories 7 | RUN cat /etc/apk/repositories 8 | 9 | RUN apk update && apk add git 10 | RUN apk update && apk add make 11 | 12 | COPY github.com /go/src/github.com/ 13 | WORKDIR /go/src/github.com/edgexfoundry-holding/edgex-ui-go/cmd/edgex-ui-go/ 14 | RUN GOOS=linux go build 15 | 16 | FROM alpine:3.6 17 | 18 | EXPOSE 4000 19 | 20 | COPY --from=builder /go/src/github.com/edgexfoundry-holding/edgex-ui-go/ /go/src/github.com/edgexfoundry-holding/edgex-ui-go/ 21 | 22 | WORKDIR /go/src/github.com/edgexfoundry-holding/edgex-ui-go/cmd/edgex-ui-go 23 | 24 | ENTRYPOINT ["./edgex-ui-go"] 25 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgexfoundry-holding/edgex-ui-go/4ad3a354d2e6f1274db1c93da4902db60649c3b7/docs/README.md -------------------------------------------------------------------------------- /glide.yaml: -------------------------------------------------------------------------------- 1 | package: github.com/edgexfoundry-holding/edgex-ui-go 2 | import: 3 | - package: github.com/eclipse/paho.mqtt.golang 4 | version: master 5 | - package: github.com/gorilla/mux 6 | version: ^1.6.2 7 | - package: github.com/gorilla/websocket 8 | version: ^1.2.0 9 | -------------------------------------------------------------------------------- /initial/init.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 Tencent 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | package initial 8 | 9 | import ( 10 | "github.com/edgexfoundry-holding/edgex-ui-go/configs" 11 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/repository/mongo" 12 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/repository/mm" 13 | ) 14 | 15 | var ProxyMapping map[string]string 16 | 17 | func Initialize() { 18 | ProxyMapping = make(map[string]string, 10) 19 | ProxyMapping[configs.CoreDataPath] = configs.CoreDataPort 20 | ProxyMapping[configs.CoreMetadataPath] = configs.CoreMetadataPort 21 | ProxyMapping[configs.CoreCommandPath] = configs.CoreCommandPort 22 | ProxyMapping[configs.CoreExportPath] = configs.CoreExportPort 23 | ProxyMapping[configs.RuleEnginePath] = configs.RuleEnginePort 24 | 25 | ok := mongo.DBConnect() 26 | if !ok { 27 | mm.DBConnect() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /version.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 Tencent 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | package edgex 8 | 9 | // Global version for edgex-go 10 | var Version string = "master" 11 | -------------------------------------------------------------------------------- /web/app/common/filter.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | package common 18 | 19 | import ( 20 | "net/http" 21 | "net/url" 22 | "path/filepath" 23 | "strings" 24 | "github.com/edgexfoundry-holding/edgex-ui-go/configs" 25 | "github.com/edgexfoundry-holding/edgex-ui-go/initial" 26 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/domain" 27 | ) 28 | 29 | //{Token:User} 30 | var TokenCache = make(map[string]domain.User, 20) 31 | 32 | const ( 33 | RelativePathToProjectRoot = "../../" 34 | HtmlSuffix = ".html" 35 | CssSuffix = ".css" 36 | JsSuffix = ".js" 37 | JsonSuffix = ".json" 38 | VendorsPath = "/vendors" 39 | DataPathPrefix = "/data" 40 | StaticDirName = "static" 41 | LoginUriPath = "/api/v1/auth/login" 42 | LoginHtmlPage = "/login.html" 43 | NoAuthorizationMsg = "no authorization." 44 | AjaxRequestIdentifier = "XMLHttpRequest" 45 | AjaxRequestHeader = "X-Requested-With" 46 | ) 47 | 48 | func GeneralFilter(h http.Handler) http.Handler { 49 | authFilter := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 50 | h.ServeHTTP(w, r) 51 | }) 52 | return AuthFilter(authFilter) 53 | } 54 | 55 | func AuthFilter(h http.Handler) http.Handler { 56 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 57 | path := r.URL.Path 58 | relativeStaticDirPath := filepath.Join(RelativePathToProjectRoot, configs.WebDirName, StaticDirName) 59 | 60 | if path == "/" { 61 | http.FileServer(http.Dir(relativeStaticDirPath)).ServeHTTP(w, r) 62 | return 63 | } 64 | 65 | if strings.HasSuffix(path, HtmlSuffix) || 66 | strings.HasSuffix(path, CssSuffix) || 67 | strings.HasSuffix(path, JsSuffix) || 68 | strings.HasSuffix(path, JsonSuffix) || 69 | strings.HasPrefix(path, VendorsPath) || 70 | strings.HasPrefix(path, DataPathPrefix) { 71 | http.FileServer(http.Dir(relativeStaticDirPath)).ServeHTTP(w, r) 72 | return 73 | } 74 | 75 | if path == LoginUriPath { 76 | h.ServeHTTP(w, r) 77 | return 78 | } 79 | 80 | var token string 81 | u := r.URL.RawQuery 82 | params, _ := url.ParseQuery(u) 83 | value, ok := params[configs.SessionTokenKey] 84 | if ok { 85 | token = value[0] 86 | } else { 87 | token = r.Header.Get(configs.SessionTokenKey) 88 | } 89 | 90 | _, isValid := TokenCache[token] 91 | 92 | if (token == "") || !(isValid) { 93 | if r.Header.Get(AjaxRequestHeader) != "" && 94 | r.Header.Get(AjaxRequestHeader) == AjaxRequestIdentifier { 95 | w.WriteHeader(configs.RedirectHttpCode) 96 | w.Write([]byte(NoAuthorizationMsg)) 97 | return 98 | } 99 | http.Redirect(w, r, LoginHtmlPage, configs.RedirectHttpCode) 100 | return 101 | } 102 | 103 | for prefix, _ := range initial.ProxyMapping { 104 | if strings.HasPrefix(path, prefix) { 105 | path = strings.TrimPrefix(path, prefix) 106 | ProxyHandler(w, r, path, prefix, token) 107 | return 108 | } 109 | } 110 | 111 | h.ServeHTTP(w, r) 112 | }) 113 | } 114 | -------------------------------------------------------------------------------- /web/app/common/proxyhandler.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | package common 18 | 19 | import ( 20 | "net/http" 21 | "net/http/httputil" 22 | "net/url" 23 | "github.com/edgexfoundry-holding/edgex-ui-go/configs" 24 | ) 25 | 26 | const ( 27 | OriginHostReqHeader = "X-Origin-Host" 28 | ForwardedHostReqHeader = "X-Forwarded-Host" 29 | ) 30 | 31 | //target ProxyCache {token:targetIP} 32 | var DynamicalProxyCache = make(map[string]string, 10) 33 | 34 | func ProxyHandler(w http.ResponseWriter, r *http.Request, path string, prefix string, token string) { 35 | defer r.Body.Close() 36 | 37 | targetIP := DynamicalProxyCache[token] 38 | targetAddr := configs.HttpProtocol + "://" + targetIP 39 | if prefix == configs.CoreDataPath { 40 | targetAddr += ":" + configs.CoreDataPort 41 | } 42 | 43 | if prefix == configs.CoreMetadataPath { 44 | targetAddr += ":" + configs.CoreMetadataPort 45 | } 46 | if prefix == configs.CoreCommandPath { 47 | targetAddr += ":" + configs.CoreCommandPort 48 | } 49 | if prefix == configs.CoreExportPath { 50 | targetAddr += ":" + configs.CoreExportPort 51 | } 52 | if prefix == configs.RuleEnginePath { 53 | targetAddr += ":" + configs.RuleEnginePort 54 | } 55 | 56 | origin, _ := url.Parse(targetAddr) 57 | 58 | director := func(req *http.Request) { 59 | req.Header.Add(ForwardedHostReqHeader, req.Host) 60 | req.Header.Add(OriginHostReqHeader, origin.Host) 61 | req.URL.Scheme = configs.HttpProtocol 62 | req.URL.Host = origin.Host 63 | req.URL.Path = path 64 | } 65 | 66 | proxy := &httputil.ReverseProxy{Director: director} 67 | proxy.ServeHTTP(w, r) 68 | } 69 | -------------------------------------------------------------------------------- /web/app/common/util.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | package common 18 | 19 | import ( 20 | "crypto/md5" 21 | "encoding/hex" 22 | ) 23 | 24 | func GetMd5String(s string) string { 25 | h := md5.New() 26 | h.Write([]byte(s)) 27 | return hex.EncodeToString(h.Sum(nil)) 28 | } 29 | -------------------------------------------------------------------------------- /web/app/component/mqtt.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | package component 18 | 19 | import ( 20 | "log" 21 | "strconv" 22 | MQTT "github.com/eclipse/paho.mqtt.golang" 23 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/domain" 24 | ) 25 | 26 | const ( 27 | ClientIDPrefix = "edgex-go-" 28 | ) 29 | 30 | var f MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) { 31 | log.Printf("TOPIC: %s\n", msg.Topic()) 32 | WsClientSend(MqttTokenCache, msg.Payload()) 33 | } 34 | var MqttTokenCache string 35 | 36 | //{token:MqttClient} 37 | var ExportSubscriberCache = make(map[string]interface{}, 10) 38 | 39 | func CreateMqttClient(addressable domain.Addressable, token string) { 40 | MqttTokenCache = token 41 | broker := addressable.Protocol + "://" + addressable.Address + ":" + strconv.Itoa(addressable.Port) 42 | opts := MQTT.NewClientOptions().AddBroker(broker) 43 | opts.SetClientID(ClientIDPrefix + addressable.Topic) 44 | opts.SetUsername(addressable.User) 45 | opts.SetPassword(addressable.Password) 46 | 47 | opts.OnConnect = func(c MQTT.Client) { 48 | if t := c.Subscribe(addressable.Topic, 0, f); t.Wait() && t.Error() != nil { 49 | panic(t.Error()) 50 | } 51 | } 52 | 53 | client := MQTT.NewClient(opts) 54 | 55 | if t := client.Connect(); t.Wait() && t.Error() != nil { 56 | panic(t.Error()) 57 | } else { 58 | log.Println("Connected to mqtt server\n") 59 | } 60 | 61 | ExportSubscriberCache[token+addressable.Topic] = client 62 | } 63 | -------------------------------------------------------------------------------- /web/app/component/websocket.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | package component 18 | 19 | import ( 20 | "log" 21 | "net/http" 22 | "net/url" 23 | _ "encoding/json" 24 | "github.com/edgexfoundry-holding/edgex-ui-go/configs" 25 | "github.com/gorilla/websocket" 26 | ) 27 | 28 | type WsClientConn struct { 29 | clientmapping map[string]*websocket.Conn 30 | } 31 | 32 | var wsConn *WsClientConn 33 | 34 | var upgrader = websocket.Upgrader{ 35 | ReadBufferSize: configs.ReadBufferSize, 36 | WriteBufferSize: configs.WriteBufferSize, 37 | } 38 | 39 | func WebSocketHandler(w http.ResponseWriter, r *http.Request) { 40 | 41 | ws, _ := upgrader.Upgrade(w, r, nil) 42 | if wsConn == nil { 43 | wsConn = &WsClientConn{clientmapping: make(map[string]*websocket.Conn, 50)} 44 | } 45 | 46 | u := r.URL.RawQuery 47 | m, _ := url.ParseQuery(u) 48 | token := m[configs.SessionTokenKey][0] 49 | 50 | wsConn.clientmapping[token] = ws 51 | log.Println("ws token:" + token) 52 | log.Printf(" %d ws client connected success!", len(wsConn.clientmapping)) 53 | } 54 | 55 | func WsClientSend(token string, message []byte) { 56 | for k, v := range wsConn.clientmapping { 57 | if k == token { 58 | if v != nil { 59 | v.WriteMessage(1, message) 60 | log.Println("sending..") 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /web/app/controller/auth.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | package controller 18 | 19 | import ( 20 | "log" 21 | "net/http" 22 | "encoding/json" 23 | "github.com/edgexfoundry-holding/edgex-ui-go/configs" 24 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/common" 25 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/domain" 26 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/repository" 27 | ) 28 | 29 | const ( 30 | UserNameKey = "name" 31 | PasswordKey = "password" 32 | ) 33 | 34 | func Login(w http.ResponseWriter, r *http.Request) { 35 | defer r.Body.Close() 36 | 37 | m := make(map[string]string) 38 | err := json.NewDecoder(r.Body).Decode(&m) 39 | if err != nil { 40 | http.Error(w, err.Error(), http.StatusServiceUnavailable) 41 | return 42 | } 43 | name := m[UserNameKey] 44 | pwd := m[PasswordKey] 45 | 46 | u := domain.User{Name: name, Password: pwd} 47 | ok, err := repository.GetUserRepos().ExistsUser(u) 48 | 49 | if err != nil { 50 | log.Println("User: " + name + " login failed : " + err.Error()) 51 | w.Write([]byte("log failed : " + err.Error())) 52 | return 53 | } 54 | 55 | if ok { 56 | token := common.GetMd5String(name) 57 | common.TokenCache[token] = u 58 | log.Println("User: " + name + " login.") 59 | w.Write([]byte(token)) 60 | } 61 | } 62 | 63 | func Logout(w http.ResponseWriter, r *http.Request) { 64 | token := r.Header.Get(configs.SessionTokenKey) 65 | delete(common.TokenCache, token) 66 | } 67 | -------------------------------------------------------------------------------- /web/app/controller/export.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | package controller 18 | 19 | import ( 20 | "log" 21 | "net/http" 22 | "encoding/json" 23 | "github.com/edgexfoundry-holding/edgex-ui-go/configs" 24 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/component" 25 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/domain" 26 | ) 27 | 28 | func ExportShow(w http.ResponseWriter, r *http.Request) { 29 | defer r.Body.Close() 30 | token := r.Header.Get(configs.SessionTokenKey) 31 | 32 | var addressable domain.Addressable 33 | err := json.NewDecoder(r.Body).Decode(&addressable) 34 | if _, ok := component.ExportSubscriberCache[token+addressable.Topic]; ok { 35 | log.Println("It exist a client, return") 36 | return 37 | } 38 | 39 | if err != nil { 40 | http.Error(w, err.Error(), http.StatusServiceUnavailable) 41 | return 42 | } 43 | 44 | component.CreateMqttClient(addressable, token) 45 | } 46 | -------------------------------------------------------------------------------- /web/app/controller/gateway.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | package controller 18 | 19 | import ( 20 | "net/http" 21 | "encoding/json" 22 | mux "github.com/gorilla/mux" 23 | "github.com/edgexfoundry-holding/edgex-ui-go/configs" 24 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/common" 25 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/domain" 26 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/repository" 27 | ) 28 | 29 | const ( 30 | HostIPKey = "hostIP" 31 | ) 32 | 33 | func ProxyConfigGateway(w http.ResponseWriter, r *http.Request) { 34 | defer r.Body.Close() 35 | m := make(map[string]string) 36 | err := json.NewDecoder(r.Body).Decode(&m) 37 | if err != nil { 38 | http.Error(w, err.Error(), http.StatusServiceUnavailable) 39 | return 40 | } 41 | targetIP := m[HostIPKey] 42 | common.DynamicalProxyCache[r.Header.Get(configs.SessionTokenKey)] = targetIP 43 | } 44 | 45 | func AddGateway(w http.ResponseWriter, r *http.Request) { 46 | defer r.Body.Close() 47 | var g domain.Gateway 48 | err := json.NewDecoder(r.Body).Decode(&g) 49 | if err != nil { 50 | http.Error(w, err.Error(), http.StatusServiceUnavailable) 51 | return 52 | } 53 | repository.GetGatewayRepos().Insert(&g) 54 | } 55 | 56 | func QueryAllGateway(w http.ResponseWriter, r *http.Request) { 57 | defer r.Body.Close() 58 | w.Header().Set(configs.ContentTypeKey, configs.JsonContentType) 59 | gatewayList, err := repository.GetGatewayRepos().SelectAll() 60 | if err != nil { 61 | w.Write([]byte(err.Error())) 62 | return 63 | } 64 | result, _ := json.Marshal(&gatewayList) 65 | w.Header().Set(configs.ContentTypeKey, configs.JsonContentType) 66 | w.Write(result) 67 | } 68 | 69 | func RemoveGateway(w http.ResponseWriter, r *http.Request) { 70 | defer r.Body.Close() 71 | vars := mux.Vars(r) 72 | id := vars["id"] 73 | err := repository.GetGatewayRepos().Delete(id) 74 | if err != nil { 75 | http.Error(w, "", http.StatusServiceUnavailable) 76 | return 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /web/app/controller/profile.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | package controller 18 | 19 | import ( 20 | "io/ioutil" 21 | "net/http" 22 | "path/filepath" 23 | "github.com/edgexfoundry-holding/edgex-ui-go/configs" 24 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/common" 25 | ) 26 | 27 | const ( 28 | TemplateDirName = "templates" 29 | ProfileTemplateName = "profileTemplate.yml" 30 | ) 31 | 32 | func DowloadProfile(w http.ResponseWriter, r *http.Request) { 33 | defer r.Body.Close() 34 | relativeTemplateFilePath := filepath.Join(common.RelativePathToProjectRoot, configs.WebDirName, TemplateDirName, ProfileTemplateName) 35 | data, err := ioutil.ReadFile(relativeTemplateFilePath) 36 | 37 | if err == nil { 38 | contentType := "application/x-yaml;charset=UTF-8" 39 | w.Header().Set("Content-Type", contentType) 40 | w.Header().Set("Content-disposition", "attachment;filename=\""+ProfileTemplateName+"\"") 41 | w.Write(data) 42 | } else { 43 | w.WriteHeader(404) 44 | w.Write([]byte("404 download failure!")) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /web/app/controller/user.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | *******************************************************************************/ 14 | 15 | package controller 16 | -------------------------------------------------------------------------------- /web/app/domain/addressable.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * @author: Huaqiao Zhang, 14 | *******************************************************************************/ 15 | 16 | package domain 17 | 18 | import "gopkg.in/mgo.v2/bson" 19 | 20 | type Addressable struct { 21 | Id bson.ObjectId `bson:"_id,omitempty" json:"id"` 22 | Name string `json:"name"` 23 | Protocol string `json:"protocol"` 24 | Address string `json:"address"` 25 | Port int `json:"port"` 26 | Path string `json:"path"` 27 | 28 | Publisher string `json:"publisher"` 29 | User string `json:"user"` 30 | Password string `json:"password"` 31 | Topic string `json:"topic"` 32 | } 33 | -------------------------------------------------------------------------------- /web/app/domain/gateway.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * @author: Huaqiao Zhang, 14 | *******************************************************************************/ 15 | 16 | package domain 17 | 18 | import ( 19 | _ "encoding/json" 20 | "gopkg.in/mgo.v2/bson" 21 | ) 22 | 23 | type Gateway struct { 24 | Id bson.ObjectId `bson:"_id,omitempty" json:"id"` 25 | Name string `json:"name"` 26 | Description string `json:"description"` 27 | Address string `json:"address"` 28 | Created int64 `bson:"created" json:"created"` 29 | Modified int64 `bson:"modified" json:"modified"` 30 | } 31 | -------------------------------------------------------------------------------- /web/app/domain/user.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * @author: Huaqiao Zhang, 14 | *******************************************************************************/ 15 | 16 | package domain 17 | 18 | import "gopkg.in/mgo.v2/bson" 19 | 20 | type User struct { 21 | Id bson.ObjectId `bson:"_id,omitempty" json:"id"` 22 | Name string `json:"name"` 23 | Password string `json:"password"` 24 | Created int64 `bson:"created" json:"created"` 25 | Modified int64 `bson:"modified" json:"modified"` 26 | } 27 | -------------------------------------------------------------------------------- /web/app/repository/gateway.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 Tencent 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | package repository 8 | 9 | import ( 10 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/domain" 11 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/repository/mongo" 12 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/repository/mm" 13 | ) 14 | 15 | type GatewayRepos interface { 16 | Select(id string) (domain.Gateway, error) 17 | SelectAll() ([]domain.Gateway, error) 18 | Exists(id string) (bool, error) 19 | Insert(gateway *domain.Gateway) (string, error) 20 | Update(gateway domain.Gateway) error 21 | Delete(id string) error 22 | } 23 | 24 | func GetGatewayRepos() GatewayRepos { 25 | if mongo.DS.S == nil { 26 | return GatewayRepos(&mm.GatewayRepository{}) 27 | } else { 28 | return GatewayRepos(&mongo.GatewayMongoRepository{}) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /web/app/repository/mm/gateway.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | package mm 18 | 19 | import ( 20 | "time" 21 | "gopkg.in/mgo.v2/bson" 22 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/domain" 23 | ) 24 | 25 | type GatewayRepository struct { 26 | } 27 | 28 | func (gr *GatewayRepository) Insert(g *domain.Gateway) (string, error) { 29 | 30 | timestamp := time.Now().UnixNano() / 1000000 31 | g.Created = timestamp 32 | g.Id = bson.NewObjectId() 33 | dataStore.Gateways = append(dataStore.Gateways,*g) 34 | 35 | return g.Id.Hex(), nil 36 | } 37 | 38 | func (gr *GatewayRepository) SelectAll() ([]domain.Gateway, error) { 39 | 40 | return dataStore.Gateways, nil 41 | } 42 | 43 | func (gr *GatewayRepository) Exists(id string) (bool, error) { 44 | return true,nil 45 | } 46 | 47 | func (gr *GatewayRepository) Select(id string) (domain.Gateway, error) { 48 | return dataStore.Gateways[0],nil 49 | } 50 | 51 | func (gr *GatewayRepository) Update(gateway domain.Gateway) error { 52 | return nil 53 | } 54 | 55 | func (gr *GatewayRepository) Delete(id string) error { 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /web/app/repository/mm/mm.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | package mm 18 | 19 | import ( 20 | "log" 21 | "time" 22 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/domain" 23 | ) 24 | 25 | type MemoryDB struct { 26 | Gateways []domain.Gateway 27 | Users []domain.User 28 | } 29 | 30 | var dataStore = MemoryDB{ 31 | Gateways : make([]domain.Gateway, 0), 32 | Users : make([]domain.User, 0), 33 | } 34 | 35 | func DBConnect() bool { 36 | timestamp := time.Now().UnixNano() / 1000000 37 | u := domain.User{ 38 | Name : "admin", 39 | Password : "admin", 40 | Created : timestamp, 41 | Modified : timestamp, 42 | } 43 | dataStore.Users = append(dataStore.Users,u) 44 | log.Println("Connect to memoryDB success !") 45 | return true 46 | } 47 | -------------------------------------------------------------------------------- /web/app/repository/mm/user.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | package mm 18 | 19 | import ( 20 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/domain" 21 | ) 22 | 23 | type UserRepository struct { 24 | } 25 | 26 | func (ur *UserRepository) ExistsUser(u domain.User) (bool, error) { 27 | ok := false 28 | for _ ,v := range dataStore.Users { 29 | if v.Name == u.Name && v.Password == u.Password { 30 | ok = true 31 | break 32 | } 33 | } 34 | return ok,nil 35 | } 36 | 37 | func (ur *UserRepository) Exists(id string) (bool, error) { 38 | return false, nil 39 | } 40 | 41 | func (ur *UserRepository) Insert(u domain.User) (string, error) { 42 | 43 | return "", nil 44 | } 45 | 46 | func (ur *UserRepository) Update(u domain.User) error { 47 | 48 | return nil 49 | } 50 | 51 | func (ur *UserRepository) Delete(id string) error { 52 | 53 | return nil 54 | } 55 | 56 | func (ur *UserRepository) Select(id string) (domain.User, error) { 57 | 58 | return dataStore.Users[0], nil 59 | } 60 | 61 | func (ur *UserRepository) SelectAll() ([]domain.User, error) { 62 | 63 | return dataStore.Users, nil 64 | } 65 | -------------------------------------------------------------------------------- /web/app/repository/mongo/gateway.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | package mongo 18 | 19 | import ( 20 | "log" 21 | "time" 22 | "gopkg.in/mgo.v2/bson" 23 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/domain" 24 | ) 25 | 26 | type GatewayMongoRepository struct { 27 | } 28 | 29 | func (gr *GatewayMongoRepository) Insert(g *domain.Gateway) (string, error) { 30 | ds := DS.DataStore() 31 | defer ds.S.Close() 32 | 33 | coll := ds.S.DB(database).C(gatewayTable) 34 | timestamp := time.Now().UnixNano() / 1000000 35 | g.Created = timestamp 36 | err := coll.Insert(g) 37 | 38 | if err != nil { 39 | log.Println("Insert gateway failed !") 40 | return "", err 41 | } 42 | 43 | return g.Id.Hex(), nil 44 | } 45 | 46 | func (gr *GatewayMongoRepository) Delete(id string) error { 47 | ds := DS.DataStore() 48 | defer ds.S.Close() 49 | 50 | coll := ds.S.DB(database).C(gatewayTable) 51 | err := coll.Remove(bson.M{"_id": bson.ObjectIdHex(id)}) 52 | if err != nil { 53 | log.Println("Delete gateway failed!" + err.Error()) 54 | return err 55 | } 56 | return nil 57 | } 58 | 59 | func (gr *GatewayMongoRepository) SelectAll() ([]domain.Gateway, error) { 60 | ds := DS.DataStore() 61 | defer ds.S.Close() 62 | 63 | coll := ds.S.DB(database).C(gatewayTable) 64 | 65 | result := make([]domain.Gateway, 0) 66 | err := coll.Find(nil).All(&result) 67 | if err != nil { 68 | log.Println("SelectAll failed!") 69 | return nil, err 70 | } 71 | return result, nil 72 | } 73 | 74 | func (gr *GatewayMongoRepository) Select(id string) (domain.Gateway, error) { 75 | ds := DS.DataStore() 76 | defer ds.S.Close() 77 | 78 | coll := ds.S.DB(database).C(gatewayTable) 79 | 80 | result := domain.Gateway{} 81 | err := coll.Find(nil).One(&result) 82 | if err != nil { 83 | log.Println("Select failed!") 84 | return result, err 85 | } 86 | return result, nil 87 | } 88 | 89 | func (gr *GatewayMongoRepository) Exists(id string) (bool, error) { 90 | ds := DS.DataStore() 91 | defer ds.S.Close() 92 | 93 | coll := ds.S.DB(database).C(gatewayTable) 94 | count, err := coll.Find(bson.M{"_id": bson.ObjectIdHex(id)}).Count() 95 | 96 | if err != nil { 97 | log.Println("Check gateway exists failed !") 98 | return false, err 99 | } 100 | 101 | return count > 0, nil 102 | } 103 | 104 | func (gr *GatewayMongoRepository) Update(gateway domain.Gateway) error { 105 | ds := DS.DataStore() 106 | defer ds.S.Close() 107 | 108 | coll := ds.S.DB(database).C(gatewayTable) 109 | timestamp := time.Now().UnixNano() / 1000000 110 | gateway.Modified = timestamp 111 | err := coll.UpdateId(gateway.Id, &gateway) 112 | 113 | if err != nil { 114 | log.Println("Update gateway failed !") 115 | return err 116 | } 117 | 118 | return nil 119 | } 120 | -------------------------------------------------------------------------------- /web/app/repository/mongo/mongo.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | package mongo 18 | 19 | import ( 20 | "log" 21 | "time" 22 | "fmt" 23 | mgo "gopkg.in/mgo.v2" 24 | ) 25 | 26 | const ( 27 | defaultMongoHost = "10.211.55.7" 28 | defaultMongoPort = 27018 29 | database = "edgex-ui-go" 30 | defaultUserName = "su" 31 | defaultPassword = "su" 32 | userTable = "user" 33 | gatewayTable = "gateway" 34 | ) 35 | 36 | type DataStore struct { 37 | S *mgo.Session 38 | } 39 | 40 | var DS DataStore 41 | 42 | func (ds DataStore) DataStore() *DataStore { 43 | return &DataStore{ds.S.Copy()} 44 | } 45 | 46 | func DBConnect() bool { 47 | mongoAddress := fmt.Sprintf("%s:%d", defaultMongoHost, defaultMongoPort) 48 | mongoDBDialInfo := &mgo.DialInfo{ 49 | Addrs: []string{mongoAddress}, 50 | Timeout: time.Duration(5000) * time.Millisecond, 51 | Database: database, 52 | Username: defaultUserName, 53 | Password: defaultPassword, 54 | } 55 | s, err := mgo.DialWithInfo(mongoDBDialInfo) 56 | if err != nil { 57 | log.Println("Connect to mongoDB failed !") 58 | return false 59 | } 60 | s.SetSocketTimeout(time.Duration(5000) * time.Millisecond) 61 | DS.S = s 62 | log.Println("Success connect to mongoDB !") 63 | 64 | return true 65 | } 66 | -------------------------------------------------------------------------------- /web/app/repository/mongo/user.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | package mongo 18 | 19 | import ( 20 | "log" 21 | "gopkg.in/mgo.v2/bson" 22 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/domain" 23 | ) 24 | 25 | type UserMongoRepository struct { 26 | } 27 | 28 | func (ur *UserMongoRepository) ExistsUser(u domain.User) (bool, error) { 29 | ds := DS.DataStore() 30 | defer ds.S.Close() 31 | 32 | coll := ds.S.DB(database).C(userTable) 33 | count, err := coll.Find(bson.M{"name": u.Name, "password": u.Password}).Count() 34 | if err != nil { 35 | return false, err 36 | } 37 | return count > 0, nil 38 | } 39 | 40 | func (ur *UserMongoRepository) Exists(id string) (bool, error) { 41 | ds := DS.DataStore() 42 | defer ds.S.Close() 43 | 44 | coll := ds.S.DB("edgex-ui-go").C(userTable) 45 | count, err := coll.Find(bson.M{"_id": bson.ObjectIdHex(id)}).Count() 46 | 47 | if err != nil { 48 | log.Println("Check user exists failed !") 49 | return false, err 50 | } 51 | 52 | return count > 0, nil 53 | } 54 | 55 | func (ur *UserMongoRepository) Insert(user domain.User) (string, error) { 56 | ds := DS.DataStore() 57 | defer ds.S.Close() 58 | 59 | coll := ds.S.DB(database).C(userTable) 60 | err := coll.Insert(user) 61 | 62 | if err != nil { 63 | log.Println("Insert user failed !") 64 | return "", err 65 | } 66 | 67 | return user.Id.Hex(), nil 68 | } 69 | 70 | func (ur *UserMongoRepository) Update(user domain.User) error { 71 | ds := DS.DataStore() 72 | defer ds.S.Close() 73 | 74 | coll := ds.S.DB(database).C(userTable) 75 | err := coll.UpdateId(user.Id, &user) 76 | 77 | if err != nil { 78 | log.Println("Update user failed !") 79 | return err 80 | } 81 | 82 | return nil 83 | } 84 | 85 | func (ur *UserMongoRepository) Delete(id string) error { 86 | ds := DS.DataStore() 87 | defer ds.S.Close() 88 | 89 | coll := ds.S.DB(database).C(userTable) 90 | err := coll.Remove(bson.M{"_id": bson.ObjectIdHex(id)}) 91 | if err != nil { 92 | log.Println("Delete user failed!" + err.Error()) 93 | return err 94 | } 95 | return nil 96 | } 97 | 98 | func (ur *UserMongoRepository) Select(id string) (domain.User, error) { 99 | ds := DS.DataStore() 100 | defer ds.S.Close() 101 | 102 | coll := ds.S.DB(database).C(userTable) 103 | 104 | result := domain.User{} 105 | err := coll.Find(nil).One(&result) 106 | if err != nil { 107 | log.Println("Select failed!") 108 | return result, err 109 | } 110 | return result, nil 111 | } 112 | 113 | func (ur *UserMongoRepository) SelectAll() ([]domain.User, error) { 114 | ds := DS.DataStore() 115 | defer ds.S.Close() 116 | 117 | coll := ds.S.DB(database).C(userTable) 118 | 119 | result := make([]domain.User, 0) 120 | err := coll.Find(nil).All(&result) 121 | if err != nil { 122 | log.Println("SelectAll failed!") 123 | return nil, err 124 | } 125 | return result, nil 126 | } 127 | -------------------------------------------------------------------------------- /web/app/repository/user.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 Tencent 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | package repository 8 | 9 | import ( 10 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/domain" 11 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/repository/mongo" 12 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/repository/mm" 13 | ) 14 | 15 | type UserRepos interface { 16 | Select(id string) (domain.User, error) 17 | SelectAll() ([]domain.User, error) 18 | Exists(id string) (bool, error) 19 | ExistsUser(user domain.User) (bool, error) 20 | Insert(user domain.User) (string, error) 21 | Update(user domain.User) error 22 | Delete(id string) error 23 | } 24 | 25 | func GetUserRepos() UserRepos { 26 | if mongo.DS.S == nil { 27 | return UserRepos(&mm.UserRepository{}) 28 | } else { 29 | return UserRepos(&mongo.UserMongoRepository{}) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /web/app/router.go: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | package app 18 | 19 | import ( 20 | "net/http" 21 | mux "github.com/gorilla/mux" 22 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/component" 23 | "github.com/edgexfoundry-holding/edgex-ui-go/web/app/controller" 24 | ) 25 | 26 | func InitRestRoutes() http.Handler { 27 | r := mux.NewRouter() 28 | 29 | s := r.PathPrefix("/api/v1").Subrouter() 30 | s.HandleFunc("/auth/login", controller.Login).Methods(http.MethodPost) 31 | s.HandleFunc("/auth/logout", controller.Logout).Methods(http.MethodGet) 32 | 33 | s.HandleFunc("/gateway", controller.QueryAllGateway).Methods(http.MethodGet) 34 | s.HandleFunc("/gateway", controller.AddGateway).Methods(http.MethodPost) 35 | s.HandleFunc("/gateway/{id}", controller.RemoveGateway).Methods(http.MethodDelete) 36 | s.HandleFunc("/gateway/proxy", controller.ProxyConfigGateway).Methods(http.MethodPost) 37 | 38 | s.HandleFunc("/exportshow", controller.ExportShow).Methods(http.MethodPost) 39 | 40 | s.HandleFunc("/profile/download", controller.DowloadProfile).Methods(http.MethodGet) 41 | 42 | s1 := r.PathPrefix("").Subrouter() 43 | s1.HandleFunc("/ws", component.WebSocketHandler) 44 | 45 | return r 46 | } 47 | -------------------------------------------------------------------------------- /web/app/service/gateway.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 Tencent 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | package service 8 | -------------------------------------------------------------------------------- /web/app/service/user.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 Tencent 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | package service 8 | -------------------------------------------------------------------------------- /web/static/css/devices/device.css: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | * @version: 0.1.0 16 | *******************************************************************************/ 17 | @charset "UTF-8"; 18 | 19 | .input-group span > font{ 20 | width: 80px; 21 | } 22 | 23 | #device_advanced_search{ 24 | float: right; 25 | } 26 | 27 | #device_btngroup{ 28 | float:left; 29 | } 30 | 31 | 32 | #device_advanced_search table td{ 33 | padding: 10px; 34 | font-weight: bold; 35 | } 36 | 37 | #device_advanced_search table select { 38 | width:200px; 39 | } 40 | 41 | #device_list { 42 | width: 100%; 43 | overflow: auto; 44 | } 45 | 46 | #device_list table { 47 | clear: both; 48 | margin-top:10px; 49 | overflow: auto; 50 | } 51 | 52 | #device_list table th, #device_list table td { 53 | word-break: keep-all; 54 | white-space: nowrap; 55 | text-align: center; 56 | } 57 | 58 | #device_detail { 59 | display: none; 60 | padding: 10px; 61 | } 62 | 63 | #device_detail #device_basic_intro { 64 | margin-top: 5px; 65 | /* margin-left: 200px; */ 66 | } 67 | 68 | #device_detail #device_basic_intro td{ 69 | text-align: center; 70 | padding: 5px; 71 | } 72 | 73 | #device_detail #device_basic_intro input{ 74 | width:200px; 75 | } 76 | 77 | .panel{ 78 | background-color: #f7f7f9; 79 | overflow: auto; 80 | } 81 | #command_list{ 82 | overflow: auto; 83 | } 84 | #device_basic_intro span:hover{ 85 | box-shadow: 3px 3px 3px #339933; 86 | } 87 | div#device_data_json_format{ 88 | position: fixed; 89 | top: 60px; 90 | bottom: 0; 91 | /* right: -400px; */ 92 | right: 0; 93 | z-index: 2; 94 | display: none; 95 | width: 400px; 96 | overflow: auto; 97 | /* background-color: rgba(51,153,51,0.6); */ 98 | 99 | } 100 | div#device_data_json_format pre{ 101 | background-color: rgba(51,153,51,0.45); 102 | font-weight: bolder; 103 | color:white; 104 | position: absolute; 105 | top: 0; 106 | bottom: 0; 107 | } 108 | -------------------------------------------------------------------------------- /web/static/css/devices/deviceProfile.css: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | * @version: 0.1.0 16 | *******************************************************************************/ 17 | @charset "UTF-8"; 18 | 19 | #device_profile_shelter { 20 | position: fixed; 21 | top:0; 22 | right:0; 23 | bottom:0; 24 | left:0; 25 | display: none; 26 | background-color: #339933; 27 | opacity: 0.3; 28 | z-index: 5; 29 | } 30 | 31 | #device_profile_list { 32 | width: 100%; 33 | overflow: auto; 34 | } 35 | 36 | #device_profile_list table th , 37 | #device_profile_list table td { 38 | word-break: keep-all; 39 | white-space:nowrap; 40 | text-align: center; 41 | } 42 | 43 | #device_profile_btn div:first-child { 44 | display: none; 45 | } 46 | 47 | #add_profile_dialog { 48 | position: fixed; 49 | width:300px; 50 | height:400px; 51 | top:0; 52 | right:0; 53 | bottom:0; 54 | left:0; 55 | margin:auto; 56 | border: 1px solid gray; 57 | z-index: 6; 58 | display: none; 59 | background-color: #f7f7f9; 60 | } 61 | 62 | div#add_profile_dialog button[name='cancel'] { 63 | position: absolute; 64 | bottom: 10px; 65 | left: 10px; 66 | } 67 | 68 | div#add_profile_dialog button[name='upload']{ 69 | position: absolute; 70 | bottom: 10px; 71 | right: 10px; 72 | } 73 | 74 | div#add_profile_dialog label { 75 | position:absolute; 76 | width:100px; 77 | height:35px; 78 | padding:5px; 79 | top:150px; 80 | right:100px; 81 | 82 | border: 1px solid gray; 83 | border-radius: 0.2em; 84 | background-color:#5cb85c; 85 | text-align: center; 86 | } 87 | 88 | div.file_proview { 89 | position:absolute; 90 | top:200px; 91 | right:100px; 92 | } 93 | -------------------------------------------------------------------------------- /web/static/css/devices/deviceService.css: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | * @version: 0.1.0 16 | *******************************************************************************/ 17 | @charset "UTF-8"; 18 | 19 | div.info_header { 20 | position: relative; 21 | height: 20px; 22 | margin: 25px 0 10px; 23 | border-bottom: 2.5px solid rgba(51,153,51,0.6); 24 | } 25 | div.info_header span { 26 | font-size: 15px; 27 | font-weight: bold; 28 | color: #339933; 29 | } 30 | 31 | #device_service_btn { 32 | margin-bottom: 10px; 33 | } 34 | 35 | #device_service_btn div.alert-warning { 36 | display: none; 37 | } 38 | 39 | #add_device_content { 40 | display: none; 41 | /* border: 1px dashed green; */ 42 | } 43 | 44 | #add_device_content h4 { 45 | margin-bottom: 3px; 46 | } 47 | 48 | #add_device_content input { 49 | width: 200px; 50 | } 51 | 52 | #add_device_content select { 53 | width: 200px; 54 | } 55 | 56 | /* .new_device_msg, .new_device_addressable, .related_service , .related_profile { 57 | padding: 5px; 58 | border: 1px solid gray; 59 | margin-bottom: 10px; 60 | } */ 61 | 62 | .new_device_msg table , 63 | .new_device_addressable table , 64 | .related_profile table { 65 | border-collapse: separate; 66 | 67 | } 68 | 69 | .new_device_msg table td, 70 | .new_device_addressable table td, 71 | .related_profile table td { 72 | padding: 5px; 73 | text-align: center; 74 | } 75 | 76 | /* .btn_group { 77 | text-align: center; 78 | } 79 | 80 | .btn_group button:first-child { 81 | margin-right: 150px; 82 | } */ 83 | 84 | .device_server_shelter { 85 | position: fixed; 86 | top: 0; 87 | bottom: 0; 88 | left: 0; 89 | right: 0; 90 | z-index: 100; 91 | display: none; 92 | } 93 | 94 | .device_server_shelter div.shelter{ 95 | position: absolute; 96 | width:100%; 97 | height:100%; 98 | background-color: #339933; 99 | opacity: 0.4; 100 | } 101 | 102 | .device_server_shelter div:last-child { 103 | position: absolute; 104 | top: 50%; 105 | left: 50%; 106 | } 107 | .device_server_shelter div:last-child *{ 108 | color: white; 109 | } 110 | #profile_file{ 111 | /* opacity: 0; */ 112 | display: none; 113 | } 114 | 115 | div.related_profile label:hover { 116 | border-bottom: 2px solid; 117 | border-bottom-color:#339933; 118 | } 119 | #device_service_list table th,div#device_service_list table tr { 120 | text-align: center; 121 | } 122 | 123 | #device_service_list span:hover { 124 | box-shadow: 3px 3px 3px #339933; 125 | width: 80px; 126 | } 127 | 128 | #device_service_json_format { 129 | position: fixed; 130 | width: 400px; 131 | top: 60px; 132 | right: 0; 133 | bottom: 0; 134 | z-index: 2; 135 | display: none; 136 | overflow: scroll; 137 | padding: 0; 138 | /* border: 2px solid red; */ 139 | } 140 | 141 | #device_service_json_format > pre { 142 | background-color: rgba(51,153,51,0.45); 143 | color: white; 144 | font-weight: bolder; 145 | /* height: 100%; */ 146 | /* border: 1px solid green; */ 147 | position: absolute; 148 | top: 0; 149 | bottom: 0; 150 | left:0; 151 | right:0; 152 | font-size: medium; 153 | margin: 0; 154 | } 155 | -------------------------------------------------------------------------------- /web/static/css/export.css: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | * @version: 0.1.0 16 | *******************************************************************************/ 17 | @charset "UTF-8"; 18 | 19 | div.select_panle 20 | { 21 | width: 250px; 22 | } 23 | 24 | 25 | #value_desc_filter_list > table, #device_filter_list > table 26 | { 27 | position: absolute; 28 | width: 500px; 29 | border: 1px solid green; 30 | border-collapse: separate; 31 | background-color: white; 32 | border-radius: 2px; 33 | height: auto; 34 | z-index: 10; 35 | padding: 5px; 36 | display: none; 37 | border-collapse: separate; 38 | } 39 | 40 | #value_desc_filter_list table td, #device_filter_list table td{ 41 | padding: 5px; 42 | text-align: center; 43 | } 44 | #value_desc_filter_list table th, #device_filter_list table th{ 45 | text-align: center; 46 | } 47 | 48 | div.core_export_shelter { 49 | position: fixed; 50 | top: 0; 51 | bottom: 0; 52 | left: 0; 53 | right: 0; 54 | z-index: 999; 55 | display: none; 56 | background-color: rgba(51, 153, 51, 0.4); 57 | /* opacity: 0.3; */ 58 | } 59 | 60 | div.core_export_shelter>div { 61 | width: 100px; 62 | height: 100px; 63 | position: absolute; 64 | left: 0; 65 | right: 0; 66 | top: 0; 67 | bottom: 0; 68 | margin: auto; 69 | color: white; 70 | font-size: large; 71 | /* border: 1px solid red; */ 72 | } 73 | 74 | div.info_header { 75 | position: relative; 76 | height: 20px; 77 | margin: 25px 0 10px; 78 | border-bottom: 2.5px solid rgba(51, 153, 51, 0.6); 79 | /* opacity: 0.7; */ 80 | background-color: rgba(247, 247, 249); 81 | } 82 | 83 | div.info_header span { 84 | font-size: 15px; 85 | font-weight: bold; 86 | color: #339933; 87 | } 88 | 89 | #export_list table th { 90 | text-align: center; 91 | } 92 | 93 | #export_list table tr { 94 | text-align: center; 95 | } 96 | 97 | /* table{ 98 | margin:2px 0; 99 | border:1px solid #4cae4c; 100 | border-top-width: 50px; 101 | border-top-color: #4cae4c; 102 | border-radius: 5px; 103 | 104 | } */ 105 | #add_new_export #export_data_form > div > table { 106 | border-collapse: separate; 107 | /* border:1.5px solid #339933; */ 108 | } 109 | 110 | #add_new_export #export_data_form > div > table > input { 111 | width: 200px; 112 | } 113 | 114 | #add_new_export #export_data_form > div > table select { 115 | width: 200px; 116 | } 117 | 118 | #add_new_export #export_data_form > div > table td { 119 | padding: 5px; 120 | text-align: right; 121 | /* font-weight: bold; */ 122 | } 123 | 124 | #export_register_data { 125 | border: 2px solid #339933; 126 | border-radius: 4px; 127 | background-color: black; 128 | color: #339933; 129 | } 130 | 131 | #websocket_msg_content { 132 | border-top: 2px solid #339933; 133 | background-color: black; 134 | color: green; 135 | height: 350px; 136 | overflow: auto; 137 | } 138 | 139 | #export_data_charts { 140 | width: 100%; 141 | height: 350px; 142 | border: 1px solid #339933; 143 | } 144 | 145 | #websocket_msg_content table { 146 | border-collapse: separate; 147 | width: 100%; 148 | font-weight: bold; 149 | } 150 | 151 | #websocket_msg_content table td { 152 | margin: 20px 10px; 153 | overflow: hidden; 154 | text-align: left; 155 | } 156 | 157 | #export_register_json_format { 158 | position: fixed; 159 | top: 60px; 160 | bottom: 0; 161 | right: 0; 162 | width: 400px; 163 | z-index: 2; 164 | display: none; 165 | overflow: auto; 166 | padding: 0; 167 | } 168 | 169 | #export_register_json_format > pre { 170 | position: absolute; 171 | top: 0; 172 | bottom: 0; 173 | left:0; 174 | right:0; 175 | background-color: rgba(51,153,51,0.45); 176 | font-weight: bolder; 177 | color: white; 178 | margin: 0; 179 | } 180 | 181 | #add_new_export span:hover { 182 | box-shadow: 3px 3px 3px #339933; 183 | } 184 | 185 | -------------------------------------------------------------------------------- /web/static/css/gateway.css: -------------------------------------------------------------------------------- 1 | #add_new_gateway{ 2 | display: none; 3 | position: relative; 4 | margin-top: 40px; 5 | } 6 | #add_new_gateway form { 7 | width: 800px; 8 | position: relative; 9 | left: 0; 10 | right: 0; 11 | margin: auto; 12 | } -------------------------------------------------------------------------------- /web/static/css/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | -webkit-box-sizing: border-box; 3 | -moz-box-sizing: border-box; 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | background-color: #f7f7f9; 9 | min-width: 1000px; 10 | } -------------------------------------------------------------------------------- /web/static/css/login.css: -------------------------------------------------------------------------------- 1 | * { 2 | -webkit-box-sizing: border-box; 3 | -moz-box-sizing: border-box; 4 | box-sizing: border-box; 5 | } 6 | 7 | div.home_back { 8 | background-color: #339933; 9 | opacity: 0.2; 10 | position: fixed; 11 | top: 0; 12 | bottom: 0; 13 | left: 0; 14 | right: 0; 15 | } 16 | 17 | div.login_form { 18 | width: 400px; 19 | position: fixed; 20 | top: 300px; 21 | right: 400px; 22 | } 23 | 24 | div.web_logo { 25 | position: fixed; 26 | top: 360px; 27 | left: 100px; 28 | } 29 | 30 | div.web_logo span { 31 | font-weight: 600; 32 | font-size: xx-large; 33 | font-stretch: wider; 34 | color: white; 35 | opacity: 0.8; 36 | font-style: oblique; 37 | /* font-variant: small-caps; */ 38 | } 39 | 40 | button { 41 | outline: none; 42 | } 43 | 44 | div.login_background { 45 | width: 100%; 46 | height: 200px; 47 | position: fixed; 48 | top: 288px; 49 | padding: 10px; 50 | background-color: #339933; 51 | opacity: 0.35; 52 | } -------------------------------------------------------------------------------- /web/static/css/main.css: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | * @version: 0.1.0 16 | *******************************************************************************/ 17 | @charset "UTF-8"; 18 | 19 | * { 20 | -webkit-box-sizing: border-box; 21 | -moz-box-sizing: border-box; 22 | box-sizing: border-box; 23 | } 24 | 25 | .main_shelter { 26 | display:none; 27 | position: fixed; 28 | top: 0; 29 | left: 0; 30 | bottom: 0; 31 | right:0; 32 | z-index: 2; 33 | opacity:0.2; 34 | background-color: #339933; 35 | } 36 | 37 | .main_msgbox { 38 | position: fixed; 39 | width: 400px; 40 | right: -400px; 41 | top: 60px; 42 | bottom: 0; 43 | z-index: 999; 44 | background-color:white; 45 | /* opacity:0.3; */ 46 | border-left: 1px solid #339933; 47 | } 48 | 49 | .headbar { 50 | position: fixed; 51 | height: 60px; 52 | background-color: #339933; 53 | top:0; 54 | left:0; 55 | right:0; 56 | z-index: 990; 57 | /* border: 1px solid red; *//* debugger */ 58 | } 59 | 60 | .headbar ul li { 61 | list-style: none; 62 | display: inline-block; 63 | } 64 | 65 | .headbar ul { 66 | position: absolute; 67 | top: 50%; 68 | right:0; 69 | left:0; 70 | transform: translateY(-50%); 71 | -ms-transform: translateY(-50%); 72 | -webkit-transform: translateY(-50%); 73 | -moz--transform: translateY(-50%); 74 | } 75 | 76 | .headbar li.title { 77 | font-weight: bold; 78 | font-size: medium; 79 | color: white; 80 | } 81 | 82 | .headbar li.user , li.notification , li.logout{ 83 | margin-right:20px; 84 | float: right; 85 | right:10px; 86 | color: white; 87 | } 88 | 89 | .headbar li.notification:hover , li.user:hover , li.logout:hover { 90 | color: black; 91 | } 92 | 93 | .headbar li.title > span.version { 94 | font-weight: normal; 95 | font-size: normal; 96 | color: white; 97 | } 98 | 99 | .sidebar { 100 | position: fixed; 101 | width: 200px; 102 | top: 60px; 103 | bottom: 0; 104 | left: 0; 105 | border-right: 3px solid #339933; 106 | z-index: 990; 107 | background-color: rgba(51, 153, 51, 0.2); 108 | /* border: 1px solid red; *//* debugger */ 109 | } 110 | 111 | .sidebar ul li { 112 | list-style: none; 113 | font-weight: bold; 114 | margin-top: 10px; 115 | padding: 0; 116 | } 117 | 118 | .sidebar li > i { 119 | margin: 0 2px 0 0; 120 | } 121 | 122 | .sidebar div > ul > li > span:hover { 123 | border: 2px solid; 124 | border-color:#339933; 125 | cursor:default; 126 | } 127 | 128 | /* .sidebar div > ul > li::before { 129 | font-family: "FontAwesome"; 130 | content: "\f105"; 131 | } */ 132 | 133 | .center { 134 | /* position: absolute; */ 135 | /* left: 200px; 136 | top: 60px; */ 137 | /* right: 0; 138 | bottom: 0; */ 139 | 140 | margin-top:60px; 141 | margin-left:200px; 142 | margin-bottom:0; 143 | padding: 0 10px; 144 | padding-top: 10px; 145 | z-index: 0; 146 | max-width: 100%; 147 | height: auto; 148 | overflow: visible; 149 | overflow-x: hidden; 150 | /* border: 1px solid red; */ /* debugger */ 151 | } 152 | -------------------------------------------------------------------------------- /web/static/css/multimedia.css: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | * @version: 0.1.0 16 | *******************************************************************************/ 17 | @charset "UTF-8"; 18 | 19 | .multi-main { 20 | /* width:800px; 21 | margin: 0 auto; */ 22 | /* border: 1px solid red; */ 23 | } -------------------------------------------------------------------------------- /web/static/css/ruleengine.css: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | * @version: 0.1.0 16 | *******************************************************************************/ 17 | @charset "UTF-8"; 18 | 19 | div.info_header { 20 | position: relative; 21 | height: 20px; 22 | margin: 25px 0 10px; 23 | border-bottom: 2.5px solid rgba(51, 153, 51, 0.6); 24 | } 25 | 26 | div.info_header span { 27 | font-size: 15px; 28 | font-weight: bold; 29 | color: #339933; 30 | } 31 | 32 | div#device_list { 33 | /* position: relative; */ 34 | /* min-height: 50%; */ 35 | /* margin-left: 60px; */ 36 | 37 | } 38 | 39 | div.select_panle, div#action_device_list select, div#device_command_list select 40 | { 41 | width: 220px; 42 | } 43 | 44 | div#condition_device_list table, div#action_device_list table, div#device_command_list table 45 | { 46 | position: absolute; 47 | width: 400px; 48 | border: 1px solid green; 49 | border-collapse: separate; 50 | background-color: white; 51 | border-radius: 2px; 52 | height: auto; 53 | z-index: 10; 54 | padding: 5px; 55 | } 56 | 57 | div#condition_device_list table tfoot nav { 58 | margin: 0; 59 | height: 50px; 60 | padding: 0; 61 | } 62 | 63 | .condition_device_list, .action_device_list { 64 | border-collapse: separate; 65 | } 66 | 67 | .condition_device_list td, .action_device_list td { 68 | padding: 5px; 69 | text-align: left; 70 | } -------------------------------------------------------------------------------- /web/static/css/userinfo.css: -------------------------------------------------------------------------------- 1 | .user_info table { 2 | font-size: medium; 3 | font-weight: bold; 4 | z-index: 400; 5 | margin-left: 20px; 6 | margin-top: 40px; 7 | } 8 | 9 | .user_info table td{ 10 | padding: 5px; 11 | } -------------------------------------------------------------------------------- /web/static/data/menu.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "title":"Gateway", 4 | "url": "/pages/gateway.html", 5 | "icon":"fa fa-bank" 6 | },{ 7 | "title":"Devices", 8 | "url": "", 9 | "icon":"fa fa-sitemap", 10 | "children":[{ 11 | "title":"Device", 12 | "url": "/pages/devices/device.html", 13 | "icon":"" 14 | },{ 15 | "title":"Device Service", 16 | "url": "/pages/devices/deviceService.html", 17 | "icon":"" 18 | },{ 19 | "title":"Device Profile", 20 | "url": "/pages/devices/deviceProfile.html", 21 | "icon":"" 22 | }] 23 | },{ 24 | "title":"Multimedia", 25 | "url": "/pages/multimedia.html", 26 | "icon":"fa fa-camera", 27 | "children":[] 28 | },{ 29 | "title":"Export", 30 | "url": "/pages/export.html", 31 | "icon":"fa fa-share", 32 | "children":[] 33 | },{ 34 | "title":"Rule Engine", 35 | "url": "/pages/ruleengine.html", 36 | "icon":"fa fa-wrench", 37 | "children":[] 38 | } 39 | ] -------------------------------------------------------------------------------- /web/static/index.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | EdgeX Foundry Console 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
33 |
34 |
35 | 36 | 37 |
38 |
    39 |
  • EdgeX Foundry Console 0.2.0
  • 40 |
  • 41 |
  • 42 |
  • 43 |
44 |
45 | 46 | 47 |
48 | 49 |
50 | 51 | 52 | 68 | 69 | 70 | 71 |
72 | 73 |
74 | 75 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /web/static/js/common.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | /* 17 | * Date format yyyy-MM-dd hh:mm:ss 18 | */ 19 | var dateToString = function (num){ 20 | var date = new Date(); 21 | date.setTime(num); 22 | var y = date.getFullYear(); 23 | var M = date.getMonth() + 1; 24 | M = (M < 10) ? ('0' + M) : M ; 25 | var d = date.getDate(); 26 | d = (d < 10) ? ('0' + d) : d ; 27 | var hh = date.getHours(); 28 | hh = (hh < 10 )? ('0' + hh) : hh ; 29 | var mm = date.getMinutes(); 30 | mm = (mm < 10 )? ('0' + mm) : mm ; 31 | var ss = date.getSeconds(); 32 | ss = (ss < 10) ?('0' + ss) : ss ; 33 | 34 | var str = y + '-' + M + '-' + d + ' ' + hh + ':' + mm + ':' + ss 35 | return str; 36 | } 37 | -------------------------------------------------------------------------------- /web/static/js/index.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | (function() { 18 | var X_Session_Token = window.sessionStorage.getItem("X_Session_Token") 19 | if (X_Session_Token == "" || X_Session_Token == "undefined") { 20 | window.location.href = '/login.html?ran=' + Math.random(); 21 | } 22 | })(); 23 | 24 | //locked browser url unchanged 25 | (function() { 26 | window.history.pushState(null, null, "/"); 27 | })(); 28 | 29 | //Disable page forward and backward 30 | history.pushState(null, null, document.URL); 31 | window.addEventListener('popstate', function() { 32 | history.pushState(null, null, document.URL); 33 | }); 34 | -------------------------------------------------------------------------------- /web/static/js/login.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | function login() { 18 | var name = $("#userName").val(); 19 | var pwd = $("#userPwd").val(); 20 | $.ajax({ 21 | url: '/api/v1/auth/login', 22 | type: 'POST', 23 | contentType: 'application/json', 24 | data: JSON.stringify({ 25 | 'name': name, 26 | 'password': pwd 27 | }), 28 | success: function(data) { 29 | window.sessionStorage.setItem("X_Session_Token", data) 30 | window.location.href = '/?X-Session-Token=' + data; 31 | var selectedGateway = JSON.parse(window.sessionStorage.getItem('selectedGateway')) 32 | if (selectedGateway) { 33 | var addr = { 34 | "hostIP": selectedGateway.address 35 | }; 36 | $.ajax({ 37 | url: '/api/v1/proxy', 38 | type: 'POST', 39 | contentType: 'application/json', 40 | data: JSON.stringify(addr), 41 | headers: { 42 | "X-Session-Token": window.sessionStorage.getItem("X_Session_Token") 43 | }, 44 | success: function(data) { 45 | //alert("Already change gateway to " + gatewayManagementModule.selectedRow.name); 46 | } 47 | }); 48 | } 49 | } 50 | }); 51 | 52 | } 53 | 54 | $(document).ready(function() { 55 | $(".login_form button").on('click', function() { 56 | login(); 57 | }); 58 | document.addEventListener('keyup', (event) => { 59 | if (event.key == 'Enter') { 60 | login(); 61 | } 62 | }, false); 63 | }); 64 | -------------------------------------------------------------------------------- /web/static/js/main.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | $(document).ready(function(){ 18 | 19 | //global ajax setting to redirect to login when session timeout (but user stay in old page) or user logout 20 | //don't worry about user bypassing it,the back-end has set permission to pass if user logout or session timeout. 21 | //here just improve user experience. 22 | $.ajaxSetup({ 23 | cache:false,//prevent browser cache result to redirect failed. 24 | headers:{"X-Session-Token":window.sessionStorage.getItem("X_Session_Token")}, 25 | statusCode: { 26 | 302: function() { 27 | window.location.href='/login.html?ran='+Math.random(); //prevent browser cache result to redirect failed. 28 | } 29 | } 30 | }); 31 | 32 | //get menu data dynamically. 33 | $.ajax({ 34 | url:"/data/menu.json", 35 | type:"GET", 36 | success:function(data){ 37 | var menu = eval(data); 38 | menuRender(menu); 39 | $(".center").load("/pages/gateway.html"); 40 | $(".sidebar li[url='/pages/gateway.html']").css({color:'#339933',borderBottom: '2px solid',borderBottomColor:'#339933'}); 41 | } 42 | }); 43 | 44 | //logout control 45 | $(".headbar li.logout").on("click",function(){ 46 | $.ajax({ 47 | url:'/api/v1/auth/logout?ran='+Math.random(), 48 | type:'GET', 49 | success:function(){ 50 | window.location.href='/login.html?ran='+Math.random(); 51 | } 52 | }); 53 | }); 54 | 55 | //user information control 56 | $(".headbar li.user").on("click",function(){ 57 | $(".main_msgbox").load("/pages/userInfo.html") 58 | $(".main_msgbox").animate({"right":"0"},"fast"); 59 | $(".main_shelter").show("fast"); 60 | }); 61 | 62 | //notification control 63 | $(".headbar li.notification").on("click",function(){ 64 | $(".main_msgbox").load("/pages/notification.html") 65 | $(".main_msgbox").animate({"right":"0"},"fast"); 66 | $(".main_shelter").show("fast"); 67 | }); 68 | 69 | //globe shelter control 70 | $(".main_shelter").on("click",function(){ 71 | $(".main_shelter").hide("fast"); 72 | $(".main_msgbox").animate({"right":"-400px"},"fast"); 73 | }); 74 | 75 | //render side_bar menu dynamically when load index page. 76 | function menuRender(data){ 77 | for(var i=0; i'+menu.title+''; 81 | if( subMenu != null && subMenu.length != 0 ){ 82 | str = '
  • '+menu.title+'
    • '; 83 | $(".sidebar ul:first").append(str); 84 | for(var j = 0; j < subMenu.length; j++){ 85 | $(".sidebar ul:first > li:last ul").append('
    • '+subMenu[j].title+'
    • '); 86 | } 87 | continue; 88 | } 89 | $(".sidebar ul:first").append(str); 90 | } 91 | //bind menu event of click 92 | $(".sidebar li").on('click',function(event){ 93 | event.stopPropagation();//prevent event propagate to parent node when click on current node 94 | //if not leaf node,expand current node. 95 | if($(this).find("li").length != 0){ 96 | //toggle menu icon when expand current node. 97 | $(this).find("i:first").toggleClass(function() { 98 | if ($(this).hasClass("fa fa-caret-right")) { 99 | $(this).removeClass(); 100 | return 'fa fa-caret-down'; 101 | } else { 102 | $(this).removeClass(); 103 | return 'fa fa-caret-right'; 104 | } 105 | }); 106 | $(this).children("div").slideToggle("normal"); 107 | return; 108 | } 109 | 110 | //if no select one gateway instance,not load other resource. 111 | if( window.sessionStorage.getItem('selectedGateway') == null ){ 112 | //alert('please select a gateway instance firstly!'); 113 | $("#addGatewayInstanceDialog").modal('show'); 114 | return; 115 | }; 116 | $(".sidebar li").not($(this)).css({color:'',borderBottom: '',borderBottomColor:''}); 117 | $(this).css({color:'#339933',borderBottom: '2px solid',borderBottomColor:'#339933'}); 118 | //if current node is leaf node,load html resource. 119 | $(".center").load($(this).attr("url")); 120 | }); 121 | } 122 | }); 123 | -------------------------------------------------------------------------------- /web/static/js/pages/devices/device.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | * @version: 0.1.0 16 | *******************************************************************************/ 17 | $(document).ready(function(){ 18 | //init loading data. 19 | deviceModule.loadDeviceData(); 20 | deviceModule.loadServiceSelectData(); 21 | deviceModule.loadProfileSelectData(); 22 | 23 | //global listener for hiding jsonShow section. 24 | document.addEventListener('click',function(event){ 25 | //$("#device_data_json_format").animate({"right": '-400px'}, "fast"); 26 | $("#device_data_json_format").hide("fast"); 27 | }); 28 | document.getElementById("device_data_json_format").addEventListener('click',function(event){ 29 | event.stopPropagation(); 30 | }); 31 | 32 | //Hand icon circular movement animate 33 | var shakee = function(){ 34 | $("#device_basic_intro i").animate({"right":"0"},function(){ 35 | $("#device_basic_intro i").animate({"right":"10px"},shakee()); 36 | }); 37 | } 38 | shakee(); 39 | }); 40 | var deviceModule = { 41 | deviceDataCache:[], 42 | selectedRow:null, 43 | loadDeviceData:function(){ 44 | $.ajax({ 45 | url:'/core-metadata/api/v1/device', 46 | type:'GET', 47 | success:function(data){ 48 | if(data){ 49 | deviceModule.renderDeviceList(data); 50 | } 51 | }, 52 | error:function(){ 53 | 54 | } 55 | }); 56 | }, 57 | renderDeviceList:function(data){ 58 | deviceModule.deviceDataCache = data; 59 | $("#device_list table tbody").empty(); 60 | $.each(data,function(index,ele){ 61 | var rowData = ""; 62 | rowData += ''; 63 | rowData += "" + (index + 1) +""; 64 | rowData += "" + ele.id + ""; 65 | rowData += "" + ele.name + ""; 66 | rowData += "" + ele.description + ""; 67 | rowData += "" + ele.labels[0] + ""; 68 | // rowData += "" + ele.addressable.address + ""; 69 | rowData += "" + ele.adminState + ""; 70 | rowData += "" + ele.operatingState + ""; 71 | // rowData += "" + ele.service.name + ""; 72 | // rowData += "" + ele.profile.name + ""; 73 | rowData += "" + dateToString(ele.created) + ""; 74 | //rowData += "" + dateToString(ele.modified) + ""; 75 | rowData += ""; 76 | $("#device_list table tbody").append(rowData); 77 | }); 78 | $("#device_list table tbody input:radio").on('click',function(){ 79 | var checked = $(this).prop("checked"); 80 | if(checked){ 81 | var deviceId = $(this).val(); 82 | $.each(deviceModule.deviceDataCache,function(index,ele){ 83 | if(ele.id == deviceId){ 84 | deviceModule.selectedRow = ele; 85 | } 86 | }); 87 | } 88 | }); 89 | $("#device_list table tfoot").hide(); 90 | }, 91 | loadServiceSelectData:function(){ 92 | $.ajax({ 93 | url:'/core-metadata/api/v1/deviceservice', 94 | type:'GET', 95 | success:function(data){ 96 | $("#device_advanced_search select[name='device_service']").empty(); 97 | var opt = ''; 98 | $("#device_advanced_search select[name='device_service']").append(opt); 99 | $.each(data,function(index,ele){ 100 | var option = ''; 101 | $("#device_advanced_search select[name='device_service']").append(option); 102 | }); 103 | //bind onchange event. 104 | $("#device_advanced_search select[name='device_service']").on('change',function(){ 105 | var v = $(this).val(); 106 | if(v != '') { 107 | $.ajax({ 108 | url:'/core-metadata/api/v1/device/servicename/' + v + '', 109 | type:'GET', 110 | success:function(data){ 111 | deviceModule.renderDeviceList(data); 112 | if(data.length == 0){ 113 | $("#device_list table tfoot").show() 114 | } 115 | } 116 | }); 117 | } 118 | }); 119 | } 120 | }); 121 | }, 122 | loadProfileSelectData:function(){ 123 | $.ajax({ 124 | url:'/core-metadata/api/v1/deviceprofile', 125 | type:'GET', 126 | success:function(data){ 127 | $("#device_advanced_search select[name='device_profile']").empty(); 128 | var opt = ''; 129 | $("#device_advanced_search select[name='device_profile']").append(opt); 130 | $.each(data,function(index,ele){ 131 | var option = ''; 132 | $("#device_advanced_search select[name='device_profile']").append(option); 133 | }); 134 | //bind onchange event. 135 | $("#device_advanced_search select[name='device_profile']").on('change',function(){ 136 | var v = $(this).val(); 137 | if(v != ''){ 138 | $.ajax({ 139 | url:'/core-metadata/api/v1/device/profilename/' + v + '', 140 | type:'GET', 141 | success:function(data){ 142 | deviceModule.renderDeviceList(data); 143 | if(data.length == 0){ 144 | $("#device_list table tfoot").show() 145 | } 146 | } 147 | }); 148 | } 149 | }); 150 | } 151 | }); 152 | } 153 | } 154 | 155 | var deviceModuleBtnGroup = { 156 | back:function(){ 157 | $("#device_detail").hide("fast"); 158 | $("#device_main").show("fast"); 159 | }, 160 | deleteDevice:function(confirm){ 161 | $('#deleteConfirmDialog').modal('show'); 162 | if(confirm){ 163 | $('#deleteConfirmDialog').modal('hide'); 164 | 165 | $.ajax({ 166 | url:'/core-metadata/api/v1/device/id/' + deviceModule.selectedRow.id + '', 167 | type:'DELETE', 168 | success:function(){ 169 | deviceModule.loadDeviceData(); 170 | $.ajax({ 171 | url: '/core-metadata/api/v1/addressable/id/' + deviceModule.selectedRow.addressable.id + '', 172 | type: 'DELETE', 173 | error: function(err){ 174 | alert("delete device address failed !") 175 | } 176 | }); 177 | }, 178 | error: function(err){ 179 | alert(err) 180 | } 181 | }); 182 | } 183 | }, 184 | detail:function(){ 185 | if(!deviceModule.selectedRow){ 186 | alert("please select desired item."); 187 | return; 188 | } 189 | 190 | $("#device_detail div.panel-body div:first-child").empty(); 191 | $("#device_detail div.panel-body div:first-child").append('
      ' + JSON.stringify(deviceModule.selectedRow,null,4) + '
      ') 192 | $("#device_detail #command_list table tbody").empty(); 193 | $("#device_detail input[name='id']").val(deviceModule.selectedRow.id); 194 | $("#device_detail input[name='name']").val(deviceModule.selectedRow.name); 195 | $("#device_detail input[name='description']").val(deviceModule.selectedRow.description); 196 | $("#device_detail input[name='address']").val(deviceModule.selectedRow.addressable.address); 197 | $("#device_detail input[name='profile_name']").val(deviceModule.selectedRow.profile.name); 198 | $("#device_detail input[name='service_name']").val(deviceModule.selectedRow.service.name); 199 | 200 | $.ajax({ 201 | url:'/core-command/api/v1/device/'+deviceModule.selectedRow.id+'', 202 | type:'GET', 203 | success:function(data){ 204 | var commands = data.commands; 205 | $.each(commands,function(index,ele){ 206 | var rowData = ''; 207 | rowData += '' + ele.name + ''; 208 | rowData += '' + ' get' 209 | + '  set' 210 | + ''; 211 | rowData += '' + '' + '' 212 | rowData += ''; 213 | if(ele.put != null) { 214 | $.each(ele.put.parameterNames,function(i,p){ 215 | rowData += p + '  ' 216 | }); 217 | } 218 | rowData += ''; 219 | rowData += '' 220 | + '' 221 | + ''; 222 | rowData += ''; 223 | $("#device_detail #command_list table tbody").append(rowData); 224 | }); 225 | $("#device_main").hide("fast"); 226 | $("#device_detail").show("fast"); 227 | } 228 | }); 229 | }, 230 | showJsonFormatter:function(event){ 231 | event.stopPropagation(); 232 | $("#device_data_json_format").empty(); 233 | //$("#device_data_json_format").animate({"right": '0'}, "fast"); 234 | $("#device_data_json_format").append('
      ' + JSON.stringify(deviceModule.selectedRow,null,3) + '
      '); 235 | $("#device_data_json_format").toggle("fast"); 236 | // if($("#device_data_json_format").is(":hidden")){ 237 | // $("#device_data_json_format").show(); 238 | // $("#device_data_json_format").animate({"right": '0'}, "fast"); 239 | // }else{ 240 | // $("#device_data_json_format").animate({"right": '-400px'}, "fast"); 241 | // $("#device_data_json_format").hide(); 242 | // } 243 | 244 | }, 245 | sendCommand: function(command){ 246 | $('#'+command.id+'').prop('disabled',true); 247 | var method = $('#device_detail #command_list tbody input[name="commandRadio_'+command.id+'"]:radio:checked').val(); 248 | if(method == 'set' && command.put != null) { 249 | var cmdUrl = command.put.url; 250 | cmdUrl = cmdUrl.replace(/(\w+):\/\/([^/:]+)(:\d*)?/,"/core-command"); 251 | var paramBody={}; 252 | $.each(command.put.parameterNames,function(i,param){ 253 | //debugger 254 | var p = $('#device_detail #command_list table tbody input[name="' + param + command.id + '"]').val(); 255 | paramBody[param] = p; 256 | }); 257 | //console.log(JSON.stringify(paramBody)) 258 | $.ajax({ 259 | url:cmdUrl, 260 | type:'PUT', 261 | contentType:'application/json', 262 | data:JSON.stringify(paramBody), 263 | success:function(data){ 264 | $('#device_detail #command_list tbody input[name="reading_value'+command.id+'"]').val("success"); 265 | $('#'+command.id+'').prop('disabled',false); 266 | }, 267 | error:function(){ 268 | $('#device_detail #command_list tbody input[name="reading_value'+command.id+'"]').val("failed"); 269 | $('#'+command.id+'').prop('disabled',false); 270 | } 271 | }); 272 | } else { 273 | var cmdUrl = command.get.url; 274 | cmdUrl = cmdUrl.replace(/(\w+):\/\/([^/:]+)(:\d*)?/,"/core-command"); 275 | $.ajax({ 276 | url:cmdUrl, 277 | type:'GET', 278 | success:function(data){ 279 | $('#device_detail #command_list tbody input[name="reading_value'+command.id+'"]').val(JSON.stringify(data)); 280 | $('#'+command.id+'').prop('disabled',false); 281 | }, 282 | error:function(){ 283 | $('#device_detail #command_list tbody input[name="reading_value'+command.id+'"]').val("failed"); 284 | $('#'+command.id+'').prop('disabled',false); 285 | } 286 | }); 287 | } 288 | }, 289 | } 290 | -------------------------------------------------------------------------------- /web/static/js/pages/devices/deviceProfile.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | * 16 | * @author: Huaqiao Zhang, 17 | * @version: 0.1.0 18 | ******************************************************************************/ 19 | $(document).ready(function() { 20 | deviceProfileModule.loadProfileList(); 21 | }); 22 | 23 | var deviceProfileModule = { 24 | selectedRow : [], 25 | profileDataCache : [], 26 | onSelectFileCompleted : function() { 27 | var uploadInput = $("#add_profile_upload") 28 | if (uploadInput[0].value) { 29 | $("#add_profile_dialog button[name='upload']").prop("disabled", 30 | false); 31 | var fileSelected = uploadInput[0].files[0]; 32 | $("#add_profile_dialog div.file_proview").append(fileSelected.name); 33 | } 34 | }, 35 | loadProfileList : function() { 36 | $.ajax({ 37 | url : '/core-metadata/api/v1/deviceprofile', 38 | type : 'GET', 39 | success : function(data) { 40 | $("#device_profile_list > table > tbody").empty(); 41 | deviceProfileModule.renderDeviceProfileList(data); 42 | $("#device_profile_list > table > tfoot").hide(); 43 | deviceProfileModule.profileDataCache = data; 44 | }, 45 | error : function() { 46 | // alert("error.") 47 | } 48 | }); 49 | }, 50 | renderDeviceProfileList : function(data) { 51 | $.each(data, function(index, element) { 52 | var rowData = ''; 53 | rowData += ''; 55 | rowData += '' + (index + 1) + ''; 56 | rowData += '' + element.id + ''; 57 | rowData += '' + element.name + ''; 58 | rowData += '' + element.labels[0] + ''; 59 | rowData += '' + element.description + ''; 60 | // rowData += 'VMware'; 61 | rowData += '' + element.manufacturer + ''; 62 | rowData += '' + dateToString(element.created) + ''; 63 | rowData += '' + dateToString(element.modified) + ''; 64 | rowData += ""; 65 | $("#device_profile_list > table > tbody").append(rowData); 66 | }); 67 | $("#device_profile_list > table input:checkbox").on( 68 | 'change', 69 | function() { 70 | if (this.checked) { 71 | deviceProfileModule.selectedRow.push(this.value); 72 | } else { 73 | deviceProfileModule.selectedRow.splice( 74 | deviceProfileModule.selectedRow 75 | .indexOf(this.value), 1); 76 | } 77 | }); 78 | } 79 | } 80 | 81 | var deviceProfileModuleBtnGroup = { 82 | add : function() { 83 | $("#device_profile_shelter").show('fast'); 84 | $('#add_profile_dialog .file_proview').empty(); 85 | $('#add_profile_dialog').show('fast'); 86 | }, 87 | deleteProfile : function(confirm) { 88 | var del_item = deviceProfileModule.selectedRow.length; 89 | if (del_item == 0) { 90 | $('[data-toggle="popover"]').popover('show'); 91 | return false; 92 | } 93 | $('#deleteConfirmDialog').modal('show'); 94 | if(confirm){ 95 | $('[data-toggle="popover"]').popover('hide'); 96 | $('#deleteConfirmDialog').modal('hide'); 97 | $.each(deviceProfileModule.selectedRow, function(index, ele) { 98 | $.ajax({ 99 | url : '/core-metadata/api/v1/deviceprofile/id/' + ele + '', 100 | type : 'DELETE', 101 | success : function() { 102 | if (index == deviceProfileModule.selectedRow.length - 1) { 103 | deviceProfileModule.selectedRow = []; 104 | deviceProfileModule.loadProfileList(); 105 | } 106 | }, 107 | error : function() { 108 | 109 | } 110 | }); 111 | }); 112 | } 113 | }, 114 | refresh : function() { 115 | deviceProfileModule.loadProfileList(); 116 | }, 117 | cancel : function() { 118 | $("#device_profile_shelter").hide('fast'); 119 | $('#add_profile_dialog').hide('fast'); 120 | }, 121 | uploadProfile : function() { 122 | var form = $("#add_profile_dialog form")[0]; 123 | form.action = "/core-metadata/api/v1/deviceprofile/uploadfile?X-Session-Token=" + window.sessionStorage.getItem('X_Session_Token'); 124 | form.method = "POST" 125 | form.enctype="multipart/form-data" 126 | form.submit(); 127 | var iframe = $("#add_profile_dialog iframe")[0]; 128 | iframe.onload = function(event) { 129 | var doc = iframe.contentDocument; 130 | var response = $(doc).find('body').html(); 131 | var result = response.match("code"); 132 | if (result != null || $(doc).find('body').find("h1").length != 0) { 133 | alert("upload faild"); 134 | } else { 135 | // alert("upload sucess"); 136 | form.reset(); 137 | $("#add_profile_dialog button[name='upload']").prop("disabled", 138 | true); 139 | deviceProfileModule.loadProfileList(); 140 | $("#device_profile_shelter").hide('fast'); 141 | $('#add_profile_dialog').hide('fast'); 142 | } 143 | } 144 | }, 145 | downloadProfileTemplate : function() { 146 | window.location.href="/api/v1/profile/download?X-Session-Token=" + window.sessionStorage.getItem('X_Session_Token'); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /web/static/js/pages/gateway.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | 17 | $(document).ready(function(){ 18 | gatewayManagementModule.loadGatewayList(); 19 | }); 20 | 21 | var gatewayManagementModule = { 22 | selectedRow:null, 23 | gatewayDataCache:[], 24 | loadGatewayList:function(){ 25 | $.ajax({ 26 | url: '/api/v1/gateway', 27 | type: 'GET', 28 | success: function(data){ 29 | debugger 30 | gatewayManagementModule.gatewayDataCache = data; 31 | $("#gateway_list > table > tbody").empty(); 32 | gatewayManagementModule.renderGatewayList(data); 33 | if(window.sessionStorage.getItem('selectedGateway') != null ){ 34 | var selectedGateway = JSON.parse(window.sessionStorage.getItem('selectedGateway')); 35 | gatewayManagementModule.selectedRow = selectedGateway; 36 | var inputs = $("#gateway_list > table > tbody").find("input:radio"); 37 | $.each(inputs,function(index,ele){ 38 | if($(ele).prop('value') == selectedGateway.id ){ 39 | $(ele).prop('checked',true); 40 | } 41 | }); 42 | } 43 | 44 | if(data.length != 0){ 45 | $("#gateway_list > table > tfoot").hide(); 46 | } 47 | 48 | }, 49 | error: function(){ 50 | } 51 | }); 52 | }, 53 | renderGatewayList:function(data){ 54 | $.each(data,function(index,element){ 55 | var rowData = ''; 56 | rowData += ''; 57 | rowData += '' + (index + 1) +''; 58 | rowData += '' + element.id + ''; 59 | rowData += '' + element.name + ''; 60 | rowData += '' + element.description + ''; 61 | rowData += '' + element.address + ''; 62 | rowData += '' + dateToString(element.created) + ''; 63 | rowData += ""; 64 | $("#gateway_list > table > tbody").append(rowData); 65 | }); 66 | $("#gateway_list > table input:radio").on('click',function(){ 67 | var currentRowID = $(this).val(); 68 | $.each(gatewayManagementModule.gatewayDataCache,function(index,ele){ 69 | if(ele.id == currentRowID){ 70 | gatewayManagementModule.selectedRow = Object.assign({},ele); 71 | window.sessionStorage.setItem('selectedGateway',JSON.stringify(Object.assign({},gatewayManagementModule.selectedRow))); 72 | } 73 | }); 74 | var param = {"hostIP":gatewayManagementModule.selectedRow.address}; 75 | $.ajax({ 76 | url: '/api/v1/gateway/proxy', 77 | type: 'POST', 78 | contentType:'application/json', 79 | data:JSON.stringify(param), 80 | success:function(data){ 81 | //alert("Already change gateway to " + gatewayManagementModule.selectedRow.name); 82 | } 83 | }); 84 | }); 85 | } 86 | } 87 | 88 | var gatewayManagementModuleBtnGroup = { 89 | add:function(){ 90 | $("#gateway_content_main").hide(); 91 | $("#add_new_gateway").show("fast"); 92 | }, 93 | deleteOne:function(){ 94 | var ro = gatewayManagementModule.selectedRow; 95 | $.ajax({ 96 | url:'/api/v1/gateway/' + gatewayManagementModule.selectedRow['id'] + '', 97 | type:'DELETE', 98 | success:function(){ 99 | gatewayManagementModule.selectedRow = null; 100 | window.sessionStorage.removeItem('selectedGateway'); 101 | gatewayManagementModule.loadGatewayList(); 102 | } 103 | }); 104 | }, 105 | refresh:function(){ 106 | gatewayManagementModule.loadGatewayList(); 107 | }, 108 | addNewGateway: function(){ 109 | var gateway_new = {} 110 | gateway_new["name"] = $("#name").val(); 111 | gateway_new["description"] = $("#description").val(); 112 | gateway_new["address"] = $("#address").val(); 113 | 114 | $.ajax({ 115 | url:'/api/v1/gateway', 116 | type:'POST', 117 | data:JSON.stringify(gateway_new), 118 | contentType:'application/json', 119 | success:function(){ 120 | gatewayManagementModuleBtnGroup.back(); 121 | } 122 | }); 123 | }, 124 | back:function(){ 125 | $("#add_new_gateway").hide("fast"); 126 | $("#gateway_content_main").show(); 127 | gatewayManagementModule.loadGatewayList(); 128 | } 129 | } 130 | 131 | 132 | var gatewayListDataTest = [ 133 | { 134 | 'id':'1234567890', 135 | 'name':'test-gateway-01', 136 | 'description':'this just test-01', 137 | 'address':'10.112.122.222', 138 | 'created':1513156359765 139 | },{ 140 | 'id':'0987654321', 141 | 'name':'test-gateway-02', 142 | 'description':'this just test-02', 143 | 'address':'10.211.55.9', 144 | 'created':1513156359765 145 | } 146 | ] 147 | -------------------------------------------------------------------------------- /web/static/js/pages/ruleengine.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright © 2017-2018 VMware, Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | * 14 | * @author: Huaqiao Zhang, 15 | *******************************************************************************/ 16 | $(document).ready(function(){ 17 | $("#rule-add-new").hide(); 18 | $("#condition_device_list table").hide(); 19 | $("#action_device_list table").hide(); 20 | $("#device_command_list table").hide(); 21 | ruleEngineModule.loadRuleEngineData(); 22 | 23 | //global listener for hiding device-list section. 24 | document.addEventListener('click',function(event){ 25 | $("#action_device_list table").hide(); 26 | $("#condition_device_list table").hide(); 27 | }); 28 | document.querySelector("#condition_device_list table").addEventListener('click',function(event){ 29 | event.stopPropagation(); 30 | }); 31 | document.querySelector("#action_device_list table").addEventListener('click',function(event){ 32 | event.stopPropagation(); 33 | }); 34 | 35 | //bind click event listener for device-ComboGrid-list 36 | $("#condition_device_list .select_panle").on('click',function(event){ 37 | event.stopPropagation(); 38 | $("#condition_device_list table").toggle(); 39 | $("#action_device_list table").hide(); 40 | }); 41 | 42 | $("#action_device_list .select_panle").on('click',function(event){ 43 | event.stopPropagation(); 44 | $("#action_device_list table").toggle(); 45 | $("#condition_device_list table").hide(); 46 | }); 47 | 48 | //initialize loading device-ComboGrid data. 49 | $.ajax({ 50 | url:'/core-metadata/api/v1/device', 51 | type:'GET', 52 | success:function(data){ 53 | ruleEngineModule.deviceDataCache = data; 54 | $("#action_device_list table > tbody").empty(); 55 | $("#condition_device_list table > tbody").empty(); 56 | $.each(data,function(i,d){ 57 | var rowData = ""; 58 | rowData += ""; 59 | rowData += "" + (i+1) + ""; 60 | rowData += "" + d.id.substr(0,8) + ""; 61 | rowData += "" + d.name + ""; 62 | rowData += ""; 63 | $("#action_device_list table > tbody").append(rowData); 64 | $("#condition_device_list table > tbody").append(rowData); 65 | }); 66 | $("#condition_device_list table > tbody input:radio").on('click',function(){ 67 | if($(this).prop('checked')){ 68 | var radio = this; 69 | $.each(ruleEngineModule.deviceDataCache,function(i,d){ 70 | if(d.id == $(radio).val()) { 71 | //$("#condition_device_list input").val(); 72 | $("#condition_device_list div.select_panle input[name='condition_device_name']").val(d.name); 73 | $("select[name='parameter']").empty(); 74 | $.each(d.profile.deviceResources,function(j,resource){ 75 | var opts = ""; 76 | $(".condition_device_list select[name='parameter']").append(opts); 77 | }); 78 | } 79 | }); 80 | } 81 | }); 82 | 83 | $("#action_device_list table > tbody input:radio").on('click',function(){ 84 | if($(this).prop('checked')){ 85 | var radio = this; 86 | $.each(ruleEngineModule.deviceDataCache,function(i,d){ 87 | if(d.id == $(radio).val()) { 88 | $("#action_device_list div.select_panle input[name='action_device_name']").val(d.name); 89 | $(".action_device_list select[name='commandName']").empty(); 90 | $.each(d.profile.commands,function(j,cmd){ 91 | var opts = ""; 92 | $(".action_device_list select[name='commandName']").append(opts); 93 | }); 94 | 95 | //trigger command select change event manually to render command's parameters. 96 | $(".action_device_list select[name='commandName']").change(); 97 | return false; 98 | } 99 | }); 100 | } 101 | }); 102 | 103 | $(".action_device_list select[name='commandName']").on('change',function(){ 104 | $("#action_device_param").empty(); 105 | var cmdId = $(this).val(); 106 | var flag = true; 107 | $.each(ruleEngineModule.deviceDataCache,function(i,d){ 108 | $.each(d.profile.commands,function(k,cmd){ 109 | if(cmd.id == cmdId){ 110 | if(cmd.put == null){ 111 | return false; 112 | } 113 | var parmArr = cmd.put.parameterNames; 114 | $.each(parmArr,function(n,p){ 115 | var ele = p + "  " + ""; 116 | $("#action_device_param").append(ele); 117 | }); 118 | flag = false 119 | return false; 120 | } 121 | }); 122 | return flag; 123 | }); 124 | }); 125 | } 126 | }); 127 | }); 128 | 129 | var ruleEngineModule = { 130 | selectRule:"", 131 | ruleEngineDataCache:[], 132 | deviceDataCache:[], 133 | loadRuleEngineData:function(){ 134 | $.ajax({ 135 | url:'/rule-engine/api/v1/rule', 136 | type:'GET', 137 | success:function(data){ 138 | if(data != null && data.length != 0){ 139 | $("#rule-engine-list table tfoot").hide(); 140 | } 141 | ruleEngineModule.renderList(data); 142 | } 143 | }); 144 | }, 145 | renderList:function(data){ 146 | $("#rule-engine-list table tbody").empty(); 147 | $.each(data,function(i,rule){ 148 | var rowData = ""; 149 | rowData += ""; 150 | rowData += "" + (i+1) + ""; 151 | rowData += "" + "--" + ""; 152 | rowData += "" + rule + ""; 153 | rowData += "" + "--" + ""; 154 | rowData += "" + "--" + ""; 155 | $("#rule-engine-list table tbody").append(rowData); 156 | }); 157 | $("#rule-engine-list table tbody input:radio").on('click',function(){ 158 | if($(this).prop('checked')){ 159 | ruleEngineModule.selectRule = $(this).val(); 160 | } 161 | }); 162 | } 163 | } 164 | var ruleEngineModuleBtnGroup = { 165 | add:function(){ 166 | $("#rule-engine-list").hide(); 167 | $("#rule-add-new").show(); 168 | }, 169 | deleteRule:function(confirm){ 170 | $('#deleteConfirmDialog').modal('show'); 171 | if(confirm){ 172 | $('#deleteConfirmDialog').modal('hide'); 173 | $.ajax({ 174 | url:'/rule-engine/api/v1/rule/name/'+ruleEngineModule.selectRule+'', 175 | type:'DELETE', 176 | success:function(){ 177 | ruleEngineModule.loadRuleEngineData(); 178 | } 179 | }); 180 | } 181 | }, 182 | detail:function(){}, 183 | back:function(){ 184 | $("#rule-engine-list").show(); 185 | $("#rule-add-new").hide(); 186 | }, 187 | submit:function(){ 188 | var newRule = {}; 189 | var condition = {}; 190 | var checks = []; 191 | var action = {}; 192 | var name = $("#rule-add-new input[name='name']").val(); 193 | var condition_device_name = $("#rule-add-new input[name='condition_device_name']").val(); 194 | var parameter = $("#rule-add-new select[name='parameter']").val(); 195 | //var operand1 = 196 | var operation = $("#rule-add-new select[name='operation']").val(); 197 | var operand2 = $("#rule-add-new input[name='operand2']").val(); 198 | 199 | var action_device_name = $("#action_device_list input[name='action_device_name']").val(); 200 | var command = $("#rule-add-new select[name='commandName']").val(); 201 | var body = '{\\\"'; 202 | var param_inputs = $("table.action_device_list td").last().find('input'); 203 | $.each(param_inputs,function(i,input){ 204 | body += $(input).prop('name')+'\\\":\\\"' + $(input).val() + '\\\"'; 205 | if(i == (param_inputs.length - 1)){ 206 | body += '}'; 207 | return false; 208 | } 209 | body += ',\\\"'; 210 | }); 211 | 212 | condition['device'] = condition_device_name; 213 | checks.push({"parameter":parameter, 214 | "operand1":"Float.parseFloat(value)", 215 | "operation":operation,"operand2":operand2}); 216 | condition['checks'] = checks; 217 | $.each(ruleEngineModule.deviceDataCache,function(i,d){ 218 | if(d.name == action_device_name){ 219 | action['device'] = d.id; 220 | } 221 | }); 222 | action['command'] = command; 223 | action['body'] = body; 224 | newRule['name'] = name; 225 | newRule['condition'] = condition; 226 | newRule['action'] = action; 227 | newRule['log'] = "just test."; 228 | console.log(JSON.stringify(newRule)); 229 | $.ajax({ 230 | url:'/rule-engine/api/v1/rule', 231 | type:'POST', 232 | data:JSON.stringify(newRule), 233 | contentType:'application/json', 234 | success:function(){ 235 | $("#rule-add-new").hide(); 236 | $("#rule-engine-list").show(); 237 | ruleEngineModule.loadRuleEngineData(); 238 | } 239 | }); 240 | }, 241 | update:function(){} 242 | } 243 | 244 | var testRuleData = { 245 | "name": "test-ruleengine-01", 246 | "condition": { 247 | "device": "KMC.BAC-121036CE01", 248 | "checks": [{ 249 | "parameter": "AnalogValue_40", 250 | "operand1": "Float.parseFloat(value)", 251 | "operation": ">", 252 | "operand2": "50" 253 | }] 254 | }, 255 | "action": { 256 | "device": "5aa89264e4b0c39331221ea7", 257 | "command": "5aa89260e4b0c39331221ea2", 258 | "body": "{\\\"enableRandomization\\\":\\\"false\\\",\\\"collectionFrequency\\\":\\\"15\\\"}" 259 | }, 260 | "log": "disabled random." 261 | } 262 | -------------------------------------------------------------------------------- /web/static/login.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | Login Home 24 | 25 | 26 | 27 | 28 | 29 | 30 |
      31 |
      32 | 34 | 37 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /web/static/pages/devices/device.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
      28 | 44 |
      45 | 48 | 51 |
      52 |
      53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 |
      #IDDevice NameDescriptionLabelAdmin StateOperating StateCreated Time
      No Data.
      79 |
      80 |
      81 | 82 |
      83 |
      84 |
      85 |
      86 | 89 |
      90 | 91 |
      92 |
      Device General Info
      93 |
      94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 |
      IDNameDescription
      AddressProfile NameService Namejson show   
      115 |
      116 |
      117 | 118 |
      119 |
      Commands
      120 |
      121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 |
      Command NameMethodReading ValueParameterOperation
      134 |
      135 |
      136 |
      137 | 138 | 155 | 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /web/static/pages/devices/deviceProfile.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
      29 | 30 | 44 | 45 |
      46 | 49 | 52 | 55 | 58 |
      59 | 60 |
      61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 |
      #IDProfile NameLabelDescriptionManufacturerCreated TimeModified Time
      No Data.
      83 |
      84 | 85 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /web/static/pages/devices/deviceService.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
      28 |
      29 |
      30 |
      31 |
      32 | 33 | Uploading... 34 |
      35 |
      36 |
      37 |
      38 | 39 | 42 | 45 | 46 | Show JSON    47 | 48 | 49 |
      50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
      #IDService NameLabelOperating StateAdmin State
      No Data.
      70 |
      71 | 72 |
      73 |
      74 | 77 | 80 |
      81 | 82 |
      83 | New Device 84 |
      85 |
      86 |
      87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 103 | 104 | 110 | 111 | 112 |
      NameDescription
      Admin State 98 | 102 | Operating State 105 | 109 |
      113 |
      114 | 115 |
      116 | New Device Profile 117 |
      118 |
      119 | 147 |
      148 |

      149 | 150 |

      151 |
      152 | 153 |
      154 | New Device Addressable 155 |
      156 |
      157 |
      158 |
      159 | 160 | 161 | 162 | 163 | 164 | 170 | 171 | 172 | 173 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 |
      NameMethod 165 | 169 |
      Protocol 174 | 181 | Address
      PortPath
      PublisherUser
      PasswordTopic
      204 |
      205 |
      206 | 207 |
      208 | New Device Related Service 209 |
      210 |
      211 | 215 | 216 |
      217 | 218 | 219 | 220 | 221 | -------------------------------------------------------------------------------- /web/static/pages/export.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | Export 24 | 25 | 26 | 27 | 28 |
      29 |
      30 |
      31 |
      32 | uploading... 33 |
      34 |
      35 |
      36 |
      37 | 40 | 43 | 46 |
      47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 |
      #IDNameDestinationEnableCreated TimeModified Time
      No Data.
      68 | 69 |
      70 | 73 |
      74 | 75 | 76 |
      77 |
      78 | 79 |
      80 |
      81 | 82 |
      83 |
      84 | 87 | 90 |   93 | Show JSON    94 |
      95 |
      96 | General 97 |
      98 |
      99 |
      100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 114 | 115 | 116 | 117 | 122 | 123 | 131 | 132 | 133 | 134 |
      IDNameDestination
      CompressionFormatEnabled
      135 |
      136 | 137 |
      138 | Addressable 139 |
      140 |
      141 | 142 | 143 | 144 | 145 | 146 | 153 | 154 | 155 | 156 | 157 | 158 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 |
      NameProtocolAddressPortMethod
      PublisherUserPasswordTopicPath
      176 |
      177 | 178 |
      179 | Encryption (optional) 180 |
      181 |
      182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 193 | 194 |
      KeyInitialization VectorAlgorithm
      195 |
      196 | 197 |
      198 | Filters (optional) 199 |
      200 |
      201 | 202 | 203 | 204 | 228 | 229 | 253 | 254 |
      Device Name 205 |
      206 |
      207 |
      208 |
      209 | 210 |
      211 | 212 |
      213 |
      214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 |
      #NameDescription
      226 |
      227 |
      Value Descriptor Name 230 |
      231 |
      232 |
      233 |
      234 | 235 |
      236 | 237 |
      238 |
      239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 |
      #NameDescriptor
      251 |
      252 |
      255 |
      256 |
      257 |
      258 | 259 | 280 | 281 | 282 | 283 | 284 | -------------------------------------------------------------------------------- /web/static/pages/gateway.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | Gateway Management 24 | 25 | 26 | 27 | 28 |
      29 |
      30 | 33 | 36 | 39 |
      40 |
      41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 |
      #IDGateway NameDescriptionAddressCreated Time
      No Data.
      61 |
      62 |
      63 | 64 |
      65 |
      66 |
      67 |
      68 |
      69 | 70 |
      71 | 72 |
      73 |
      74 |
      75 | 76 |
      77 | 78 |
      79 |
      80 |
      81 | 82 |
      83 | 84 |
      85 |
      86 |
      87 |
      88 | 89 | 90 |
      91 |
      92 |
      93 |
      94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /web/static/pages/multimedia.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
      26 |

      Loading...

      27 |
      28 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /web/static/pages/ruleengine.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | Rules Engine 22 | 23 | 24 | 25 | 26 |
      27 |
      28 | 31 | 34 | 37 |
      38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 |
      #IDNameCreatedModified
      No Data.
      56 |
      57 |
      58 | 59 |
      60 | 63 | 66 |
      67 | 68 |
      69 | General 70 |
      71 |
      72 | 73 | 74 | 75 | 76 | 77 |
      Name   
      78 |
      79 | Condition 80 |
      81 |
      82 | 83 | 84 | 85 | 135 | 136 | 143 | 144 | 151 | 152 | 153 | 154 |
      Device Name 86 |
      87 |
      88 |
      89 |
      90 | 91 |
      92 | 93 |
      94 |
      95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 130 | 131 | 132 |
      #IDName
      110 | 129 |
      133 |
      134 |
      Parameter 137 | 142 | Operation 145 | 150 | Argument
      155 | 156 |
      157 | Action 158 |
      159 | 160 | 161 | 162 | 186 | 187 | 190 | 191 | 192 |
      Device Name 163 |
      164 |
      165 |
      166 |
      167 | 168 |
      169 | 170 |
      171 |
      172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 |
      #IDName
      184 |
      185 |
      Command 188 | 189 |
      193 |
      194 | 195 | 212 | 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /web/static/pages/userInfo.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /web/static/vendors/bootstrap/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/HELP-US-OUT.txt: -------------------------------------------------------------------------------- 1 | I hope you love Font Awesome. If you've found it useful, please do me a favor and check out my latest project, 2 | Fort Awesome (https://fortawesome.com). It makes it easy to put the perfect icons on your website. Choose from our awesome, 3 | comprehensive icon sets or copy and paste your own. 4 | 5 | Please. Check it out. 6 | 7 | -Dave Gandy 8 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgexfoundry-holding/edgex-ui-go/4ad3a354d2e6f1274db1c93da4902db60649c3b7/web/static/vendors/font-awesome-4.7.0/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgexfoundry-holding/edgex-ui-go/4ad3a354d2e6f1274db1c93da4902db60649c3b7/web/static/vendors/font-awesome-4.7.0/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgexfoundry-holding/edgex-ui-go/4ad3a354d2e6f1274db1c93da4902db60649c3b7/web/static/vendors/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgexfoundry-holding/edgex-ui-go/4ad3a354d2e6f1274db1c93da4902db60649c3b7/web/static/vendors/font-awesome-4.7.0/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edgexfoundry-holding/edgex-ui-go/4ad3a354d2e6f1274db1c93da4902db60649c3b7/web/static/vendors/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/less/animated.less: -------------------------------------------------------------------------------- 1 | // Animated Icons 2 | // -------------------------- 3 | 4 | .@{fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .@{fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/less/bordered-pulled.less: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em @fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .@{fa-css-prefix}-pull-left { float: left; } 11 | .@{fa-css-prefix}-pull-right { float: right; } 12 | 13 | .@{fa-css-prefix} { 14 | &.@{fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.@{fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .@{fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/less/core.less: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/less/fixed-width.less: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .@{fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/less/font-awesome.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables.less"; 7 | @import "mixins.less"; 8 | @import "path.less"; 9 | @import "core.less"; 10 | @import "larger.less"; 11 | @import "fixed-width.less"; 12 | @import "list.less"; 13 | @import "bordered-pulled.less"; 14 | @import "animated.less"; 15 | @import "rotated-flipped.less"; 16 | @import "stacked.less"; 17 | @import "icons.less"; 18 | @import "screen-reader.less"; 19 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/less/larger.less: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .@{fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .@{fa-css-prefix}-2x { font-size: 2em; } 11 | .@{fa-css-prefix}-3x { font-size: 3em; } 12 | .@{fa-css-prefix}-4x { font-size: 4em; } 13 | .@{fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/less/list.less: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: @fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .@{fa-css-prefix}-li { 11 | position: absolute; 12 | left: -@fa-li-width; 13 | width: @fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.@{fa-css-prefix}-lg { 17 | left: (-@fa-li-width + (4em / 14)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/less/mixins.less: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | .fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | 14 | .fa-icon-rotate(@degrees, @rotation) { 15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})"; 16 | -webkit-transform: rotate(@degrees); 17 | -ms-transform: rotate(@degrees); 18 | transform: rotate(@degrees); 19 | } 20 | 21 | .fa-icon-flip(@horiz, @vert, @rotation) { 22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)"; 23 | -webkit-transform: scale(@horiz, @vert); 24 | -ms-transform: scale(@horiz, @vert); 25 | transform: scale(@horiz, @vert); 26 | } 27 | 28 | 29 | // Only display content to screen readers. A la Bootstrap 4. 30 | // 31 | // See: http://a11yproject.com/posts/how-to-hide-content/ 32 | 33 | .sr-only() { 34 | position: absolute; 35 | width: 1px; 36 | height: 1px; 37 | padding: 0; 38 | margin: -1px; 39 | overflow: hidden; 40 | clip: rect(0,0,0,0); 41 | border: 0; 42 | } 43 | 44 | // Use in conjunction with .sr-only to only display content when it's focused. 45 | // 46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 47 | // 48 | // Credit: HTML5 Boilerplate 49 | 50 | .sr-only-focusable() { 51 | &:active, 52 | &:focus { 53 | position: static; 54 | width: auto; 55 | height: auto; 56 | margin: 0; 57 | overflow: visible; 58 | clip: auto; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/less/path.less: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}'); 7 | src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'), 8 | url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'), 9 | url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'), 10 | url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'), 11 | url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg'); 12 | // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/less/rotated-flipped.less: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); } 5 | .@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); } 6 | .@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); } 7 | 8 | .@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); } 9 | .@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .@{fa-css-prefix}-rotate-90, 15 | :root .@{fa-css-prefix}-rotate-180, 16 | :root .@{fa-css-prefix}-rotate-270, 17 | :root .@{fa-css-prefix}-flip-horizontal, 18 | :root .@{fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/less/screen-reader.less: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { .sr-only(); } 5 | .sr-only-focusable { .sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/less/stacked.less: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .@{fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .@{fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .@{fa-css-prefix}-inverse { color: @fa-inverse; } 21 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/scss/_animated.scss: -------------------------------------------------------------------------------- 1 | // Spinning Icons 2 | // -------------------------- 3 | 4 | .#{$fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .#{$fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/scss/_bordered-pulled.scss: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em $fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .#{$fa-css-prefix}-pull-left { float: left; } 11 | .#{$fa-css-prefix}-pull-right { float: right; } 12 | 13 | .#{$fa-css-prefix} { 14 | &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .#{$fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/scss/_core.scss: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/scss/_fixed-width.scss: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .#{$fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/scss/_larger.scss: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .#{$fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .#{$fa-css-prefix}-2x { font-size: 2em; } 11 | .#{$fa-css-prefix}-3x { font-size: 3em; } 12 | .#{$fa-css-prefix}-4x { font-size: 4em; } 13 | .#{$fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/scss/_list.scss: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: $fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .#{$fa-css-prefix}-li { 11 | position: absolute; 12 | left: -$fa-li-width; 13 | width: $fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.#{$fa-css-prefix}-lg { 17 | left: -$fa-li-width + (4em / 14); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/scss/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | @mixin fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | 14 | @mixin fa-icon-rotate($degrees, $rotation) { 15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})"; 16 | -webkit-transform: rotate($degrees); 17 | -ms-transform: rotate($degrees); 18 | transform: rotate($degrees); 19 | } 20 | 21 | @mixin fa-icon-flip($horiz, $vert, $rotation) { 22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)"; 23 | -webkit-transform: scale($horiz, $vert); 24 | -ms-transform: scale($horiz, $vert); 25 | transform: scale($horiz, $vert); 26 | } 27 | 28 | 29 | // Only display content to screen readers. A la Bootstrap 4. 30 | // 31 | // See: http://a11yproject.com/posts/how-to-hide-content/ 32 | 33 | @mixin sr-only { 34 | position: absolute; 35 | width: 1px; 36 | height: 1px; 37 | padding: 0; 38 | margin: -1px; 39 | overflow: hidden; 40 | clip: rect(0,0,0,0); 41 | border: 0; 42 | } 43 | 44 | // Use in conjunction with .sr-only to only display content when it's focused. 45 | // 46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 47 | // 48 | // Credit: HTML5 Boilerplate 49 | 50 | @mixin sr-only-focusable { 51 | &:active, 52 | &:focus { 53 | position: static; 54 | width: auto; 55 | height: auto; 56 | margin: 0; 57 | overflow: visible; 58 | clip: auto; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/scss/_path.scss: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); 7 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), 8 | url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'), 9 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), 10 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), 11 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); 12 | // src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/scss/_rotated-flipped.scss: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } 5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } 6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } 7 | 8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } 9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .#{$fa-css-prefix}-rotate-90, 15 | :root .#{$fa-css-prefix}-rotate-180, 16 | :root .#{$fa-css-prefix}-rotate-270, 17 | :root .#{$fa-css-prefix}-flip-horizontal, 18 | :root .#{$fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/scss/_screen-reader.scss: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { @include sr-only(); } 5 | .sr-only-focusable { @include sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/scss/_stacked.scss: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; } 21 | -------------------------------------------------------------------------------- /web/static/vendors/font-awesome-4.7.0/scss/font-awesome.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables"; 7 | @import "mixins"; 8 | @import "path"; 9 | @import "core"; 10 | @import "larger"; 11 | @import "fixed-width"; 12 | @import "list"; 13 | @import "bordered-pulled"; 14 | @import "animated"; 15 | @import "rotated-flipped"; 16 | @import "stacked"; 17 | @import "icons"; 18 | @import "screen-reader"; 19 | -------------------------------------------------------------------------------- /web/templates/profileTemplate.yml: -------------------------------------------------------------------------------- 1 | name: "KMC.BAC-121036CE" 2 | manufacturer: "Author Name" 3 | model: "BAC-121036CE" 4 | labels: 5 | - "thermostat" 6 | - "industrial" 7 | description: "KMC BAC-121036CE BACnet thermostat Template" 8 | deviceResources: 9 | - 10 | name: "AnalogValue_40" 11 | description: "The current temperature." 12 | attributes: 13 | { type: "analogValue", instance: "40" } 14 | properties: 15 | value: 16 | { type: "Float", size: "4", readWrite: "R", precision: "3.2", defaultValue: "0.00", minimum: "-99.99", maximum: "199.99" } 17 | units: 18 | { type: "String", readWrite: "R", defaultValue: "DegreesFarenheit" } 19 | - 20 | name: "AnalogValue_22" 21 | description: "Get the current humidity." 22 | attributes: 23 | { type: "analogValue", instance: "22" } 24 | properties: 25 | value: 26 | { type: "Float", size: "4", readWrite: "R", precision: "3.2", defaultValue: "0.00", minimum: "0.00", maximum: "100.00" } 27 | units: 28 | { type: "String", readWrite: "R", defaultValue: "RelativeHumidity" } 29 | - 30 | name: "AnalogValue_20" 31 | description: "The occupied cooling set point." 32 | attributes: 33 | { type: "analogValue", instance: "20" } 34 | properties: 35 | value: 36 | { type: "Float", size: "4", readWrite: "R", precision: "3.2", defaultValue: "0.00", minimum: "-99.99", maximum: "199.99" } 37 | units: 38 | { type: "String", readWrite: "R", defaultValue: "DegreesFarenheit" } 39 | - 40 | name: "AnalogValue_21" 41 | description: "The occupied heating set point." 42 | attributes: 43 | { type: "analogValue", instance: "21" } 44 | properties: 45 | value: 46 | { type: "Float", size: "4", readWrite: "R", precision: "3.2", defaultValue: "0.00", minimum: "-99.99", maximum: "199.99" } 47 | units: 48 | { type: "String", readWrite: "R", defaultValue: "DegreesFarenheit" } 49 | - 50 | name: "enableRandomization" 51 | description: "whether generating random value in each collection cycle" 52 | properties: 53 | value: 54 | { type: "Boolean", size: "1", readWrite: "W", defaultValue: "true" } 55 | units: 56 | { type: "String", readWrite: "R", defaultValue: "Random" } 57 | - 58 | name: "collectionFrequency" 59 | description: "the frequency of collection" 60 | properties: 61 | value: 62 | { type: "Integer", size: "4", readWrite: "W", precision: "3", defaultValue: "15", minimum: "0", maximum: "600" } 63 | units: 64 | { type: "String", readWrite: "R", defaultValue: "Seconds" } 65 | 66 | resources: 67 | - 68 | name: "CurrentTemperature" 69 | get: 70 | - 71 | { operation: "get", object: "AnalogValue_40", property: "value", parameter: "CurrentTemperature" } 72 | set: 73 | - 74 | { operation: "set", object: "enableRandomization", property: "value", parameter: "enableRandomization" } 75 | - 76 | { operation: "set", object: "collectionFrequency", property: "value", parameter: "collectionFrequency" } 77 | - 78 | name: "CurrentHumidity" 79 | get: 80 | - 81 | { operation: "get", object: "AnalogValue_22", property: "value", parameter: "CurrentHumidity" } 82 | set: 83 | - 84 | { operation: "set", object: "enableRandomization", property: "value", parameter: "enableRandomization" } 85 | - 86 | { operation: "set", object: "collectionFrequency", property: "value", parameter: "collectionFrequency" } 87 | - 88 | name: "OccupiedCoolingSetPoint" 89 | get: 90 | - 91 | { operation: "get", object: "AnalogValue_20", property: "value", parameter: "OccupiedCoolingSetPoint" } 92 | set: 93 | - 94 | { operation: "set", object: "enableRandomization", property: "value", parameter: "enableRandomization" } 95 | - 96 | { operation: "set", object: "collectionFrequency", property: "value", parameter: "collectionFrequency" } 97 | - 98 | name: "OccupiedHeatingSetPoint" 99 | get: 100 | - 101 | { operation: "get", object: "AnalogValue_21", property: "value", parameter: "OccupiedHeatingSetPoint" } 102 | set: 103 | - 104 | { operation: "set", object: "enableRandomization", property: "value", parameter: "enableRandomization" } 105 | - 106 | { operation: "set", object: "collectionFrequency", property: "value", parameter: "collectionFrequency" } 107 | 108 | commands: 109 | - 110 | name: "CurrentTemperature" 111 | get: 112 | path: "/api/v1/device/{deviceId}/CurrentTemperature" 113 | responses: 114 | - 115 | code: "200" 116 | description: "" 117 | expectedValues: ["AnalogValue_40"] 118 | - 119 | code: "503" 120 | description: "service unavailable" 121 | expectedValues: [] 122 | put: 123 | path: "/api/v1/device/{deviceId}/CurrentTemperature" 124 | parameterNames: ["enableRandomization","collectionFrequency"] 125 | responses: 126 | - 127 | code: "204" 128 | description: "valid and accepted" 129 | expectedValues: [] 130 | - 131 | code: "400" 132 | description: "bad request" 133 | expectedValues: [] 134 | - 135 | code: "503" 136 | description: "service unavailable" 137 | expectedValues: [] 138 | - 139 | name: "CurrentHumidity" 140 | get: 141 | path: "/api/v1/device/{deviceId}/CurrentHumidity" 142 | responses: 143 | - 144 | code: "200" 145 | description: "" 146 | expectedValues: ["AnalogValue_22"] 147 | - 148 | code: "503" 149 | description: "service unavailable" 150 | expectedValues: [] 151 | put: 152 | path: "/api/v1/device/{deviceId}/CurrentHumidity" 153 | parameterNames: ["enableRandomization","collectionFrequency"] 154 | responses: 155 | - 156 | code: "204" 157 | description: "valid and accepted" 158 | expectedValues: [] 159 | - 160 | code: "400" 161 | description: "bad request" 162 | expectedValues: [] 163 | - 164 | code: "503" 165 | description: "service unavailable" 166 | expectedValues: [] 167 | - 168 | name: "OccupiedCoolingSetPoint" 169 | get: 170 | path: "/api/v1/device/{deviceId}/OccupiedCoolingSetPoint" 171 | responses: 172 | - 173 | code: "200" 174 | description: "" 175 | expectedValues: ["AnalogValue_20"] 176 | - 177 | code: "503" 178 | description: "service unavailable" 179 | expectedValues: [] 180 | put: 181 | path: "/api/v1/device/{deviceId}/OccupiedCoolingSetPoint" 182 | parameterNames: ["enableRandomization","collectionFrequency"] 183 | responses: 184 | - 185 | code: "204" 186 | description: "valid and accepted" 187 | expectedValues: [] 188 | - 189 | code: "400" 190 | description: "bad request" 191 | expectedValues: [] 192 | - 193 | code: "503" 194 | description: "service unavailable" 195 | expectedValues: [] 196 | - 197 | name: "OccupiedHeatingSetPoint" 198 | get: 199 | path: "/api/v1/device/{deviceId}/OccupiedHeatingSetPoint" 200 | responses: 201 | - 202 | code: "200" 203 | description: "" 204 | expectedValues: ["AnalogValue_21"] 205 | - 206 | code: "503" 207 | description: "service unavailable" 208 | expectedValues: [] 209 | put: 210 | path: "/api/v1/device/{deviceId}/OccupiedHeatingSetPoint" 211 | parameterNames: ["enableRandomization","collectionFrequency"] 212 | responses: 213 | - 214 | code: "204" 215 | description: "valid and accepted" 216 | expectedValues: [] 217 | - 218 | code: "400" 219 | description: "bad request" 220 | expectedValues: [] 221 | - 222 | code: "503" 223 | description: "service unavailable" 224 | expectedValues: [] 225 | --------------------------------------------------------------------------------