From 538abeb14067c39e99bac100389ee403990d6baa Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 10 Feb 2020 13:04:56 +0200 Subject: [PATCH] Input widgets --- .../core/notification/notification.models.ts | 2 + ui-ngx/src/app/core/services/utils.service.ts | 21 +++- .../widget/dynamic-widget.component.ts | 47 +++++++- .../components/widget/widget.component.ts | 8 +- .../home/models/widget-component.models.ts | 1 + .../components/snack-bar-component.html | 2 +- .../app/shared/components/toast.directive.ts | 31 +++++- .../app/shared/pipe/keyboard-shortcut.pipe.ts | 1 - .../assets/locale/locale.constant-de_DE.json | 27 ++++- .../assets/locale/locale.constant-en_US.json | 40 +++++++ .../assets/locale/locale.constant-es_ES.json | 25 +++++ .../assets/locale/locale.constant-fr_FR.json | 27 ++++- .../assets/locale/locale.constant-it_IT.json | 27 ++++- .../assets/locale/locale.constant-ru_RU.json | 40 +++++++ .../assets/locale/locale.constant-uk_UA.json | 103 +++++++++++++++++- 15 files changed, 385 insertions(+), 17 deletions(-) diff --git a/ui-ngx/src/app/core/notification/notification.models.ts b/ui-ngx/src/app/core/notification/notification.models.ts index 26df85b101..88bf992a1e 100644 --- a/ui-ngx/src/app/core/notification/notification.models.ts +++ b/ui-ngx/src/app/core/notification/notification.models.ts @@ -29,8 +29,10 @@ export class NotificationMessage { type: NotificationType; target?: string; duration?: number; + forceDismiss?: boolean; horizontalPosition?: NotificationHorizontalPosition; verticalPosition?: NotificationVerticalPosition; + panelClass?: string | string[]; } export class HideNotification { diff --git a/ui-ngx/src/app/core/services/utils.service.ts b/ui-ngx/src/app/core/services/utils.service.ts index 3ab20bb36d..50faae512b 100644 --- a/ui-ngx/src/app/core/services/utils.service.ts +++ b/ui-ngx/src/app/core/services/utils.service.ts @@ -20,7 +20,7 @@ import { Inject, Injectable, NgZone } from '@angular/core'; import { WINDOW } from '@core/services/window.service'; import { ExceptionData } from '@app/shared/models/error.models'; -import { deepClone, deleteNullProperties, guid, isDefined, isUndefined } from '@core/utils'; +import { deepClone, deleteNullProperties, guid, isDefined, isDefinedAndNotNull, isUndefined } from '@core/utils'; import { WindowMessage } from '@shared/models/window-message.model'; import { TranslateService } from '@ngx-translate/core'; import { customTranslationsPrefix } from '@app/shared/models/constants'; @@ -441,4 +441,23 @@ export class UtilsService { this.window.history.replaceState({}, '', baseUrl + params); } + public deepClone(target: T, ignoreFields?: string[]): T { + return deepClone(target, ignoreFields); + } + + public isUndefined(value: any): boolean { + return isUndefined(value); + } + + public isDefined(value: any): boolean { + return isDefined(value); + } + + public defaultValue(value: any, defaultValue: any): any { + if (isDefinedAndNotNull(value)) { + return value; + } else { + return defaultValue; + } + } } diff --git a/ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts index b70f694c36..4107c1bb5f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts @@ -15,14 +15,19 @@ /// import { PageComponent } from '@shared/components/page.component'; -import { Inject, Injector, Input, OnDestroy, OnInit } from '@angular/core'; +import { Inject, Injector, OnDestroy, OnInit } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { WidgetContext, IDynamicWidgetComponent } from '@home/models/widget-component.models'; -import { ExceptionData } from '@shared/models/error.models'; +import { IDynamicWidgetComponent, WidgetContext } from '@home/models/widget-component.models'; import { HttpErrorResponse } from '@angular/common/http'; import { RafService } from '@core/services/raf.service'; -import { DeviceService } from '@core/http/device.service'; +import { ActionNotificationShow } from '@core/notification/notification.actions'; +import { + NotificationHorizontalPosition, + NotificationType, + NotificationVerticalPosition +} from '@core/notification/notification.models'; +import { FormBuilder, Validators } from '@angular/forms'; export class DynamicWidgetComponent extends PageComponent implements IDynamicWidgetComponent, OnInit, OnDestroy { @@ -33,8 +38,11 @@ export class DynamicWidgetComponent extends PageComponent implements IDynamicWid [key: string]: any; + validators = Validators; + constructor(@Inject(RafService) public raf: RafService, @Inject(Store) protected store: Store, + @Inject(FormBuilder) public fb: FormBuilder, @Inject(Injector) private $injector: Injector, @Inject('widgetContext') public readonly ctx: WidgetContext, @Inject('errorMessages') public readonly errorMessages: string[]) { @@ -63,4 +71,35 @@ export class DynamicWidgetComponent extends PageComponent implements IDynamicWid } } + showSuccessToast(message: string, duration: number = 1000, + verticalPosition: NotificationVerticalPosition = 'bottom', + horizontalPosition: NotificationHorizontalPosition = 'left', + target?: string) { + this.showToast('success', message, duration, verticalPosition, horizontalPosition, target); + } + + showErrorToast(message: string, + verticalPosition: NotificationVerticalPosition = 'bottom', + horizontalPosition: NotificationHorizontalPosition = 'left', + target?: string) { + this.showToast('error', message, undefined, verticalPosition, horizontalPosition, target); + } + + showToast(type: NotificationType, message: string, duration: number = 1000, + verticalPosition: NotificationVerticalPosition = 'bottom', + horizontalPosition: NotificationHorizontalPosition = 'left', + target?: string) { + this.store.dispatch(new ActionNotificationShow( + { + message, + type, + duration, + verticalPosition, + horizontalPosition, + target, + panelClass: this.ctx.widgetNamespace, + forceDismiss: true + })); + } + } diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index adfcd079b9..d636945ffb 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -95,6 +95,8 @@ import { DialogService } from '@core/services/dialog.service'; import { CustomDialogService } from '@home/components/widget/dialog/custom-dialog.service'; import { DatePipe } from '@angular/common'; import { AttributeService } from '@core/http/attribute.service'; +import { TranslateService } from '@ngx-translate/core'; +import { HttpClient } from '@angular/common/http'; const ServicesMap = new Map>(); ServicesMap.set('deviceService', DeviceService); @@ -104,6 +106,8 @@ ServicesMap.set('dialogs', DialogService); ServicesMap.set('customDialog', CustomDialogService); ServicesMap.set('date', DatePipe); ServicesMap.set('utils', UtilsService); +ServicesMap.set('translate', TranslateService); +ServicesMap.set('http', HttpClient); @Component({ selector: 'tb-widget', @@ -390,10 +394,10 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI } private loadFromWidgetInfo() { - const widgetNamespace = `widget-type-${(this.widget.isSystemType ? 'sys-' : '')}${this.widget.bundleAlias}-${this.widget.typeAlias}`; + this.widgetContext.widgetNamespace = `widget-type-${(this.widget.isSystemType ? 'sys-' : '')}${this.widget.bundleAlias}-${this.widget.typeAlias}`; const elem = this.elementRef.nativeElement; elem.classList.add('tb-widget'); - elem.classList.add(widgetNamespace); + elem.classList.add(this.widgetContext.widgetNamespace); this.widgetType = this.widgetInfo.widgetTypeFunction; this.typeParameters = this.widgetInfo.typeParameters; diff --git a/ui-ngx/src/app/modules/home/models/widget-component.models.ts b/ui-ngx/src/app/modules/home/models/widget-component.models.ts index e4f307f4ab..0460792ae8 100644 --- a/ui-ngx/src/app/modules/home/models/widget-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/widget-component.models.ts @@ -161,6 +161,7 @@ export class WidgetContext { isEdit: boolean; isMobile: boolean; + widgetNamespace?: string; subscriptionApi?: WidgetSubscriptionApi; actionsApi?: WidgetActionsApi; diff --git a/ui-ngx/src/app/shared/components/snack-bar-component.html b/ui-ngx/src/app/shared/components/snack-bar-component.html index 4dabc33d75..dd001db296 100644 --- a/ui-ngx/src/app/shared/components/snack-bar-component.html +++ b/ui-ngx/src/app/shared/components/snack-bar-component.html @@ -22,5 +22,5 @@ 'info-toast': notification.type === 'info' }">
- + diff --git a/ui-ngx/src/app/shared/components/toast.directive.ts b/ui-ngx/src/app/shared/components/toast.directive.ts index b9c2198f11..3d62912b17 100644 --- a/ui-ngx/src/app/shared/components/toast.directive.ts +++ b/ui-ngx/src/app/shared/components/toast.directive.ts @@ -15,12 +15,12 @@ /// import { - AfterViewInit, + AfterViewInit, ApplicationRef, ChangeDetectorRef, Component, Directive, ElementRef, Inject, Input, NgZone, - OnDestroy, + OnDestroy, ViewChild, ViewContainerRef } from '@angular/core'; import { @@ -35,6 +35,8 @@ import { Subscription } from 'rxjs'; import { NotificationService } from '@app/core/services/notification.service'; import { BreakpointObserver } from '@angular/cdk/layout'; import { MediaBreakpoints } from '@shared/models/constants'; +import Timeout = NodeJS.Timeout; +import { MatButton } from '@angular/material/button'; @Directive({ selector: '[tb-toast]' @@ -50,6 +52,8 @@ export class ToastDirective implements AfterViewInit, OnDestroy { private snackBarRef: MatSnackBarRef = null; private currentMessage: NotificationMessage = null; + private dismissTimeout: Timeout = null; + constructor(public elementRef: ElementRef, public viewContainerRef: ViewContainerRef, private notificationService: NotificationService, @@ -73,6 +77,7 @@ export class ToastDirective implements AfterViewInit, OnDestroy { verticalPosition: !isGtSm ? 'bottom' : (notificationMessage.verticalPosition || 'top'), viewContainerRef: this.viewContainerRef, duration: notificationMessage.duration, + panelClass: notificationMessage.panelClass, data }; this.ngZone.run(() => { @@ -80,7 +85,23 @@ export class ToastDirective implements AfterViewInit, OnDestroy { this.snackBarRef.dismiss(); } this.snackBarRef = this.snackBar.openFromComponent(TbSnackBarComponent, config); + if (notificationMessage.duration && notificationMessage.duration > 0 && notificationMessage.forceDismiss) { + if (this.dismissTimeout !== null) { + clearTimeout(this.dismissTimeout); + this.dismissTimeout = null; + } + this.dismissTimeout = setTimeout(() => { + if (this.snackBarRef) { + this.snackBarRef.instance.actionButton._elementRef.nativeElement.click(); + } + this.dismissTimeout = null; + }, notificationMessage.duration); + } this.snackBarRef.afterDismissed().subscribe(() => { + if (this.dismissTimeout !== null) { + clearTimeout(this.dismissTimeout); + this.dismissTimeout = null; + } this.snackBarRef = null; this.currentMessage = null; }); @@ -134,11 +155,15 @@ export class ToastDirective implements AfterViewInit, OnDestroy { styleUrls: ['snack-bar-component.scss'] }) export class TbSnackBarComponent implements AfterViewInit, OnDestroy { + + @ViewChild('actionButton', {static: true}) actionButton: MatButton; + private parentEl: HTMLElement; - private snackBarContainerEl: HTMLElement; + public snackBarContainerEl: HTMLElement; private parentScrollSubscription: Subscription = null; public notification: NotificationMessage; constructor(@Inject(MAT_SNACK_BAR_DATA) public data: any, private elementRef: ElementRef, + public cd: ChangeDetectorRef, public snackBarRef: MatSnackBarRef) { this.notification = data.notification; } diff --git a/ui-ngx/src/app/shared/pipe/keyboard-shortcut.pipe.ts b/ui-ngx/src/app/shared/pipe/keyboard-shortcut.pipe.ts index 0c6402aeb5..a88f3b5dce 100644 --- a/ui-ngx/src/app/shared/pipe/keyboard-shortcut.pipe.ts +++ b/ui-ngx/src/app/shared/pipe/keyboard-shortcut.pipe.ts @@ -44,7 +44,6 @@ export class KeyboardShortcutPipe implements PipeTransform { const last = index === keys.length - 1; return last ? key : abbreviations[key]; }).join(seperator); - return (!value) ? '' : value.replace(/ /g, ''); } } diff --git a/ui-ngx/src/assets/locale/locale.constant-de_DE.json b/ui-ngx/src/assets/locale/locale.constant-de_DE.json index f7048368b4..3c7c57b1c3 100644 --- a/ui-ngx/src/assets/locale/locale.constant-de_DE.json +++ b/ui-ngx/src/assets/locale/locale.constant-de_DE.json @@ -1607,6 +1607,31 @@ "Step size": "Schrittlänge", "Ok": "Ok" } + }, + "input-widgets": { + "attribute-not-allowed": "Attributparameter können in diesem Widget nicht verwendet werden", + "date": "Datum", + "discard-changes": "Änderungen verwerfen", + "entity-attribute-required": "Entitätsattribut ist erforderlich", + "entity-timeseries-required": "Zeitreihen für Entitäten sind erforderlich", + "not-allowed-entity": "Die ausgewählte Entität kann keine gemeinsamen Attribute haben", + "no-attribute-selected": "Es ist kein Attribut ausgewählt", + "no-datakey-selected": "Es ist kein Datenschlüssel ausgewählt", + "no-entity-selected": "Keine Entität ausgewählt", + "no-image": "Kein Bild", + "no-support-web-camera": "Keine unterstützte Webcam", + "no-timeseries-selected": "Keine Zeitreihen ausgewählt", + "switch-attribute-value": "Entitätsattributwert wechseln", + "switch-camera": "Kamera wechseln", + "switch-timeseries-value": "Wert für Zeitreihen von Entitäten wechseln", + "take-photo": "Foto machen", + "time": "Zeit", + "timeseries-not-allowed": "Der Timeseries-Parameter kann in diesem Widget nicht verwendet werden", + "update-failed": "Aktualisierung fehlgeschlagen", + "update-successful": "Aktualisierung erfolgreich", + "update-attribute": "Attribut aktualisieren", + "update-timeseries": "Zeitreihen aktualisieren", + "value": "Wert" } }, "icon": { @@ -1641,7 +1666,7 @@ "tr_TR": "Türkisch", "fa_IR": "Persisch", "uk_UA": "Ukrainisch", - "cs_CZ": "Tschechisch" + "cs_CZ": "Tschechisch" } } } 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 d806f61f42..b9cffa96a6 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1728,6 +1728,46 @@ "Step size": "Step size", "Ok": "Ok" } + }, + "input-widgets": { + "attribute-not-allowed": "Attribute parameter cannot be used in this widget", + "blocked-location": "Geolocation is blocked in your browser", + "claim-device": "Claim device", + "claim-failed": "Failed to claim the device!", + "claim-not-found": "Device not found!", + "claim-successful": "Device was successfully claimed!", + "date": "Date", + "device-name": "Device name", + "device-name-required": "Device name is required", + "discard-changes": "Discard changes", + "entity-attribute-required": "Entity attribute is required", + "entity-coordinate-required": "Both fields, latitude and longitude, are required", + "entity-timeseries-required": "Entity timeseries is required", + "get-location": "Get current location", + "latitude": "Latitude", + "longitude": "Longitude", + "not-allowed-entity": "Selected entity cannot have shared attributes", + "no-attribute-selected": "No attribute is selected", + "no-datakey-selected": "No datakey is selected", + "no-coordinate-specified": "Datakey for latitude/longitude doesn't specified", + "no-entity-selected": "No entity selected", + "no-image": "No image", + "no-support-geolocation": "Your browser doesn't support geolocation", + "no-support-web-camera": "No supported web camera", + "no-timeseries-selected": "No timeseries selected", + "secret-key": "Secret key", + "secret-key-required": "Secret key is required", + "switch-attribute-value": "Switch entity attribute value", + "switch-camera": "Switch camera", + "switch-timeseries-value": "Switch entity timeseries value", + "take-photo": "Take photo", + "time": "Time", + "timeseries-not-allowed": "Timeseries parameter cannot be used in this widget", + "update-failed": "Update failed", + "update-successful": "Update successful", + "update-attribute": "Update attribute", + "update-timeseries": "Update timeseries", + "value": "Value" } }, "icon": { diff --git a/ui-ngx/src/assets/locale/locale.constant-es_ES.json b/ui-ngx/src/assets/locale/locale.constant-es_ES.json index 2465365563..cc52b202b5 100644 --- a/ui-ngx/src/assets/locale/locale.constant-es_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-es_ES.json @@ -1680,6 +1680,31 @@ "Step size": "Numero de pie", "Ok": "De acuerdo" } + }, + "input-widgets": { + "attribute-not-allowed": "El parámetro de atributo no se puede usar en este widget", + "date": "Fecha", + "discard-changes": "Descartar los cambios", + "entity-attribute-required": "Se requiere atributo de entidad", + "entity-timeseries-required": "Se requiere la serie de tiempo de la entidad", + "not-allowed-entity": "La entidad seleccionada no puede tener atributos compartidos", + "no-attribute-selected": "No se seleccionó ningún atributo", + "no-datakey-selected": "No se seleccionó ninguna clave de datos", + "no-entity-selected": "Ninguna entidad seleccionada", + "no-image": "Sin imágen", + "no-support-web-camera": "No hay cámara web compatible", + "no-timeseries-selected": "No hay series de tiempo seleccionadas", + "switch-attribute-value": "Cambiar el valor del atributo de entidad", + "switch-camera": "Cambiar de cámara", + "switch-timeseries-value": "Cambiar el valor de la serie de tiempo de la entidad", + "take-photo": "Tomar foto", + "time": "Tiempo", + "timeseries-not-allowed": "El parámetro Timeseries no se puede usar en este widget", + "update-failed": "Actualización fallida", + "update-successful": "Actualización exitosa", + "update-attribute": "Actualizar atributo", + "update-timeseries": "Actualizar series de tiempo", + "value": "Valor" } }, "icon": { diff --git a/ui-ngx/src/assets/locale/locale.constant-fr_FR.json b/ui-ngx/src/assets/locale/locale.constant-fr_FR.json index 9603442080..9b935b44eb 100644 --- a/ui-ngx/src/assets/locale/locale.constant-fr_FR.json +++ b/ui-ngx/src/assets/locale/locale.constant-fr_FR.json @@ -1018,7 +1018,7 @@ "tr_TR": "Turc", "fa_IR": "Persane", "uk_UA": "Ukrainien", - "cs_CZ": "Tchèque" + "cs_CZ": "Tchèque" } }, "layout": { @@ -1501,6 +1501,31 @@ "Step size": "Taille de pas", "Ok": "Ok" } + }, + "input-widgets": { + "attribute-not-allowed": "Le paramètre d'attribut ne peut pas être utilisé dans ce widget", + "date": "Date", + "discard-changes": "Annuler les modifications", + "entity-attribute-required": "L'attribut d'entité est requis", + "entity-timeseries-required": "Entité timeseries est requis", + "not-allowed-entity": "L'entité sélectionnée ne peut pas avoir d'attributs partagés", + "no-attribute-selected": "Aucun attribut n'est sélectionné", + "no-datakey-selected": "Aucune date n'est sélectionnée", + "no-entity-selected": "Aucune entité sélectionnée", + "no-image": "Pas d'image", + "no-support-web-camera": "Pas de webcam supportée", + "no-timeseries-selected": "Aucune série temporelle sélectionnée", + "switch-attribute-value": "Changer la valeur de l'attribut d'entité", + "switch-camera": "Changer de caméra", + "switch-timeseries-value": "Changer la valeur de l'entité série temporelle", + "take-photo": "Prendre une photo", + "time": "Temps", + "timeseries-not-allowed": "Le paramètre série temporelle ne peut pas être utilisé dans ce widget", + "update-failed": "Mise à jour a échoué", + "update-successful": "Mise à jour réussie", + "update-attribute": "Attribut de mise à jour", + "update-timeseries": "Mise à jour de la série temporelle", + "value": "Valeur" } }, "widgets-bundle": { diff --git a/ui-ngx/src/assets/locale/locale.constant-it_IT.json b/ui-ngx/src/assets/locale/locale.constant-it_IT.json index 2f36ba5f52..e9c670586b 100644 --- a/ui-ngx/src/assets/locale/locale.constant-it_IT.json +++ b/ui-ngx/src/assets/locale/locale.constant-it_IT.json @@ -1615,6 +1615,31 @@ "Step size": "Dimensione del passo", "Ok": "Ok" } + }, + "input-widgets": { + "attribute-not-allowed": "Questo widget non può usare un parametro di tipo attributo", + "date": "Data", + "discard-changes": "Annulla modifiche", + "entity-attribute-required": "E' richiesta un'entità di tipo attributo", + "entity-timeseries-required": "E' richiesta un'entità di tipo serie temporale", + "not-allowed-entity": "L'entità selezionata non può avere attributi condivisi", + "no-attribute-selected": "Nessun attributo selezionato", + "no-datakey-selected": "Nessuna datakey selezionata", + "no-entity-selected": "Nessuna entità selezionata", + "no-image": "Nessuna immagine", + "no-support-web-camera": "Web camera non supportata", + "no-timeseries-selected": "Nessuna serie temporale selezionata", + "switch-attribute-value": "Cambia il valore dell'attributo", + "switch-camera": "Cambia camera", + "switch-timeseries-value": "Cambia il valore della serie temporale", + "take-photo": "Fai una foto", + "time": "Tempo", + "timeseries-not-allowed": "Questo widget non può usare un parametro di tipo serie temporale", + "update-failed": "Aggiornamento fallito", + "update-successful": "Aggiornamento eseguito con successo", + "update-attribute": "Aggiorna attributo", + "update-timeseries": "Aggiorna serie temporale", + "value": "Valore" } }, "icon": { @@ -1649,7 +1674,7 @@ "tr_TR": "Turco", "fa_IR": "Persiana", "uk_UA": "Ucraino", - "cs_CZ": "Ceco" + "cs_CZ": "Ceco" } } } diff --git a/ui-ngx/src/assets/locale/locale.constant-ru_RU.json b/ui-ngx/src/assets/locale/locale.constant-ru_RU.json index ae69c79681..0ba4023be2 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ru_RU.json +++ b/ui-ngx/src/assets/locale/locale.constant-ru_RU.json @@ -1611,6 +1611,46 @@ "Step size": "Размер шага", "Ok": "Ok" } + }, + "input-widgets": { + "attribute-not-allowed": "Атрибут не может быть выбран в этом виджете", + "date": "Дата", + "blocked-location": "Геолокация заблокирована в вашем браузере", + "claim-device": "Подтвердить устройство", + "claim-failed": "Не удалось подтвердить устройство!", + "claim-not-found": "Устройство не найдено!", + "claim-successful": "Устройство успешно подтверждено!", + "discard-changes": "Отменить изменения", + "device-name": "Название устройства", + "device-name-required": "Необходимо указать название устройства", + "entity-attribute-required": "Значение атрибута обязателено", + "entity-coordinate-required": "Необходимо указать широту и долготу", + "entity-timeseries-required": "Значение телеметрии обязательно", + "get-location": "Получить текущее местоположение", + "latitude": "Широта", + "longitude": "Долгота", + "not-allowed-entity": "Выбраный объект не имеет общих атрибутов", + "no-attribute-selected": "Атрибут не выбран", + "no-datakey-selected": "Ни один datakey не выбран", + "no-entity-selected": "Объект не выбран", + "no-coordinate-specified": "Ключ для широты/долготы не указан", + "no-support-geolocation": "Ваш браузер не поддерживает геолокацию", + "no-image": "Нет изображения", + "no-support-web-camera": "Нет поддерживаемой веб-камеры", + "no-timeseries-selected": "Параметр телеметрии не выбран", + "secret-key": "Секретный ключ", + "secret-key-required": "Необходимо указать секретный ключ", + "switch-attribute-value": "Изменить значение атрибута", + "switch-camera": "Изменить камеру", + "switch-timeseries-value": "Изменить значение телеметрии", + "take-photo": "Сделать фото", + "time": "Время", + "timeseries-not-allowed": "Телеметрия не может быть выбрана в этом виджете", + "update-failed": "Не удалось обновить", + "update-successful": "Успешно обновлено", + "update-attribute": "Обновить атрибут", + "update-timeseries": "Обновить телеметрию", + "value": "Значение" } }, "icon": { diff --git a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json index 082f8a9b41..cd9ad87ba9 100644 --- a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json +++ b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json @@ -1,7 +1,7 @@ { "access": { "unauthorized": "Неавторизований", - "unauthorized-access": "Неавторизований доступ", + "unauthorized-access": "Неавторизований доступ", "unauthorized-access-text": "Щоб отримати доступ до цього ресурсу, потрібно ввійти в систему!", "access-forbidden": "Доступ заборонено", "access-forbidden-text": "Недостатньо прав для доступу!
Спробуйте увійти як інший користувач, якщо ви все ще хочете отримати доступ до цього ресурсу.", @@ -246,7 +246,7 @@ "assign-assets": "Надати активи", "assign-assets-text": "Надати { count, plural, 1 {1 актив} other {# активи} } клієнту", "delete-assets": "Видалити активи", - "unassign-assets": "Позбавити активів", + "unassign-assets": "Позбавити активів", "unassign-assets-action-title": "Позбавити { count, plural, 1 {1 актив} other {# активи} } клієнта", "assign-new-asset": "Надати новий актив", "delete-asset-title": "Ви впевнені, що хочете видалити актив '{{assetName}}'?", @@ -2123,6 +2123,105 @@ "widget-type-file": "Файл типу віджета", "invalid-widget-type-file-error": "Неможливо імпортувати тип віджету: неправильна структура даних типу віджета." }, + "widgets": { + "date-range-navigator": { + "localizationMap": { + "Sun": "Нд", + "Mon": "Пн", + "Tue": "Вт", + "Wed": "Ср", + "Thu": "Чт", + "Fri": "Пт", + "Sat": "Сб", + "Jan": "Січ.", + "Feb": "Лют.", + "Mar": "Берез.", + "Apr": "Квіт.", + "May": "Трав.", + "Jun": "Черв.", + "Jul": "Лип.", + "Aug": "Серп.", + "Sep": "Верес.", + "Oct": "Жовт.", + "Nov": "Листоп.", + "Dec": "Груд.", + "January": "Січень", + "February": "Лютий", + "March": "Березень", + "April": "Квітень", + "June": "Червень", + "July": "Липень", + "August": "Серпень", + "September": "Вересень", + "October": "Жовтень", + "November": "Листопад", + "December": "Грудень", + "Custom Date Range": "Користувацький діапазон дат", + "Date Range Template": "Шаблон діапазону дат", + "Today": "Сьогодні", + "Yesterday": "Вчора", + "This Week": "Цього тижня", + "Last Week": "Минулий тиждень", + "This Month": "Цей місяць", + "Last Month": "Минулий місяць", + "Year": "Рік", + "This Year": "Цього року", + "Last Year": "Минулий рік", + "Date picker": "Вибір дати", + "Hour": "Година", + "Day": "День", + "Week": "Тиждень", + "2 weeks": "2 Тижні", + "Month": "Місяць", + "3 months": "3 Місяці", + "6 months": "6 Місяців", + "Custom interval": "Користувацький інтервал", + "Interval": "Інтервал", + "Step size": "Розмір кроку", + "Ok": "Ok" + } + }, + "input-widgets": { + "attribute-not-allowed": "Атрибут не може бути вибраний в цьому віджеті", + "date": "Дата", + "blocked-location": "Геолокація заблокована у вашому браузері", + "claim-device": "Підтвердити пристрій", + "claim-failed": "Не вдалося підтвердити пристрій!", + "claim-not-found": "Пристрій не знайдено!", + "claim-successful": "Пристрій успішно підтверджено!", + "discard-changes": "Скасувати зміни", + "device-name": "Назва пристрою", + "device-name-required": "Необхідно вказати назву пристрою", + "entity-attribute-required": "Значення атрибута обов'язкове", + "entity-coordinate-required": "Необхідно вказати широту та довготу", + "entity-timeseries-required": "Значення телеметрії обов'язкове", + "get-location": "Отримати поточне місцезнаходження", + "latitude": "Широта", + "longitude": "Довгота", + "not-allowed-entity": "Обрана сутність не має спільних атрибутів", + "no-attribute-selected": "Атрибут не вибрано", + "no-datakey-selected": "Ні один datakey не обраний", + "no-entity-selected": "Сутність не вибрано", + "no-coordinate-specified": "Ключ для широти/довготи не вказаний", + "no-support-geolocation": "Ваш браузер не підтримує геолокацію", + "no-image": "Немає зображення", + "no-support-web-camera": "Нет поддерживаемой веб-камеры", + "no-timeseries-selected": "Параметр телеметрії не вибрано", + "secret-key": "Секретний ключ", + "secret-key-required": "Необхідно вказати секретний ключ", + "switch-attribute-value": "Змінити значення атрибута", + "switch-camera": "Змінити камеру", + "switch-timeseries-value": "Змінити значення телеметрії", + "take-photo": "Зробити фото", + "time": "Час", + "timeseries-not-allowed": "Телеметрія не може бути вибрана в цьому віджеті", + "update-failed": "Не вдалося оновити", + "update-successful": "Успішно оновлено", + "update-attribute": "Оновити атрибут", + "update-timeseries": "Оновити телеметрію", + "value": "Значення" + } + }, "white-labeling": { "white-labeling": "Білий маркування", "login-white-labeling": "Login White Labeling",