diff --git a/modules/bindings/src/lib/common/controls/select-controller/binding-control-select-controller.component.html b/modules/bindings/src/lib/common/controls/select-controller/binding-control-select-controller.component.html index dfec57e8..f1ff74ce 100644 --- a/modules/bindings/src/lib/common/controls/select-controller/binding-control-select-controller.component.html +++ b/modules/bindings/src/lib/common/controls/select-controller/binding-control-select-controller.component.html @@ -7,7 +7,6 @@ @if (syntheticInputControl) { @@ -16,7 +15,6 @@ @if (areSettingsVisible) { } @if (isControllerAssigned) { } @else { } diff --git a/modules/pages/control-scheme-view/src/lib/bindings-section/hub-port-binding-list-item/hub-port-binding-list-item.component.html b/modules/pages/control-scheme-view/src/lib/bindings-section/hub-port-binding-list-item/hub-port-binding-list-item.component.html index 80510641..af5a65e7 100644 --- a/modules/pages/control-scheme-view/src/lib/bindings-section/hub-port-binding-list-item/hub-port-binding-list-item.component.html +++ b/modules/pages/control-scheme-view/src/lib/bindings-section/hub-port-binding-list-item/hub-port-binding-list-item.component.html @@ -6,6 +6,10 @@ + + {{ hubName() }}, + {{ 'hub.port' | transloco: { portId: unwrappedBinding.portId | portIdToPortName } }}, + {{ unwrappedBinding.bindingType | bindingTypeToL10nKey | transloco }} diff --git a/modules/pages/control-scheme-view/src/lib/bindings-section/hub-port-binding-list-item/hub-port-binding-list-item.component.ts b/modules/pages/control-scheme-view/src/lib/bindings-section/hub-port-binding-list-item/hub-port-binding-list-item.component.ts index 2645c169..9976ccb7 100644 --- a/modules/pages/control-scheme-view/src/lib/bindings-section/hub-port-binding-list-item/hub-port-binding-list-item.component.ts +++ b/modules/pages/control-scheme-view/src/lib/bindings-section/hub-port-binding-list-item/hub-port-binding-list-item.component.ts @@ -4,9 +4,11 @@ import { MatError } from '@angular/material/form-field'; import { TranslocoPipe } from '@ngneat/transloco'; import { Observable } from 'rxjs'; import { RouterLink } from '@angular/router'; -import { ControlSchemeBinding } from '@app/store'; +import { Store } from '@ngrx/store'; +import { ControlSchemeBinding, HUBS_SELECTORS } from '@app/store'; import { BindingControllerInputNamePipe, BindingTypeToL10nKeyPipe } from '@app/shared-control-schemes'; import { RoutesBuilderService, ScreenSizeObserverService } from '@app/shared-misc'; +import { PortIdToPortNamePipe } from '@app/shared-components'; import { BindingActionListItemComponent } from '../binding-action-list-item'; @@ -22,7 +24,8 @@ import { BindingActionListItemComponent } from '../binding-action-list-item'; MatError, TranslocoPipe, RouterLink, - BindingActionListItemComponent + BindingActionListItemComponent, + PortIdToPortNamePipe ], changeDetection: ChangeDetectionStrategy.OnPush }) @@ -44,13 +47,22 @@ export class HubPortBindingListItemComponent { return Object.keys(binding.inputs) as (keyof ControlSchemeBinding['inputs'])[]; }); + public readonly hubName = computed(() => { + const binding = this._binding(); + if (binding === null) { + return ''; + } + return this.store.selectSignal(HUBS_SELECTORS.selectHubName(binding.hubId))(); + }); + private _binding: WritableSignal = signal(null); private _controlSchemeName: WritableSignal = signal(null); constructor( private readonly screenSizeObserverService: ScreenSizeObserverService, - private readonly routesBuilderService: RoutesBuilderService + private readonly routesBuilderService: RoutesBuilderService, + private readonly store: Store ) { } diff --git a/modules/pages/control-scheme-view/src/lib/widgets/reorder-widgets-dialog/reorder-widget-dialog.component.html b/modules/pages/control-scheme-view/src/lib/widgets/reorder-widgets-dialog/reorder-widget-dialog.component.html index 9a265bee..200c224f 100644 --- a/modules/pages/control-scheme-view/src/lib/widgets/reorder-widgets-dialog/reorder-widget-dialog.component.html +++ b/modules/pages/control-scheme-view/src/lib/widgets/reorder-widgets-dialog/reorder-widget-dialog.component.html @@ -19,7 +19,7 @@

