@devtron-labs/devtron-fe-common-lib 0.0.52-beta-2 → 0.0.52-beta-3
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/.eslintignore +79 -0
- package/.eslintrc.js +84 -16
- package/.github/pull_request_template.md +25 -0
- package/.github/workflows/ci.yml +31 -0
- package/.github/workflows/release-package.yml +2 -3
- package/.husky/pre-commit +5 -0
- package/.lintstagedrc +3 -0
- package/.nvmrc +1 -0
- package/dist/Common/BreadCrumb/BreadCrumb.d.ts +1 -1
- package/dist/Common/BreadCrumb/BreadcrumbStore.d.ts +2 -2
- package/dist/Common/Constants.d.ts +1 -5
- package/dist/Common/CustomInput/CustomInput.d.ts +1 -1
- package/dist/Common/CustomInput/Types.d.ts +2 -2
- package/dist/Common/CustomTagSelector/ResizableTagTextArea.d.ts +1 -1
- package/dist/Common/DeleteComponentModal/DeleteComponent.d.ts +1 -1
- package/dist/Common/DevtronProgressing/DevtronProgressing.d.ts +1 -1
- package/dist/Common/Dialogs/ConfirmationDialog.d.ts +6 -6
- package/dist/Common/Dialogs/DeleteDialog.d.ts +1 -1
- package/dist/Common/Dialogs/ForceDeleteDialog.d.ts +1 -1
- package/dist/Common/Dialogs/Types.d.ts +1 -1
- package/dist/Common/EmptyState/EmptyState.d.ts +20 -17
- package/dist/Common/EmptyState/GenericEmptyState.d.ts +1 -1
- package/dist/Common/Error.d.ts +2 -1
- package/dist/Common/ErrorScreenNotFound.d.ts +1 -1
- package/dist/Common/Helper.d.ts +1 -1
- package/dist/Common/ImageTags.d.ts +1 -1
- package/dist/Common/InfoColorBar/InfoColourbar.d.ts +1 -1
- package/dist/Common/Modals/Modal.d.ts +2 -2
- package/dist/Common/Modals/OpaqueModal.d.ts +3 -3
- package/dist/Common/Modals/VisibleModal.d.ts +3 -3
- package/dist/Common/Modals/VisibleModal2.d.ts +3 -3
- package/dist/Common/MultiSelectCustomization.d.ts +1 -1
- package/dist/Common/Policy.Types.d.ts +2 -2
- package/dist/Common/PopupMenu.d.ts +5 -5
- package/dist/Common/Progressing.d.ts +2 -2
- package/dist/Common/RadioGroup/RadioGroup.d.ts +1 -1
- package/dist/Common/ResizableTextarea.d.ts +1 -1
- package/dist/Common/TippyCustomized.d.ts +1 -1
- package/dist/Common/ToastBody.d.ts +5 -5
- package/dist/Common/Types.d.ts +0 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +286 -370
- package/package.json +19 -2
- package/src/Common/AddCDButton/AddCDButton.tsx +1 -2
- package/src/Common/Api.ts +20 -25
- package/src/Common/AppStatus/AppStatus.tsx +12 -12
- package/src/Common/AppStatus/utils.ts +6 -5
- package/src/Common/BreadCrumb/BreadCrumb.tsx +32 -28
- package/src/Common/BreadCrumb/BreadcrumbStore.tsx +2 -2
- package/src/Common/BreadCrumb/Types.ts +11 -12
- package/src/Common/ChartVersionAndTypeSelector.tsx +1 -1
- package/src/Common/Checkbox.tsx +17 -19
- package/src/Common/ClipboardButton/ClipboardButton.tsx +1 -1
- package/src/Common/ClipboardButton/__tests__/ClipboardButton.test.tsx +0 -1
- package/src/Common/Common.service.ts +60 -65
- package/src/Common/Constants.ts +9 -13
- package/src/Common/CustomInput/CustomInput.tsx +22 -29
- package/src/Common/CustomInput/Types.ts +4 -4
- package/src/Common/CustomInput/index.ts +1 -1
- package/src/Common/CustomTagSelector/PropagateTagInfo.tsx +15 -18
- package/src/Common/CustomTagSelector/ResizableTagTextArea.tsx +9 -9
- package/src/Common/CustomTagSelector/TagDetails.tsx +9 -3
- package/src/Common/CustomTagSelector/TagLabelSelect.tsx +7 -9
- package/src/Common/CustomTagSelector/TagLabelValueSelector.tsx +31 -35
- package/src/Common/CustomTagSelector/TagSelector.utils.ts +2 -3
- package/src/Common/CustomTagSelector/Types.ts +1 -1
- package/src/Common/CustomTagSelector/ValidationRules.ts +18 -22
- package/src/Common/CustomTagSelector/index.ts +2 -2
- package/src/Common/DebouncedSearch/DebouncedSearch.tsx +2 -1
- package/src/Common/DebouncedSearch/__tests__/DebouncedSearch.test.tsx +0 -1
- package/src/Common/DeleteComponentModal/DeleteComponent.tsx +27 -32
- package/src/Common/DeleteComponentModal/types.ts +1 -1
- package/src/Common/DevtronProgressing/DevtronProgressing.tsx +5 -8
- package/src/Common/Dialogs/ConfirmationDialog.tsx +24 -24
- package/src/Common/Dialogs/DeleteDialog.tsx +3 -5
- package/src/Common/Dialogs/DialogForm.tsx +31 -35
- package/src/Common/Dialogs/ForceDeleteDialog.tsx +13 -7
- package/src/Common/Dialogs/Types.ts +12 -12
- package/src/Common/Dialogs/index.ts +1 -1
- package/src/Common/Drawer/Drawer.tsx +1 -1
- package/src/Common/EmptyState/EmptyState.tsx +13 -17
- package/src/Common/EmptyState/GenericEmptyState.tsx +7 -29
- package/src/Common/Error.tsx +5 -5
- package/src/Common/ErrorScreenNotFound.tsx +9 -12
- package/src/Common/Grid/Grid.tsx +1 -2
- package/src/Common/Helper.tsx +36 -37
- package/src/Common/Hooks/UseClickOutside/UseClickOutside.tsx +1 -1
- package/src/Common/Hooks/UseSuperAdmin/UseSuperAdmin.tsx +1 -1
- package/src/Common/Hooks/UseWindowSize/UseWindowSize.tsx +5 -7
- package/src/Common/ImageTags.Types.ts +2 -3
- package/src/Common/ImageTags.tsx +61 -66
- package/src/Common/InfoColorBar/InfoColourbar.tsx +10 -5
- package/src/Common/Modals/Modal.tsx +3 -3
- package/src/Common/Modals/OpaqueModal.tsx +25 -18
- package/src/Common/Modals/VisibleModal.tsx +7 -3
- package/src/Common/Modals/VisibleModal2.tsx +20 -15
- package/src/Common/MultiSelectCustomization.tsx +9 -13
- package/src/Common/Policy.Types.ts +38 -38
- package/src/Common/PopupMenu.tsx +10 -9
- package/src/Common/Progressing.tsx +15 -18
- package/src/Common/RJSF/Form.tsx +0 -1
- package/src/Common/RJSF/common/FieldRow.tsx +0 -1
- package/src/Common/RJSF/config.ts +0 -1
- package/src/Common/RJSF/templates/ArrayFieldItemTemplate.tsx +1 -1
- package/src/Common/RJSF/templates/ArrayFieldTemplate.tsx +0 -1
- package/src/Common/RJSF/templates/BaseInput.tsx +0 -1
- package/src/Common/RJSF/templates/ButtonTemplates/AddButton.tsx +0 -1
- package/src/Common/RJSF/templates/ButtonTemplates/RemoveButton.tsx +0 -1
- package/src/Common/RJSF/templates/ButtonTemplates/SubmitButton.tsx +1 -6
- package/src/Common/RJSF/templates/Description.tsx +0 -1
- package/src/Common/RJSF/templates/Field.tsx +14 -3
- package/src/Common/RJSF/templates/FieldErrorTemplate.tsx +6 -9
- package/src/Common/RJSF/templates/ObjectFieldTemplate.tsx +5 -7
- package/src/Common/RJSF/templates/TitleField.tsx +0 -1
- package/src/Common/RJSF/templates/WrapIfAdditionalTemplate.tsx +0 -1
- package/src/Common/RJSF/utils.ts +53 -57
- package/src/Common/RJSF/widgets/Checkbox.tsx +2 -2
- package/src/Common/RJSF/widgets/Select.tsx +0 -1
- package/src/Common/RadioGroup/RadioGroup.tsx +18 -23
- package/src/Common/RadioGroup.tsx +24 -23
- package/src/Common/Reload.tsx +0 -1
- package/src/Common/ResizableTextarea.tsx +18 -17
- package/src/Common/Security/ScanVulnerabilitiesTable.tsx +29 -34
- package/src/Common/ServerError.ts +5 -1
- package/src/Common/TippyCustomized.tsx +41 -38
- package/src/Common/ToastBody.tsx +6 -7
- package/src/Common/Toggle/Toggle.tsx +3 -3
- package/src/Common/Types.ts +19 -20
- package/src/custom.d.ts +7 -7
- package/src/index.ts +1 -1
package/src/Common/Constants.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RegistryTypeDetailType } from
|
|
1
|
+
import { RegistryTypeDetailType } from './Types'
|
|
2
2
|
|
|
3
3
|
export const FALLBACK_REQUEST_TIMEOUT = 60000
|
|
4
4
|
export const Host = process.env.REACT_APP_ORCHESTRATOR_ROOT
|
|
@@ -23,9 +23,9 @@ export const URLS = {
|
|
|
23
23
|
export const ROUTES = {
|
|
24
24
|
PROJECT_LIST_MIN: 'team/autocomplete',
|
|
25
25
|
USER_CHECK_ROLE: 'user/check/roles',
|
|
26
|
-
IMAGE_TAGGING:'app/image-tagging',
|
|
26
|
+
IMAGE_TAGGING: 'app/image-tagging',
|
|
27
27
|
CD_MATERIAL_GET: 'app/cd-pipeline',
|
|
28
|
-
DEPLOYMENT_TEMPLATE_LIST: 'app/template/list'
|
|
28
|
+
DEPLOYMENT_TEMPLATE_LIST: 'app/template/list',
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export enum KEY_VALUE {
|
|
@@ -66,9 +66,9 @@ export const TriggerTypeMap = {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
export const BuildStageVariable = {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
PreBuild: 'preBuildStage',
|
|
70
|
+
Build: 'buildStage',
|
|
71
|
+
PostBuild: 'postBuildStage',
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
export const REGISTRY_TYPE_MAP: Record<string, RegistryTypeDetailType> = {
|
|
@@ -237,13 +237,9 @@ export const REGISTRY_TYPE_MAP: Record<string, RegistryTypeDetailType> = {
|
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
export const RepositoryAction = {
|
|
240
|
-
CONTAINER:
|
|
241
|
-
CHART_PULL:
|
|
242
|
-
CHART_PUSH:
|
|
240
|
+
CONTAINER: 'CONTAINER',
|
|
241
|
+
CHART_PULL: 'CHART_PULL',
|
|
242
|
+
CHART_PUSH: 'CHART_PUSH',
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
export enum APPROVAL_MODAL_TYPE {
|
|
246
|
-
CONFIG = 'CONFIG',
|
|
247
|
-
DEPLOYMENT = 'DEPLOYMENT',
|
|
248
|
-
}
|
|
249
245
|
export const MAX_Z_INDEX = 2147483647
|
|
@@ -2,7 +2,7 @@ import { CustomInputProps } from './Types'
|
|
|
2
2
|
import { ReactComponent as Info } from '../../Assets/Icon/ic-info-filled.svg'
|
|
3
3
|
import { ReactComponent as ErrorIcon } from '../../Assets/Icon/ic-warning.svg'
|
|
4
4
|
|
|
5
|
-
export
|
|
5
|
+
export const CustomInput = ({
|
|
6
6
|
name,
|
|
7
7
|
value,
|
|
8
8
|
error,
|
|
@@ -29,9 +29,7 @@ export function CustomInput({
|
|
|
29
29
|
onKeyDown,
|
|
30
30
|
required,
|
|
31
31
|
additionalErrorInfo,
|
|
32
|
-
|
|
33
|
-
}: CustomInputProps) {
|
|
34
|
-
|
|
32
|
+
}: CustomInputProps) => {
|
|
35
33
|
function handleError(error: any): any[] {
|
|
36
34
|
if (!Array.isArray(error)) {
|
|
37
35
|
return [error]
|
|
@@ -40,7 +38,7 @@ export function CustomInput({
|
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
const onBlur = (event) => {
|
|
43
|
-
//NOTE: This is to prevent the input from being trimmed when the user do not want to trim the input
|
|
41
|
+
// NOTE: This is to prevent the input from being trimmed when the user do not want to trim the input
|
|
44
42
|
if (!noTrim) {
|
|
45
43
|
event.stopPropagation()
|
|
46
44
|
event.target.value = event.target.value?.trim()
|
|
@@ -51,50 +49,45 @@ export function CustomInput({
|
|
|
51
49
|
}
|
|
52
50
|
}
|
|
53
51
|
|
|
54
|
-
const renderFormErrorWithIcon = (error: string) =>
|
|
55
|
-
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
)
|
|
62
|
-
}
|
|
52
|
+
const renderFormErrorWithIcon = (error: string) => (
|
|
53
|
+
<div className="form__error" key={error}>
|
|
54
|
+
<ErrorIcon className="form__icon form__icon--error" />
|
|
55
|
+
{error}
|
|
56
|
+
{typeof additionalErrorInfo === 'function' && additionalErrorInfo()}
|
|
57
|
+
</div>
|
|
58
|
+
)
|
|
63
59
|
|
|
64
60
|
const getInputError = () => {
|
|
65
61
|
if (!error?.length) {
|
|
66
62
|
return null
|
|
67
|
-
} else {
|
|
68
|
-
if (typeof error === 'object') {
|
|
69
|
-
return handleError(error).map((err: string) => renderFormErrorWithIcon(err))
|
|
70
|
-
}
|
|
71
|
-
return renderFormErrorWithIcon(error)
|
|
72
63
|
}
|
|
64
|
+
if (typeof error === 'object') {
|
|
65
|
+
return handleError(error).map((err: string) => renderFormErrorWithIcon(err))
|
|
66
|
+
}
|
|
67
|
+
return renderFormErrorWithIcon(error)
|
|
73
68
|
}
|
|
74
69
|
|
|
75
70
|
const renderInputLabelConditionally = () => {
|
|
76
71
|
if (typeof label === 'string') {
|
|
77
72
|
return <span className={`${isRequiredField ? 'dc__required-field' : ''}`}>{label}</span>
|
|
78
|
-
} else {
|
|
79
|
-
return label
|
|
80
73
|
}
|
|
74
|
+
return label
|
|
81
75
|
}
|
|
82
76
|
|
|
83
77
|
const renderInputLabel = () => {
|
|
84
78
|
if (!label) {
|
|
85
79
|
return null
|
|
86
|
-
} else {
|
|
87
|
-
return (
|
|
88
|
-
<label className={`form__label ${labelClassName}`} data-testid={`label-${dataTestid}`}>
|
|
89
|
-
{renderInputLabelConditionally()}
|
|
90
|
-
</label>
|
|
91
|
-
)
|
|
92
80
|
}
|
|
81
|
+
return (
|
|
82
|
+
<label className={`form__label ${labelClassName}`} data-testid={`label-${dataTestid}`}>
|
|
83
|
+
{renderInputLabelConditionally()}
|
|
84
|
+
</label>
|
|
85
|
+
)
|
|
93
86
|
}
|
|
94
87
|
|
|
95
88
|
return (
|
|
96
|
-
<div className=
|
|
97
|
-
|
|
89
|
+
<div className="flex column left top">
|
|
90
|
+
{renderInputLabel()}
|
|
98
91
|
<input
|
|
99
92
|
data-testid={dataTestid}
|
|
100
93
|
type={type}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { HTMLInputTypeAttribute } from 'react'
|
|
2
|
+
import * as React from 'react'
|
|
2
3
|
|
|
3
4
|
export interface CustomInputProps {
|
|
4
5
|
name: string
|
|
@@ -6,7 +7,7 @@ export interface CustomInputProps {
|
|
|
6
7
|
onChange: (e: any) => void
|
|
7
8
|
onFocus?: (e: any) => void
|
|
8
9
|
autoComplete?: string
|
|
9
|
-
label?: string |
|
|
10
|
+
label?: string | React.ReactNode
|
|
10
11
|
labelClassName?: string
|
|
11
12
|
type?: HTMLInputTypeAttribute
|
|
12
13
|
disabled?: boolean
|
|
@@ -27,5 +28,4 @@ export interface CustomInputProps {
|
|
|
27
28
|
onKeyDown?: (e) => void
|
|
28
29
|
required?: boolean
|
|
29
30
|
additionalErrorInfo?: React.ReactNode
|
|
30
|
-
|
|
31
|
-
}
|
|
31
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export * from './CustomInput'
|
|
2
|
-
export * from './Types'
|
|
2
|
+
export * from './Types'
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
1
|
import { ReactComponent as InjectTag } from '../../Assets/Icon/inject-tag.svg'
|
|
3
2
|
import { ReactComponent as Help } from '../../Assets/Icon/ic-help-outline.svg'
|
|
4
3
|
import { TippyCustomized } from '../TippyCustomized'
|
|
@@ -6,33 +5,31 @@ import { TippyTheme } from '../Types'
|
|
|
6
5
|
import { DOCUMENTATION } from '../Constants'
|
|
7
6
|
|
|
8
7
|
export default function PropagateTagInfo({ isCreateApp }: { isCreateApp: boolean }) {
|
|
9
|
-
const additionalInfo = () =>
|
|
10
|
-
|
|
11
|
-
<div className="
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
propagate tags as labels to Kubernetes resources
|
|
19
|
-
</div>
|
|
20
|
-
<div>Use these tags to filter/identify resources via CLI or in other Kubernetes tools.</div>
|
|
8
|
+
const additionalInfo = () => (
|
|
9
|
+
<div className="p-12 fs-13">
|
|
10
|
+
<div className="mb-20">
|
|
11
|
+
<span className="flex left">
|
|
12
|
+
Add a tag and click on the
|
|
13
|
+
<InjectTag className="icon-dim-16 ml-4 mr-4" />
|
|
14
|
+
icon to
|
|
15
|
+
</span>
|
|
16
|
+
propagate tags as labels to Kubernetes resources
|
|
21
17
|
</div>
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
<div>Use these tags to filter/identify resources via CLI or in other Kubernetes tools.</div>
|
|
19
|
+
</div>
|
|
20
|
+
)
|
|
24
21
|
return (
|
|
25
22
|
<TippyCustomized
|
|
26
23
|
theme={TippyTheme.white}
|
|
27
24
|
className="w-300"
|
|
28
25
|
placement="top"
|
|
29
26
|
Icon={InjectTag}
|
|
30
|
-
heading=
|
|
27
|
+
heading="Propagate tags to K8s resources"
|
|
31
28
|
infoText=""
|
|
32
29
|
additionalContent={additionalInfo()}
|
|
33
|
-
showCloseButton
|
|
30
|
+
showCloseButton
|
|
34
31
|
trigger="click"
|
|
35
|
-
interactive
|
|
32
|
+
interactive
|
|
36
33
|
documentationLink={isCreateApp ? DOCUMENTATION.APP_TAGS : DOCUMENTATION.APP_OVERVIEW_TAGS}
|
|
37
34
|
documentationLinkText="View Documentation"
|
|
38
35
|
>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
2
|
import { useThrottledEffect } from '../Helper'
|
|
3
3
|
import { ResizableTagTextAreaProps } from './Types'
|
|
4
4
|
|
|
5
|
-
export
|
|
5
|
+
export const ResizableTagTextArea = ({
|
|
6
6
|
className,
|
|
7
7
|
minHeight,
|
|
8
8
|
maxHeight,
|
|
@@ -16,7 +16,7 @@ export function ResizableTagTextArea({
|
|
|
16
16
|
dependentRef,
|
|
17
17
|
dataTestId,
|
|
18
18
|
handleKeyDown,
|
|
19
|
-
}: ResizableTagTextAreaProps) {
|
|
19
|
+
}: ResizableTagTextAreaProps) => {
|
|
20
20
|
const [text, setText] = useState('')
|
|
21
21
|
|
|
22
22
|
useEffect(() => {
|
|
@@ -30,9 +30,9 @@ export function ResizableTagTextArea({
|
|
|
30
30
|
|
|
31
31
|
const reInitHeight = () => {
|
|
32
32
|
if (document.activeElement !== refVar.current) return
|
|
33
|
-
refVar.current.style.height = minHeight
|
|
33
|
+
refVar.current.style.height = `${minHeight}px`
|
|
34
34
|
if (dependentRef) {
|
|
35
|
-
dependentRef.current.style.height = minHeight
|
|
35
|
+
dependentRef.current.style.height = `${minHeight}px`
|
|
36
36
|
}
|
|
37
37
|
let nextHeight = refVar.current.scrollHeight
|
|
38
38
|
if (dependentRef && nextHeight < dependentRef.current.scrollHeight) {
|
|
@@ -44,18 +44,18 @@ export function ResizableTagTextArea({
|
|
|
44
44
|
if (maxHeight && nextHeight > maxHeight) {
|
|
45
45
|
nextHeight = maxHeight
|
|
46
46
|
}
|
|
47
|
-
refVar.current.style.height = nextHeight
|
|
47
|
+
refVar.current.style.height = `${nextHeight}px`
|
|
48
48
|
if (dependentRef) {
|
|
49
|
-
dependentRef.current.style.height = nextHeight
|
|
49
|
+
dependentRef.current.style.height = `${nextHeight}px`
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
useThrottledEffect(reInitHeight, 500, [text])
|
|
54
54
|
|
|
55
55
|
const handleOnBlur = (event) => {
|
|
56
|
-
refVar.current.style.height = minHeight
|
|
56
|
+
refVar.current.style.height = `${minHeight}px`
|
|
57
57
|
if (dependentRef) {
|
|
58
|
-
dependentRef.current.style.height = minHeight
|
|
58
|
+
dependentRef.current.style.height = `${minHeight}px`
|
|
59
59
|
}
|
|
60
60
|
onBlur && onBlur(event)
|
|
61
61
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useRef } from 'react'
|
|
2
2
|
import { ReactComponent as DeleteCross } from '../../Assets/Icon/ic-cross.svg'
|
|
3
3
|
import { ReactComponent as InjectTag } from '../../Assets/Icon/inject-tag.svg'
|
|
4
4
|
import { TagLabelValueSelector } from './TagLabelValueSelector'
|
|
@@ -41,7 +41,9 @@ export const TagDetails = ({
|
|
|
41
41
|
return (
|
|
42
42
|
<div className="flexbox mb-8">
|
|
43
43
|
<div
|
|
44
|
-
className={`dc__border h-30 pl-4 pr-4 br-4 mr-8 pointer ${tagData.propagate ? 'bcn-7' : ''} ${
|
|
44
|
+
className={`dc__border h-30 pl-4 pr-4 br-4 mr-8 pointer ${tagData.propagate ? 'bcn-7' : ''} ${
|
|
45
|
+
tagData.key.startsWith('devtron.ai/') ? 'cursor-not-allowed bcn-1' : ''
|
|
46
|
+
}`}
|
|
45
47
|
onClick={propagateTagToResource}
|
|
46
48
|
data-testid={`propagate-tag-${index}`}
|
|
47
49
|
>
|
|
@@ -68,7 +70,11 @@ export const TagDetails = ({
|
|
|
68
70
|
refVar={valueRef}
|
|
69
71
|
dependentRef={keyRef}
|
|
70
72
|
/>
|
|
71
|
-
<div
|
|
73
|
+
<div
|
|
74
|
+
className="dc__border pl-4 pr-4 dc__right-radius-4 pointer flex top"
|
|
75
|
+
onClick={deleteTag}
|
|
76
|
+
data-testid={`delete-tag-${index}`}
|
|
77
|
+
>
|
|
72
78
|
<DeleteCross className="icon-dim-20 mt-4" />
|
|
73
79
|
</div>
|
|
74
80
|
</div>
|
|
@@ -1,20 +1,14 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
1
|
import PropagateTagInfo from './PropagateTagInfo'
|
|
3
2
|
import { ReactComponent as Add } from '../../Assets/Icon/ic-add.svg'
|
|
4
3
|
import { DEFAULT_TAG_DATA } from '../Constants'
|
|
5
4
|
import { TagLabelSelectType } from './Types'
|
|
6
5
|
import { TagDetails } from './TagDetails'
|
|
7
6
|
|
|
8
|
-
export const TagLabelSelect = ({
|
|
9
|
-
isCreateApp,
|
|
10
|
-
labelTags,
|
|
11
|
-
setLabelTags,
|
|
12
|
-
tabIndex = 0
|
|
13
|
-
}: TagLabelSelectType) => {
|
|
7
|
+
export const TagLabelSelect = ({ isCreateApp, labelTags, setLabelTags, tabIndex = 0 }: TagLabelSelectType) => {
|
|
14
8
|
const setTagData = (index, tagValue): void => {
|
|
15
9
|
const _tags = [...labelTags]
|
|
16
10
|
const _tagValue = tagValue
|
|
17
|
-
if(_tagValue.key.startsWith(
|
|
11
|
+
if (_tagValue.key.startsWith('devtron.ai/')) {
|
|
18
12
|
_tagValue.propagate = false
|
|
19
13
|
}
|
|
20
14
|
_tags[index] = _tagValue
|
|
@@ -40,7 +34,11 @@ export const TagLabelSelect = ({
|
|
|
40
34
|
<PropagateTagInfo isCreateApp={isCreateApp} />
|
|
41
35
|
</div>
|
|
42
36
|
<div>
|
|
43
|
-
<div
|
|
37
|
+
<div
|
|
38
|
+
className="dc_width-max-content cb-5 fw-6 fs-13 flexbox mr-20 mb-8 cursor"
|
|
39
|
+
onClick={addNewTag}
|
|
40
|
+
data-testid="add-tag-button"
|
|
41
|
+
>
|
|
44
42
|
<Add className="icon-dim-20 fcb-5" /> Add tag
|
|
45
43
|
</div>
|
|
46
44
|
<div className="mb-8" data-testid="tag-rows-container">
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useState, useEffect } from 'react'
|
|
2
|
+
import Tippy from '@tippyjs/react'
|
|
2
3
|
import PopupMenu from '../PopupMenu'
|
|
3
4
|
import { ReactComponent as ErrorCross } from '../../Assets/Icon/ic-cross.svg'
|
|
4
5
|
import { ReactComponent as Info } from '../../Assets/Icon/ic-info-outlined.svg'
|
|
@@ -6,7 +7,6 @@ import { KEY_VALUE } from '../Constants'
|
|
|
6
7
|
import { stopPropagation } from '../Helper'
|
|
7
8
|
import { ResizableTagTextArea } from './ResizableTagTextArea'
|
|
8
9
|
import { SuggestedTagOptionType, TagLabelValueSelectorType } from './Types'
|
|
9
|
-
import Tippy from '@tippyjs/react'
|
|
10
10
|
import { ValidationRules } from './ValidationRules'
|
|
11
11
|
|
|
12
12
|
export const TagLabelValueSelector = ({
|
|
@@ -107,38 +107,34 @@ export const TagLabelValueSelector = ({
|
|
|
107
107
|
return null
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
const option = (tag: SuggestedTagOptionType, index: number): JSX.Element =>
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
)
|
|
123
|
-
}
|
|
110
|
+
const option = (tag: SuggestedTagOptionType, index: number): JSX.Element => (
|
|
111
|
+
<div
|
|
112
|
+
key={`${tag.value}-${index}`}
|
|
113
|
+
data-key={tag.label}
|
|
114
|
+
data-propagate={tag.propagate}
|
|
115
|
+
className="dc__hover-n50 dc__ellipsis-right lh-20 fs-13 fw-4 pt-6 pr-8 pb-6 pl-8 cursor"
|
|
116
|
+
onClick={onSelectValue}
|
|
117
|
+
data-testid={`tag-label-value-${index}`}
|
|
118
|
+
>
|
|
119
|
+
{tag.label}
|
|
120
|
+
</div>
|
|
121
|
+
)
|
|
124
122
|
|
|
125
|
-
const optionWithTippy = (tag: SuggestedTagOptionType, index: number): JSX.Element =>
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
<div>
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
)
|
|
141
|
-
}
|
|
123
|
+
const optionWithTippy = (tag: SuggestedTagOptionType, index: number): JSX.Element => (
|
|
124
|
+
<Tippy
|
|
125
|
+
className="default-tt"
|
|
126
|
+
arrow={false}
|
|
127
|
+
placement="right"
|
|
128
|
+
content={
|
|
129
|
+
<div>
|
|
130
|
+
<div className="mb-10 fs-12 fw-6 cn-0 dc__break-word">{tag.label}</div>
|
|
131
|
+
<div className="fs-12 fw-4 cn-0 dc__break-word">{tag.description}</div>
|
|
132
|
+
</div>
|
|
133
|
+
}
|
|
134
|
+
>
|
|
135
|
+
{option(tag, index)}
|
|
136
|
+
</Tippy>
|
|
137
|
+
)
|
|
142
138
|
|
|
143
139
|
const renderSuggestions = (): JSX.Element => {
|
|
144
140
|
if (tagOptions?.length) {
|
|
@@ -186,8 +182,8 @@ export const TagLabelValueSelector = ({
|
|
|
186
182
|
{popupMenuBody && (
|
|
187
183
|
<PopupMenu.Body
|
|
188
184
|
rootClassName={`mxh-210 dc__overflow-auto tag-${selectedTagIndex}-class`}
|
|
189
|
-
autoWidth
|
|
190
|
-
preventWheelDisable
|
|
185
|
+
autoWidth
|
|
186
|
+
preventWheelDisable
|
|
191
187
|
noBackDrop={noBackDrop}
|
|
192
188
|
>
|
|
193
189
|
{popupMenuBody}
|
|
@@ -59,10 +59,9 @@ export const validateKubernetesKey = (key: string) => {
|
|
|
59
59
|
if (noOfSlashInKey > 1) {
|
|
60
60
|
invalidMessageList.push('Key: Max 1 ( / ) allowed')
|
|
61
61
|
} else {
|
|
62
|
-
|
|
62
|
+
const name = key
|
|
63
63
|
if (noOfSlashInKey === 1) {
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
const [prefix, name] = key.split('/')
|
|
66
65
|
}
|
|
67
66
|
}
|
|
68
67
|
}
|
|
@@ -20,25 +20,23 @@ export class ValidationRules {
|
|
|
20
20
|
const errorList = []
|
|
21
21
|
if (!key) {
|
|
22
22
|
errorList.push('Key is required')
|
|
23
|
-
} else {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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}`))
|
|
23
|
+
} else if (!key.startsWith('devtron.ai/')) {
|
|
24
|
+
const re = new RegExp('/', 'g')
|
|
25
|
+
const noOfSlashInKey = key.match(re)?.length
|
|
26
|
+
if (noOfSlashInKey > 1) {
|
|
27
|
+
errorList.push('Key: Max 1 ( / ) allowed')
|
|
28
|
+
} else if (noOfSlashInKey === 1) {
|
|
29
|
+
const [prefix, name] = key.split('/')
|
|
30
|
+
errorList.push(...validateTagValue(name).map((error) => `Name: ${error}`))
|
|
31
|
+
if (prefix.length > 253) {
|
|
32
|
+
errorList.push('Prefix: Can be max 253 characters')
|
|
41
33
|
}
|
|
34
|
+
const validPrefix = PATTERNS.KUBERNETES_KEY_PREFIX.test(prefix)
|
|
35
|
+
if (!validPrefix) {
|
|
36
|
+
errorList.push('Prefix: Must be a DNS subdomain (a series of DNS labels separated by dots (.)')
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
errorList.push(...validateTagValue(key).map((error) => `Name: ${error}`))
|
|
42
40
|
}
|
|
43
41
|
}
|
|
44
42
|
return { isValid: errorList.length === 0, messages: errorList }
|
|
@@ -48,10 +46,8 @@ export class ValidationRules {
|
|
|
48
46
|
const errorList = []
|
|
49
47
|
if (!value) {
|
|
50
48
|
errorList.push('Value is required')
|
|
51
|
-
} else {
|
|
52
|
-
|
|
53
|
-
errorList.push(...validateTagValue(value))
|
|
54
|
-
}
|
|
49
|
+
} else if (!key.startsWith('devtron.ai/')) {
|
|
50
|
+
errorList.push(...validateTagValue(value))
|
|
55
51
|
}
|
|
56
52
|
return { isValid: errorList.length === 0, messages: errorList }
|
|
57
53
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export {default as PropagateTagInfo} from './PropagateTagInfo'
|
|
1
|
+
export { default as PropagateTagInfo } from './PropagateTagInfo'
|
|
2
2
|
export * from './TagDetails'
|
|
3
3
|
export * from './TagLabelSelect'
|
|
4
4
|
export * from './TagLabelValueSelector'
|
|
5
5
|
export * from './ResizableTagTextArea'
|
|
6
|
-
export * from './Types'
|
|
6
|
+
export * from './Types'
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
|
+
import * as React from 'react'
|
|
2
3
|
import { useDebouncedEffect } from './Utils'
|
|
3
4
|
import { ReactComponent as ICClear } from '../../Assets/Icon/ic-error-cross.svg'
|
|
4
5
|
import { DebouncedSearchProps } from './Types'
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useState } from 'react'
|
|
2
2
|
import { useHistory } from 'react-router-dom'
|
|
3
3
|
import { toast } from 'react-toastify'
|
|
4
4
|
import info from '../../Assets/Icon/ic-info-filled.svg'
|
|
@@ -6,8 +6,7 @@ import { ConfirmationDialog, DeleteDialog } from '../Dialogs'
|
|
|
6
6
|
import { ServerErrors } from '../ServerError'
|
|
7
7
|
import { DeleteComponentProps } from './types'
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
function DeleteComponent({
|
|
9
|
+
const DeleteComponent = ({
|
|
11
10
|
setDeleting,
|
|
12
11
|
toggleConfirmation,
|
|
13
12
|
deleteComponent,
|
|
@@ -20,7 +19,7 @@ function DeleteComponent({
|
|
|
20
19
|
reload,
|
|
21
20
|
configuration = '',
|
|
22
21
|
closeCustomComponent,
|
|
23
|
-
}: DeleteComponentProps) {
|
|
22
|
+
}: DeleteComponentProps) => {
|
|
24
23
|
const [showCannotDeleteDialogModal, setCannotDeleteDialogModal] = useState(false)
|
|
25
24
|
const { push } = useHistory()
|
|
26
25
|
|
|
@@ -55,35 +54,31 @@ function DeleteComponent({
|
|
|
55
54
|
}
|
|
56
55
|
}
|
|
57
56
|
|
|
58
|
-
const renderCannotDeleteDialogModal = () =>
|
|
59
|
-
|
|
60
|
-
<ConfirmationDialog
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
)
|
|
71
|
-
}
|
|
57
|
+
const renderCannotDeleteDialogModal = () => (
|
|
58
|
+
<ConfirmationDialog className="confirmation-dialog__body--w-360">
|
|
59
|
+
<ConfirmationDialog.Icon src={info} />
|
|
60
|
+
<ConfirmationDialog.Body title={`Cannot delete ${component} '${title}'`} />
|
|
61
|
+
<p className="fs-13 cn-7 ">{confirmationDialogDescription}</p>
|
|
62
|
+
<ConfirmationDialog.ButtonGroup>
|
|
63
|
+
<button type="button" className="cta" onClick={handleConfirmation}>
|
|
64
|
+
Okay
|
|
65
|
+
</button>
|
|
66
|
+
</ConfirmationDialog.ButtonGroup>
|
|
67
|
+
</ConfirmationDialog>
|
|
68
|
+
)
|
|
72
69
|
|
|
73
|
-
const renderDeleteDialog = () =>
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
>
|
|
81
|
-
<
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
)
|
|
86
|
-
}
|
|
70
|
+
const renderDeleteDialog = () => (
|
|
71
|
+
<DeleteDialog
|
|
72
|
+
title={`Delete ${component} '${title}'`}
|
|
73
|
+
delete={handleDelete}
|
|
74
|
+
closeDelete={() => toggleConfirmation(false)}
|
|
75
|
+
dataTestId="delete-dialog"
|
|
76
|
+
>
|
|
77
|
+
<DeleteDialog.Description>
|
|
78
|
+
<p>Are you sure you want to delete this {configuration || component}? </p>
|
|
79
|
+
</DeleteDialog.Description>
|
|
80
|
+
</DeleteDialog>
|
|
81
|
+
)
|
|
87
82
|
return (
|
|
88
83
|
<div>
|
|
89
84
|
{!showCannotDeleteDialogModal && renderDeleteDialog()}
|