@devtron-labs/devtron-fe-common-lib 0.0.7 → 0.0.9-beta-2

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.
Files changed (86) hide show
  1. package/dist/Common/BreadCrumb/BreadCrumb.d.ts +1 -29
  2. package/dist/Common/BreadCrumb/Types.d.ts +28 -0
  3. package/dist/Common/CIPipeline.Types.d.ts +264 -0
  4. package/dist/Common/Checkbox.d.ts +1 -14
  5. package/dist/Common/Constants.d.ts +18 -0
  6. package/dist/Common/CustomTagSelector/ResizableTagTextArea.d.ts +1 -1
  7. package/dist/Common/CustomTagSelector/TagLabelValueSelector.d.ts +1 -1
  8. package/dist/Common/CustomTagSelector/Types.d.ts +11 -3
  9. package/dist/Common/CustomTagSelector/ValidationRules.d.ts +1 -1
  10. package/dist/Common/DeleteComponentModal/DeleteComponent.d.ts +4 -0
  11. package/dist/Common/DeleteComponentModal/types.d.ts +15 -0
  12. package/dist/Common/Dialogs/ConfirmationDialog.d.ts +5 -16
  13. package/dist/Common/Dialogs/DialogForm.d.ts +1 -9
  14. package/dist/Common/Dialogs/Types.d.ts +28 -0
  15. package/dist/Common/EmptyState/EmptyState.d.ts +2 -1
  16. package/dist/Common/EmptyState/GenericEmptyState.d.ts +5 -0
  17. package/dist/Common/Error.d.ts +2 -2
  18. package/dist/Common/Helper.d.ts +31 -1
  19. package/dist/Common/InfoColorBar/InfoColourbar.d.ts +2 -15
  20. package/dist/Common/Modals/Modal.d.ts +2 -9
  21. package/dist/Common/MultiSelectCustomization.d.ts +1 -2
  22. package/dist/Common/PopupMenu.d.ts +4 -21
  23. package/dist/Common/Progressing.d.ts +4 -13
  24. package/dist/Common/RadioGroup/RadioGroup.d.ts +17 -0
  25. package/dist/Common/RadioGroup.d.ts +1 -10
  26. package/dist/Common/Reload.d.ts +2 -4
  27. package/dist/Common/Security/ScanVulnerabilitiesTable.d.ts +4 -0
  28. package/dist/Common/TippyCustomized.d.ts +2 -30
  29. package/dist/Common/Toggle/Toggle.d.ts +12 -0
  30. package/dist/Common/Types.d.ts +293 -0
  31. package/dist/Common/index.d.ts +7 -1
  32. package/dist/index.js +2472 -1948
  33. package/package.json +2 -2
  34. package/rollup.config.js +3 -3
  35. package/src/Assets/Icon/ic-help.svg +3 -0
  36. package/src/Assets/Icon/ic-info-filled.svg +7 -0
  37. package/src/Assets/Icon/ic-warning.svg +7 -0
  38. package/src/Assets/Img/app-not-deployed.png +0 -0
  39. package/src/Common/Api.ts +7 -1
  40. package/src/Common/BreadCrumb/BreadCrumb.tsx +1 -30
  41. package/src/Common/BreadCrumb/Types.ts +30 -0
  42. package/src/Common/CIPipeline.Types.ts +276 -0
  43. package/src/Common/Checkbox.tsx +3 -16
  44. package/src/Common/Constants.ts +21 -0
  45. package/src/Common/CustomTagSelector/ResizableTagTextArea.tsx +6 -4
  46. package/src/Common/CustomTagSelector/TagDetails.tsx +15 -2
  47. package/src/Common/CustomTagSelector/TagLabelSelect.tsx +7 -3
  48. package/src/Common/CustomTagSelector/TagLabelValueSelector.tsx +66 -26
  49. package/src/Common/CustomTagSelector/Types.ts +11 -3
  50. package/src/Common/CustomTagSelector/ValidationRules.ts +21 -18
  51. package/src/Common/DeleteComponentModal/DeleteComponent.tsx +95 -0
  52. package/src/Common/DeleteComponentModal/types.ts +15 -0
  53. package/src/Common/Dialogs/ConfirmationDialog.tsx +6 -4
  54. package/src/Common/Dialogs/DeleteDialog.tsx +45 -27
  55. package/src/Common/Dialogs/DialogForm.tsx +2 -11
  56. package/src/Common/Dialogs/Types.ts +29 -0
  57. package/src/Common/Drawer/Drawer.scss +12 -11
  58. package/src/Common/EmptyState/EmptyState.tsx +5 -5
  59. package/src/Common/EmptyState/GenericEmptyState.tsx +41 -0
  60. package/src/Common/EmptyState/emptyState.scss +4 -15
  61. package/src/Common/Error.tsx +13 -16
  62. package/src/Common/ErrorScreenNotFound.tsx +23 -30
  63. package/src/Common/Helper.tsx +258 -2
  64. package/src/Common/InfoColorBar/InfoColourbar.tsx +6 -18
  65. package/src/Common/Modals/Modal.tsx +7 -1
  66. package/src/Common/Modals/OpaqueModal.tsx +2 -2
  67. package/src/Common/Modals/VisibleModal.tsx +1 -1
  68. package/src/Common/Modals/VisibleModal2.tsx +1 -1
  69. package/src/Common/MultiSelectCustomization.tsx +3 -3
  70. package/src/Common/PopupMenu.tsx +23 -6
  71. package/src/Common/Progressing.tsx +8 -15
  72. package/src/Common/RadioGroup/RadioGroup.tsx +88 -0
  73. package/src/Common/RadioGroup/radioGroup.scss +46 -0
  74. package/src/Common/RadioGroup.tsx +3 -13
  75. package/src/Common/Reload.tsx +15 -10
  76. package/src/Common/Security/ScanVulnerabilitiesTable.tsx +55 -0
  77. package/src/Common/Security/scanVulnerabilities.css +67 -0
  78. package/src/Common/TippyCustomized.tsx +29 -31
  79. package/src/Common/Toggle/Toggle.scss +70 -0
  80. package/src/Common/Toggle/Toggle.tsx +38 -0
  81. package/src/Common/Types.ts +319 -0
  82. package/src/Common/index.ts +7 -1
  83. package/dist/27bfa7a87d0b7039.png +0 -0
  84. package/dist/b5d52f036bdcd3ed.png +0 -0
  85. package/src/Assets/Icon/ic-close.svg +0 -9
  86. /package/src/Assets/Img/{warning-medium.svg → delete-medium.svg} +0 -0