[inline]="true" > - {{ 'controlScheme.widgets.moveWidgetUp' | transloco }} + {{ 'controlScheme.widgets.moveWidgetUp' | transloco }} {{ widget.title }}
diff --git a/modules/shared/misc/src/lib/screen-size-observer.service.ts b/modules/shared/misc/src/lib/screen-size-observer.service.ts index 5b52ddc9..f40abf4b 100644 --- a/modules/shared/misc/src/lib/screen-size-observer.service.ts +++ b/modules/shared/misc/src/lib/screen-size-observer.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; -import { distinctUntilChanged, map, startWith } from 'rxjs'; +import { distinctUntilChanged, map, shareReplay, startWith } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class ScreenSizeObserverService { @@ -13,7 +13,8 @@ export class ScreenSizeObserverService { Breakpoints.Small, Breakpoints.XSmall ])), - distinctUntilChanged() + distinctUntilChanged(), + shareReplay(1) ); constructor( diff --git a/modules/store/src/lib/effects/control-scheme/index.ts b/modules/store/src/lib/effects/control-scheme/index.ts index 9d79259a..b2484186 100644 --- a/modules/store/src/lib/effects/control-scheme/index.ts +++ b/modules/store/src/lib/effects/control-scheme/index.ts @@ -8,6 +8,8 @@ import { CONSUME_QUEUE_EFFECT } from './consume-queue.effect'; import { EXECUTE_TASK_EFFECT } from './execute-task.effect'; import { NOTIFY_ON_CONTROL_SCHEME_IMPORTED_EFFECT } from './notify-on-control-scheme-imported.effect'; import { NOTIFY_ON_CONTROL_SCHEME_START_FAILURE_EFFECT } from './notify-on-control-scheme-start-failure.effect'; +import { NOTIFY_ON_CONTROL_SCHEME_STARTED_EFFECT } from './notify-on-control-scheme-started.effect'; +import { NOTIFY_ON_CONTROL_SCHEME_STOPPED_EFFECT } from './notify-on-control-scheme-stopped.effect'; export * from './i-task-filter'; export * from './i-task-runner'; @@ -24,4 +26,6 @@ export const CONTROL_SCHEME_EFFECTS: {[name in string]: FunctionalEffect} = { executeTask: EXECUTE_TASK_EFFECT, notifyOnControlSchemeImported: NOTIFY_ON_CONTROL_SCHEME_IMPORTED_EFFECT, notifyOnControlSchemeStartFailure: NOTIFY_ON_CONTROL_SCHEME_START_FAILURE_EFFECT, + notifyOnControlSchemeStarted: NOTIFY_ON_CONTROL_SCHEME_STARTED_EFFECT, + notifyOnControlSchemeStopped: NOTIFY_ON_CONTROL_SCHEME_STOPPED_EFFECT, } as const; diff --git a/modules/store/src/lib/effects/control-scheme/notify-on-control-scheme-started.effect.ts b/modules/store/src/lib/effects/control-scheme/notify-on-control-scheme-started.effect.ts new file mode 100644 index 00000000..6a3596c0 --- /dev/null +++ b/modules/store/src/lib/effects/control-scheme/notify-on-control-scheme-started.effect.ts @@ -0,0 +1,19 @@ +import { Actions, createEffect, ofType } from '@ngrx/effects'; +import { inject } from '@angular/core'; +import { map } from 'rxjs'; + +import { CONTROL_SCHEME_ACTIONS, SHOW_NOTIFICATION_ACTIONS } from '../../actions'; + +export const NOTIFY_ON_CONTROL_SCHEME_STARTED_EFFECT = createEffect(( + actions: Actions = inject(Actions), +) => { + return actions.pipe( + ofType(CONTROL_SCHEME_ACTIONS.schemeStarted), + map((action) => { + return SHOW_NOTIFICATION_ACTIONS.info({ + l10nKey: 'controlScheme.runSuccessNotification', + l10nPayload: action + }); + }) + ); +}, { functional: true }); diff --git a/modules/store/src/lib/effects/control-scheme/notify-on-control-scheme-stopped.effect.ts b/modules/store/src/lib/effects/control-scheme/notify-on-control-scheme-stopped.effect.ts new file mode 100644 index 00000000..b9c84056 --- /dev/null +++ b/modules/store/src/lib/effects/control-scheme/notify-on-control-scheme-stopped.effect.ts @@ -0,0 +1,16 @@ +import { Actions, createEffect, ofType } from '@ngrx/effects'; +import { inject } from '@angular/core'; +import { map } from 'rxjs'; + +import { CONTROL_SCHEME_ACTIONS, SHOW_NOTIFICATION_ACTIONS } from '../../actions'; + +export const NOTIFY_ON_CONTROL_SCHEME_STOPPED_EFFECT = createEffect(( + actions: Actions = inject(Actions), +) => { + return actions.pipe( + ofType(CONTROL_SCHEME_ACTIONS.schemeStopped), + map(() => { + return SHOW_NOTIFICATION_ACTIONS.info({ l10nKey: 'controlScheme.stopNotification'}); + }) + ); +}, { functional: true }); diff --git a/src/app/nav-menu/full-nav-menu/full-nav-menu.component.html b/src/app/nav-menu/full-nav-menu/full-nav-menu.component.html index b887bdd8..04c8ccf4 100644 --- a/src/app/nav-menu/full-nav-menu/full-nav-menu.component.html +++ b/src/app/nav-menu/full-nav-menu/full-nav-menu.component.html @@ -4,6 +4,7 @@

{{ 'appName' | transloco }} diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index d858ebd6..b58f58c1 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -50,7 +50,7 @@ "controllersList": "Controllers", "hubsList": "Hubs", "controlSchemesList": "Control schemes", - "navMenuAriaLabel": "Menu", + "navMenuAriaLabel": "App menu", "aboutPageButton": "About", "settingsPageButton": "Settings", "help": "Help" @@ -188,6 +188,8 @@ "editNameSaveButtonTitle": "Save", "editNameCancelButtonTitle": "Cancel", "run": "Start", + "runSuccessNotification": "Control scheme ''{ name }'' started", + "stopNotification": "Control scheme stopped", "runFailed": "Failed to start", "runFailedCalibrationOutOfRange": "Failed to start due to servo calibration failure: range is out of bounds", "runBlockerSchemeDoesNotExist": "Control scheme does not exist", diff --git a/src/assets/i18n/ru.json b/src/assets/i18n/ru.json index 427489ce..38c27a4b 100644 --- a/src/assets/i18n/ru.json +++ b/src/assets/i18n/ru.json @@ -50,7 +50,7 @@ "controllersList": "Контроллеры", "hubsList": "Хабы", "controlSchemesList": "Схемы управления", - "navMenuAriaLabel": "Меню", + "navMenuAriaLabel": "Меню приложения", "aboutPageButton": "О программе", "settingsPageButton": "Настройки", "help": "Помощь" @@ -188,6 +188,8 @@ "editNameSaveButtonTitle": "Сохранить", "editNameCancelButtonTitle": "Отмена", "run": "Старт", + "runSuccessNotification": "Схема управления ''{ name }'' запущена", + "stopNotification": "Схема управления остановлена", "runFailed": "Не удалось запустить схему управления", "runFailedCalibrationOutOfRange": "Не удалось запустить схему управления из-за ошибки калибровки: диапазон больше допустимого", "runBlockerSchemeDoesNotExist": "Схема управления не существует",