Skip to content

Commit 9339f43

Browse files
committed
Merge branch 'develop' of https://github.com/devtron-labs/devtron-fe-common-lib into feat/security-modal
2 parents a6096f9 + 6db886c commit 9339f43

30 files changed

+710
-203
lines changed

package-lock.json

Lines changed: 9 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@devtron-labs/devtron-fe-common-lib",
3-
"version": "0.3.11-beta-1",
3+
"version": "0.3.15",
44
"description": "Supporting common component library",
55
"type": "module",
66
"main": "dist/index.js",
@@ -87,6 +87,7 @@
8787
"react-router": "^5.3.0",
8888
"react-router-dom": "^5.3.0",
8989
"react-select": "5.8.0",
90+
"react-keybind": "^0.9.4",
9091
"rxjs": "^7.8.1",
9192
"yaml": "^2.4.1"
9293
},

src/Assets/Icon/ic-collapse-all.svg

Lines changed: 3 additions & 0 deletions
Loading

src/Assets/Icon/ic-expand-all.svg

Lines changed: 3 additions & 0 deletions
Loading

src/Common/Constants.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,3 +548,6 @@ export const VULNERABILITIES_SORT_PRIORITY = {
548548
low: 4,
549549
unknown: 5,
550550
}
551+
552+
// TODO: might not work need to verify
553+
export const IS_PLATFORM_MAC_OS = window.navigator.userAgent.toUpperCase().includes('MAC')