@@ -0,0 +1,41 @@
1
+ import React from 'react'
2
+ import AppNotDeployed from '../../Assets/Img/app-not-deployed.png'
3
+ import { GenericEmptyStateType, ImageType } from '../Types'
4
+ import './emptyState.scss'
5
+
6
+ function GenericEmptyState({
7
+ title,
8
+ image,
9
+ subTitle,
10
+ isButtonAvailable,
11
+ classname,
12
+ styles,
13
+ heightToDeduct,
14
+ imageType,
15
+ renderButton,
16
+ imageClassName,
17
+ children,
18
+ noImage
19
+ }: GenericEmptyStateType): JSX.Element {
20
+ return (
21
+ <div
22
+ className={`flex column empty-state dc__align-reload-center ${classname ? classname : ''}`}
23
+ style={styles}
24
+ data-testid="generic-empty-state"
25
+ {...(heightToDeduct >= 0 && { style: { ...styles, height: `calc(100vh - ${heightToDeduct}px)` } })}
26
+ >
27
+ {!noImage && <img className={imageClassName ? imageClassName : ''}
28
+ src={image || AppNotDeployed}
29
+ width={imageType === ImageType.Medium ? '200' : '250'}
30
+ height={imageType === ImageType.Medium ? '160' : '200'}
31
+ alt="empty-state"
32
+ />}
33
+ <h4 className="title fw-6 cn-9 mb-8 mt-20">{title}</h4>
34
+ {subTitle && <p className="subtitle">{subTitle}</p>}
35
+ {isButtonAvailable && renderButton()}
36
+ {children}
37
+ </div>
38
+ )
39
+ }
40
+
41
+ export default GenericEmptyState
@@ -19,12 +19,9 @@
19
19
  h6 {
20
20
  color: var(--N900);
21
21
  }
22
- .title {
23
- font-weight: 600;
24
- }
25
22
  .subtitle {
26
23
  font-size: 13px;
27
- width: 250px;
24
+ width: 300px;
28
25
  font-weight: 400;
29
26
  text-align: center;
30
27
  line-height: 1.5;
@@ -34,7 +31,7 @@
34
31
  height: 36px;
35
32
  }
