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

mendersoftware / gui / 901187442

pending completion
901187442

Pull #3795

gitlab-ci

mzedel
feat: increased chances of adopting our intended navigation patterns instead of unsupported browser navigation

Ticket: None
Changelog: None
Signed-off-by: Manuel Zedel <manuel.zedel@northern.tech>
Pull Request #3795: feat: increased chances of adopting our intended navigation patterns instead of unsupported browser navigation

4389 of 6365 branches covered (68.96%)

5 of 5 new or added lines in 1 file covered. (100.0%)

1729 existing lines in 165 files now uncovered.

8274 of 10019 relevant lines covered (82.58%)

144.86 hits per line

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

86.84
/src/js/components/common/forms/passwordinput.js
1
// Copyright 2016 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 from 'react';
15

16
import { CheckCircle as CheckIcon, Visibility as VisibilityIcon, VisibilityOff as VisibilityOffIcon } from '@mui/icons-material';
17
import { Button, FormControl, FormHelperText, IconButton, Input, InputAdornment, InputLabel } from '@mui/material';
18

19
import copy from 'copy-to-clipboard';
20
import generator from 'generate-password';
21

22
import { TIMEOUTS } from '../../../constants/appConstants';
23

24
const PasswordGenerateButtons = ({ clearPass, edit, generatePass }) => (
14✔
25
  <div className="pass-buttons">
5✔
26
    <Button color="primary" onClick={generatePass}>
27
      Generate
28
    </Button>
29
    {edit ? <Button onClick={clearPass}>Cancel</Button> : null}
5!
30
  </div>
31
);
32

33
export default class PasswordInput extends React.Component {
34
  constructor(props, context) {
35
    super(props, context);
22✔
36
    this.state = this._getState();
21✔
37
  }
38

39
  componentDidMount() {
40
    this.props.attachToForm(this); // Attaching the component to the form
21✔
41
  }
42
  componentWillUnmount() {
43
    this.props.detachFromForm(this); // Detaching if unmounting
21✔
44
  }
45
  componentDidUpdate(prevProps) {
46
    if (prevProps.className !== this.props.className) {
334!
47
      // resets state when "cancel" pressed
UNCOV
48
      this.setState(this._getState());
×
49
    }
50
  }
51
  _getState() {
52
    return {
21✔
53
      value: this.props.value || '',
42✔
54
      errortext: null,
55
      isValid: true,
56
      score: '',
57
      feedback: [],
58
      visible: false,
59
      copied: false
60
    };
61
  }
62
  setValue(event) {
63
    const value = event ? event.currentTarget.value : '';
142!
64
    this.setState({ value });
142✔
65
    if (this.props.create) {
142✔
66
      import(/* webpackChunkName: "zxcvbn" */ 'zxcvbn').then(({ default: zxcvbn }) => {
82✔
67
        const strength = zxcvbn(value);
82✔
68
        const score = strength.score;
82✔
69
        const feedback = strength.feedback.suggestions || [];
82!
70
        this.setState({ score, feedback });
82✔
71
        if (score > 3) {
82✔
72
          this.props.validate(this, value);
24✔
73
        } else {
74
          // if some weak pass exists, pass it to validate as "0", otherwise leave empty- if not required, blank is allowed but weak is not
75
          this.props.validate(this, value ? '0' : '');
58✔
76
        }
77
      });
78
    } else {
79
      this.props.validate(this, value);
60✔
80
    }
81
  }
82
  clearPass() {
UNCOV
83
    this.setValue();
×
UNCOV
84
    this.props.onClear();
×
UNCOV
85
    this.setState({ copied: false });
×
86
  }
87
  generatePass() {
88
    const self = this;
1✔
89
    const password = generator.generate({ length: 16, numbers: true });
1✔
90
    self.setValue({ currentTarget: { value: password } });
1✔
91
    copy(password);
1✔
92
    self.setState({ copied: true, visible: true });
1✔
93
    setTimeout(() => self.setState({ copied: false }), TIMEOUTS.fiveSeconds);
1✔
94
  }
95
  render() {
96
    const { className, create, defaultValue, disabled, edit, generate, handleKeyPress, id, InputLabelProps = {}, label, placeholder, required } = this.props;
355✔
97
    const { copied, errortext, feedback, score, visible, value } = this.state;
355✔
98
    const feedbackMessages = Boolean(errortext) && (
355✔
99
      <p className="help-text">
100
        {feedback.map((message, index) => (
101
          <React.Fragment key={`feedback-${index}`}>
128✔
102
            <span>{message}</span>
103
            <br />
104
          </React.Fragment>
105
        ))}
106
      </p>
107
    );
108

109
    return (
355✔
110
      <div id={`${id}-holder`} className={className}>
111
        <div className="password-wrapper">
112
          <FormControl error={Boolean(errortext)} className={required ? 'required' : ''}>
355✔
113
            <InputLabel htmlFor={id} {...InputLabelProps}>
114
              {label}
115
            </InputLabel>
116
            <Input
117
              id={id}
118
              name={id}
119
              type={visible ? 'text' : 'password'}
355✔
120
              defaultValue={defaultValue}
121
              placeholder={placeholder}
122
              value={value}
123
              disabled={disabled}
124
              style={{ width: 400 }}
125
              required={required}
126
              onChange={e => this.setValue(e)}
141✔
127
              onKeyPress={handleKeyPress}
128
              endAdornment={
129
                <InputAdornment position="end">
UNCOV
130
                  <IconButton onClick={() => this.setState({ visible: !visible })} size="large">
×
131
                    {visible ? <VisibilityIcon /> : <VisibilityOffIcon />}
355✔
132
                  </IconButton>
133
                </InputAdornment>
134
              }
135
            />
136
            <FormHelperText id="component-error-text">{errortext}</FormHelperText>
137
          </FormControl>
UNCOV
138
          {generate && !required && <PasswordGenerateButtons clearPass={() => this.clearPass()} edit={edit} generatePass={() => this.generatePass()} />}
✔
139
        </div>
140
        {copied ? <div className="green fadeIn margin-bottom-small">Copied to clipboard</div> : null}
355✔
141
        {create ? (
355✔
142
          <div>
143
            <div className="help-text" id="pass-strength">
144
              Strength: <meter max={4} min={0} value={score} high={3.9} optimum={4} low={2.5} />
145
              {score > 3 ? <CheckIcon className="fadeIn green" style={{ height: '18px', marginTop: '-3px', marginBottom: '-3px' }} /> : null}
256✔
146
            </div>
147
            {feedbackMessages}
148
            {generate && required && <PasswordGenerateButtons clearPass={() => this.clearPass()} edit={edit} generatePass={() => this.generatePass()} />}
1✔
149
          </div>
150
        ) : null}
151
      </div>
152
    );
153
  }
154
}
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