Merge pull request #12540 from ArtemDzhereleiko/AD/imp/multiple-input/radio

Radio button for multiple input widget
This commit is contained in:
Igor Kulikov 2025-01-31 18:14:17 +02:00 committed by GitHub
commit c5b744f6fd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 208 additions and 112 deletions

View File

@ -138,6 +138,28 @@
{{ getErrorMessageText(key.settings, 'required') }}
</mat-error>
</mat-form-field>
<div *ngIf="key.settings.dataKeyValueType === 'radio'">
<mat-label>{{key.label}}</mat-label>
<mat-radio-group
[style]="{'display': 'grid', 'grid-template-columns': 'repeat(' + key.settings.radioColumns + ', 1fr)', 'column-gap': '5px', 'row-gap': '5px'}"
[labelPosition]="key.settings.radioLabelPosition"
(change)="inputChanged(source, key)"
formControlName="{{key.formId}}">
<mat-radio-button
[style]="radioButtonSelectedColor(key.settings.radioColor)"
[disabled]="key.settings.isEditable === 'readonly'"
*ngFor="let option of key.settings.selectOptions"
[value]="option.value">
<ng-container *ngIf="key.settings.icon || key.settings.customIconUrl" matIconPrefix>
<ng-container *ngTemplateOutlet="iconPrefix; context: {key: key}"></ng-container>
</ng-container>
<span class="label-wrapper">
{{ getCustomTranslationText(option.label ? option.label : option.value) }}
</span>
</mat-radio-button>
</mat-radio-group>
</div>
<mat-form-field *ngIf="key.settings.dataKeyValueType === 'color'"
class="color-input" [appearance]="key.settings.appearance" [subscriptSizing]="key.settings.subscriptSizing"
(click)="colorInput.openColorPickerPopup($event)">

View File

