@devtron-labs/devtron-fe-common-lib 0.0.7-beta-39 → 0.0.7-beta-42

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.
@@ -0,0 +1,4 @@
1
+ /// <reference types="react" />
2
+ import { DeleteComponentProps } from './types';
3
+ declare function DeleteComponent({ setDeleting, toggleConfirmation, deleteComponent, title, component, payload, confirmationDialogDescription, redirectTo, url, reload, configuration, closeCustomComponent, }: DeleteComponentProps): JSX.Element;
4
+ export default DeleteComponent;
@@ -0,0 +1,15 @@
1
+ export interface DeleteComponentProps {
2
+ setDeleting: (boolean: any) => void;
3
+ toggleConfirmation: any;
4
+ deleteComponent: (any: any) => Promise<any>;
5
+ title: string;
6
+ component: string;
7
+ payload: any;
8
+ confirmationDialogDescription?: string;
9
+ redirectTo?: boolean;
10
+ url?: string;
11
+ reload?: () => void;
12
+ configuration?: string;
13
+ dataTestid?: string;
14
+ closeCustomComponent?: () => void;
15
+ }
@@ -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$2;
507
- function _extends$a() { _extends$a = 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$a.apply(this, arguments); }
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$a({
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$2 || (_g$2 = /*#__PURE__*/React__namespace.createElement("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$9() {
562
- _extends$9 = Object.assign || function (target) {
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$9.apply(this, arguments);
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$9({}, userStyle, {
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$9({}, style, {
1579
+ var containerStyle = !toastList.length ? _extends$a({}, style, {
1580
1580
  pointerEvents: 'none'
1581
- }) : _extends$9({}, style);
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$9({}, options, {
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$9({
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$9({}, options, pending));
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$9({
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$9({}, baseParams, params));
1751
+ toast.update(id, _extends$a({}, baseParams, params));
1752
1752
  } else {
1753
1753
  // using toast.promise without loading
1754
- toast(params.render, _extends$9({}, baseParams, params));
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$9({
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$9({}, oldOptions, options, {
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devtron-labs/devtron-fe-common-lib",
3
- "version": "0.0.7-beta-39",
3
+ "version": "0.0.7-beta-42",
4
4
  "description": "Supporting common component library",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -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>
@@ -0,0 +1,95 @@
1
+ import React, { useState } from 'react'
2
+ import { toast } from 'react-toastify'
3
+ import { useHistory } from 'react-router'
4
+ import info from '../assets/icons/ic-info-filled.svg'
5
+ import ConfirmationDialog from '../Dialogs/ConfirmationDialog'
6
+ import { DeleteDialog } from '../Dialogs'
7
+ import { ServerErrors } from '../ServerError'
8
+ import { DeleteComponentProps } from './types'
9
+
10
+ function DeleteComponent({
11
+ setDeleting,
12
+ toggleConfirmation,
13
+ deleteComponent,
14
+ title,
15
+ component,
16
+ payload,
17
+ confirmationDialogDescription = '',
18
+ redirectTo = false,
19
+ url = '',
20
+ reload,
21
+ configuration = '',
22
+ closeCustomComponent,
23
+ }: DeleteComponentProps) {
24
+ const [showCannotDeleteDialogModal, setCannotDeleteDialogModal] = useState(false)
25
+ const { push } = useHistory()
26
+
27
+ async function handleDelete() {
28
+ setDeleting(true)
29
+ try {
30
+ await deleteComponent(payload)
31
+ toast.success('Successfully deleted')
32
+ toggleConfirmation(false)
33
+ if (redirectTo) {
34
+ push(url)
35
+ } else {
36
+ reload()
37
+ }
38
+ if (typeof closeCustomComponent === 'function') {
39
+ closeCustomComponent()
40
+ }
41
+ } catch (serverError) {
42
+ if (serverError instanceof ServerErrors && serverError.code === 500) {
43
+ setCannotDeleteDialogModal(true)
44
+ }
45
+ } finally {
46
+ setDeleting(false)
47
+ }
48
+ }
49
+
50
+ const handleConfirmation = () => {
51
+ setCannotDeleteDialogModal(false)
52
+ toggleConfirmation(false)
53
+ if (typeof closeCustomComponent === 'function') {
54
+ closeCustomComponent()
55
+ }
56
+ }
57
+
58
+ const renderCannotDeleteDialogModal = () => {
59
+ return (
60
+ <ConfirmationDialog className="confirmation-dialog__body--w-360">
61
+ <ConfirmationDialog.Icon src={info} />
62
+ <ConfirmationDialog.Body title={`Cannot delete ${component} '${title}'`} />
63
+ <p className="fs-13 cn-7 ">{confirmationDialogDescription}</p>
64
+ <ConfirmationDialog.ButtonGroup>
65
+ <button type="button" className="cta" onClick={handleConfirmation}>
66
+ Okay
67
+ </button>
68
+ </ConfirmationDialog.ButtonGroup>
69
+ </ConfirmationDialog>
70
+ )
71
+ }
72
+
73
+ const renderDeleteDialog = () => {
74
+ return (
75
+ <DeleteDialog
76
+ title={`Delete ${component} '${title}'`}
77
+ delete={handleDelete}
78
+ closeDelete={() => toggleConfirmation(false)}
79
+ dataTestId="delete-dialog"
80
+ >
81
+ <DeleteDialog.Description>
82
+ <p>Are you sure you want to delete this {configuration ? configuration : component}? </p>
83
+ </DeleteDialog.Description>
84
+ </DeleteDialog>
85
+ )
86
+ }
87
+ return (
88
+ <div>
89
+ {!showCannotDeleteDialogModal && renderDeleteDialog()}
90
+ {showCannotDeleteDialogModal && renderCannotDeleteDialogModal()}
91
+ </div>
92
+ )
93
+ }
94
+
95
+ export default DeleteComponent
@@ -0,0 +1,15 @@
1
+ export interface DeleteComponentProps {
2
+ setDeleting: (boolean) => void
3
+ toggleConfirmation: any
4
+ deleteComponent: (any) => Promise<any>
5
+ title: string
6
+ component: string
7
+ payload: any
8
+ confirmationDialogDescription?: string
9
+ redirectTo?: boolean
10
+ url?: string
11
+ reload?: () => void
12
+ configuration?: string
13
+ dataTestid?: string
14
+ closeCustomComponent?: () => void
15
+ }
@@ -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
- autoClose: 3000,
10
- hideProgressBar: true,
11
- pauseOnHover: true,
12
- pauseOnFocusLoss: true,
13
- closeOnClick: false,
14
- newestOnTop: true,
15
- toastClassName: 'devtron-toast',
16
- bodyClassName: 'devtron-toast__body',
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
- if (serverError instanceof ServerErrors && Array.isArray(serverError.errors)) {
21
- serverError.errors.map(({ userMessage, internalMessage }) => {
22
- if (
23
- serverError.code === 403 &&
24
- (userMessage === ERROR_EMPTY_SCREEN.UNAUTHORIZED || userMessage === ERROR_EMPTY_SCREEN.FORBIDDEN)
25
- ) {
26
- if (!hideAccessError) {
27
- toastAccessDenied()
28
- }
29
- } else {
30
- toast.error(userMessage || internalMessage)
31
- }
32
- })
33
- } else {
34
- if (serverError.code !== 403 && serverError.code !== 408) {
35
- Sentry.captureException(serverError)
36
- }
37
-
38
- if (showToastOnUnknownError) {
39
- if (serverError.message) {
40
- toast.error(serverError.message)
41
- } else {
42
- toast.error('Some Error Occurred')
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
+ }