UI: [Rule node save ts] Rename Persistence settings to Processing settings
This commit is contained in:
parent
12a8c070a6
commit
fc3bc52247
@ -24,11 +24,11 @@ import {
|
||||
Validator
|
||||
} from '@angular/forms';
|
||||
import {
|
||||
AdvancedPersistenceConfig,
|
||||
defaultAdvancedPersistenceConfig,
|
||||
AdvancedProcessingConfig,
|
||||
defaultAdvancedProcessingConfig,
|
||||
maxDeduplicateTimeSecs,
|
||||
PersistenceType,
|
||||
PersistenceTypeTranslationMap
|
||||
ProcessingType,
|
||||
ProcessingTypeTranslationMap
|
||||
} from '@home/components/rule-node/action/timeseries-config.models';
|
||||
import { isDefinedAndNotNull } from '@core/utils';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
@ -52,13 +52,13 @@ export class AdvancedPersistenceSettingRowComponent implements ControlValueAcces
|
||||
title: string;
|
||||
|
||||
persistenceSettingRowForm = this.fb.group({
|
||||
type: [defaultAdvancedPersistenceConfig.type],
|
||||
type: [defaultAdvancedProcessingConfig.type],
|
||||
deduplicationIntervalSecs: [{value: 60, disabled: true}]
|
||||
});
|
||||
|
||||
PersistenceType = PersistenceType;
|
||||
persistenceStrategies = [PersistenceType.ON_EVERY_MESSAGE, PersistenceType.DEDUPLICATE, PersistenceType.SKIP];
|
||||
PersistenceTypeTranslationMap = PersistenceTypeTranslationMap;
|
||||
PersistenceType = ProcessingType;
|
||||
persistenceStrategies = [ProcessingType.ON_EVERY_MESSAGE, ProcessingType.DEDUPLICATE, ProcessingType.SKIP];
|
||||
PersistenceTypeTranslationMap = ProcessingTypeTranslationMap;
|
||||
|
||||
maxDeduplicateTime = maxDeduplicateTimeSecs;
|
||||
|
||||
@ -96,16 +96,16 @@ export class AdvancedPersistenceSettingRowComponent implements ControlValueAcces
|
||||
};
|
||||
}
|
||||
|
||||
writeValue(value: AdvancedPersistenceConfig) {
|
||||
writeValue(value: AdvancedProcessingConfig) {
|
||||
if (isDefinedAndNotNull(value)) {
|
||||
this.persistenceSettingRowForm.patchValue(value, {emitEvent: false});
|
||||
} else {
|
||||
this.persistenceSettingRowForm.patchValue(defaultAdvancedPersistenceConfig);
|
||||
this.persistenceSettingRowForm.patchValue(defaultAdvancedProcessingConfig);
|
||||
}
|
||||
}
|
||||
|
||||
private updatedValidation() {
|
||||
if (this.persistenceSettingRowForm.get('type').value === PersistenceType.DEDUPLICATE) {
|
||||
if (this.persistenceSettingRowForm.get('type').value === ProcessingType.DEDUPLICATE) {
|
||||
this.persistenceSettingRowForm.get('deduplicationIntervalSecs').enable({emitEvent: false});
|
||||
} else {
|
||||
this.persistenceSettingRowForm.get('deduplicationIntervalSecs').disable({emitEvent: false})
|
||||
|
||||
@ -16,6 +16,11 @@
|
||||
|
||||
-->
|
||||
<section [formGroup]="persistenceForm" class="tb-form-panel no-border no-padding">
|
||||
<tb-example-hint
|
||||
[hintText]="'rule-node-config.save-time-series.advanced-settings-hint'"
|
||||
[popupHelpLink]="'rulenode/save_timeseries_node_advanced'"
|
||||
>
|
||||
</tb-example-hint>
|
||||
<tb-advanced-persistence-setting-row
|
||||
formControlName="timeseries"
|
||||
title="{{ 'rule-node-config.save-time-series.time-series' | translate }}"
|
||||
|
||||
@ -24,7 +24,7 @@ import {
|
||||
} from '@angular/forms';
|
||||
import { Component, forwardRef } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { AdvancedPersistenceStrategy } from '@home/components/rule-node/action/timeseries-config.models';
|
||||
import { AdvancedProcessingStrategy } from '@home/components/rule-node/action/timeseries-config.models';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-advanced-persistence-settings',
|
||||
@ -76,8 +76,7 @@ export class AdvancedPersistenceSettingComponent implements ControlValueAccessor
|
||||
};
|
||||
}
|
||||
|
||||
writeValue(value: AdvancedPersistenceStrategy) {
|
||||
writeValue(value: AdvancedProcessingStrategy) {
|
||||
this.persistenceForm.patchValue(value, {emitEvent: false});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -16,10 +16,10 @@
|
||||
|
||||
-->
|
||||
<section [formGroup]="timeseriesConfigForm" class="tb-form-panel no-border no-padding">
|
||||
<div class="tb-form-panel stroked no-padding-bottom no-gap" formGroupName="persistenceSettings">
|
||||
<div class="tb-form-panel stroked no-padding-bottom no-gap" formGroupName="processingSettings">
|
||||
<div class="mb-4 flex flex-row items-center justify-between">
|
||||
<div class="tb-form-panel-title" tb-hint-tooltip-icon="{{ 'rule-node-config.save-time-series.persistence-settings-hint' | translate}}" translate>
|
||||
rule-node-config.save-time-series.persistence-settings
|
||||
<div class="tb-form-panel-title" tb-hint-tooltip-icon="{{ 'rule-node-config.save-time-series.processing-settings-hint' | translate}}" translate>
|
||||
rule-node-config.save-time-series.processing-settings
|
||||
</div>
|
||||
<tb-toggle-select appearance="fill" selectMediaBreakpoint="xs"
|
||||
formControlName="isAdvanced">
|
||||
@ -27,7 +27,7 @@
|
||||
<tb-toggle-option [value]=true>{{ 'rule-node-config.advanced-mode' | translate }}</tb-toggle-option>
|
||||
</tb-toggle-select>
|
||||
</div>
|
||||
@if(!timeseriesConfigForm.get('persistenceSettings.isAdvanced').value) {
|
||||
@if(!timeseriesConfigForm.get('processingSettings.isAdvanced').value) {
|
||||
<mat-form-field>
|
||||
<mat-label translate>rule-node-config.save-time-series.strategy</mat-label>
|
||||
<mat-select formControlName="type">
|
||||
@ -37,7 +37,7 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
@if(timeseriesConfigForm.get('persistenceSettings.type').value === PersistenceType.DEDUPLICATE) {
|
||||
@if(timeseriesConfigForm.get('processingSettings.type').value === PersistenceType.DEDUPLICATE) {
|
||||
<tb-time-unit-input
|
||||
required
|
||||
labelText="{{ 'rule-node-config.save-time-series.deduplication-interval' | translate }}"
|
||||
@ -49,8 +49,7 @@
|
||||
formControlName="deduplicationIntervalSecs">
|
||||
</tb-time-unit-input>
|
||||
}
|
||||
}
|
||||
@else {
|
||||
} @else {
|
||||
<tb-advanced-persistence-settings
|
||||
class="mb-4"
|
||||
formControlName="advanced"
|
||||
|
||||
@ -20,10 +20,10 @@ import { RuleNodeConfigurationComponent } from '@shared/models/rule-node.models'
|
||||
import {
|
||||
defaultAdvancedPersistenceStrategy,
|
||||
maxDeduplicateTimeSecs,
|
||||
PersistenceSettings,
|
||||
PersistenceSettingsForm,
|
||||
PersistenceType,
|
||||
PersistenceTypeTranslationMap,
|
||||
ProcessingSettings,
|
||||
ProcessingSettingsForm,
|
||||
ProcessingType,
|
||||
ProcessingTypeTranslationMap,
|
||||
TimeseriesNodeConfiguration,
|
||||
TimeseriesNodeConfigurationForm
|
||||
} from '@home/components/rule-node/action/timeseries-config.models';
|
||||
@ -37,9 +37,9 @@ export class TimeseriesConfigComponent extends RuleNodeConfigurationComponent {
|
||||
|
||||
timeseriesConfigForm: FormGroup;
|
||||
|
||||
PersistenceType = PersistenceType;
|
||||
persistenceStrategies = [PersistenceType.ON_EVERY_MESSAGE, PersistenceType.DEDUPLICATE, PersistenceType.WEBSOCKETS_ONLY];
|
||||
PersistenceTypeTranslationMap = PersistenceTypeTranslationMap;
|
||||
PersistenceType = ProcessingType;
|
||||
persistenceStrategies = [ProcessingType.ON_EVERY_MESSAGE, ProcessingType.DEDUPLICATE, ProcessingType.WEBSOCKETS_ONLY];
|
||||
PersistenceTypeTranslationMap = ProcessingTypeTranslationMap;
|
||||
|
||||
maxDeduplicateTime = maxDeduplicateTimeSecs
|
||||
|
||||
@ -52,22 +52,22 @@ export class TimeseriesConfigComponent extends RuleNodeConfigurationComponent {
|
||||
}
|
||||
|
||||
protected validatorTriggers(): string[] {
|
||||
return ['persistenceSettings.isAdvanced', 'persistenceSettings.type'];
|
||||
return ['processingSettings.isAdvanced', 'processingSettings.type'];
|
||||
}
|
||||
|
||||
protected prepareInputConfig(config: TimeseriesNodeConfiguration): TimeseriesNodeConfigurationForm {
|
||||
let persistenceSettings: PersistenceSettingsForm;
|
||||
if (config?.persistenceSettings) {
|
||||
const isAdvanced = config?.persistenceSettings?.type === PersistenceType.ADVANCED;
|
||||
persistenceSettings = {
|
||||
type: isAdvanced ? PersistenceType.ON_EVERY_MESSAGE : config.persistenceSettings.type,
|
||||
let processingSettings: ProcessingSettingsForm;
|
||||
if (config?.processingSettings) {
|
||||
const isAdvanced = config?.processingSettings?.type === ProcessingType.ADVANCED;
|
||||
processingSettings = {
|
||||
type: isAdvanced ? ProcessingType.ON_EVERY_MESSAGE : config.processingSettings.type,
|
||||
isAdvanced: isAdvanced,
|
||||
deduplicationIntervalSecs: config.persistenceSettings?.deduplicationIntervalSecs ?? 60,
|
||||
advanced: isAdvanced ? config.persistenceSettings : defaultAdvancedPersistenceStrategy
|
||||
deduplicationIntervalSecs: config.processingSettings?.deduplicationIntervalSecs ?? 60,
|
||||
advanced: isAdvanced ? config.processingSettings : defaultAdvancedPersistenceStrategy
|
||||
}
|
||||
} else {
|
||||
persistenceSettings = {
|
||||
type: PersistenceType.ON_EVERY_MESSAGE,
|
||||
processingSettings = {
|
||||
type: ProcessingType.ON_EVERY_MESSAGE,
|
||||
isAdvanced: false,
|
||||
deduplicationIntervalSecs: 60,
|
||||
advanced: defaultAdvancedPersistenceStrategy
|
||||
@ -75,36 +75,36 @@ export class TimeseriesConfigComponent extends RuleNodeConfigurationComponent {
|
||||
}
|
||||
return {
|
||||
...config,
|
||||
persistenceSettings: persistenceSettings
|
||||
processingSettings: processingSettings
|
||||
}
|
||||
}
|
||||
|
||||
protected prepareOutputConfig(config: TimeseriesNodeConfigurationForm): TimeseriesNodeConfiguration {
|
||||
let persistenceSettings: PersistenceSettings;
|
||||
if (config.persistenceSettings.isAdvanced) {
|
||||
persistenceSettings = {
|
||||
...config.persistenceSettings.advanced,
|
||||
type: PersistenceType.ADVANCED
|
||||
let processingSettings: ProcessingSettings;
|
||||
if (config.processingSettings.isAdvanced) {
|
||||
processingSettings = {
|
||||
...config.processingSettings.advanced,
|
||||
type: ProcessingType.ADVANCED
|
||||
};
|
||||
} else {
|
||||
persistenceSettings = {
|
||||
type: config.persistenceSettings.type,
|
||||
deduplicationIntervalSecs: config.persistenceSettings?.deduplicationIntervalSecs
|
||||
processingSettings = {
|
||||
type: config.processingSettings.type,
|
||||
deduplicationIntervalSecs: config.processingSettings?.deduplicationIntervalSecs
|
||||
};
|
||||
}
|
||||
return {
|
||||
...config,
|
||||
persistenceSettings
|
||||
processingSettings
|
||||
};
|
||||
}
|
||||
|
||||
protected onConfigurationSet(config: TimeseriesNodeConfigurationForm) {
|
||||
this.timeseriesConfigForm = this.fb.group({
|
||||
persistenceSettings: this.fb.group({
|
||||
isAdvanced: [config?.persistenceSettings?.isAdvanced ?? false],
|
||||
type: [config?.persistenceSettings?.type ?? PersistenceType.ON_EVERY_MESSAGE],
|
||||
processingSettings: this.fb.group({
|
||||
isAdvanced: [config?.processingSettings?.isAdvanced ?? false],
|
||||
type: [config?.processingSettings?.type ?? ProcessingType.ON_EVERY_MESSAGE],
|
||||
deduplicationIntervalSecs: [
|
||||
{value: config?.persistenceSettings?.deduplicationIntervalSecs ?? 60, disabled: true},
|
||||
{value: config?.processingSettings?.deduplicationIntervalSecs ?? 60, disabled: true},
|
||||
[Validators.required, Validators.max(maxDeduplicateTimeSecs)]
|
||||
],
|
||||
advanced: [{value: null, disabled: true}]
|
||||
@ -115,18 +115,18 @@ export class TimeseriesConfigComponent extends RuleNodeConfigurationComponent {
|
||||
}
|
||||
|
||||
protected updateValidators(emitEvent: boolean, _trigger?: string) {
|
||||
const persistenceForm = this.timeseriesConfigForm.get('persistenceSettings') as FormGroup;
|
||||
const isAdvanced: boolean = persistenceForm.get('isAdvanced').value;
|
||||
const type: PersistenceType = persistenceForm.get('type').value;
|
||||
if (!isAdvanced && type === PersistenceType.DEDUPLICATE) {
|
||||
persistenceForm.get('deduplicationIntervalSecs').enable({emitEvent});
|
||||
const processingForm = this.timeseriesConfigForm.get('processingSettings') as FormGroup;
|
||||
const isAdvanced: boolean = processingForm.get('isAdvanced').value;
|
||||
const type: ProcessingType = processingForm.get('type').value;
|
||||
if (!isAdvanced && type === ProcessingType.DEDUPLICATE) {
|
||||
processingForm.get('deduplicationIntervalSecs').enable({emitEvent});
|
||||
} else {
|
||||
persistenceForm.get('deduplicationIntervalSecs').disable({emitEvent});
|
||||
processingForm.get('deduplicationIntervalSecs').disable({emitEvent});
|
||||
}
|
||||
if (isAdvanced) {
|
||||
persistenceForm.get('advanced').enable({emitEvent});
|
||||
processingForm.get('advanced').enable({emitEvent});
|
||||
} else {
|
||||
persistenceForm.get('advanced').disable({emitEvent});
|
||||
processingForm.get('advanced').disable({emitEvent});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,24 +19,24 @@ import { DAY, SECOND } from '@shared/models/time/time.models';
|
||||
export const maxDeduplicateTimeSecs = DAY / SECOND;
|
||||
|
||||
export interface TimeseriesNodeConfiguration {
|
||||
persistenceSettings: PersistenceSettings;
|
||||
processingSettings: ProcessingSettings;
|
||||
defaultTTL: number;
|
||||
useServerTs: boolean;
|
||||
}
|
||||
|
||||
export interface TimeseriesNodeConfigurationForm extends Omit<TimeseriesNodeConfiguration, 'persistenceSettings'> {
|
||||
persistenceSettings: PersistenceSettingsForm
|
||||
export interface TimeseriesNodeConfigurationForm extends Omit<TimeseriesNodeConfiguration, 'processingSettings'> {
|
||||
processingSettings: ProcessingSettingsForm
|
||||
}
|
||||
|
||||
export type PersistenceSettings = BasicPersistenceSettings & Partial<DeduplicatePersistenceStrategy> & Partial<AdvancedPersistenceStrategy>;
|
||||
export type ProcessingSettings = ProcessingSettingsSettings & Partial<DeduplicateProcessingStrategy> & Partial<AdvancedProcessingStrategy>;
|
||||
|
||||
export type PersistenceSettingsForm = Omit<PersistenceSettings, keyof AdvancedPersistenceStrategy> & {
|
||||
export type ProcessingSettingsForm = Omit<ProcessingSettings, keyof AdvancedProcessingStrategy> & {
|
||||
isAdvanced: boolean;
|
||||
advanced?: Partial<AdvancedPersistenceStrategy>;
|
||||
type: PersistenceType;
|
||||
advanced?: Partial<AdvancedProcessingStrategy>;
|
||||
type: ProcessingType;
|
||||
};
|
||||
|
||||
export enum PersistenceType {
|
||||
export enum ProcessingType {
|
||||
ON_EVERY_MESSAGE = 'ON_EVERY_MESSAGE',
|
||||
DEDUPLICATE = 'DEDUPLICATE',
|
||||
WEBSOCKETS_ONLY = 'WEBSOCKETS_ONLY',
|
||||
@ -44,35 +44,35 @@ export enum PersistenceType {
|
||||
SKIP = 'SKIP'
|
||||
}
|
||||
|
||||
export const PersistenceTypeTranslationMap = new Map<PersistenceType, string>([
|
||||
[PersistenceType.ON_EVERY_MESSAGE, 'rule-node-config.save-time-series.strategy-type.every-message'],
|
||||
[PersistenceType.DEDUPLICATE, 'rule-node-config.save-time-series.strategy-type.deduplicate'],
|
||||
[PersistenceType.WEBSOCKETS_ONLY, 'rule-node-config.save-time-series.strategy-type.web-sockets-only'],
|
||||
[PersistenceType.SKIP, 'rule-node-config.save-time-series.strategy-type.skip'],
|
||||
export const ProcessingTypeTranslationMap = new Map<ProcessingType, string>([
|
||||
[ProcessingType.ON_EVERY_MESSAGE, 'rule-node-config.save-time-series.strategy-type.every-message'],
|
||||
[ProcessingType.DEDUPLICATE, 'rule-node-config.save-time-series.strategy-type.deduplicate'],
|
||||
[ProcessingType.WEBSOCKETS_ONLY, 'rule-node-config.save-time-series.strategy-type.web-sockets-only'],
|
||||
[ProcessingType.SKIP, 'rule-node-config.save-time-series.strategy-type.skip'],
|
||||
])
|
||||
|
||||
export interface BasicPersistenceSettings {
|
||||
type: PersistenceType;
|
||||
export interface ProcessingSettingsSettings {
|
||||
type: ProcessingType;
|
||||
}
|
||||
|
||||
export interface DeduplicatePersistenceStrategy extends BasicPersistenceSettings{
|
||||
export interface DeduplicateProcessingStrategy extends ProcessingSettingsSettings{
|
||||
deduplicationIntervalSecs: number;
|
||||
}
|
||||
|
||||
export interface AdvancedPersistenceStrategy extends BasicPersistenceSettings{
|
||||
timeseries: AdvancedPersistenceConfig;
|
||||
latest: AdvancedPersistenceConfig;
|
||||
webSockets: AdvancedPersistenceConfig;
|
||||
export interface AdvancedProcessingStrategy extends ProcessingSettingsSettings{
|
||||
timeseries: AdvancedProcessingConfig;
|
||||
latest: AdvancedProcessingConfig;
|
||||
webSockets: AdvancedProcessingConfig;
|
||||
}
|
||||
|
||||
export type AdvancedPersistenceConfig = WithOptional<DeduplicatePersistenceStrategy, 'deduplicationIntervalSecs'>;
|
||||
export type AdvancedProcessingConfig = WithOptional<DeduplicateProcessingStrategy, 'deduplicationIntervalSecs'>;
|
||||
|
||||
export const defaultAdvancedPersistenceConfig: AdvancedPersistenceConfig = {
|
||||
type: PersistenceType.ON_EVERY_MESSAGE
|
||||
export const defaultAdvancedProcessingConfig: AdvancedProcessingConfig = {
|
||||
type: ProcessingType.ON_EVERY_MESSAGE
|
||||
}
|
||||
|
||||
export const defaultAdvancedPersistenceStrategy: Omit<AdvancedPersistenceStrategy, 'type'> = {
|
||||
timeseries: defaultAdvancedPersistenceConfig,
|
||||
latest: defaultAdvancedPersistenceConfig,
|
||||
webSockets: defaultAdvancedPersistenceConfig,
|
||||
export const defaultAdvancedPersistenceStrategy: Omit<AdvancedProcessingStrategy, 'type'> = {
|
||||
timeseries: defaultAdvancedProcessingConfig,
|
||||
latest: defaultAdvancedProcessingConfig,
|
||||
webSockets: defaultAdvancedProcessingConfig,
|
||||
}
|
||||
|
||||
@ -15,11 +15,11 @@
|
||||
limitations under the License.
|
||||
|
||||
-->
|
||||
<div [hidden]="!hintText" class="tb-form-hint tb-primary-fill space-between">
|
||||
<div [hidden]="!hintText" class="tb-form-hint tb-primary-fill flex justify-between gap-5">
|
||||
<div [innerHTML]=" hintText | translate | safe: 'html'"
|
||||
[style.text-align]="textAlign"
|
||||
class="hint-text"></div>
|
||||
<div *ngIf="popupHelpLink" class="see-example" tb-help-popup="{{ popupHelpLink }}"
|
||||
class="w-full"></div>
|
||||
<div *ngIf="popupHelpLink" class="flex shrink-0" tb-help-popup="{{ popupHelpLink }}"
|
||||
hintMode
|
||||
tb-help-popup-placement="right"
|
||||
trigger-style="letter-spacing:0.25px; font-size:12px"
|
||||
|
||||
@ -1,31 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2024 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
:host {
|
||||
.space-between {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 20px;
|
||||
|
||||
.see-example {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.hint-text {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@ -19,7 +19,7 @@ import { Component, Input } from '@angular/core';
|
||||
@Component({
|
||||
selector: 'tb-example-hint',
|
||||
templateUrl: './example-hint.component.html',
|
||||
styleUrls: ['./example-hint.component.scss']
|
||||
styleUrls: []
|
||||
})
|
||||
export class ExampleHintComponent {
|
||||
@Input() hintText: string;
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
**TO DO;**
|
||||
|
||||
Advanced mode doc
|
||||
@ -5134,8 +5134,9 @@
|
||||
"basic-mode": "Basic",
|
||||
"advanced-mode": "Advanced",
|
||||
"save-time-series": {
|
||||
"persistence-settings": "Persistence settings",
|
||||
"persistence-settings-hint": "Define how and when time series data is saved. In Basic mode, apply a single persistence strategy to all actions or enable only WebSockets updates. Advanced mode allows you to configure individual persistence strategies for each action.",
|
||||
"processing-settings": "Processing settings",
|
||||
"processing-settings-hint": "Define how time series data is processed. In Basic mode, select a preconfigured processing strategy or enable only WebSocket updates. Advanced mode allows you to select individual processing strategies for each action.",
|
||||
"advanced-settings-hint": "Advanced settings mode is dangerous, and if you do not understand it, you may lose telemetry.\n\n\n\n\n\n\n\n",
|
||||
"strategy": "Strategy",
|
||||
"deduplication-interval": "Deduplication interval",
|
||||
"deduplication-interval-required": "Deduplication interval is required",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user