• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / gui / 951400782

pending completion
951400782

Pull #3900

gitlab-ci

web-flow
chore: bump @testing-library/jest-dom from 5.16.5 to 5.17.0

Bumps [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) from 5.16.5 to 5.17.0.
- [Release notes](https://github.com/testing-library/jest-dom/releases)
- [Changelog](https://github.com/testing-library/jest-dom/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/jest-dom/compare/v5.16.5...v5.17.0)

---
updated-dependencies:
- dependency-name: "@testing-library/jest-dom"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #3900: chore: bump @testing-library/jest-dom from 5.16.5 to 5.17.0

4446 of 6414 branches covered (69.32%)

8342 of 10084 relevant lines covered (82.73%)

186.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.27
/src/js/components/common/forms/keyvalueeditor.js
1
// Copyright 2021 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14
import React, { createRef, useEffect, useRef, useState } from 'react';
15

16
import { Clear as ClearIcon, Add as ContentAddIcon } from '@mui/icons-material';
17
import { Fab, FormControl, FormHelperText, IconButton, Input } from '@mui/material';
18
import { useTheme } from '@mui/material/styles';
19

20
const emptyInput = { helptip: null, key: '', value: '' };
18✔
21

22
export const KeyValueEditor = ({ disabled, errortext, input = {}, inputHelpTipsMap = {}, onInputChange, reset, showHelptips }) => {
18✔
23
  const theme = useTheme();
196✔
24
  const [inputs, setInputs] = useState([{ ...emptyInput }]);
196✔
25
  const [error, setError] = useState('');
196✔
26
  // need to useRef here to get positioning of
27
  let inputRefs = useRef([]);
196✔
28

29
  useEffect(() => {
196✔
30
    const newInputs = Object.keys(input).length
19✔
31
      ? Object.entries(input).map(([key, value]) => ({ helptip: inputHelpTipsMap[key.toLowerCase()], key, ref: createRef(), value }))
9✔
32
      : [{ ...emptyInput, ref: createRef() }];
33
    inputRefs.current = newInputs.map((_, i) => inputRefs.current[i] ?? createRef());
23✔
34
    setInputs(newInputs);
19✔
35
  }, [reset]);
36

37
  const onClearClick = () => {
196✔
38
    const changedInputs = [{ ...emptyInput }];
×
39
    setInputs(changedInputs);
×
40
    const inputObject = reducePairs(changedInputs);
×
41
    onInputChange(inputObject);
×
42
  };
43

44
  const updateInputs = (key, index, event) => {
196✔
45
    let changedInputs = [...inputs];
148✔
46
    const {
47
      target: { value }
48
    } = event;
148✔
49
    changedInputs[index][key] = value;
148✔
50
    changedInputs[index].helptip = null;
148✔
51
    const normalizedKey = changedInputs[index].key.toLowerCase();
148✔
52
    if (inputHelpTipsMap[normalizedKey]) {
148✔
53
      changedInputs[index].helptip = inputHelpTipsMap[normalizedKey];
1✔
54
    }
55
    setInputs(changedInputs);
148✔
56
    const inputObject = reducePairs(changedInputs);
148✔
57
    if (changedInputs.every(item => item.key && item.value) && changedInputs.length !== Object.keys(inputObject).length) {
208✔
58
      setError('Duplicate keys exist, only the last set value will be submitted');
10✔
59
    } else {
60
      setError('');
138✔
61
    }
62
    onInputChange(inputObject);
148✔
63
  };
64

65
  const reducePairs = listOfPairs => listOfPairs.reduce((accu, item) => ({ ...accu, ...(item.value ? { [item.key]: item.value } : {}) }), {});
208✔
66

67
  const addKeyValue = () => {
196✔
68
    const changedInputs = [...inputs, { ...emptyInput, ref: createRef() }];
3✔
69
    inputRefs.current = changedInputs.map((_, i) => inputRefs.current[i] ?? createRef());
6✔
70
    setInputs(changedInputs);
3✔
71
    setError('');
3✔
72
  };
73

74
  const removeInput = index => {
196✔
75
    let changedInputs = [...inputs];
×
76
    changedInputs.splice(index, 1);
×
77
    inputRefs.current = changedInputs.map((_, i) => inputRefs.current[i] ?? createRef());
×
78
    setInputs(changedInputs);
×
79
    const inputObject = reducePairs(changedInputs);
×
80
    onInputChange(inputObject);
×
81
    setError('');
×
82
  };
83

84
  const getHelptipPosition = ref => {
196✔
85
    const { offsetHeight, offsetLeft, offsetTop } = ref.current.closest('.key-value-container');
1✔
86
    const top = offsetTop + offsetHeight / 3;
1✔
87
    const left = offsetLeft - 15;
1✔
88
    return { left, top };
1✔
89
  };
90

91
  return (
196✔
92
    <div>
93
      {inputs.map((input, index) => {
94
        const hasError = Boolean(index === inputs.length - 1 && (errortext || error));
264✔
95
        const hasRemovalDisabled = !(inputs[index].key && inputs[index].value);
264✔
96
        const Helptip = inputs[index].helptip?.component;
264✔
97
        const ref = inputRefs.current[index];
264✔
98
        return (
264✔
99
          <div className="key-value-container relative" key={index}>
100
            <FormControl>
101
              <Input value={input.key} placeholder="Key" inputRef={ref} onChange={e => updateInputs('key', index, e)} type="text" />
64✔
102
              {hasError && <FormHelperText>{errortext || error}</FormHelperText>}
332✔
103
            </FormControl>
104
            <FormControl>
105
              <Input value={`${input.value}`} placeholder="Value" onChange={e => updateInputs('value', index, e)} type="text" />
84✔
106
            </FormControl>
107
            {inputs.length > 1 && !hasRemovalDisabled ? (
646✔
108
              <IconButton disabled={disabled || hasRemovalDisabled} onClick={() => removeInput(index)} size="large">
✔
109
                <ClearIcon fontSize="small" />
110
              </IconButton>
111
            ) : (
112
              <span />
113
            )}
114
            {showHelptips && Helptip && ref.current && <Helptip anchor={getHelptipPosition(ref)} {...inputs[index].helptip.props} />}
282✔
115
          </div>
116
        );
117
      })}
118
      <div className="key-value-container">
119
        <div style={{ minWidth: theme.spacing(30) }}>
120
          <Fab
121
            disabled={disabled || !inputs[inputs.length - 1].key || !inputs[inputs.length - 1].value}
532✔
122
            style={{ marginBottom: 10 }}
123
            color="secondary"
124
            size="small"
125
            onClick={addKeyValue}
126
          >
127
            <ContentAddIcon />
128
          </Fab>
129
        </div>
130
        <div style={{ minWidth: theme.spacing(30) }} />
131
        {inputs.length > 1 ? (
196✔
132
          <a className="margin-left-small" onClick={onClearClick}>
133
            clear all
134
          </a>
135
        ) : (
136
          <div />
137
        )}
138
      </div>
139
    </div>
140
  );
141
};
142

143
export default KeyValueEditor;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc