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

mendersoftware / gui / 1081664682

22 Nov 2023 02:11PM UTC coverage: 82.798% (-17.2%) from 99.964%
1081664682

Pull #4214

gitlab-ci

tranchitella
fix: Fixed the infinite page redirects when the back button is pressed

Remove the location and navigate from the useLocationParams.setValue callback
dependencies as they change the set function that is presented in other
useEffect dependencies. This happens when the back button is clicked, which
leads to the location changing infinitely.

Changelog: Title
Ticket: MEN-6847
Ticket: MEN-6796

Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
Signed-off-by: Fabio Tranchitella <fabio.tranchitella@northern.tech>
Pull Request #4214: fix: Fixed the infinite page redirects when the back button is pressed

4319 of 6292 branches covered (0.0%)

8332 of 10063 relevant lines covered (82.8%)

191.0 hits per line

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

84.31
/src/js/components/common/forms/form.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, { useEffect } from 'react';
15
import { FormProvider, useForm } from 'react-hook-form';
16

17
import { Button } from '@mui/material';
18

19
import validator from 'validator';
20

21
const getErrorMsg = (validateMethod, args) => {
17✔
22
  switch (validateMethod) {
306!
23
    case 'isLength':
24
      if (args[0] === 1) {
68!
25
        return 'This field is required';
×
26
      } else if (args[0] > 1) {
68!
27
        return `Must be at least ${args[0]} characters long`;
68✔
28
      }
29
      break;
×
30
    case 'isAlpha':
31
      return 'This field must contain only letters';
×
32
    case 'isAlphanumeric':
33
      return 'This field must contain only letters or numbers';
×
34
    case 'isNumeric':
35
      return 'Please enter a valid code';
×
36
    case 'isEmail':
37
      return 'Please enter a valid email address';
176✔
38
    case 'isNot':
39
      if (args[0] === args[1]) {
62!
40
        return `This field should have a value other than ${args[0]}`;
×
41
      }
42
      break;
62✔
43
    default:
44
      return 'There is an error with this field';
×
45
  }
46
};
47

48
const tryApplyValidations = (value, validations, initialValidationResult) =>
17✔
49
  validations.split(',').reduce((accu, validation) => {
718✔
50
    if (!accu.isValid || !validation) {
1,510✔
51
      return accu;
363✔
52
    }
53
    var args = validation.split(':');
1,147✔
54
    var validateMethod = args.shift();
1,147✔
55
    // We use JSON.parse to convert the string values passed to the
56
    // correct type. Ex. 'isLength:1' will make '1' actually a number
57
    args = args.map(arg => JSON.parse(JSON.stringify(arg)));
1,147✔
58

59
    var tmpArgs = args;
1,147✔
60
    // We then merge two arrays, ending up with the value
61
    // to pass first, then options, if any. ['valueFromInput', 5]
62
    args = [value].concat(args);
1,147✔
63
    try {
1,147✔
64
      // So the next line of code is actually:
65
      // validator.isLength('valueFromInput', 5)
66
      if (!validator[validateMethod].apply(validator, args)) {
1,147✔
67
        return { errortext: getErrorMsg(validateMethod, tmpArgs), isValid: false };
244✔
68
      }
69
    } catch {
70
      const errortext = getErrorMsg(validateMethod, args) || '';
62✔
71
      return { errortext, isValid: !errortext };
62✔
72
    }
73
    return accu;
841✔
74
  }, initialValidationResult);
75

76
const runPasswordValidations = ({ required, value, validations, isValid, errortext }) => {
17✔
77
  if (required && !value) {
353!
78
    return { isValid: false, errortext: 'Password is required' };
×
79
  } else if (required || value) {
353✔
80
    isValid = tryApplyValidations(value, validations, { isValid, errortext }).isValid;
343✔
81
    return { isValid, errortext: !isValid ? 'Password too weak' : errortext };
343✔
82
  }
83
  return { isValid, errortext };
10✔
84
};
85

86
export const runValidations = ({ required, value, id, validations }) => {
17✔
87
  let isValid = true;
800✔
88
  let errortext = '';
800✔
89
  if (id && id.includes('password')) {
800✔
90
    return runPasswordValidations({ required, value, validations, isValid, errortext });
353✔
91
  } else {
92
    if (value || required) {
447✔
93
      return tryApplyValidations(validations.includes('trim') ? value.trim() : value, validations, { isValid, errortext });
375✔
94
    }
95
  }
96
  return { isValid, errortext };
72✔
97
};
98

99
export const Form = ({
17✔
100
  autocomplete,
101
  buttonColor,
102
  children,
103
  className = '',
452✔
104
  defaultValues = {},
710✔
105
  handleCancel,
106
  id,
107
  initialValues = {},
732✔
108
  onSubmit,
109
  showButtons,
110
  submitLabel
111
}) => {
112
  const methods = useForm({ mode: 'onChange', defaultValues });
922✔
113
  const {
114
    handleSubmit,
115
    formState: { isValid },
116
    setValue
117
  } = methods;
922✔
118

119
  useEffect(() => {
922✔
120
    Object.entries(initialValues).map(([key, value]) => setValue(key, value));
28✔
121
    // eslint-disable-next-line react-hooks/exhaustive-deps
122
  }, [JSON.stringify(initialValues), setValue]);
123

124
  return (
922✔
125
    <FormProvider {...methods}>
126
      <form autoComplete={autocomplete} className={className} id={id} noValidate onSubmit={handleSubmit(onSubmit)}>
127
        {children}
128
        {!!showButtons && (
1,684✔
129
          <div className="flexbox" style={{ justifyContent: 'flex-end', height: 'min-content', marginTop: 32 }}>
130
            {!!handleCancel && (
829✔
131
              <Button key="cancel" onClick={handleCancel} style={{ marginRight: 10, display: 'inline-block' }}>
132
                Cancel
133
              </Button>
134
            )}
135
            <Button variant="contained" type="submit" disabled={!isValid} color={buttonColor}>
136
              {submitLabel}
137
            </Button>
138
          </div>
139
        )}
140
      </form>
141
    </FormProvider>
142
  );
143
};
144

145
export default Form;
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