Merge branch 'master' into develop/3.2

This commit is contained in:
Igor Kulikov 2020-10-06 19:06:35 +03:00
commit 98227ea665
20 changed files with 433 additions and 380 deletions

View File

@ -45,7 +45,6 @@ import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.UpdateMessage;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
@ -56,6 +55,7 @@ import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.audit.AuditLog;
import org.thingsboard.server.common.data.device.DeviceSearchQuery;
import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
@ -73,6 +73,7 @@ import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.SortOrder;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
import org.thingsboard.server.common.data.plugin.ComponentType;
@ -890,7 +891,7 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
}, params).getBody();
}
public PageData<DashboardInfo> getCustomerDashboards(CustomerId customerId, TimePageLink pageLink) {
public PageData<DashboardInfo> getCustomerDashboards(CustomerId customerId, PageLink pageLink) {
Map<String, String> params = new HashMap<>();
params.put("customerId", customerId.getId().toString());
addPageLinkToParam(params, pageLink);
@ -1629,22 +1630,42 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
return RestJsonConverter.toTimeseries(timeseries);
}
@Deprecated
public List<TsKvEntry> getTimeseries(EntityId entityId, List<String> keys, Long interval, Aggregation agg, TimePageLink pageLink) {
return getTimeseries(entityId, keys, interval, agg, pageLink, true);
}
@Deprecated
public List<TsKvEntry> getTimeseries(EntityId entityId, List<String> keys, Long interval, Aggregation agg, TimePageLink pageLink, boolean useStrictDataTypes) {
SortOrder sortOrder = pageLink.getSortOrder();
return getTimeseries(entityId, keys, interval, agg, sortOrder != null ? sortOrder.getDirection() : null, pageLink.getStartTime(), pageLink.getEndTime(), 100, useStrictDataTypes);
}
public List<TsKvEntry> getTimeseries(EntityId entityId, List<String> keys, Long interval, Aggregation agg, SortOrder.Direction sortOrder, Long startTime, Long endTime, Integer limit, boolean useStrictDataTypes) {
Map<String, String> params = new HashMap<>();
params.put("entityType", entityId.getEntityType().name());
params.put("entityId", entityId.getId().toString());
params.put("keys", listToString(keys));
params.put("interval", interval == null ? "0" : interval.toString());
params.put("agg", agg == null ? "NONE" : agg.name());
params.put("limit", limit != null ? limit.toString() : "100");
params.put("orderBy", sortOrder != null ? sortOrder.name() : "DESC");
params.put("useStrictDataTypes", Boolean.toString(useStrictDataTypes));
addPageLinkToParam(params, pageLink);
StringBuilder urlBuilder = new StringBuilder(baseURL);
urlBuilder.append("/api/plugins/telemetry/{entityType}/{entityId}/values/timeseries?keys={keys}&interval={interval}&agg={agg}&useStrictDataTypes={useStrictDataTypes}&orderBy={orderBy}");
if (startTime != null) {
urlBuilder.append("&startTs={startTs}");
params.put("startTs", String.valueOf(startTime));
}
if (endTime != null) {
urlBuilder.append("&endTs={endTs}");
params.put("endTs", String.valueOf(endTime));
}
Map<String, List<JsonNode>> timeseries = restTemplate.exchange(
baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/timeseries?keys={keys}&interval={interval}&agg={agg}&useStrictDataTypes={useStrictDataTypes}&" + getUrlParamsTs(pageLink),
urlBuilder.toString(),
HttpMethod.GET,
HttpEntity.EMPTY,
new ParameterizedTypeReference<Map<String, List<JsonNode>>>() {
@ -1996,23 +2017,12 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
}
private String getTimeUrlParams(TimePageLink pageLink) {
return this.getUrlParams(pageLink);
}
private String getUrlParams(TimePageLink pageLink) {
return getUrlParams(pageLink, "startTime", "endTime");
}
private String getUrlParamsTs(TimePageLink pageLink) {
return getUrlParams(pageLink, "startTs", "endTs");
}
private String getUrlParams(TimePageLink pageLink, String startTime, String endTime) {
String urlParams = "limit={limit}&ascOrder={ascOrder}";
if (pageLink.getStartTime() != null) {
urlParams += "&" + startTime + "={startTime}";
urlParams += "&startTime={startTime}";
}
if (pageLink.getEndTime() != null) {
urlParams += "&" + endTime + "={endTime}";
urlParams += "&endTime={endTime}";
}
return urlParams;
}

View File

@ -65,7 +65,7 @@
"moment": "^2.27.0",
"ngx-clipboard": "^13.0.1",
"ngx-color-picker": "^10.0.1",
"ngx-daterangepicker-material": "^3.0.4",
"ngx-daterangepicker-material": "^4.0.1",
"ngx-flowchart": "git://github.com/thingsboard/ngx-flowchart.git#master",
"ngx-hm-carousel": "^2.0.0-rc.1",
"ngx-sharebuttons": "^8.0.1",
@ -105,10 +105,9 @@
"@types/jquery": "^3.5.1",
"@types/js-beautify": "^1.11.0",
"@types/jstree": "^3.3.40",
"@types/jszip": "^3.4.1",
"@types/leaflet": "^1.5.17",
"@types/leaflet-markercluster": "^1.0.3",
"@types/leaflet-polylinedecorator": "^1.6.0",
"@types/leaflet.markercluster": "^1.4.2",
"@types/lodash": "^4.14.159",
"@types/raphael": "^2.3.0",
"@types/react": "^16.9.46",

View File

@ -47,7 +47,7 @@ import {
import { forkJoin, Observable, of, ReplaySubject, Subject, throwError } from 'rxjs';
import { CancelAnimationFrame } from '@core/services/raf.service';
import { EntityType } from '@shared/models/entity-type.models';
import { createLabelFromDatasource, deepClone, isDefined, isEqual } from '@core/utils';
import { createLabelFromDatasource, deepClone, isDefined, isDefinedAndNotNull, isEqual } from '@core/utils';
import { EntityId } from '@app/shared/models/id/entity-id';
import * as moment_ from 'moment';
import { emptyPageData, PageData } from '@shared/models/page/page-data';
@ -1332,7 +1332,7 @@ export class WidgetSubscription implements IWidgetSubscription {
private updateLegend(dataIndex: number, data: DataSet, detectChanges: boolean) {
const dataKey = this.legendData.keys.find(key => key.dataIndex === dataIndex).dataKey;
const decimals = isDefined(dataKey.decimals) ? dataKey.decimals : this.decimals;
const decimals = isDefinedAndNotNull(dataKey.decimals) ? dataKey.decimals : this.decimals;
const units = dataKey.units && dataKey.units.length ? dataKey.units : this.units;
const legendKeyData = this.legendData.data[dataIndex];
if (this.legendConfig.showMin) {

View File

@ -421,7 +421,7 @@ export class ImportExportService {
}
public exportJSZip(data: object, filename: string) {
const jsZip: JSZip = new JSZip();
const jsZip = new JSZip();
for (const keyName in data) {
if (data.hasOwnProperty(keyName)) {
const valueData = data[keyName];

View File

@ -61,7 +61,7 @@
</div>
</mat-toolbar>
<div fxFlex class="table-container">
<table mat-table [dataSource]="alarmsDatasource"
<table mat-table [dataSource]="alarmsDatasource" [trackBy]="trackByRowIndex"
matSort [matSortActive]="sortOrderProperty" [matSortDirection]="pageLinkSortDirection()" matSortDisableClear>
<ng-container matColumnDef="select" sticky>
<mat-header-cell *matHeaderCellDef style="width: 30px;">

View File

@ -247,11 +247,8 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
}
public onDataUpdated() {
this.ngZone.run(() => {
this.updateTitle(true);
this.alarmsDatasource.updateAlarms();
this.ctx.detectChanges();
});
this.updateTitle(true);
this.alarmsDatasource.updateAlarms();
}
public pageLinkSortDirection(): SortDirection {
@ -565,6 +562,10 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
return column.def;
}
public trackByRowIndex(index: number) {
return index;
}
public headerStyle(key: EntityColumn): any {
const columnWidth = this.columnWidth[key.def];
return widthStyle(columnWidth);
@ -606,7 +607,19 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
} else {
content = this.defaultContent(key, contentInfo, value);
}
return isDefined(content) ? this.domSanitizer.bypassSecurityTrustHtml(content) : '';
if (!isDefined(content)) {
return '';
} else {
switch (typeof content) {
case 'string':
return this.domSanitizer.bypassSecurityTrustHtml(content);
default:
return content;
}
}
} else {
return '';
}
@ -804,7 +817,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
const alarmField = alarmFields[key.name];
if (alarmField) {
if (alarmField.time) {
return this.datePipe.transform(value, 'yyyy-MM-dd HH:mm:ss');
return value ? this.datePipe.transform(value, 'yyyy-MM-dd HH:mm:ss') : '';
} else if (alarmField.value === alarmFields.severity.value) {
return this.translate.instant(alarmSeverityTranslations.get(value));
} else if (alarmField.value === alarmFields.status.value) {

View File

@ -1002,7 +1002,8 @@ export abstract class TbAnalogueGauge<S extends AnalogueGaugeSettings, O extends
// animations
animation: settings.animation !== false && !this.ctx.isMobile,
animationDuration: (isDefined(settings.animationDuration) && settings.animationDuration !== null) ? settings.animationDuration : 500,
animationRule: settings.animationRule || 'cycle'
animationRule: settings.animationRule || 'cycle',
animatedValue: true
} as O;
this.prepareGaugeOptions(settings, gaugeData);

View File

@ -38,7 +38,7 @@
</div>
</mat-toolbar>
<div fxFlex class="table-container">
<table mat-table [dataSource]="entityDatasource"
<table mat-table [dataSource]="entityDatasource" [trackBy]="trackByRowIndex"
matSort [matSortActive]="sortOrderProperty" [matSortDirection]="pageLinkSortDirection()" matSortDisableClear>
<ng-container [matColumnDef]="column.def" *ngFor="let column of columns; trackBy: trackByColumnDef;">
<mat-header-cell [ngStyle]="headerStyle(column)" *matHeaderCellDef mat-sort-header> {{ column.title }} </mat-header-cell>

View File

@ -206,11 +206,8 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
}
public onDataUpdated() {
this.ngZone.run(() => {
this.updateTitle(true);
this.entityDatasource.dataUpdated();
this.ctx.detectChanges();
});
this.updateTitle(true);
this.entityDatasource.dataUpdated();
}
public pageLinkSortDirection(): SortDirection {
@ -488,6 +485,10 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
return column.def;
}
public trackByRowIndex(index: number) {
return index;
}
public headerStyle(key: EntityColumn): any {
const columnWidth = this.columnWidth[key.def];
return widthStyle(columnWidth);
@ -529,7 +530,19 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
} else {
content = this.defaultContent(key, contentInfo, value);
}
return isDefined(content) ? this.domSanitizer.bypassSecurityTrustHtml(content) : '';
if (!isDefined(content)) {
return '';
} else {
switch (typeof content) {
case 'string':
return this.domSanitizer.bypassSecurityTrustHtml(content);
default:
return content;
}
}
} else {
return '';
}

View File

@ -380,7 +380,7 @@ export class TbFlot {
const yaxesMap: {[units: string]: TbFlotAxisOptions} = {};
const predefinedThresholds: TbFlotThresholdMarking[] = [];
const thresholdsDatasources: Datasource[] = [];
if (this.settings.customLegendEnabled) {
if (this.settings.customLegendEnabled && this.settings.dataKeysListForLabels?.length) {
this.labelPatternsSourcesData = [];
const labelPatternsDatasources: Datasource[] = [];
this.settings.dataKeysListForLabels.forEach((item) => {

View File

@ -67,6 +67,7 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy {
title = '';
minValue: number;
maxValue: number;
newValue = 0;
private startDeg = -1;
private currentDeg = 0;
@ -175,16 +176,15 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy {
const offset = this.knob.offset();
const center = {
y : offset.top + this.knob.height()/2,
x: offset.left + this.knob.width()/2
y: offset.top + this.knob.height() / 2,
x: offset.left + this.knob.width() / 2
};
const rad2deg = 180/Math.PI;
const rad2deg = 180 / Math.PI;
const t: Touch = ((e.originalEvent as any).touches) ? (e.originalEvent as any).touches[0] : e;
const a = center.y - t.pageY;
const b = center.x - t.pageX;
let deg = Math.atan2(a,b)*rad2deg;
if(deg < 0){
let deg = Math.atan2(a, b) * rad2deg;
if (deg < 0) {
deg = 360 + deg;
}
if (deg > this.maxDeg) {
@ -196,13 +196,17 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy {
}
this.currentDeg = deg;
this.lastDeg = deg;
this.knobTopPointerContainer.css('transform','rotate('+(this.currentDeg)+'deg)');
this.knobTopPointerContainer.css('transform', 'rotate(' + (this.currentDeg) + 'deg)');
this.turn(this.degreeToRatio(this.currentDeg));
this.rotation = this.currentDeg;
this.startDeg = -1;
this.rpcUpdateValue(this.newValue);
});
this.knob.on('mousedown touchstart', (e) => {
this.moving = false;
e.preventDefault();
const offset = this.knob.offset();
const center = {
@ -211,7 +215,7 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy {
};
const rad2deg = 180/Math.PI;
this.knob.on('mousemove.rem touchmove.rem', (ev) => {
$(document).on('mousemove.rem touchmove.rem', (ev) => {
this.moving = true;
const t: Touch = ((ev.originalEvent as any).touches) ? (ev.originalEvent as any).touches[0] : ev;
@ -262,6 +266,9 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy {
});
$(document).on('mouseup.rem touchend.rem',() => {
if(this.newValue !== this.rpcValue && this.moving) {
this.rpcUpdateValue(this.newValue);
}
this.knob.off('.rem');
$(document).off('.rem');
this.rotation = this.currentDeg;
@ -308,12 +315,12 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy {
}
private turn(ratio: number) {
const value = Number((this.minValue + (this.maxValue - this.minValue)*ratio).toFixed(this.ctx.decimals));
if (this.canvasBar.value !== value) {
this.canvasBar.value = value;
this.newValue = Number((this.minValue + (this.maxValue - this.minValue)*ratio).toFixed(this.ctx.decimals));
if (this.canvasBar.value !== this.newValue) {
this.canvasBar.value = this.newValue;
}
this.updateColor(this.canvasBar.getValueColor());
this.onValue(value);
this.onValue(this.newValue);
}
private resize() {
@ -379,7 +386,6 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy {
private onValue(value: number) {
this.value = this.formatValue(value);
this.checkValueSize();
this.rpcUpdateValue(value);
this.ctx.detectChanges();
}

View File

@ -112,6 +112,9 @@ $error-height: 14px !default;
height: 90%;
}
.mat-slide-toggle-label{
height: 100%;
}
.mat-slide-toggle-thumb {
top: 0;
left: 0;

View File

@ -40,7 +40,7 @@ import {
} from '@shared/models/widget.models';
import { UtilsService } from '@core/services/utils.service';
import { TranslateService } from '@ngx-translate/core';
import { hashCode, isDefined, isNumber } from '@core/utils';
import {hashCode, isDefined, isDefinedAndNotNull, isNumber} from '@core/utils';
import cssjs from '@core/css/css';
import { PageLink } from '@shared/models/page/page-link';
import { Direction, SortOrder, sortOrderFromString } from '@shared/models/page/sort-order';
@ -197,11 +197,8 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
}
public onDataUpdated() {
this.ngZone.run(() => {
this.sources.forEach((source) => {
source.timeseriesDatasource.dataUpdated(this.data);
});
this.ctx.detectChanges();
this.sources.forEach((source) => {
source.timeseriesDatasource.dataUpdated(this.data);
});
}
@ -410,7 +407,18 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
const units = contentInfo.units || this.ctx.widgetConfig.units;
content = this.ctx.utils.formatValue(value, decimals, units, true);
}
return isDefined(content) ? this.domSanitizer.bypassSecurityTrustHtml(content) : '';
if (!isDefined(content)) {
return '';
} else {
switch (typeof content) {
case 'string':
return this.domSanitizer.bypassSecurityTrustHtml(content);
default:
return content;
}
}
}
}
@ -515,26 +523,20 @@ class TimeseriesDatasource implements DataSource<TimeseriesRow> {
row[d + 1] = cellData[1];
});
}
const rows: TimeseriesRow[] = [];
for (const t of Object.keys(rowsMap)) {
if (this.hideEmptyLines) {
let hideLine = true;
for (let c = 0; (c < data.length) && hideLine; c++) {
if (rowsMap[t][c + 1]) {
hideLine = false;
}
}
if (!hideLine) {
rows.push(rowsMap[t]);
}
for (const value of Object.values(rowsMap)) {
if (this.hideEmptyLines && isDefinedAndNotNull(value[1])) {
rows.push(value);
} else {
rows.push(rowsMap[t]);
rows.push(value);
}
}
return rows;
}
isEmpty(): Observable<boolean> {
return this.rowsSubject.pipe(
map((rows) => !rows.length)

View File

@ -96,8 +96,9 @@ export class DashboardFormComponent extends EntityComponent<Dashboard> {
}
prepareFormValue(formValue: any): any {
formValue.configuration = {...(this.entity.configuration || {}), ...(formValue.configuration || {})};
return formValue;
const preparedValue = super.prepareFormValue(formValue);
preparedValue.configuration = {...(this.entity.configuration || {}), ...(preparedValue.configuration || {})};
return preparedValue;
}
onPublicLinkCopied($event) {

View File

@ -29,7 +29,8 @@
<mat-form-field fxFlex class="mat-block">
<mat-label translate>rulenode.name</mat-label>
<input matInput formControlName="name" required>
<mat-error *ngIf="ruleNodeFormGroup.get('name').hasError('required')">
<mat-error *ngIf="ruleNodeFormGroup.get('name').hasError('required')
|| ruleNodeFormGroup.get('name').hasError('pattern')">
{{ 'rulenode.name-required' | translate }}
</mat-error>
</mat-form-field>

View File

@ -72,8 +72,9 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O
}
if (this.ruleNode) {
if (this.ruleNode.component.type !== RuleNodeType.RULE_CHAIN) {
this.ruleNodeFormGroup = this.fb.group({
name: [this.ruleNode.name, [Validators.required]],
name: [this.ruleNode.name, [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]],
debugMode: [this.ruleNode.debugMode, []],
configuration: [this.ruleNode.configuration, [Validators.required]],
additionalInfo: this.fb.group(
@ -102,6 +103,7 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O
private updateRuleNode() {
const formValue = this.ruleNodeFormGroup.value || {};
if (this.ruleNode.component.type === RuleNodeType.RULE_CHAIN) {
const targetRuleChainId: string = formValue.targetRuleChainId;
if (this.ruleNode.targetRuleChainId !== targetRuleChainId && targetRuleChainId) {
@ -115,6 +117,7 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O
Object.assign(this.ruleNode, formValue);
}
} else {
formValue.name = formValue.name.trim();
Object.assign(this.ruleNode, formValue);
}
}

View File

@ -1550,6 +1550,7 @@ export class AddRuleNodeDialogComponent extends DialogComponent<AddRuleNodeDialo
add(): void {
this.submitted = true;
this.ruleNodeDetailsComponent.validate();
if (this.ruleNodeDetailsComponent.ruleNodeFormGroup.valid) {
this.dialogRef.close(this.ruleNode);

View File

@ -1,12 +1,14 @@
{
"access": {
"unauthorized": "권한 없음.",
"unauthorized-access": "허가되지 않은 접근",
"unauthorized": "승인되지 않음",
"unauthorized-access": "승인되지 않은 접근",
"unauthorized-access-text": "이 리소스에 접근하려면 로그인해야 합니다!",
"access-forbidden": "접근 금지",
"access-forbidden-text": "접근 권한이 없습니다.!<br> 만일 이 페이지에 계속 접근하려면 다른 사용자로 로그인 하세요.",
"refresh-token-expired": "세션이 만료되었습니다.",
"refresh-token-failed": "세션을 새로 고칠 수 없습니다."
"access-forbidden-text": "접근 권한이 없습니다!<br> 만일 이 페이지에 계속 접근하려면 다른 사용자로 로그인 하세요.",
"refresh-token-expired": "세션이 만료되었습니다",
"refresh-token-failed": "세션을 새로 고칠 수 없습니다.",
"permission-denied": "권한이 없습니다",
"permission-denied-text": "이 작업을 수행할 권한이 없습니다!"
},
"action": {
"activate": "활설화",
@ -22,11 +24,11 @@
"update": "업데이트",
"remove": "제거",
"search": "검색",
"clear-search": "Clear search",
"clear-search": "검색 초기화",
"assign": "할당",
"unassign": "비할당",
"share": "Share",
"make-private": "Make private",
"make-private": "비공개로 설정",
"apply": "적용",
"apply-changes": "변경사항 적용",
"edit-mode": "수정 모드",
@ -44,8 +46,8 @@
"undo": "취소",
"copy": "복사",
"paste": "붙여넣기",
"copy-reference": "Copy reference",
"paste-reference": "Paste reference",
"copy-reference": "참조 복사",
"paste-reference": "참조 붙여넣기",
"import": "가져오기",
"export": "내보내기",
"share-via": "Share via {{provider}}"
@ -79,26 +81,26 @@
"smtp-port": "SMTP 포트",
"smtp-port-required": "SMTP 포트를 입력해야 합니다.",
"smtp-port-invalid": "올바른 SMTP 포트가 아닙니다.",
"timeout-msec": "제한시간 (msec)",
"timeout-required": "제한시간을 입력해야 합니다.",
"timeout-invalid": "올바른 제한시간이 아닙니다.",
"timeout-msec": "제한시간 (ms)",
"timeout-required": "제한시이 입력되지 않았습니다.",
"timeout-invalid": "제한시간이 올바르게 입력되지 않았습니다.",
"enable-tls": "TLS 사용",
"tls-version" : "TLS 버전",
"send-test-mail": "테스트 메일 보내기"
},
"alarm": {
"alarm": "Alarm",
"alarms": "Alarms",
"select-alarm": "Select alarm",
"no-alarms-matching": "No alarms matching '{{entity}}' were found.",
"alarm-required": "Alarm is required",
"alarm-status": "Alarm status",
"alarm": "알람",
"alarms": "알람",
"select-alarm": "알람 선택",
"no-alarms-matching": "'{{entity}}'에 대한 알람이 존재하지 않습니다.",
"alarm-required": "알람이 필요합니다",
"alarm-status": "알람 상태",
"search-status": {
"ANY": "Any",
"ACTIVE": "Active",
"ACTIVE": "활성",
"CLEARED": "Cleared",
"ACK": "Acknowledged",
"UNACK": "Unacknowledged"
"ACK": "수용",
"UNACK": "불수용"
},
"display-status": {
"ACTIVE_UNACK": "Active Unacknowledged",
@ -107,28 +109,28 @@
"CLEARED_ACK": "Cleared Acknowledged"
},
"no-alarms-prompt": "No alarms found",
"created-time": "Created time",
"type": "Type",
"severity": "Severity",
"originator": "Originator",
"originator-type": "Originator type",
"details": "Details",
"status": "Status",
"created-time": "생성된 시간",
"type": "종류",
"severity": "심각도",
"originator": "창시자",
"originator-type": "창시자 종류",
"details": "자세히",
"status": "상태",
"alarm-details": "Alarm details",
"start-time": "Start time",
"end-time": "End time",
"start-time": "시작 시각",
"end-time": "마지막 시각",
"ack-time": "Acknowledged time",
"clear-time": "Cleared time",
"severity-critical": "Critical",
"severity-major": "Major",
"severity-minor": "Minor",
"severity-warning": "Warning",
"severity-indeterminate": "Indeterminate",
"acknowledge": "Acknowledge",
"clear": "Clear",
"search": "Search alarms",
"selected-alarms": "{ count, plural, 1 {1 alarm} other {# alarms} } selected",
"no-data": "No data to display",
"severity-critical": "심각한",
"severity-major": "주요한",
"severity-minor": "작은",
"severity-warning": "경고",
"severity-indeterminate": "중간",
"acknowledge": "수용",
"clear": "지우기",
"search": "알람 검색",
"selected-alarms": "{ count, plural, 1 {1 alarm} other {# alarms} } 선택됨",
"no-data": "표시할 데이터가 없습니다",
"polling-interval": "Alarms polling interval (sec)",
"polling-interval-required": "Alarms polling interval is required.",
"min-polling-interval-message": "At least 1 sec polling interval is allowed.",
@ -178,46 +180,46 @@
"any-relation": "any"
},
"asset": {
"asset": "Asset",
"assets": "Assets",
"management": "Asset management",
"view-assets": "View Assets",
"add": "Add Asset",
"assign-to-customer": "Assign to customer",
"assign-asset-to-customer": "Assign Asset(s) To Customer",
"assign-asset-to-customer-text": "Please select the assets to assign to the customer",
"no-assets-text": "No assets found",
"assign-to-customer-text": "Please select the customer to assign the asset(s)",
"public": "Public",
"assignedToCustomer": "Assigned to customer",
"make-public": "Make asset public",
"make-private": "Make asset private",
"unassign-from-customer": "Unassign from customer",
"delete": "Delete asset",
"asset-public": "Asset is public",
"asset-type": "Asset type",
"asset-type-required": "Asset type is required.",
"select-asset-type": "Select asset type",
"enter-asset-type": "Enter asset type",
"any-asset": "Any asset",
"no-asset-types-matching": "No asset types matching '{{entitySubtype}}' were found.",
"asset-type-list-empty": "No asset types selected.",
"asset-types": "Asset types",
"name": "Name",
"name-required": "Name is required.",
"description": "Description",
"type": "Type",
"type-required": "Type is required.",
"details": "Details",
"events": "Events",
"add-asset-text": "Add new asset",
"asset-details": "Asset details",
"assign-assets": "Assign assets",
"assign-assets-text": "Assign { count, plural, 1 {1 asset} other {# assets} } to customer",
"delete-assets": "Delete assets",
"unassign-assets": "Unassign assets",
"asset": "자산",
"assets": "자산",
"management": "자산 관리",
"view-assets": "자산 보기",
"add": "자산 추가",
"assign-to-customer": "고객에게 자산 지정",
"assign-asset-to-customer": "자산을 고객에게 지정",
"assign-asset-to-customer-text": "고객에게 지정할 자산을 선택하세요",
"no-assets-text": "아무 자산도 없습니다",
"assign-to-customer-text": "자산에 지정될 고객을 선택하세요",
"public": "공개",
"assignedToCustomer": "지정된 고객",
"make-public": "자산을 공개로 설정",
"make-private": "자산을 비공개로 설정",
"unassign-from-customer": "고객 지정 해제",
"delete": "자산 삭제",
"asset-public": "공개된 자산",
"asset-type": "자산 종류",
"asset-type-required": "자산 종류를 선택하세요.",
"select-asset-type": "자산 종류 선택",
"enter-asset-type": "자산 종류 입력",
"any-asset": "모든 자산",
"no-asset-types-matching": "'{{entitySubtype}}'과 일치하는 자산 종류가 없습니다.",
"asset-type-list-empty": "아무 자산 종류도 선택되지 않았습니다.",
"asset-types": "자산 종류",
"name": "이름",
"name-required": "이름을 입력하세요.",
"description": "설명",
"type": "종류",
"type-required": "종류를 입력하세요.",
"details": "자세히",
"events": "이벤트",
"add-asset-text": "새로운 자산 추가",
"asset-details": "자산 자세히",
"assign-assets": "자산 지정",
"assign-assets-text": "자산 { count, plural, 1 {1 asset} other {# assets} }을 고객에게 지정",
"delete-assets": "자산 삭제",
"unassign-assets": "자산 지정 해제",
"unassign-assets-action-title": "Unassign { count, plural, 1 {1 asset} other {# assets} } from customer",
"assign-new-asset": "Assign new asset",
"assign-new-asset": "새로운 자산 지정",
"delete-asset-title": "Are you sure you want to delete the asset '{{assetName}}'?",
"delete-asset-text": "Be careful, after the confirmation the asset and all related data will become unrecoverable.",
"delete-assets-title": "Are you sure you want to delete { count, plural, 1 {1 asset} other {# assets} }?",
@ -248,10 +250,11 @@
"scope-server": "서버 속성",
"scope-shared": "공유 속성",
"add": "속성 추가",
"key": "Key",
"key-required": "속성 key를 입력하세요.",
"key": "키",
"last-update-time": "마지막 수정된 시간",
"key-required": "속성 키를 입력하세요.",
"value": "Value",
"value-required": "속성 value를 입력하세요.",
"value-required": "속성 값을 입력하세요.",
"delete-attributes-title": "{ count, plural, 1 {속성} other {여러 속성들을} } 삭제하시겠습니까??",
"delete-attributes-text": "모든 선택된 속성들이 제거 될 것이므로 주의하십시오.",
"delete-attributes": "속성 삭제",
@ -264,38 +267,40 @@
"add-widget-to-dashboard": "대시보드에 위젯 추가",
"selected-attributes": "{ count, plural, 1 {속성 1개} other {속성 #개} } 선택됨",
"selected-telemetry": "{ count, plural, 1 {최근 데이터 1개} other {최근 데이터 #개} } 선택됨"
"no-attributes-text": "아무 속성도 찾을 수 없습니다",
"no-telemetry-text": "아무 텔레메트리도 찾을 수 없습니다."
},
"audit-log": {
"audit": "Audit",
"audit-logs": "Audit Logs",
"timestamp": "Timestamp",
"entity-type": "Entity Type",
"entity-name": "Entity Name",
"user": "User",
"type": "Type",
"status": "Status",
"details": "Details",
"type-added": "Added",
"type-deleted": "Deleted",
"type-updated": "Updated",
"type-attributes-updated": "Attributes updated",
"type-attributes-deleted": "Attributes deleted",
"audit": "감사",
"audit-logs": "감사 로그",
"timestamp": "타임스탬프",
"entity-type": "기체 종류",
"entity-name": "개체 이름",
"user": "사용자",
"type": "종류",
"status": "상태",
"details": "자세히",
"type-added": "추가됨",
"type-deleted": "삭제됨",
"type-updated": "수정됨",
"type-attributes-updated": "속성이 수정되었습니다",
"type-attributes-deleted": "속성이 삭제되었습니다",
"type-rpc-call": "RPC call",
"type-credentials-updated": "Credentials updated",
"type-assigned-to-customer": "Assigned to Customer",
"type-unassigned-from-customer": "Unassigned from Customer",
"type-activated": "Activated",
"type-suspended": "Suspended",
"type-credentials-read": "Credentials read",
"type-attributes-read": "Attributes read",
"status-success": "Success",
"status-failure": "Failure",
"audit-log-details": "Audit log details",
"no-audit-logs-prompt": "No logs found",
"action-data": "Action data",
"failure-details": "Failure details",
"search": "Search audit logs",
"clear-search": "Clear search"
"type-credentials-updated": "자격 증명이 갱신되었습니다",
"type-assigned-to-customer": "고객에게 지정",
"type-unassigned-from-customer": "지정된 고객 해제",
"type-activated": "활성",
"type-suspended": "일시 중지",
"type-credentials-read": "자격 증명 읽기",
"type-attributes-read": "속성 읽기",
"status-success": "성공",
"status-failure": "실패",
"audit-log-details": "감사 로그 세부 사항",
"no-audit-logs-prompt": "아무 로그도 없습니다.",
"action-data": "액션 데이터",
"failure-details": "실패 세부 사항",
"search": "감사 로그 검색",
"clear-search": "검색 초기화"
},
"confirm-on-exit": {
"message": "변경 사항을 저장하지 않았습니다. 이 페이지를 나가시겠습니까?",
@ -323,8 +328,8 @@
},
"content-type": {
"json": "Json",
"text": "Text",
"binary": "Binary (Base64)"
"text": "텍스트",
"binary": "바이너리 (Base64)"
},
"customer": {
"customers": "커스터머",
@ -337,10 +342,10 @@
"manage-customer-users": "커스터머 사용자 관리",
"manage-customer-devices": "커스터머 디바이스 관리",
"manage-customer-dashboards": "커스터머 대시보드 관리",
"manage-public-devices": "Manage public devices",
"manage-public-dashboards": "Manage public dashboards",
"manage-customer-assets": "Manage customer assets",
"manage-public-assets": "Manage public assets",
"manage-public-devices": "공개된 디바이스 관리",
"manage-public-dashboards": "공개된 대시보드 관리",
"manage-customer-assets": "고객 자산 관리",
"manage-public-assets": "공개된 자산 관리",
"add-customer-text": "커스터머 추가",
"no-customers-text": "커스터머가 없습니다.",
"customer-details": "커스터머 상세정보",
@ -355,16 +360,16 @@
"title": "타이틀",
"title-required": "타이틀을 입력하세요.",
"description": "설명",
"details": "Details",
"events": "Events",
"copyId": "Copy customer Id",
"idCopiedMessage": "Customer Id has been copied to clipboard",
"select-customer": "Select customer",
"no-customers-matching": "No customers matching '{{entity}}' were found.",
"customer-required": "Customer is required",
"select-default-customer": "Select default customer",
"default-customer": "Default customer",
"default-customer-required": "Default customer is required in order to debug dashboard on Tenant level"
"details": "자세히",
"events": "이벤트",
"copyId": "고객 ID 복사",
"idCopiedMessage": "고객 ID가 클립 보드에 복사되었습니다.",
"select-customer": "선택된 고객",
"no-customers-matching": "'{{entity}}'에 해당하는 고객을 찾을 수 없습니다.",
"customer-required": "고객을 입력하세요.",
"select-default-customer": "기본 고객 선택",
"default-customer": "기본 고객",
"default-customer-required": "테넌트 수준에서 대시보드를 디버그 하기 위해서는 기본 고객이 필요합니다."
},
"datetime": {
"date-from": "시작 날짜",
@ -522,8 +527,8 @@
"assign-to-customer-text": "디바이스를 할당할 커스터머를 선택하세요.",
"device-details": "디바이스 상세정보",
"add-device-text": "디바이스 추가",
"credentials": "크리덴셜",
"manage-credentials": "크리덴셜 관리",
"credentials": "자격 증명",
"manage-credentials": "자격 증명 관리",
"delete": "디바이스 삭제",
"assign-devices": "디바이스 할당",
"assign-devices-text": "{ count, plural, 1 {디바이스 1개} other {디바이스 #개} }를 커서터머에 할당",
@ -575,8 +580,8 @@
"unknown-error": "알 수 없는 오류"
},
"entity": {
"entity": "Entity",
"entities": "Entities",
"entity": "개체",
"entities": "개체",
"aliases": "Entity aliases",
"entity-alias": "Entity alias",
"unable-delete-entity-alias-title": "Unable to delete entity alias",
@ -588,70 +593,70 @@
"alias-required": "Entity alias is required.",
"remove-alias": "Remove entity alias",
"add-alias": "Add entity alias",
"entity-list": "Entity list",
"entity-type": "Entity type",
"entity-types": "Entity types",
"entity-type-list": "Entity type list",
"any-entity": "Any entity",
"enter-entity-type": "Enter entity type",
"entity-list": "개체 목록",
"entity-type": "개체 종류",
"entity-types": "개체 종류",
"entity-type-list": "개체 종류 목록",
"any-entity": "모든 개체",
"enter-entity-type": "개체 종류 입력",
"no-entities-matching": "No entities matching '{{entity}}' were found.",
"no-entity-types-matching": "No entity types matching '{{entityType}}' were found.",
"name-starts-with": "Name starts with",
"name-starts-with": "다음으로 시작하는 이름",
"use-entity-name-filter": "Use filter",
"entity-list-empty": "No entities selected.",
"entity-type-list-empty": "No entity types selected.",
"entity-list-empty": "아무 개체도 선택되지 않았습니다.",
"entity-type-list-empty": "개체 종류가 선택되지 않았습니다.",
"entity-name-filter-required": "Entity name filter is required.",
"entity-name-filter-no-entity-matched": "No entities starting with '{{entity}}' were found.",
"all-subtypes": "All",
"select-entities": "Select entities",
"all-subtypes": "모두",
"select-entities": "선택된 개체",
"no-aliases-found": "No aliases found.",
"no-alias-matching": "'{{alias}}' not found.",
"create-new-alias": "Create a new one!",
"key": "Key",
"key-name": "Key name",
"no-keys-found": "No keys found.",
"no-key-matching": "'{{key}}' not found.",
"create-new-key": "Create a new one!",
"type": "Type",
"type-required": "Entity type is required.",
"type-device": "Device",
"type-devices": "Devices",
"create-new-alias": "생성 완료!",
"key": "",
"key-name": "키 이름",
"no-keys-found": "아무 키도 찾을 수 없습니다..",
"no-key-matching": "'{{key}}'를 찾을 수 없습니다.",
"create-new-key": "생성 완료!",
"type": "종류",
"type-required": "개체의 종류를 입력하세요.",
"type-device": "장치",
"type-devices": "장치",
"list-of-devices": "{ count, plural, 1 {One device} other {List of # devices} }",
"device-name-starts-with": "Devices whose names start with '{{prefix}}'",
"type-asset": "Asset",
"type-assets": "Assets",
"type-asset": "자산",
"type-assets": "자산",
"list-of-assets": "{ count, plural, 1 {One asset} other {List of # assets} }",
"asset-name-starts-with": "Assets whose names start with '{{prefix}}'",
"type-rule": "Rule",
"type-rules": "Rules",
"type-rule": "규칙",
"type-rules": "규칙",
"list-of-rules": "{ count, plural, 1 {One rule} other {List of # rules} }",
"rule-name-starts-with": "Rules whose names start with '{{prefix}}'",
"type-plugin": "Plugin",
"type-plugins": "Plugins",
"type-plugin": "플러그인",
"type-plugins": "플러그인",
"list-of-plugins": "{ count, plural, 1 {One plugin} other {List of # plugins} }",
"plugin-name-starts-with": "Plugins whose names start with '{{prefix}}'",
"type-tenant": "Tenant",
"type-tenants": "Tenants",
"type-tenant": "테넌트",
"type-tenants": "테넌트",
"list-of-tenants": "{ count, plural, 1 {One tenant} other {List of # tenants} }",
"tenant-name-starts-with": "Tenants whose names start with '{{prefix}}'",
"type-customer": "Customer",
"type-customers": "Customers",
"type-customer": "고객",
"type-customers": "고객",
"list-of-customers": "{ count, plural, 1 {One customer} other {List of # customers} }",
"customer-name-starts-with": "Customers whose names start with '{{prefix}}'",
"type-user": "User",
"type-users": "Users",
"type-user": "사용자",
"type-users": "사용자",
"list-of-users": "{ count, plural, 1 {One user} other {List of # users} }",
"user-name-starts-with": "Users whose names start with '{{prefix}}'",
"type-dashboard": "Dashboard",
"type-dashboards": "Dashboards",
"type-dashboard": "대시보드",
"type-dashboards": "대시보드",
"list-of-dashboards": "{ count, plural, 1 {One dashboard} other {List of # dashboards} }",
"dashboard-name-starts-with": "Dashboards whose names start with '{{prefix}}'",
"type-alarm": "Alarm",
"type-alarms": "Alarms",
"type-alarm": "알람",
"type-alarms": "알람",
"list-of-alarms": "{ count, plural, 1 {One alarms} other {List of # alarms} }",
"alarm-name-starts-with": "Alarms whose names start with '{{prefix}}'",
"type-rulechain": "Rule chain",
"type-rulechains": "Rule chains",
"type-rulechain": "규칙 사슬",
"type-rulechains": "규칙 사슬",
"list-of-rulechains": "{ count, plural, 1 {One rule chain} other {List of # rule chains} }",
"rulechain-name-starts-with": "Rule chains whose names start with '{{prefix}}'",
"type-current-customer": "Current Customer",
@ -667,23 +672,23 @@
"type-error": "에러",
"type-lc-event": "주기적 이벤트",
"type-stats": "통계",
"type-debug-rule-node": "Debug",
"type-debug-rule-chain": "Debug",
"type-debug-rule-node": "디버그",
"type-debug-rule-chain": "디버그",
"no-events-prompt": "이벤트 없음",
"error": "에러",
"alarm": "알람",
"event-time": "이벤트 발생 시간",
"server": "서버",
"body": "Body",
"method": "Method",
"type": "Type",
"entity": "Entity",
"message-id": "Message Id",
"message-type": "Message Type",
"data-type": "Data Type",
"relation-type": "Relation Type",
"metadata": "Metadata",
"data": "Data",
"method": "방법",
"type": "종류",
"entity": "개체",
"message-id": "메시지 ID",
"message-type": "메시지 종류",
"data-type": "데이터 종류",
"relation-type": "관계 종류",
"metadata": "메타데이터",
"data": "데이터",
"event": "이벤트",
"status": "상태",
"success": "성공",
@ -692,11 +697,11 @@
"errors-occurred": "오류가 발생했습니다"
},
"extension": {
"extensions": "Extensions",
"extensions": "확장",
"selected-extensions": "{ count, plural, 1 {1 extension} other {# extensions} } selected",
"type": "Type",
"key": "Key",
"value": "Value",
"type": "종류",
"key": "",
"value": "",
"id": "Id",
"extension-id": "Extension id",
"extension-type": "Extension type",
@ -992,14 +997,14 @@
"invalid-additional-info": "Unable to parse additional info json."
},
"rulechain": {
"rulechain": "Rule chain",
"rulechains": "Rule chains",
"rulechain": "규칙 사슬",
"rulechains": "규칙 사슬",
"root": "Root",
"delete": "Delete rule chain",
"name": "Name",
"name-required": "Name is required.",
"description": "Description",
"add": "Add Rule Chain",
"name": "이름",
"name-required": "이름을 입력하세요.",
"description": "설명",
"add": "규칙 사슬 추가",
"set-root": "Make rule chain root",
"set-root-rulechain-title": "Are you sure you want to make the rule chain '{{ruleChainName}}' root?",
"set-root-rulechain-text": "After the confirmation the rule chain will become root and will handle all incoming transport messages.",
@ -1008,14 +1013,14 @@
"delete-rulechains-title": "Are you sure you want to delete { count, plural, 1 {1 rule chain} other {# rule chains} }?",
"delete-rulechains-action-title": "Delete { count, plural, 1 {1 rule chain} other {# rule chains} }",
"delete-rulechains-text": "Be careful, after the confirmation all selected rule chains will be removed and all related data will become unrecoverable.",
"add-rulechain-text": "Add new rule chain",
"no-rulechains-text": "No rule chains found",
"rulechain-details": "Rule chain details",
"details": "Details",
"events": "Events",
"system": "System",
"import": "Import rule chain",
"export": "Export rule chain",
"add-rulechain-text": "새로운 규칙 사슬 추가",
"no-rulechains-text": "아무 규칙 사슬도 없습니다.",
"rulechain-details": "규칙 사슬 상세 정보",
"details": "자세히",
"events": "이벤트",
"system": "시스템",
"import": "규칙 사슬 불러오기",
"export": "규칙 사슬 내보내기",
"export-failed-error": "Unable to export rule chain: {{error}}",
"create-new-rulechain": "Create new rule chain",
"rulechain-file": "Rule chain file",
@ -1029,70 +1034,70 @@
"debug-mode": "Debug mode"
},
"rulenode": {
"details": "Details",
"events": "Events",
"search": "Search nodes",
"open-node-library": "Open node library",
"add": "Add rule node",
"name": "Name",
"name-required": "Name is required.",
"type": "Type",
"description": "Description",
"delete": "Delete rule node",
"select-all-objects": "Select all nodes and connections",
"deselect-all-objects": "Deselect all nodes and connections",
"delete-selected-objects": "Delete selected nodes and connections",
"delete-selected": "Delete selected",
"select-all": "Select all",
"copy-selected": "Copy selected",
"deselect-all": "Deselect all",
"rulenode-details": "Rule node details",
"debug-mode": "Debug mode",
"configuration": "Configuration",
"link": "Link",
"link-details": "Rule node link details",
"add-link": "Add link",
"link-label": "Link label",
"link-label-required": "Link label is required.",
"custom-link-label": "Custom link label",
"custom-link-label-required": "Custom link label is required.",
"type-filter": "Filter",
"details": "자세히",
"events": "이벤트",
"search": "노드 검색",
"open-node-library": "노드 라이브러리 열기",
"add": "규칙 노드 추가",
"name": "이름",
"name-required": "이름을 입력하세요.",
"type": "종류",
"description": "설명",
"delete": "규칙 노드 삭제",
"select-all-objects": "모든 노드와 연결을 선택",
"deselect-all-objects": "모든 노드와 연결을 선택 해제",
"delete-selected-objects": "선택된 노드와 연결을 삭제",
"delete-selected": "선택 삭제",
"select-all": "모두 선택",
"copy-selected": "선택 복사",
"deselect-all": "선택 해제",
"rulenode-details": "규칙 노드 상세 정보",
"debug-mode": "디버그 모드",
"configuration": "설정",
"link": "링크",
"link-details": "규칙 노드 링크 상세 정보",
"add-link": "링크 추가",
"link-label": "링크 라벨",
"link-label-required": "링크 라벨을 입력하세요.",
"custom-link-label": "링크 라벨 사용자 정의",
"custom-link-label-required": "링크 라벨 사용자 정의를 입력하세요.",
"type-filter": "필터",
"type-filter-details": "Filter incoming messages with configured conditions",
"type-enrichment": "Enrichment",
"type-enrichment-details": "Add additional information into Message Metadata",
"type-transformation": "Transformation",
"type-transformation-details": "Change Message payload and Metadata",
"type-action": "Action",
"type-action": "",
"type-action-details": "Perform special action",
"type-external": "External",
"type-external": "외부",
"type-external-details": "Interacts with external system",
"type-rule-chain": "Rule Chain",
"type-rule-chain-details": "Forwards incoming messages to specified Rule Chain",
"type-input": "Input",
"type-input": "입력",
"type-input-details": "Logical input of Rule Chain, forwards incoming messages to next related Rule Node",
"directive-is-not-loaded": "Defined configuration directive '{{directiveName}}' is not available.",
"ui-resources-load-error": "Failed to load configuration ui resources.",
"invalid-target-rulechain": "Unable to resolve target rule chain!",
"test-script-function": "Test script function",
"message": "Message",
"message-type": "Message type",
"message-type-required": "Message type is required",
"metadata": "Metadata",
"metadata-required": "Metadata entries can't be empty.",
"output": "Output",
"test": "Test",
"help": "Help"
"message": "메시지",
"message-type": "메시지 종류",
"message-type-required": "메시지 종류를 입력하세요.",
"metadata": "메타데이터",
"metadata-required": "메타데이터 엔트리를 입력하세요.",
"output": "출력",
"test": "테스트",
"help": "도움말"
},
"tenant": {
"tenants": "테넌트",
"management": "테넌트 관리",
"add": "테넌트 추가",
"admins": "Admins",
"admins": "관리자",
"manage-tenant-admins": "테넌트 관리자 관리",
"delete": "테넌트 삭제",
"add-tenant-text": "테넌트 추가",
"no-tenants-text": "테넌트가 없습니다.",
"tenant-details": "테넌트 상세정보",
"tenant-details": "테넌트 상세 정보",
"delete-tenant-title": "'{{tenantTitle}}' 테넌트를 삭제하시겠습니까?",
"delete-tenant-text": "테넌트와 관련된 모든 정보를 복구할 수 없으므로 주의하십시오.",
"delete-tenants-title": "{ count, plural, 1 {테넌트 1개} other {테넌트 #개} }를 삭제하시겠습니까?",
@ -1101,23 +1106,23 @@
"title": "타이틀",
"title-required": "타이틀을 입력하세요.",
"description": "설명",
"details": "Details",
"events": "Events",
"copyId": "Copy tenant Id",
"idCopiedMessage": "Tenant Id has been copied to clipboard",
"select-tenant": "Select tenant",
"details": "자세히",
"events": "이벤트",
"copyId": "테넌트 ID 복사",
"idCopiedMessage": "테넌트 ID를 클립보드로 복사",
"select-tenant": "테넌트 선택",
"no-tenants-matching": "No tenants matching '{{entity}}' were found.",
"tenant-required": "Tenant is required"
"tenant-required": "테넌트가 필요합니다."
},
"timeinterval": {
"seconds-interval": "{ seconds, plural, 1 {1 second} other {# seconds} }",
"minutes-interval": "{ minutes, plural, 1 {1 minute} other {# minutes} }",
"hours-interval": "{ hours, plural, 1 {1 hour} other {# hours} }",
"days-interval": "{ days, plural, 1 {1 day} other {# days} }",
"days": "Days",
"hours": "Hours",
"minutes": "Minutes",
"seconds": "Seconds",
"days": "",
"hours": "시간",
"minutes": "",
"seconds": "",
"advanced": "고급"
},
"timewindow": {
@ -1125,13 +1130,13 @@
"hours": "{ hours, plural, 0 { hour } 1 {1 hour } other {# hours } }",
"minutes": "{ minutes, plural, 0 { minute } 1 {1 minute } other {# minutes } }",
"seconds": "{ seconds, plural, 0 { second } 1 {1 second } other {# seconds } }",
"realtime": "Realtime",
"history": "History",
"last-prefix": "last",
"period": "from {{ startTime }} to {{ endTime }}",
"realtime": "실시간",
"history": "기록",
"last-prefix": "과거",
"period": "{{ startTime }}부터 {{ endTime }}까지",
"edit": "타임윈도우 편집",
"date-range": "날짜 범위",
"last": "Last",
"last": "과거",
"time-period": "기간"
},
"user": {
@ -1146,7 +1151,7 @@
"delete": "사용자 삭제",
"add-user-text": "새로운 사용자 추가",
"no-users-text": "사용자가 없습니다.",
"user-details": "사용자 상세정보",
"user-details": "사용자 상세 정보",
"delete-user-title": "'{{userEmail}}' 사용자를 삭제하시겠습니까?",
"delete-user-text": "사용자와 관련된 모든 데이터를 복구할 수 없으므로 주의하십시오.",
"delete-users-title": "{ count, plural, 1 {사용자 1명} other {사용자 #명} }을 삭제하시겠니까?",
@ -1242,10 +1247,10 @@
"update-dashboard-state": "Update current dashboard state",
"open-dashboard": "Navigate to other dashboard",
"custom": "Custom action",
"target-dashboard-state": "Target dashboard state",
"target-dashboard-state-required": "Target dashboard state is required",
"set-entity-from-widget": "Set entity from widget",
"target-dashboard": "Target dashboard",
"target-dashboard-state": "대상 대시보드 상태",
"target-dashboard-state-required": "대상 대시보드 상태가 필요합니다.",
"set-entity-from-widget": "위젯으로 부터 객체 설정",
"target-dashboard": "대상 대시보드",
"open-right-layout": "Open right dashboard layout (mobile view)"
},
"widgets-bundle": {
@ -1253,13 +1258,13 @@
"widgets-bundles": "위젯 번들",
"add": "위젯 번들 추가",
"delete": "위젯 번들 삭제",
"title": "타이틀",
"title-required": "타이틀을 입력하세요.",
"title": "제목",
"title-required": "제목을 입력하세요.",
"add-widgets-bundle-text": "위젯 번들 추가",
"no-widgets-bundles-text": "위젯 번들이 없습니다.",
"empty": "위젯 번들이 비어있습니다.",
"details": "상세",
"widgets-bundle-details": "위젯 번들 상세정보",
"widgets-bundle-details": "위젯 번들 상세 정보",
"delete-widgets-bundle-title": "'{{widgetsBundleTitle}}' 위젯 번들을 삭제하시겠습니까?",
"delete-widgets-bundle-text": "위젯 번들과 관련된 모든 데이터를 복구할 수 없으므로 주의하십시오.",
"delete-widgets-bundles-title": "{ count, plural, 1 {위젯 번들 1개} other {위젯 번들 #개} }를 삭제하시겠습니까?",
@ -1279,15 +1284,15 @@
"data": "데이터",
"settings": "설정",
"advanced": "고급",
"title": "타이틀",
"title": "제목",
"general-settings": "일반 설정",
"display-title": "타이틀 표시",
"display-title": "제목 표시",
"drop-shadow": "그림자",
"enable-fullscreen": "전체화면 사용 ",
"background-color": "배경 색",
"text-color": "글자 색",
"padding": "패딩",
"title-style": "타이틀 스타일",
"title-style": "제목 스타일",
"mobile-mode-settings": "모바일 모드 설정",
"order": "순서",
"height": "높이",
@ -1333,18 +1338,18 @@
"Oct": "10월",
"Nov": "11월",
"Dec": "12월",
"January": "월",
"February": "월",
"March": "행진",
"April": "4 월",
"June": "월",
"July": "월",
"August": "월",
"September": "월",
"October": "월",
"November": "십일월",
"December": "12 월",
"Custom Date Range": "맞춤 기간",
"January": "1월",
"February": "2월",
"March": "3월",
"April": "4월",
"June": "6월",
"July": "7월",
"August": "8월",
"September": "9월",
"October": "10월",
"November": "11월",
"December": "12월",
"Custom Date Range": "임의 기간 범위",
"Date Range Template": "기간 템플릿",
"Today": "오늘",
"Yesterday": "어제",
@ -1359,22 +1364,22 @@
"Hour": "시간",
"Day": "일",
"Week": "주",
"2 weeks": "주",
"2 weeks": "2 주",
"Month": "달",
"3 months": "3 개월",
"6 months": "6 개월",
"Custom interval": "사용자 지정 간격",
"Interval": "간격",
"Step size": "단계 크기",
"Ok": "Ok"
"Ok": "확인"
}
}
},
"icon": {
"icon": "Icon",
"select-icon": "Select icon",
"icon": "아이콘",
"select-icon": "선택된 아이콘",
"material-icons": "Material icons",
"show-all": "Show all icons"
"show-all": "모든 아이콘 보기"
},
"custom": {
"widget-action": {

View File

@ -3,7 +3,7 @@
"compilerOptions": {
"outDir": "../out-tsc/app",
"types": ["node", "jquery", "flot", "tooltipster", "tinycolor2", "js-beautify",
"react", "react-dom", "jstree", "raphael", "canvas-gauges", "leaflet", "leaflet-markercluster"]
"react", "react-dom", "jstree", "raphael", "canvas-gauges", "leaflet", "leaflet.markercluster"]
},
"angularCompilerOptions": {
"fullTemplateTypeCheck": true

View File

@ -1397,20 +1397,6 @@
dependencies:
"@types/jquery" "*"
"@types/jszip@^3.4.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@types/jszip/-/jszip-3.4.1.tgz#e7a4059486e494c949ef750933d009684227846f"
integrity sha512-TezXjmf3lj+zQ651r6hPqvSScqBLvyPI9FxdXBqpEwBijNGQ2NXpaFW/7joGzveYkKQUil7iiDHLo6LV71Pc0A==
dependencies:
jszip "*"
"@types/leaflet-markercluster@^1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@types/leaflet-markercluster/-/leaflet-markercluster-1.0.3.tgz#64151be453f6490e8751500482deb961064e782c"
integrity sha1-ZBUb5FP2SQ6HUVAEgt65YQZOeCw=
dependencies:
"@types/leaflet" "*"
"@types/leaflet-polylinedecorator@^1.6.0":
version "1.6.0"
resolved "https://registry.yarnpkg.com/@types/leaflet-polylinedecorator/-/leaflet-polylinedecorator-1.6.0.tgz#1572131ffedb3154c6e18e682d2fb700e203af19"
@ -1418,6 +1404,13 @@
dependencies:
"@types/leaflet" "*"
"@types/leaflet.markercluster@^1.4.2":
version "1.4.2"
resolved "https://registry.yarnpkg.com/@types/leaflet.markercluster/-/leaflet.markercluster-1.4.2.tgz#86b8ab7ca2397b48d9ba637757aaf7a6d1cc6f0f"
integrity sha512-QQ//hevAxMH2dlRQdRre7V/1G+TbtuDtZnZF/75TNwVIgklrsQVCIcS/cvLsl7UUryfPJ6xmoYHfFzK5iGVgpg==
dependencies:
"@types/leaflet" "*"
"@types/leaflet@*", "@types/leaflet@^1.5.17":
version "1.5.17"
resolved "https://registry.yarnpkg.com/@types/leaflet/-/leaflet-1.5.17.tgz#b2153dc12c344e6896a93ffc6b61ac79da251e5b"
@ -5632,7 +5625,7 @@ jstree@^3.3.10:
dependencies:
jquery ">=1.9.1"
jszip@*, jszip@^3.1.3, jszip@^3.5.0:
jszip@^3.1.3, jszip@^3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.5.0.tgz#b4fd1f368245346658e781fec9675802489e15f6"
integrity sha512-WRtu7TPCmYePR1nazfrtuF216cIVon/3GWOvHS9QR5bIwSbnxtdpma6un3jyGGNhHsKCSzn5Ypk+EkDRvTGiFA==
@ -6421,10 +6414,12 @@ ngx-color-picker@^10.0.1:
dependencies:
tslib "^2.0.0"
ngx-daterangepicker-material@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/ngx-daterangepicker-material/-/ngx-daterangepicker-material-3.0.4.tgz#af759e52fd587fcc9bce1fbcfc8cde828df6a471"
integrity sha512-pDg8kdXx/h8es8dpjBI+xbsxQbS0dV3uSPgfsx39t9LIw3Dv50h8T1achT5jUWSzSU7855ywTk+NlNBDTgkeNg==
ngx-daterangepicker-material@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/ngx-daterangepicker-material/-/ngx-daterangepicker-material-4.0.1.tgz#788c2e32eb4717629d4a0e60a60bf8d6430d8c13"
integrity sha512-0gY6DGU+dgYdmoAKrIJSB9xnDqBvj91Yis3II/ZJxxMfZVTG4qMMatck6w8FzdU+CYT64ArCq+Uwa6hJRHX6Nw==
dependencies:
tslib "^1.10.0"
"ngx-flowchart@git://github.com/thingsboard/ngx-flowchart.git#master":
version "0.0.0"