92 changed files with 4276 additions and 169 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,46 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2019 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.config; |
||||
|
|
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.scheduling.TaskScheduler; |
||||
|
import org.springframework.scheduling.annotation.EnableScheduling; |
||||
|
import org.springframework.scheduling.annotation.SchedulingConfigurer; |
||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; |
||||
|
import org.springframework.scheduling.config.ScheduledTaskRegistrar; |
||||
|
|
||||
|
import java.util.concurrent.Executor; |
||||
|
import java.util.concurrent.Executors; |
||||
|
|
||||
|
@Configuration |
||||
|
@EnableScheduling |
||||
|
public class SchedulingConfiguration implements SchedulingConfigurer { |
||||
|
|
||||
|
@Override |
||||
|
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { |
||||
|
taskRegistrar.setScheduler(taskScheduler()); |
||||
|
} |
||||
|
|
||||
|
@Bean(destroyMethod="shutdown") |
||||
|
public TaskScheduler taskScheduler() { |
||||
|
ThreadPoolTaskScheduler threadPoolScheduler = new ThreadPoolTaskScheduler(); |
||||
|
threadPoolScheduler.setThreadNamePrefix("TB-Scheduling-"); |
||||
|
threadPoolScheduler.setPoolSize(Runtime.getRuntime().availableProcessors()); |
||||
|
threadPoolScheduler.setRemoveOnCancelPolicy(true); |
||||
|
return threadPoolScheduler; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,5 @@ |
|||||
|
|
||||
|
# Database used by ThingsBoard, can be either postgres (PostgreSQL) or cassandra (Cassandra). |
||||
|
# According to the database type corresponding kubernetes resources will be deployed (see postgres.yml, cassandra.yml for details). |
||||
|
|
||||
|
DATABASE=postgres |
||||
@ -0,0 +1,100 @@ |
|||||
|
# Kubernetes resources configuration for ThingsBoard Microservices |
||||
|
|
||||
|
This folder containing scripts and Kubernetes resources configurations to run ThingsBoard in Microservices mode. |
||||
|
|
||||
|
## Prerequisites |
||||
|
|
||||
|
ThingsBoard Microservices are running on Kubernetes cluster. |
||||
|
You need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. |
||||
|
If you do not already have a cluster, you can create one by using [Minikube](https://kubernetes.io/docs/setup/minikube), |
||||
|
or you can choose any other available [Kubernetes cluster deployment solutions](https://kubernetes.io/docs/setup/pick-right-solution/). |
||||
|
|
||||
|
## Installation |
||||
|
|
||||
|
Before performing initial installation you can configure the type of database to be used with ThingsBoard. |
||||
|
In order to set database type change the value of `DATABASE` variable in `.env` file to one of the following: |
||||
|
|
||||
|
- `postgres` - use PostgreSQL database; |
||||
|
- `cassandra` - use Cassandra database; |
||||
|
|
||||
|
**NOTE**: According to the database type corresponding kubernetes resources will be deployed (see `postgres.yml`, `cassandra.yml` for details). |
||||
|
|
||||
|
Execute the following command to run installation: |
||||
|
|
||||
|
` |
||||
|
$ ./k8s-install-tb.sh --loadDemo |
||||
|
` |
||||
|
|
||||
|
Where: |
||||
|
|
||||
|
- `--loadDemo` - optional argument. Whether to load additional demo data. |
||||
|
|
||||
|
## Running |
||||
|
|
||||
|
Execute the following command to deploy resources: |
||||
|
|
||||
|
` |
||||
|
$ ./k8s-deploy-resources.sh |
||||
|
` |
||||
|
|
||||
|
After a while when all resources will be successfully started you can open `http://{your-cluster-ip}` in you browser (for ex. `http://192.168.99.101`). |
||||
|
You should see ThingsBoard login page. |
||||
|
|
||||
|
Use the following default credentials: |
||||
|
|
||||
|
- **System Administrator**: sysadmin@thingsboard.org / sysadmin |
||||
|
|
||||
|
If you installed DataBase with demo data (using `--loadDemo` flag) you can also use the following credentials: |
||||
|
|
||||
|
- **Tenant Administrator**: tenant@thingsboard.org / tenant |
||||
|
- **Customer User**: customer@thingsboard.org / customer |
||||
|
|
||||
|
In case of any issues you can examine service logs for errors. |
||||
|
For example to see ThingsBoard node logs execute the following commands: |
||||
|
|
||||
|
1) Get list of the running tb-node pods: |
||||
|
|
||||
|
` |
||||
|
$ kubectl get pods -l app=tb-node |
||||
|
` |
||||
|
|
||||
|
2) Fetch logs of tb-node pod: |
||||
|
|
||||
|
` |
||||
|
$ kubectl logs -f [tb-node-pod-name] |
||||
|
` |
||||
|
|
||||
|
Where: |
||||
|
|
||||
|
- `tb-node-pod-name` - tb-node pod name obtained from the list of the running tb-node pods. |
||||
|
|
||||
|
Or use `kubectl get pods` to see the state of all the pods. |
||||
|
Or use `kubectl get services` to see the state of all the services. |
||||
|
Or use `kubectl get deployments` to see the state of all the deployments. |
||||
|
See [kubectl Cheat Sheet](https://kubernetes.io/docs/reference/kubectl/cheatsheet/) command reference for details. |
||||
|
|
||||
|
Execute the following command to delete all deployed microservices: |
||||
|
|
||||
|
` |
||||
|
$ ./k8s-delete-resources.sh |
||||
|
` |
||||
|
|
||||
|
Execute the following command to delete all resources (including database): |
||||
|
|
||||
|
` |
||||
|
$ ./k8s-delete-all.sh |
||||
|
` |
||||
|
|
||||
|
## Upgrading |
||||
|
|
||||
|
In case when database upgrade is needed, execute the following commands: |
||||
|
|
||||
|
``` |
||||
|
$ ./k8s-delete-resources.sh |
||||
|
$ ./k8s-upgrade-tb.sh --fromVersion=[FROM_VERSION] |
||||
|
$ ./k8s-deploy-resources.sh |
||||
|
``` |
||||
|
|
||||
|
Where: |
||||
|
|
||||
|
- `FROM_VERSION` - from which version upgrade should be started. See [Upgrade Instructions](https://thingsboard.io/docs/user-guide/install/upgrade-instructions) for valid `fromVersion` values. |
||||
@ -0,0 +1,164 @@ |
|||||
|
# |
||||
|
# Copyright © 2016-2019 The Thingsboard Authors |
||||
|
# |
||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
# you may not use this file except in compliance with the License. |
||||
|
# You may obtain a copy of the License at |
||||
|
# |
||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
# |
||||
|
# Unless required by applicable law or agreed to in writing, software |
||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
# See the License for the specific language governing permissions and |
||||
|
# limitations under the License. |
||||
|
# |
||||
|
|
||||
|
apiVersion: storage.k8s.io/v1 |
||||
|
kind: StorageClass |
||||
|
metadata: |
||||
|
name: fast |
||||
|
namespace: thingsboard |
||||
|
provisioner: k8s.io/minikube-hostpath |
||||
|
parameters: |
||||
|
type: pd-ssd |
||||
|
--- |
||||
|
apiVersion: v1 |
||||
|
kind: ConfigMap |
||||
|
metadata: |
||||
|
name: cassandra-probe-config |
||||
|
namespace: thingsboard |
||||
|
labels: |
||||
|
name: cassandra-probe-config |
||||
|
data: |
||||
|
probe: | |
||||
|
if [[ $(nodetool status | grep $POD_IP) == *"UN"* ]]; then |
||||
|
if [[ $DEBUG ]]; then |
||||
|
echo "UN"; |
||||
|
fi |
||||
|
exit 0; |
||||
|
else |
||||
|
if [[ $DEBUG ]]; then |
||||
|
echo "Not Up"; |
||||
|
fi |
||||
|
exit 1; |
||||
|
fi |
||||
|
--- |
||||
|
apiVersion: apps/v1 |
||||
|
kind: StatefulSet |
||||
|
metadata: |
||||
|
name: cassandra |
||||
|
namespace: thingsboard |
||||
|
labels: |
||||
|
app: cassandra |
||||
|
spec: |
||||
|
serviceName: cassandra |
||||
|
replicas: 1 |
||||
|
selector: |
||||
|
matchLabels: |
||||
|
app: cassandra |
||||
|
template: |
||||
|
metadata: |
||||
|
labels: |
||||
|
app: cassandra |
||||
|
spec: |
||||
|
volumes: |
||||
|
- name: cassandra-probe-config |
||||
|
configMap: |
||||
|
name: cassandra-probe-config |
||||
|
items: |
||||
|
- key: probe |
||||
|
path: ready-probe.sh |
||||
|
mode: 0777 |
||||
|
terminationGracePeriodSeconds: 1800 |
||||
|
containers: |
||||
|
- name: cassandra |
||||
|
image: cassandra:3.11.3 |
||||
|
imagePullPolicy: Always |
||||
|
ports: |
||||
|
- containerPort: 7000 |
||||
|
name: intra-node |
||||
|
- containerPort: 7001 |
||||
|
name: tls-intra-node |
||||
|
- containerPort: 7199 |
||||
|
name: jmx |
||||
|
- containerPort: 9042 |
||||
|
name: cql |
||||
|
- containerPort: 9160 |
||||
|
name: thrift |
||||
|
resources: |
||||
|
limits: |
||||
|
cpu: "1000m" |
||||
|
memory: 2Gi |
||||
|
requests: |
||||
|
cpu: "1000m" |
||||
|
memory: 2Gi |
||||
|
securityContext: |
||||
|
capabilities: |
||||
|
add: |
||||
|
- IPC_LOCK |
||||
|
lifecycle: |
||||
|
preStop: |
||||
|
exec: |
||||
|
command: |
||||
|
- /bin/sh |
||||
|
- -c |
||||
|
- nodetool drain |
||||
|
env: |
||||
|
- name: CASSANDRA_SEEDS |
||||
|
value: "cassandra-0.cassandra.thingsboard.svc.cluster.local" |
||||
|
- name: MAX_HEAP_SIZE |
||||
|
value: 1024M |
||||
|
- name: HEAP_NEWSIZE |
||||
|
value: 256M |
||||
|
- name: CASSANDRA_CLUSTER_NAME |
||||
|
value: "Thingsboard Cluster" |
||||
|
- name: CASSANDRA_DC |
||||
|
value: "DC1-Thingsboard-Cluster" |
||||
|
- name: CASSANDRA_RACK |
||||
|
value: "Rack-Thingsboard-Cluster" |
||||
|
- name: CASSANDRA_AUTO_BOOTSTRAP |
||||
|
value: "false" |
||||
|
- name: CASSANDRA_ENDPOINT_SNITCH |
||||
|
value: GossipingPropertyFileSnitch |
||||
|
- name: POD_IP |
||||
|
valueFrom: |
||||
|
fieldRef: |
||||
|
fieldPath: status.podIP |
||||
|
readinessProbe: |
||||
|
exec: |
||||
|
command: |
||||
|
- /bin/bash |
||||
|
- -c |
||||
|
- /probe/ready-probe.sh |
||||
|
initialDelaySeconds: 60 |
||||
|
timeoutSeconds: 5 |
||||
|
volumeMounts: |
||||
|
- name: cassandra-probe-config |
||||
|
mountPath: /probe |
||||
|
- name: cassandra-data |
||||
|
mountPath: /var/lib/cassandra |
||||
|
volumeClaimTemplates: |
||||
|
- metadata: |
||||
|
name: cassandra-data |
||||
|
spec: |
||||
|
accessModes: [ "ReadWriteOnce" ] |
||||
|
storageClassName: fast |
||||
|
resources: |
||||
|
requests: |
||||
|
storage: 1Gi |
||||
|
--- |
||||
|
apiVersion: v1 |
||||
|
kind: Service |
||||
|
metadata: |
||||
|
labels: |
||||
|
app: cassandra |
||||
|
name: cassandra |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
clusterIP: None |
||||
|
ports: |
||||
|
- port: 9042 |
||||
|
selector: |
||||
|
app: cassandra |
||||
|
--- |
||||
@ -0,0 +1,43 @@ |
|||||
|
# |
||||
|
# Copyright © 2016-2019 The Thingsboard Authors |
||||
|
# |
||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
# you may not use this file except in compliance with the License. |
||||
|
# You may obtain a copy of the License at |
||||
|
# |
||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
# |
||||
|
# Unless required by applicable law or agreed to in writing, software |
||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
# See the License for the specific language governing permissions and |
||||
|
# limitations under the License. |
||||
|
# |
||||
|
|
||||
|
apiVersion: v1 |
||||
|
kind: Pod |
||||
|
metadata: |
||||
|
name: tb-db-setup |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
volumes: |
||||
|
- name: tb-node-config |
||||
|
configMap: |
||||
|
name: tb-node-config |
||||
|
items: |
||||
|
- key: conf |
||||
|
path: thingsboard.conf |
||||
|
- key: logback |
||||
|
path: logback.xml |
||||
|
containers: |
||||
|
- name: tb-db-setup |
||||
|
imagePullPolicy: Always |
||||
|
image: thingsboard/tb-node:latest |
||||
|
envFrom: |
||||
|
- configMapRef: |
||||
|
name: tb-node-db-config |
||||
|
volumeMounts: |
||||
|
- mountPath: /config |
||||
|
name: tb-node-config |
||||
|
command: ['sh', '-c', 'while [ ! -f /install-finished ]; do sleep 2; done;'] |
||||
|
restartPolicy: Never |
||||
@ -0,0 +1,18 @@ |
|||||
|
#!/bin/bash |
||||
|
# |
||||
|
# Copyright © 2016-2019 The Thingsboard Authors |
||||
|
# |
||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
# you may not use this file except in compliance with the License. |
||||
|
# You may obtain a copy of the License at |
||||
|
# |
||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
# |
||||
|
# Unless required by applicable law or agreed to in writing, software |
||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
# See the License for the specific language governing permissions and |
||||
|
# limitations under the License. |
||||
|
# |
||||
|
|
||||
|
kubectl -n thingsboard delete svc,sts,deploy,pv,pvc,cm,po,ing --all --include-uninitialized |
||||
@ -0,0 +1,21 @@ |
|||||
|
#!/bin/bash |
||||
|
# |
||||
|
# Copyright © 2016-2019 The Thingsboard Authors |
||||
|
# |
||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
# you may not use this file except in compliance with the License. |
||||
|
# You may obtain a copy of the License at |
||||
|
# |
||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
# |
||||
|
# Unless required by applicable law or agreed to in writing, software |
||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
# See the License for the specific language governing permissions and |
||||
|
# limitations under the License. |
||||
|
# |
||||
|
|
||||
|
set -e |
||||
|
|
||||
|
kubectl config set-context $(kubectl config current-context) --namespace=thingsboard |
||||
|
kubectl delete -f thingsboard.yml |
||||
@ -0,0 +1,26 @@ |
|||||
|
#!/bin/bash |
||||
|
# |
||||
|
# Copyright © 2016-2019 The Thingsboard Authors |
||||
|
# |
||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
# you may not use this file except in compliance with the License. |
||||
|
# You may obtain a copy of the License at |
||||
|
# |
||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
# |
||||
|
# Unless required by applicable law or agreed to in writing, software |
||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
# See the License for the specific language governing permissions and |
||||
|
# limitations under the License. |
||||
|
# |
||||
|
|
||||
|
set -e |
||||
|
|
||||
|
kubectl apply -f tb-namespace.yml |
||||
|
kubectl config set-context $(kubectl config current-context) --namespace=thingsboard |
||||
|
kubectl apply -f tb-node-configmap.yml |
||||
|
kubectl apply -f tb-mqtt-transport-configmap.yml |
||||
|
kubectl apply -f tb-http-transport-configmap.yml |
||||
|
kubectl apply -f tb-coap-transport-configmap.yml |
||||
|
kubectl apply -f thingsboard.yml |
||||
@ -0,0 +1,93 @@ |
|||||
|
#!/bin/bash |
||||
|
# |
||||
|
# Copyright © 2016-2019 The Thingsboard Authors |
||||
|
# |
||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
# you may not use this file except in compliance with the License. |
||||
|
# You may obtain a copy of the License at |
||||
|
# |
||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
# |
||||
|
# Unless required by applicable law or agreed to in writing, software |
||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
# See the License for the specific language governing permissions and |
||||
|
# limitations under the License. |
||||
|
# |
||||
|
|
||||
|
function installTb() { |
||||
|
|
||||
|
loadDemo=$1 |
||||
|
|
||||
|
kubectl apply -f tb-node-configmap.yml |
||||
|
kubectl apply -f database-setup.yml && |
||||
|
kubectl wait --for=condition=Ready pod/tb-db-setup --timeout=120s && |
||||
|
kubectl exec tb-db-setup -- sh -c 'export INSTALL_TB=true; export LOAD_DEMO='"$loadDemo"'; start-tb-node.sh; touch /install-finished;' |
||||
|
|
||||
|
kubectl delete pod tb-db-setup |
||||
|
|
||||
|
} |
||||
|
|
||||
|
function installPostgres() { |
||||
|
|
||||
|
kubectl apply -f postgres.yml |
||||
|
kubectl apply -f tb-node-postgres-configmap.yml |
||||
|
|
||||
|
kubectl rollout status deployment/postgres |
||||
|
} |
||||
|
|
||||
|
function installCassandra() { |
||||
|
|
||||
|
kubectl apply -f cassandra.yml |
||||
|
kubectl apply -f tb-node-cassandra-configmap.yml |
||||
|
|
||||
|
kubectl rollout status statefulset/cassandra |
||||
|
|
||||
|
kubectl exec -it cassandra-0 -- bash -c "cqlsh -e \ |
||||
|
\"CREATE KEYSPACE IF NOT EXISTS thingsboard \ |
||||
|
WITH replication = { \ |
||||
|
'class' : 'SimpleStrategy', \ |
||||
|
'replication_factor' : 1 \ |
||||
|
};\"" |
||||
|
} |
||||
|
|
||||
|
while [[ $# -gt 0 ]] |
||||
|
do |
||||
|
key="$1" |
||||
|
|
||||
|
case $key in |
||||
|
--loadDemo) |
||||
|
LOAD_DEMO=true |
||||
|
shift # past argument |
||||
|
;; |
||||
|
*) |
||||
|
# unknown option |
||||
|
;; |
||||
|
esac |
||||
|
shift # past argument or value |
||||
|
done |
||||
|
|
||||
|
if [ "$LOAD_DEMO" == "true" ]; then |
||||
|
loadDemo=true |
||||
|
else |
||||
|
loadDemo=false |
||||
|
fi |
||||
|
|
||||
|
source .env |
||||
|
|
||||
|
kubectl apply -f tb-namespace.yml |
||||
|
kubectl config set-context $(kubectl config current-context) --namespace=thingsboard |
||||
|
|
||||
|
case $DATABASE in |
||||
|
postgres) |
||||
|
installPostgres |
||||
|
installTb ${loadDemo} |
||||
|
;; |
||||
|
cassandra) |
||||
|
installCassandra |
||||
|
installTb ${loadDemo} |
||||
|
;; |
||||
|
*) |
||||
|
echo "Unknown DATABASE value specified: '${DATABASE}'. Should be either postgres or cassandra." >&2 |
||||
|
exit 1 |
||||
|
esac |
||||
@ -0,0 +1,43 @@ |
|||||
|
#!/bin/bash |
||||
|
# |
||||
|
# Copyright © 2016-2019 The Thingsboard Authors |
||||
|
# |
||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
# you may not use this file except in compliance with the License. |
||||
|
# You may obtain a copy of the License at |
||||
|
# |
||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
# |
||||
|
# Unless required by applicable law or agreed to in writing, software |
||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
# See the License for the specific language governing permissions and |
||||
|
# limitations under the License. |
||||
|
# |
||||
|
|
||||
|
for i in "$@" |
||||
|
do |
||||
|
case $i in |
||||
|
--fromVersion=*) |
||||
|
FROM_VERSION="${i#*=}" |
||||
|
shift |
||||
|
;; |
||||
|
*) |
||||
|
# unknown option |
||||
|
;; |
||||
|
esac |
||||
|
done |
||||
|
|
||||
|
if [[ -z "${FROM_VERSION// }" ]]; then |
||||
|
echo "--fromVersion parameter is invalid or unspecified!" |
||||
|
echo "Usage: k8s-upgrade-tb.sh --fromVersion={VERSION}" |
||||
|
exit 1 |
||||
|
else |
||||
|
fromVersion="${FROM_VERSION// }" |
||||
|
fi |
||||
|
|
||||
|
kubectl apply -f database-setup.yml && |
||||
|
kubectl wait --for=condition=Ready pod/tb-db-setup --timeout=120s && |
||||
|
kubectl exec tb-db-setup -- sh -c 'export UPGRADE_TB=true; export FROM_VERSION='"$fromVersion"'; start-tb-node.sh; touch /install-finished;' |
||||
|
|
||||
|
kubectl delete pod tb-db-setup |
||||
@ -0,0 +1,95 @@ |
|||||
|
# |
||||
|
# Copyright © 2016-2019 The Thingsboard Authors |
||||
|
# |
||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
# you may not use this file except in compliance with the License. |
||||
|
# You may obtain a copy of the License at |
||||
|
# |
||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
# |
||||
|
# Unless required by applicable law or agreed to in writing, software |
||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
# See the License for the specific language governing permissions and |
||||
|
# limitations under the License. |
||||
|
# |
||||
|
|
||||
|
apiVersion: v1 |
||||
|
kind: PersistentVolumeClaim |
||||
|
metadata: |
||||
|
name: postgres-pv-claim |
||||
|
namespace: thingsboard |
||||
|
labels: |
||||
|
app: postgres |
||||
|
spec: |
||||
|
accessModes: |
||||
|
- ReadWriteOnce |
||||
|
resources: |
||||
|
requests: |
||||
|
storage: 5Gi |
||||
|
--- |
||||
|
apiVersion: extensions/v1beta1 |
||||
|
kind: Deployment |
||||
|
metadata: |
||||
|
name: postgres |
||||
|
namespace: thingsboard |
||||
|
labels: |
||||
|
app: postgres |
||||
|
spec: |
||||
|
template: |
||||
|
metadata: |
||||
|
labels: |
||||
|
app: postgres |
||||
|
spec: |
||||
|
volumes: |
||||
|
- name: postgres-data |
||||
|
persistentVolumeClaim: |
||||
|
claimName: postgres-pv-claim |
||||
|
containers: |
||||
|
- name: postgres |
||||
|
imagePullPolicy: Always |
||||
|
image: postgres:9.6 |
||||
|
ports: |
||||
|
- containerPort: 5432 |
||||
|
name: postgres |
||||
|
env: |
||||
|
- name: POSTGRES_DB |
||||
|
value: "thingsboard" |
||||
|
volumeMounts: |
||||
|
- mountPath: /var/lib/postgresql/data |
||||
|
name: postgres-data |
||||
|
livenessProbe: |
||||
|
exec: |
||||
|
command: |
||||
|
- pg_isready |
||||
|
- -h |
||||
|
- localhost |
||||
|
- -U |
||||
|
- postgres |
||||
|
initialDelaySeconds: 60 |
||||
|
timeoutSeconds: 30 |
||||
|
readinessProbe: |
||||
|
exec: |
||||
|
command: |
||||
|
- pg_isready |
||||
|
- -h |
||||
|
- localhost |
||||
|
- -U |
||||
|
- postgres |
||||
|
initialDelaySeconds: 5 |
||||
|
timeoutSeconds: 1 |
||||
|
restartPolicy: Always |
||||
|
--- |
||||
|
apiVersion: v1 |
||||
|
kind: Service |
||||
|
metadata: |
||||
|
name: tb-database |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
type: ClusterIP |
||||
|
selector: |
||||
|
app: postgres |
||||
|
ports: |
||||
|
- port: 5432 |
||||
|
name: postgres |
||||
|
--- |
||||
@ -0,0 +1,65 @@ |
|||||
|
# |
||||
|
# Copyright © 2016-2019 The Thingsboard Authors |
||||
|
# |
||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
# you may not use this file except in compliance with the License. |
||||
|
# You may obtain a copy of the License at |
||||
|
# |
||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
# |
||||
|
# Unless required by applicable law or agreed to in writing, software |
||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
# See the License for the specific language governing permissions and |
||||
|
# limitations under the License. |
||||
|
# |
||||
|
|
||||
|
apiVersion: v1 |
||||
|
kind: ConfigMap |
||||
|
metadata: |
||||
|
name: tb-coap-transport-config |
||||
|
namespace: thingsboard |
||||
|
labels: |
||||
|
name: tb-coap-transport-config |
||||
|
data: |
||||
|
conf: | |
||||
|
export JAVA_OPTS="$JAVA_OPTS -Xloggc:/var/log/tb-coap-transport/${TB_HOST}/gc.log -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/tb-coap-transport/${TB_HOST}/heapdump.bin -XX:+PrintGCDetails -XX:+PrintGCDateStamps" |
||||
|
export JAVA_OPTS="$JAVA_OPTS -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10" |
||||
|
export JAVA_OPTS="$JAVA_OPTS -XX:GCLogFileSize=10M -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark" |
||||
|
export JAVA_OPTS="$JAVA_OPTS -XX:CMSWaitDuration=10000 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+CMSParallelInitialMarkEnabled" |
||||
|
export JAVA_OPTS="$JAVA_OPTS -XX:+CMSEdenChunksRecordAlways -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -XX:+ExitOnOutOfMemoryError" |
||||
|
export LOG_FILENAME=tb-coap-transport.out |
||||
|
export LOADER_PATH=/usr/share/tb-coap-transport/conf |
||||
|
logback: | |
||||
|
<!DOCTYPE configuration> |
||||
|
<configuration scan="true" scanPeriod="10 seconds"> |
||||
|
|
||||
|
<appender name="fileLogAppender" |
||||
|
class="ch.qos.logback.core.rolling.RollingFileAppender"> |
||||
|
<file>/var/log/tb-coap-transport/${TB_HOST}/tb-coap-transport.log</file> |
||||
|
<rollingPolicy |
||||
|
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> |
||||
|
<fileNamePattern>/var/log/tb-coap-transport/${TB_HOST}/tb-coap-transport.%d{yyyy-MM-dd}.%i.log</fileNamePattern> |
||||
|
<maxFileSize>100MB</maxFileSize> |
||||
|
<maxHistory>30</maxHistory> |
||||
|
<totalSizeCap>3GB</totalSizeCap> |
||||
|
</rollingPolicy> |
||||
|
<encoder> |
||||
|
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern> |
||||
|
</encoder> |
||||
|
</appender> |
||||
|
|
||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> |
||||
|
<encoder> |
||||
|
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern> |
||||
|
</encoder> |
||||
|
</appender> |
||||
|
|
||||
|
<logger name="org.thingsboard.server" level="INFO" /> |
||||
|
|
||||
|
<root level="INFO"> |
||||
|
<appender-ref ref="fileLogAppender"/> |
||||
|
<appender-ref ref="STDOUT"/> |
||||
|
</root> |
||||
|
|
||||
|
</configuration> |
||||
@ -0,0 +1,65 @@ |
|||||
|
# |
||||
|
# Copyright © 2016-2019 The Thingsboard Authors |
||||
|
# |
||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
# you may not use this file except in compliance with the License. |
||||
|
# You may obtain a copy of the License at |
||||
|
# |
||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
# |
||||
|
# Unless required by applicable law or agreed to in writing, software |
||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
# See the License for the specific language governing permissions and |
||||
|
# limitations under the License. |
||||
|
# |
||||
|
|
||||
|
apiVersion: v1 |
||||
|
kind: ConfigMap |
||||
|
metadata: |
||||
|
name: tb-http-transport-config |
||||
|
namespace: thingsboard |
||||
|
labels: |
||||
|
name: tb-http-transport-config |
||||
|
data: |
||||
|
conf: | |
||||
|
export JAVA_OPTS="$JAVA_OPTS -Xloggc:/var/log/tb-http-transport/${TB_HOST}/gc.log -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/tb-http-transport/${TB_HOST}/heapdump.bin -XX:+PrintGCDetails -XX:+PrintGCDateStamps" |
||||
|
export JAVA_OPTS="$JAVA_OPTS -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10" |
||||
|
export JAVA_OPTS="$JAVA_OPTS -XX:GCLogFileSize=10M -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark" |
||||
|
export JAVA_OPTS="$JAVA_OPTS -XX:CMSWaitDuration=10000 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+CMSParallelInitialMarkEnabled" |
||||
|
export JAVA_OPTS="$JAVA_OPTS -XX:+CMSEdenChunksRecordAlways -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -XX:+ExitOnOutOfMemoryError" |
||||
|
export LOG_FILENAME=tb-http-transport.out |
||||
|
export LOADER_PATH=/usr/share/tb-http-transport/conf |
||||
|
logback: | |
||||
|
<!DOCTYPE configuration> |
||||
|
<configuration scan="true" scanPeriod="10 seconds"> |
||||
|
|
||||
|
<appender name="fileLogAppender" |
||||
|
class="ch.qos.logback.core.rolling.RollingFileAppender"> |
||||
|
<file>/var/log/tb-http-transport/${TB_HOST}/tb-http-transport.log</file> |
||||
|
<rollingPolicy |
||||
|
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> |
||||
|
<fileNamePattern>/var/log/tb-http-transport/${TB_HOST}/tb-http-transport.%d{yyyy-MM-dd}.%i.log</fileNamePattern> |
||||
|
<maxFileSize>100MB</maxFileSize> |
||||
|
<maxHistory>30</maxHistory> |
||||
|
<totalSizeCap>3GB</totalSizeCap> |
||||
|
</rollingPolicy> |
||||
|
<encoder> |
||||
|
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern> |
||||
|
</encoder> |
||||
|
</appender> |
||||
|
|
||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> |
||||
|
<encoder> |
||||
|
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern> |
||||
|
</encoder> |
||||
|
</appender> |
||||
|
|
||||
|
<logger name="org.thingsboard.server" level="INFO" /> |
||||
|
|
||||
|
<root level="INFO"> |
||||
|
<appender-ref ref="fileLogAppender"/> |
||||
|
<appender-ref ref="STDOUT"/> |
||||
|
</root> |
||||
|
|
||||
|
</configuration> |
||||
@ -0,0 +1,65 @@ |
|||||
|
# |
||||
|
# Copyright © 2016-2019 The Thingsboard Authors |
||||
|
# |
||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
# you may not use this file except in compliance with the License. |
||||
|
# You may obtain a copy of the License at |
||||
|
# |
||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
# |
||||
|
# Unless required by applicable law or agreed to in writing, software |
||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
# See the License for the specific language governing permissions and |
||||
|
# limitations under the License. |
||||
|
# |
||||
|
|
||||
|
apiVersion: v1 |
||||
|
kind: ConfigMap |
||||
|
metadata: |
||||
|
name: tb-mqtt-transport-config |
||||
|
namespace: thingsboard |
||||
|
labels: |
||||
|
name: tb-mqtt-transport-config |
||||
|
data: |
||||
|
conf: | |
||||
|
export JAVA_OPTS="$JAVA_OPTS -Xloggc:/var/log/tb-mqtt-transport/${TB_HOST}/gc.log -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/tb-mqtt-transport/${TB_HOST}/heapdump.bin -XX:+PrintGCDetails -XX:+PrintGCDateStamps" |
||||
|
export JAVA_OPTS="$JAVA_OPTS -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10" |
||||
|
export JAVA_OPTS="$JAVA_OPTS -XX:GCLogFileSize=10M -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark" |
||||
|
export JAVA_OPTS="$JAVA_OPTS -XX:CMSWaitDuration=10000 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+CMSParallelInitialMarkEnabled" |
||||
|
export JAVA_OPTS="$JAVA_OPTS -XX:+CMSEdenChunksRecordAlways -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -XX:+ExitOnOutOfMemoryError" |
||||
|
export LOG_FILENAME=tb-mqtt-transport.out |
||||
|
export LOADER_PATH=/usr/share/tb-mqtt-transport/conf |
||||
|
logback: | |
||||
|
<!DOCTYPE configuration> |
||||
|
<configuration scan="true" scanPeriod="10 seconds"> |
||||
|
|
||||
|
<appender name="fileLogAppender" |
||||
|
class="ch.qos.logback.core.rolling.RollingFileAppender"> |
||||
|
<file>/var/log/tb-mqtt-transport/${TB_HOST}/tb-mqtt-transport.log</file> |
||||
|
<rollingPolicy |
||||
|
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> |
||||
|
<fileNamePattern>/var/log/tb-mqtt-transport/${TB_HOST}/tb-mqtt-transport.%d{yyyy-MM-dd}.%i.log</fileNamePattern> |
||||
|
<maxFileSize>100MB</maxFileSize> |
||||
|
<maxHistory>30</maxHistory> |
||||
|
<totalSizeCap>3GB</totalSizeCap> |
||||
|
</rollingPolicy> |
||||
|
<encoder> |
||||
|
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern> |
||||
|
</encoder> |
||||
|
</appender> |
||||
|
|
||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> |
||||
|
<encoder> |
||||
|
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern> |
||||
|
</encoder> |
||||
|
</appender> |
||||
|
|
||||
|
<logger name="org.thingsboard.server" level="INFO" /> |
||||
|
|
||||
|
<root level="INFO"> |
||||
|
<appender-ref ref="fileLogAppender"/> |
||||
|
<appender-ref ref="STDOUT"/> |
||||
|
</root> |
||||
|
|
||||
|
</configuration> |
||||
@ -0,0 +1,22 @@ |
|||||
|
# |
||||
|
# Copyright © 2016-2019 The Thingsboard Authors |
||||
|
# |
||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
# you may not use this file except in compliance with the License. |
||||
|
# You may obtain a copy of the License at |
||||
|
# |
||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
# |
||||
|
# Unless required by applicable law or agreed to in writing, software |
||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
# See the License for the specific language governing permissions and |
||||
|
# limitations under the License. |
||||
|
# |
||||
|
|
||||
|
apiVersion: v1 |
||||
|
kind: Namespace |
||||
|
metadata: |
||||
|
name: thingsboard |
||||
|
labels: |
||||
|
name: thingsboard |
||||
@ -0,0 +1,28 @@ |
|||||
|
# |
||||
|
# Copyright © 2016-2019 The Thingsboard Authors |
||||
|
# |
||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
# you may not use this file except in compliance with the License. |
||||
|
# You may obtain a copy of the License at |
||||
|
# |
||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
# |
||||
|
# Unless required by applicable law or agreed to in writing, software |
||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
# See the License for the specific language governing permissions and |
||||
|
# limitations under the License. |
||||
|
# |
||||
|
|
||||
|
apiVersion: v1 |
||||
|
kind: ConfigMap |
||||
|
metadata: |
||||
|
name: tb-node-db-config |
||||
|
namespace: thingsboard |
||||
|
labels: |
||||
|
name: tb-node-db-config |
||||
|
data: |
||||
|
DATABASE_TS_TYPE: cassandra |
||||
|
DATABASE_ENTITIES_TYPE: cassandra |
||||
|
CASSANDRA_URL: cassandra:9042 |
||||
|
CASSANDRA_SOCKET_READ_TIMEOUT: "60000" |
||||
@ -0,0 +1,67 @@ |
|||||
|
# |
||||
|
# Copyright © 2016-2019 The Thingsboard Authors |
||||
|
# |
||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
# you may not use this file except in compliance with the License. |
||||
|
# You may obtain a copy of the License at |
||||
|
# |
||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
# |
||||
|
# Unless required by applicable law or agreed to in writing, software |
||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
# See the License for the specific language governing permissions and |
||||
|
# limitations under the License. |
||||
|
# |
||||
|
|
||||
|
apiVersion: v1 |
||||
|
kind: ConfigMap |
||||
|
metadata: |
||||
|
name: tb-node-config |
||||
|
namespace: thingsboard |
||||
|
labels: |
||||
|
name: tb-node-config |
||||
|
data: |
||||
|
conf: | |
||||
|
export JAVA_OPTS="$JAVA_OPTS -Dplatform=deb -Dinstall.data_dir=/usr/share/thingsboard/data" |
||||
|
export JAVA_OPTS="$JAVA_OPTS -Xloggc:/var/log/thingsboard/${TB_HOST}/gc.log -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/thingsboard/${TB_HOST}/heapdump.bin -XX:+PrintGCDetails -XX:+PrintGCDateStamps" |
||||
|
export JAVA_OPTS="$JAVA_OPTS -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10" |
||||
|
export JAVA_OPTS="$JAVA_OPTS -XX:GCLogFileSize=10M -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark" |
||||
|
export JAVA_OPTS="$JAVA_OPTS -XX:CMSWaitDuration=10000 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+CMSParallelInitialMarkEnabled" |
||||
|
export JAVA_OPTS="$JAVA_OPTS -XX:+CMSEdenChunksRecordAlways -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -XX:+ExitOnOutOfMemoryError" |
||||
|
export LOG_FILENAME=thingsboard.out |
||||
|
export LOADER_PATH=/usr/share/thingsboard/conf,/usr/share/thingsboard/extensions |
||||
|
logback: | |
||||
|
<!DOCTYPE configuration> |
||||
|
<configuration scan="true" scanPeriod="10 seconds"> |
||||
|
|
||||
|
<appender name="fileLogAppender" |
||||
|
class="ch.qos.logback.core.rolling.RollingFileAppender"> |
||||
|
<file>/var/log/thingsboard/${TB_HOST}/thingsboard.log</file> |
||||
|
<rollingPolicy |
||||
|
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> |
||||
|
<fileNamePattern>/var/log/thingsboard/${TB_HOST}/thingsboard.%d{yyyy-MM-dd}.%i.log</fileNamePattern> |
||||
|
<maxFileSize>100MB</maxFileSize> |
||||
|
<maxHistory>30</maxHistory> |
||||
|
<totalSizeCap>3GB</totalSizeCap> |
||||
|
</rollingPolicy> |
||||
|
<encoder> |
||||
|
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern> |
||||
|
</encoder> |
||||
|
</appender> |
||||
|
|
||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> |
||||
|
<encoder> |
||||
|
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern> |
||||
|
</encoder> |
||||
|
</appender> |
||||
|
|
||||
|
<logger name="org.thingsboard.server" level="INFO" /> |
||||
|
<logger name="com.google.common.util.concurrent.AggregateFuture" level="OFF" /> |
||||
|
|
||||
|
<root level="INFO"> |
||||
|
<appender-ref ref="fileLogAppender"/> |
||||
|
<appender-ref ref="STDOUT"/> |
||||
|
</root> |
||||
|
|
||||
|
</configuration> |
||||
@ -0,0 +1,31 @@ |
|||||
|
# |
||||
|
# Copyright © 2016-2019 The Thingsboard Authors |
||||
|
# |
||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
# you may not use this file except in compliance with the License. |
||||
|
# You may obtain a copy of the License at |
||||
|
# |
||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
# |
||||
|
# Unless required by applicable law or agreed to in writing, software |
||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
# See the License for the specific language governing permissions and |
||||
|
# limitations under the License. |
||||
|
# |
||||
|
|
||||
|
apiVersion: v1 |
||||
|
kind: ConfigMap |
||||
|
metadata: |
||||
|
name: tb-node-db-config |
||||
|
namespace: thingsboard |
||||
|
labels: |
||||
|
name: tb-node-db-config |
||||
|
data: |
||||
|
DATABASE_TS_TYPE: sql |
||||
|
DATABASE_ENTITIES_TYPE: sql |
||||
|
SPRING_JPA_DATABASE_PLATFORM: org.hibernate.dialect.PostgreSQLDialect |
||||
|
SPRING_DRIVER_CLASS_NAME: org.postgresql.Driver |
||||
|
SPRING_DATASOURCE_URL: jdbc:postgresql://tb-database:5432/thingsboard |
||||
|
SPRING_DATASOURCE_USERNAME: postgres |
||||
|
SPRING_DATASOURCE_PASSWORD: postgres |
||||
@ -0,0 +1,608 @@ |
|||||
|
# |
||||
|
# Copyright © 2016-2019 The Thingsboard Authors |
||||
|
# |
||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
# you may not use this file except in compliance with the License. |
||||
|
# You may obtain a copy of the License at |
||||
|
# |
||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
# |
||||
|
# Unless required by applicable law or agreed to in writing, software |
||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
# See the License for the specific language governing permissions and |
||||
|
# limitations under the License. |
||||
|
# |
||||
|
|
||||
|
apiVersion: extensions/v1beta1 |
||||
|
kind: Deployment |
||||
|
metadata: |
||||
|
name: zookeeper |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
template: |
||||
|
metadata: |
||||
|
labels: |
||||
|
app: zookeeper |
||||
|
spec: |
||||
|
containers: |
||||
|
- name: server |
||||
|
imagePullPolicy: Always |
||||
|
image: zookeeper:3.5 |
||||
|
ports: |
||||
|
- containerPort: 2181 |
||||
|
readinessProbe: |
||||
|
periodSeconds: 5 |
||||
|
tcpSocket: |
||||
|
port: 2181 |
||||
|
livenessProbe: |
||||
|
periodSeconds: 5 |
||||
|
tcpSocket: |
||||
|
port: 2181 |
||||
|
env: |
||||
|
- name: ZOO_MY_ID |
||||
|
value: "1" |
||||
|
- name: ZOO_SERVERS |
||||
|
value: "server.1=0.0.0.0:2888:3888;0.0.0.0:2181" |
||||
|
restartPolicy: Always |
||||
|
--- |
||||
|
apiVersion: v1 |
||||
|
kind: Service |
||||
|
metadata: |
||||
|
name: zookeeper |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
type: ClusterIP |
||||
|
selector: |
||||
|
app: zookeeper |
||||
|
ports: |
||||
|
- name: zk-port |
||||
|
port: 2181 |
||||
|
--- |
||||
|
apiVersion: extensions/v1beta1 |
||||
|
kind: Deployment |
||||
|
metadata: |
||||
|
name: tb-kafka |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
template: |
||||
|
metadata: |
||||
|
labels: |
||||
|
app: tb-kafka |
||||
|
spec: |
||||
|
containers: |
||||
|
- name: server |
||||
|
imagePullPolicy: Always |
||||
|
image: wurstmeister/kafka |
||||
|
ports: |
||||
|
- containerPort: 9092 |
||||
|
readinessProbe: |
||||
|
periodSeconds: 20 |
||||
|
tcpSocket: |
||||
|
port: 9092 |
||||
|
livenessProbe: |
||||
|
periodSeconds: 5 |
||||
|
tcpSocket: |
||||
|
port: 9092 |
||||
|
env: |
||||
|
- name: KAFKA_ZOOKEEPER_CONNECT |
||||
|
value: "zookeeper:2181" |
||||
|
- name: KAFKA_LISTENERS |
||||
|
value: "INSIDE://:9093,OUTSIDE://:9092" |
||||
|
- name: KAFKA_ADVERTISED_LISTENERS |
||||
|
value: "INSIDE://:9093,OUTSIDE://tb-kafka:9092" |
||||
|
- name: KAFKA_LISTENER_SECURITY_PROTOCOL_MAP |
||||
|
value: "INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT" |
||||
|
- name: KAFKA_INTER_BROKER_LISTENER_NAME |
||||
|
value: "INSIDE" |
||||
|
- name: KAFKA_CREATE_TOPICS |
||||
|
value: "js.eval.requests:100:1:delete --config=retention.ms=60000 --config=segment.bytes=26214400 --config=retention.bytes=104857600,tb.transport.api.requests:30:1:delete --config=retention.ms=60000 --config=segment.bytes=26214400 --config=retention.bytes=104857600,tb.rule-engine:30:1:delete --config=retention.ms=60000 --config=segment.bytes=26214400 --config=retention.bytes=104857600" |
||||
|
- name: KAFKA_AUTO_CREATE_TOPICS_ENABLE |
||||
|
value: "false" |
||||
|
- name: KAFKA_LOG_RETENTION_BYTES |
||||
|
value: "1073741824" |
||||
|
- name: KAFKA_LOG_SEGMENT_BYTES |
||||
|
value: "268435456" |
||||
|
- name: KAFKA_LOG_RETENTION_MS |
||||
|
value: "300000" |
||||
|
- name: KAFKA_LOG_CLEANUP_POLICY |
||||
|
value: "delete" |
||||
|
restartPolicy: Always |
||||
|
--- |
||||
|
apiVersion: v1 |
||||
|
kind: Service |
||||
|
metadata: |
||||
|
name: tb-kafka |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
type: ClusterIP |
||||
|
selector: |
||||
|
app: tb-kafka |
||||
|
ports: |
||||
|
- name: tb-kafka-port |
||||
|
port: 9092 |
||||
|
--- |
||||
|
apiVersion: extensions/v1beta1 |
||||
|
kind: Deployment |
||||
|
metadata: |
||||
|
name: tb-redis |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
template: |
||||
|
metadata: |
||||
|
labels: |
||||
|
app: tb-redis |
||||
|
spec: |
||||
|
containers: |
||||
|
- name: server |
||||
|
imagePullPolicy: Always |
||||
|
image: redis:4.0 |
||||
|
ports: |
||||
|
- containerPort: 6379 |
||||
|
readinessProbe: |
||||
|
periodSeconds: 5 |
||||
|
tcpSocket: |
||||
|
port: 6379 |
||||
|
livenessProbe: |
||||
|
periodSeconds: 5 |
||||
|
tcpSocket: |
||||
|
port: 6379 |
||||
|
volumeMounts: |
||||
|
- mountPath: /data |
||||
|
name: redis-data |
||||
|
volumes: |
||||
|
- name: redis-data |
||||
|
emptyDir: {} |
||||
|
restartPolicy: Always |
||||
|
--- |
||||
|
apiVersion: v1 |
||||
|
kind: Service |
||||
|
metadata: |
||||
|
name: tb-redis |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
type: ClusterIP |
||||
|
selector: |
||||
|
app: tb-redis |
||||
|
ports: |
||||
|
- name: tb-redis-port |
||||
|
port: 6379 |
||||
|
--- |
||||
|
apiVersion: extensions/v1beta1 |
||||
|
kind: Deployment |
||||
|
metadata: |
||||
|
name: tb-js-executor |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
replicas: 20 |
||||
|
selector: |
||||
|
matchLabels: |
||||
|
app: tb-js-executor |
||||
|
template: |
||||
|
metadata: |
||||
|
labels: |
||||
|
app: tb-js-executor |
||||
|
spec: |
||||
|
containers: |
||||
|
- name: server |
||||
|
imagePullPolicy: Always |
||||
|
image: thingsboard/tb-js-executor:latest |
||||
|
env: |
||||
|
- name: REMOTE_JS_EVAL_REQUEST_TOPIC |
||||
|
value: "js.eval.requests" |
||||
|
- name: TB_KAFKA_SERVERS |
||||
|
value: "tb-kafka:9092" |
||||
|
- name: LOGGER_LEVEL |
||||
|
value: "info" |
||||
|
- name: LOG_FOLDER |
||||
|
value: "logs" |
||||
|
- name: LOGGER_FILENAME |
||||
|
value: "tb-js-executor-%DATE%.log" |
||||
|
- name: DOCKER_MODE |
||||
|
value: "true" |
||||
|
- name: SCRIPT_BODY_TRACE_FREQUENCY |
||||
|
value: "1000" |
||||
|
restartPolicy: Always |
||||
|
--- |
||||
|
apiVersion: extensions/v1beta1 |
||||
|
kind: Deployment |
||||
|
metadata: |
||||
|
name: tb-node |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
replicas: 2 |
||||
|
selector: |
||||
|
matchLabels: |
||||
|
app: tb-node |
||||
|
template: |
||||
|
metadata: |
||||
|
labels: |
||||
|
app: tb-node |
||||
|
spec: |
||||
|
volumes: |
||||
|
- name: tb-node-config |
||||
|
configMap: |
||||
|
name: tb-node-config |
||||
|
items: |
||||
|
- key: conf |
||||
|
path: thingsboard.conf |
||||
|
- key: logback |
||||
|
path: logback.xml |
||||
|
containers: |
||||
|
- name: server |
||||
|
imagePullPolicy: Always |
||||
|
image: thingsboard/tb-node:latest |
||||
|
ports: |
||||
|
- containerPort: 8080 |
||||
|
name: http |
||||
|
- containerPort: 9001 |
||||
|
name: rpc |
||||
|
env: |
||||
|
- name: RPC_HOST |
||||
|
valueFrom: |
||||
|
fieldRef: |
||||
|
fieldPath: status.podIP |
||||
|
- name: CLUSTER_NODE_ID |
||||
|
valueFrom: |
||||
|
fieldRef: |
||||
|
fieldPath: metadata.name |
||||
|
- name: TB_HOST |
||||
|
valueFrom: |
||||
|
fieldRef: |
||||
|
fieldPath: metadata.name |
||||
|
- name: ZOOKEEPER_ENABLED |
||||
|
value: "true" |
||||
|
- name: ZOOKEEPER_URL |
||||
|
value: "zookeeper:2181" |
||||
|
- name: TB_KAFKA_SERVERS |
||||
|
value: "tb-kafka:9092" |
||||
|
- name: JS_EVALUATOR |
||||
|
value: "remote" |
||||
|
- name: TRANSPORT_TYPE |
||||
|
value: "remote" |
||||
|
- name: CACHE_TYPE |
||||
|
value: "redis" |
||||
|
- name: REDIS_HOST |
||||
|
value: "tb-redis" |
||||
|
- name: HTTP_LOG_CONTROLLER_ERROR_STACK_TRACE |
||||
|
value: "false" |
||||
|
envFrom: |
||||
|
- configMapRef: |
||||
|
name: tb-node-db-config |
||||
|
volumeMounts: |
||||
|
- mountPath: /config |
||||
|
name: tb-node-config |
||||
|
livenessProbe: |
||||
|
httpGet: |
||||
|
path: /login |
||||
|
port: http |
||||
|
initialDelaySeconds: 120 |
||||
|
timeoutSeconds: 10 |
||||
|
restartPolicy: Always |
||||
|
--- |
||||
|
apiVersion: v1 |
||||
|
kind: Service |
||||
|
metadata: |
||||
|
name: tb-node |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
type: ClusterIP |
||||
|
selector: |
||||
|
app: tb-node |
||||
|
ports: |
||||
|
- port: 8080 |
||||
|
name: http |
||||
|
--- |
||||
|
apiVersion: extensions/v1beta1 |
||||
|
kind: Deployment |
||||
|
metadata: |
||||
|
name: tb-mqtt-transport |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
replicas: 2 |
||||
|
selector: |
||||
|
matchLabels: |
||||
|
app: tb-mqtt-transport |
||||
|
template: |
||||
|
metadata: |
||||
|
labels: |
||||
|
app: tb-mqtt-transport |
||||
|
spec: |
||||
|
volumes: |
||||
|
- name: tb-mqtt-transport-config |
||||
|
configMap: |
||||
|
name: tb-mqtt-transport-config |
||||
|
items: |
||||
|
- key: conf |
||||
|
path: tb-mqtt-transport.conf |
||||
|
- key: logback |
||||
|
path: logback.xml |
||||
|
containers: |
||||
|
- name: server |
||||
|
imagePullPolicy: Always |
||||
|
image: thingsboard/tb-mqtt-transport:latest |
||||
|
ports: |
||||
|
- containerPort: 1883 |
||||
|
name: mqtt |
||||
|
env: |
||||
|
- name: CLUSTER_NODE_ID |
||||
|
valueFrom: |
||||
|
fieldRef: |
||||
|
fieldPath: metadata.name |
||||
|
- name: TB_HOST |
||||
|
valueFrom: |
||||
|
fieldRef: |
||||
|
fieldPath: metadata.name |
||||
|
- name: MQTT_BIND_ADDRESS |
||||
|
value: "0.0.0.0" |
||||
|
- name: MQTT_BIND_PORT |
||||
|
value: "1883" |
||||
|
- name: MQTT_TIMEOUT |
||||
|
value: "10000" |
||||
|
- name: TB_KAFKA_SERVERS |
||||
|
value: "tb-kafka:9092" |
||||
|
volumeMounts: |
||||
|
- mountPath: /config |
||||
|
name: tb-mqtt-transport-config |
||||
|
readinessProbe: |
||||
|
periodSeconds: 20 |
||||
|
tcpSocket: |
||||
|
port: 1883 |
||||
|
livenessProbe: |
||||
|
periodSeconds: 20 |
||||
|
tcpSocket: |
||||
|
port: 1883 |
||||
|
restartPolicy: Always |
||||
|
--- |
||||
|
apiVersion: v1 |
||||
|
kind: Service |
||||
|
metadata: |
||||
|
name: tb-mqtt-transport |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
type: LoadBalancer |
||||
|
selector: |
||||
|
app: tb-mqtt-transport |
||||
|
ports: |
||||
|
- port: 1883 |
||||
|
targetPort: 1883 |
||||
|
name: mqtt |
||||
|
--- |
||||
|
apiVersion: extensions/v1beta1 |
||||
|
kind: Deployment |
||||
|
metadata: |
||||
|
name: tb-http-transport |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
replicas: 2 |
||||
|
selector: |
||||
|
matchLabels: |
||||
|
app: tb-http-transport |
||||
|
template: |
||||
|
metadata: |
||||
|
labels: |
||||
|
app: tb-http-transport |
||||
|
spec: |
||||
|
volumes: |
||||
|
- name: tb-http-transport-config |
||||
|
configMap: |
||||
|
name: tb-http-transport-config |
||||
|
items: |
||||
|
- key: conf |
||||
|
path: tb-http-transport.conf |
||||
|
- key: logback |
||||
|
path: logback.xml |
||||
|
containers: |
||||
|
- name: server |
||||
|
imagePullPolicy: Always |
||||
|
image: thingsboard/tb-http-transport:latest |
||||
|
ports: |
||||
|
- containerPort: 8080 |
||||
|
name: http |
||||
|
env: |
||||
|
- name: CLUSTER_NODE_ID |
||||
|
valueFrom: |
||||
|
fieldRef: |
||||
|
fieldPath: metadata.name |
||||
|
- name: TB_HOST |
||||
|
valueFrom: |
||||
|
fieldRef: |
||||
|
fieldPath: metadata.name |
||||
|
- name: HTTP_BIND_ADDRESS |
||||
|
value: "0.0.0.0" |
||||
|
- name: HTTP_BIND_PORT |
||||
|
value: "8080" |
||||
|
- name: HTTP_REQUEST_TIMEOUT |
||||
|
value: "60000" |
||||
|
- name: TB_KAFKA_SERVERS |
||||
|
value: "tb-kafka:9092" |
||||
|
volumeMounts: |
||||
|
- mountPath: /config |
||||
|
name: tb-http-transport-config |
||||
|
readinessProbe: |
||||
|
periodSeconds: 20 |
||||
|
tcpSocket: |
||||
|
port: 8080 |
||||
|
livenessProbe: |
||||
|
periodSeconds: 20 |
||||
|
tcpSocket: |
||||
|
port: 8080 |
||||
|
restartPolicy: Always |
||||
|
--- |
||||
|
apiVersion: v1 |
||||
|
kind: Service |
||||
|
metadata: |
||||
|
name: tb-http-transport |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
type: ClusterIP |
||||
|
selector: |
||||
|
app: tb-http-transport |
||||
|
ports: |
||||
|
- port: 8080 |
||||
|
name: http |
||||
|
--- |
||||
|
apiVersion: extensions/v1beta1 |
||||
|
kind: Deployment |
||||
|
metadata: |
||||
|
name: tb-coap-transport |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
replicas: 2 |
||||
|
selector: |
||||
|
matchLabels: |
||||
|
app: tb-coap-transport |
||||
|
template: |
||||
|
metadata: |
||||
|
labels: |
||||
|
app: tb-coap-transport |
||||
|
spec: |
||||
|
volumes: |
||||
|
- name: tb-coap-transport-config |
||||
|
configMap: |
||||
|
name: tb-coap-transport-config |
||||
|
items: |
||||
|
- key: conf |
||||
|
path: tb-coap-transport.conf |
||||
|
- key: logback |
||||
|
path: logback.xml |
||||
|
containers: |
||||
|
- name: server |
||||
|
imagePullPolicy: Always |
||||
|
image: thingsboard/tb-coap-transport:latest |
||||
|
ports: |
||||
|
- containerPort: 5683 |
||||
|
name: coap |
||||
|
protocol: UDP |
||||
|
env: |
||||
|
- name: CLUSTER_NODE_ID |
||||
|
valueFrom: |
||||
|
fieldRef: |
||||
|
fieldPath: metadata.name |
||||
|
- name: TB_HOST |
||||
|
valueFrom: |
||||
|
fieldRef: |
||||
|
fieldPath: metadata.name |
||||
|
- name: COAP_BIND_ADDRESS |
||||
|
value: "0.0.0.0" |
||||
|
- name: COAP_BIND_PORT |
||||
|
value: "5683" |
||||
|
- name: COAP_TIMEOUT |
||||
|
value: "10000" |
||||
|
- name: TB_KAFKA_SERVERS |
||||
|
value: "tb-kafka:9092" |
||||
|
volumeMounts: |
||||
|
- mountPath: /config |
||||
|
name: tb-coap-transport-config |
||||
|
restartPolicy: Always |
||||
|
--- |
||||
|
apiVersion: v1 |
||||
|
kind: Service |
||||
|
metadata: |
||||
|
name: tb-coap-transport |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
type: LoadBalancer |
||||
|
selector: |
||||
|
app: tb-coap-transport |
||||
|
ports: |
||||
|
- port: 5683 |
||||
|
name: coap |
||||
|
protocol: UDP |
||||
|
--- |
||||
|
apiVersion: extensions/v1beta1 |
||||
|
kind: Deployment |
||||
|
metadata: |
||||
|
name: tb-web-ui |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
replicas: 2 |
||||
|
selector: |
||||
|
matchLabels: |
||||
|
app: tb-web-ui |
||||
|
template: |
||||
|
metadata: |
||||
|
labels: |
||||
|
app: tb-web-ui |
||||
|
spec: |
||||
|
containers: |
||||
|
- name: server |
||||
|
imagePullPolicy: Always |
||||
|
image: thingsboard/tb-web-ui:latest |
||||
|
ports: |
||||
|
- containerPort: 8080 |
||||
|
name: http |
||||
|
env: |
||||
|
- name: HTTP_BIND_ADDRESS |
||||
|
value: "0.0.0.0" |
||||
|
- name: HTTP_BIND_PORT |
||||
|
value: "8080" |
||||
|
- name: TB_ENABLE_PROXY |
||||
|
value: "false" |
||||
|
- name: LOGGER_LEVEL |
||||
|
value: "info" |
||||
|
- name: LOG_FOLDER |
||||
|
value: "logs" |
||||
|
- name: LOGGER_FILENAME |
||||
|
value: "tb-web-ui-%DATE%.log" |
||||
|
- name: DOCKER_MODE |
||||
|
value: "true" |
||||
|
livenessProbe: |
||||
|
httpGet: |
||||
|
path: /index.html |
||||
|
port: http |
||||
|
initialDelaySeconds: 120 |
||||
|
timeoutSeconds: 10 |
||||
|
restartPolicy: Always |
||||
|
--- |
||||
|
apiVersion: v1 |
||||
|
kind: Service |
||||
|
metadata: |
||||
|
name: tb-web-ui |
||||
|
namespace: thingsboard |
||||
|
spec: |
||||
|
type: ClusterIP |
||||
|
selector: |
||||
|
app: tb-web-ui |
||||
|
ports: |
||||
|
- port: 8080 |
||||
|
name: http |
||||
|
--- |
||||
|
apiVersion: extensions/v1beta1 |
||||
|
kind: Ingress |
||||
|
metadata: |
||||
|
name: tb-ingress |
||||
|
namespace: thingsboard |
||||
|
annotations: |
||||
|
nginx.ingress.kubernetes.io/use-regex: "true" |
||||
|
nginx.ingress.kubernetes.io/ssl-redirect: "false" |
||||
|
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" |
||||
|
spec: |
||||
|
rules: |
||||
|
- http: |
||||
|
paths: |
||||
|
- path: /api/v1/.* |
||||
|
backend: |
||||
|
serviceName: tb-http-transport |
||||
|
servicePort: 8080 |
||||
|
- path: /static/rulenode/.* |
||||
|
backend: |
||||
|
serviceName: tb-node |
||||
|
servicePort: 8080 |
||||
|
- path: /static/.* |
||||
|
backend: |
||||
|
serviceName: tb-web-ui |
||||
|
servicePort: 8080 |
||||
|
- path: /index.html.* |
||||
|
backend: |
||||
|
serviceName: tb-web-ui |
||||
|
servicePort: 8080 |
||||
|
- path: / |
||||
|
backend: |
||||
|
serviceName: tb-web-ui |
||||
|
servicePort: 8080 |
||||
|
- path: /.* |
||||
|
backend: |
||||
|
serviceName: tb-node |
||||
|
servicePort: 8080 |
||||
|
--- |
||||
@ -0,0 +1,206 @@ |
|||||
|
/* |
||||
|
* Copyright © 2016-2019 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
import './nav-tree.scss'; |
||||
|
|
||||
|
/* eslint-disable import/no-unresolved, import/default */ |
||||
|
|
||||
|
import navTreeTemplate from './nav-tree.tpl.html'; |
||||
|
|
||||
|
/* eslint-enable import/no-unresolved, import/default */ |
||||
|
|
||||
|
export default angular.module('thingsboard.directives.navTree', []) |
||||
|
.directive('tbNavTree', NavTree) |
||||
|
.name; |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
function NavTree() { |
||||
|
return { |
||||
|
restrict: "E", |
||||
|
scope: true, |
||||
|
bindToController: { |
||||
|
loadNodes: '=', |
||||
|
editCallbacks: '=', |
||||
|
enableSearch: '@?', |
||||
|
onNodeSelected: '&', |
||||
|
onNodesInserted: '&', |
||||
|
searchCallback: '&?' |
||||
|
}, |
||||
|
controller: NavTreeController, |
||||
|
controllerAs: 'vm', |
||||
|
templateUrl: navTreeTemplate |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
function NavTreeController($scope, $element, types) { |
||||
|
|
||||
|
var vm = this; |
||||
|
vm.types = types; |
||||
|
|
||||
|
$scope.$watch('vm.loadNodes', (newVal) => { |
||||
|
if (newVal) { |
||||
|
initTree(); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
function initTree() { |
||||
|
var config = { |
||||
|
core: { |
||||
|
multiple: false, |
||||
|
check_callback: true, |
||||
|
themes: { name: 'proton', responsive: true }, |
||||
|
data: vm.loadNodes |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
if (vm.enableSearch) { |
||||
|
config.plugins = ["search"]; |
||||
|
config.search = { |
||||
|
case_sensitive: false, |
||||
|
show_only_matches: true, |
||||
|
show_only_matches_children: false, |
||||
|
search_leaves_only: false |
||||
|
}; |
||||
|
if (vm.searchCallback) { |
||||
|
config.search.search_callback = (searchText, node) => vm.searchCallback({searchText: searchText, node: node}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
vm.treeElement = angular.element('.tb-nav-tree-container', $element) |
||||
|
.jstree(config); |
||||
|
|
||||
|
vm.treeElement.on("changed.jstree", function (e, data) { |
||||
|
if (vm.onNodeSelected) { |
||||
|
vm.onNodeSelected({node: data.instance.get_selected(true)[0], event: e}); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
vm.treeElement.on("model.jstree", function (e, data) { |
||||
|
if (vm.onNodesInserted) { |
||||
|
vm.onNodesInserted({nodes: data.nodes, parent: data.parent}); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
if (vm.editCallbacks) { |
||||
|
vm.editCallbacks.selectNode = (id) => { |
||||
|
var node = vm.treeElement.jstree('get_node', id); |
||||
|
if (node) { |
||||
|
vm.treeElement.jstree('deselect_all', true); |
||||
|
vm.treeElement.jstree('select_node', node); |
||||
|
} |
||||
|
}; |
||||
|
vm.editCallbacks.deselectAll = () => { |
||||
|
vm.treeElement.jstree('deselect_all'); |
||||
|
}; |
||||
|
vm.editCallbacks.getNode = (id) => { |
||||
|
var node = vm.treeElement.jstree('get_node', id); |
||||
|
return node; |
||||
|
}; |
||||
|
vm.editCallbacks.getParentNodeId = (id) => { |
||||
|
var node = vm.treeElement.jstree('get_node', id); |
||||
|
if (node) { |
||||
|
return vm.treeElement.jstree('get_parent', node); |
||||
|
} |
||||
|
}; |
||||
|
vm.editCallbacks.openNode = (id, cb) => { |
||||
|
var node = vm.treeElement.jstree('get_node', id); |
||||
|
if (node) { |
||||
|
vm.treeElement.jstree('open_node', node, cb); |
||||
|
} |
||||
|
}; |
||||
|
vm.editCallbacks.nodeIsOpen = (id) => { |
||||
|
var node = vm.treeElement.jstree('get_node', id); |
||||
|
if (node) { |
||||
|
return vm.treeElement.jstree('is_open', node); |
||||
|
} else { |
||||
|
return true; |
||||
|
} |
||||
|
}; |
||||
|
vm.editCallbacks.nodeIsLoaded = (id) => { |
||||
|
var node = vm.treeElement.jstree('get_node', id); |
||||
|
if (node) { |
||||
|
return vm.treeElement.jstree('is_loaded', node); |
||||
|
} else { |
||||
|
return true; |
||||
|
} |
||||
|
}; |
||||
|
vm.editCallbacks.refreshNode = (id) => { |
||||
|
if (id === '#') { |
||||
|
vm.treeElement.jstree('refresh'); |
||||
|
vm.treeElement.jstree('redraw'); |
||||
|
} else { |
||||
|
var node = vm.treeElement.jstree('get_node', id); |
||||
|
if (node) { |
||||
|
var opened = vm.treeElement.jstree('is_open', node); |
||||
|
vm.treeElement.jstree('refresh_node', node); |
||||
|
vm.treeElement.jstree('redraw'); |
||||
|
if (node.children && opened/* && !node.children.length*/) { |
||||
|
vm.treeElement.jstree('open_node', node); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
vm.editCallbacks.updateNode = (id, newName) => { |
||||
|
var node = vm.treeElement.jstree('get_node', id); |
||||
|
if (node) { |
||||
|
vm.treeElement.jstree('rename_node', node, newName); |
||||
|
} |
||||
|
}; |
||||
|
vm.editCallbacks.createNode = (parentId, node, pos) => { |
||||
|
var parentNode = vm.treeElement.jstree('get_node', parentId); |
||||
|
if (parentNode) { |
||||
|
vm.treeElement.jstree('create_node', parentNode, node, pos); |
||||
|
} |
||||
|
}; |
||||
|
vm.editCallbacks.deleteNode = (id) => { |
||||
|
var node = vm.treeElement.jstree('get_node', id); |
||||
|
if (node) { |
||||
|
vm.treeElement.jstree('delete_node', node); |
||||
|
} |
||||
|
}; |
||||
|
vm.editCallbacks.disableNode = (id) => { |
||||
|
var node = vm.treeElement.jstree('get_node', id); |
||||
|
if (node) { |
||||
|
vm.treeElement.jstree('disable_node', node); |
||||
|
} |
||||
|
}; |
||||
|
vm.editCallbacks.enableNode = (id) => { |
||||
|
var node = vm.treeElement.jstree('get_node', id); |
||||
|
if (node) { |
||||
|
vm.treeElement.jstree('enable_node', node); |
||||
|
} |
||||
|
}; |
||||
|
vm.editCallbacks.setNodeHasChildren = (id, hasChildren) => { |
||||
|
var node = vm.treeElement.jstree('get_node', id); |
||||
|
if (node) { |
||||
|
if (!node.children || !node.children.length) { |
||||
|
node.children = hasChildren; |
||||
|
node.state.loaded = !hasChildren; |
||||
|
node.state.opened = false; |
||||
|
vm.treeElement.jstree('_node_changed', node.id); |
||||
|
vm.treeElement.jstree('redraw'); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
vm.editCallbacks.search = (searchText) => { |
||||
|
vm.treeElement.jstree('search', searchText); |
||||
|
}; |
||||
|
vm.editCallbacks.clearSearch = () => { |
||||
|
vm.treeElement.jstree('clear_search'); |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,346 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2019 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
.tb-nav-tree-container { |
||||
|
padding: 15px; |
||||
|
font-family: Roboto, "Helvetica Neue", sans-serif; |
||||
|
|
||||
|
&.jstree-proton { |
||||
|
.jstree-node, |
||||
|
.jstree-icon { |
||||
|
background-image: url("../../png/jstree/32px.png"); |
||||
|
} |
||||
|
|
||||
|
.jstree-last { |
||||
|
background: transparent; |
||||
|
} |
||||
|
|
||||
|
.jstree-themeicon-custom { |
||||
|
background-image: none; |
||||
|
|
||||
|
&.material-icons { |
||||
|
font-size: 18px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.jstree-anchor { |
||||
|
font-size: 16px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&.jstree-proton-small { |
||||
|
.jstree-node, |
||||
|
.jstree-icon { |
||||
|
background-image: url("../../png/jstree/32px.png"); |
||||
|
} |
||||
|
|
||||
|
.jstree-last { |
||||
|
background: transparent; |
||||
|
} |
||||
|
|
||||
|
.jstree-themeicon-custom { |
||||
|
background-image: none; |
||||
|
|
||||
|
&.material-icons { |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.jstree-anchor { |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&.jstree-proton-large { |
||||
|
.jstree-node, |
||||
|
.jstree-icon { |
||||
|
background-image: url("../../png/jstree/32px.png"); |
||||
|
} |
||||
|
|
||||
|
.jstree-last { |
||||
|
background: transparent; |
||||
|
} |
||||
|
|
||||
|
.jstree-themeicon-custom { |
||||
|
background-image: none; |
||||
|
|
||||
|
&.material-icons { |
||||
|
font-size: 24px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.jstree-anchor { |
||||
|
font-size: 20px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
a { |
||||
|
border-bottom: none; |
||||
|
|
||||
|
i.jstree-themeicon-custom { |
||||
|
&.tb-user-group { |
||||
|
&::before { |
||||
|
content: "account_circle"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&.tb-customer-group { |
||||
|
&::before { |
||||
|
content: "supervisor_account"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&.tb-asset-group { |
||||
|
&::before { |
||||
|
content: "domain"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&.tb-device-group { |
||||
|
&::before { |
||||
|
content: "devices_other"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&.tb-entity-view-group { |
||||
|
&::before { |
||||
|
content: "view_quilt"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&.tb-dashboard-group { |
||||
|
&::before { |
||||
|
content: "dashboard"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&.tb-customer { |
||||
|
&::before { |
||||
|
content: "supervisor_account"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@media (max-width: 768px) { |
||||
|
.tb-nav-tree-container { |
||||
|
&.jstree-proton-responsive { |
||||
|
.jstree-node, |
||||
|
.jstree-icon, |
||||
|
.jstree-node > .jstree-ocl, |
||||
|
.jstree-themeicon, |
||||
|
.jstree-checkbox { |
||||
|
background-image: url("../../png/jstree/40px.png"); |
||||
|
background-size: 120px 240px; |
||||
|
} |
||||
|
|
||||
|
.jstree-container-ul { |
||||
|
overflow: visible; |
||||
|
} |
||||
|
|
||||
|
.jstree-themeicon-custom { |
||||
|
background-color: transparent; |
||||
|
background-image: none; |
||||
|
background-position: 0 0; |
||||
|
|
||||
|
&.material-icons { |
||||
|
margin: 0; |
||||
|
font-size: 24px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.jstree-node, |
||||
|
.jstree-leaf > .jstree-ocl { |
||||
|
background: 0 0; |
||||
|
} |
||||
|
|
||||
|
.jstree-node { |
||||
|
min-width: 40px; |
||||
|
min-height: 40px; |
||||
|
margin-left: 40px; |
||||
|
line-height: 40px; |
||||
|
white-space: nowrap; |
||||
|
background-repeat: repeat-y; |
||||
|
background-position: -80px 0; |
||||
|
} |
||||
|
|
||||
|
.jstree-last { |
||||
|
background: 0 0; |
||||
|
} |
||||
|
|
||||
|
.jstree-anchor { |
||||
|
height: 40px; |
||||
|
font-size: 1.1em; |
||||
|
font-weight: 700; |
||||
|
line-height: 40px; |
||||
|
text-shadow: 1px 1px #fff; |
||||
|
} |
||||
|
|
||||
|
.jstree-icon, |
||||
|
.jstree-icon:empty { |
||||
|
width: 40px; |
||||
|
height: 40px; |
||||
|
line-height: 40px; |
||||
|
} |
||||
|
|
||||
|
> { |
||||
|
.jstree-container-ul > .jstree-node { |
||||
|
margin-right: 0; |
||||
|
margin-left: 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.jstree-ocl, |
||||
|
.jstree-themeicon, |
||||
|
.jstree-checkbox { |
||||
|
background-size: 120px 240px; |
||||
|
} |
||||
|
|
||||
|
.jstree-leaf > .jstree-ocl { |
||||
|
background: 0 0; |
||||
|
background-position: -40px -120px; |
||||
|
} |
||||
|
|
||||
|
.jstree-last > .jstree-ocl { |
||||
|
background-position: -40px -160px; |
||||
|
} |
||||
|
|
||||
|
.jstree-open > .jstree-ocl { |
||||
|
background-position: 0 0 !important; |
||||
|
} |
||||
|
|
||||
|
.jstree-closed > .jstree-ocl { |
||||
|
background-position: 0 -40px !important; |
||||
|
} |
||||
|
|
||||
|
.jstree-themeicon { |
||||
|
background-position: -40px -40px; |
||||
|
} |
||||
|
|
||||
|
.jstree-checkbox, |
||||
|
.jstree-checkbox:hover { |
||||
|
background-position: -40px -80px; |
||||
|
} |
||||
|
|
||||
|
&.jstree-checkbox-selection { |
||||
|
.jstree-clicked > .jstree-checkbox, |
||||
|
.jstree-clicked > .jstree-checkbox:hover { |
||||
|
background-position: 0 -80px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.jstree-checked > .jstree-checkbox, |
||||
|
.jstree-checked > .jstree-checkbox:hover { |
||||
|
background-position: 0 -80px; |
||||
|
} |
||||
|
|
||||
|
.jstree-anchor > .jstree-undetermined, |
||||
|
.jstree-anchor > .jstree-undetermined:hover { |
||||
|
background-position: 0 -120px; |
||||
|
} |
||||
|
|
||||
|
.jstree-striped { |
||||
|
background: 0 0; |
||||
|
} |
||||
|
|
||||
|
.jstree-wholerow { |
||||
|
height: 40px; |
||||
|
background: #ebebeb; |
||||
|
border-top: 1px solid rgba(255, 255, 255, .7); |
||||
|
border-bottom: 1px solid rgba(64, 64, 64, .2); |
||||
|
} |
||||
|
|
||||
|
.jstree-wholerow-hovered { |
||||
|
background: #e7f4f9; |
||||
|
} |
||||
|
|
||||
|
.jstree-wholerow-clicked { |
||||
|
background: #beebff; |
||||
|
} |
||||
|
|
||||
|
.jstree-children { |
||||
|
.jstree-last > .jstree-wholerow { |
||||
|
box-shadow: inset 0 -6px 3px -5px #666; |
||||
|
} |
||||
|
|
||||
|
.jstree-open > .jstree-wholerow { |
||||
|
border-top: 0; |
||||
|
box-shadow: inset 0 6px 3px -5px #666; |
||||
|
} |
||||
|
|
||||
|
.jstree-open + .jstree-open { |
||||
|
box-shadow: none; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&.jstree-rtl { |
||||
|
.jstree-node { |
||||
|
margin-right: 40px; |
||||
|
margin-left: 0; |
||||
|
} |
||||
|
|
||||
|
.jstree-container-ul > .jstree-node { |
||||
|
margin-right: 0; |
||||
|
} |
||||
|
|
||||
|
.jstree-closed > .jstree-ocl { |
||||
|
background-position: -40px 0 !important; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.tb-nav-tree .md-button.tb-active { |
||||
|
font-weight: 500; |
||||
|
background-color: rgba(255, 255, 255, .15); |
||||
|
} |
||||
|
|
||||
|
.tb-nav-tree, |
||||
|
.tb-nav-tree ul { |
||||
|
margin-top: 0; |
||||
|
list-style: none; |
||||
|
|
||||
|
&:first-child { |
||||
|
padding: 0; |
||||
|
} |
||||
|
|
||||
|
li { |
||||
|
.md-button { |
||||
|
width: 100%; |
||||
|
max-height: 40px; |
||||
|
padding: 0 16px; |
||||
|
margin: 0; |
||||
|
overflow: hidden; |
||||
|
line-height: 40px; |
||||
|
color: inherit; |
||||
|
text-align: left; |
||||
|
text-decoration: none; |
||||
|
text-overflow: ellipsis; |
||||
|
text-transform: none; |
||||
|
text-rendering: optimizeLegibility; |
||||
|
white-space: nowrap; |
||||
|
cursor: pointer; |
||||
|
border-radius: 0; |
||||
|
|
||||
|
span { |
||||
|
overflow: hidden; |
||||
|
text-overflow: ellipsis; |
||||
|
white-space: nowrap; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2019 The Thingsboard Authors |
||||
|
|
||||
|
Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
you may not use this file except in compliance with the License. |
||||
|
You may obtain a copy of the License at |
||||
|
|
||||
|
http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
|
||||
|
Unless required by applicable law or agreed to in writing, software |
||||
|
distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
See the License for the specific language governing permissions and |
||||
|
limitations under the License. |
||||
|
|
||||
|
--> |
||||
|
<div class="tb-nav-tree-container"></div> |
||||
@ -0,0 +1,530 @@ |
|||||
|
/* |
||||
|
* Copyright © 2016-2019 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
|
||||
|
import './entities-hierarchy-widget.scss'; |
||||
|
|
||||
|
/* eslint-disable import/no-unresolved, import/default */ |
||||
|
|
||||
|
import entitiesHierarchyWidgetTemplate from './entities-hierarchy-widget.tpl.html'; |
||||
|
|
||||
|
/* eslint-enable import/no-unresolved, import/default */ |
||||
|
|
||||
|
export default angular.module('thingsboard.widgets.entitiesHierarchyWidget', []) |
||||
|
.directive('tbEntitiesHierarchyWidget', EntitiesHierarchyWidget) |
||||
|
.name; |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
function EntitiesHierarchyWidget() { |
||||
|
return { |
||||
|
restrict: "E", |
||||
|
scope: true, |
||||
|
bindToController: { |
||||
|
hierarchyId: '=', |
||||
|
ctx: '=' |
||||
|
}, |
||||
|
controller: EntitiesHierarchyWidgetController, |
||||
|
controllerAs: 'vm', |
||||
|
templateUrl: entitiesHierarchyWidgetTemplate |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
function EntitiesHierarchyWidgetController($element, $scope, $q, $timeout, toast, types, entityService, entityRelationService /*$filter, $mdMedia, $mdPanel, $document, $translate, $timeout, utils, types*/) { |
||||
|
var vm = this; |
||||
|
|
||||
|
vm.showData = true; |
||||
|
|
||||
|
vm.nodeEditCallbacks = {}; |
||||
|
|
||||
|
vm.nodeIdCounter = 0; |
||||
|
|
||||
|
vm.nodesMap = {}; |
||||
|
vm.pendingUpdateNodeTasks = {}; |
||||
|
|
||||
|
vm.query = { |
||||
|
search: null |
||||
|
}; |
||||
|
|
||||
|
vm.searchAction = { |
||||
|
name: 'action.search', |
||||
|
show: true, |
||||
|
onAction: function() { |
||||
|
vm.enterFilterMode(); |
||||
|
}, |
||||
|
icon: 'search' |
||||
|
}; |
||||
|
|
||||
|
vm.onNodesInserted = onNodesInserted; |
||||
|
vm.onNodeSelected = onNodeSelected; |
||||
|
vm.enterFilterMode = enterFilterMode; |
||||
|
vm.exitFilterMode = exitFilterMode; |
||||
|
vm.searchCallback = searchCallback; |
||||
|
|
||||
|
$scope.$watch('vm.ctx', function() { |
||||
|
if (vm.ctx && vm.ctx.defaultSubscription) { |
||||
|
vm.settings = vm.ctx.settings; |
||||
|
vm.widgetConfig = vm.ctx.widgetConfig; |
||||
|
vm.subscription = vm.ctx.defaultSubscription; |
||||
|
vm.datasources = vm.subscription.datasources; |
||||
|
initializeConfig(); |
||||
|
updateDatasources(); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
$scope.$watch("vm.query.search", function(newVal, prevVal) { |
||||
|
if (!angular.equals(newVal, prevVal) && vm.query.search != null) { |
||||
|
updateSearchNodes(); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
$scope.$on('entities-hierarchy-data-updated', function(event, hierarchyId) { |
||||
|
if (vm.hierarchyId == hierarchyId) { |
||||
|
if (vm.subscription) { |
||||
|
updateNodeData(vm.subscription.data); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
function initializeConfig() { |
||||
|
|
||||
|
vm.ctx.widgetActions = [ vm.searchAction ]; |
||||
|
|
||||
|
var testNodeCtx = { |
||||
|
entity: { |
||||
|
id: { |
||||
|
entityType: 'DEVICE', |
||||
|
id: '123' |
||||
|
}, |
||||
|
name: 'TEST DEV1' |
||||
|
}, |
||||
|
data: {}, |
||||
|
level: 2 |
||||
|
}; |
||||
|
var parentNodeCtx = angular.copy(testNodeCtx); |
||||
|
parentNodeCtx.level = 1; |
||||
|
testNodeCtx.parentNodeCtx = parentNodeCtx; |
||||
|
|
||||
|
var nodeRelationQueryFunction = loadNodeCtxFunction(vm.settings.nodeRelationQueryFunction, 'nodeCtx', testNodeCtx); |
||||
|
var nodeIconFunction = loadNodeCtxFunction(vm.settings.nodeIconFunction, 'nodeCtx', testNodeCtx); |
||||
|
var nodeTextFunction = loadNodeCtxFunction(vm.settings.nodeTextFunction, 'nodeCtx', testNodeCtx); |
||||
|
var nodeDisabledFunction = loadNodeCtxFunction(vm.settings.nodeDisabledFunction, 'nodeCtx', testNodeCtx); |
||||
|
var nodeOpenedFunction = loadNodeCtxFunction(vm.settings.nodeOpenedFunction, 'nodeCtx', testNodeCtx); |
||||
|
var nodeHasChildrenFunction = loadNodeCtxFunction(vm.settings.nodeHasChildrenFunction, 'nodeCtx', testNodeCtx); |
||||
|
|
||||
|
var testNodeCtx2 = angular.copy(testNodeCtx); |
||||
|
testNodeCtx2.entity.name = 'TEST DEV2'; |
||||
|
|
||||
|
var nodesSortFunction = loadNodeCtxFunction(vm.settings.nodesSortFunction, 'nodeCtx1,nodeCtx2', testNodeCtx, testNodeCtx2); |
||||
|
|
||||
|
vm.nodeRelationQueryFunction = nodeRelationQueryFunction || defaultNodeRelationQueryFunction; |
||||
|
vm.nodeIconFunction = nodeIconFunction || defaultNodeIconFunction; |
||||
|
vm.nodeTextFunction = nodeTextFunction || ((nodeCtx) => nodeCtx.entity.name); |
||||
|
vm.nodeDisabledFunction = nodeDisabledFunction || (() => false); |
||||
|
vm.nodeOpenedFunction = nodeOpenedFunction || defaultNodeOpenedFunction; |
||||
|
vm.nodeHasChildrenFunction = nodeHasChildrenFunction || (() => true); |
||||
|
vm.nodesSortFunction = nodesSortFunction || defaultSortFunction; |
||||
|
} |
||||
|
|
||||
|
function loadNodeCtxFunction(functionBody, argNames, ...args) { |
||||
|
var nodeCtxFunction = null; |
||||
|
if (angular.isDefined(functionBody) && functionBody.length) { |
||||
|
try { |
||||
|
nodeCtxFunction = new Function(argNames, functionBody); |
||||
|
var res = nodeCtxFunction.apply(null, args); |
||||
|
if (angular.isUndefined(res)) { |
||||
|
nodeCtxFunction = null; |
||||
|
} |
||||
|
} catch (e) { |
||||
|
nodeCtxFunction = null; |
||||
|
} |
||||
|
} |
||||
|
return nodeCtxFunction; |
||||
|
} |
||||
|
|
||||
|
function enterFilterMode () { |
||||
|
vm.query.search = ''; |
||||
|
vm.ctx.hideTitlePanel = true; |
||||
|
$timeout(()=>{ |
||||
|
angular.element(vm.ctx.$container).find('.searchInput').focus(); |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
function exitFilterMode () { |
||||
|
vm.query.search = null; |
||||
|
updateSearchNodes(); |
||||
|
vm.ctx.hideTitlePanel = false; |
||||
|
} |
||||
|
|
||||
|
function searchCallback (searchText, node) { |
||||
|
var theNode = vm.nodesMap[node.id]; |
||||
|
if (theNode && theNode.data.searchText) { |
||||
|
return theNode.data.searchText.includes(searchText.toLowerCase()); |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
function updateDatasources() { |
||||
|
vm.loadNodes = loadNodes; |
||||
|
} |
||||
|
|
||||
|
function updateSearchNodes() { |
||||
|
if (vm.query.search != null) { |
||||
|
vm.nodeEditCallbacks.search(vm.query.search); |
||||
|
} else { |
||||
|
vm.nodeEditCallbacks.clearSearch(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function onNodesInserted(nodes/*, parent*/) { |
||||
|
if (nodes) { |
||||
|
nodes.forEach((nodeId) => { |
||||
|
var task = vm.pendingUpdateNodeTasks[nodeId]; |
||||
|
if (task) { |
||||
|
task(); |
||||
|
delete vm.pendingUpdateNodeTasks[nodeId]; |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function onNodeSelected(node, event) { |
||||
|
var nodeId; |
||||
|
if (!node) { |
||||
|
nodeId = -1; |
||||
|
} else { |
||||
|
nodeId = node.id; |
||||
|
} |
||||
|
if (nodeId !== -1) { |
||||
|
var selectedNode = vm.nodesMap[nodeId]; |
||||
|
if (selectedNode) { |
||||
|
var descriptors = vm.ctx.actionsApi.getActionDescriptors('nodeSelected'); |
||||
|
if (descriptors.length) { |
||||
|
var entity = selectedNode.data.nodeCtx.entity; |
||||
|
vm.ctx.actionsApi.handleWidgetAction(event, descriptors[0], entity.id, entity.name, { nodeCtx: selectedNode.data.nodeCtx }); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function updateNodeData(subscriptionData) { |
||||
|
var affectedNodes = []; |
||||
|
if (subscriptionData) { |
||||
|
for (var i=0;i<subscriptionData.length;i++) { |
||||
|
var datasource = subscriptionData[i].datasource; |
||||
|
if (datasource.nodeId) { |
||||
|
var node = vm.nodesMap[datasource.nodeId]; |
||||
|
var key = subscriptionData[i].dataKey.label; |
||||
|
var value = undefined; |
||||
|
if (subscriptionData[i].data && subscriptionData[i].data.length) { |
||||
|
value = subscriptionData[i].data[0][1]; |
||||
|
} |
||||
|
if (node.data.nodeCtx.data[key] !== value) { |
||||
|
if (affectedNodes.indexOf(datasource.nodeId) === -1) { |
||||
|
affectedNodes.push(datasource.nodeId); |
||||
|
} |
||||
|
node.data.nodeCtx.data[key] = value; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
affectedNodes.forEach((nodeId) => { |
||||
|
var node = vm.nodeEditCallbacks.getNode(nodeId); |
||||
|
if (node) { |
||||
|
updateNodeStyle(vm.nodesMap[nodeId]); |
||||
|
} else { |
||||
|
vm.pendingUpdateNodeTasks[nodeId] = () => { |
||||
|
updateNodeStyle(vm.nodesMap[nodeId]); |
||||
|
}; |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function updateNodeStyle(node) { |
||||
|
var newText = prepareNodeText(node); |
||||
|
if (!angular.equals(node.text, newText)) { |
||||
|
node.text = newText; |
||||
|
vm.nodeEditCallbacks.updateNode(node.id, node.text); |
||||
|
} |
||||
|
var newDisabled = vm.nodeDisabledFunction(node.data.nodeCtx); |
||||
|
if (!angular.equals(node.state.disabled, newDisabled)) { |
||||
|
node.state.disabled = newDisabled; |
||||
|
if (node.state.disabled) { |
||||
|
vm.nodeEditCallbacks.disableNode(node.id); |
||||
|
} else { |
||||
|
vm.nodeEditCallbacks.enableNode(node.id); |
||||
|
} |
||||
|
} |
||||
|
var newHasChildren = vm.nodeHasChildrenFunction(node.data.nodeCtx); |
||||
|
if (!angular.equals(node.children, newHasChildren)) { |
||||
|
node.children = newHasChildren; |
||||
|
vm.nodeEditCallbacks.setNodeHasChildren(node.id, node.children); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function prepareNodeText(node) { |
||||
|
var nodeIcon = prepareNodeIcon(node.data.nodeCtx); |
||||
|
var nodeText = vm.nodeTextFunction(node.data.nodeCtx); |
||||
|
node.data.searchText = nodeText ? nodeText.replace(/<[^>]+>/g, '').toLowerCase() : ""; |
||||
|
return nodeIcon + nodeText; |
||||
|
} |
||||
|
|
||||
|
function loadNodes(node, cb) { |
||||
|
if (node.id === '#') { |
||||
|
var tasks = []; |
||||
|
for (var i=0;i<vm.datasources.length;i++) { |
||||
|
var datasource = vm.datasources[i]; |
||||
|
tasks.push(datasourceToNode(datasource)); |
||||
|
} |
||||
|
$q.all(tasks).then((nodes) => { |
||||
|
cb(prepareNodes(nodes)); |
||||
|
updateNodeData(vm.subscription.data); |
||||
|
}); |
||||
|
} else { |
||||
|
if (node.data && node.data.nodeCtx.entity && node.data.nodeCtx.entity.id && node.data.nodeCtx.entity.id.entityType !== 'function') { |
||||
|
var relationQuery = prepareNodeRelationQuery(node.data.nodeCtx); |
||||
|
entityRelationService.findByQuery(relationQuery, {ignoreErrors: true, ignoreLoading: true}).then( |
||||
|
(entityRelations) => { |
||||
|
var tasks = []; |
||||
|
for (var i=0;i<entityRelations.length;i++) { |
||||
|
var relation = entityRelations[i]; |
||||
|
var targetId = relationQuery.parameters.direction === types.entitySearchDirection.from ? relation.to : relation.from; |
||||
|
tasks.push(entityIdToNode(targetId.entityType, targetId.id, node.data.datasource, node.data.nodeCtx)); |
||||
|
} |
||||
|
$q.all(tasks).then((nodes) => { |
||||
|
cb(prepareNodes(nodes)); |
||||
|
}); |
||||
|
}, |
||||
|
(error) => { |
||||
|
var errorText = "Failed to get relations!"; |
||||
|
if (error && error.status === 400) { |
||||
|
errorText = "Invalid relations query returned by 'Node relations query function'! Please check widget configuration!"; |
||||
|
} |
||||
|
showError(errorText); |
||||
|
} |
||||
|
); |
||||
|
} else { |
||||
|
cb([]); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function showError(errorText) { |
||||
|
var toastParent = angular.element('.tb-entities-hierarchy', $element); |
||||
|
toast.showError(errorText, toastParent, 'bottom left'); |
||||
|
} |
||||
|
|
||||
|
function prepareNodes(nodes) { |
||||
|
nodes = nodes.filter((node) => node !== null); |
||||
|
nodes.sort((node1, node2) => vm.nodesSortFunction(node1.data.nodeCtx, node2.data.nodeCtx)); |
||||
|
return nodes; |
||||
|
} |
||||
|
|
||||
|
function datasourceToNode(datasource, parentNodeCtx) { |
||||
|
var deferred = $q.defer(); |
||||
|
resolveEntity(datasource).then( |
||||
|
(entity) => { |
||||
|
if (entity != null) { |
||||
|
var node = { |
||||
|
id: ++vm.nodeIdCounter |
||||
|
}; |
||||
|
vm.nodesMap[node.id] = node; |
||||
|
datasource.nodeId = node.id; |
||||
|
node.icon = false; |
||||
|
var nodeCtx = { |
||||
|
parentNodeCtx: parentNodeCtx, |
||||
|
entity: entity, |
||||
|
data: {} |
||||
|
}; |
||||
|
nodeCtx.level = parentNodeCtx ? parentNodeCtx.level + 1 : 1; |
||||
|
node.data = { |
||||
|
datasource: datasource, |
||||
|
nodeCtx: nodeCtx |
||||
|
}; |
||||
|
node.state = { |
||||
|
disabled: vm.nodeDisabledFunction(node.data.nodeCtx), |
||||
|
opened: vm.nodeOpenedFunction(node.data.nodeCtx) |
||||
|
}; |
||||
|
node.text = prepareNodeText(node); |
||||
|
node.children = vm.nodeHasChildrenFunction(node.data.nodeCtx); |
||||
|
deferred.resolve(node); |
||||
|
} else { |
||||
|
deferred.resolve(null); |
||||
|
} |
||||
|
} |
||||
|
); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function entityIdToNode(entityType, entityId, parentDatasource, parentNodeCtx) { |
||||
|
var deferred = $q.defer(); |
||||
|
var datasource = { |
||||
|
dataKeys: parentDatasource.dataKeys, |
||||
|
type: types.datasourceType.entity, |
||||
|
entityType: entityType, |
||||
|
entityId: entityId |
||||
|
}; |
||||
|
datasourceToNode(datasource, parentNodeCtx).then( |
||||
|
(node) => { |
||||
|
if (node != null) { |
||||
|
var subscriptionOptions = { |
||||
|
type: types.widgetType.latest.value, |
||||
|
datasources: [datasource], |
||||
|
callbacks: { |
||||
|
onDataUpdated: (subscription) => { |
||||
|
updateNodeData(subscription.data); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
vm.ctx.subscriptionApi.createSubscription(subscriptionOptions, true).then( |
||||
|
(/*subscription*/) => { |
||||
|
deferred.resolve(node); |
||||
|
} |
||||
|
); |
||||
|
} else { |
||||
|
deferred.resolve(node); |
||||
|
} |
||||
|
} |
||||
|
); |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
function resolveEntity(datasource) { |
||||
|
var deferred = $q.defer(); |
||||
|
if (datasource.type === types.datasourceType.function) { |
||||
|
var entity = { |
||||
|
id: { |
||||
|
entityType: "function" |
||||
|
}, |
||||
|
name: datasource.name |
||||
|
} |
||||
|
deferred.resolve(entity); |
||||
|
} else { |
||||
|
entityService.getEntity(datasource.entityType, datasource.entityId, {ignoreLoading: true}).then( |
||||
|
(entity) => { |
||||
|
deferred.resolve(entity); |
||||
|
}, |
||||
|
() => { |
||||
|
deferred.resolve(null); |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
return deferred.promise; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
function prepareNodeRelationQuery(nodeCtx) { |
||||
|
var relationQuery = vm.nodeRelationQueryFunction(nodeCtx); |
||||
|
if (relationQuery && relationQuery === 'default') { |
||||
|
relationQuery = defaultNodeRelationQueryFunction(nodeCtx); |
||||
|
} |
||||
|
return relationQuery; |
||||
|
} |
||||
|
|
||||
|
function defaultNodeRelationQueryFunction(nodeCtx) { |
||||
|
var entity = nodeCtx.entity; |
||||
|
var query = { |
||||
|
parameters: { |
||||
|
rootId: entity.id.id, |
||||
|
rootType: entity.id.entityType, |
||||
|
direction: types.entitySearchDirection.from, |
||||
|
relationTypeGroup: "COMMON", |
||||
|
maxLevel: 1 |
||||
|
}, |
||||
|
filters: [ |
||||
|
{ |
||||
|
relationType: "Contains", |
||||
|
entityTypes: [] |
||||
|
} |
||||
|
] |
||||
|
}; |
||||
|
return query; |
||||
|
} |
||||
|
|
||||
|
function prepareNodeIcon(nodeCtx) { |
||||
|
var iconInfo = vm.nodeIconFunction(nodeCtx); |
||||
|
if (iconInfo && iconInfo === 'default') { |
||||
|
iconInfo = defaultNodeIconFunction(nodeCtx); |
||||
|
} |
||||
|
if (iconInfo && (iconInfo.iconUrl || iconInfo.materialIcon)) { |
||||
|
if (iconInfo.materialIcon) { |
||||
|
return materialIconHtml(iconInfo.materialIcon); |
||||
|
} else { |
||||
|
return iconUrlHtml(iconInfo.iconUrl); |
||||
|
} |
||||
|
} else { |
||||
|
return ""; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function materialIconHtml(materialIcon) { |
||||
|
return '<md-icon aria-label="'+materialIcon+'" class="node-icon material-icons" role="img" aria-hidden="false">'+materialIcon+'</md-icon>'; |
||||
|
} |
||||
|
|
||||
|
function iconUrlHtml(iconUrl) { |
||||
|
return '<div class="node-icon" style="background-image: url('+iconUrl+');"> </div>'; |
||||
|
} |
||||
|
|
||||
|
function defaultNodeIconFunction(nodeCtx) { |
||||
|
var materialIcon = 'insert_drive_file'; |
||||
|
var entity = nodeCtx.entity; |
||||
|
if (entity && entity.id && entity.id.entityType) { |
||||
|
switch (entity.id.entityType) { |
||||
|
case 'function': |
||||
|
materialIcon = 'functions'; |
||||
|
break; |
||||
|
case types.entityType.device: |
||||
|
materialIcon = 'devices_other'; |
||||
|
break; |
||||
|
case types.entityType.asset: |
||||
|
materialIcon = 'domain'; |
||||
|
break; |
||||
|
case types.entityType.tenant: |
||||
|
materialIcon = 'supervisor_account'; |
||||
|
break; |
||||
|
case types.entityType.customer: |
||||
|
materialIcon = 'supervisor_account'; |
||||
|
break; |
||||
|
case types.entityType.user: |
||||
|
materialIcon = 'account_circle'; |
||||
|
break; |
||||
|
case types.entityType.dashboard: |
||||
|
materialIcon = 'dashboards'; |
||||
|
break; |
||||
|
case types.entityType.alarm: |
||||
|
materialIcon = 'notifications_active'; |
||||
|
break; |
||||
|
case types.entityType.entityView: |
||||
|
materialIcon = 'view_quilt'; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
return { |
||||
|
materialIcon: materialIcon |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
function defaultNodeOpenedFunction(nodeCtx) { |
||||
|
return nodeCtx.level <= 4; |
||||
|
} |
||||
|
|
||||
|
function defaultSortFunction(nodeCtx1, nodeCtx2) { |
||||
|
var result = nodeCtx1.entity.id.entityType.localeCompare(nodeCtx2.entity.id.entityType); |
||||
|
if (result === 0) { |
||||
|
result = nodeCtx1.entity.name.localeCompare(nodeCtx2.entity.name); |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,110 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2019 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
|
||||
|
.tb-has-timewindow { |
||||
|
.tb-entities-hierarchy { |
||||
|
md-toolbar { |
||||
|
min-height: 60px; |
||||
|
max-height: 60px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.tb-entities-hierarchy { |
||||
|
md-toolbar { |
||||
|
min-height: 39px; |
||||
|
max-height: 39px; |
||||
|
} |
||||
|
|
||||
|
.tb-entities-nav-tree-panel { |
||||
|
overflow-x: auto; |
||||
|
overflow-y: auto; |
||||
|
|
||||
|
.tb-nav-tree-container { |
||||
|
&.jstree-proton { |
||||
|
.jstree-anchor { |
||||
|
div.node-icon { |
||||
|
display: inline-block; |
||||
|
width: 22px; |
||||
|
height: 22px; |
||||
|
margin-right: 2px; |
||||
|
margin-bottom: 2px; |
||||
|
background-color: transparent; |
||||
|
background-repeat: no-repeat; |
||||
|
background-attachment: scroll; |
||||
|
background-position: center center; |
||||
|
background-size: 18px 18px; |
||||
|
} |
||||
|
|
||||
|
md-icon.node-icon { |
||||
|
width: 22px; |
||||
|
min-width: 22px; |
||||
|
height: 22px; |
||||
|
min-height: 22px; |
||||
|
margin-right: 2px; |
||||
|
margin-bottom: 2px; |
||||
|
color: inherit; |
||||
|
|
||||
|
&.material-icons { /* stylelint-disable-line selector-max-class */ |
||||
|
font-size: 18px; |
||||
|
line-height: 22px; |
||||
|
text-align: center; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&.jstree-hovered:not(.jstree-clicked), |
||||
|
&.jstree-disabled { |
||||
|
div.node-icon { /* stylelint-disable-line selector-max-class */ |
||||
|
opacity: .5; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@media (max-width: 768px) { |
||||
|
.tb-entities-hierarchy { |
||||
|
.tb-entities-nav-tree-panel { |
||||
|
.tb-nav-tree-container { |
||||
|
&.jstree-proton-responsive { |
||||
|
.jstree-anchor { |
||||
|
div.node-icon { |
||||
|
width: 40px; |
||||
|
height: 40px; |
||||
|
margin: 0; |
||||
|
background-size: 24px 24px; |
||||
|
} |
||||
|
|
||||
|
md-icon.node-icon { |
||||
|
width: 40px; |
||||
|
min-width: 40px; |
||||
|
height: 40px; |
||||
|
min-height: 40px; |
||||
|
margin: 0; |
||||
|
|
||||
|
&.material-icons { /* stylelint-disable-line selector-max-class */ |
||||
|
font-size: 24px; |
||||
|
line-height: 40px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2019 The Thingsboard Authors |
||||
|
|
||||
|
Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
you may not use this file except in compliance with the License. |
||||
|
You may obtain a copy of the License at |
||||
|
|
||||
|
http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
|
||||
|
Unless required by applicable law or agreed to in writing, software |
||||
|
distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
See the License for the specific language governing permissions and |
||||
|
limitations under the License. |
||||
|
|
||||
|
--> |
||||
|
<div class="tb-absolute-fill tb-entities-hierarchy" layout="column"> |
||||
|
<div ng-show="vm.showData" flex class="tb-absolute-fill" layout="column"> |
||||
|
<md-toolbar class="md-table-toolbar md-default" ng-show="vm.query.search != null"> |
||||
|
<div class="md-toolbar-tools"> |
||||
|
<md-button class="md-icon-button" aria-label="{{ 'action.search' | translate }}"> |
||||
|
<md-icon aria-label="{{ 'action.search' | translate }}" class="material-icons">search</md-icon> |
||||
|
<md-tooltip md-direction="{{vm.ctx.dashboard.isWidgetExpanded ? 'bottom' : 'top'}}"> |
||||
|
{{'entity.search' | translate}} |
||||
|
</md-tooltip> |
||||
|
</md-button> |
||||
|
<md-input-container flex> |
||||
|
<label> </label> |
||||
|
<input ng-model="vm.query.search" class="searchInput" placeholder="{{'entity.search' | translate}}"/> |
||||
|
</md-input-container> |
||||
|
<md-button class="md-icon-button" aria-label="Close" ng-click="vm.exitFilterMode()"> |
||||
|
<md-icon aria-label="Close" class="material-icons">close</md-icon> |
||||
|
<md-tooltip md-direction="{{vm.ctx.dashboard.isWidgetExpanded ? 'bottom' : 'top'}}"> |
||||
|
{{ 'action.close' | translate }} |
||||
|
</md-tooltip> |
||||
|
</md-button> |
||||
|
</div> |
||||
|
</md-toolbar> |
||||
|
<div flex class="tb-entities-nav-tree-panel"> |
||||
|
<tb-nav-tree |
||||
|
load-nodes="vm.loadNodes" |
||||
|
on-node-selected="vm.onNodeSelected(node, event)" |
||||
|
on-nodes-inserted="vm.onNodesInserted(nodes, parent)" |
||||
|
edit-callbacks="vm.nodeEditCallbacks" |
||||
|
enable-search="true" |
||||
|
search-callback="vm.searchCallback(searchText, node)" |
||||
|
></tb-nav-tree> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,106 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2019 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
|
||||
|
.heat-map-widget { |
||||
|
position: relative; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
font-size: 16px; |
||||
|
line-height: 24px; |
||||
|
} |
||||
|
|
||||
|
.heat-map-info-panel { |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
right: 0; |
||||
|
z-index: 2; |
||||
|
background-color: rgba(0, 0, 0, .3); |
||||
|
border-bottom-left-radius: 5px; |
||||
|
|
||||
|
.md-button { |
||||
|
min-width: auto; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.heat-map-tooltip { |
||||
|
position: absolute; |
||||
|
top: 47px; |
||||
|
right: 0; |
||||
|
z-index: 2; |
||||
|
padding: 10px; |
||||
|
background-color: #fff; |
||||
|
border-top-left-radius: 10px; |
||||
|
border-bottom-left-radius: 10px; |
||||
|
transition: .3s ease-in-out; |
||||
|
|
||||
|
&-hidden { |
||||
|
transform: translateX(100%); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.heat-map-title { |
||||
|
padding: 10px; |
||||
|
} |
||||
|
|
||||
|
.heat-map-control-panel { |
||||
|
position: absolute; |
||||
|
bottom: 0; |
||||
|
z-index: 2; |
||||
|
box-sizing: border-box; |
||||
|
width: 100%; |
||||
|
padding-right: 70px; |
||||
|
padding-left: 20px; |
||||
|
background: rgba(0, 0, 0, .3); |
||||
|
|
||||
|
md-slider-container { |
||||
|
button { |
||||
|
max-width: none; |
||||
|
|
||||
|
ng-md-icon { |
||||
|
width: 36px; |
||||
|
height: 36px; |
||||
|
|
||||
|
svg { |
||||
|
width: inherit; |
||||
|
height: inherit; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.panel-timer { |
||||
|
max-width: none; |
||||
|
font-size: 20px; |
||||
|
font-weight: 600; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.heat-map-container { |
||||
|
position: relative; |
||||
|
z-index: 1; |
||||
|
flex: 1; |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
|
#heat-map { |
||||
|
z-index: 1; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
|
||||
|
.pointsLayerMarkerIcon { |
||||
|
border-radius: 50%; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,54 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2019 The Thingsboard Authors |
||||
|
|
||||
|
Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
you may not use this file except in compliance with the License. |
||||
|
You may obtain a copy of the License at |
||||
|
|
||||
|
http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
|
||||
|
Unless required by applicable law or agreed to in writing, software |
||||
|
distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
See the License for the specific language governing permissions and |
||||
|
limitations under the License. |
||||
|
|
||||
|
--> |
||||
|
<div class="heat-map-widget tracking-widget" layout="column" layout-align="center start" |
||||
|
ng-style="{'padding-top' : (!vm.widgetConfig.showTitle && vm.ctx.settings.showLabel) ? '5px' : '0px'}"> |
||||
|
<div ng-show="vm.ctx.settings.showLabel"> |
||||
|
{{vm.trips[vm.activeTripIndex].settings.labelText}} |
||||
|
</div> |
||||
|
<div class="heat-map-control-panel" lang="row" layout-align="center start"> |
||||
|
<md-slider-container> |
||||
|
<md-slider ng-model="vm.index" min="{{vm.minTime}}" max="{{vm.maxTime}}" ng-change="vm.recalculateTrips()"></md-slider> |
||||
|
<md-button aria-label="Play" ng-click="vm.playMove(true)" ng-disabled="vm.isPlaying"> |
||||
|
<ng-md-icon icon="play_circle_outline"></ng-md-icon> |
||||
|
</md-button> |
||||
|
<md-select ng-model="vm.speed" aria-label="Speed selector"> |
||||
|
<md-option ng-value="speed" flex="1" ng-repeat="speed in vm.speeds track by $index">{{ speed}} |
||||
|
</md-option> |
||||
|
</md-select> |
||||
|
<md-button aria-label="Stop playing" ng-click="vm.stopPlay()"> |
||||
|
<ng-md-icon icon="pause_circle_outline"></ng-md-icon> |
||||
|
</md-button> |
||||
|
<div class="panel-timer">{{vm.trips[vm.activeTripIndex].timeRange[vm.index].ts | date:'medium'}} |
||||
|
</div> |
||||
|
</md-slider-container> |
||||
|
</div> |
||||
|
<div class="heat-map-container" layout="column"> |
||||
|
<div flex id='heat-map'></div> |
||||
|
<div class="heat-map-info-panel" layout="row"> |
||||
|
<md-button aria-label="tooltip" ng-show="vm.staticSettings.displayTooltip" ng-click="vm.showHideTooltip()"> |
||||
|
<ng-md-icon icon="info"></ng-md-icon> |
||||
|
</md-button> |
||||
|
<!--<md-button aria-label="settings" ng-click="vm.openHideSettings()">--> |
||||
|
<!--<ng-md-icon icon="settings_applications"></ng-md-icon>--> |
||||
|
<!--</md-button>--> |
||||
|
</div> |
||||
|
<div class="heat-map-tooltip" class="heat-map-title" layout="column" ng-class="!vm.staticSettings.showTooltip ? 'heat-map-tooltip-hidden':''" ng-bind-html="vm.trips[vm.activeTripIndex].settings.tooltipText" |
||||
|
ng-style="{'background-color': vm.staticSettings.tooltipColor, 'opacity': vm.staticSettings.tooltipOpacity, 'color': vm.staticSettings.tooltipFontColor}"> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
Loading…
Reference in new issue