refactoring

This commit is contained in:
mpetrov 2024-11-13 14:50:23 +02:00
parent 2933071a0f
commit 0a8e526d08
14 changed files with 87 additions and 107 deletions

View File

@ -19,12 +19,12 @@
class="tb-rounded-btn flex-1 w-36" class="tb-rounded-btn flex-1 w-36"
color="primary" color="primary"
#matButton #matButton
[class.active]="(isDebugAllActive() || debugFailures) && !disabled" [class.active]="((isDebugAllActive$ | async) || debugFailures) && !disabled"
[disabled]="disabled" [disabled]="disabled"
(click)="openDebugStrategyPanel($event, matButton)"> (click)="openDebugStrategyPanel($event, matButton)">
<mat-icon [color]="disabled ? 'inherit' : 'primary'">bug_report</mat-icon> <mat-icon [color]="disabled ? 'inherit' : 'primary'">bug_report</mat-icon>
<span *ngIf="!debugFailures && !isDebugAllActive()" translate>common.disabled</span> <span *ngIf="!debugFailures && !(isDebugAllActive$ | async)" translate>common.disabled</span>
<span *ngIf="isDebugAllActive() && debugFailures" translate>debug-config.all</span> <span *ngIf="(isDebugAllActive$ | async) && debugFailures" translate>debug-config.all</span>
<span *ngIf="isDebugAllActive() && !debugFailures">{{ debugAllUntil | debugDurationLeft }}</span> <span *ngIf="(isDebugAllActive$ | async) && !debugFailures">{{ debugAllUntil | durationLeft }}</span>
<span *ngIf="!isDebugAllActive() && debugFailures" translate>debug-config.failures</span> <span *ngIf="!(isDebugAllActive$ | async) && debugFailures" translate>debug-config.failures</span>
</button> </button>

View File

