@devtron-labs/devtron-fe-common-lib 0.0.7-beta-39 → 0.0.7-beta-41
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/dist/Common/Helper.d.ts +22 -0
- package/dist/index.js +146 -18
- package/package.json +1 -1
- package/src/Assets/Icon/ic-warning.svg +7 -0
- package/src/Common/Helper.tsx +199 -36
package/dist/Common/Helper.d.ts
CHANGED
|
@@ -17,4 +17,26 @@ export declare function not(e: any): boolean;
|
|
|
17
17
|
export declare function useEffectAfterMount(cb: any, dependencies: any): void;
|
|
18
18
|
export declare function getCookie(sKey: any): string;
|
|
19
19
|
export declare function getLoginInfo(): any;
|
|
20
|
+
export declare function useForm(stateSchema: any, validationSchema: {}, callback: any): {
|
|
21
|
+
state: any;
|
|
22
|
+
disable: boolean;
|
|
23
|
+
handleOnChange: (event: any) => void;
|
|
24
|
+
handleOnSubmit: (event: any) => void;
|
|
25
|
+
};
|
|
26
|
+
export declare function CustomInput({ name, value, error, onChange, onBlur, onFocus, label, type, disabled, autoComplete, labelClassName, placeholder, tabIndex, dataTestid, }: {
|
|
27
|
+
name: any;
|
|
28
|
+
value: any;
|
|
29
|
+
error: any;
|
|
30
|
+
onChange: any;
|
|
31
|
+
onBlur?: (e: any) => void;
|
|
32
|
+
onFocus?: (e: any) => void;
|
|
33
|
+
label: any;
|
|
34
|
+
type?: string;
|
|
35
|
+
disabled?: boolean;
|
|
36
|
+
autoComplete?: string;
|
|
37
|
+
labelClassName?: string;
|
|
38
|
+
placeholder?: string;
|
|
39
|
+
tabIndex?: number;
|
|
40
|
+
dataTestid?: string;
|
|
41
|
+
}): JSX.Element;
|
|
20
42
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -503,15 +503,15 @@ function styleInject(css, ref) {
|
|
|
503
503
|
var css_248z$6 = ".empty-state {\n height: 100%;\n}\n.empty-state img {\n height: 40%;\n max-height: 200px;\n width: auto;\n max-width: 250px;\n}\n.empty-state svg {\n height: 40%;\n max-height: 200px;\n width: auto;\n}\n.empty-state h1,\n.empty-state h2,\n.empty-state h3,\n.empty-state h4,\n.empty-state h5,\n.empty-state h6 {\n color: var(--N900);\n}\n.empty-state .subtitle {\n font-size: 13px;\n width: 300px;\n font-weight: 400;\n text-align: center;\n line-height: 1.5;\n margin-bottom: 20px;\n}\n.empty-state .cta {\n height: 36px;\n}\n.empty-state p {\n width: 300px;\n text-align: center;\n font-size: 13px;\n color: var(--N700);\n}\n.empty-state strong {\n font-size: 16px;\n margin-bottom: 4px;\n color: var(--N900);\n font-weight: normal;\n}\n.empty-state .select-popup {\n height: min-content;\n max-height: 250px;\n overflow: auto;\n padding: 8px 0;\n}\n.empty-state .empty-state__loader {\n width: 34px;\n height: 34px;\n margin-bottom: 16px;\n}\n.empty-state .empty-state__loading-text {\n font-size: 12px;\n width: 200px;\n font-weight: normal;\n font-stretch: normal;\n font-style: normal;\n line-height: 1.5;\n letter-spacing: normal;\n text-align: center;\n color: var(--N900);\n}\n.empty-state .button__icon {\n width: 16px;\n height: 16px;\n margin-left: 8px;\n}";
|
|
504
504
|
styleInject(css_248z$6);
|
|
505
505
|
|
|
506
|
-
var _g$
|
|
507
|
-
function _extends$
|
|
506
|
+
var _g$3;
|
|
507
|
+
function _extends$b() { _extends$b = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$b.apply(this, arguments); }
|
|
508
508
|
var SvgIcProgressing = function SvgIcProgressing(props) {
|
|
509
|
-
return /*#__PURE__*/React__namespace.createElement("svg", _extends$
|
|
509
|
+
return /*#__PURE__*/React__namespace.createElement("svg", _extends$b({
|
|
510
510
|
xmlns: "http://www.w3.org/2000/svg",
|
|
511
511
|
viewBox: "0 0 24 24",
|
|
512
512
|
width: "1em",
|
|
513
513
|
height: "1em"
|
|
514
|
-
}, props), _g$
|
|
514
|
+
}, props), _g$3 || (_g$3 = /*#__PURE__*/React__namespace.createElement("g", {
|
|
515
515
|
fill: "none"
|
|
516
516
|
}, /*#__PURE__*/React__namespace.createElement("animateTransform", {
|
|
517
517
|
attributeName: "transform",
|
|
@@ -558,8 +558,8 @@ EmptyState.Loading = Loading;
|
|
|
558
558
|
|
|
559
559
|
function r(e){var t,f,n="";if("string"==typeof e||"number"==typeof e)n+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;t<e.length;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=" "),n+=f);else for(t in e)e[t]&&(n&&(n+=" "),n+=t);return n}function clsx(){for(var e,t,f=0,n="";f<arguments.length;)(e=arguments[f++])&&(t=r(e))&&(n&&(n+=" "),n+=t);return n}
|
|
560
560
|
|
|
561
|
-
function _extends$
|
|
562
|
-
_extends$
|
|
561
|
+
function _extends$a() {
|
|
562
|
+
_extends$a = Object.assign || function (target) {
|
|
563
563
|
for (var i = 1; i < arguments.length; i++) {
|
|
564
564
|
var source = arguments[i];
|
|
565
565
|
|
|
@@ -573,7 +573,7 @@ function _extends$9() {
|
|
|
573
573
|
return target;
|
|
574
574
|
};
|
|
575
575
|
|
|
576
|
-
return _extends$
|
|
576
|
+
return _extends$a.apply(this, arguments);
|
|
577
577
|
}
|
|
578
578
|
|
|
579
579
|
function _objectWithoutPropertiesLoose$2(source, excluded) {
|
|
@@ -1299,7 +1299,7 @@ function ProgressBar(_ref) {
|
|
|
1299
1299
|
isIn = _ref.isIn,
|
|
1300
1300
|
theme = _ref.theme;
|
|
1301
1301
|
|
|
1302
|
-
var style = _extends$
|
|
1302
|
+
var style = _extends$a({}, userStyle, {
|
|
1303
1303
|
animationDuration: delay + "ms",
|
|
1304
1304
|
animationPlayState: isRunning ? 'running' : 'paused',
|
|
1305
1305
|
opacity: hide ? 0 : 1
|
|
@@ -1576,9 +1576,9 @@ var ToastContainer = function ToastContainer(props) {
|
|
|
1576
1576
|
,
|
|
1577
1577
|
id: containerId
|
|
1578
1578
|
}, getToastToRender(function (position, toastList) {
|
|
1579
|
-
var containerStyle = !toastList.length ? _extends$
|
|
1579
|
+
var containerStyle = !toastList.length ? _extends$a({}, style, {
|
|
1580
1580
|
pointerEvents: 'none'
|
|
1581
|
-
}) : _extends$
|
|
1581
|
+
}) : _extends$a({}, style);
|
|
1582
1582
|
return React.createElement("div", {
|
|
1583
1583
|
className: getClassName(position),
|
|
1584
1584
|
style: containerStyle,
|
|
@@ -1685,7 +1685,7 @@ function dispatchToast(content, options) {
|
|
|
1685
1685
|
|
|
1686
1686
|
|
|
1687
1687
|
function mergeOptions(type, options) {
|
|
1688
|
-
return _extends$
|
|
1688
|
+
return _extends$a({}, options, {
|
|
1689
1689
|
type: options && options.type || type,
|
|
1690
1690
|
toastId: getToastId(options)
|
|
1691
1691
|
});
|
|
@@ -1702,7 +1702,7 @@ function toast(content, options) {
|
|
|
1702
1702
|
}
|
|
1703
1703
|
|
|
1704
1704
|
toast.loading = function (content, options) {
|
|
1705
|
-
return dispatchToast(content, mergeOptions(TYPE.DEFAULT, _extends$
|
|
1705
|
+
return dispatchToast(content, mergeOptions(TYPE.DEFAULT, _extends$a({
|
|
1706
1706
|
isLoading: true,
|
|
1707
1707
|
autoClose: false,
|
|
1708
1708
|
closeOnClick: false,
|
|
@@ -1718,7 +1718,7 @@ function handlePromise(promise, _ref2, options) {
|
|
|
1718
1718
|
var id;
|
|
1719
1719
|
|
|
1720
1720
|
if (pending) {
|
|
1721
|
-
id = isStr(pending) ? toast.loading(pending, options) : toast.loading(pending.render, _extends$
|
|
1721
|
+
id = isStr(pending) ? toast.loading(pending, options) : toast.loading(pending.render, _extends$a({}, options, pending));
|
|
1722
1722
|
}
|
|
1723
1723
|
|
|
1724
1724
|
var resetParams = {
|
|
@@ -1737,7 +1737,7 @@ function handlePromise(promise, _ref2, options) {
|
|
|
1737
1737
|
return;
|
|
1738
1738
|
}
|
|
1739
1739
|
|
|
1740
|
-
var baseParams = _extends$
|
|
1740
|
+
var baseParams = _extends$a({
|
|
1741
1741
|
type: type
|
|
1742
1742
|
}, resetParams, options, {
|
|
1743
1743
|
data: result
|
|
@@ -1748,10 +1748,10 @@ function handlePromise(promise, _ref2, options) {
|
|
|
1748
1748
|
} : input; // if the id is set we know that it's an update
|
|
1749
1749
|
|
|
1750
1750
|
if (id) {
|
|
1751
|
-
toast.update(id, _extends$
|
|
1751
|
+
toast.update(id, _extends$a({}, baseParams, params));
|
|
1752
1752
|
} else {
|
|
1753
1753
|
// using toast.promise without loading
|
|
1754
|
-
toast(params.render, _extends$
|
|
1754
|
+
toast(params.render, _extends$a({}, baseParams, params));
|
|
1755
1755
|
}
|
|
1756
1756
|
|
|
1757
1757
|
return result;
|
|
@@ -1775,7 +1775,7 @@ toast.warning = /*#__PURE__*/createToastByType(TYPE.WARNING);
|
|
|
1775
1775
|
toast.warn = toast.warning;
|
|
1776
1776
|
|
|
1777
1777
|
toast.dark = function (content, options) {
|
|
1778
|
-
return dispatchToast(content, mergeOptions(TYPE.DEFAULT, _extends$
|
|
1778
|
+
return dispatchToast(content, mergeOptions(TYPE.DEFAULT, _extends$a({
|
|
1779
1779
|
theme: 'dark'
|
|
1780
1780
|
}, options)));
|
|
1781
1781
|
};
|
|
@@ -1832,7 +1832,7 @@ toast.update = function (toastId, options) {
|
|
|
1832
1832
|
var oldOptions = toast.props,
|
|
1833
1833
|
oldContent = toast.content;
|
|
1834
1834
|
|
|
1835
|
-
var nextOptions = _extends$
|
|
1835
|
+
var nextOptions = _extends$a({}, oldOptions, options, {
|
|
1836
1836
|
toastId: options.toastId || toastId,
|
|
1837
1837
|
updateId: generateToastId()
|
|
1838
1838
|
});
|
|
@@ -3927,6 +3927,28 @@ function captureException(exception, captureContext) {
|
|
|
3927
3927
|
return getCurrentHub().captureException(exception, { captureContext });
|
|
3928
3928
|
}
|
|
3929
3929
|
|
|
3930
|
+
var _g$2;
|
|
3931
|
+
function _extends$9() { _extends$9 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$9.apply(this, arguments); }
|
|
3932
|
+
var SvgIcWarning = function SvgIcWarning(props) {
|
|
3933
|
+
return /*#__PURE__*/React__namespace.createElement("svg", _extends$9({
|
|
3934
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
3935
|
+
width: "1em",
|
|
3936
|
+
height: "1em",
|
|
3937
|
+
viewBox: "0 0 32 32"
|
|
3938
|
+
}, props), _g$2 || (_g$2 = /*#__PURE__*/React__namespace.createElement("g", {
|
|
3939
|
+
fill: "none",
|
|
3940
|
+
fillRule: "evenodd"
|
|
3941
|
+
}, /*#__PURE__*/React__namespace.createElement("path", {
|
|
3942
|
+
d: "M0 0h32v32H0z"
|
|
3943
|
+
}), /*#__PURE__*/React__namespace.createElement("path", {
|
|
3944
|
+
fill: "#FFCB5D",
|
|
3945
|
+
d: "M18.315 5.052 29.72 25.01A2.667 2.667 0 0 1 27.405 29H4.595a2.667 2.667 0 0 1-2.315-3.99L13.685 5.052a2.667 2.667 0 0 1 4.63 0z"
|
|
3946
|
+
}), /*#__PURE__*/React__namespace.createElement("path", {
|
|
3947
|
+
fill: "#FFF",
|
|
3948
|
+
d: "M16 22.667a1.333 1.333 0 1 1 0 2.666 1.333 1.333 0 0 1 0-2.666zM16 12c.736 0 1.333.597 1.333 1.333v6.334a1.333 1.333 0 1 1-2.666 0v-6.334c0-.736.597-1.333 1.333-1.333z"
|
|
3949
|
+
}))));
|
|
3950
|
+
};
|
|
3951
|
+
|
|
3930
3952
|
toast.configure({
|
|
3931
3953
|
autoClose: 3000,
|
|
3932
3954
|
hideProgressBar: true,
|
|
@@ -4065,6 +4087,110 @@ function getLoginInfo() {
|
|
|
4065
4087
|
return null;
|
|
4066
4088
|
}
|
|
4067
4089
|
}
|
|
4090
|
+
}
|
|
4091
|
+
function useForm(stateSchema, validationSchema, callback) {
|
|
4092
|
+
if (validationSchema === void 0) { validationSchema = {}; }
|
|
4093
|
+
var _a = __read(React.useState(stateSchema), 2), state = _a[0], setState = _a[1];
|
|
4094
|
+
var _b = __read(React.useState(true), 2), disable = _b[0], setDisable = _b[1];
|
|
4095
|
+
var _c = __read(React.useState(false), 2), isDirty = _c[0], setIsDirty = _c[1];
|
|
4096
|
+
// Disable button in initial render.
|
|
4097
|
+
React.useEffect(function () {
|
|
4098
|
+
setDisable(true);
|
|
4099
|
+
}, []);
|
|
4100
|
+
// For every changed in our state this will be fired
|
|
4101
|
+
// To be able to disable the button
|
|
4102
|
+
React.useEffect(function () {
|
|
4103
|
+
if (isDirty) {
|
|
4104
|
+
setDisable(validateState(state));
|
|
4105
|
+
}
|
|
4106
|
+
}, [state, isDirty]);
|
|
4107
|
+
// Used to disable submit button if there's an error in state
|
|
4108
|
+
// or the required field in state has no value.
|
|
4109
|
+
// Wrapped in useCallback to cached the function to avoid intensive memory leaked
|
|
4110
|
+
// in every re-render in component
|
|
4111
|
+
var validateState = React.useCallback(function (state) {
|
|
4112
|
+
//check errors in all fields
|
|
4113
|
+
var hasErrorInState = Object.keys(validationSchema).some(function (key) {
|
|
4114
|
+
var isInputFieldRequired = validationSchema[key].required;
|
|
4115
|
+
var stateValue = state[key].value; // state value
|
|
4116
|
+
var stateError = state[key].error; // state error
|
|
4117
|
+
return (isInputFieldRequired && !stateValue) || stateError;
|
|
4118
|
+
});
|
|
4119
|
+
return hasErrorInState;
|
|
4120
|
+
}, [state, validationSchema]);
|
|
4121
|
+
function validateField(name, value) {
|
|
4122
|
+
if (validationSchema[name].required) {
|
|
4123
|
+
if (!value) {
|
|
4124
|
+
return 'This is a required field.';
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4127
|
+
function _validateSingleValidator(validator, value) {
|
|
4128
|
+
if (value && !validator.regex.test(value)) {
|
|
4129
|
+
return false;
|
|
4130
|
+
}
|
|
4131
|
+
return true;
|
|
4132
|
+
}
|
|
4133
|
+
// single validator
|
|
4134
|
+
var _validator = validationSchema[name].validator;
|
|
4135
|
+
if (_validator && typeof _validator === 'object') {
|
|
4136
|
+
if (!_validateSingleValidator(_validator, value)) {
|
|
4137
|
+
return _validator.error;
|
|
4138
|
+
}
|
|
4139
|
+
}
|
|
4140
|
+
// multiple validators
|
|
4141
|
+
var _validators = validationSchema[name].validators;
|
|
4142
|
+
if (_validators && typeof _validators === 'object' && Array.isArray(_validators)) {
|
|
4143
|
+
var errors_1 = [];
|
|
4144
|
+
_validators.forEach(function (_validator) {
|
|
4145
|
+
if (!_validateSingleValidator(_validator, value)) {
|
|
4146
|
+
errors_1.push(_validator.error);
|
|
4147
|
+
}
|
|
4148
|
+
});
|
|
4149
|
+
if (errors_1.length > 0) {
|
|
4150
|
+
return errors_1;
|
|
4151
|
+
}
|
|
4152
|
+
}
|
|
4153
|
+
return '';
|
|
4154
|
+
}
|
|
4155
|
+
var handleOnChange = React.useCallback(function (event) {
|
|
4156
|
+
setIsDirty(true);
|
|
4157
|
+
var _a = event.target, name = _a.name, value = _a.value;
|
|
4158
|
+
var error = validateField(name, value);
|
|
4159
|
+
setState(function (prevState) {
|
|
4160
|
+
var _a;
|
|
4161
|
+
return (__assign(__assign({}, prevState), (_a = {}, _a[name] = { value: value, error: error }, _a)));
|
|
4162
|
+
});
|
|
4163
|
+
}, [validationSchema]);
|
|
4164
|
+
var handleOnSubmit = function (event) {
|
|
4165
|
+
event.preventDefault();
|
|
4166
|
+
var newState = Object.keys(validationSchema).reduce(function (agg, curr) {
|
|
4167
|
+
agg[curr] = __assign(__assign({}, state[curr]), { error: validateField(curr, state[curr].value) });
|
|
4168
|
+
return agg;
|
|
4169
|
+
}, state);
|
|
4170
|
+
if (!validateState(newState)) {
|
|
4171
|
+
callback(state);
|
|
4172
|
+
}
|
|
4173
|
+
else {
|
|
4174
|
+
setState(__assign({}, newState));
|
|
4175
|
+
}
|
|
4176
|
+
};
|
|
4177
|
+
return { state: state, disable: disable, handleOnChange: handleOnChange, handleOnSubmit: handleOnSubmit };
|
|
4178
|
+
}
|
|
4179
|
+
function handleError(error) {
|
|
4180
|
+
if (!error) {
|
|
4181
|
+
return [];
|
|
4182
|
+
}
|
|
4183
|
+
if (!Array.isArray(error)) {
|
|
4184
|
+
return [error];
|
|
4185
|
+
}
|
|
4186
|
+
return error;
|
|
4187
|
+
}
|
|
4188
|
+
function CustomInput(_a) {
|
|
4189
|
+
var name = _a.name, value = _a.value, error = _a.error, onChange = _a.onChange, _b = _a.onBlur, onBlur = _b === void 0 ? function (e) { } : _b, _c = _a.onFocus, onFocus = _c === void 0 ? function (e) { } : _c, label = _a.label, _d = _a.type, type = _d === void 0 ? 'text' : _d, _e = _a.disabled, disabled = _e === void 0 ? false : _e; _a.autoComplete; var _g = _a.labelClassName, labelClassName = _g === void 0 ? '' : _g, _h = _a.placeholder, placeholder = _h === void 0 ? '' : _h, _j = _a.tabIndex, tabIndex = _j === void 0 ? 1 : _j, _k = _a.dataTestid, dataTestid = _k === void 0 ? '' : _k;
|
|
4190
|
+
return (jsxRuntime.jsxs("div", __assign({ className: "flex column left top" }, { children: [jsxRuntime.jsx("label", __assign({ className: "form__label ".concat(labelClassName) }, { children: label })), jsxRuntime.jsx("input", { "data-testid": dataTestid, type: type, name: name, autoComplete: "off", className: "form__input", onChange: function (e) {
|
|
4191
|
+
e.persist();
|
|
4192
|
+
onChange(e);
|
|
4193
|
+
}, onBlur: onBlur, onFocus: onFocus, placeholder: placeholder, value: value, disabled: disabled, tabIndex: tabIndex }), handleError(error).map(function (err) { return (jsxRuntime.jsxs("div", __assign({ className: "form__error" }, { children: [jsxRuntime.jsx(SvgIcWarning, { className: "form__icon form__icon--error" }), err] }))); })] })));
|
|
4068
4194
|
}
|
|
4069
4195
|
|
|
4070
4196
|
function Progressing(_a) {
|
|
@@ -16585,6 +16711,7 @@ exports.Checkbox = Checkbox;
|
|
|
16585
16711
|
exports.ClearIndicator = ClearIndicator;
|
|
16586
16712
|
exports.ConditionalWrap = ConditionalWrap;
|
|
16587
16713
|
exports.ConfirmationDialog = ConfirmationDialog;
|
|
16714
|
+
exports.CustomInput = CustomInput;
|
|
16588
16715
|
exports.CustomSelect = CustomSelect;
|
|
16589
16716
|
exports.DEFAULT_TAG_DATA = DEFAULT_TAG_DATA;
|
|
16590
16717
|
exports.DOCUMENTATION = DOCUMENTATION;
|
|
@@ -16656,4 +16783,5 @@ exports.toastAccessDenied = toastAccessDenied;
|
|
|
16656
16783
|
exports.trash = trash;
|
|
16657
16784
|
exports.useBreadcrumb = useBreadcrumb;
|
|
16658
16785
|
exports.useEffectAfterMount = useEffectAfterMount;
|
|
16786
|
+
exports.useForm = useForm;
|
|
16659
16787
|
exports.useThrottledEffect = useThrottledEffect;
|
package/package.json
CHANGED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
|
2
|
+
<g fill="none" fill-rule="evenodd">
|
|
3
|
+
<path d="M0 0h32v32H0z"/>
|
|
4
|
+
<path fill="#FFCB5D" d="M18.315 5.052L29.72 25.01A2.667 2.667 0 0 1 27.405 29H4.595a2.667 2.667 0 0 1-2.315-3.99L13.685 5.052a2.667 2.667 0 0 1 4.63 0z"/>
|
|
5
|
+
<path fill="#FFF" d="M16 22.667a1.333 1.333 0 1 1 0 2.666 1.333 1.333 0 0 1 0-2.666zM16 12c.736 0 1.333.597 1.333 1.333v6.334a1.333 1.333 0 1 1-2.666 0v-6.334c0-.736.597-1.333 1.333-1.333z"/>
|
|
6
|
+
</g>
|
|
7
|
+
</svg>
|
package/src/Common/Helper.tsx
CHANGED
|
@@ -1,48 +1,49 @@
|
|
|
1
|
-
import React, { useEffect, useRef } from 'react'
|
|
1
|
+
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
|
2
2
|
import { ServerErrors } from './ServerError'
|
|
3
3
|
import { toast } from 'react-toastify'
|
|
4
4
|
import * as Sentry from '@sentry/browser'
|
|
5
5
|
import { toastAccessDenied } from './ToastBody'
|
|
6
6
|
import { ERROR_EMPTY_SCREEN, TOKEN_COOKIE_NAME } from './Constants'
|
|
7
|
+
import { ReactComponent as FormError } from '../Assets/Icon/ic-warning.svg'
|
|
7
8
|
|
|
8
9
|
toast.configure({
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
autoClose: 3000,
|
|
11
|
+
hideProgressBar: true,
|
|
12
|
+
pauseOnHover: true,
|
|
13
|
+
pauseOnFocusLoss: true,
|
|
14
|
+
closeOnClick: false,
|
|
15
|
+
newestOnTop: true,
|
|
16
|
+
toastClassName: 'devtron-toast',
|
|
17
|
+
bodyClassName: 'devtron-toast__body',
|
|
17
18
|
})
|
|
18
19
|
|
|
19
20
|
export function showError(serverError, showToastOnUnknownError = true, hideAccessError = false) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
21
|
+
if (serverError instanceof ServerErrors && Array.isArray(serverError.errors)) {
|
|
22
|
+
serverError.errors.map(({ userMessage, internalMessage }) => {
|
|
23
|
+
if (
|
|
24
|
+
serverError.code === 403 &&
|
|
25
|
+
(userMessage === ERROR_EMPTY_SCREEN.UNAUTHORIZED || userMessage === ERROR_EMPTY_SCREEN.FORBIDDEN)
|
|
26
|
+
) {
|
|
27
|
+
if (!hideAccessError) {
|
|
28
|
+
toastAccessDenied()
|
|
29
|
+
}
|
|
30
|
+
} else {
|
|
31
|
+
toast.error(userMessage || internalMessage)
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
} else {
|
|
35
|
+
if (serverError.code !== 403 && serverError.code !== 408) {
|
|
36
|
+
Sentry.captureException(serverError)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (showToastOnUnknownError) {
|
|
40
|
+
if (serverError.message) {
|
|
41
|
+
toast.error(serverError.message)
|
|
42
|
+
} else {
|
|
43
|
+
toast.error('Some Error Occurred')
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
interface ConditionalWrapper<T> {
|
|
@@ -167,4 +168,166 @@ export function getLoginInfo() {
|
|
|
167
168
|
return null
|
|
168
169
|
}
|
|
169
170
|
}
|
|
170
|
-
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function useForm(stateSchema, validationSchema = {}, callback) {
|
|
174
|
+
const [state, setState] = useState(stateSchema)
|
|
175
|
+
const [disable, setDisable] = useState(true)
|
|
176
|
+
const [isDirty, setIsDirty] = useState(false)
|
|
177
|
+
|
|
178
|
+
// Disable button in initial render.
|
|
179
|
+
useEffect(() => {
|
|
180
|
+
setDisable(true)
|
|
181
|
+
}, [])
|
|
182
|
+
|
|
183
|
+
// For every changed in our state this will be fired
|
|
184
|
+
// To be able to disable the button
|
|
185
|
+
useEffect(() => {
|
|
186
|
+
if (isDirty) {
|
|
187
|
+
setDisable(validateState(state))
|
|
188
|
+
}
|
|
189
|
+
}, [state, isDirty])
|
|
190
|
+
|
|
191
|
+
// Used to disable submit button if there's an error in state
|
|
192
|
+
// or the required field in state has no value.
|
|
193
|
+
// Wrapped in useCallback to cached the function to avoid intensive memory leaked
|
|
194
|
+
// in every re-render in component
|
|
195
|
+
const validateState = useCallback(
|
|
196
|
+
(state) => {
|
|
197
|
+
//check errors in all fields
|
|
198
|
+
const hasErrorInState = Object.keys(validationSchema).some((key) => {
|
|
199
|
+
const isInputFieldRequired = validationSchema[key].required
|
|
200
|
+
const stateValue = state[key].value // state value
|
|
201
|
+
const stateError = state[key].error // state error
|
|
202
|
+
return (isInputFieldRequired && !stateValue) || stateError
|
|
203
|
+
})
|
|
204
|
+
return hasErrorInState
|
|
205
|
+
},
|
|
206
|
+
[state, validationSchema],
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
function validateField(name, value): string | string[] {
|
|
210
|
+
if (validationSchema[name].required) {
|
|
211
|
+
if (!value) {
|
|
212
|
+
return 'This is a required field.'
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function _validateSingleValidator(validator, value) {
|
|
217
|
+
if (value && !validator.regex.test(value)) {
|
|
218
|
+
return false
|
|
219
|
+
}
|
|
220
|
+
return true
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// single validator
|
|
224
|
+
let _validator = validationSchema[name].validator
|
|
225
|
+
if (_validator && typeof _validator === 'object') {
|
|
226
|
+
if (!_validateSingleValidator(_validator, value)) {
|
|
227
|
+
return _validator.error
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// multiple validators
|
|
232
|
+
let _validators = validationSchema[name].validators
|
|
233
|
+
if (_validators && typeof _validators === 'object' && Array.isArray(_validators)) {
|
|
234
|
+
let errors = []
|
|
235
|
+
_validators.forEach((_validator) => {
|
|
236
|
+
if (!_validateSingleValidator(_validator, value)) {
|
|
237
|
+
errors.push(_validator.error)
|
|
238
|
+
}
|
|
239
|
+
})
|
|
240
|
+
if (errors.length > 0) {
|
|
241
|
+
return errors
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return ''
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const handleOnChange = useCallback(
|
|
249
|
+
(event) => {
|
|
250
|
+
setIsDirty(true)
|
|
251
|
+
|
|
252
|
+
const { name, value } = event.target
|
|
253
|
+
let error = validateField(name, value)
|
|
254
|
+
setState((prevState) => ({
|
|
255
|
+
...prevState,
|
|
256
|
+
[name]: { value, error },
|
|
257
|
+
}))
|
|
258
|
+
},
|
|
259
|
+
[validationSchema],
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
const handleOnSubmit = (event) => {
|
|
263
|
+
event.preventDefault()
|
|
264
|
+
const newState = Object.keys(validationSchema).reduce((agg, curr) => {
|
|
265
|
+
agg[curr] = { ...state[curr], error: validateField(curr, state[curr].value) }
|
|
266
|
+
return agg
|
|
267
|
+
}, state)
|
|
268
|
+
if (!validateState(newState)) {
|
|
269
|
+
callback(state)
|
|
270
|
+
} else {
|
|
271
|
+
setState({ ...newState })
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return { state, disable, handleOnChange, handleOnSubmit }
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function handleError(error: any): any[] {
|
|
278
|
+
if (!error) {
|
|
279
|
+
return []
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (!Array.isArray(error)) {
|
|
283
|
+
return [error]
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return error
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export function CustomInput({
|
|
290
|
+
name,
|
|
291
|
+
value,
|
|
292
|
+
error,
|
|
293
|
+
onChange,
|
|
294
|
+
onBlur = (e) => {},
|
|
295
|
+
onFocus = (e) => {},
|
|
296
|
+
label,
|
|
297
|
+
type = 'text',
|
|
298
|
+
disabled = false,
|
|
299
|
+
autoComplete = 'off',
|
|
300
|
+
labelClassName = '',
|
|
301
|
+
placeholder = '',
|
|
302
|
+
tabIndex = 1,
|
|
303
|
+
dataTestid = '',
|
|
304
|
+
}) {
|
|
305
|
+
return (
|
|
306
|
+
<div className="flex column left top">
|
|
307
|
+
<label className={`form__label ${labelClassName}`}>{label}</label>
|
|
308
|
+
<input
|
|
309
|
+
data-testid={dataTestid}
|
|
310
|
+
type={type}
|
|
311
|
+
name={name}
|
|
312
|
+
autoComplete="off"
|
|
313
|
+
className="form__input"
|
|
314
|
+
onChange={(e) => {
|
|
315
|
+
e.persist()
|
|
316
|
+
onChange(e)
|
|
317
|
+
}}
|
|
318
|
+
onBlur={onBlur}
|
|
319
|
+
onFocus={onFocus}
|
|
320
|
+
placeholder={placeholder}
|
|
321
|
+
value={value}
|
|
322
|
+
disabled={disabled}
|
|
323
|
+
tabIndex={tabIndex}
|
|
324
|
+
/>
|
|
325
|
+
{handleError(error).map((err) => (
|
|
326
|
+
<div className="form__error">
|
|
327
|
+
<FormError className="form__icon form__icon--error" />
|
|
328
|
+
{err}
|
|
329
|
+
</div>
|
|
330
|
+
))}
|
|
331
|
+
</div>
|
|
332
|
+
)
|
|
333
|
+
}
|