@devtron-labs/devtron-fe-common-lib 0.0.6-beta-16 → 0.0.6-beta-18
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/CustomTagSelector/TagDetails.d.ts +2 -7
- package/dist/Common/CustomTagSelector/TagLabelSelect.d.ts +2 -5
- package/dist/Common/CustomTagSelector/TagLabelValueSelector.d.ts +2 -9
- package/dist/Common/InfoColorBar/InfoColourbar.d.ts +18 -0
- package/dist/Common/MultiSelectCustomization.d.ts +38 -0
- package/dist/Common/Types.d.ts +20 -0
- package/dist/Common/index.d.ts +2 -0
- package/dist/index.js +7913 -354
- package/package.json +3 -1
- package/rollup.config.js +3 -1
- package/src/Assets/Icon/ic-appstatus-cancelled.svg +6 -0
- package/src/Assets/Icon/ic-check.svg +5 -0
- package/src/Assets/Icon/ic-error-medium.svg +6 -0
- package/src/Common/Constants.ts +1 -1
- package/src/Common/CustomTagSelector/PropagateTagInfo.tsx +19 -19
- package/src/Common/CustomTagSelector/TagDetails.tsx +16 -14
- package/src/Common/CustomTagSelector/TagLabelSelect.tsx +2 -8
- package/src/Common/CustomTagSelector/TagLabelValueSelector.tsx +19 -27
- package/src/Common/CustomTagSelector/ValidationRules.ts +3 -3
- package/src/Common/InfoColorBar/InfoColourbar.tsx +92 -0
- package/src/Common/InfoColorBar/infoColourBar.scss +28 -0
- package/src/Common/MultiSelectCustomization.tsx +150 -0
- package/src/Common/Types.ts +33 -8
- package/src/Common/index.ts +3 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devtron-labs/devtron-fe-common-lib",
|
|
3
|
-
"version": "0.0.6-beta-
|
|
3
|
+
"version": "0.0.6-beta-18",
|
|
4
4
|
"description": "Supporting common component library",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -32,9 +32,11 @@
|
|
|
32
32
|
"rollup-plugin-delete": "^2.0.0",
|
|
33
33
|
"@svgr/rollup": "6.5.1",
|
|
34
34
|
"@rollup/plugin-url": "8.0.1",
|
|
35
|
+
"@rollup/plugin-commonjs": "24.0.1",
|
|
35
36
|
"typescript": "^4.9.4",
|
|
36
37
|
"react-toastify": "^8.2.0",
|
|
37
38
|
"@tippyjs/react": "^4.2.0",
|
|
39
|
+
"react-select": "^5.2.2",
|
|
38
40
|
"@sentry/browser": "^7.31.1"
|
|
39
41
|
},
|
|
40
42
|
"peerDependencies": {
|
package/rollup.config.js
CHANGED
|
@@ -7,13 +7,15 @@ import del from 'rollup-plugin-delete'
|
|
|
7
7
|
import pkg from './package.json'
|
|
8
8
|
import svgr from '@svgr/rollup'
|
|
9
9
|
import url from '@rollup/plugin-url'
|
|
10
|
+
import commonjs from '@rollup/plugin-commonjs';
|
|
10
11
|
|
|
11
12
|
export default {
|
|
12
13
|
input: './src/index.ts',
|
|
13
|
-
output: [{ file: pkg.main, format: '
|
|
14
|
+
output: [{ file: pkg.main, format: 'cjs' }],
|
|
14
15
|
plugins: [
|
|
15
16
|
peerDepsExternal(),
|
|
16
17
|
resolve(),
|
|
18
|
+
commonjs(),
|
|
17
19
|
typescript(),
|
|
18
20
|
postcss({
|
|
19
21
|
extensions: ['.css'],
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 28 28" width="24" height="24">
|
|
2
|
+
<g fill="none" fill-rule="evenodd" transform="translate(2 2)">
|
|
3
|
+
<rect width="20" height="20" fill="#B1B7BC" rx="10"/>
|
|
4
|
+
<path fill="#FFF" fill-rule="nonzero" d="M6.464 6.464a1 1 0 0 1 1.415 0l2.12 2.12 2.122-2.12a1 1 0 0 1 1.32-.083l.095.083a1 1 0 0 1 0 1.415l-2.122 2.12 2.122 2.122a1 1 0 0 1 .083 1.32l-.083.095a1 1 0 0 1-1.415 0L10 11.414l-2.121 2.122a1 1 0 0 1-1.32.083l-.095-.083a1 1 0 0 1 0-1.415L8.584 10l-2.12-2.121a1 1 0 0 1-.083-1.32z"/>
|
|
5
|
+
</g>
|
|
6
|
+
</svg>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="21" viewBox="0 0 20 21">
|
|
2
|
+
<g fill="none" fill-rule="evenodd">
|
|
3
|
+
<path fill="#FDE7E7" stroke="#F33E3E" stroke-linejoin="round" stroke-width="2" d="M10 1.667C5.4 1.667 1.667 5.4 1.667 10S5.4 18.333 10 18.333 18.333 14.6 18.333 10 14.6 1.667 10 1.667z"/>
|
|
4
|
+
<path fill="#F33E3E" d="M10 10.833c.46 0 .833-.373.833-.833V6.667c0-.46-.373-.834-.833-.834-.46 0-.833.373-.833.834V10c0 .46.373.833.833.833zm0 3.334c.46 0 .833-.373.833-.834 0-.46-.373-.833-.833-.833-.46 0-.833.373-.833.833 0 .46.373.834.833.834z"/>
|
|
5
|
+
</g>
|
|
6
|
+
</svg>
|
package/src/Common/Constants.ts
CHANGED
|
@@ -4,6 +4,6 @@ export const Host = process.env.REACT_APP_ORCHESTRATOR_ROOT
|
|
|
4
4
|
export const PATTERNS = {
|
|
5
5
|
KUBERNETES_KEY_PREFIX: /^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$/,
|
|
6
6
|
KUBERNETES_KEY_NAME: /^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$/,
|
|
7
|
-
START_END_ALPHANUMERIC: /^([
|
|
7
|
+
START_END_ALPHANUMERIC: /^([Az09].*[A-Za-z0-9])$|[A-Za-z0-9]$/,
|
|
8
8
|
ALPHANUMERIC_WITH_SPECIAL_CHAR: /^[A-Za-z0-9._-]+$/, // allow alphanumeric,(.) ,(-),(_)
|
|
9
9
|
}
|
|
@@ -13,25 +13,25 @@ export default function PropagateTagInfo() {
|
|
|
13
13
|
)
|
|
14
14
|
}
|
|
15
15
|
return (
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
16
|
+
<TippyCustomized
|
|
17
|
+
theme={TippyTheme.white}
|
|
18
|
+
className="w-300"
|
|
19
|
+
placement="top"
|
|
20
|
+
Icon={InjectTag}
|
|
21
|
+
heading={'Propagate tags to K8s resources'}
|
|
22
|
+
infoText={`Add a tag and click on the ⬡ icon to propagate tags as labels to Kubernetes resources.`}
|
|
23
|
+
additionalContent={additionalInfo()}
|
|
24
|
+
showCloseButton={true}
|
|
25
|
+
trigger="click"
|
|
26
|
+
interactive={true}
|
|
27
|
+
documentationLink={''}
|
|
28
|
+
documentationLinkText={'View Documentation'}
|
|
29
|
+
>
|
|
30
|
+
<div className="flexbox">
|
|
31
|
+
<InjectTag className="icon-dim-16 mt-2 mr-4" />
|
|
32
|
+
<span>Propagate tags</span>
|
|
33
33
|
<Help className="icon-dim-16 mt-2 ml-4 cursor" />
|
|
34
|
-
</
|
|
35
|
-
</
|
|
34
|
+
</div>
|
|
35
|
+
</TippyCustomized>
|
|
36
36
|
)
|
|
37
37
|
}
|
|
@@ -1,20 +1,10 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { ReactComponent as DeleteCross } from '../../Assets/Icon/ic-close.svg'
|
|
3
3
|
import { ReactComponent as InjectTag } from '../../Assets/Icon/inject-tag.svg'
|
|
4
|
-
import {
|
|
4
|
+
import { TagDetailType } from '../Types'
|
|
5
5
|
import { TagLabelValueSelector } from './TagLabelValueSelector'
|
|
6
6
|
|
|
7
|
-
export default function TagDetails({
|
|
8
|
-
index,
|
|
9
|
-
tagData,
|
|
10
|
-
setTagData,
|
|
11
|
-
removeTag,
|
|
12
|
-
}: {
|
|
13
|
-
index: number
|
|
14
|
-
tagData: TagType
|
|
15
|
-
setTagData: (index: number, tagData: TagType) => void
|
|
16
|
-
removeTag: (index: number) => void
|
|
17
|
-
}) {
|
|
7
|
+
export default function TagDetails({ index, tagData, setTagData, removeTag }: TagDetailType) {
|
|
18
8
|
const deleteTag = (): void => {
|
|
19
9
|
removeTag(index)
|
|
20
10
|
}
|
|
@@ -31,8 +21,20 @@ export default function TagDetails({
|
|
|
31
21
|
>
|
|
32
22
|
<InjectTag className={`icon-dim-20 mt-4 ${tagData.propagate ? 'scn-0' : ''}`} />
|
|
33
23
|
</div>
|
|
34
|
-
<TagLabelValueSelector
|
|
35
|
-
|
|
24
|
+
<TagLabelValueSelector
|
|
25
|
+
selectedTagIndex={index}
|
|
26
|
+
tagData={tagData}
|
|
27
|
+
setTagData={setTagData}
|
|
28
|
+
type="key"
|
|
29
|
+
placeholder="Enter key"
|
|
30
|
+
/>
|
|
31
|
+
<TagLabelValueSelector
|
|
32
|
+
selectedTagIndex={index}
|
|
33
|
+
tagData={tagData}
|
|
34
|
+
setTagData={setTagData}
|
|
35
|
+
type="value"
|
|
36
|
+
placeholder="Enter value"
|
|
37
|
+
/>
|
|
36
38
|
<div className="dc__border pl-4 pr-4 dc__right-radius-4 pointer" onClick={deleteTag}>
|
|
37
39
|
<DeleteCross className="icon-dim-20 mt-4" />
|
|
38
40
|
</div>
|
|
@@ -2,15 +2,9 @@ import React from 'react'
|
|
|
2
2
|
import PropagateTagInfo from './PropagateTagInfo'
|
|
3
3
|
import { ReactComponent as Add } from '../../Assets/Icon/ic-add.svg'
|
|
4
4
|
import TagDetails from './TagDetails'
|
|
5
|
-
import {
|
|
5
|
+
import { TagLabelSelectType } from '../Types'
|
|
6
6
|
|
|
7
|
-
export const TagLabelSelect = ({
|
|
8
|
-
labelTags,
|
|
9
|
-
setLabelTags,
|
|
10
|
-
}: {
|
|
11
|
-
labelTags: TagType[]
|
|
12
|
-
setLabelTags: (tagList: TagType[]) => void
|
|
13
|
-
}) => {
|
|
7
|
+
export const TagLabelSelect = ({ labelTags, setLabelTags }: TagLabelSelectType) => {
|
|
14
8
|
const setTagData = (index, tagValue): void => {
|
|
15
9
|
const _tags = [...labelTags]
|
|
16
10
|
_tags[index] = tagValue
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useEffect } from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import { TagLabelValueSelectorType } from '../Types'
|
|
3
3
|
import PopupMenu from '../PopupMenu'
|
|
4
4
|
import { ValidationRules } from './ValidationRules'
|
|
5
5
|
import { ReactComponent as ErrorCross } from '../../Assets/Icon/ic-close.svg'
|
|
@@ -12,29 +12,22 @@ export const TagLabelValueSelector = ({
|
|
|
12
12
|
tagOptions,
|
|
13
13
|
isRequired,
|
|
14
14
|
type,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
tagData: TagType
|
|
18
|
-
setTagData: (index: number, tagData: TagType) => void
|
|
19
|
-
tagOptions?: OptionType[]
|
|
20
|
-
isRequired?: boolean
|
|
21
|
-
type?: string
|
|
22
|
-
}) => {
|
|
15
|
+
placeholder,
|
|
16
|
+
}: TagLabelValueSelectorType) => {
|
|
23
17
|
const [selectedValue, setSelectedValue] = useState<string>('')
|
|
24
18
|
const [isPopupOpen, togglePopup] = useState<boolean>(false)
|
|
25
19
|
|
|
26
20
|
const validationRules = new ValidationRules()
|
|
27
21
|
|
|
28
22
|
useEffect(() => {
|
|
29
|
-
|
|
30
|
-
setSelectedValue(_tagData[type])
|
|
23
|
+
setSelectedValue(tagData?.[type] || '')
|
|
31
24
|
}, [selectedTagIndex, tagData, type])
|
|
32
25
|
|
|
33
26
|
const handleOnBlur = (e) => {
|
|
34
27
|
if (
|
|
35
28
|
!e.relatedTarget ||
|
|
36
29
|
!e.relatedTarget.classList.value ||
|
|
37
|
-
e.relatedTarget.classList.value.
|
|
30
|
+
!e.relatedTarget.classList.value.includes(`tag-${selectedTagIndex}-class`)
|
|
38
31
|
) {
|
|
39
32
|
const _tagData = { ...tagData }
|
|
40
33
|
_tagData[type] = selectedValue
|
|
@@ -42,14 +35,12 @@ export const TagLabelValueSelector = ({
|
|
|
42
35
|
_tagData.isInvalidKey = selectedValue
|
|
43
36
|
? !validationRules.propagateTagKey(selectedValue).isValid
|
|
44
37
|
: _tagData.value !== ''
|
|
38
|
+
} else if (selectedValue) {
|
|
39
|
+
_tagData.isInvalidValue = !validationRules.propagateTagValue(selectedValue).isValid
|
|
40
|
+
_tagData.isInvalidKey = !_tagData.key || _tagData.isInvalidKey
|
|
45
41
|
} else {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
_tagData.isInvalidKey = !_tagData.key || _tagData.isInvalidKey
|
|
49
|
-
} else {
|
|
50
|
-
_tagData.isInvalidValue = false
|
|
51
|
-
_tagData.isInvalidKey = !_tagData.key ? false : _tagData.isInvalidKey
|
|
52
|
-
}
|
|
42
|
+
_tagData.isInvalidValue = false
|
|
43
|
+
_tagData.isInvalidKey = !_tagData.key ? false : _tagData.isInvalidKey
|
|
53
44
|
}
|
|
54
45
|
setTagData(selectedTagIndex, _tagData)
|
|
55
46
|
}
|
|
@@ -67,12 +58,12 @@ export const TagLabelValueSelector = ({
|
|
|
67
58
|
|
|
68
59
|
const renderValidationsSuggestions = (): JSX.Element => {
|
|
69
60
|
let field = { isValid: true, messages: [] }
|
|
70
|
-
if (type === '
|
|
71
|
-
if (
|
|
72
|
-
field = validationRules.
|
|
61
|
+
if (type === 'key') {
|
|
62
|
+
if (selectedValue || tagData.value || tagData.description) {
|
|
63
|
+
field = validationRules.propagateTagKey(selectedValue)
|
|
73
64
|
}
|
|
74
|
-
} else {
|
|
75
|
-
field = validationRules.
|
|
65
|
+
} else if (isRequired || selectedValue) {
|
|
66
|
+
field = validationRules.propagateTagValue(selectedValue)
|
|
76
67
|
}
|
|
77
68
|
if (!field.isValid) {
|
|
78
69
|
return (
|
|
@@ -80,7 +71,7 @@ export const TagLabelValueSelector = ({
|
|
|
80
71
|
{field.messages.map((error) => (
|
|
81
72
|
<div key={error} className="flexbox p-4">
|
|
82
73
|
<span>
|
|
83
|
-
<ErrorCross className="
|
|
74
|
+
<ErrorCross className="fcr-5 mr-4" />
|
|
84
75
|
</span>
|
|
85
76
|
<span>{error}</span>
|
|
86
77
|
</div>
|
|
@@ -88,7 +79,7 @@ export const TagLabelValueSelector = ({
|
|
|
88
79
|
{type === 'key' && (
|
|
89
80
|
<div className="flexbox p-4">
|
|
90
81
|
<span>
|
|
91
|
-
<Info className="
|
|
82
|
+
<Info className="mr-4" />
|
|
92
83
|
</span>
|
|
93
84
|
<span className="dc__italic-font-style">Key format: prefix/name or name</span>
|
|
94
85
|
</div>
|
|
@@ -122,7 +113,7 @@ export const TagLabelValueSelector = ({
|
|
|
122
113
|
return (
|
|
123
114
|
<PopupMenu onToggleCallback={(isOpen) => togglePopup(isOpen)} autoClose>
|
|
124
115
|
<PopupMenu.Button
|
|
125
|
-
rootClassName={
|
|
116
|
+
rootClassName={`h-32 ${
|
|
126
117
|
type === 'key'
|
|
127
118
|
? `dc__no-right-radius`
|
|
128
119
|
: `dc__no-border-radius dc__no-right-border dc__no-left-border`
|
|
@@ -134,6 +125,7 @@ export const TagLabelValueSelector = ({
|
|
|
134
125
|
value={selectedValue}
|
|
135
126
|
onChange={handleInputChange}
|
|
136
127
|
onBlur={handleOnBlur}
|
|
128
|
+
placeholder={placeholder}
|
|
137
129
|
/>
|
|
138
130
|
</PopupMenu.Button>
|
|
139
131
|
<PopupMenu.Body rootClassName={`tag-${selectedTagIndex}-class`} autoWidth={true}>
|
|
@@ -5,11 +5,11 @@ const validateTagValue = (value: string): string[] => {
|
|
|
5
5
|
if (value.length > 63) {
|
|
6
6
|
errorList.push('Can be max 63 characters')
|
|
7
7
|
}
|
|
8
|
-
|
|
8
|
+
const firstLastAlphanumeric = PATTERNS.START_END_ALPHANUMERIC.test(value)
|
|
9
9
|
if (!firstLastAlphanumeric) {
|
|
10
10
|
errorList.push('Must start and end with an alphanumeric character')
|
|
11
11
|
}
|
|
12
|
-
|
|
12
|
+
const validValue = PATTERNS.ALPHANUMERIC_WITH_SPECIAL_CHAR.test(value)
|
|
13
13
|
if (!validValue) {
|
|
14
14
|
errorList.push('Can only contain alphanumeric chars and (-), (_), (.)')
|
|
15
15
|
}
|
|
@@ -32,7 +32,7 @@ export class ValidationRules {
|
|
|
32
32
|
if (prefix.length > 253) {
|
|
33
33
|
errorList.push('Prefix: Can be max 253 characters')
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
const validPrefix = PATTERNS.KUBERNETES_KEY_PREFIX.test(prefix)
|
|
36
36
|
if (!validPrefix) {
|
|
37
37
|
errorList.push('Prefix: Must be a DNS subdomain (a series of DNS labels separated by dots (.)')
|
|
38
38
|
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import React, { CSSProperties } from 'react'
|
|
2
|
+
import { Link } from 'react-router-dom'
|
|
3
|
+
import './infoColourBar.scss'
|
|
4
|
+
|
|
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
|
+
function InfoColourBar({
|
|
21
|
+
message,
|
|
22
|
+
classname,
|
|
23
|
+
Icon,
|
|
24
|
+
iconClass,
|
|
25
|
+
iconSize,
|
|
26
|
+
renderActionButton,
|
|
27
|
+
linkText,
|
|
28
|
+
redirectLink,
|
|
29
|
+
linkOnClick,
|
|
30
|
+
linkClass,
|
|
31
|
+
internalLink,
|
|
32
|
+
styles,
|
|
33
|
+
}: InfoColourBarType) {
|
|
34
|
+
const renderLink = () => {
|
|
35
|
+
if (!linkText) {
|
|
36
|
+
return null
|
|
37
|
+
} else if (redirectLink) {
|
|
38
|
+
if (internalLink) {
|
|
39
|
+
return (
|
|
40
|
+
<Link
|
|
41
|
+
to={redirectLink}
|
|
42
|
+
onClick={linkOnClick}
|
|
43
|
+
className="cursor dc__link dc__underline-onhover mr-5"
|
|
44
|
+
>
|
|
45
|
+
{linkText}
|
|
46
|
+
</Link>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<a
|
|
52
|
+
href={redirectLink}
|
|
53
|
+
target="_blank"
|
|
54
|
+
onClick={linkOnClick}
|
|
55
|
+
className="cursor dc__link dc__underline-onhover mr-5"
|
|
56
|
+
>
|
|
57
|
+
{linkText}
|
|
58
|
+
</a>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
linkOnClick && (
|
|
64
|
+
<div onClick={linkOnClick} className="cursor dc__link dc__underline-onhover">
|
|
65
|
+
{linkText}
|
|
66
|
+
</div>
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<div className="info-bar-container">
|
|
73
|
+
<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`}
|
|
75
|
+
style={styles}
|
|
76
|
+
>
|
|
77
|
+
<div className={`flex top ${typeof renderActionButton === 'function' ? 'mr-5' : ''}`}>
|
|
78
|
+
<div className={`icon-dim-${iconSize ?? '20'} mr-10`}>
|
|
79
|
+
<Icon className={`icon-dim-${iconSize ?? '20'} ${iconClass || ''} mr-8`} />
|
|
80
|
+
</div>
|
|
81
|
+
<div className={`info-bar-message-wrapper ${linkClass || ''}`}>
|
|
82
|
+
<span className={linkText && redirectLink ? 'mr-5' : ''}>{message}</span>
|
|
83
|
+
{renderLink()}
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
{typeof renderActionButton === 'function' && renderActionButton()}
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export default InfoColourBar
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
.info-bar-container {
|
|
2
|
+
.info_text .success {
|
|
3
|
+
background-color: var(--G100);
|
|
4
|
+
}
|
|
5
|
+
.warn {
|
|
6
|
+
background: var(--Y100);
|
|
7
|
+
border: solid var(--Y200);
|
|
8
|
+
|
|
9
|
+
.warning-icon path:nth-child(2) {
|
|
10
|
+
fill: var(--Y700);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.info_bar {
|
|
15
|
+
background-color: var(--B100);
|
|
16
|
+
border: 1px solid var(--B200);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.error_bar {
|
|
20
|
+
background-color: var(--R100);
|
|
21
|
+
border: 1px solid var(--R200);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.question-bar {
|
|
25
|
+
background-color: var(--V100);
|
|
26
|
+
border: 1px solid var(--V200);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import Select, { components } from 'react-select'
|
|
3
|
+
import { ReactComponent as ClearIcon } from '../Assets/Icon/ic-appstatus-cancelled.svg'
|
|
4
|
+
import { ReactComponent as Check } from '../Assets/Icon/ic-check.svg'
|
|
5
|
+
import { ReactComponent as RedWarning } from '../Assets/Icon/ic-error-medium.svg'
|
|
6
|
+
|
|
7
|
+
export const Option = (props) => {
|
|
8
|
+
const { selectOption, data } = props
|
|
9
|
+
return (
|
|
10
|
+
<div className="flex left pl-12" style={{ background: props.isFocused ? 'var(--N100)' : 'transparent' }}>
|
|
11
|
+
<input
|
|
12
|
+
checked={props.isSelected}
|
|
13
|
+
disabled={props.isDisabled}
|
|
14
|
+
onChange={(e) => selectOption(data)}
|
|
15
|
+
type="checkbox"
|
|
16
|
+
style={{ height: '16px', width: '16px', flex: '0 0 16px' }}
|
|
17
|
+
className="mr-8"
|
|
18
|
+
/>
|
|
19
|
+
<components.Option {...props} />
|
|
20
|
+
</div>
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const SingleSelectOption = (props) => {
|
|
25
|
+
const { selectOption, data } = props
|
|
26
|
+
const style = { height: '16px', width: '16px', flex: '0 0 16px' }
|
|
27
|
+
const onClick = (e) => selectOption(data)
|
|
28
|
+
return (
|
|
29
|
+
<div className="flex left pl-12" style={{ background: props.isFocused ? 'var(--N100)' : 'transparent' }}>
|
|
30
|
+
{props.isSelected ? (
|
|
31
|
+
<Check onClick={onClick} className="mr-8 icon-dim-16" style={style} />
|
|
32
|
+
) : (
|
|
33
|
+
<span onClick={onClick} className="mr-8" style={style} />
|
|
34
|
+
)}
|
|
35
|
+
<components.Option {...props} />
|
|
36
|
+
</div>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const MultiValueContainer = (props) => {
|
|
41
|
+
const { children, data, innerProps, selectProps } = props
|
|
42
|
+
const { label, value } = data
|
|
43
|
+
return (
|
|
44
|
+
<components.MultiValueContainer {...{ data, innerProps, selectProps }}>
|
|
45
|
+
<div className={`flex fs-12 ml-4 cn-9`}>{label}</div>
|
|
46
|
+
{children[1]}
|
|
47
|
+
</components.MultiValueContainer>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const ClearIndicator = (props) => {
|
|
52
|
+
const {
|
|
53
|
+
children = <ClearIcon className="icon-dim-24" />,
|
|
54
|
+
getStyles,
|
|
55
|
+
innerProps: { ref, ...restInnerProps },
|
|
56
|
+
} = props
|
|
57
|
+
return (
|
|
58
|
+
<div {...restInnerProps} ref={ref} style={getStyles('clearIndicator', props)}>
|
|
59
|
+
<div className="flex pointer">{children}</div>
|
|
60
|
+
</div>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const MultiValueRemove = (props) => {
|
|
65
|
+
const {
|
|
66
|
+
data,
|
|
67
|
+
innerProps: { onClick, onMouseDown },
|
|
68
|
+
selectProps,
|
|
69
|
+
} = props
|
|
70
|
+
return (
|
|
71
|
+
<components.MultiValueRemove {...props}>
|
|
72
|
+
<ClearIcon
|
|
73
|
+
{...{ onClick, onMouseDown }}
|
|
74
|
+
onClick={(e) => onClick(data)}
|
|
75
|
+
style={{ height: '18px', width: '18px' }}
|
|
76
|
+
/>
|
|
77
|
+
</components.MultiValueRemove>
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export const MultiValueChipContainer = ({ validator, isAllSelected = false, ...props }) => {
|
|
82
|
+
const { children, data, innerProps, selectProps } = props
|
|
83
|
+
const { label, value } = data
|
|
84
|
+
const isValidEmail = validator ? validator(value) : true
|
|
85
|
+
|
|
86
|
+
if(isAllSelected && value !== '*') return null
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<components.MultiValueContainer {...{ data, innerProps, selectProps }}>
|
|
90
|
+
<div className={`flex fs-12 pl-4 pr-4`}>
|
|
91
|
+
{!isValidEmail && <RedWarning className="mr-4 icon-dim-16" />}
|
|
92
|
+
<div className={`${isValidEmail ? 'cn-9' : 'cr-5'}`}>{label}</div>
|
|
93
|
+
</div>
|
|
94
|
+
{children[1]}
|
|
95
|
+
</components.MultiValueContainer>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export const multiSelectStyles = {
|
|
100
|
+
control: (base, state) => ({
|
|
101
|
+
...base,
|
|
102
|
+
cursor: state.isDisabled ? 'not-allowed' : 'normal',
|
|
103
|
+
border: state.isFocused ? '1px solid #06c' : '1px solid #d6dbdf',
|
|
104
|
+
boxShadow: 'none',
|
|
105
|
+
minheight: '24px !important'
|
|
106
|
+
}),
|
|
107
|
+
menu: (base, state) => ({
|
|
108
|
+
...base,
|
|
109
|
+
top: `40px`,
|
|
110
|
+
}),
|
|
111
|
+
option: (base, state) => {
|
|
112
|
+
return ({
|
|
113
|
+
...base,
|
|
114
|
+
backgroundColor: state.isFocused ? 'var(--N100)' : 'white',
|
|
115
|
+
color: 'var(--N900)',
|
|
116
|
+
padding: '8px 12px',
|
|
117
|
+
})
|
|
118
|
+
},
|
|
119
|
+
container: (base, state) => ({
|
|
120
|
+
...base,
|
|
121
|
+
cursor: state.isDisabled ? 'not-allowed' : 'normal'
|
|
122
|
+
}),
|
|
123
|
+
valueContainer: (base, state) => ({
|
|
124
|
+
...base,
|
|
125
|
+
color: state.selectProps.menuIsOpen ? 'var(--N500)' : base.color,
|
|
126
|
+
}),
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
interface CustomSelect {
|
|
130
|
+
sortSelected?: boolean
|
|
131
|
+
options: any[]
|
|
132
|
+
onChange: (...args) => void
|
|
133
|
+
value?: any
|
|
134
|
+
name?: string
|
|
135
|
+
placeholder?: string
|
|
136
|
+
className?: string
|
|
137
|
+
classNamePrefix?: string
|
|
138
|
+
menuPortalTarget?: any
|
|
139
|
+
components?: object
|
|
140
|
+
styles?: object
|
|
141
|
+
isMulti?: boolean
|
|
142
|
+
isDisabled?: boolean
|
|
143
|
+
closeMenuOnSelect?: boolean
|
|
144
|
+
hideSelectedOptions?: boolean
|
|
145
|
+
formatOptionLabel?: (...args) => any
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export const CustomSelect: React.FC<CustomSelect> = (props) => {
|
|
149
|
+
return <Select {...props} />
|
|
150
|
+
}
|
package/src/Common/Types.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { TagLabelSelect } from './CustomTagSelector'
|
|
2
|
+
|
|
1
3
|
export interface ResponseType {
|
|
2
4
|
code: number
|
|
3
5
|
status: string
|
|
@@ -12,20 +14,43 @@ export interface APIOptions {
|
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
export interface TagType {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
key: string
|
|
18
|
+
value?: string
|
|
19
|
+
description?: string
|
|
20
|
+
propagate: boolean
|
|
21
|
+
mandatoryProjectIdsCsv?: string[]
|
|
22
|
+
isInvalidKey?: boolean
|
|
23
|
+
isInvalidValue?: boolean
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
export interface OptionType {
|
|
24
|
-
label: string
|
|
25
|
-
value: string
|
|
27
|
+
label: string
|
|
28
|
+
value: string
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
export enum TippyTheme {
|
|
29
32
|
black = 'black',
|
|
30
33
|
white = 'white',
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface TagLabelSelectType {
|
|
37
|
+
labelTags: TagType[]
|
|
38
|
+
setLabelTags: (tagList: TagType[]) => void
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface TagDetailType {
|
|
42
|
+
index: number
|
|
43
|
+
tagData: TagType
|
|
44
|
+
setTagData: (index: number, tagData: TagType) => void
|
|
45
|
+
removeTag: (index: number) => void
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface TagLabelValueSelectorType {
|
|
49
|
+
selectedTagIndex: number
|
|
50
|
+
tagData: TagType
|
|
51
|
+
setTagData: (index: number, tagData: TagType) => void
|
|
52
|
+
tagOptions?: OptionType[]
|
|
53
|
+
isRequired?: boolean
|
|
54
|
+
type?: string
|
|
55
|
+
placeholder?: string
|
|
31
56
|
}
|
package/src/Common/index.ts
CHANGED
|
@@ -19,4 +19,6 @@ export * from './RadioGroup'
|
|
|
19
19
|
export { default as PopupMenu } from './PopupMenu'
|
|
20
20
|
export * from './TippyCustomized'
|
|
21
21
|
export * from './CustomTagSelector'
|
|
22
|
-
export * from './Dialogs'
|
|
22
|
+
export * from './Dialogs'
|
|
23
|
+
export * from './MultiSelectCustomization'
|
|
24
|
+
export * from './InfoColorBar/InfoColourbar'
|