diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.scss
index 193fb5e793..20345a97f4 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.scss
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.scss
@@ -83,13 +83,105 @@
color: rgba(0, 0, 0, 0.87);
}
- .tb-get-started .mat-vertical-content p {
- font-style: normal;
- font-weight: 400;
- font-size: 14px;
- line-height: 20px;
- letter-spacing: 0.2px;
- color: rgba(0, 0, 0, 0.54);
+ .tb-get-started .mat-vertical-content {
+ p, li {
+ font-style: normal;
+ font-weight: 400;
+ font-size: 14px;
+ line-height: 20px;
+ letter-spacing: 0.2px;
+ color: rgba(0, 0, 0, 0.54);
+ em {
+ font-style: normal;
+ font-weight: 500;
+ font-size: 13px;
+ color: rgba(0, 0, 0, 0.38);
+ }
+ }
+ ul {
+ padding-inline-start: 20px;
+ }
+ .tb-bordered-content {
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ border: 1px solid rgba(0, 0, 0, 0.05);
+ border-radius: 8px;
+ padding: 16px;
+ p {
+ margin-top: 16px;
+ margin-bottom: 8px;
+ }
+ }
+ .tb-markdown-view {
+ .tb-getting-started-code {
+ .code-wrapper {
+ padding: 0;
+ pre[class*=language-] {
+ margin: 0;
+ padding: 9px 38px 9px 16px;
+ background: rgba(0, 0, 0, 0.03);
+ border-radius: 6px;
+ border: none;
+ }
+ code[class*="language-"], pre[class*="language-"] {
+ font-family: 'Roboto';
+ font-style: normal;
+ font-weight: 400;
+ font-size: 12px;
+ line-height: 16px;
+ letter-spacing: 0.25px;
+ color: rgba(0, 0, 0, 0.38);
+ overflow: hidden;
+ white-space: break-spaces;
+ word-break: break-all;
+ & * {
+ color: rgba(0, 0, 0, 0.38);
+ cursor: inherit;
+ background: transparent;
+ }
+ }
+ button.clipboard-btn {
+ right: 0;
+ height: 34px;
+ p, div {
+ background: transparent;
+ }
+ p {
+ margin: 0;
+ padding: 7px;
+ color: #305680;
+ }
+ div {
+ top: 0;
+ padding: 8px;
+ height: 34px;
+ width: 34px;
+ img {
+ display: none;
+ }
+ &:after {
+ content: "";
+ position: initial;
+ display: block;
+ width: 18px;
+ height: 18px;
+ background: #305680;
+ -webkit-mask-image: url(/assets/copy-code-icon.svg);
+ -webkit-mask-repeat: no-repeat;
+ mask-image: url(/assets/copy-code-icon.svg);
+ mask-repeat: no-repeat;
+ }
+ }
+ }
+ }
+ }
+ }
+ @media #{$mat-md-lg} {
+ .tb-bordered-content {
+ padding: 4px;
+ }
+ }
}
@media #{$mat-md-lg} {
@@ -107,15 +199,16 @@
line-height: 16px;
}
- .tb-get-started .mat-vertical-content p {
- font-size: 12px;
- line-height: 16px;
- letter-spacing: 0.25px;
+ .tb-get-started .mat-vertical-content {
+ p, li {
+ font-size: 12px;
+ line-height: 16px;
+ letter-spacing: 0.25px;
+ }
}
.tb-get-started .mat-vertical-content {
padding: 0 16px 16px 16px;
}
-
}
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.ts
index 9c07e62978..7566ae8579 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.ts
@@ -27,7 +27,7 @@ import {
} from '@home/components/widget/lib/home-page/getting-started-completed-dialog.component';
import { GettingStarted } from '@shared/models/user-settings.models';
import { CdkStep, StepperSelectionEvent } from '@angular/cdk/stepper';
-import { isUndefined } from '@core/utils';
+import { baseUrl, isUndefined } from '@core/utils';
import { MatStepper } from '@angular/material/stepper';
import { first } from 'rxjs/operators';
import { Authority } from '@shared/models/authority.enum';
@@ -54,6 +54,8 @@ export class GettingStartedWidgetComponent extends PageComponent implements OnIn
};
allCompleted = false;
+ baseUrl = baseUrl();
+
constructor(protected store: Store
,
private cd: ChangeDetectorRef,
private userSettingsService: UserSettingsService,
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/home-page-widgets.module.ts b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/home-page-widgets.module.ts
index 3be30dad30..debd1d6ca0 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/home-page-widgets.module.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/home-page-widgets.module.ts
@@ -28,6 +28,7 @@ import { GettingStartedWidgetComponent } from '@home/components/widget/lib/home-
import {
GettingStartedCompletedDialogComponent
} from '@home/components/widget/lib/home-page/getting-started-completed-dialog.component';
+import { ToggleHeaderComponent } from '@home/components/widget/lib/home-page/toggle-header.component';
@NgModule({
declarations:
@@ -40,7 +41,8 @@ import {
AddDocLinkDialogComponent,
EditDocLinksDialogComponent,
GettingStartedWidgetComponent,
- GettingStartedCompletedDialogComponent
+ GettingStartedCompletedDialogComponent,
+ ToggleHeaderComponent
],
imports: [
CommonModule,
@@ -55,7 +57,8 @@ import {
AddDocLinkDialogComponent,
EditDocLinksDialogComponent,
GettingStartedWidgetComponent,
- GettingStartedCompletedDialogComponent
+ GettingStartedCompletedDialogComponent,
+ ToggleHeaderComponent
]
})
export class HomePageWidgetsModule { }
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/toggle-header.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/toggle-header.component.html
new file mode 100644
index 0000000000..3cbf61fdae
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/toggle-header.component.html
@@ -0,0 +1,20 @@
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/toggle-header.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/toggle-header.component.scss
new file mode 100644
index 0000000000..0dce288424
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/toggle-header.component.scss
@@ -0,0 +1,87 @@
+/**
+ * Copyright © 2016-2023 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 "../../../../../../../scss/constants";
+
+:host ::ng-deep {
+ .mat-button-toggle-group.mat-button-toggle-group-appearance-standard.tb-toggle-header {
+ width: 100%;
+ border-radius: 100px;
+ height: 32px;
+ padding: 2px;
+ border: none;
+ background: rgba(0, 0, 0, 0.06);
+ margin-bottom: 8px;
+ .mat-button-toggle + .mat-button-toggle {
+ border-left: none;
+ }
+ .mat-button-toggle.mat-button-toggle-appearance-standard {
+ flex: 1;
+ color: rgba(0, 0, 0, 0.38);
+ background: transparent;
+
+ .mat-button-toggle-focus-overlay, .mat-button-toggle-ripple {
+ border-radius: 20px;
+ }
+ .mat-button-toggle-button {
+ height: 28px;
+ .mat-button-toggle-label-content {
+ line-height: 26px;
+ font-weight: 400;
+ font-size: 14px;
+ letter-spacing: 0.2px;
+ }
+ }
+ &.mat-button-toggle-checked {
+ .mat-button-toggle-button {
+ background: #F3F6FA;
+ color: #305680;
+ border: 1px solid #305680;
+ border-radius: 20px;
+
+ .mat-button-toggle-label-content {
+ font-weight: 500;
+ line-height: 24px;
+ }
+ }
+ }
+ }
+ }
+ @media #{$mat-md-lg} {
+ .mat-button-toggle-group.mat-button-toggle-group-appearance-standard.tb-toggle-header {
+ height: 24px;
+ margin-bottom: 0;
+ .mat-button-toggle.mat-button-toggle-appearance-standard {
+ .mat-button-toggle-button {
+ height: 20px;
+ display: grid;
+ .mat-button-toggle-label-content {
+ line-height: 20px;
+ font-size: 10px;
+ padding: 0 2px;
+ }
+ }
+ &.mat-button-toggle-checked {
+ .mat-button-toggle-button {
+ .mat-button-toggle-label-content {
+ line-height: 18px;
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/toggle-header.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/toggle-header.component.ts
new file mode 100644
index 0000000000..1d7876eb36
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/toggle-header.component.ts
@@ -0,0 +1,82 @@
+///
+/// Copyright © 2016-2023 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 {
+ AfterContentInit,
+ AfterViewInit,
+ ChangeDetectorRef,
+ Component,
+ ContentChildren,
+ Input,
+ OnInit,
+ QueryList,
+ ViewChild
+} from '@angular/core';
+import { PageComponent } from '@shared/components/page.component';
+import { Store } from '@ngrx/store';
+import { AppState } from '@core/core.state';
+import { AdminService } from '@core/http/admin.service';
+import { UpdateMessage } from '@shared/models/settings.models';
+import { getCurrentAuthUser } from '@core/auth/auth.selectors';
+import { Authority } from '@shared/models/authority.enum';
+import { of } from 'rxjs';
+import { MatStepper } from '@angular/material/stepper';
+import { MatButtonToggle, MatButtonToggleGroup } from '@angular/material/button-toggle';
+
+@Component({
+ selector: 'tb-toggle-header',
+ templateUrl: './toggle-header.component.html',
+ styleUrls: ['./toggle-header.component.scss']
+})
+export class ToggleHeaderComponent extends PageComponent implements OnInit, AfterViewInit {
+
+ @ViewChild('toggleGroup')
+ toggleGroup: MatButtonToggleGroup;
+
+ @ContentChildren(MatButtonToggle)
+ _buttonToggles: QueryList;
+
+ innerValue: any;
+
+ @Input()
+ set value(value: any) {
+ this.innerValue = value;
+ }
+
+ get value(): any {
+ return this.toggleGroup?.value;
+ }
+
+ @Input()
+ name: string;
+
+ constructor(protected store: Store) {
+ super(store);
+ }
+
+ ngOnInit() {
+ }
+
+ ngAfterViewInit() {
+ for (const toggle of this._buttonToggles) {
+ toggle.buttonToggleGroup = this.toggleGroup;
+ if (this.innerValue === toggle.value) {
+ toggle.checked = true;
+ }
+ }
+ }
+
+}
diff --git a/ui-ngx/src/app/modules/home/pages/home-links/home-links-routing.module.ts b/ui-ngx/src/app/modules/home/pages/home-links/home-links-routing.module.ts
index be408da234..3e0f797be1 100644
--- a/ui-ngx/src/app/modules/home/pages/home-links/home-links-routing.module.ts
+++ b/ui-ngx/src/app/modules/home/pages/home-links/home-links-routing.module.ts
@@ -27,6 +27,7 @@ import { AppState } from '@core/core.state';
import { map } from 'rxjs/operators';
import { getCurrentAuthUser } from '@core/auth/auth.selectors';
import sysAdminHomePageDashboardJson from '!raw-loader!./sys_admin_home_page.raw';
+import tenantAdminHomePageDashboardJson from '!raw-loader!./tenant_admin_home_page.raw';
@Injectable()
export class HomeDashboardResolver implements Resolve {
@@ -39,8 +40,18 @@ export class HomeDashboardResolver implements Resolve {
return this.dashboardService.getHomeDashboard().pipe(
map((dashboard) => {
if (!dashboard) {
- if (getCurrentAuthUser(this.store).authority === Authority.SYS_ADMIN) {
- dashboard = JSON.parse(sysAdminHomePageDashboardJson);
+ const authority = getCurrentAuthUser(this.store).authority;
+ switch (authority) {
+ case Authority.SYS_ADMIN:
+ dashboard = JSON.parse(sysAdminHomePageDashboardJson);
+ break;
+ case Authority.TENANT_ADMIN:
+ dashboard = JSON.parse(tenantAdminHomePageDashboardJson);
+ break;
+ case Authority.CUSTOMER_USER:
+ break;
+ }
+ if (dashboard) {
dashboard.hideDashboardToolbar = true;
}
}
diff --git a/ui-ngx/src/app/modules/home/pages/home-links/tenant_admin_home_page.raw b/ui-ngx/src/app/modules/home/pages/home-links/tenant_admin_home_page.raw
new file mode 100644
index 0000000000..3044499da0
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/pages/home-links/tenant_admin_home_page.raw
@@ -0,0 +1,667 @@
+{
+ "title": "Tenant Administrator Home Page",
+ "image": null,
+ "mobileHide": false,
+ "mobileOrder": null,
+ "configuration": {
+ "description": "",
+ "widgets": {
+ "d70cc256-4c7b-ee06-9905-b8c5e546605f": {
+ "isSystemType": true,
+ "bundleAlias": "cards",
+ "typeAlias": "markdown_card",
+ "type": "latest",
+ "title": "New widget",
+ "image": null,
+ "description": null,
+ "sizeX": 5,
+ "sizeY": 3.5,
+ "config": {
+ "datasources": [],
+ "timewindow": {
+ "displayValue": "",
+ "selectedTab": 0,
+ "realtime": {
+ "realtimeType": 1,
+ "interval": 1000,
+ "timewindowMs": 60000,
+ "quickInterval": "CURRENT_DAY"
+ },
+ "history": {
+ "historyType": 0,
+ "interval": 1000,
+ "timewindowMs": 60000,
+ "fixedTimewindow": {
+ "startTimeMs": 1680168340431,
+ "endTimeMs": 1680254740431
+ },
+ "quickInterval": "CURRENT_DAY"
+ },
+ "aggregation": {
+ "type": "AVG",
+ "limit": 25000
+ }
+ },
+ "showTitle": false,
+ "backgroundColor": "#fff",
+ "color": "rgba(0, 0, 0, 0.87)",
+ "padding": "16px",
+ "settings": {
+ "useMarkdownTextFunction": false,
+ "markdownTextPattern": "\n
\n
{{ 'widgets.activity.title' | translate }}
\n
\n {{ 'device.devices' | translate }}\n {{ 'widgets.transport-messages.title' | translate }}\n \n
\n
\n \n \n \n \n \n \n \n
",
+ "applyDefaultMarkdownStyle": false,
+ "markdownCss": ".tb-card-content {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n}\n"
+ },
+ "title": "Transport messages",
+ "showTitleIcon": false,
+ "iconColor": "rgba(0, 0, 0, 0.87)",
+ "iconSize": "24px",
+ "titleTooltip": "",
+ "dropShadow": false,
+ "enableFullscreen": false,
+ "widgetStyle": {},
+ "titleStyle": {
+ "fontSize": "16px",
+ "fontWeight": 400
+ },
+ "showLegend": false,
+ "useDashboardTimewindow": true,
+ "widgetCss": "",
+ "pageSize": 1024,
+ "noDataDisplayMessage": ""
+ },
+ "row": 0,
+ "col": 0,
+ "id": "d70cc256-4c7b-ee06-9905-b8c5e546605f"
+ },
+ "8ee72d43-678c-4e25-e9a8-7d4cfd7a5f8e": {
+ "isSystemType": true,
+ "bundleAlias": "charts",
+ "typeAlias": "timeseries_bars_flot",
+ "type": "timeseries",
+ "title": "New widget",
+ "image": null,
+ "description": null,
+ "sizeX": 8,
+ "sizeY": 5,
+ "config": {
+ "datasources": [
+ {
+ "type": "entity",
+ "name": null,
+ "entityAliasId": "d9229b29-3f46-de8d-7fe8-eb0c43c75079",
+ "filterId": null,
+ "dataKeys": [
+ {
+ "name": "transportMsgCountHourly",
+ "type": "timeseries",
+ "label": "{i18n:widgets.transport-messages.title}",
+ "color": "#305680",
+ "settings": {},
+ "_hash": 0.2880464219129071,
+ "aggregationType": null,
+ "units": null,
+ "decimals": null,
+ "funcBody": null,
+ "usePostProcessing": null,
+ "postFuncBody": null
+ }
+ ],
+ "latestDataKeys": []
+ }
+ ],
+ "timewindow": {
+ "hideInterval": false,
+ "hideLastInterval": false,
+ "hideQuickInterval": false,
+ "hideAggregation": true,
+ "hideAggInterval": false,
+ "hideTimezone": false,
+ "selectedTab": 1,
+ "history": {
+ "historyType": 0,
+ "timewindowMs": 2592000000,
+ "interval": 86400000,
+ "fixedTimewindow": {
+ "startTimeMs": 1680443065451,
+ "endTimeMs": 1680529465451
+ },
+ "quickInterval": "CURRENT_DAY"
+ },
+ "aggregation": {
+ "type": "SUM",
+ "limit": 50000
+ }
+ },
+ "showTitle": false,
+ "backgroundColor": "#fff",
+ "color": "rgba(0, 0, 0, 0.87)",
+ "padding": "0px",
+ "settings": {
+ "stack": true,
+ "fontSize": 10,
+ "fontColor": "#545454",
+ "showTooltip": true,
+ "tooltipIndividual": false,
+ "tooltipCumulative": false,
+ "hideZeros": false,
+ "grid": {
+ "verticalLines": false,
+ "horizontalLines": false,
+ "outlineWidth": 0,
+ "color": "#545454",
+ "backgroundColor": null,
+ "tickColor": "#DDDDDD"
+ },
+ "xaxis": {
+ "title": null,
+ "showLabels": true,
+ "color": "#545454"
+ },
+ "yaxis": {
+ "min": 0,
+ "max": null,
+ "title": null,
+ "showLabels": true,
+ "color": "#545454",
+ "tickSize": null,
+ "tickDecimals": 0,
+ "ticksFormatter": "return value % 1000 === 0 ? ((value / 1000) + 'k') : '';"
+ },
+ "defaultBarWidth": 1800000,
+ "barAlignment": "left",
+ "comparisonEnabled": false,
+ "timeForComparison": "previousInterval",
+ "comparisonCustomIntervalValue": 7200000,
+ "xaxisSecond": {
+ "axisPosition": "top",
+ "title": null,
+ "showLabels": true
+ },
+ "customLegendEnabled": false,
+ "dataKeysListForLabels": []
+ },
+ "title": "Transport messages",
+ "dropShadow": false,
+ "enableFullscreen": false,
+ "titleStyle": {
+ "fontSize": "16px",
+ "fontWeight": 400
+ },
+ "widgetStyle": {
+ "padding": "0"
+ },
+ "useDashboardTimewindow": false,
+ "showLegend": false,
+ "actions": {},
+ "displayTimewindow": true,
+ "showTitleIcon": false,
+ "titleTooltip": "",
+ "widgetCss": ".tb-widget-container > .tb-widget {\n border: none !important;\n border-radius: 0 !important;\n box-shadow: none !important;\n}\n\n.tb-widget-container > .tb-widget .flot-base {\n opacity: 0.48;\n}\n",
+ "pageSize": 1024,
+ "noDataDisplayMessage": "",
+ "legendConfig": {
+ "direction": "column",
+ "position": "bottom",
+ "sortDataKeys": false,
+ "showMin": false,
+ "showMax": false,
+ "showAvg": true,
+ "showTotal": false,
+ "showLatest": false
+ }
+ },
+ "row": 0,
+ "col": 0,
+ "id": "8ee72d43-678c-4e25-e9a8-7d4cfd7a5f8e"
+ },
+ "867f82cf-ecf2-2d5c-35cb-08c6f2edc3a4": {
+ "isSystemType": true,
+ "bundleAlias": "home_page_widgets",
+ "typeAlias": "documentation_links",
+ "type": "static",
+ "title": "New widget",
+ "image": null,
+ "description": null,
+ "sizeX": 7.5,
+ "sizeY": 3,
+ "config": {
+ "datasources": [],
+ "timewindow": {
+ "realtime": {
+ "timewindowMs": 60000
+ }
+ },
+ "showTitle": false,
+ "backgroundColor": "rgb(255, 255, 255)",
+ "color": "rgba(0, 0, 0, 0.87)",
+ "padding": "16px",
+ "settings": {
+ "columns": 2
+ },
+ "title": "Documentation",
+ "dropShadow": false,
+ "enableFullscreen": false,
+ "widgetStyle": {},
+ "widgetCss": "",
+ "pageSize": 1024,
+ "noDataDisplayMessage": "",
+ "showLegend": false
+ },
+ "row": 0,
+ "col": 0,
+ "id": "867f82cf-ecf2-2d5c-35cb-08c6f2edc3a4"
+ },
+ "a23185ad-dc46-806c-0e50-5b21fb080ace": {
+ "isSystemType": true,
+ "bundleAlias": "home_page_widgets",
+ "typeAlias": "getting_started",
+ "type": "static",
+ "title": "New widget",
+ "image": null,
+ "description": null,
+ "sizeX": 7.5,
+ "sizeY": 6.5,
+ "config": {
+ "datasources": [],
+ "timewindow": {
+ "realtime": {
+ "timewindowMs": 60000
+ }
+ },
+ "showTitle": false,
+ "backgroundColor": "rgb(255, 255, 255)",
+ "color": "rgba(0, 0, 0, 0.87)",
+ "padding": "16px",
+ "settings": {
+ "columns": 3
+ },
+ "title": "Getting started",
+ "dropShadow": false,
+ "enableFullscreen": false,
+ "widgetStyle": {},
+ "widgetCss": "",
+ "pageSize": 1024,
+ "noDataDisplayMessage": "",
+ "showLegend": false
+ },
+ "row": 0,
+ "col": 0,
+ "id": "a23185ad-dc46-806c-0e50-5b21fb080ace"
+ },
+ "d26e5cd7-75ef-d475-00c7-1a2d1114efe8": {
+ "isSystemType": true,
+ "bundleAlias": "charts",
+ "typeAlias": "basic_timeseries",
+ "type": "timeseries",
+ "title": "New widget",
+ "image": null,
+ "description": null,
+ "sizeX": 8,
+ "sizeY": 5,
+ "config": {
+ "datasources": [
+ {
+ "type": "entity",
+ "name": null,
+ "entityAliasId": "d9229b29-3f46-de8d-7fe8-eb0c43c75079",
+ "filterId": null,
+ "dataKeys": [
+ {
+ "name": "activeDevicesCount",
+ "type": "timeseries",
+ "label": "{i18n:device.devices}",
+ "color": "#305680",
+ "settings": {
+ "hideDataByDefault": false,
+ "disableDataHiding": false,
+ "removeFromLegend": false,
+ "excludeFromStacking": false,
+ "showLines": true,
+ "lineWidth": 3,
+ "fillLines": true,
+ "showPoints": false,
+ "showPointsLineWidth": 5,
+ "showPointsRadius": 3,
+ "showPointShape": "circle",
+ "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
+ "showSeparateAxis": false,
+ "axisPosition": "left",
+ "comparisonSettings": {
+ "showValuesForComparison": true,
+ "comparisonValuesLabel": "",
+ "color": ""
+ },
+ "thresholds": []
+ },
+ "_hash": 0.9688095820365725,
+ "aggregationType": null,
+ "units": null,
+ "decimals": null,
+ "funcBody": null,
+ "usePostProcessing": null,
+ "postFuncBody": null
+ }
+ ],
+ "latestDataKeys": []
+ }
+ ],
+ "timewindow": {
+ "hideInterval": false,
+ "hideLastInterval": false,
+ "hideQuickInterval": false,
+ "hideAggregation": true,
+ "hideAggInterval": true,
+ "hideTimezone": false,
+ "selectedTab": 1,
+ "history": {
+ "historyType": 0,
+ "timewindowMs": 2592000000,
+ "interval": 7200000,
+ "fixedTimewindow": {
+ "startTimeMs": 1681400576338,
+ "endTimeMs": 1681486976338
+ },
+ "quickInterval": "CURRENT_DAY"
+ },
+ "aggregation": {
+ "type": "NONE",
+ "limit": 25000
+ }
+ },
+ "showTitle": false,
+ "backgroundColor": "#fff",
+ "color": "rgba(0, 0, 0, 0.87)",
+ "padding": "0px",
+ "settings": {
+ "stack": false,
+ "fontSize": 10,
+ "fontColor": "#545454",
+ "showTooltip": true,
+ "tooltipIndividual": false,
+ "tooltipCumulative": false,
+ "hideZeros": false,
+ "grid": {
+ "verticalLines": false,
+ "horizontalLines": false,
+ "outlineWidth": 0,
+ "color": "#545454",
+ "backgroundColor": null,
+ "tickColor": "#DDDDDD"
+ },
+ "xaxis": {
+ "title": null,
+ "showLabels": true,
+ "color": "#545454"
+ },
+ "yaxis": {
+ "min": null,
+ "max": null,
+ "title": null,
+ "showLabels": true,
+ "color": "#545454",
+ "tickSize": null,
+ "tickDecimals": 0,
+ "ticksFormatter": ""
+ },
+ "shadowSize": 0,
+ "smoothLines": true,
+ "comparisonEnabled": false,
+ "timeForComparison": "previousInterval",
+ "comparisonCustomIntervalValue": 7200000,
+ "xaxisSecond": {
+ "axisPosition": "top",
+ "title": null,
+ "showLabels": true
+ },
+ "customLegendEnabled": false,
+ "dataKeysListForLabels": []
+ },
+ "title": "Devices activity",
+ "dropShadow": false,
+ "enableFullscreen": false,
+ "titleStyle": {
+ "fontSize": "16px",
+ "fontWeight": 400
+ },
+ "useDashboardTimewindow": false,
+ "displayTimewindow": true,
+ "showTitleIcon": false,
+ "titleTooltip": "",
+ "widgetStyle": {
+ "padding": "0"
+ },
+ "widgetCss": ".tb-widget-container > .tb-widget {\n border: none !important;\n border-radius: 0 !important;\n box-shadow: none !important;\n}",
+ "pageSize": 1024,
+ "noDataDisplayMessage": "",
+ "showLegend": false,
+ "legendConfig": {
+ "direction": "column",
+ "position": "bottom",
+ "sortDataKeys": false,
+ "showMin": false,
+ "showMax": false,
+ "showAvg": true,
+ "showTotal": false,
+ "showLatest": false
+ }
+ },
+ "row": 0,
+ "col": 0,
+ "id": "d26e5cd7-75ef-d475-00c7-1a2d1114efe8"
+ }
+ },
+ "states": {
+ "default": {
+ "name": "Tenant Administrator Home Page",
+ "root": true,
+ "layouts": {
+ "main": {
+ "widgets": {
+ "d70cc256-4c7b-ee06-9905-b8c5e546605f": {
+ "sizeX": 41,
+ "sizeY": 16,
+ "row": 26,
+ "col": 44,
+ "mobileOrder": 7,
+ "mobileHeight": 8
+ },
+ "867f82cf-ecf2-2d5c-35cb-08c6f2edc3a4": {
+ "sizeX": 31,
+ "sizeY": 16,
+ "row": 42,
+ "col": 26,
+ "mobileHide": true
+ },
+ "a23185ad-dc46-806c-0e50-5b21fb080ace": {
+ "sizeX": 35,
+ "sizeY": 58,
+ "row": 0,
+ "col": 85,
+ "mobileHide": true
+ }
+ },
+ "gridSettings": {
+ "backgroundColor": "#eeeeee",
+ "columns": 120,
+ "margin": 12,
+ "backgroundSizeMode": "100%",
+ "autoFillHeight": true,
+ "backgroundImageUrl": null,
+ "mobileAutoFillHeight": false,
+ "mobileRowHeight": 20,
+ "outerMargin": true
+ }
+ }
+ }
+ },
+ "transport_messages": {
+ "name": "Transport messages",
+ "root": false,
+ "layouts": {
+ "main": {
+ "widgets": {
+ "8ee72d43-678c-4e25-e9a8-7d4cfd7a5f8e": {
+ "sizeX": 24,
+ "sizeY": 11,
+ "row": 0,
+ "col": 0
+ }
+ },
+ "gridSettings": {
+ "backgroundColor": "#ffffff",
+ "columns": 24,
+ "margin": 0,
+ "backgroundSizeMode": "100%",
+ "autoFillHeight": true,
+ "backgroundImageUrl": null,
+ "mobileAutoFillHeight": true,
+ "mobileRowHeight": 70,
+ "outerMargin": true
+ }
+ }
+ }
+ },
+ "devices_activity": {
+ "name": "Devices activity",
+ "root": false,
+ "layouts": {
+ "main": {
+ "widgets": {
+ "d26e5cd7-75ef-d475-00c7-1a2d1114efe8": {
+ "sizeX": 24,
+ "sizeY": 11,
+ "row": 0,
+ "col": 0
+ }
+ },
+ "gridSettings": {
+ "backgroundColor": "#ffffff",
+ "columns": 24,
+ "margin": 0,
+ "outerMargin": true,
+ "backgroundSizeMode": "100%",
+ "autoFillHeight": true,
+ "backgroundImageUrl": null,
+ "mobileAutoFillHeight": true,
+ "mobileRowHeight": 70
+ }
+ }
+ }
+ }
+ },
+ "entityAliases": {
+ "ae870700-071f-b3bc-406c-16ba554c5a55": {
+ "id": "ae870700-071f-b3bc-406c-16ba554c5a55",
+ "alias": "Tenants",
+ "filter": {
+ "type": "entityType",
+ "resolveMultiple": true,
+ "entityType": "TENANT"
+ }
+ },
+ "ca4d90e4-f9ae-6fca-6b09-85815a48d52b": {
+ "id": "ca4d90e4-f9ae-6fca-6b09-85815a48d52b",
+ "alias": "TenantProfiles",
+ "filter": {
+ "type": "entityType",
+ "resolveMultiple": true,
+ "entityType": "TENANT"
+ }
+ },
+ "a1ddb8fa-90ff-5598-e7f2-e254194d055d": {
+ "id": "a1ddb8fa-90ff-5598-e7f2-e254194d055d",
+ "alias": "Devices",
+ "filter": {
+ "type": "entityType",
+ "resolveMultiple": true,
+ "entityType": "DEVICE"
+ }
+ },
+ "619cdf00-a042-3b55-124e-194c1b28c236": {
+ "id": "619cdf00-a042-3b55-124e-194c1b28c236",
+ "alias": "Assets",
+ "filter": {
+ "type": "entityType",
+ "resolveMultiple": true,
+ "entityType": "ASSET"
+ }
+ },
+ "1d97ff7f-8b42-5882-f87b-16f3d0dee4f2": {
+ "id": "1d97ff7f-8b42-5882-f87b-16f3d0dee4f2",
+ "alias": "Users",
+ "filter": {
+ "type": "entityType",
+ "resolveMultiple": true,
+ "entityType": "USER"
+ }
+ },
+ "0dd2b154-59f4-0f97-da1a-d85f5b5cfe31": {
+ "id": "0dd2b154-59f4-0f97-da1a-d85f5b5cfe31",
+ "alias": "Customers",
+ "filter": {
+ "type": "entityType",
+ "resolveMultiple": true,
+ "entityType": "CUSTOMER"
+ }
+ },
+ "d9229b29-3f46-de8d-7fe8-eb0c43c75079": {
+ "id": "d9229b29-3f46-de8d-7fe8-eb0c43c75079",
+ "alias": "Api Usage State",
+ "filter": {
+ "type": "apiUsageState",
+ "resolveMultiple": true
+ }
+ }
+ },
+ "filters": {},
+ "timewindow": {
+ "displayValue": "",
+ "hideInterval": false,
+ "hideLastInterval": false,
+ "hideQuickInterval": false,
+ "hideAggregation": false,
+ "hideAggInterval": false,
+ "hideTimezone": false,
+ "selectedTab": 0,
+ "realtime": {
+ "realtimeType": 0,
+ "interval": 1000,
+ "timewindowMs": 60000,
+ "quickInterval": "CURRENT_DAY"
+ },
+ "history": {
+ "historyType": 0,
+ "interval": 1000,
+ "timewindowMs": 60000,
+ "fixedTimewindow": {
+ "startTimeMs": 1680168326072,
+ "endTimeMs": 1680254726072
+ },
+ "quickInterval": "CURRENT_DAY"
+ },
+ "aggregation": {
+ "type": "AVG",
+ "limit": 25000
+ }
+ },
+ "settings": {
+ "stateControllerId": "entity",
+ "showTitle": false,
+ "showDashboardsSelect": true,
+ "showEntitiesSelect": true,
+ "showDashboardTimewindow": true,
+ "showDashboardExport": true,
+ "toolbarAlwaysOpen": true,
+ "titleColor": "rgba(0,0,0,0.870588)",
+ "showDashboardLogo": false,
+ "dashboardLogoUrl": null,
+ "hideToolbar": true,
+ "showFilters": true,
+ "showUpdateDashboardImage": true,
+ "dashboardCss": ".tb-widget-container > .tb-widget {\n border: 1px solid rgba(0, 0, 0, 0.05);\n box-shadow: 0px 5px 16px rgba(0, 0, 0, 0.04);\n border-radius: 12px;\n}\n\n.tb-widget-container > .tb-widget:not([style*=\"padding: 0\"]) {\n padding: 16px !important;\n}\n\n.tb-card-title {\n display: grid;\n}\n\n.tb-home-widget-title {\n font-style: normal;\n font-weight: 500;\n font-size: 14px;\n line-height: 20px;\n letter-spacing: 0.25px;\n color: rgba(0, 0, 0, 0.54);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.tb-home-widget-link {\n position: relative;\n border-bottom: none;\n}\n\n.tb-home-widget-link:hover {\n border-bottom: none;\n}\n\n.tb-home-widget-link:focus {\n border-bottom: none;\n}\n\n.tb-home-widget-link::after {\n content: 'arrow_forward';\n display: inline-block;\n transform: rotate(315deg);\n font-family: 'Material Icons';\n font-weight: normal;\n font-style: normal;\n font-size: 18px;\n color: rgba(0, 0, 0, 0.12);\n vertical-align: bottom;\n margin-left: 6px; \n}\n\n.tb-home-widget-link:hover::after {\n color: inherit;\n}\n\n.tb-home-widget-info-icon {\n color: rgba(0, 0, 0, 0.12);\n font-size: 16px;\n width: 16px;\n height: 16px;\n line-height: 15px;\n vertical-align: middle;\n}\n\n.tb-widget-container > .tb-widget .tb-timewindow {\n font-size: 14px;\n line-height: 20px;\n letter-spacing: 0.25px;\n color: rgba(0, 0, 0, 0.54);\n padding: 0;\n}\n\n.tb-widget-container > .tb-widget .tb-legend-keys .tb-legend-label {\n cursor: pointer;\n user-select: none;\n font-weight: 400;\n font-size: 14px;\n line-height: 20px;\n letter-spacing: 0.2px;\n color: rgba(0, 0, 0, 0.54);\n}\n\n@media screen and (min-width: 960px) and (max-width: 1279px) {\n .tb-widget-container > .tb-widget {\n border-radius: 4px;\n }\n .tb-widget-container > .tb-widget:not([style*=\"padding: 0\"]) {\n padding: 2px !important;\n }\n .tb-hide-md {\n display: none;\n }\n}\n\n@media screen and (min-width: 1280px) and (max-width: 1819px) {\n .tb-widget-container > .tb-widget:not([style*=\"padding: 0\"]) {\n padding: 8px !important;\n }\n .tb-hide-lg {\n display: none;\n }\n}\n\n@media screen and (min-width: 960px) and (max-width: 1819px) {\n .tb-hide-md-lg {\n display: none;\n }\n\n .tb-home-widget-title {\n font-size: 12px;\n line-height: 16px;\n }\n \n .tb-widget-container > .tb-widget .tb-widget-title {\n padding: 0;\n }\n\n .tb-widget-container > .tb-widget .tb-timewindow {\n font-size: 12px;\n line-height: 16px;\n min-height: 24px;\n padding: 0;\n }\n\n .tb-widget-container > .tb-widget .tb-timewindow .mat-mdc-icon-button.tb-mat-32 {\n width: 24px;\n height: 24px;\n line-height: 24px;\n }\n\n .tb-widget-container > .tb-widget .tb-timewindow .mat-mdc-icon-button.tb-mat-32 .mat-icon {\n width: 18px;\n height: 18px;\n font-size: 18px;\n }\n \n .tb-widget-container > .tb-widget tb-legend {\n padding-bottom: 0 !important;\n }\n \n .tb-widget-container > .tb-widget .tb-legend-keys .tb-legend-label {\n font-size: 11px;\n line-height: 16px;\n letter-spacing: 0.25px;\n }\n}\n\n@media screen and (max-width: 959px), screen and (min-width: 1820px) {\n .tb-hide-not-md-lg {\n display: none;\n }\n}\n"
+ }
+ },
+ "externalId": null,
+ "name": "Tenant Administrator Home Page"
+}
\ No newline at end of file
diff --git a/ui-ngx/src/app/shared/components/markdown.component.html b/ui-ngx/src/app/shared/components/markdown.component.html
index 5b8b9f8af0..67e8cd0da2 100644
--- a/ui-ngx/src/app/shared/components/markdown.component.html
+++ b/ui-ngx/src/app/shared/components/markdown.component.html
@@ -22,5 +22,5 @@
background: #efefef;">
{{error}}
-
+
diff --git a/ui-ngx/src/app/shared/components/markdown.component.ts b/ui-ngx/src/app/shared/components/markdown.component.ts
index 5af7ccce6b..753effc24f 100644
--- a/ui-ngx/src/app/shared/components/markdown.component.ts
+++ b/ui-ngx/src/app/shared/components/markdown.component.ts
@@ -39,6 +39,7 @@ import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { SHARED_MODULE_TOKEN } from '@shared/components/tokens';
import { deepClone, guid, isDefinedAndNotNull } from '@core/utils';
import { Observable, of, ReplaySubject } from 'rxjs';
+import { coerceBoolean } from '@shared/decorators/coerce-boolean';
let defaultMarkdownStyle;
@@ -76,6 +77,10 @@ export class TbMarkdownComponent implements OnChanges {
get fallbackToPlainMarkdown(): boolean { return this.fallbackToPlainMarkdownValue; }
set fallbackToPlainMarkdown(value: boolean) { this.fallbackToPlainMarkdownValue = coerceBooleanProperty(value); }
+ @Input()
+ @coerceBoolean()
+ usePlainMarkdown = false;
+
@Output() ready = new EventEmitter
();
private lineNumbersValue = false;
@@ -124,13 +129,8 @@ export class TbMarkdownComponent implements OnChanges {
}
template = this.sanitizeCurlyBraces(template);
this.markdownContainer.clear();
- const parent = this;
- let readyObservable: Observable;
- let compileModules = [this.sharedModule];
- if (this.additionalCompileModules) {
- compileModules = compileModules.concat(this.additionalCompileModules);
- }
let styles: string[] = [];
+ let readyObservable: Observable;
if (this.applyDefaultMarkdownStyle) {
if (!defaultMarkdownStyle) {
defaultMarkdownStyle = deepClone(TbMarkdownComponent['ɵcmp'].styles)[0].replace(/\[_nghost\-%COMP%\]/g, '')
@@ -141,70 +141,87 @@ export class TbMarkdownComponent implements OnChanges {
if (this.additionalStyles) {
styles = styles.concat(this.additionalStyles);
}
- this.dynamicComponentFactoryService.createDynamicComponentFactory(
- class TbMarkdownInstance {
- ngOnDestroy(): void {
- parent.destroyMarkdownInstanceResources();
- }
- },
- template,
- compileModules,
- true, 1, styles
- ).subscribe((factory) => {
- this.tbMarkdownInstanceComponentFactory = factory;
- const injector: Injector = Injector.create({providers: [], parent: this.markdownContainer.injector});
- try {
- this.tbMarkdownInstanceComponentRef =
- this.markdownContainer.createComponent(this.tbMarkdownInstanceComponentFactory, 0, injector);
- if (this.context) {
- for (const propName of Object.keys(this.context)) {
- this.tbMarkdownInstanceComponentRef.instance[propName] = this.context[propName];
- }
- }
- this.tbMarkdownInstanceComponentRef.instance.style = this.style;
- readyObservable = this.handleImages(this.tbMarkdownInstanceComponentRef.location.nativeElement);
- this.cd.detectChanges();
- this.error = null;
- } catch (error) {
- readyObservable = this.handleError(template, error, styles);
- }
- readyObservable.subscribe(() => {
- this.ready.emit();
- });
- },
- (error) => {
- readyObservable = this.handleError(template, error, styles);
+ if (this.usePlainMarkdown) {
+ readyObservable = this.plainMarkdown(template, styles);
this.cd.detectChanges();
readyObservable.subscribe(() => {
this.ready.emit();
});
- });
+ } else {
+ const parent = this;
+ let compileModules = [this.sharedModule];
+ if (this.additionalCompileModules) {
+ compileModules = compileModules.concat(this.additionalCompileModules);
+ }
+ this.dynamicComponentFactoryService.createDynamicComponentFactory(
+ class TbMarkdownInstance {
+ ngOnDestroy(): void {
+ parent.destroyMarkdownInstanceResources();
+ }
+ },
+ template,
+ compileModules,
+ true, 1, styles
+ ).subscribe((factory) => {
+ this.tbMarkdownInstanceComponentFactory = factory;
+ const injector: Injector = Injector.create({providers: [], parent: this.markdownContainer.injector});
+ try {
+ this.tbMarkdownInstanceComponentRef =
+ this.markdownContainer.createComponent(this.tbMarkdownInstanceComponentFactory, 0, injector);
+ if (this.context) {
+ for (const propName of Object.keys(this.context)) {
+ this.tbMarkdownInstanceComponentRef.instance[propName] = this.context[propName];
+ }
+ }
+ this.tbMarkdownInstanceComponentRef.instance.style = this.style;
+ readyObservable = this.handleImages(this.tbMarkdownInstanceComponentRef.location.nativeElement);
+ this.cd.detectChanges();
+ this.error = null;
+ } catch (error) {
+ readyObservable = this.handleError(template, error, styles);
+ }
+ readyObservable.subscribe(() => {
+ this.ready.emit();
+ });
+ },
+ (error) => {
+ readyObservable = this.handleError(template, error, styles);
+ this.cd.detectChanges();
+ readyObservable.subscribe(() => {
+ this.ready.emit();
+ });
+ });
+ }
}
private handleError(template: string, error, styles?: string[]): Observable {
this.error = (error ? error + '' : 'Failed to render markdown!').replace(/\n/g, '
');
this.markdownContainer.clear();
if (this.fallbackToPlainMarkdownValue) {
- const element = this.fallbackElement.nativeElement;
- let styleElement;
- if (styles?.length) {
- const markdownClass = 'tb-markdown-view-' + guid();
- let innerStyle = styles.join('\n');
- innerStyle = innerStyle.replace(/\.tb-markdown-view/g, '.' + markdownClass);
- template = template.replace(/tb-markdown-view/g, markdownClass);
- styleElement = this.renderer.createElement('style');
- styleElement.innerHTML = innerStyle;
- }
- element.innerHTML = template;
- if (styleElement) {
- this.renderer.appendChild(element, styleElement);
- }
- return this.handleImages(element);
+ return this.plainMarkdown(template, styles);
} else {
return of(null);
}
}
+ private plainMarkdown(template: string, styles?: string[]): Observable {
+ const element = this.fallbackElement.nativeElement;
+ let styleElement;
+ if (styles?.length) {
+ const markdownClass = 'tb-markdown-view-' + guid();
+ let innerStyle = styles.join('\n');
+ innerStyle = innerStyle.replace(/\.tb-markdown-view/g, '.' + markdownClass);
+ template = template.replace(/tb-markdown-view/g, markdownClass);
+ styleElement = this.renderer.createElement('style');
+ styleElement.innerHTML = innerStyle;
+ }
+ element.innerHTML = template;
+ if (styleElement) {
+ this.renderer.appendChild(element, styleElement);
+ }
+ return this.handleImages(element);
+ }
+
private handlePlugins(element: HTMLElement): void {
if (this.lineNumbers) {
this.setPluginClass(element, PrismPlugin.LineNumbers);
diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json
index 610cdb209e..0c318d4849 100644
--- a/ui-ngx/src/assets/locale/locale.constant-en_US.json
+++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json
@@ -5114,6 +5114,9 @@
"title": "Transport messages",
"info": "All the messages that came from devices"
},
+ "activity": {
+ "title": "Activity"
+ },
"documentation": {
"title": "Documentation",
"add-link": "Add link",
@@ -5201,6 +5204,52 @@
"content": "Some text
Follow the documentation on how to do it:
",
"how-to-configure-notifications": "How to configure Notifications"
}
+ },
+ "tenant-admin": {
+ "step1": {
+ "title": "Create device",
+ "content": "We will manually provision the device using the UI. Follow the documentation on how to do it:
",
+ "how-to-create-device": "How to create Device"
+ },
+ "step2": {
+ "title": "Connect device",
+ "content-before": "To connect the device you need to get the device credentials. But we recommend using the default auto-generated one.
- Go to device table
- Click on the device row to open device details
- Press the button \"Copy access token\"
Use simple commands to publish data over HTTP:
",
+ "ubuntu": {
+ "install-curl": "Install cURL for Ubuntu:"
+ },
+ "macos": {
+ "install-curl": "Install cURL for MacOS:"
+ },
+ "windows": {
+ "install-curl": "Starting Windows 10 b17063, cURL is available by default."
+ },
+ "replace-access-token": "Replace $ACCESS_TOKEN with your device's token:",
+ "content-after": "You can also use other protocols such as MQTT, CoAP, etc.
Follow the documentation on how to do it:
",
+ "how-to-connect-device": "How to connect Device"
+ },
+ "step3": {
+ "title": "Create dashboard",
+ "content": "Create a dashboard to visualize data from entities such as assets, devices, etc.
Follow the documentation on how to do it:
",
+ "how-to-create-dashboard": "How to create Dashboard"
+ },
+ "step4": {
+ "title": "Configure alarm rules",
+ "alarm-rules": "Alarm rules",
+ "content": "When the temperature reaches 25°C, we will raise an alarm. Follow the documentation on how to do it:
",
+ "how-to-configure-alarm-rules": "How to configure Alarm rules"
+ },
+ "step5": {
+ "title": "Create alarm",
+ "content-before": "To trigger the alarm, send a new telemetry value of 26°C or higher.
",
+ "replace-access-token": "Replace $ACCESS_TOKEN with your device's token:",
+ "content-after": "Follow the documentation on how to do it:
",
+ "how-to-create-alarm": "How to create Alarm"
+ },
+ "step6": {
+ "title": "Create customer and assign dashboard",
+ "content": "By creating end-user dashboards, a customer user can only see his own devices, and data from another customer will be hidden.
Follow the documentation on how to do it:
",
+ "how-to-create-customer-and-assign-dashboard": "How to create Customer and assign Dashboard"
+ }
}
}
},