src/Common/CustomInput/CustomInput.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export const CustomInput = ({
3737
rootClassName = '',
3838
autoComplete = 'off',
3939
helperText = '',
40-
handleOnBlur,
40+
onBlur,
4141
readOnly = false,
4242
noTrim = false,
4343
onKeyPress,
@@ -66,15 +66,15 @@ export const CustomInput = ({
6666
return error
6767
}
6868

69-
const onBlur = (event) => {
69+
const handleOnBlur = (event) => {
7070
// NOTE: This is to prevent the input from being trimmed when the user do not want to trim the input
7171
if (!noTrim) {
7272
event.stopPropagation()
7373
event.target.value = event.target.value?.trim()
7474
onChange(event)
7575
}
76-
if (typeof handleOnBlur === 'function') {
77-
handleOnBlur(event)
76+
if (typeof onBlur === 'function') {
77+
onBlur(event)
7878
}
7979
}
8080

@@ -127,7 +127,7 @@ export const CustomInput = ({
127127
e.persist()
128128
onChange(e)
129129
}}
130-
onBlur={onBlur}
130+
onBlur={handleOnBlur}
131131
onFocus={onFocus}
132132
placeholder={placeholder}
133133
value={value}

src/Common/CustomInput/Types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export interface CustomInputProps {
3434
rootClassName?: string
3535
error?: string[] | string
3636
helperText?: ReactNode
37-
handleOnBlur?: (e) => void
37+
onBlur?: (e) => void
3838
readOnly?: boolean
3939
noTrim?: boolean
4040
onKeyPress?: (e) => void

src/Common/CustomTagSelector/TagDetails.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export const TagDetails = ({
6060
{!hidePropagateTag && (
6161
<div
6262
className={`dc__border h-30 pl-4 pr-4 br-4 mr-8 pointer ${tagData.propagate ? 'bcn-7' : ''} ${tagData.key.startsWith('devtron.ai/') ? 'cursor-not-allowed bcn-1' : ''}`}
63-
onClick={propagateTagToResource}
63+
onClick={!tagData?.isPropagateDisabled ? propagateTagToResource : null}
6464
data-testid={`propagate-tag-${index}`}
6565
>
6666
<InjectTag className={`icon-dim-20 mt-4 ${tagData.propagate ? 'scn-0' : ''}`} />

src/Common/DeleteComponentModal/DeleteComponent.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@
1414
* limitations under the License.
1515
*/
1616

17-
import React, { useState } from 'react'
17+
import { useState } from 'react'
1818
import { useHistory } from 'react-router-dom'
1919
import info from '../../Assets/Icon/ic-info-filled.svg'
2020
import { ConfirmationDialog, DeleteDialog } from '../Dialogs'
2121
import { ServerErrors } from '../ServerError'
2222
import { DeleteComponentProps } from './types'
2323
import { ToastManager, ToastVariantType } from '@Shared/Services'
24+
import { showError } from '@Common/Helper'
2425

2526
const DeleteComponent = ({
2627
setDeleting,
@@ -36,11 +37,13 @@ const DeleteComponent = ({
3637
configuration = '',
3738
closeCustomComponent,
3839
}: DeleteComponentProps) => {
40+
const [isDeleting, setIsDeleting] = useState(false)
3941
const [showCannotDeleteDialogModal, setCannotDeleteDialogModal] = useState(false)
4042
const { push } = useHistory()
4143

4244
async function handleDelete() {
43-
setDeleting(true)
45+
setDeleting?.(true)
46+
setIsDeleting(true)
4447
try {
4548
await deleteComponent(payload)
4649
ToastManager.showToast({
@@ -59,9 +62,12 @@ const DeleteComponent = ({
5962
} catch (serverError) {
6063
if (serverError instanceof ServerErrors && serverError.code === 500) {
6164
setCannotDeleteDialogModal(true)
65+
} else {
66+
showError(serverError)
6267
}
6368
} finally {
64-
setDeleting(false)
69+
setDeleting?.(false)
70+
setIsDeleting(false)
6571
}
6672
}
6773

@@ -92,6 +98,7 @@ const DeleteComponent = ({
9298
delete={handleDelete}
9399
closeDelete={() => toggleConfirmation(false)}
94100
dataTestId="delete-dialog"
101+
apiCallInProgress={isDeleting}
95102
>
96103
<DeleteDialog.Description>
97104
<p>Are you sure you want to delete this {configuration || component}? </p>

src/Common/DeleteComponentModal/types.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
*/
1616

1717
export interface DeleteComponentProps {
18-
setDeleting: (boolean) => void
18+
/**
19+
* @deprecated - Delete component internally handles loading for the `Delete Button`.
20+
*/
21+
setDeleting?: (boolean) => void
1922
toggleConfirmation: any
2023
deleteComponent: (any) => Promise<any>
2124
title: string

src/Common/Helper.tsx

Lines changed: 0 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -206,110 +206,6 @@ export function getCookie(sKey) {
206206
)
207207
}
208208

209-
export function useForm(stateSchema, validationSchema = {}, callback) {
210-
const [state, setState] = useState(stateSchema)
211-
const [disable, setDisable] = useState(true)
212-
const [isDirty, setIsDirty] = useState(false)
213-
214-
// Disable button in initial render.
215-
useEffect(() => {
216-
setDisable(true)
217-
}, [])
218-
219-
// For every changed in our state this will be fired
220-
// To be able to disable the button
221-
useEffect(() => {
222-
if (isDirty) {
223-
setDisable(validateState(state))
224-
}
225-
}, [state, isDirty])
226-
227-
// Used to disable submit button if there's an error in state
228-
// or the required field in state has no value.
229-
// Wrapped in useCallback to cached the function to avoid intensive memory leaked
230-
// in every re-render in component
231-
const validateState = useCallback(
232-
(state) => {
233-
// check errors in all fields
234-
const hasErrorInState = Object.keys(validationSchema).some((key) => {
235-
const isInputFieldRequired = validationSchema[key].required
236-
const stateValue = state[key].value // state value
237-
const stateError = state[key].error // state error
238-
return (isInputFieldRequired && !stateValue) || stateError
239-
})
240-
return hasErrorInState
241-
},
242-
[state, validationSchema],
243-
)
244-
245-
function validateField(name, value): string | string[] {
246-
if (validationSchema[name].required) {
247-
if (!value) {
248-
return 'This is a required field.'
249-
}
250-
}
251-
252-
function _validateSingleValidator(validator, value) {
253-
if (value && !validator.regex.test(value)) {
254-
return false
255-
}
256-
return true
257-
}
258-
259-
// single validator
260-
const _validator = validationSchema[name].validator
261-
if (_validator && typeof _validator === 'object') {
262-
if (!_validateSingleValidator(_validator, value)) {
263-
return _validator.error
264-
}
265-
}
266-
267-
// multiple validators
268-
const _validators = validationSchema[name].validators
269-
if (_validators && typeof _validators === 'object' && Array.isArray(_validators)) {
270-
const errors = []
271-
_validators.forEach((_validator) => {
272-
if (!_validateSingleValidator(_validator, value)) {
273-
errors.push(_validator.error)
274-
}
275-
})
276-
if (errors.length > 0) {
277-
return errors
278-
}
279-
}
280-
281-
return ''
282-
}
283-
284-
const handleOnChange = useCallback(
285-
(event) => {
286-
setIsDirty(true)
287-
288-
const { name, value } = event.target
289-
const error = validateField(name, value)
290-
setState((prevState) => ({
291-
...prevState,
292-
[name]: { value, error },
293-
}))
294-
},
295-
[validationSchema],
296-
)
297-
298-
const handleOnSubmit = (event) => {
299-
event.preventDefault()
300-
const newState = Object.keys(validationSchema).reduce((agg, curr) => {
301-
agg[curr] = { ...state[curr], error: validateField(curr, state[curr].value) }
302-
return agg
303-
}, state)
304-
if (!validateState(newState)) {
305-
callback(state)
306-
} else {
307-
setState({ ...newState })
308-
}
309-
}
310-
return { state, disable, handleOnChange, handleOnSubmit }
311-
}
312-
313209
export function handleUTCTime(ts: string, isRelativeTime = false) {
314210
let timestamp = ''
315211
try {
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { KEYBOARD_KEYS_MAP, TooltipProps } from './types'
2+
3+
const ShortcutKeyComboTooltipContent = ({ text, combo }: TooltipProps['shortcutKeyCombo']) => (
4+
<div className="flexbox dc__gap-8 px-8 py-4 flex-wrap">
5+
<span className="lh-18 fs-12 fw-4 cn-0">{text}</span>
6+
{!!combo?.length && (
7+
<div className="flexbox dc__gap-4 dc__align-items-center flex-wrap">
8+
{combo.map((key) => (
9+
<span key={key} className="shortcut-keys__chip dc__capitalize lh-16 fs-11 fw-5 flex">
10+
{KEYBOARD_KEYS_MAP[key]}
11+
</span>
12+
))}
13+
</div>
14+
)}
15+
</div>
16+
)
17+
18+
export default ShortcutKeyComboTooltipContent

src/Common/Tooltip/Tooltip.tsx

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import { useState, cloneElement } from 'react'
22
import TippyJS from '@tippyjs/react'
33
import { TooltipProps } from './types'
4+
import ShortcutKeyComboTooltipContent from './ShortcutKeyComboTooltipContent'
5+
import './styles.scss'
46

57
const Tooltip = ({
8+
shortcutKeyCombo,
69
alwaysShowTippyOnHover,
7-
// NOTE: if alwaysShowTippyOnHover is being passed by user don't apply truncation logic at all
8-
showOnTruncate = alwaysShowTippyOnHover === undefined,
10+
// NOTE: if alwaysShowTippyOnHover or shortcutKeyCombo are being passed by user don't apply truncation logic at all
11+
showOnTruncate = alwaysShowTippyOnHover === undefined && shortcutKeyCombo === undefined,
912
wordBreak = true,
1013
children: child,
1114
...rest
@@ -22,17 +25,24 @@ const Tooltip = ({
2225
}
2326
}
2427

25-
return (!isTextTruncated || !showOnTruncate) && !alwaysShowTippyOnHover ? (
26-
cloneElement(child, { ...child.props, onMouseEnter: handleMouseEnterEvent })
27-
) : (
28+
const showTooltipWhenShortcutKeyComboProvided =
29+
!!shortcutKeyCombo && (alwaysShowTippyOnHover === undefined || alwaysShowTippyOnHover)
30+
const showTooltipOnTruncate = showOnTruncate && isTextTruncated
31+
32+
return showTooltipOnTruncate || showTooltipWhenShortcutKeyComboProvided || alwaysShowTippyOnHover ? (
2833
<TippyJS
2934
arrow={false}
3035
placement="top"
36+
// NOTE: setting the default maxWidth to empty string so that we can override using css
37+
maxWidth=""
3138
{...rest}
32-
className={`default-tt ${wordBreak ? 'dc__word-break-all' : ''} dc__mxw-200-imp ${rest.className}`}
39+
{...(shortcutKeyCombo ? { content: <ShortcutKeyComboTooltipContent {...shortcutKeyCombo} /> } : {})}
40+
className={`${shortcutKeyCombo ? 'shortcut-keys__tippy' : 'default-tt'} ${wordBreak ? 'dc__word-break-all' : ''} dc__mxw-200 ${rest.className ?? ''}`}
3341
>
3442
{cloneElement(child, { ...child.props, onMouseEnter: handleMouseEnterEvent })}
3543
</TippyJS>
44+
) : (
45+
cloneElement(child, { ...child.props, onMouseEnter: handleMouseEnterEvent })
3646
)
3747
}
3848

src/Common/Tooltip/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export { default as Tooltip } from './Tooltip'
2+
export type { SupportedKeyboardKeysType } from './types'
23
export { TOOLTIP_CONTENTS } from './constants'

src/Common/Tooltip/styles.scss

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.tippy-box.shortcut-keys__tippy {
2+
border-radius: 4px;
3+
border: 1px solid rgba(255, 255, 255, 0.20);
4+
background: var(--N900);
5+
6+
& > .tippy-content {
7+
padding: 0;
8+
}
9+
10+
& .shortcut-keys__chip {
11+
border-radius: 4px;
12+
border: 0.5px solid rgba(255, 255, 255, 0.20);
13+
background: var(--N800);
14+
box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, 0.20);
15+
padding: 0 2px;
16+
min-width: 16px;
17+
max-width: 250px;
18+
}
19+
}

0 commit comments

Comments
 (0)