Skip to content

Commit 21430ed

Browse files
committed
[Forms/UI] fix for "incorrect use of label for=FORM_ELEMENT" bug
1 parent 1fde0d9 commit 21430ed

18 files changed

+62
-25
lines changed

e2e/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ By adhering to this principle, we can create tests that are both robust and refl
426426
// Fill the "Notes" section with information about the
427427
// currently running test and its project.
428428
const { testNotes } = page;
429-
const notesInput = page.locator('form[name="mctForm"] #notes-textarea');
429+
const notesInput = page.locator('form[name="mctForm"] #form-notes');
430430
await notesInput.fill(testNotes);
431431
```
432432

e2e/appActions.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ async function createDomainObjectWithDefaults(page, { type, name, parent = 'mine
9393
// Fill the "Notes" section with information about the
9494
// currently running test and its project.
9595
// eslint-disable-next-line playwright/no-raw-locators
96-
await page.locator('#notes-textarea').fill(page.testNotes);
96+
await page.locator('#form-notes').fill(page.testNotes);
9797
}
9898

9999
await page.getByRole('button', { name: 'Save' }).click();

e2e/tests/functional/forms.e2e.spec.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,8 @@ test.describe('Persistence operations @couchdb @network', () => {
223223
// Both pages: Fill the "Notes" section with information about the
224224
// currently running test and its project.
225225
const testNotes = page.testNotes;
226-
const notesInput = page.locator('form[name="mctForm"] #notes-textarea');
227-
const notesInput2 = page2.locator('form[name="mctForm"] #notes-textarea');
226+
const notesInput = page.locator('form[name="mctForm"] #form-notes');
227+
const notesInput2 = page2.locator('form[name="mctForm"] #form-notes');
228228
await Promise.all([notesInput.fill(testNotes), notesInput2.fill(testNotes)]);
229229

230230
// Page 2: Click "OK" to create the domain object and wait for navigation.

src/api/forms/components/FormRow.vue

+5-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@
2222

2323
<template>
2424
<div class="form-row c-form__row" :class="[{ first: first }, cssClass]" @on-change="onChange">
25-
<label class="c-form-row__label" :title="row.description" :for="`form-${row.key}`">
25+
<label
26+
class="c-form-row__label"
27+
:title="row.description"
28+
:for="row.key ? `form-${row.key}` : null"
29+
>
2630
{{ row.name }}
2731
</label>
2832
<div class="c-form-row__state-indicator" :class="reqClass"></div>

src/api/forms/components/controls/AutoCompleteField.vue

+4-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
<div ref="autoCompleteForm" class="form-control c-input--autocomplete js-autocomplete">
2424
<div class="c-input--autocomplete__wrapper">
2525
<input
26+
:id="fieldId"
2627
ref="autoCompleteInput"
2728
v-model="field"
2829
class="c-input--autocomplete__input js-autocomplete__input"
@@ -94,7 +95,8 @@ export default {
9495
hideOptions: true,
9596
showFilteredOptions: false,
9697
optionIndex: 0,
97-
field: this.model.value
98+
field: this.model.value,
99+
fieldId: null
98100
};
99101
},
100102
computed: {
@@ -166,6 +168,7 @@ export default {
166168
} else {
167169
this.options = this.model.options;
168170
}
171+
this.fieldId = this.model.key ? 'form-' + this.model.key : null;
169172
},
170173
unmounted() {
171174
document.body.removeEventListener('click', this.handleOutsideClick);

src/api/forms/components/controls/DatetimeField.vue

+4-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
<div class="hint timezone">Timezone</div>
3030
<form ref="dateTimeForm" prevent class="u-contents">
3131
<input
32+
:id="dateFieldId"
3233
v-model="date"
3334
class="field control date"
3435
:pattern="/\d{4}-\d{2}-\d{2}/"
@@ -92,10 +93,12 @@ export default {
9293
date: '',
9394
hour: 0,
9495
min: 0,
95-
sec: 0
96+
sec: 0,
97+
dateFieldId: null
9698
};
9799
},
98100
mounted() {
101+
this.dateFieldId = this.model.key ? 'form-' + this.model.key : null;
99102
this.formatDatetime();
100103
},
101104
methods: {

src/api/forms/components/controls/FileInput.vue

+3-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
style="display: none"
3232
aria-labelledby="fileSelect"
3333
/>
34-
<button id="fileSelect" class="c-button" @click="selectFile">
34+
<button :id="fileButtonId" class="c-button" @click="selectFile">
3535
{{ name }}
3636
</button>
3737
<button
@@ -56,7 +56,8 @@ export default {
5656
emits: ['on-change'],
5757
data() {
5858
return {
59-
fileInfo: undefined
59+
fileInfo: undefined,
60+
fileButtonId: this.model.key ? 'form-' + this.model.key : null
6061
};
6162
},
6263
computed: {

src/api/forms/components/controls/LocatorField.vue

+6
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
<template>
2424
<MctTree
25+
:form-key="formKey"
2526
:is-selector-tree="true"
2627
:initial-selection="model.parent"
2728
@tree-item-selection="handleItemSelection"
@@ -43,6 +44,11 @@ export default {
4344
}
4445
},
4546
emits: ['on-change'],
47+
data() {
48+
return {
49+
formKey: this.model.key ? 'form-' + this.model.key : null
50+
};
51+
},
4652
methods: {
4753
handleItemSelection(item) {
4854
const data = {

src/api/forms/components/controls/NumberField.vue

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
<span class="form-control shell">
2525
<span class="field control" :class="model.cssClass">
2626
<input
27+
:id="fieldId"
2728
v-model="field"
2829
:aria-label="model.name"
2930
type="number"
@@ -49,7 +50,8 @@ export default {
4950
emits: ['on-change'],
5051
data() {
5152
return {
52-
field: this.model.value
53+
field: this.model.value,
54+
fieldId: this.model.key ? 'form-' + this.model.key : null
5355
};
5456
},
5557
mounted() {

src/api/forms/components/controls/SelectField.vue

+3-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
<template>
2424
<div class="form-control select-field">
2525
<select
26+
:id="fieldId"
2627
v-model="selected"
2728
required="model.required"
2829
name="mctControl"
@@ -47,7 +48,8 @@ export default {
4748
emits: ['on-change'],
4849
data() {
4950
return {
50-
selected: this.model.value
51+
selected: this.model.value,
52+
fieldId: this.model.key ? 'form-' + this.model.key : null
5153
};
5254
},
5355
methods: {

src/api/forms/components/controls/TextAreaField.vue

+4-8
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,7 @@
2323
<template>
2424
<span class="form-control shell">
2525
<span class="field control" :class="model.cssClass">
26-
<textarea
27-
:id="`${model.key}-textarea`"
28-
v-model="field"
29-
type="text"
30-
:size="model.size"
31-
@input="updateText()"
32-
>
26+
<textarea :id="fieldId" v-model="field" type="text" :size="model.size" @input="updateText()">
3327
</textarea>
3428
</span>
3529
</span>
@@ -48,11 +42,13 @@ export default {
4842
emits: ['on-change'],
4943
data() {
5044
return {
51-
field: this.model.value
45+
field: this.model.value,
46+
fieldId: null
5247
};
5348
},
5449
mounted() {
5550
this.updateText = throttle(this.updateText.bind(this), 500);
51+
this.fieldId = this.model.key ? 'form-' + this.model.key : null;
5652
},
5753
methods: {
5854
updateText() {

src/api/forms/components/controls/ToggleSwitchField.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<span class="form-control shell">
2525
<span class="field control" :class="model.cssClass">
2626
<ToggleSwitch
27-
id="switchId"
27+
:id="switchId"
2828
:checked="isChecked"
2929
:name="model.name"
3030
@change="toggleCheckBox"
@@ -53,7 +53,7 @@ export default {
5353
},
5454
data() {
5555
return {
56-
switchId: `toggleSwitch-${uuid}`,
56+
switchId: this.model.key ? 'form-' + this.model.key : `toggleSwitch-${uuid}`,
5757
isChecked: this.model.value
5858
};
5959
}

src/plugins/charts/scatter/plugin.js

-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ export default function () {
6363
name: 'Underlay ranges',
6464
control: 'scatter-plot-form-control',
6565
cssClass: 'l-input',
66-
key: 'scatterPlotForm',
6766
required: false,
6867
hideFromInspector: false,
6968
property: ['configuration', 'ranges'],

src/plugins/displayLayout/DisplayLayoutType.js

+4
Original file line numberDiff line numberDiff line change
@@ -37,27 +37,31 @@ export default function DisplayLayoutType() {
3737
form: [
3838
{
3939
name: 'Horizontal grid (px)',
40+
key: 'horizontalGrid',
4041
control: 'numberfield',
4142
cssClass: 'l-input-sm l-numeric',
4243
property: ['configuration', 'layoutGrid', 0],
4344
required: true
4445
},
4546
{
4647
name: 'Vertical grid (px)',
48+
key: 'verticalGrid',
4749
control: 'numberfield',
4850
cssClass: 'l-input-sm l-numeric',
4951
property: ['configuration', 'layoutGrid', 1],
5052
required: true
5153
},
5254
{
5355
name: 'Horizontal size (px)',
56+
key: 'horizontalSize',
5457
control: 'numberfield',
5558
cssClass: 'l-input-sm l-numeric',
5659
property: ['configuration', 'layoutDimensions', 0],
5760
required: false
5861
},
5962
{
6063
name: 'Vertical size (px)',
64+
key: 'verticalSize',
6165
control: 'numberfield',
6266
cssClass: 'l-input-sm l-numeric',
6367
property: ['configuration', 'layoutDimensions', 1],

src/plugins/gauge/GaugePlugin.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export default function () {
7373
}),
7474
control: 'select',
7575
cssClass: 'l-input-sm',
76-
key: 'gaugeController',
76+
key: 'gaugeType',
7777
property: ['configuration', 'gaugeController', 'gaugeType']
7878
},
7979
{

src/plugins/gauge/components/GaugeFormController.vue

+5-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<span class="form-control">
2525
<span class="field control" :class="model.cssClass">
2626
<ToggleSwitch
27-
:id="'gaugeToggle'"
27+
:id="fieldId"
2828
:checked="isUseTelemetryLimits"
2929
label="Use telemetry limits for minimum and maximum ranges"
3030
@change="toggleUseTelemetryLimits"
@@ -84,6 +84,8 @@
8484
</template>
8585

8686
<script>
87+
import { v4 as uuid } from 'uuid';
88+
8789
import ToggleSwitch from '@/ui/components/ToggleSwitch.vue';
8890

8991
export default {
@@ -106,7 +108,8 @@ export default {
106108
limitHigh: this.model.value.limitHigh,
107109
limitLow: this.model.value.limitLow,
108110
max: this.model.value.max,
109-
min: this.model.value.min
111+
min: this.model.value.min,
112+
fieldId: this.model.key ? 'form-' + this.model.key : 'gaugeToggle-' + uuid()
110113
};
111114
},
112115
methods: {

src/ui/components/SearchComponent.vue

+7
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
<template>
2323
<div class="c-search" v-bind="$attrs" :class="{ 'is-active': active }">
2424
<input
25+
:id="formKey"
2526
class="c-search__input"
2627
aria-label="Search Input"
2728
tabindex="0"
@@ -40,6 +41,12 @@
4041
export default {
4142
inheritAttrs: false,
4243
props: {
44+
formKey: {
45+
type: String,
46+
default() {
47+
return null;
48+
}
49+
},
4350
value: {
4451
type: String,
4552
default: ''

src/ui/layout/MctTree.vue

+7
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
<Search
3232
v-show="isSelectorTree"
3333
ref="shell-search"
34+
:form-key="formKey"
3435
class="c-search"
3536
:value="searchValue"
3637
@input="searchTree"
@@ -150,6 +151,12 @@ export default {
150151
return {};
151152
}
152153
},
154+
formKey: {
155+
type: String,
156+
default() {
157+
return null;
158+
}
159+
},
153160
syncTreeNavigation: {
154161
type: Boolean,
155162
required: false

0 commit comments

Comments
 (0)