@ -21,22 +21,20 @@ import {
ViewContainerRef, ViewContainerRef,
DestroyRef, DestroyRef,
ChangeDetectionStrategy, ChangeDetectionStrategy,
ChangeDetectorRef,
EventEmitter, EventEmitter,
Output Output
} from '@angular/core'; } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { SharedModule } from '@shared/shared.module'; import { SharedModule } from '@shared/shared.module';
import { DebugDurationLeftPipe } from '@home/pages/rulechain/debug-duration-left.pipe'; import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { TbPopoverService } from '@shared/components/popover.service'; import { TbPopoverService } from '@shared/components/popover.service';
import { MatButton } from '@angular/material/button'; import { MatButton } from '@angular/material/button';
import { DebugConfigPanelComponent } from '@home/pages/rulechain/debug-config-panel.component'; import { DebugConfigPanelComponent } from './debug-config-panel.component';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { interval } from 'rxjs'; import { timer } from 'rxjs';
import { SECOND } from '@shared/models/time/time.models'; import { SECOND } from '@shared/models/time/time.models';
import { RuleNodeDebugConfig } from '@shared/models/rule-node.models'; import { HasDebugConfig } from '@shared/models/entity.models';
import { map } from 'rxjs/operators';
@Component({ @Component({
selector: 'tb-debug-config-button', selector: 'tb-debug-config-button',
@ -45,7 +43,7 @@ import { RuleNodeDebugConfig } from '@shared/models/rule-node.models';
imports: [ imports: [
CommonModule, CommonModule,
SharedModule, SharedModule,
DebugDurationLeftPipe, DurationLeftPipe,
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
@ -55,20 +53,18 @@ export class DebugConfigButtonComponent {
@Input() debugAll = false; @Input() debugAll = false;
@Input() debugAllUntil = 0; @Input() debugAllUntil = 0;
@Input() disabled = false; @Input() disabled = false;
@Input() maxRuleNodeDebugDurationMinutes: number;
@Input() ruleChainDebugPerTenantLimitsConfiguration: string;
@Output() onDebugConfigChanged = new EventEmitter<RuleNodeDebugConfig>() @Output() onDebugConfigChanged = new EventEmitter<HasDebugConfig>();
constructor(protected store: Store<AppState>, isDebugAllActive$ = timer(0, SECOND).pipe(map(() => this.debugAllUntil > new Date().getTime()));
private popoverService: TbPopoverService,
constructor(private popoverService: TbPopoverService,
private renderer: Renderer2, private renderer: Renderer2,
private viewContainerRef: ViewContainerRef, private viewContainerRef: ViewContainerRef,
private destroyRef: DestroyRef, private destroyRef: DestroyRef,
private cdr: ChangeDetectorRef ) {}
) {
interval(SECOND)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(() => this.cdr.markForCheck());
}
openDebugStrategyPanel($event: Event, matButton: MatButton): void { openDebugStrategyPanel($event: Event, matButton: MatButton): void {
if ($event) { if ($event) {
@ -84,19 +80,16 @@ export class DebugConfigButtonComponent {
debugFailures: this.debugFailures, debugFailures: this.debugFailures,
debugAll: this.debugAll, debugAll: this.debugAll,
debugAllUntil: this.debugAllUntil, debugAllUntil: this.debugAllUntil,
maxRuleNodeDebugDurationMinutes: this.maxRuleNodeDebugDurationMinutes,
ruleChainDebugPerTenantLimitsConfiguration: this.ruleChainDebugPerTenantLimitsConfiguration
}, },
{}, {},
{}, {}, true); {}, {}, true);
debugStrategyPopover.tbComponentRef.instance.popover = debugStrategyPopover; debugStrategyPopover.tbComponentRef.instance.popover = debugStrategyPopover;
debugStrategyPopover.tbComponentRef.instance.onConfigApplied.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((config: RuleNodeDebugConfig) => { debugStrategyPopover.tbComponentRef.instance.onConfigApplied.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((config: HasDebugConfig) => {
this.onDebugConfigChanged.emit(config); this.onDebugConfigChanged.emit(config);
this.cdr.markForCheck();
debugStrategyPopover.hide(); debugStrategyPopover.hide();
}); });
} }
} }
isDebugAllActive(): boolean {
return this.debugAllUntil > new Date().getTime();
}
} }

View File

@ -27,23 +27,18 @@
</div> </div>
<div class="flex flex-col gap-3"> <div class="flex flex-col gap-3">
<mat-slide-toggle class="mat-slide" [formControl]="onFailuresControl"> <mat-slide-toggle class="mat-slide" [formControl]="onFailuresControl">
<mat-label tb-hint-tooltip-icon="{{ 'debug-config.hint.on-failure' | translate }}"> <div tb-hint-tooltip-icon="{{ 'debug-config.hint.on-failure' | translate }}">
{{ 'debug-config.on-failure' | translate }} {{ 'debug-config.on-failure' | translate }}
</mat-label> </div>
</mat-slide-toggle> </mat-slide-toggle>
<div class="flex justify-between align-center"> <div class="flex justify-between align-center">
<mat-slide-toggle class="mat-slide" [formControl]="debugAllControl"> <mat-slide-toggle class="mat-slide" [formControl]="debugAllControl">
<mat-label tb-hint-tooltip-icon="{{ 'debug-config.hint.all-messages' | translate }}"> <div tb-hint-tooltip-icon="{{ 'debug-config.hint.all-messages' | translate }}">
{{ 'debug-config.all-messages' | translate }} {{ '( ' }} {{ 'debug-config.all-messages' | translate: { time: (isDebugAllActive$ | async) ? (debugAllUntil | durationLeft) : ('debug-config.min' | translate: { number: maxRuleNodeDebugDurationMinutes }) } }}
<span *ngIf="isDebugAllOn() else debugAllOffLabel">{{ debugAllUntil | debugDurationLeft }}</span> </div>
<ng-template #debugAllOffLabel>
{{ maxRuleNodeDebugDurationMinutes + ' ' }} {{ ('debug-config.min' | translate) }}
</ng-template>
{{ ' )' }}
</mat-label>
</mat-slide-toggle> </mat-slide-toggle>
<button mat-icon-button *ngIf="isDebugAllOn()" <button mat-icon-button *ngIf="(isDebugAllActive$ | async)"
class="tb-mat-20 p-0 mr-2" class="tb-mat-20"
matTooltip="{{ 'action.reset' | translate }}" matTooltip="{{ 'action.reset' | translate }}"
matTooltipPosition="above" matTooltipPosition="above"
color="primary" color="primary"

View File

@ -18,24 +18,21 @@ import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
ChangeDetectorRef, ChangeDetectorRef,
Component, Component,
DestroyRef,
EventEmitter, EventEmitter,
Input, Input,
OnInit OnInit
} from '@angular/core'; } from '@angular/core';
import { PageComponent } from '@shared/components/page.component'; import { PageComponent } from '@shared/components/page.component';
import { TbPopoverComponent } from '@shared/components/popover.component'; import { TbPopoverComponent } from '@shared/components/popover.component';
import { FormControl, UntypedFormBuilder } from '@angular/forms'; import { UntypedFormBuilder } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { SharedModule } from '@shared/shared.module'; import { SharedModule } from '@shared/shared.module';
import { getCurrentAuthState } from '@core/auth/auth.selectors';
import { RuleNodeDebugConfig } from '@shared/models/rule-node.models';
import { MINUTE, SECOND } from '@shared/models/time/time.models'; import { MINUTE, SECOND } from '@shared/models/time/time.models';
import { DebugDurationLeftPipe } from '@home/pages/rulechain/debug-duration-left.pipe'; import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe';
import { interval } from 'rxjs'; import { timer } from 'rxjs';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { HasDebugConfig } from '@shared/models/entity.models';
import { distinctUntilChanged, map, tap } from 'rxjs/operators';
@Component({ @Component({
selector: 'tb-debug-config-panel', selector: 'tb-debug-config-panel',
@ -44,7 +41,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
imports: [ imports: [
SharedModule, SharedModule,
CommonModule, CommonModule,
DebugDurationLeftPipe DurationLeftPipe
], ],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
@ -54,31 +51,35 @@ export class DebugConfigPanelComponent extends PageComponent implements OnInit {
@Input() debugFailures = false; @Input() debugFailures = false;
@Input() debugAll = false; @Input() debugAll = false;
@Input() debugAllUntil = 0; @Input() debugAllUntil = 0;
@Input() maxRuleNodeDebugDurationMinutes: number;
@Input() ruleChainDebugPerTenantLimitsConfiguration: string;
onFailuresControl: FormControl<boolean>; onFailuresControl = this.fb.control(false);
debugAllControl: FormControl<boolean>; debugAllControl = this.fb.control(false);
onConfigApplied = new EventEmitter<RuleNodeDebugConfig>() maxMessagesCount: string;
maxTimeFrameSec: string;
readonly maxRuleNodeDebugDurationMinutes = getCurrentAuthState(this.store).maxRuleNodeDebugDurationMinutes; isDebugAllActive$ = timer(0, SECOND).pipe(
readonly ruleChainDebugPerTenantLimitsConfiguration = getCurrentAuthState(this.store).ruleChainDebugPerTenantLimitsConfiguration; map(() => {
readonly maxMessagesCount = this.ruleChainDebugPerTenantLimitsConfiguration?.split(':')[0]; this.cd.markForCheck();
readonly maxTimeFrameSec = this.ruleChainDebugPerTenantLimitsConfiguration?.split(':')[1]; return this.debugAllUntil > new Date().getTime()
}),
distinctUntilChanged(),
tap(isDebugOn => this.debugAllControl.patchValue(isDebugOn, { emitEvent: false }))
);
constructor(private fb: UntypedFormBuilder, onConfigApplied = new EventEmitter<HasDebugConfig>();
private destroyRef: DestroyRef,
private cdr: ChangeDetectorRef,
protected store: Store<AppState>) {
super(store);
this.onFailuresControl = this.fb.control(false); constructor(private fb: UntypedFormBuilder, private cd: ChangeDetectorRef) {
this.debugAllControl = this.fb.control(false); super();
this.observeDebugAllChange(); this.observeDebugAllChange();
} }
ngOnInit(): void { ngOnInit(): void {
this.debugAllControl.patchValue(this.isDebugAllOn(), { emitEvent: false }); this.maxMessagesCount = this.ruleChainDebugPerTenantLimitsConfiguration?.split(':')[0];
this.maxTimeFrameSec = this.ruleChainDebugPerTenantLimitsConfiguration?.split(':')[1];
this.onFailuresControl.patchValue(this.debugFailures); this.onFailuresControl.patchValue(this.debugFailures);
} }
@ -99,22 +100,10 @@ export class DebugConfigPanelComponent extends PageComponent implements OnInit {
this.debugAllUntil = new Date().getTime() + this.maxRuleNodeDebugDurationMinutes * MINUTE; this.debugAllUntil = new Date().getTime() + this.maxRuleNodeDebugDurationMinutes * MINUTE;
} }
isDebugAllOn(): boolean {
return this.debugAllUntil > new Date().getTime();
}
private observeDebugAllChange(): void { private observeDebugAllChange(): void {
interval(SECOND)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(() => {
this.debugAllControl.patchValue(this.isDebugAllOn(), { emitEvent: false });
this.cdr.markForCheck();
});
this.debugAllControl.valueChanges.pipe(takeUntilDestroyed()).subscribe(value => { this.debugAllControl.valueChanges.pipe(takeUntilDestroyed()).subscribe(value => {
this.debugAllUntil = value? new Date().getTime() + this.maxRuleNodeDebugDurationMinutes * MINUTE : 0; this.debugAllUntil = value? new Date().getTime() + this.maxRuleNodeDebugDurationMinutes * MINUTE : 0;
this.debugAll = value; this.debugAll = value;
this.cdr.markForCheck();
}); });
} }
} }

View File

@ -40,6 +40,8 @@
[debugAll]="ruleNode.debugAll" [debugAll]="ruleNode.debugAll"
[debugFailures]="ruleNode.debugFailures" [debugFailures]="ruleNode.debugFailures"
[debugAllUntil]="ruleNode.debugAllUntil" [debugAllUntil]="ruleNode.debugAllUntil"
[maxRuleNodeDebugDurationMinutes]="maxRuleNodeDebugDurationMinutes"
[ruleChainDebugPerTenantLimitsConfiguration]="ruleChainDebugPerTenantLimitsConfiguration"
(onDebugConfigChanged)="onDebugConfigChanged($event)" (onDebugConfigChanged)="onDebugConfigChanged($event)"
/> />
<button mat-stroked-button <button mat-stroked-button

View File

@ -29,7 +29,7 @@ import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { FcRuleNode, RuleNodeDebugConfig, RuleNodeType } from '@shared/models/rule-node.models'; import { FcRuleNode, RuleNodeType } from '@shared/models/rule-node.models';
import { EntityType } from '@shared/models/entity-type.models'; import { EntityType } from '@shared/models/entity-type.models';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { RuleNodeConfigComponent } from './rule-node-config.component'; import { RuleNodeConfigComponent } from './rule-node-config.component';
@ -39,6 +39,8 @@ import { ComponentClusteringMode } from '@shared/models/component-descriptor.mod
import { coerceBoolean } from '@shared/decorators/coercion'; import { coerceBoolean } from '@shared/decorators/coercion';
import { ServiceType } from '@shared/models/queue.models'; import { ServiceType } from '@shared/models/queue.models';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { getCurrentAuthState } from '@core/auth/auth.selectors';
import { HasDebugConfig } from '@shared/models/entity.models';
@Component({ @Component({
selector: 'tb-rule-node', selector: 'tb-rule-node',
@ -79,6 +81,9 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O
ruleNodeFormGroup: UntypedFormGroup; ruleNodeFormGroup: UntypedFormGroup;
readonly maxRuleNodeDebugDurationMinutes = getCurrentAuthState(this.store).maxRuleNodeDebugDurationMinutes;
readonly ruleChainDebugPerTenantLimitsConfiguration = getCurrentAuthState(this.store).ruleChainDebugPerTenantLimitsConfiguration;
private destroy$ = new Subject<void>(); private destroy$ = new Subject<void>();
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
@ -205,7 +210,7 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O
return this.ruleNode.component.clusteringMode === ComponentClusteringMode.USER_PREFERENCE; return this.ruleNode.component.clusteringMode === ComponentClusteringMode.USER_PREFERENCE;
} }
onDebugConfigChanged(config: RuleNodeDebugConfig): void { onDebugConfigChanged(config: HasDebugConfig): void {
this.ruleNodeFormGroup.get('debugAllUntil').setValue(config.debugAllUntil); this.ruleNodeFormGroup.get('debugAllUntil').setValue(config.debugAllUntil);
this.ruleNodeFormGroup.get('debugAll').setValue(config.debugAll); this.ruleNodeFormGroup.get('debugAll').setValue(config.debugAll);
this.ruleNodeFormGroup.get('debugFailures').setValue(config.debugFailures); this.ruleNodeFormGroup.get('debugFailures').setValue(config.debugFailures);

View File

@ -32,8 +32,8 @@ import { RuleNodeDetailsComponent } from './rule-node-details.component';
import { RuleNodeLinkComponent } from './rule-node-link.component'; import { RuleNodeLinkComponent } from './rule-node-link.component';
import { LinkLabelsComponent } from '@home/pages/rulechain/link-labels.component'; import { LinkLabelsComponent } from '@home/pages/rulechain/link-labels.component';
import { RuleNodeConfigComponent } from './rule-node-config.component'; import { RuleNodeConfigComponent } from './rule-node-config.component';
import { DebugDurationLeftPipe } from '@home/pages/rulechain/debug-duration-left.pipe'; import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe';
import { DebugConfigButtonComponent } from '@home/pages/rulechain/debug-config-button.component'; import { DebugConfigButtonComponent } from '@home/components/debug-config/debug-config-button.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -62,7 +62,7 @@ import { DebugConfigButtonComponent } from '@home/pages/rulechain/debug-config-b
SharedModule, SharedModule,
HomeComponentsModule, HomeComponentsModule,
RuleChainRoutingModule, RuleChainRoutingModule,
DebugDurationLeftPipe, DurationLeftPipe,
DebugConfigButtonComponent DebugConfigButtonComponent
] ]
}) })