36
33
  p {
37
- width: 250px;
34
+ width: 300px;
38
35
  text-align: center;
39
36
  font-size: 13px;
40
37
  color: var(--N700);
@@ -68,16 +65,8 @@
68
65
  color: var(--N900);
69
66
  }
70
67
  .button__icon {
71
- width:16px;
72
- height:16px;
68
+ width: 16px;
69
+ height: 16px;
73
70
  margin-left: 8px;
74
71
  }
75
- //TODO: use name
76
- // .subtitle a {
77
- // color: inherit;
78
- // }
79
- // .subtitle a:focus,
80
- // .subtitle a:hover {
81
- // color: inherit;
82
- // }
83
72
  }
@@ -1,8 +1,10 @@
1
1
  import React, { Component } from 'react'
2
2
  import EmptyState from './EmptyState/EmptyState'
3
3
  import notAuthorized from '../Assets/Img/ic-not-authorized.svg'
4
- import Reload from './Reload'
5
4
  import ErrorScreenNotFound from './ErrorScreenNotFound'
5
+ import { ERROR_EMPTY_SCREEN } from './Constants'
6
+ import GenericEmptyState from './EmptyState/GenericEmptyState'
7
+ import Reload from './Reload'
6
8
 
7
9
  export class ErrorScreenManager extends Component<{
8
10
  code?: number
@@ -19,7 +21,7 @@ export class ErrorScreenManager extends Component<{
19
21
  return 'Unauthorized'
20
22
  case 403:
21
23
  return (
22
- <ErrorScreenNotAuthorized subtitle={this.props.subtitle} subtitleClass={this.props.subtitleClass} />
24
+ <ErrorScreenNotAuthorized subtitle={this.props.subtitle} />
23
25
  )
24
26
  case 404:
25
27
  return <ErrorScreenNotFound />
@@ -43,22 +45,17 @@ export class ErrorScreenManager extends Component<{
43
45
  }
44
46
  }
45
47
 
46
- export class ErrorScreenNotAuthorized extends Component<{ subtitle: React.ReactChild; subtitleClass?: string }> {
48
+ export class ErrorScreenNotAuthorized extends Component<{
49
+ subtitle?: React.ReactChild
50
+ title?: string
51
+ }> {
47
52
  render() {
48
53
  return (
49
- <EmptyState>
50
- <EmptyState.Image>
51
- <img src={notAuthorized} alt="Not Authorized" />
52
- </EmptyState.Image>
53
- <EmptyState.Title>
54
- <h3 className="title">Not authorized</h3>
55
- </EmptyState.Title>
56
- <EmptyState.Subtitle className={this.props.subtitleClass}>
57
- {this.props.subtitle
58
- ? this.props.subtitle
59
- : "Looks like you don't have access to information on this page. Please contact your manager to request access."}
60
- </EmptyState.Subtitle>
61
- </EmptyState>
54
+ <GenericEmptyState
55
+ image={notAuthorized}
56
+ title={this.props.title ?? ERROR_EMPTY_SCREEN.NOT_AUTHORIZED}
57
+ subTitle={this.props.subtitle ?? ERROR_EMPTY_SCREEN.ONLY_FOR_SUPERADMIN}
58
+ />
62
59
  )
63
60
  }
64
61
  }
@@ -1,38 +1,31 @@
1
1
  import React from 'react'
2
2
  import notFound from '../Assets/Img/ic-empty-error@2x.png'
3
- import { useHistory } from 'react-router'
4
- import EmptyState from './EmptyState/EmptyState'
3
+ import { useHistory } from 'react-router-dom'
5
4
  import { ERROR_EMPTY_SCREEN } from './Constants'
5
+ import GenericEmptyState from './EmptyState/GenericEmptyState'
6
6
 
7
7
  function ErrorScreenNotFound() {
8
- const history = useHistory()
8
+ const {push} = useHistory()
9
+ const redirectToHome = () => {
10
+ push('/app/list')
11
+ }
12
+ const renderGenerateButton = () => {
13
+ return (
14
+ <button className="flex cta h-32" onClick={redirectToHome} data-testid="empty-screen-take-me-home">
15
+ {ERROR_EMPTY_SCREEN.TAKE_BACK_HOME}
16
+ </button>
17
+ )
18
+ }
9
19
 
10
- const redirectToHome = () => {
11
- history.push('/app/list')
12
- }
13
-
14
- return (
15
- <div>
16
- <EmptyState>
17
- <EmptyState.Image>
18
- <img src={notFound} alt="Not Found" />
19
- </EmptyState.Image>
20
- <EmptyState.Title>
21
- <h3 className="title">{ERROR_EMPTY_SCREEN.PAGE_NOT_FOUND}</h3>
22
- </EmptyState.Title>
23
- <EmptyState.Subtitle >
24
- <p>{ERROR_EMPTY_SCREEN.PAGE_NOT_EXIST}</p>
25
- </EmptyState.Subtitle>
26
- <EmptyState.Button>
27
- <button className="flex cta h-32"
28
- onClick={redirectToHome}
29
- >
30
- {ERROR_EMPTY_SCREEN.TAKE_BACK_HOME}
31
- </button>
32
- </EmptyState.Button>
33
- </EmptyState>
34
- </div>
35
- )
20
+ return (
21
+ <GenericEmptyState
22
+ image={notFound}
23
+ title={ERROR_EMPTY_SCREEN.PAGE_NOT_FOUND}
24
+ subTitle={ERROR_EMPTY_SCREEN.PAGE_NOT_EXIST}
25
+ isButtonAvailable={true}
26
+ renderButton={renderGenerateButton}
27
+ />
28
+ )
36
29
  }
37
30
 
38
- export default ErrorScreenNotFound
31
+ export default ErrorScreenNotFound
@@ -1,13 +1,29 @@
1
+ import React, { useCallback, useEffect, useRef, useState } from 'react'
1
2
  import { ServerErrors } from './ServerError'
2
3
  import { toast } from 'react-toastify'
3
4
  import * as Sentry from '@sentry/browser'
4
5
  import { toastAccessDenied } from './ToastBody'
5
- import { useEffect, useRef } from 'react'
6
+ import { ERROR_EMPTY_SCREEN, TOKEN_COOKIE_NAME } from './Constants'
7
+ import { ReactComponent as FormError } from '../Assets/Icon/ic-warning.svg'
8
+
9
+ toast.configure({
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',
18
+ })
6
19
 
7
20
  export function showError(serverError, showToastOnUnknownError = true, hideAccessError = false) {
8
21
  if (serverError instanceof ServerErrors && Array.isArray(serverError.errors)) {
9
22
  serverError.errors.map(({ userMessage, internalMessage }) => {
10
- if (serverError.code === 403 && userMessage === 'unauthorized') {
23
+ if (
24
+ serverError.code === 403 &&
25
+ (userMessage === ERROR_EMPTY_SCREEN.UNAUTHORIZED || userMessage === ERROR_EMPTY_SCREEN.FORBIDDEN)
26
+ ) {
11
27
  if (!hideAccessError) {
12
28
  toastAccessDenied()
13
29
  }
@@ -75,3 +91,243 @@ export function useThrottledEffect(callback, delay, deps = []) {
75
91
  }
76
92
  }, [delay, ...deps])
77
93
  }
94
+
95
+ const colors = [
96
+ '#FFB900',
97
+ '#D83B01',
98
+ '#B50E0E',
99
+ '#E81123',
100
+ '#B4009E',
101
+ '#5C2D91',
102
+ '#0078D7',
103
+ '#00B4FF',
104
+ '#008272',
105
+ '#107C10',
106
+ ]
107
+
108
+ export function getRandomColor(email: string): string {
109
+ let sum = 0
110
+ for (let i = 0; i < email.length; i++) {
111
+ sum += email.charCodeAt(i)
112
+ }
113
+ return colors[sum % colors.length]
114
+ }
115
+
116
+ export const getAlphabetIcon = (str: string) => {
117
+ if (!str) return null
118
+ return (
119
+ <span
120
+ className="alphabet-icon__initial fs-13 icon-dim-20 flex cn-0 mr-8"
121
+ style={{ backgroundColor: getRandomColor(str) }}
122
+ >
123
+ {str[0]}
124
+ </span>
125
+ )
126
+ }
127
+
128
+ export const getEmptyArrayOfLength = (length: number) => {
129
+ return Array.from({ length })
130
+ }
131
+
132
+ export function noop(...args): any {}
133
+
134
+ export function not(e) {
135
+ return !e
136
+ }
137
+
138
+ export function useEffectAfterMount(cb, dependencies) {
139
+ const justMounted = React.useRef(true)
140
+ React.useEffect(() => {
141
+ if (!justMounted.current) {
142
+ return cb()
143
+ }
144
+ justMounted.current = false
145
+ }, dependencies)
146
+ }
147
+
148
+ export function getCookie(sKey) {
149
+ if (!sKey) {
150
+ return null
151
+ }
152
+ return (
153
+ document.cookie.replace(
154
+ new RegExp('(?:(?:^|.*;)\\s*' + sKey.replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=\\s*([^;]*).*$)|^.*$'),
155
+ '$1',
156
+ ) || null
157
+ )
158
+ }
159
+
160
+ export function getLoginInfo() {
161
+ const argocdToken = getCookie(TOKEN_COOKIE_NAME)
162
+ if (argocdToken) {
163
+ const jwts = argocdToken.split('.')
164
+ try {
165
+ return JSON.parse(atob(jwts[1]))
166
+ } catch (err) {
167
+ console.error('error in setting user ', err)
168
+ return null
169
+ }
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
+ }
@@ -1,22 +1,8 @@
1
- import React, { CSSProperties } from 'react'
1
+ import React from 'react'
2
2
  import { Link } from 'react-router-dom'
3
+ import { InfoColourBarType } from '../Types'
3
4
  import './infoColourBar.scss'
4
5
 
5
- interface InfoColourBarType {
6
- message: React.ReactNode
7
- classname: string
8
- Icon
9
- iconClass?: string
10
- iconSize?: number // E.g. 16, 20, etc.. Currently, there are around 12 sizes supported. Check `icons.css` or `base.scss` for supported sizes or add new size (class names starts with `icon-dim-`).
11
- renderActionButton?: () => JSX.Element
12
- linkText?: React.ReactNode
13
- redirectLink?: string
14
- linkOnClick?: () => void
15
- linkClass?: string
16
- internalLink?: boolean
17
- styles?: CSSProperties
18
- }
19
-
20
6
  function InfoColourBar({
21
7
  message,
22
8
  classname,
@@ -40,6 +26,7 @@ function InfoColourBar({
40
26
  <Link
41
27
  to={redirectLink}
42
28
  onClick={linkOnClick}
29
+ data-testid="info-bar-internal-link"
43
30
  className="cursor dc__link dc__underline-onhover mr-5"
44
31
  >
45
32
  {linkText}
@@ -52,6 +39,7 @@ function InfoColourBar({
52
39
  href={redirectLink}
53
40
  target="_blank"
54
41
  onClick={linkOnClick}
42
+ data-testid="info-bar-redirectLink"
55
43
  className="cursor dc__link dc__underline-onhover mr-5"
56
44
  >
57
45
  {linkText}
@@ -61,7 +49,7 @@ function InfoColourBar({
61
49
 
62
50
  return (
63
51
  linkOnClick && (
64
- <div onClick={linkOnClick} className="cursor dc__link dc__underline-onhover">
52
+ <div onClick={linkOnClick} className="cursor dc__link dc__underline-onhover" data-testid="info-bar-linkText">
65
53
  {linkText}
66
54
  </div>
67
55
  )
@@ -71,7 +59,7 @@ function InfoColourBar({
71
59
  return (
72
60
  <div className="info-bar-container">
73
61
  <div
74
- className={`${classname} info_text flex dc__content-space pt-8 pb-8 pl-16 pr-16 br-4 top fs-13 fw-4`}
62
+ className={`${classname} info_text flex dc__content-space pt-8 pb-8 pl-12 pr-12 br-4 top fs-13 fw-4`}
75
63
  style={styles}
76
64
  >
77
65
  <div className={`flex top ${typeof renderActionButton === 'function' ? 'mr-5' : ''}`}>
@@ -1,5 +1,7 @@
1
1
  import React, { useEffect } from 'react'
2
2
  import ReactDOM from 'react-dom'
3
+ import { ModalType } from '../Types'
4
+
3
5
  export const Modal = ({
4
6
  style = {},
5
7
  children,
@@ -8,7 +10,8 @@ export const Modal = ({
8
10
  onClick = null,
9
11
  callbackRef = null,
10
12
  preventWheelDisable = false,
11
- }) => {
13
+ noBackDrop,
14
+ }: ModalType) => {
12
15
  const innerRef = React.useRef(null)
13
16
  function handleClick(e) {
14
17
  if (typeof onClick !== 'function') return
@@ -34,17 +37,20 @@ export const Modal = ({
34
37
  document.addEventListener('click', handleClick)
35
38
  let modal = document.getElementById('visible-modal')
36
39
  if (modal) modal.classList.add('show')
40
+ if (noBackDrop) modal.classList.add('no-back-drop')
37
41
  if (!preventWheelDisable) document.body.addEventListener('wheel', disableWheel, { passive: false })
38
42
  return () => {
39
43
  if (!preventWheelDisable) document.body.removeEventListener('wheel', disableWheel)
40
44
  document.removeEventListener('click', handleClick)
41
45
  if (modal) modal.classList.remove('show')
46
+ if (noBackDrop) modal.classList.remove('no-back-drop')
42
47
  }
43
48
  }, [])
44
49
  return ReactDOM.createPortal(
45
50
  <div
46
51
  tabIndex={0}
47
52
  onClick={onClick}
53
+ data-testid="common-modal"
48
54
  ref={(el) => {
49
55
  if (typeof callbackRef === 'function') {
50
56
  callbackRef(el)
@@ -1,6 +1,6 @@
1
1
  import React from 'react'
2
2
  import ReactDOM from 'react-dom';
3
- import closeIcon from '../../Assets/Icon/ic-close.svg'
3
+ import closeIcon from '../../Assets/Icon/ic-cross.svg'
4
4
 
5
5
  export interface OpaqueModalProps {
6
6
  className?: string;
@@ -28,7 +28,7 @@ export class OpaqueModal extends React.Component<OpaqueModalProps> {
28
28
  return ReactDOM.createPortal(
29
29
  <div className={`full-screen-modal__body-container ${className}`}>
30
30
  {this.props.children}
31
- {typeof onHide === 'function' && <div className="close-btn icon-dim-24" onClick={e => onHide(false)}>
31
+ {typeof onHide === 'function' && <div className="close-btn icon-dim-24" onClick={e => onHide(false)} data-testid="opaque-modal-close">
32
32
  <img className="close-img" src={closeIcon} alt="close" />
33
33
  </div>}
34
34
  </div>, document.getElementById('full-screen-modal'))
@@ -46,7 +46,7 @@ export class VisibleModal extends React.Component<{
46
46
 
47
47
  render() {
48
48
  return ReactDOM.createPortal(
49
- <div className={`visible-modal__body ${this.props.className}`} onClick={this.props?.close}>
49
+ <div className={`visible-modal__body ${this.props.className}`} onClick={this.props?.close} data-testid="visible-modal-close">
50
50
  {this.props.children}
51
51
  </div>,
52
52
  document.getElementById('visible-modal'),
@@ -28,7 +28,7 @@ export class VisibleModal2 extends React.Component<{ className: string; close?:
28
28
 
29
29
  render() {
30
30
  return ReactDOM.createPortal(
31
- <div className={`visible-modal__body ${this.props.className}`} onClick={this.props?.close}>
31
+ <div className={`visible-modal__body ${this.props.className}`} onClick={this.props?.close} data-testid="visible-modal2-close">
32
32
  {this.props.children}
33
33
  </div>, document.getElementById('visible-modal-2'))
34
34
  }
@@ -87,9 +87,9 @@ export const MultiValueChipContainer = ({ validator, isAllSelected = false, ...p
87
87
 
88
88
  return (
89
89
  <components.MultiValueContainer {...{ data, innerProps, selectProps }}>
90
- <div className={`flex fs-12 pl-4 pr-4`}>
90
+ <div className="flex left fs-12 pl-4 pr-4 dc__ellipsis-right">
91
91
  {!isValidEmail && <RedWarning className="mr-4 icon-dim-16" />}
92
- <div className={`${isValidEmail ? 'cn-9' : 'cr-5'}`}>{label}</div>
92
+ <div className={`dc__ellipsis-right ${isValidEmail ? 'cn-9' : 'cr-5'}`}>{label}</div>
93
93
  </div>
94
94
  {children[1]}
95
95
  </components.MultiValueContainer>
@@ -124,7 +124,7 @@ export const multiSelectStyles = {
124
124
  }),
125
125
  }
126
126
 
127
- interface CustomSelect {
127
+ export interface CustomSelect {
128
128
  sortSelected?: boolean
129
129
  options: any[]
130
130
  onChange: (...args) => void