@ -75,7 +75,7 @@
:host ::ng-deep {
.tb-multiple-input {
.mat-mdc-slide-toggle, .mat-mdc-checkbox {
.mat-mdc-slide-toggle, .mat-mdc-checkbox, .mat-mdc-radio-button {
.mdc-form-field {
width: 100%;
& > label {

View File

@ -54,7 +54,7 @@ type FieldAlignment = 'row' | 'column';
type MultipleInputWidgetDataKeyType = 'server' | 'shared' | 'timeseries';
export type MultipleInputWidgetDataKeyValueType = 'string' | 'double' | 'integer' |
'JSON' | 'booleanCheckbox' | 'booleanSwitch' |
'dateTime' | 'date' | 'time' | 'select' | 'color';
'dateTime' | 'date' | 'time' | 'select' | 'radio' | 'color';
export type MultipleInputWidgetDataKeyEditableType = 'editable' | 'disabled' | 'readonly';
type ConvertGetValueFunction = (value: any, ctx: WidgetContext) => any;
@ -86,6 +86,9 @@ interface MultipleInputWidgetDataKeySettings {
dataKeyValueType: MultipleInputWidgetDataKeyValueType;
slideToggleLabelPosition?: 'after' | 'before';
selectOptions: MultipleInputWidgetSelectOption[];
radioColor: string;
radioColumns: number;
radioLabelPosition?: 'after' | 'before';
required: boolean;
isEditable: MultipleInputWidgetDataKeyEditableType;
disabledOnDataKey: string;
@ -300,7 +303,7 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni
// For backward compatibility
if (dataKey.settings.dataKeyValueType === 'select') {
if (dataKey.settings.dataKeyValueType === 'select' || dataKey.settings.dataKeyValueType === 'radio') {
dataKey.settings.selectOptions.forEach((option) => {
if (option.value.toLowerCase() === 'null') {
option.value = null;
@ -444,6 +447,7 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni
}
break;
case 'select':
case 'radio':
value = keyValue !== null ? keyValue.toString() : null;
break;
case 'JSON':
@ -566,6 +570,12 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni
return this.getTranslatedErrorText(errorMessage, defaultMessage, messageValues);
}
public radioButtonSelectedColor(radioColor: string) {
if (isDefinedAndNotNull(radioColor)) {
return `--mdc-radio-selected-icon-color: ${radioColor}; --mdc-radio-selected-focus-icon-color: ${radioColor}; --mdc-radio-selected-hover-icon-color: ${radioColor}; --mdc-radio-selected-pressed-icon-color: ${radioColor}; --mat-radio-checked-ripple-color: ${radioColor};`
}
}
public getTranslatedErrorText(errorMessage: string, defaultMessage: string, messageValues?: object): string {
let messageText;
if (errorMessage && errorMessage.length) {

View File

@ -21,6 +21,7 @@
</mat-slide-toggle>
<fieldset [class.!hidden]="updateMultipleAttributesKeySettingsForm.get('dataKeyHidden').value" class="fields-group">
<legend class="group-title" translate>widgets.input-widgets.general-settings</legend>
<div class="flex flex-col">
<section class="flex flex-col gt-xs:flex-row gt-xs:items-center gt-xs:justify-start gt-xs:gap-2">
<mat-form-field class="mat-block flex-full xs:max-h-50% gt-xs:max-w-50%">
<mat-label translate>widgets.input-widgets.datakey-type</mat-label>
@ -66,6 +67,9 @@
<mat-option [value]="'select'">
{{ 'widgets.input-widgets.datakey-value-type-select' | translate }}
</mat-option>
<mat-option [value]="'radio'">
{{ 'widgets.input-widgets.datakey-value-type-radio' | translate }}
</mat-option>
<mat-option [value]="'JSON'">
{{ 'widgets.input-widgets.datakey-value-type-json' | translate }}
</mat-option>
@ -98,7 +102,7 @@
<input matInput formControlName="disabledOnDataKey">
</mat-form-field>
</section>
<section *ngIf="!['booleanSwitch', 'booleanCheckbox'].includes(updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value)"
<section *ngIf="!['booleanSwitch', 'booleanCheckbox', 'radio'].includes(updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value)"
class="flex flex-col gt-xs:flex-row gt-xs:items-center gt-xs:justify-start gt-xs:gap-2">
<mat-form-field class="mat-block flex-full xs:max-h-50% gt-xs:max-w-50%">
<mat-label translate>widgets.input-widgets.field-appearance</mat-label>
@ -123,6 +127,7 @@
</mat-select>
</mat-form-field>
</section>
</div>
</fieldset>
<fieldset [class.!hidden]="updateMultipleAttributesKeySettingsForm.get('dataKeyHidden').value ||
updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value !== 'booleanSwitch'" class="fields-group">
@ -140,8 +145,10 @@
</mat-form-field>
</fieldset>
<fieldset [class.!hidden]="updateMultipleAttributesKeySettingsForm.get('dataKeyHidden').value ||
updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value !== 'select'" class="fields-group">
<legend class="group-title" translate>widgets.input-widgets.select-options</legend>
(updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value !== 'select' && updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value !== 'radio')" class="fields-group">
<legend class="group-title">
{{ (updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value === 'select' ? 'widgets.input-widgets.select-options' : 'widgets.input-widgets.radio-options') | translate }}
</legend>
<div class="flex flex-col">
<div class="tb-control-list tb-drop-list" cdkDropList cdkDropListOrientation="vertical"
(cdkDropListDropped)="selectOptionDrop($event)">
@ -155,18 +162,51 @@
</div>
</div>
<div *ngIf="!selectOptionsFormArray().controls.length">
<span translate
class="tb-prompt flex items-center justify-center">widgets.input-widgets.no-select-options</span>
<span class="tb-prompt flex items-center justify-center">
{{ (updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value === 'select' ? 'widgets.input-widgets.no-select-options' : 'widgets.input-widgets.no-radio-options') | translate }}
</span>
</div>
<div style="padding-top: 16px;">
<button mat-raised-button color="primary"
type="button"
(click)="addSelectOption()">
<span translate>widgets.input-widgets.add-select-option</span>
<span>
{{ (updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value === 'select' ? 'widgets.input-widgets.add-select-option' : 'widgets.input-widgets.add-radio-option') | translate }}
</span>
</button>
</div>
</div>
</fieldset>
<div class="tb-form-panel mb-3.5"
[class.!hidden]="updateMultipleAttributesKeySettingsForm.get('dataKeyHidden').value ||
updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value !== 'radio'">
<div class="tb-form-panel-title" translate>widgets.input-widgets.radio-button-settings</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.input-widgets.color' | translate }}</div>
<tb-color-input asBoxInput
formControlName="radioColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.input-widgets.columns' | translate }}</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="radioColumns" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.input-widgets.radio-label-position' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="radioLabelPosition">
<mat-option [value]="'after'">
{{ 'widgets.input-widgets.radio-label-position-after' | translate }}
</mat-option>
<mat-option [value]="'before'">
{{ 'widgets.input-widgets.radio-label-position-before' | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
<fieldset [class.!hidden]="updateMultipleAttributesKeySettingsForm.get('dataKeyHidden').value ||
(updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value !== 'integer' &&
updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value !== 'double')" class="fields-group">

View File

@ -60,6 +60,9 @@ export class UpdateMultipleAttributesKeySettingsComponent extends WidgetSettings
slideToggleLabelPosition: 'after',
selectOptions: [],
radioColor: null,
radioColumns: 1,
radioLabelPosition: 'after',
step: 1,
minValue: null,
maxValue: null,
@ -104,10 +107,16 @@ export class UpdateMultipleAttributesKeySettingsComponent extends WidgetSettings
slideToggleLabelPosition: [settings.slideToggleLabelPosition, []],
// Select options
// Select/Radio options
selectOptions: this.prepareSelectOptionsFormArray(settings.selectOptions),
// Radio settings
radioColor: [settings.radioColor, []],
radioColumns: [settings.radioColumns, []],
radioLabelPosition: [settings.radioLabelPosition, []],
// Numeric field settings
step: [settings.step, [Validators.min(0)]],
@ -183,6 +192,11 @@ export class UpdateMultipleAttributesKeySettingsComponent extends WidgetSettings
this.updateMultipleAttributesKeySettingsForm.get('slideToggleLabelPosition').enable({emitEvent: false});
} else if (dataKeyValueType === 'select') {
this.updateMultipleAttributesKeySettingsForm.get('selectOptions').enable({emitEvent: false});
} else if (dataKeyValueType === 'radio') {
this.updateMultipleAttributesKeySettingsForm.get('selectOptions').enable({emitEvent: false});
this.updateMultipleAttributesKeySettingsForm.get('radioColor').enable({emitEvent: false});
this.updateMultipleAttributesKeySettingsForm.get('radioColumns').enable({emitEvent: false});
this.updateMultipleAttributesKeySettingsForm.get('radioLabelPosition').enable({emitEvent: false});
} else if (dataKeyValueType === 'integer' || dataKeyValueType === 'double') {
this.updateMultipleAttributesKeySettingsForm.get('step').enable({emitEvent: false});
this.updateMultipleAttributesKeySettingsForm.get('minValue').enable({emitEvent: false});

View File

@ -7400,6 +7400,7 @@
"datakey-value-type-date": "Date",
"datakey-value-type-time": "Time",
"datakey-value-type-select": "Select",
"datakey-value-type-radio": "Radio",
"datakey-value-type-color": "Color",
"value-is-required": "Value is required",
"ability-to-edit-attribute": "Ability to edit attribute",
@ -7440,7 +7441,16 @@
"set-value-function": "setValue function",
"json-invalid": "JSON value has an invalid format",
"title": "Title",
"cancel-button-label": "'Cancel' button label"
"cancel-button-label": "'Cancel' button label",
"radio-button-settings": "Radio button settings",
"color": "Color",
"columns": "Columns",
"radio-options": "Radio options",
"no-radio-options": "No radio options configured",
"add-radio-option": "Add radio option",
"radio-label-position": "Label position",
"radio-label-position-before": "Before",
"radio-label-position-after": "After"
},
"invalid-qr-code-text": "Invalid input text for QR code. Input should have a string type",
"qr-code": {