View File

@ -191,3 +191,9 @@ export interface HasTenantId {
export interface HasVersion { export interface HasVersion {
version?: number; version?: number;
} }
export interface HasDebugConfig {
debugAll: boolean;
debugFailures: boolean;
debugAllUntil: number;
}

View File

@ -27,19 +27,16 @@ import { AppState } from '@core/core.state';
import { AbstractControl, UntypedFormGroup } from '@angular/forms'; import { AbstractControl, UntypedFormGroup } from '@angular/forms';
import { RuleChainType } from '@shared/models/rule-chain.models'; import { RuleChainType } from '@shared/models/rule-chain.models';
import { DebugRuleNodeEventBody } from '@shared/models/event.models'; import { DebugRuleNodeEventBody } from '@shared/models/event.models';
import { TranslateService } from '@ngx-translate/core'; import { HasDebugConfig } from '@shared/models/entity.models';
export interface RuleNodeConfiguration { export interface RuleNodeConfiguration {
[key: string]: any; [key: string]: any;
} }
export interface RuleNode extends BaseData<RuleNodeId> { export interface RuleNode extends BaseData<RuleNodeId>, HasDebugConfig {
ruleChainId?: RuleChainId; ruleChainId?: RuleChainId;
type: string; type: string;
name: string; name: string;
debugAll: boolean;
debugFailures: boolean;
debugAllUntil: number;
singletonMode: boolean; singletonMode: boolean;
queueName?: string; queueName?: string;
configurationVersion?: number; configurationVersion?: number;
@ -347,21 +344,12 @@ export interface FcRuleNode extends FcRuleNodeType {
ruleNodeId?: RuleNodeId; ruleNodeId?: RuleNodeId;
additionalInfo?: any; additionalInfo?: any;
configuration?: RuleNodeConfiguration; configuration?: RuleNodeConfiguration;
debugAll?: boolean;
debugFailures?: boolean;
debugAllUntil?: number;
error?: string; error?: string;
highlighted?: boolean; highlighted?: boolean;
componentClazz?: string; componentClazz?: string;
ruleChainType?: RuleChainType; ruleChainType?: RuleChainType;
} }
export interface RuleNodeDebugConfig {
debugAll: boolean;
debugFailures: boolean;
debugAllUntil: number;
}
export interface FcRuleEdge extends FcEdge { export interface FcRuleEdge extends FcEdge {
labels?: string[]; labels?: string[];
} }

View File

@ -15,22 +15,21 @@
/// ///
import { Pipe, PipeTransform } from '@angular/core'; import { Pipe, PipeTransform } from '@angular/core';
import { MINUTE } from '@shared/models/time/time.models';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { MillisecondsToTimeStringPipe } from '@shared/pipe/milliseconds-to-time-string.pipe'; import { MillisecondsToTimeStringPipe } from './milliseconds-to-time-string.pipe';
@Pipe({ @Pipe({
name: 'debugDurationLeft', name: 'durationLeft',
pure: false, pure: false,
standalone: true, standalone: true,
}) })
export class DebugDurationLeftPipe implements PipeTransform { export class DurationLeftPipe implements PipeTransform {
constructor(private translate: TranslateService, private millisecondsToTimeString: MillisecondsToTimeStringPipe) { constructor(private translate: TranslateService, private millisecondsToTimeString: MillisecondsToTimeStringPipe) {
} }
transform(debugAllUntil: number): string { transform(untilTimestamp: number, shortFormat = true, onlyFirstDigit = true): string {
const time = this.millisecondsToTimeString.transform((debugAllUntil - new Date().getTime()), true, true); const time = this.millisecondsToTimeString.transform((untilTimestamp - new Date().getTime()), shortFormat, onlyFirstDigit) ?? 0;
return `${time} ` + this.translate.instant('common.left'); return this.translate.instant('common.time-left', { time });
} }
} }

View File

@ -58,7 +58,9 @@ export class MillisecondsToTimeStringPipe implements PipeTransform {
for (const { value, key, shortKey } of timeUnits) { for (const { value, key, shortKey } of timeUnits) {
if (value > 0) { if (value > 0) {
timeString += this.translate.instant(shortFormat ? `timewindow.${shortKey}` : `timewindow.${key}`, { [key]: value }); timeString += this.translate.instant(shortFormat ? `timewindow.${shortKey}` : `timewindow.${key}`, { [key]: value });
if (onlyFirstDigit) return timeString; if (onlyFirstDigit) {
return timeString;
}
} }
} }

View File

@ -25,3 +25,4 @@ export * from './file-size.pipe';
export * from './selectable-columns.pipe'; export * from './selectable-columns.pipe';
export * from './image.pipe'; export * from './image.pipe';
export * from './key-value-not-empty.pipe'; export * from './key-value-not-empty.pipe';
export * from './duration-left.pipe';

View File

@ -996,10 +996,10 @@
"type-sms-sent": "SMS sent" "type-sms-sent": "SMS sent"
}, },
"debug-config": { "debug-config": {
"min": "min", "min": "{{number}} min",
"label": "Debug configuration", "label": "Debug configuration",
"on-failure": "Failures only (24/7)", "on-failure": "Failures only (24/7)",
"all-messages": "All messages", "all-messages": "All messages ({{time}})",
"failures": "Failures", "failures": "Failures",
"all": "All", "all": "All",
"hint": { "hint": {
@ -1045,7 +1045,7 @@
"open-details-page": "Open details page", "open-details-page": "Open details page",
"not-found": "Not found", "not-found": "Not found",
"documentation": "Documentation", "documentation": "Documentation",
"left": "left" "time-left": "{{time}} left"
}, },
"content-type": { "content-type": {
"json": "Json", "json": "Json",

View File

@ -1278,7 +1278,7 @@ pre.tb-highlight {
} }
&.active:not(:disabled) { &.active:not(:disabled) {
border-color: $primary !important; --mdc-outlined-button-outline-color: $primary;
} }
&:disabled { &:disabled {