@plesk/ui-library 3.27.0 → 3.27.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/components/Dialog/Dialog.js +11 -2
- package/cjs/components/Drawer/DrawerProgress.js +15 -1
- package/cjs/components/FormFieldPassword/FormFieldPassword.js +24 -214
- package/cjs/components/FormFieldPassword/PasswordMeter.js +81 -0
- package/cjs/components/FormFieldPassword/estimatePassword.js +203 -0
- package/cjs/components/FormFieldPassword/generatePassword.js +21 -0
- package/cjs/components/FormFieldPassword/index.js +5 -5
- package/cjs/components/Icon/Icon.js +1 -1
- package/cjs/components/List/List.js +1 -1
- package/cjs/components/ProgressDialog/ProgressDialog.js +2 -1
- package/cjs/components/Rating/images/rating.svg +5 -5
- package/cjs/index.js +1 -1
- package/dist/images/rating.svg +5 -5
- package/dist/plesk-ui-library-rtl.css +1 -1
- package/dist/plesk-ui-library-rtl.css.map +1 -1
- package/dist/plesk-ui-library.css +1 -1
- package/dist/plesk-ui-library.css.map +1 -1
- package/dist/plesk-ui-library.js +336 -309
- package/dist/plesk-ui-library.js.map +1 -1
- package/dist/plesk-ui-library.min.js +5 -5
- package/dist/plesk-ui-library.min.js.map +1 -1
- package/esm/components/Dialog/Dialog.js +11 -2
- package/esm/components/Drawer/DrawerProgress.js +16 -2
- package/esm/components/FormFieldPassword/FormFieldPassword.js +22 -206
- package/esm/components/FormFieldPassword/PasswordMeter.js +61 -0
- package/esm/components/FormFieldPassword/estimatePassword.js +187 -0
- package/esm/components/FormFieldPassword/generatePassword.js +14 -0
- package/esm/components/FormFieldPassword/index.js +3 -2
- package/esm/components/Icon/Icon.js +1 -1
- package/esm/components/List/List.js +1 -1
- package/esm/components/ProgressDialog/ProgressDialog.js +2 -1
- package/esm/components/Rating/images/rating.svg +5 -5
- package/esm/index.js +1 -1
- package/package.json +13 -8
- package/styleguide/build/bundle.f38c467d.js +2 -0
- package/styleguide/build/{bundle.ff1f903a.js.LICENSE.txt → bundle.f38c467d.js.LICENSE.txt} +0 -0
- package/styleguide/images/rating.svg +5 -5
- package/styleguide/index.html +2 -2
- package/types/package.d.ts +5 -0
- package/types/src/components/FormFieldPassword/FormFieldPassword.d.ts +91 -0
- package/types/src/components/FormFieldPassword/PasswordMeter.d.ts +9 -0
- package/types/src/components/FormFieldPassword/estimatePassword.d.ts +13 -0
- package/types/src/components/FormFieldPassword/index.d.ts +2 -0
- package/cjs/components/FormFieldPassword/passwordScore.js +0 -131
- package/esm/components/FormFieldPassword/passwordScore.js +0 -122
- package/styleguide/build/bundle.ff1f903a.js +0 -2
|
@@ -40,6 +40,7 @@ const Dialog = ({
|
|
|
40
40
|
closable,
|
|
41
41
|
onClose,
|
|
42
42
|
closingConfirmation,
|
|
43
|
+
canClose,
|
|
43
44
|
...props
|
|
44
45
|
}) => {
|
|
45
46
|
const [isVisible, setIsVisible] = useState(isOpen);
|
|
@@ -150,8 +151,8 @@ const Dialog = ({
|
|
|
150
151
|
className: classNames(baseClassName, className),
|
|
151
152
|
isOpen: isVisible,
|
|
152
153
|
onClose: onCloseWithConfirmation,
|
|
153
|
-
canCloseOnBackdropClick: closable,
|
|
154
|
-
canCloseOnEscapePress: closable,
|
|
154
|
+
canCloseOnBackdropClick: canClose && closable,
|
|
155
|
+
canCloseOnEscapePress: canClose && closable,
|
|
155
156
|
size: size
|
|
156
157
|
}, props), (title || subtitle || actions) && /*#__PURE__*/React.createElement("header", {
|
|
157
158
|
className: `${baseClassName}__header`
|
|
@@ -174,6 +175,7 @@ const Dialog = ({
|
|
|
174
175
|
className: `${baseClassName}__header-actions`
|
|
175
176
|
}, actions, closable && /*#__PURE__*/React.createElement(Button, {
|
|
176
177
|
className: `${baseClassName}__header-close`,
|
|
178
|
+
disabled: !canClose,
|
|
177
179
|
ghost: true,
|
|
178
180
|
size: "lg",
|
|
179
181
|
icon: "cross-mark",
|
|
@@ -279,6 +281,12 @@ Dialog.propTypes = {
|
|
|
279
281
|
*/
|
|
280
282
|
closable: PropTypes.bool,
|
|
281
283
|
|
|
284
|
+
/**
|
|
285
|
+
* Disable close dialog button
|
|
286
|
+
* @since 4.0.0
|
|
287
|
+
*/
|
|
288
|
+
canClose: PropTypes.bool,
|
|
289
|
+
|
|
282
290
|
/**
|
|
283
291
|
* On close event handler. Called immediately after dialog closed by "cancel" button or "Esc" key.
|
|
284
292
|
* @since 0.0.68
|
|
@@ -322,6 +330,7 @@ Dialog.defaultProps = {
|
|
|
322
330
|
form: undefined,
|
|
323
331
|
size: 'md',
|
|
324
332
|
closable: true,
|
|
333
|
+
canClose: true,
|
|
325
334
|
onClose: undefined,
|
|
326
335
|
closingConfirmation: undefined,
|
|
327
336
|
children: undefined,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
2
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
3
3
|
// Copyright 1999-2019. Plesk International GmbH. All rights reserved.
|
|
4
|
-
import React, { Component, Fragment } from 'react';
|
|
4
|
+
import React, { Component, Fragment, isValidElement, cloneElement } from 'react';
|
|
5
5
|
import Button from '../Button';
|
|
6
6
|
import Translate from '../Translate';
|
|
7
7
|
import Progress from '../Progress';
|
|
@@ -9,6 +9,20 @@ import ProgressStep, { STATUS_DONE, STATUS_ERROR, STATUS_NOT_STARTED } from '../
|
|
|
9
9
|
import { CLS_PREFIX } from '../../constants';
|
|
10
10
|
import { safeInvoke } from '../utils';
|
|
11
11
|
|
|
12
|
+
const renderAdditionalButtons = buttons => {
|
|
13
|
+
const buttonProcessing = button => {
|
|
14
|
+
if ( /*#__PURE__*/isValidElement(button) && button.type === Button) {
|
|
15
|
+
return /*#__PURE__*/cloneElement(button, {
|
|
16
|
+
size: 'lg'
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return button;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
return Array.isArray(buttons) ? buttons.map(buttonProcessing) : buttonProcessing(buttons);
|
|
24
|
+
};
|
|
25
|
+
|
|
12
26
|
class DrawerProgress extends Component {
|
|
13
27
|
constructor(...args) {
|
|
14
28
|
super(...args);
|
|
@@ -125,7 +139,7 @@ class DrawerProgress extends Component {
|
|
|
125
139
|
}, step)))));
|
|
126
140
|
const footer = hasFooter ? /*#__PURE__*/React.createElement("div", {
|
|
127
141
|
className: `${baseClassName}__footer`
|
|
128
|
-
}, buttons, canCancel && /*#__PURE__*/React.createElement(Button, {
|
|
142
|
+
}, renderAdditionalButtons(buttons), canCancel && /*#__PURE__*/React.createElement(Button, {
|
|
129
143
|
onClick: this.handleCancel,
|
|
130
144
|
size: "lg"
|
|
131
145
|
}, /*#__PURE__*/React.createElement(Translate, {
|
|
@@ -1,32 +1,21 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
2
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
3
|
-
// Copyright 1999-
|
|
3
|
+
// Copyright 1999-2022. Plesk International GmbH. All rights reserved.
|
|
4
4
|
import React, { Component, Fragment, createRef } from 'react';
|
|
5
|
-
import PropTypes from 'prop-types';
|
|
6
5
|
import classNames from 'classnames';
|
|
7
6
|
import { CLS_PREFIX } from '../../constants';
|
|
8
7
|
import Button from '../Button';
|
|
9
8
|
import FormField from '../FormField';
|
|
10
9
|
import Input from '../Input';
|
|
11
|
-
import Popover from '../Popover';
|
|
12
10
|
import Translate from '../Translate';
|
|
13
|
-
import
|
|
11
|
+
import PasswordMeter from './PasswordMeter';
|
|
12
|
+
import generatePassword from './generatePassword';
|
|
14
13
|
import locale from './locale/en-US';
|
|
15
|
-
|
|
16
|
-
upper: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
|
17
|
-
lower: 'abcdefghijklmnopqrstuvwxyz',
|
|
18
|
-
number: '0123456789',
|
|
19
|
-
special: '!@#$%^&*?_~'
|
|
20
|
-
};
|
|
21
|
-
export const generatePassword = () => {
|
|
22
|
-
const password = ['upper', 'lower', 'lower', 'lower', 'number', 'number', 'special', 'number', 'upper', 'upper', 'lower', 'lower', 'lower', 'lower', 'lower', 'lower'];
|
|
23
|
-
return password.sort((a, b) => Math.floor(b.length * Math.random()) - Math.floor(a.length * Math.random())).map(symbolClass => symbolClasses[symbolClass][Math.floor(symbolClasses[symbolClass].length * Math.random())]).join('');
|
|
24
|
-
};
|
|
14
|
+
|
|
25
15
|
/**
|
|
26
16
|
* `FormFieldPassword` component provides secure way to enter a password.
|
|
27
17
|
* @since 0.0.58
|
|
28
18
|
*/
|
|
29
|
-
|
|
30
19
|
class FormFieldPassword extends Component {
|
|
31
20
|
constructor(...args) {
|
|
32
21
|
super(...args);
|
|
@@ -55,117 +44,6 @@ class FormFieldPassword extends Component {
|
|
|
55
44
|
_defineProperty(this, "handleBlur", this.handleClosePasswordMeter);
|
|
56
45
|
}
|
|
57
46
|
|
|
58
|
-
passwordScore(value) {
|
|
59
|
-
if (!value) {
|
|
60
|
-
return {
|
|
61
|
-
intent: null,
|
|
62
|
-
strength: null,
|
|
63
|
-
unusedRules: []
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const {
|
|
68
|
-
passwordScoreRules
|
|
69
|
-
} = this.props;
|
|
70
|
-
const {
|
|
71
|
-
score,
|
|
72
|
-
unusedRules
|
|
73
|
-
} = passwordScore(value, passwordScoreRules);
|
|
74
|
-
let intent = 'success';
|
|
75
|
-
let strength = /*#__PURE__*/React.createElement(Translate, {
|
|
76
|
-
content: "FormFieldPassword.strengthVeryStrong",
|
|
77
|
-
fallback: locale.strengthVeryStrong
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
if (score < 16) {
|
|
81
|
-
intent = 'danger';
|
|
82
|
-
strength = /*#__PURE__*/React.createElement(Translate, {
|
|
83
|
-
content: "FormFieldPassword.strengthVeryWeak",
|
|
84
|
-
fallback: locale.strengthVeryWeak
|
|
85
|
-
});
|
|
86
|
-
} else if (score < 25) {
|
|
87
|
-
intent = 'danger';
|
|
88
|
-
strength = /*#__PURE__*/React.createElement(Translate, {
|
|
89
|
-
content: "FormFieldPassword.strengthWeak",
|
|
90
|
-
fallback: locale.strengthWeak
|
|
91
|
-
});
|
|
92
|
-
} else if (score < 35) {
|
|
93
|
-
intent = 'warning';
|
|
94
|
-
strength = /*#__PURE__*/React.createElement(Translate, {
|
|
95
|
-
content: "FormFieldPassword.strengthMedium",
|
|
96
|
-
fallback: locale.strengthMedium
|
|
97
|
-
});
|
|
98
|
-
} else if (score < 45) {
|
|
99
|
-
intent = 'success';
|
|
100
|
-
strength = /*#__PURE__*/React.createElement(Translate, {
|
|
101
|
-
content: "FormFieldPassword.strengthStrong",
|
|
102
|
-
fallback: locale.strengthStrong
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return {
|
|
107
|
-
intent,
|
|
108
|
-
strength,
|
|
109
|
-
unusedRules
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
renderPasswordMeter(value, target) {
|
|
114
|
-
const {
|
|
115
|
-
passwordMeterVisible
|
|
116
|
-
} = this.state;
|
|
117
|
-
const {
|
|
118
|
-
passwordMeterProps
|
|
119
|
-
} = this.props;
|
|
120
|
-
const {
|
|
121
|
-
intent,
|
|
122
|
-
strength,
|
|
123
|
-
unusedRules
|
|
124
|
-
} = this.passwordScore(value);
|
|
125
|
-
return /*#__PURE__*/React.createElement(Popover, _extends({
|
|
126
|
-
visible: passwordMeterVisible && !!value,
|
|
127
|
-
target: target,
|
|
128
|
-
targetRef: this.targetRef,
|
|
129
|
-
placement: "bottom-right",
|
|
130
|
-
intent: intent,
|
|
131
|
-
canCloseOnOutsideClick: false,
|
|
132
|
-
canCloseOnEscapePress: false,
|
|
133
|
-
onClose: this.handleClosePasswordMeter
|
|
134
|
-
}, passwordMeterProps), /*#__PURE__*/React.createElement(Translate, {
|
|
135
|
-
content: "FormFieldPassword.passwordStrength",
|
|
136
|
-
fallback: locale.passwordStrength,
|
|
137
|
-
params: {
|
|
138
|
-
strength: /*#__PURE__*/React.createElement("b", null, strength)
|
|
139
|
-
}
|
|
140
|
-
}), /*#__PURE__*/React.createElement("br", null), unusedRules.length ? /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(Translate, {
|
|
141
|
-
content: "FormFieldPassword.improvePassword",
|
|
142
|
-
fallback: locale.improvePassword
|
|
143
|
-
}), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement("ul", null, unusedRules.slice(0, 3).map(({
|
|
144
|
-
rule
|
|
145
|
-
}, index) => {
|
|
146
|
-
const {
|
|
147
|
-
name
|
|
148
|
-
} = rule;
|
|
149
|
-
let {
|
|
150
|
-
message
|
|
151
|
-
} = rule;
|
|
152
|
-
|
|
153
|
-
if (name && !message) {
|
|
154
|
-
message = /*#__PURE__*/React.createElement(Translate, {
|
|
155
|
-
content: `FormFieldPassword.${name}`,
|
|
156
|
-
fallback: locale[name]
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return /*#__PURE__*/React.createElement("li", {
|
|
161
|
-
key: name || index.toString()
|
|
162
|
-
}, message);
|
|
163
|
-
}))) : /*#__PURE__*/React.createElement(Translate, {
|
|
164
|
-
content: "FormFieldPassword.yourPasswordIsStrong",
|
|
165
|
-
fallback: locale.yourPasswordIsStrong
|
|
166
|
-
}));
|
|
167
|
-
}
|
|
168
|
-
|
|
169
47
|
renderGenerateButton({
|
|
170
48
|
setValue,
|
|
171
49
|
isDisabled
|
|
@@ -207,12 +85,15 @@ class FormFieldPassword extends Component {
|
|
|
207
85
|
hideGenerateButton,
|
|
208
86
|
hidePasswordMeter,
|
|
209
87
|
passwordMeterProps,
|
|
210
|
-
passwordScoreRules,
|
|
211
88
|
size,
|
|
212
89
|
autoFocus,
|
|
213
90
|
autoComplete,
|
|
214
91
|
...props
|
|
215
92
|
} = this.props;
|
|
93
|
+
const {
|
|
94
|
+
visible,
|
|
95
|
+
passwordMeterVisible
|
|
96
|
+
} = this.state;
|
|
216
97
|
return /*#__PURE__*/React.createElement(FormField, _extends({
|
|
217
98
|
className: classNames(baseClassName, className)
|
|
218
99
|
}, props), ({
|
|
@@ -222,18 +103,18 @@ class FormFieldPassword extends Component {
|
|
|
222
103
|
setValue,
|
|
223
104
|
isDisabled
|
|
224
105
|
}) => {
|
|
106
|
+
const value = getValue('');
|
|
225
107
|
const input = /*#__PURE__*/React.createElement(Input, {
|
|
226
108
|
id: getId(),
|
|
227
109
|
name: getName(),
|
|
228
|
-
type:
|
|
229
|
-
value:
|
|
110
|
+
type: visible ? 'text' : 'password',
|
|
111
|
+
value: value,
|
|
230
112
|
onChange: e => {
|
|
231
113
|
setValue(e.target.value);
|
|
232
114
|
this.setState({
|
|
233
115
|
passwordMeterVisible: true
|
|
234
116
|
});
|
|
235
117
|
},
|
|
236
|
-
onFocus: this.handleFocus,
|
|
237
118
|
onBlur: this.handleBlur,
|
|
238
119
|
autoFocus: autoFocus,
|
|
239
120
|
autoComplete: autoComplete,
|
|
@@ -242,8 +123,8 @@ class FormFieldPassword extends Component {
|
|
|
242
123
|
suffix: hideShowButton ? null : /*#__PURE__*/React.createElement(Button, {
|
|
243
124
|
className: `${baseClassName}__button--show`,
|
|
244
125
|
onClick: this.handleToggleClick,
|
|
245
|
-
icon:
|
|
246
|
-
tooltip:
|
|
126
|
+
icon: visible ? 'visible' : 'invisible',
|
|
127
|
+
tooltip: visible ? /*#__PURE__*/React.createElement(Translate, {
|
|
247
128
|
content: "FormFieldPassword.hidePassword",
|
|
248
129
|
fallback: locale.hidePassword
|
|
249
130
|
}) : /*#__PURE__*/React.createElement(Translate, {
|
|
@@ -262,7 +143,12 @@ class FormFieldPassword extends Component {
|
|
|
262
143
|
className: classNames(`${baseClassName}__control`, `${baseClassName}__control--${size}`)
|
|
263
144
|
}, /*#__PURE__*/React.createElement("div", {
|
|
264
145
|
className: classNames(`${baseClassName}__field`, `${baseClassName}__field--${size}`)
|
|
265
|
-
}, hidePasswordMeter ? input :
|
|
146
|
+
}, hidePasswordMeter ? input : /*#__PURE__*/React.createElement(PasswordMeter, _extends({
|
|
147
|
+
value: value,
|
|
148
|
+
targetRef: this.targetRef,
|
|
149
|
+
visible: passwordMeterVisible && value !== '',
|
|
150
|
+
onClose: this.handleClosePasswordMeter
|
|
151
|
+
}, passwordMeterProps), input)), hideGenerateButton ? null : this.renderGenerateButton({
|
|
266
152
|
setValue,
|
|
267
153
|
isDisabled
|
|
268
154
|
}));
|
|
@@ -271,87 +157,17 @@ class FormFieldPassword extends Component {
|
|
|
271
157
|
|
|
272
158
|
}
|
|
273
159
|
|
|
274
|
-
FormFieldPassword
|
|
275
|
-
/**
|
|
276
|
-
* Is show button hidden?
|
|
277
|
-
* @since 0.0.59
|
|
278
|
-
*/
|
|
279
|
-
hideShowButton: PropTypes.bool,
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Is generate button hidden?
|
|
283
|
-
* @since 0.0.59
|
|
284
|
-
*/
|
|
285
|
-
hideGenerateButton: PropTypes.bool,
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* Is password meter hidden?
|
|
289
|
-
* @since 0.0.59
|
|
290
|
-
*/
|
|
291
|
-
hidePasswordMeter: PropTypes.bool,
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* Additional props for password meter. . See [Popover](#!/Popover) for more information.
|
|
295
|
-
* @since 1.5.6
|
|
296
|
-
*/
|
|
297
|
-
passwordMeterProps: PropTypes.object,
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* A set of custom password score rules.
|
|
301
|
-
* @since 3.21.0
|
|
302
|
-
*/
|
|
303
|
-
passwordScoreRules: PropTypes.arrayOf(PropTypes.shape({
|
|
304
|
-
name: PropTypes.string,
|
|
305
|
-
message: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
|
|
306
|
-
score: PropTypes.func.isRequired
|
|
307
|
-
})),
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* Size of the control
|
|
311
|
-
* @since 1.5.6
|
|
312
|
-
*/
|
|
313
|
-
size: PropTypes.oneOf(['md', 'lg', 'xl', 'fill']),
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* The browser will automatically focus on the component upon rendering the screen
|
|
317
|
-
* @since 1.9.0
|
|
318
|
-
*/
|
|
319
|
-
autoFocus: PropTypes.bool,
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* Prevent password autocompletion.
|
|
323
|
-
* @since 2.5.1
|
|
324
|
-
*/
|
|
325
|
-
autoComplete: PropTypes.oneOf(['new-password']),
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* A render function for customizing the password generation button.
|
|
329
|
-
* @since 3.13.0
|
|
330
|
-
*/
|
|
331
|
-
generateButton: PropTypes.func,
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* @ignore
|
|
335
|
-
*/
|
|
336
|
-
className: PropTypes.string,
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* @ignore
|
|
340
|
-
*/
|
|
341
|
-
baseClassName: PropTypes.string
|
|
342
|
-
};
|
|
343
|
-
FormFieldPassword.defaultProps = {
|
|
160
|
+
_defineProperty(FormFieldPassword, "defaultProps", {
|
|
344
161
|
hideShowButton: false,
|
|
345
162
|
generateButton: undefined,
|
|
346
163
|
hideGenerateButton: false,
|
|
347
164
|
hidePasswordMeter: false,
|
|
348
165
|
passwordMeterProps: {},
|
|
349
|
-
passwordScoreRules: undefined,
|
|
350
166
|
size: 'md',
|
|
351
167
|
autoFocus: undefined,
|
|
352
168
|
autoComplete: undefined,
|
|
353
169
|
className: undefined,
|
|
354
170
|
baseClassName: `${CLS_PREFIX}form-field-password`
|
|
355
|
-
};
|
|
356
|
-
|
|
171
|
+
});
|
|
172
|
+
|
|
357
173
|
export default FormFieldPassword;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
+
// Copyright 1999-2022. Plesk International GmbH. All rights reserved.
|
|
3
|
+
import React, { Fragment, useState, useEffect } from 'react';
|
|
4
|
+
import Popover from '../Popover';
|
|
5
|
+
import Translate from '../Translate';
|
|
6
|
+
import estimatePassword, { DEFAULT_RULES } from './estimatePassword';
|
|
7
|
+
import locale from './locale/en-US';
|
|
8
|
+
const strengthIntents = {
|
|
9
|
+
VeryWeak: 'danger',
|
|
10
|
+
Weak: 'danger',
|
|
11
|
+
Medium: 'warning',
|
|
12
|
+
Strong: 'success',
|
|
13
|
+
VeryStrong: 'success'
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const PasswordMeter = ({
|
|
17
|
+
value,
|
|
18
|
+
visible,
|
|
19
|
+
onEstimate,
|
|
20
|
+
children,
|
|
21
|
+
...props
|
|
22
|
+
}) => {
|
|
23
|
+
const [result, setResult] = useState(null);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!visible) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
Promise.resolve(onEstimate ? onEstimate(value, estimatePassword, DEFAULT_RULES) : estimatePassword(value)).then(result => {
|
|
30
|
+
setResult(result);
|
|
31
|
+
});
|
|
32
|
+
}, [visible, value, onEstimate]);
|
|
33
|
+
return /*#__PURE__*/React.createElement(Popover, _extends({
|
|
34
|
+
visible: visible && result !== null,
|
|
35
|
+
target: children,
|
|
36
|
+
placement: "bottom-right",
|
|
37
|
+
intent: result ? strengthIntents[result.strength] : undefined,
|
|
38
|
+
canCloseOnOutsideClick: false,
|
|
39
|
+
canCloseOnEscapePress: false
|
|
40
|
+
}, props), result !== null && result !== void 0 && result.strength ? /*#__PURE__*/React.createElement(Translate, {
|
|
41
|
+
component: "div",
|
|
42
|
+
content: "FormFieldPassword.passwordStrength",
|
|
43
|
+
fallback: locale.passwordStrength,
|
|
44
|
+
params: {
|
|
45
|
+
strength: /*#__PURE__*/React.createElement("b", null, /*#__PURE__*/React.createElement(Translate, {
|
|
46
|
+
content: `FormFieldPassword.strength${result === null || result === void 0 ? void 0 : result.strength}`,
|
|
47
|
+
fallback: locale[`strength${result === null || result === void 0 ? void 0 : result.strength}`]
|
|
48
|
+
}))
|
|
49
|
+
}
|
|
50
|
+
}) : null, result !== null && result !== void 0 && result.suggestions.length ? /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(Translate, {
|
|
51
|
+
content: "FormFieldPassword.improvePassword",
|
|
52
|
+
fallback: locale.improvePassword
|
|
53
|
+
}), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement("ul", null, result.suggestions.slice(0, 3).map((suggestion, index) => /*#__PURE__*/React.createElement("li", {
|
|
54
|
+
key: index.toString()
|
|
55
|
+
}, suggestion)))) : /*#__PURE__*/React.createElement(Translate, {
|
|
56
|
+
content: "FormFieldPassword.yourPasswordIsStrong",
|
|
57
|
+
fallback: locale.yourPasswordIsStrong
|
|
58
|
+
}));
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export default PasswordMeter;
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// Copyright 1999-2022. Plesk International GmbH. All rights reserved.
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import Translate from '../Translate';
|
|
4
|
+
import locale from './locale/en-US';
|
|
5
|
+
export const DEFAULT_RULES = [{
|
|
6
|
+
name: 'passwordTooShort',
|
|
7
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
8
|
+
content: `FormFieldPassword.passwordTooShort`,
|
|
9
|
+
fallback: locale.passwordTooShort
|
|
10
|
+
}),
|
|
11
|
+
|
|
12
|
+
score(passwd) {
|
|
13
|
+
return passwd.length < 5 ? -1 : 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
}, {
|
|
17
|
+
name: 'passwordLength',
|
|
18
|
+
|
|
19
|
+
score(passwd) {
|
|
20
|
+
if (passwd.length < 5) {
|
|
21
|
+
return 3;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (passwd.length > 4 && passwd.length < 8) {
|
|
25
|
+
return 6;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (passwd.length > 7 && passwd.length < 16) {
|
|
29
|
+
return 12;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return 18;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
}, {
|
|
36
|
+
name: 'lettersLowerCase',
|
|
37
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
38
|
+
content: `FormFieldPassword.lettersLowerCase`,
|
|
39
|
+
fallback: locale.lettersLowerCase
|
|
40
|
+
}),
|
|
41
|
+
|
|
42
|
+
score(passwd) {
|
|
43
|
+
// [verified] at least one lower case letter
|
|
44
|
+
return passwd.match(/[a-z]/) ? 1 : -1;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
}, {
|
|
48
|
+
name: 'lettersUpperCase',
|
|
49
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
50
|
+
content: `FormFieldPassword.lettersUpperCase`,
|
|
51
|
+
fallback: locale.lettersUpperCase
|
|
52
|
+
}),
|
|
53
|
+
|
|
54
|
+
score(passwd) {
|
|
55
|
+
// [verified] at least one upper case letter
|
|
56
|
+
return passwd.match(/[A-Z]/) ? 5 : -1;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
}, {
|
|
60
|
+
name: 'numbers1',
|
|
61
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
62
|
+
content: `FormFieldPassword.numbers1`,
|
|
63
|
+
fallback: locale.numbers1
|
|
64
|
+
}),
|
|
65
|
+
|
|
66
|
+
score(passwd) {
|
|
67
|
+
// [verified] at least one number
|
|
68
|
+
return passwd.match(/\d+/) ? 5 : -1;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
}, {
|
|
72
|
+
name: 'numbers3',
|
|
73
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
74
|
+
content: `FormFieldPassword.numbers3`,
|
|
75
|
+
fallback: locale.numbers3
|
|
76
|
+
}),
|
|
77
|
+
|
|
78
|
+
score(passwd) {
|
|
79
|
+
// [verified] at least three numbers
|
|
80
|
+
return passwd.match(/(.*[0-9].*[0-9].*[0-9])/) ? 5 : -1;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
}, {
|
|
84
|
+
name: 'specialChar1',
|
|
85
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
86
|
+
content: `FormFieldPassword.specialChar1`,
|
|
87
|
+
fallback: locale.specialChar1
|
|
88
|
+
}),
|
|
89
|
+
|
|
90
|
+
score(passwd) {
|
|
91
|
+
// [verified] at least one special character
|
|
92
|
+
return passwd.match(/[!@#$%^&*?_~]/) ? 5 : -1;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
}, {
|
|
96
|
+
name: 'specialChar2',
|
|
97
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
98
|
+
content: `FormFieldPassword.specialChar2`,
|
|
99
|
+
fallback: locale.specialChar2
|
|
100
|
+
}),
|
|
101
|
+
|
|
102
|
+
score(passwd) {
|
|
103
|
+
// [verified] at least two special characters
|
|
104
|
+
return passwd.match(/(.*[!@#$%^&*?_~].*[!@#$%^&*?_~])/) ? 5 : -1;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
}, {
|
|
108
|
+
name: 'comboUpperAndLower',
|
|
109
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
110
|
+
content: `FormFieldPassword.comboUpperAndLower`,
|
|
111
|
+
fallback: locale.comboUpperAndLower
|
|
112
|
+
}),
|
|
113
|
+
|
|
114
|
+
score(passwd) {
|
|
115
|
+
// [verified] both upper and lower case
|
|
116
|
+
return passwd.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) ? 2 : -1;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
}, {
|
|
120
|
+
name: 'comboLettersAndNumbers',
|
|
121
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
122
|
+
content: `FormFieldPassword.comboLettersAndNumbers`,
|
|
123
|
+
fallback: locale.comboLettersAndNumbers
|
|
124
|
+
}),
|
|
125
|
+
|
|
126
|
+
score(passwd) {
|
|
127
|
+
// [verified] both letters and numbers
|
|
128
|
+
return passwd.match(/([a-zA-Z])/) && passwd.match(/([0-9])/) ? 2 : -1;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
}, {
|
|
132
|
+
name: 'comboLettersNumbersSpecial',
|
|
133
|
+
suggestion: /*#__PURE__*/React.createElement(Translate, {
|
|
134
|
+
content: `FormFieldPassword.comboLettersNumbersSpecial`,
|
|
135
|
+
fallback: locale.comboLettersNumbersSpecial
|
|
136
|
+
}),
|
|
137
|
+
|
|
138
|
+
score(passwd) {
|
|
139
|
+
// [verified] letters, numbers, and special characters
|
|
140
|
+
return passwd.match(/([a-zA-Z0-9].*[!@#$%^&*?_~])|([!@#$%^&*?_~].*[a-zA-Z0-9])/) ? 2 : -1;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
}];
|
|
144
|
+
export default ((password, rules = DEFAULT_RULES) => {
|
|
145
|
+
const suggestions = [];
|
|
146
|
+
let passwordScore = 0;
|
|
147
|
+
rules.forEach(({
|
|
148
|
+
suggestion,
|
|
149
|
+
score
|
|
150
|
+
}) => {
|
|
151
|
+
const ruleScore = score(password);
|
|
152
|
+
|
|
153
|
+
if (ruleScore < 0 && suggestion) {
|
|
154
|
+
suggestions.push(suggestion);
|
|
155
|
+
} else {
|
|
156
|
+
passwordScore += ruleScore;
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
let strength;
|
|
160
|
+
|
|
161
|
+
switch (true) {
|
|
162
|
+
case passwordScore < 16:
|
|
163
|
+
strength = 'VeryWeak';
|
|
164
|
+
break;
|
|
165
|
+
|
|
166
|
+
case passwordScore < 25:
|
|
167
|
+
strength = 'Weak';
|
|
168
|
+
break;
|
|
169
|
+
|
|
170
|
+
case passwordScore < 35:
|
|
171
|
+
strength = 'Medium';
|
|
172
|
+
break;
|
|
173
|
+
|
|
174
|
+
case passwordScore < 45:
|
|
175
|
+
strength = 'Strong';
|
|
176
|
+
break;
|
|
177
|
+
|
|
178
|
+
default:
|
|
179
|
+
strength = 'VeryStrong';
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
strength,
|
|
185
|
+
suggestions
|
|
186
|
+
};
|
|
187
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Copyright 1999-2022. Plesk International GmbH. All rights reserved.
|
|
2
|
+
const symbolClasses = {
|
|
3
|
+
upper: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
|
4
|
+
lower: 'abcdefghijklmnopqrstuvwxyz',
|
|
5
|
+
number: '0123456789',
|
|
6
|
+
special: '!@#$%^&*?_~'
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const generatePassword = () => {
|
|
10
|
+
const password = ['upper', 'upper', 'upper', 'lower', 'lower', 'lower', 'lower', 'lower', 'lower', 'lower', 'lower', 'number', 'number', 'number', 'special', 'special'];
|
|
11
|
+
return password.sort((a, b) => Math.floor(b.length * Math.random()) - Math.floor(a.length * Math.random())).map(symbolClass => symbolClasses[symbolClass][Math.floor(symbolClasses[symbolClass].length * Math.random())]).join('');
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default generatePassword;
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
// Copyright 1999-
|
|
2
|
-
export { default
|
|
1
|
+
// Copyright 1999-2022. Plesk International GmbH. All rights reserved.
|
|
2
|
+
export { default } from './FormFieldPassword';
|
|
3
|
+
export { default as generatePassword } from './generatePassword';
|
|
@@ -73,7 +73,7 @@ const Icon = ({
|
|
|
73
73
|
}, props), newName ? /*#__PURE__*/React.createElement("svg", {
|
|
74
74
|
focusable: "false"
|
|
75
75
|
}, /*#__PURE__*/React.createElement("use", {
|
|
76
|
-
|
|
76
|
+
href: getHref(newName, newSize)
|
|
77
77
|
})) : src && /*#__PURE__*/React.createElement("img", {
|
|
78
78
|
src: src,
|
|
79
79
|
alt: alt
|
|
@@ -1190,7 +1190,7 @@ class List extends Component {
|
|
|
1190
1190
|
[`${baseClassName}__table--vertical`]: vertical,
|
|
1191
1191
|
[`${baseClassName}__table--reorderable`]: reorderable
|
|
1192
1192
|
})
|
|
1193
|
-
},
|
|
1193
|
+
}, reorderableProps), hasTitle && /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", {
|
|
1194
1194
|
className: classNames(`${baseClassName}__table-thead`, {
|
|
1195
1195
|
[`${baseClassName}__row--expanded`]: this.isAllRowsExpanded(data, this.state.expandedRows)
|
|
1196
1196
|
})
|
|
@@ -131,7 +131,8 @@ class ProgressDialog extends Component {
|
|
|
131
131
|
}, props, {
|
|
132
132
|
isOpen: isOpen,
|
|
133
133
|
onClose: this.handleClose,
|
|
134
|
-
closable: canClose || canCancel
|
|
134
|
+
closable: canClose || canCancel,
|
|
135
|
+
canClose: canClose
|
|
135
136
|
}), description && /*#__PURE__*/React.createElement("div", {
|
|
136
137
|
className: `${baseClassName}__description`
|
|
137
138
|
}, description), /*#__PURE__*/React.createElement(Progress, {
|