@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.
- package/dist/Common/BreadCrumb/BreadCrumb.d.ts +1 -29
- package/dist/Common/BreadCrumb/Types.d.ts +28 -0
- package/dist/Common/CIPipeline.Types.d.ts +264 -0
- package/dist/Common/Checkbox.d.ts +1 -14
- package/dist/Common/Constants.d.ts +18 -0
- package/dist/Common/CustomTagSelector/ResizableTagTextArea.d.ts +1 -1
- package/dist/Common/CustomTagSelector/TagLabelValueSelector.d.ts +1 -1
- package/dist/Common/CustomTagSelector/Types.d.ts +11 -3
- package/dist/Common/CustomTagSelector/ValidationRules.d.ts +1 -1
- package/dist/Common/DeleteComponentModal/DeleteComponent.d.ts +4 -0
- package/dist/Common/DeleteComponentModal/types.d.ts +15 -0
- package/dist/Common/Dialogs/ConfirmationDialog.d.ts +5 -16
- package/dist/Common/Dialogs/DialogForm.d.ts +1 -9
- package/dist/Common/Dialogs/Types.d.ts +28 -0
- package/dist/Common/EmptyState/EmptyState.d.ts +2 -1
- package/dist/Common/EmptyState/GenericEmptyState.d.ts +5 -0
- package/dist/Common/Error.d.ts +2 -2
- package/dist/Common/Helper.d.ts +31 -1
- package/dist/Common/InfoColorBar/InfoColourbar.d.ts +2 -15
- package/dist/Common/Modals/Modal.d.ts +2 -9
- package/dist/Common/MultiSelectCustomization.d.ts +1 -2
- package/dist/Common/PopupMenu.d.ts +4 -21
- package/dist/Common/Progressing.d.ts +4 -13
- package/dist/Common/RadioGroup/RadioGroup.d.ts +17 -0
- package/dist/Common/RadioGroup.d.ts +1 -10
- package/dist/Common/Reload.d.ts +2 -4
- package/dist/Common/Security/ScanVulnerabilitiesTable.d.ts +4 -0
- package/dist/Common/TippyCustomized.d.ts +2 -30
- package/dist/Common/Toggle/Toggle.d.ts +12 -0
- package/dist/Common/Types.d.ts +293 -0
- package/dist/Common/index.d.ts +7 -1
- package/dist/index.js +2472 -1948
- package/package.json +2 -2
- package/rollup.config.js +3 -3
- package/src/Assets/Icon/ic-help.svg +3 -0
- package/src/Assets/Icon/ic-info-filled.svg +7 -0
- package/src/Assets/Icon/ic-warning.svg +7 -0
- package/src/Assets/Img/app-not-deployed.png +0 -0
- package/src/Common/Api.ts +7 -1
- package/src/Common/BreadCrumb/BreadCrumb.tsx +1 -30
- package/src/Common/BreadCrumb/Types.ts +30 -0
- package/src/Common/CIPipeline.Types.ts +276 -0
- package/src/Common/Checkbox.tsx +3 -16
- package/src/Common/Constants.ts +21 -0
- package/src/Common/CustomTagSelector/ResizableTagTextArea.tsx +6 -4
- package/src/Common/CustomTagSelector/TagDetails.tsx +15 -2
- package/src/Common/CustomTagSelector/TagLabelSelect.tsx +7 -3
- package/src/Common/CustomTagSelector/TagLabelValueSelector.tsx +66 -26
- package/src/Common/CustomTagSelector/Types.ts +11 -3
- package/src/Common/CustomTagSelector/ValidationRules.ts +21 -18
- package/src/Common/DeleteComponentModal/DeleteComponent.tsx +95 -0
- package/src/Common/DeleteComponentModal/types.ts +15 -0
- package/src/Common/Dialogs/ConfirmationDialog.tsx +6 -4
- package/src/Common/Dialogs/DeleteDialog.tsx +45 -27
- package/src/Common/Dialogs/DialogForm.tsx +2 -11
- package/src/Common/Dialogs/Types.ts +29 -0
- package/src/Common/Drawer/Drawer.scss +12 -11
- package/src/Common/EmptyState/EmptyState.tsx +5 -5
- package/src/Common/EmptyState/GenericEmptyState.tsx +41 -0
- package/src/Common/EmptyState/emptyState.scss +4 -15
- package/src/Common/Error.tsx +13 -16
- package/src/Common/ErrorScreenNotFound.tsx +23 -30
- package/src/Common/Helper.tsx +258 -2
- package/src/Common/InfoColorBar/InfoColourbar.tsx +6 -18
- package/src/Common/Modals/Modal.tsx +7 -1
- package/src/Common/Modals/OpaqueModal.tsx +2 -2
- package/src/Common/Modals/VisibleModal.tsx +1 -1
- package/src/Common/Modals/VisibleModal2.tsx +1 -1
- package/src/Common/MultiSelectCustomization.tsx +3 -3
- package/src/Common/PopupMenu.tsx +23 -6
- package/src/Common/Progressing.tsx +8 -15
- package/src/Common/RadioGroup/RadioGroup.tsx +88 -0
- package/src/Common/RadioGroup/radioGroup.scss +46 -0
- package/src/Common/RadioGroup.tsx +3 -13
- package/src/Common/Reload.tsx +15 -10
- package/src/Common/Security/ScanVulnerabilitiesTable.tsx +55 -0
- package/src/Common/Security/scanVulnerabilities.css +67 -0
- package/src/Common/TippyCustomized.tsx +29 -31
- package/src/Common/Toggle/Toggle.scss +70 -0
- package/src/Common/Toggle/Toggle.tsx +38 -0
- package/src/Common/Types.ts +319 -0
- package/src/Common/index.ts +7 -1
- package/dist/27bfa7a87d0b7039.png +0 -0
- package/dist/b5d52f036bdcd3ed.png +0 -0
- package/src/Assets/Icon/ic-close.svg +0 -9
- /package/src/Assets/Img/{warning-medium.svg → delete-medium.svg} +0 -0
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import React, { useState, useEffect } from 'react'
|
|
2
2
|
import PopupMenu from '../PopupMenu'
|
|
3
|
-
import { ValidationRules } from './ValidationRules'
|
|
4
3
|
import { ReactComponent as ErrorCross } from '../../Assets/Icon/ic-cross.svg'
|
|
5
4
|
import { ReactComponent as Info } from '../../Assets/Icon/ic-info-outlined.svg'
|
|
6
5
|
import { KEY_VALUE } from '../Constants'
|
|
7
6
|
import { stopPropagation } from '../Helper'
|
|
8
7
|
import { ResizableTagTextArea } from './ResizableTagTextArea'
|
|
9
|
-
import { TagLabelValueSelectorType } from './Types'
|
|
8
|
+
import { SuggestedTagOptionType, TagLabelValueSelectorType } from './Types'
|
|
9
|
+
import Tippy from '@tippyjs/react'
|
|
10
|
+
import { ValidationRules } from './ValidationRules'
|
|
10
11
|
|
|
11
12
|
export const TagLabelValueSelector = ({
|
|
12
13
|
selectedTagIndex,
|
|
@@ -19,6 +20,7 @@ export const TagLabelValueSelector = ({
|
|
|
19
20
|
tabIndex = null,
|
|
20
21
|
refVar,
|
|
21
22
|
dependentRef,
|
|
23
|
+
noBackDrop,
|
|
22
24
|
}: TagLabelValueSelectorType) => {
|
|
23
25
|
const [selectedValue, setSelectedValue] = useState<string>('')
|
|
24
26
|
const [activeElement, setActiveElement] = useState<string>('')
|
|
@@ -43,11 +45,12 @@ export const TagLabelValueSelector = ({
|
|
|
43
45
|
const _tagData = { ...tagData }
|
|
44
46
|
_tagData[tagInputType] = selectedValue
|
|
45
47
|
if (tagInputType === KEY_VALUE.KEY) {
|
|
46
|
-
_tagData.isInvalidKey =
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
_tagData.isInvalidKey =
|
|
49
|
+
selectedValue || _tagData.propagate
|
|
50
|
+
? !validationRules.propagateTagKey(selectedValue).isValid
|
|
51
|
+
: _tagData.value !== ''
|
|
52
|
+
} else if (selectedValue || isRequired || _tagData.propagate) {
|
|
53
|
+
_tagData.isInvalidValue = !validationRules.propagateTagValue(selectedValue, _tagData.key).isValid
|
|
51
54
|
_tagData.isInvalidKey = !_tagData.key || _tagData.isInvalidKey
|
|
52
55
|
} else {
|
|
53
56
|
_tagData.isInvalidValue = false
|
|
@@ -65,7 +68,9 @@ export const TagLabelValueSelector = ({
|
|
|
65
68
|
stopPropagation(e)
|
|
66
69
|
const _tagData = { ...tagData }
|
|
67
70
|
_tagData[tagInputType] = e.currentTarget.dataset.key
|
|
71
|
+
_tagData.propagate = e.currentTarget.dataset.propagate === 'true'
|
|
68
72
|
setTagData(selectedTagIndex, _tagData)
|
|
73
|
+
setActiveElement('')
|
|
69
74
|
}
|
|
70
75
|
|
|
71
76
|
const renderValidationsSuggestions = (): JSX.Element => {
|
|
@@ -74,12 +79,12 @@ export const TagLabelValueSelector = ({
|
|
|
74
79
|
if (selectedValue || tagData.value) {
|
|
75
80
|
field = validationRules.propagateTagKey(selectedValue)
|
|
76
81
|
}
|
|
77
|
-
} else if (isRequired || selectedValue) {
|
|
78
|
-
field = validationRules.propagateTagValue(selectedValue)
|
|
82
|
+
} else if (isRequired || selectedValue || tagData.propagate) {
|
|
83
|
+
field = validationRules.propagateTagValue(selectedValue, tagData.key)
|
|
79
84
|
}
|
|
80
85
|
if (!field.isValid) {
|
|
81
86
|
return (
|
|
82
|
-
<div className="p-4" onClick={stopPropagation}>
|
|
87
|
+
<div className="p-4" onClick={stopPropagation} data-testid="tag-label-cross-stop-propagation">
|
|
83
88
|
{field.messages.map((error) => (
|
|
84
89
|
<div key={error} className="flexbox pr-4 pl-4">
|
|
85
90
|
<span>
|
|
@@ -102,22 +107,48 @@ export const TagLabelValueSelector = ({
|
|
|
102
107
|
return null
|
|
103
108
|
}
|
|
104
109
|
|
|
110
|
+
const option = (tag: SuggestedTagOptionType, index: number): JSX.Element => {
|
|
111
|
+
return (
|
|
112
|
+
<div
|
|
113
|
+
key={`${tag.value}-${index}`}
|
|
114
|
+
data-key={tag.label}
|
|
115
|
+
data-propagate={tag.propagate}
|
|
116
|
+
className="dc__hover-n50 dc__ellipsis-right lh-20 fs-13 fw-4 pt-6 pr-8 pb-6 pl-8 cursor"
|
|
117
|
+
onClick={onSelectValue}
|
|
118
|
+
data-testid={`tag-label-value-${index}`}
|
|
119
|
+
>
|
|
120
|
+
{tag.label}
|
|
121
|
+
</div>
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const optionWithTippy = (tag: SuggestedTagOptionType, index: number): JSX.Element => {
|
|
126
|
+
return (
|
|
127
|
+
<Tippy
|
|
128
|
+
className="default-tt"
|
|
129
|
+
arrow={false}
|
|
130
|
+
placement="right"
|
|
131
|
+
content={
|
|
132
|
+
<div>
|
|
133
|
+
<div className="mb-10 fs-12 fw-6 cn-0 dc__break-word">{tag.label}</div>
|
|
134
|
+
<div className="fs-12 fw-4 cn-0 dc__break-word">{tag.description}</div>
|
|
135
|
+
</div>
|
|
136
|
+
}
|
|
137
|
+
>
|
|
138
|
+
{option(tag, index)}
|
|
139
|
+
</Tippy>
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
|
|
105
143
|
const renderSuggestions = (): JSX.Element => {
|
|
106
144
|
if (tagOptions?.length) {
|
|
107
|
-
const filteredTags = tagOptions.filter((tag) => tag.
|
|
145
|
+
const filteredTags = tagOptions.filter((tag) => tag.label.indexOf(selectedValue) >= 0)
|
|
108
146
|
if (filteredTags.length) {
|
|
109
147
|
return (
|
|
110
148
|
<div>
|
|
111
|
-
{filteredTags.map((tag, index) =>
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
data-key={tag.label}
|
|
115
|
-
className="dc__hover-n50 lh-20 fs-13 fw-4 pt-6 pr-8 pb-6 pl-8 cursor"
|
|
116
|
-
onClick={onSelectValue}
|
|
117
|
-
>
|
|
118
|
-
{tag.label}
|
|
119
|
-
</div>
|
|
120
|
-
))}
|
|
149
|
+
{filteredTags.map((tag, index) =>
|
|
150
|
+
tag.description ? optionWithTippy(tag, index) : option(tag, index),
|
|
151
|
+
)}
|
|
121
152
|
</div>
|
|
122
153
|
)
|
|
123
154
|
}
|
|
@@ -125,13 +156,14 @@ export const TagLabelValueSelector = ({
|
|
|
125
156
|
return renderValidationsSuggestions()
|
|
126
157
|
}
|
|
127
158
|
|
|
159
|
+
const popupMenuBody = activeElement === `tag-${tagInputType}-${selectedTagIndex}` ? renderSuggestions() : null
|
|
128
160
|
return (
|
|
129
161
|
<PopupMenu autoClose autoPosition>
|
|
130
|
-
<PopupMenu.Button rootClassName="dc__bg-n50 flex top dc__no-border">
|
|
162
|
+
<PopupMenu.Button rootClassName="dc__bg-n50 flex top dc__no-border-imp">
|
|
131
163
|
<ResizableTagTextArea
|
|
132
164
|
minHeight={30}
|
|
133
165
|
maxHeight={80}
|
|
134
|
-
className={`form__input pt-4-imp pb-4-imp fs-13 ${
|
|
166
|
+
className={`form__input tag-input pt-4-imp pb-4-imp fs-13 ${
|
|
135
167
|
tagInputType === KEY_VALUE.KEY
|
|
136
168
|
? `dc__no-right-radius`
|
|
137
169
|
: `dc__no-border-radius dc__no-right-border dc__no-left-border`
|
|
@@ -148,11 +180,19 @@ export const TagLabelValueSelector = ({
|
|
|
148
180
|
tabIndex={tabIndex}
|
|
149
181
|
refVar={refVar}
|
|
150
182
|
dependentRef={dependentRef}
|
|
183
|
+
dataTestId={`tag-${tagInputType === KEY_VALUE.KEY ? 'key' : 'value'}-${selectedTagIndex}`}
|
|
151
184
|
/>
|
|
152
185
|
</PopupMenu.Button>
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
186
|
+
{popupMenuBody && (
|
|
187
|
+
<PopupMenu.Body
|
|
188
|
+
rootClassName={`mxh-210 dc__overflow-auto tag-${selectedTagIndex}-class`}
|
|
189
|
+
autoWidth={true}
|
|
190
|
+
preventWheelDisable={true}
|
|
191
|
+
noBackDrop={noBackDrop}
|
|
192
|
+
>
|
|
193
|
+
{popupMenuBody}
|
|
194
|
+
</PopupMenu.Body>
|
|
195
|
+
)}
|
|
156
196
|
</PopupMenu>
|
|
157
197
|
)
|
|
158
198
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { KEY_VALUE } from '../Constants'
|
|
2
2
|
import { OptionType } from '../Types'
|
|
3
3
|
|
|
4
|
+
export interface SuggestedTagOptionType extends OptionType {
|
|
5
|
+
description: string
|
|
6
|
+
propagate: boolean
|
|
7
|
+
}
|
|
4
8
|
export interface TagType {
|
|
5
9
|
id?: number
|
|
6
10
|
key: string
|
|
@@ -11,6 +15,7 @@ export interface TagType {
|
|
|
11
15
|
isInvalidKey?: boolean
|
|
12
16
|
isInvalidValue?: boolean
|
|
13
17
|
isSuggested?: boolean
|
|
18
|
+
isPropagateDisabled?: boolean
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
export interface TagErrorType {
|
|
@@ -23,7 +28,8 @@ export interface TagLabelSelectType {
|
|
|
23
28
|
setLabelTags: (tagList: TagType[]) => void
|
|
24
29
|
tabIndex?: number
|
|
25
30
|
selectedProjectId?: number
|
|
26
|
-
suggestedTagsOptions?:
|
|
31
|
+
suggestedTagsOptions?: SuggestedTagOptionType[]
|
|
32
|
+
reloadProjectTags?: boolean
|
|
27
33
|
}
|
|
28
34
|
|
|
29
35
|
export interface TagDetailType {
|
|
@@ -32,20 +38,21 @@ export interface TagDetailType {
|
|
|
32
38
|
setTagData: (index: number, tagData: TagType) => void
|
|
33
39
|
removeTag?: (index: number) => void
|
|
34
40
|
tabIndex?: number
|
|
35
|
-
suggestedTagsOptions?:
|
|
41
|
+
suggestedTagsOptions?: SuggestedTagOptionType[]
|
|
36
42
|
}
|
|
37
43
|
|
|
38
44
|
export interface TagLabelValueSelectorType {
|
|
39
45
|
selectedTagIndex: number
|
|
40
46
|
tagData: TagType
|
|
41
47
|
setTagData: (index: number, tagData: TagType) => void
|
|
42
|
-
tagOptions?:
|
|
48
|
+
tagOptions?: SuggestedTagOptionType[]
|
|
43
49
|
isRequired?: boolean
|
|
44
50
|
tagInputType?: KEY_VALUE
|
|
45
51
|
placeholder?: string
|
|
46
52
|
tabIndex?: number
|
|
47
53
|
refVar?: React.MutableRefObject<HTMLTextAreaElement>
|
|
48
54
|
dependentRef?: React.MutableRefObject<HTMLTextAreaElement>
|
|
55
|
+
noBackDrop?: boolean
|
|
49
56
|
}
|
|
50
57
|
|
|
51
58
|
export interface ResizableTagTextAreaProps {
|
|
@@ -60,4 +67,5 @@ export interface ResizableTagTextAreaProps {
|
|
|
60
67
|
tabIndex?: number
|
|
61
68
|
refVar?: React.MutableRefObject<HTMLTextAreaElement>
|
|
62
69
|
dependentRef?: React.MutableRefObject<HTMLTextAreaElement>
|
|
70
|
+
dataTestId?: string
|
|
63
71
|
}
|
|
@@ -16,39 +16,42 @@ const validateTagValue = (value: string): string[] => {
|
|
|
16
16
|
return errorList
|
|
17
17
|
}
|
|
18
18
|
export class ValidationRules {
|
|
19
|
-
|
|
20
19
|
propagateTagKey = (key: string): { isValid: boolean; messages: string[] } => {
|
|
21
20
|
const errorList = []
|
|
22
21
|
if (!key) {
|
|
23
22
|
errorList.push('Key is required')
|
|
24
23
|
} else {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
24
|
+
if(!key.startsWith("devtron.ai/")){
|
|
25
|
+
const re = new RegExp('/', 'g')
|
|
26
|
+
const noOfSlashInKey = key.match(re)?.length
|
|
27
|
+
if (noOfSlashInKey > 1) {
|
|
28
|
+
errorList.push('Key: Max 1 ( / ) allowed')
|
|
29
|
+
} else if (noOfSlashInKey === 1) {
|
|
30
|
+
const [prefix, name] = key.split('/')
|
|
31
|
+
errorList.push(...validateTagValue(name).map((error) => `Name: ${error}`))
|
|
32
|
+
if (prefix.length > 253) {
|
|
33
|
+
errorList.push('Prefix: Can be max 253 characters')
|
|
34
|
+
}
|
|
35
|
+
const validPrefix = PATTERNS.KUBERNETES_KEY_PREFIX.test(prefix)
|
|
36
|
+
if (!validPrefix) {
|
|
37
|
+
errorList.push('Prefix: Must be a DNS subdomain (a series of DNS labels separated by dots (.)')
|
|
38
|
+
}
|
|
39
|
+
} else {
|
|
40
|
+
errorList.push(...validateTagValue(key).map((error) => `Name: ${error}`))
|
|
38
41
|
}
|
|
39
|
-
} else {
|
|
40
|
-
errorList.push(...validateTagValue(key).map((error) => `Name: ${error}`))
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
return { isValid: errorList.length === 0, messages: errorList }
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
propagateTagValue = (value: string): { isValid: boolean; messages: string[] } => {
|
|
47
|
+
propagateTagValue = (value: string, key: string): { isValid: boolean; messages: string[] } => {
|
|
47
48
|
const errorList = []
|
|
48
49
|
if (!value) {
|
|
49
50
|
errorList.push('Value is required')
|
|
50
51
|
} else {
|
|
51
|
-
|
|
52
|
+
if(!key.startsWith("devtron.ai/")){
|
|
53
|
+
errorList.push(...validateTagValue(value))
|
|
54
|
+
}
|
|
52
55
|
}
|
|
53
56
|
return { isValid: errorList.length === 0, messages: errorList }
|
|
54
57
|
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import { useHistory } from 'react-router-dom'
|
|
3
|
+
import { toast } from 'react-toastify'
|
|
4
|
+
import info from '../../Assets/Icon/ic-info-filled.svg'
|
|
5
|
+
import { ConfirmationDialog, DeleteDialog } from '../Dialogs'
|
|
6
|
+
import { ServerErrors } from '../ServerError'
|
|
7
|
+
import { DeleteComponentProps } from './types'
|
|
8
|
+
|
|
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,6 +1,8 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { VisibleModal2 } from '../Modals/VisibleModal2'
|
|
3
|
-
|
|
3
|
+
import { ConfirmationDialogBodyType, ConfirmationDialogButtonGroupType, ConfirmationDialogIconType, ConfirmationDialogType } from './Types'
|
|
4
|
+
|
|
5
|
+
function ConfirmationDialog({ className = '', children }: ConfirmationDialogType) {
|
|
4
6
|
return (
|
|
5
7
|
<VisibleModal2 className="confirmation-dialog">
|
|
6
8
|
<div className={`confirmation-dialog__body ${className}`}>{children}</div>
|
|
@@ -8,11 +10,11 @@ function ConfirmationDialog({ className = '', children }) {
|
|
|
8
10
|
)
|
|
9
11
|
}
|
|
10
12
|
|
|
11
|
-
function Icon({ src, className = '' }) {
|
|
13
|
+
function Icon({ src, className = '' }: ConfirmationDialogIconType) {
|
|
12
14
|
return <img src={src} className={`confirmation-dialog__icon ${className}`} alt="" />
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
function Body({ title, subtitle = null, children = null }) {
|
|
17
|
+
function Body({ title, subtitle = null, children = null }: ConfirmationDialogBodyType) {
|
|
16
18
|
return (
|
|
17
19
|
<div className="flex left column ">
|
|
18
20
|
<h3 className="confirmation-dialog__title lh-1-25 dc__break-word w-100">{title}</h3>
|
|
@@ -22,7 +24,7 @@ function Body({ title, subtitle = null, children = null }) {
|
|
|
22
24
|
)
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
function ButtonGroup({ children }) {
|
|
27
|
+
function ButtonGroup({ children }: ConfirmationDialogButtonGroupType) {
|
|
26
28
|
return <div className="flex right confirmation-dialog__button-group">{children}</div>
|
|
27
29
|
}
|
|
28
30
|
|
|
@@ -1,35 +1,53 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import warn from '../../Assets/Img/
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import warn from '../../Assets/Img/delete-medium.svg'
|
|
3
3
|
import { Progressing } from '../Progressing'
|
|
4
|
-
import ConfirmationDialog from './ConfirmationDialog'
|
|
5
|
-
import { DeleteDialogProps } from './Types'
|
|
4
|
+
import ConfirmationDialog from './ConfirmationDialog'
|
|
5
|
+
import { DeleteDialogProps } from './Types'
|
|
6
6
|
|
|
7
7
|
export const DeleteDialog: React.FC<DeleteDialogProps> & { Description?: React.FC<any> } = function (props) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
8
|
+
return (
|
|
9
|
+
<ConfirmationDialog className="confirmation-dialog__body--w-400">
|
|
10
|
+
<ConfirmationDialog.Icon src={warn} />
|
|
11
|
+
<ConfirmationDialog.Body title={props.title}>
|
|
12
|
+
<div className="fs-13 cn-7 lh-1-54 w-100">
|
|
13
|
+
{props.description ? props.description : null}
|
|
14
|
+
{props.children}
|
|
15
|
+
</div>
|
|
16
|
+
</ConfirmationDialog.Body>
|
|
17
|
+
<ConfirmationDialog.ButtonGroup>
|
|
18
|
+
<div className="flex right">
|
|
19
|
+
<button
|
|
20
|
+
type="button"
|
|
21
|
+
className="cta cancel cta-cd-delete-modal ml-16"
|
|
22
|
+
onClick={props.closeDelete}
|
|
23
|
+
disabled={props.apiCallInProgress}
|
|
24
|
+
data-testid="dialog-cancel"
|
|
25
|
+
>
|
|
26
|
+
Cancel
|
|
27
|
+
</button>
|
|
28
|
+
<button
|
|
29
|
+
type="button"
|
|
30
|
+
className="cta delete cta-cd-delete-modal ml-16"
|
|
31
|
+
onClick={() => props.delete()}
|
|
32
|
+
disabled={props.apiCallInProgress}
|
|
33
|
+
data-testid="dialog-delete"
|
|
34
|
+
>
|
|
35
|
+
{props.apiCallInProgress ? (
|
|
36
|
+
<Progressing />
|
|
37
|
+
) : (
|
|
38
|
+
`${props.deletePrefix || ''}${
|
|
39
|
+
props.buttonPrimaryText ? props.buttonPrimaryText : 'Delete'
|
|
40
|
+
}${props.deletePostfix || ''}`
|
|
41
|
+
)}
|
|
42
|
+
</button>
|
|
43
|
+
</div>
|
|
44
|
+
</ConfirmationDialog.ButtonGroup>
|
|
45
|
+
</ConfirmationDialog>
|
|
46
|
+
)
|
|
26
47
|
}
|
|
27
48
|
|
|
28
49
|
function DeleteDialogDescription(props) {
|
|
29
|
-
|
|
30
|
-
return <>
|
|
31
|
-
{props.children}
|
|
32
|
-
</>
|
|
50
|
+
return <>{props.children}</>
|
|
33
51
|
}
|
|
34
52
|
|
|
35
|
-
DeleteDialog.Description = DeleteDialogDescription
|
|
53
|
+
DeleteDialog.Description = DeleteDialogDescription
|
|
@@ -1,20 +1,11 @@
|
|
|
1
1
|
import React, { Component, createContext } from 'react';
|
|
2
2
|
import { VisibleModal } from '../Modals/VisibleModal';
|
|
3
|
-
import close from '../../Assets/Icon/ic-
|
|
3
|
+
import close from '../../Assets/Icon/ic-cross.svg';
|
|
4
4
|
import { Progressing } from '../Progressing'
|
|
5
|
+
import { DialogFormProps } from './Types';
|
|
5
6
|
//TODO: may not need context
|
|
6
7
|
const DialogFormContext = createContext({ title: '', isLoading: false, close: (event) => {}, onSave: (event) => {} });
|
|
7
8
|
|
|
8
|
-
export interface DialogFormProps {
|
|
9
|
-
className: string;
|
|
10
|
-
title: string;
|
|
11
|
-
isLoading: boolean;
|
|
12
|
-
closeOnESC?: boolean;
|
|
13
|
-
close: (event) => void;
|
|
14
|
-
onSave: (event) => void;
|
|
15
|
-
headerClassName?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
9
|
export class DialogForm extends Component<DialogFormProps> {
|
|
19
10
|
constructor(props) {
|
|
20
11
|
super(props);
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ReactNode } from "react"
|
|
2
|
+
|
|
1
3
|
export interface DeleteDialogProps {
|
|
2
4
|
title: string
|
|
3
5
|
description?: string
|
|
@@ -6,6 +8,8 @@ export interface DeleteDialogProps {
|
|
|
6
8
|
deletePrefix?: string
|
|
7
9
|
deletePostfix?: string
|
|
8
10
|
apiCallInProgress?: boolean
|
|
11
|
+
dataTestId?: string
|
|
12
|
+
buttonPrimaryText?: string
|
|
9
13
|
}
|
|
10
14
|
|
|
11
15
|
export interface ForceDeleteDialogType {
|
|
@@ -14,3 +18,28 @@ export interface ForceDeleteDialogType {
|
|
|
14
18
|
forceDeleteDialogTitle: string
|
|
15
19
|
forceDeleteDialogMessage: string
|
|
16
20
|
}
|
|
21
|
+
export interface ConfirmationDialogType {
|
|
22
|
+
className?: string
|
|
23
|
+
children: any
|
|
24
|
+
}
|
|
25
|
+
export interface ConfirmationDialogIconType {
|
|
26
|
+
src: string
|
|
27
|
+
className?: string
|
|
28
|
+
}
|
|
29
|
+
export interface ConfirmationDialogBodyType {
|
|
30
|
+
title: string
|
|
31
|
+
subtitle?: ReactNode
|
|
32
|
+
children?: any
|
|
33
|
+
}
|
|
34
|
+
export interface ConfirmationDialogButtonGroupType {
|
|
35
|
+
children: any
|
|
36
|
+
}
|
|
37
|
+
export interface DialogFormProps {
|
|
38
|
+
className: string;
|
|
39
|
+
title: string;
|
|
40
|
+
isLoading: boolean;
|
|
41
|
+
closeOnESC?: boolean;
|
|
42
|
+
close: (event) => void;
|
|
43
|
+
onSave: (event) => void;
|
|
44
|
+
headerClassName?: string;
|
|
45
|
+
}
|
|
@@ -1,39 +1,40 @@
|
|
|
1
|
-
.drawer{
|
|
1
|
+
.drawer {
|
|
2
2
|
position: absolute;
|
|
3
3
|
overflow: hidden;
|
|
4
|
-
&.left,
|
|
4
|
+
&.left,
|
|
5
|
+
&.right {
|
|
5
6
|
top: 0;
|
|
6
7
|
bottom: 0;
|
|
7
8
|
width: 0;
|
|
8
9
|
transition: width 200ms;
|
|
9
|
-
&.show{
|
|
10
|
+
&.show {
|
|
10
11
|
min-width: var(--minWidth);
|
|
11
12
|
width: var(--width);
|
|
12
13
|
max-width: var(--maxWidth);
|
|
13
14
|
}
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
&.top,
|
|
17
|
+
&.top,
|
|
18
|
+
&.bottom {
|
|
17
19
|
left: 0;
|
|
18
20
|
right: 0;
|
|
19
21
|
height: 0;
|
|
20
22
|
transition: height 200ms;
|
|
21
|
-
&.show{
|
|
23
|
+
&.show {
|
|
22
24
|
height: var(--height);
|
|
23
25
|
}
|
|
24
26
|
}
|
|
25
|
-
&.right{
|
|
27
|
+
&.right {
|
|
26
28
|
right: 0;
|
|
27
29
|
}
|
|
28
|
-
&.left{
|
|
30
|
+
&.left {
|
|
29
31
|
left: 0;
|
|
30
|
-
|
|
31
32
|
}
|
|
32
|
-
&.top{
|
|
33
|
+
&.top {
|
|
33
34
|
top: 0;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
&.bottom{
|
|
37
|
+
&.bottom {
|
|
37
38
|
bottom: 0;
|
|
38
39
|
}
|
|
39
|
-
}
|
|
40
|
+
}
|
|
@@ -2,9 +2,9 @@ import React from 'react'
|
|
|
2
2
|
import './emptyState.scss';
|
|
3
3
|
import { ReactComponent as Progressing } from '../../Assets/Icon/ic-progressing.svg';
|
|
4
4
|
|
|
5
|
-
function EmptyState({ children }) {
|
|
5
|
+
function EmptyState({ children, className = '' }) {
|
|
6
6
|
return (
|
|
7
|
-
<div className=
|
|
7
|
+
<div className={`flex column empty-state w-100 h-100 ${className}`}>
|
|
8
8
|
{children}
|
|
9
9
|
</div>
|
|
10
10
|
)
|
|
@@ -18,8 +18,8 @@ function Title({ children }) {
|
|
|
18
18
|
return children
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
function Subtitle({ children, className }:{children: any
|
|
22
|
-
return <p className={`subtitle ${className}`}>{children}</p>
|
|
21
|
+
function Subtitle({ children, className }: { children: any; className?: string }) {
|
|
22
|
+
return <p className={`subtitle ${className || ''}`}>{children}</p>
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
function Button({ children }) {
|
|
@@ -39,4 +39,4 @@ EmptyState.Subtitle = Subtitle
|
|
|
39
39
|
EmptyState.Button = Button
|
|
40
40
|
EmptyState.Loading = Loading
|
|
41
41
|
|
|
42
|
-
export default EmptyState
|
|
42
|
+
export default EmptyState
|