@devtron-labs/devtron-fe-common-lib 0.0.52-beta-3 → 0.0.52
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/.eslintrc.js +16 -84
- package/.github/workflows/release-package.yml +3 -2
- 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 -1
- package/dist/Common/CustomInput/CustomInput.d.ts +1 -1
- package/dist/Common/CustomInput/Types.d.ts +1 -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 +17 -20
- package/dist/Common/EmptyState/GenericEmptyState.d.ts +1 -1
- package/dist/Common/Error.d.ts +1 -2
- 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/index.d.ts +1 -1
- package/dist/index.js +354 -283
- package/package.json +2 -19
- package/src/Common/AddCDButton/AddCDButton.tsx +2 -1
- package/src/Common/Api.ts +25 -20
- package/src/Common/AppStatus/AppStatus.tsx +12 -12
- package/src/Common/AppStatus/utils.ts +5 -6
- package/src/Common/BreadCrumb/BreadCrumb.tsx +28 -32
- package/src/Common/BreadCrumb/BreadcrumbStore.tsx +2 -2
- package/src/Common/BreadCrumb/Types.ts +12 -11
- package/src/Common/ChartVersionAndTypeSelector.tsx +1 -1
- package/src/Common/Checkbox.tsx +19 -17
- package/src/Common/ClipboardButton/ClipboardButton.tsx +1 -1
- package/src/Common/ClipboardButton/__tests__/ClipboardButton.test.tsx +1 -0
- package/src/Common/Common.service.ts +65 -60
- package/src/Common/Constants.ts +9 -9
- package/src/Common/CustomInput/CustomInput.tsx +28 -22
- package/src/Common/CustomInput/Types.ts +3 -4
- package/src/Common/CustomInput/index.ts +1 -1
- package/src/Common/CustomTagSelector/PropagateTagInfo.tsx +18 -15
- package/src/Common/CustomTagSelector/ResizableTagTextArea.tsx +9 -9
- package/src/Common/CustomTagSelector/TagDetails.tsx +3 -9
- package/src/Common/CustomTagSelector/TagLabelSelect.tsx +9 -7
- package/src/Common/CustomTagSelector/TagLabelValueSelector.tsx +35 -31
- package/src/Common/CustomTagSelector/TagSelector.utils.ts +3 -2
- package/src/Common/CustomTagSelector/Types.ts +1 -1
- package/src/Common/CustomTagSelector/ValidationRules.ts +22 -18
- package/src/Common/CustomTagSelector/index.ts +2 -2
- package/src/Common/DebouncedSearch/DebouncedSearch.tsx +1 -2
- package/src/Common/DebouncedSearch/__tests__/DebouncedSearch.test.tsx +1 -0
- package/src/Common/DeleteComponentModal/DeleteComponent.tsx +32 -27
- package/src/Common/DeleteComponentModal/types.ts +1 -1
- package/src/Common/DevtronProgressing/DevtronProgressing.tsx +8 -5
- package/src/Common/Dialogs/ConfirmationDialog.tsx +24 -24
- package/src/Common/Dialogs/DeleteDialog.tsx +5 -3
- package/src/Common/Dialogs/DialogForm.tsx +35 -31
- package/src/Common/Dialogs/ForceDeleteDialog.tsx +7 -13
- 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 +17 -13
- package/src/Common/EmptyState/GenericEmptyState.tsx +15 -25
- package/src/Common/Error.tsx +5 -5
- package/src/Common/ErrorScreenNotFound.tsx +12 -9
- package/src/Common/Grid/Grid.tsx +2 -1
- package/src/Common/Helper.tsx +37 -36
- 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 +7 -5
- package/src/Common/ImageTags.Types.ts +3 -2
- package/src/Common/ImageTags.tsx +66 -61
- package/src/Common/InfoColorBar/InfoColourbar.tsx +5 -10
- package/src/Common/Modals/Modal.tsx +3 -3
- package/src/Common/Modals/OpaqueModal.tsx +18 -25
- package/src/Common/Modals/VisibleModal.tsx +3 -7
- package/src/Common/Modals/VisibleModal2.tsx +15 -20
- package/src/Common/MultiSelectCustomization.tsx +13 -9
- package/src/Common/Policy.Types.ts +38 -38
- package/src/Common/PopupMenu.tsx +9 -10
- package/src/Common/Progressing.tsx +18 -15
- package/src/Common/RJSF/Form.tsx +1 -0
- package/src/Common/RJSF/common/FieldRow.tsx +1 -0
- package/src/Common/RJSF/config.ts +1 -0
- package/src/Common/RJSF/templates/ArrayFieldItemTemplate.tsx +1 -1
- package/src/Common/RJSF/templates/ArrayFieldTemplate.tsx +1 -0
- package/src/Common/RJSF/templates/BaseInput.tsx +1 -0
- package/src/Common/RJSF/templates/ButtonTemplates/AddButton.tsx +1 -0
- package/src/Common/RJSF/templates/ButtonTemplates/RemoveButton.tsx +1 -0
- package/src/Common/RJSF/templates/ButtonTemplates/SubmitButton.tsx +6 -1
- package/src/Common/RJSF/templates/Description.tsx +1 -0
- package/src/Common/RJSF/templates/Field.tsx +3 -14
- package/src/Common/RJSF/templates/FieldErrorTemplate.tsx +9 -6
- package/src/Common/RJSF/templates/ObjectFieldTemplate.tsx +7 -5
- package/src/Common/RJSF/templates/TitleField.tsx +1 -0
- package/src/Common/RJSF/templates/WrapIfAdditionalTemplate.tsx +1 -0
- package/src/Common/RJSF/utils.ts +57 -53
- package/src/Common/RJSF/widgets/Checkbox.tsx +2 -2
- package/src/Common/RJSF/widgets/Select.tsx +1 -0
- package/src/Common/RadioGroup/RadioGroup.tsx +23 -18
- package/src/Common/RadioGroup.tsx +23 -24
- package/src/Common/Reload.tsx +1 -0
- package/src/Common/ResizableTextarea.tsx +17 -18
- package/src/Common/Security/ScanVulnerabilitiesTable.tsx +34 -29
- package/src/Common/ServerError.ts +1 -5
- package/src/Common/TippyCustomized.tsx +38 -41
- package/src/Common/ToastBody.tsx +7 -6
- package/src/Common/Toggle/Toggle.tsx +3 -3
- package/src/Common/Types.ts +19 -19
- package/src/custom.d.ts +7 -7
- package/src/index.ts +1 -1
- package/.eslintignore +0 -79
- package/.github/pull_request_template.md +0 -25
- package/.github/workflows/ci.yml +0 -31
- package/.husky/pre-commit +0 -5
- package/.lintstagedrc +0 -3
- package/.nvmrc +0 -1
package/src/Common/Helper.tsx
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import * as Sentry from '@sentry/browser'
|
|
2
2
|
import moment from 'moment'
|
|
3
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
4
|
-
import * as React from 'react'
|
|
3
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
5
4
|
import { useLocation } from 'react-router-dom'
|
|
6
5
|
import { toast } from 'react-toastify'
|
|
7
|
-
import { JSONPath } from 'jsonpath-plus'
|
|
8
|
-
import * as jsonpatch from 'fast-json-patch'
|
|
9
6
|
import { ERROR_EMPTY_SCREEN, TOKEN_COOKIE_NAME } from './Constants'
|
|
10
7
|
import { ServerErrors } from './ServerError'
|
|
11
8
|
import { toastAccessDenied } from './ToastBody'
|
|
12
9
|
import { AsyncOptions, AsyncState, UseSearchString } from './Types'
|
|
10
|
+
import { JSONPath } from 'jsonpath-plus'
|
|
11
|
+
import * as jsonpatch from 'fast-json-patch'
|
|
13
12
|
|
|
14
13
|
toast.configure({
|
|
15
14
|
autoClose: 3000,
|
|
@@ -80,19 +79,16 @@ export const stopPropagation = (event): void => {
|
|
|
80
79
|
}
|
|
81
80
|
|
|
82
81
|
export function useThrottledEffect(callback, delay, deps = []) {
|
|
83
|
-
//
|
|
82
|
+
//function will be executed only once in a given time interval.
|
|
84
83
|
const lastRan = useRef(Date.now())
|
|
85
84
|
|
|
86
85
|
useEffect(() => {
|
|
87
|
-
const handler = setTimeout(
|
|
88
|
-
()
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
},
|
|
94
|
-
delay - (Date.now() - lastRan.current),
|
|
95
|
-
)
|
|
86
|
+
const handler = setTimeout(function () {
|
|
87
|
+
if (Date.now() - lastRan.current >= delay) {
|
|
88
|
+
callback()
|
|
89
|
+
lastRan.current = Date.now()
|
|
90
|
+
}
|
|
91
|
+
}, delay - (Date.now() - lastRan.current))
|
|
96
92
|
|
|
97
93
|
return () => {
|
|
98
94
|
clearTimeout(handler)
|
|
@@ -121,7 +117,7 @@ export function getRandomColor(email: string): string {
|
|
|
121
117
|
return colors[sum % colors.length]
|
|
122
118
|
}
|
|
123
119
|
|
|
124
|
-
export const getAlphabetIcon = (str: string, rootClassName: string =
|
|
120
|
+
export const getAlphabetIcon = (str: string, rootClassName: string = "") => {
|
|
125
121
|
if (!str) return null
|
|
126
122
|
return (
|
|
127
123
|
<span
|
|
@@ -133,7 +129,9 @@ export const getAlphabetIcon = (str: string, rootClassName: string = '') => {
|
|
|
133
129
|
)
|
|
134
130
|
}
|
|
135
131
|
|
|
136
|
-
export const getEmptyArrayOfLength = (length: number) =>
|
|
132
|
+
export const getEmptyArrayOfLength = (length: number) => {
|
|
133
|
+
return Array.from({ length })
|
|
134
|
+
}
|
|
137
135
|
|
|
138
136
|
export function noop(...args): any {}
|
|
139
137
|
|
|
@@ -157,7 +155,7 @@ export function getCookie(sKey) {
|
|
|
157
155
|
}
|
|
158
156
|
return (
|
|
159
157
|
document.cookie.replace(
|
|
160
|
-
new RegExp(
|
|
158
|
+
new RegExp('(?:(?:^|.*;)\\s*' + sKey.replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=\\s*([^;]*).*$)|^.*$'),
|
|
161
159
|
'$1',
|
|
162
160
|
) || null
|
|
163
161
|
)
|
|
@@ -200,7 +198,7 @@ export function useForm(stateSchema, validationSchema = {}, callback) {
|
|
|
200
198
|
// in every re-render in component
|
|
201
199
|
const validateState = useCallback(
|
|
202
200
|
(state) => {
|
|
203
|
-
//
|
|
201
|
+
//check errors in all fields
|
|
204
202
|
const hasErrorInState = Object.keys(validationSchema).some((key) => {
|
|
205
203
|
const isInputFieldRequired = validationSchema[key].required
|
|
206
204
|
const stateValue = state[key].value // state value
|
|
@@ -227,7 +225,7 @@ export function useForm(stateSchema, validationSchema = {}, callback) {
|
|
|
227
225
|
}
|
|
228
226
|
|
|
229
227
|
// single validator
|
|
230
|
-
|
|
228
|
+
let _validator = validationSchema[name].validator
|
|
231
229
|
if (_validator && typeof _validator === 'object') {
|
|
232
230
|
if (!_validateSingleValidator(_validator, value)) {
|
|
233
231
|
return _validator.error
|
|
@@ -235,9 +233,9 @@ export function useForm(stateSchema, validationSchema = {}, callback) {
|
|
|
235
233
|
}
|
|
236
234
|
|
|
237
235
|
// multiple validators
|
|
238
|
-
|
|
236
|
+
let _validators = validationSchema[name].validators
|
|
239
237
|
if (_validators && typeof _validators === 'object' && Array.isArray(_validators)) {
|
|
240
|
-
|
|
238
|
+
let errors = []
|
|
241
239
|
_validators.forEach((_validator) => {
|
|
242
240
|
if (!_validateSingleValidator(_validator, value)) {
|
|
243
241
|
errors.push(_validator.error)
|
|
@@ -256,7 +254,7 @@ export function useForm(stateSchema, validationSchema = {}, callback) {
|
|
|
256
254
|
setIsDirty(true)
|
|
257
255
|
|
|
258
256
|
const { name, value } = event.target
|
|
259
|
-
|
|
257
|
+
let error = validateField(name, value)
|
|
260
258
|
setState((prevState) => ({
|
|
261
259
|
...prevState,
|
|
262
260
|
[name]: { value, error },
|
|
@@ -284,7 +282,7 @@ export function handleUTCTime(ts: string, isRelativeTime = false) {
|
|
|
284
282
|
let timestamp = ''
|
|
285
283
|
try {
|
|
286
284
|
if (ts && ts.length) {
|
|
287
|
-
|
|
285
|
+
let date = moment(ts)
|
|
288
286
|
if (isRelativeTime) timestamp = date.fromNow()
|
|
289
287
|
else timestamp = date.format('ddd DD MMM YYYY HH:mm:ss')
|
|
290
288
|
}
|
|
@@ -368,7 +366,9 @@ export function useAsync<T>(
|
|
|
368
366
|
dependencies: dependencyArray,
|
|
369
367
|
})
|
|
370
368
|
const mounted = useRef(true)
|
|
371
|
-
const dependencies: any[] = useMemo(() =>
|
|
369
|
+
const dependencies: any[] = useMemo(() => {
|
|
370
|
+
return [...dependencyArray, shouldRun]
|
|
371
|
+
}, [...dependencyArray, shouldRun])
|
|
372
372
|
|
|
373
373
|
const reload = () => {
|
|
374
374
|
async function call() {
|
|
@@ -434,8 +434,9 @@ export function useAsync<T>(
|
|
|
434
434
|
export const processDeployedTime = (lastDeployed, isArgoInstalled) => {
|
|
435
435
|
if (lastDeployed) {
|
|
436
436
|
return handleUTCTime(lastDeployed, true)
|
|
437
|
+
} else {
|
|
438
|
+
return isArgoInstalled ? '' : 'Not deployed'
|
|
437
439
|
}
|
|
438
|
-
return isArgoInstalled ? '' : 'Not deployed'
|
|
439
440
|
}
|
|
440
441
|
|
|
441
442
|
/**
|
|
@@ -488,19 +489,19 @@ export const customStyles = {
|
|
|
488
489
|
}),
|
|
489
490
|
}
|
|
490
491
|
|
|
491
|
-
export const getFilteredChartVersions = (charts, selectedChartType) =>
|
|
492
|
+
export const getFilteredChartVersions = (charts, selectedChartType) => {
|
|
492
493
|
// Filter chart versions based on selected chart type
|
|
493
|
-
charts
|
|
494
|
+
return charts
|
|
494
495
|
.filter((item) => item?.chartType === selectedChartType.value)
|
|
495
496
|
.map((item) => ({
|
|
496
497
|
value: item?.chartVersion,
|
|
497
498
|
label: item?.chartVersion,
|
|
498
499
|
chartRefId: item.chartRefId,
|
|
499
500
|
}))
|
|
500
|
-
|
|
501
|
+
}
|
|
501
502
|
function removeEmptyObjectKeysAndNullValues(obj) {
|
|
502
503
|
// It recursively removes empty object keys and array values that are null
|
|
503
|
-
for (
|
|
504
|
+
for (let key in obj) {
|
|
504
505
|
if (Array.isArray(obj[key])) {
|
|
505
506
|
if (obj[key].length === 0) continue
|
|
506
507
|
obj[key] = obj[key].filter((item) => item !== null)
|
|
@@ -521,7 +522,7 @@ function removeEmptyObjectKeysAndNullValues(obj) {
|
|
|
521
522
|
|
|
522
523
|
export function getUnlockedJSON(json, jsonPathArray) {
|
|
523
524
|
const jsonCopy = JSON.parse(JSON.stringify(json))
|
|
524
|
-
|
|
525
|
+
let patches = jsonPathArray.flatMap((jsonPath) => {
|
|
525
526
|
const pathsToRemove = JSONPath({ path: jsonPath, json: jsonCopy, resultType: 'all' })
|
|
526
527
|
return pathsToRemove.map((result) =>
|
|
527
528
|
Array.isArray(result.parent)
|
|
@@ -529,7 +530,7 @@ export function getUnlockedJSON(json, jsonPathArray) {
|
|
|
529
530
|
: { op: 'remove', path: result.pointer },
|
|
530
531
|
)
|
|
531
532
|
})
|
|
532
|
-
|
|
533
|
+
let newDocument = jsonpatch.applyPatch(jsonCopy, patches).newDocument
|
|
533
534
|
|
|
534
535
|
removeEmptyObjectKeysAndNullValues(newDocument)
|
|
535
536
|
return newDocument
|
|
@@ -537,7 +538,7 @@ export function getUnlockedJSON(json, jsonPathArray) {
|
|
|
537
538
|
|
|
538
539
|
export function getLockedJSON(json, jsonPathArray: string[]) {
|
|
539
540
|
const jsonCopy = JSON.parse(JSON.stringify(json))
|
|
540
|
-
|
|
541
|
+
let resultJson = {}
|
|
541
542
|
jsonPathArray.forEach((jsonPath) => {
|
|
542
543
|
const elements = JSONPath({ path: jsonPath, json: jsonCopy, resultType: 'all' })
|
|
543
544
|
elements.forEach((element) => {
|
|
@@ -545,16 +546,16 @@ export function getLockedJSON(json, jsonPathArray: string[]) {
|
|
|
545
546
|
const lastPath = pathArray.pop()
|
|
546
547
|
let current = resultJson
|
|
547
548
|
for (let i = 0; i < pathArray.length; i++) {
|
|
548
|
-
|
|
549
|
+
let key = isNaN(Number(pathArray[i])) ? pathArray[i] : parseInt(pathArray[i])
|
|
549
550
|
if (!current[key]) {
|
|
550
|
-
current[key] = isNaN(Number(pathArray[i + 1]
|
|
551
|
+
current[key] = isNaN(Number(pathArray[i + 1]??lastPath)) ? {} : []
|
|
551
552
|
}
|
|
552
553
|
current = current[key]
|
|
553
554
|
}
|
|
554
|
-
|
|
555
|
+
let key = isNaN(Number(lastPath)) ? lastPath : parseInt(lastPath)
|
|
555
556
|
current[key] = element.value
|
|
556
557
|
})
|
|
557
558
|
})
|
|
558
|
-
// eslint-disable-next-line dot-notation
|
|
559
559
|
return resultJson['$']
|
|
560
560
|
}
|
|
561
|
+
|
|
@@ -2,10 +2,12 @@ import { useState, useEffect } from 'react'
|
|
|
2
2
|
|
|
3
3
|
let timeout
|
|
4
4
|
|
|
5
|
-
const getSize = () =>
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
const getSize = () => {
|
|
6
|
+
return {
|
|
7
|
+
width: window.innerWidth,
|
|
8
|
+
height: window.innerHeight,
|
|
9
|
+
}
|
|
10
|
+
}
|
|
9
11
|
|
|
10
12
|
export const useWindowSize = () => {
|
|
11
13
|
const [windowSize, setWindowSize] = useState(getSize)
|
|
@@ -15,7 +17,7 @@ export const useWindowSize = () => {
|
|
|
15
17
|
window.cancelAnimationFrame(timeout)
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
timeout = window.requestAnimationFrame(()
|
|
20
|
+
timeout = window.requestAnimationFrame(function () {
|
|
19
21
|
setWindowSize(getSize())
|
|
20
22
|
})
|
|
21
23
|
}
|
|
@@ -13,12 +13,13 @@ export interface ImageComment {
|
|
|
13
13
|
artifactId: number
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
|
|
16
17
|
export interface ImageTaggingContainerType {
|
|
17
18
|
ciPipelineId?: number
|
|
18
19
|
artifactId?: number
|
|
19
20
|
imageComment?: ImageComment
|
|
20
21
|
imageReleaseTags?: ReleaseTag[]
|
|
21
|
-
updateCurrentAppMaterial
|
|
22
|
+
updateCurrentAppMaterial? : (matId:number, releaseTags?:ReleaseTag[], imageComment?:ImageComment) => void
|
|
22
23
|
appReleaseTagNames?: string[]
|
|
23
24
|
tagsEditable?: boolean
|
|
24
25
|
forceReInit?: boolean
|
|
@@ -40,4 +41,4 @@ export interface ImageButtonType {
|
|
|
40
41
|
isSuperAdmin: any
|
|
41
42
|
duplicateTag?: boolean
|
|
42
43
|
hideHardDelete?: boolean
|
|
43
|
-
}
|
|
44
|
+
}
|
package/src/Common/ImageTags.tsx
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { useEffect, useMemo, useRef, useState } from 'react'
|
|
2
|
-
import { toast } from 'react-toastify'
|
|
3
|
-
import Tippy from '@tippyjs/react'
|
|
1
|
+
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
|
4
2
|
import { ReactComponent as Add } from '../Assets/Icon/ic-add.svg'
|
|
5
3
|
import { ReactComponent as Close } from '../Assets/Icon/ic-cross.svg'
|
|
6
4
|
import { ReactComponent as QuestionFilled } from '../Assets/Icon/ic-help.svg'
|
|
@@ -9,6 +7,7 @@ import { ReactComponent as Question } from '../Assets/Icon/ic-help-outline.svg'
|
|
|
9
7
|
import { ReactComponent as EditIcon } from '../Assets/Icon/ic-pencil.svg'
|
|
10
8
|
import { ReactComponent as Redo } from '../Assets/Icon/ic-arrow-counter-clockwise.svg'
|
|
11
9
|
import { ReactComponent as Minus } from '../Assets/Icon/ic-minus.svg'
|
|
10
|
+
import { toast } from 'react-toastify'
|
|
12
11
|
import { ReactComponent as Info } from '../Assets/Icon/ic-info-filled.svg'
|
|
13
12
|
import { ReactComponent as Error } from '../Assets/Icon/ic-warning.svg'
|
|
14
13
|
import { ReactComponent as Warning } from '../Assets/Icon/ic-error-exclamation.svg'
|
|
@@ -18,6 +17,7 @@ import { ImageButtonType, ImageTaggingContainerType, ReleaseTag } from './ImageT
|
|
|
18
17
|
import { showError, stopPropagation } from './Helper'
|
|
19
18
|
import { TippyCustomized } from './TippyCustomized'
|
|
20
19
|
import { setImageTags } from './Common.service'
|
|
20
|
+
import Tippy from '@tippyjs/react'
|
|
21
21
|
import { Progressing } from './Progressing'
|
|
22
22
|
|
|
23
23
|
export const ImageTagsContainer = ({
|
|
@@ -34,15 +34,15 @@ export const ImageTagsContainer = ({
|
|
|
34
34
|
toggleCardMode,
|
|
35
35
|
hideHardDelete,
|
|
36
36
|
forceReInit,
|
|
37
|
-
isSuperAdmin
|
|
37
|
+
isSuperAdmin
|
|
38
38
|
}: ImageTaggingContainerType) => {
|
|
39
|
-
const [initialTags, setInitialTags] = useState<ReleaseTag[]>(imageReleaseTags
|
|
39
|
+
const [initialTags, setInitialTags] = useState<ReleaseTag[]>(imageReleaseTags ? imageReleaseTags : [])
|
|
40
40
|
const [initialDescription, setInitialDescription] = useState(imageComment ? imageComment.comment : '')
|
|
41
|
-
const [existingTags, setExistingTags] = useState(appReleaseTagNames
|
|
41
|
+
const [existingTags, setExistingTags] = useState(appReleaseTagNames ? appReleaseTagNames : [])
|
|
42
42
|
const [newDescription, setNewDescription] = useState(imageComment ? imageComment.comment : '')
|
|
43
43
|
const [isEditing, setIsEditing] = useState(false)
|
|
44
44
|
const [showTagsWarning, setShowTagsWarning] = useState(false)
|
|
45
|
-
const [displayedTags, setDisplayedTags] = useState<ReleaseTag[]>(imageReleaseTags
|
|
45
|
+
const [displayedTags, setDisplayedTags] = useState<ReleaseTag[]>(imageReleaseTags ? imageReleaseTags : [])
|
|
46
46
|
const [tagErrorMessage, setTagErrorMessage] = useState('')
|
|
47
47
|
const [createTags, setCreateTags] = useState<ReleaseTag[]>([])
|
|
48
48
|
const [softDeleteTags, setSoftDeleteTags] = useState<ReleaseTag[]>([])
|
|
@@ -51,20 +51,22 @@ export const ImageTagsContainer = ({
|
|
|
51
51
|
const [textInput, setTextInput] = useState<string>('')
|
|
52
52
|
const [loading, setLoading] = useState<boolean>(false)
|
|
53
53
|
|
|
54
|
+
|
|
54
55
|
useEffect(() => {
|
|
55
56
|
reInitState()
|
|
56
57
|
}, [imageReleaseTags, imageComment, tagsEditable])
|
|
57
58
|
|
|
58
59
|
useEffect(() => {
|
|
59
|
-
setExistingTags(appReleaseTagNames
|
|
60
|
+
setExistingTags(appReleaseTagNames ? appReleaseTagNames : [])
|
|
60
61
|
}, [appReleaseTagNames])
|
|
61
62
|
|
|
63
|
+
|
|
62
64
|
const reInitState = () => {
|
|
63
65
|
if (forceReInit || !isEditing) {
|
|
64
|
-
setInitialTags(imageReleaseTags
|
|
66
|
+
setInitialTags(imageReleaseTags ? imageReleaseTags : [])
|
|
65
67
|
setInitialDescription(imageComment ? imageComment.comment : '')
|
|
66
68
|
setNewDescription(imageComment ? imageComment.comment : '')
|
|
67
|
-
setDisplayedTags(imageReleaseTags
|
|
69
|
+
setDisplayedTags(imageReleaseTags ? imageReleaseTags : [])
|
|
68
70
|
setIsEditing(false)
|
|
69
71
|
}
|
|
70
72
|
}
|
|
@@ -95,7 +97,7 @@ export const ImageTagsContainer = ({
|
|
|
95
97
|
setTagErrorMessage('')
|
|
96
98
|
}
|
|
97
99
|
|
|
98
|
-
const validateTag = (lowercaseValue): boolean => {
|
|
100
|
+
const validateTag = (lowercaseValue) : boolean => {
|
|
99
101
|
if (
|
|
100
102
|
lowercaseValue.length == 0 ||
|
|
101
103
|
lowercaseValue.length >= 128 ||
|
|
@@ -118,9 +120,9 @@ export const ImageTagsContainer = ({
|
|
|
118
120
|
return true
|
|
119
121
|
}
|
|
120
122
|
|
|
121
|
-
const handleTagCreate = (newValue): ReleaseTag[] => {
|
|
123
|
+
const handleTagCreate = (newValue) : ReleaseTag[] => {
|
|
122
124
|
const lowercaseValue = newValue.toLowerCase().trim()
|
|
123
|
-
if
|
|
125
|
+
if(validateTag(lowercaseValue)) {
|
|
124
126
|
const newTag: ReleaseTag = {
|
|
125
127
|
id: 0,
|
|
126
128
|
tagName: lowercaseValue,
|
|
@@ -146,7 +148,7 @@ export const ImageTagsContainer = ({
|
|
|
146
148
|
deleted: !updatedTags[index].deleted,
|
|
147
149
|
}
|
|
148
150
|
const updatedTag = updatedTags[index]
|
|
149
|
-
|
|
151
|
+
let updatedSoftDeleteTags = [...softDeleteTags]
|
|
150
152
|
const tagIndex = updatedSoftDeleteTags.findIndex((tag) => tag.tagName === updatedTag.tagName)
|
|
151
153
|
if (tagIndex !== -1) {
|
|
152
154
|
// Tag already exists in softDeleteTags array, remove it
|
|
@@ -204,13 +206,13 @@ export const ImageTagsContainer = ({
|
|
|
204
206
|
|
|
205
207
|
const payload = {
|
|
206
208
|
createTags: tagsToBeCreated,
|
|
207
|
-
softDeleteTags,
|
|
209
|
+
softDeleteTags: softDeleteTags,
|
|
208
210
|
imageComment: {
|
|
209
211
|
id: 0,
|
|
210
212
|
comment: newDescription.trim(),
|
|
211
213
|
artifactId: 0,
|
|
212
214
|
},
|
|
213
|
-
hardDeleteTags,
|
|
215
|
+
hardDeleteTags: hardDeleteTags,
|
|
214
216
|
}
|
|
215
217
|
|
|
216
218
|
// set loading state true
|
|
@@ -240,7 +242,7 @@ export const ImageTagsContainer = ({
|
|
|
240
242
|
handleEditClick()
|
|
241
243
|
setShowTagsWarning(false)
|
|
242
244
|
setTagErrorMessage('')
|
|
243
|
-
if
|
|
245
|
+
if(updateCurrentAppMaterial)updateCurrentAppMaterial(artifactId,tags,res.result?.imageComment)
|
|
244
246
|
})
|
|
245
247
|
.catch((err) => {
|
|
246
248
|
// Fix toast message
|
|
@@ -251,45 +253,50 @@ export const ImageTagsContainer = ({
|
|
|
251
253
|
showError(err)
|
|
252
254
|
}
|
|
253
255
|
})
|
|
254
|
-
.finally(()
|
|
256
|
+
.finally(()=>{
|
|
255
257
|
setLoading(false)
|
|
256
258
|
})
|
|
257
259
|
}
|
|
258
260
|
|
|
259
|
-
const renderInfoCard = (): JSX.Element =>
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
<
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
261
|
+
const renderInfoCard = (): JSX.Element => {
|
|
262
|
+
return (
|
|
263
|
+
<TippyCustomized
|
|
264
|
+
theme={TippyTheme.white}
|
|
265
|
+
className="w-300 fcv-5"
|
|
266
|
+
placement="right"
|
|
267
|
+
Icon={QuestionFilled}
|
|
268
|
+
heading="Release tags"
|
|
269
|
+
showCloseButton={true}
|
|
270
|
+
trigger="click"
|
|
271
|
+
interactive={true}
|
|
272
|
+
additionalContent={getBuildContextAdditionalContent()}
|
|
273
|
+
>
|
|
274
|
+
<div className="flex">
|
|
275
|
+
<Question className="fcn-5 ml-8 cursor icon-dim-16"/>
|
|
276
|
+
</div>
|
|
277
|
+
</TippyCustomized>
|
|
278
|
+
)
|
|
279
|
+
}
|
|
276
280
|
|
|
277
|
-
const getBuildContextAdditionalContent = () =>
|
|
278
|
-
|
|
279
|
-
<div
|
|
280
|
-
|
|
281
|
-
<
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
281
|
+
const getBuildContextAdditionalContent = () => {
|
|
282
|
+
return (
|
|
283
|
+
<div className="h-250 fs-13 dc__overflow-scroll p-12">
|
|
284
|
+
<div>Release tags allow you to tag container images with readable and relatable tags eg. v1.0.</div>
|
|
285
|
+
<ul className="pl-20 mt-8">
|
|
286
|
+
<li>
|
|
287
|
+
A release tag can only be added if a workflow has CD pipelines deploying to Production
|
|
288
|
+
environments.
|
|
289
|
+
</li>
|
|
290
|
+
<li>Multiple tags can be added to an image.</li>
|
|
291
|
+
<li>Multiple images in an application cannot have the same tag.</li>
|
|
292
|
+
<li>
|
|
293
|
+
Tags cannot be deleted once saved. Although, you can soft delete a tag if an unwanted tag has
|
|
294
|
+
been added.
|
|
295
|
+
</li>
|
|
296
|
+
</ul>
|
|
297
|
+
</div>
|
|
298
|
+
)
|
|
299
|
+
}
|
|
293
300
|
|
|
294
301
|
const creatableRef = useRef(null)
|
|
295
302
|
|
|
@@ -299,7 +306,7 @@ export const ImageTagsContainer = ({
|
|
|
299
306
|
<AddImageButton handleEditClick={handleEditClick} />
|
|
300
307
|
</div>
|
|
301
308
|
) : (
|
|
302
|
-
<div
|
|
309
|
+
<div></div>
|
|
303
310
|
)
|
|
304
311
|
}
|
|
305
312
|
|
|
@@ -449,10 +456,8 @@ export const ImageTagsContainer = ({
|
|
|
449
456
|
className="flex left image-tag-left-border w-100 mt-8 mb-8 pr-10 pl-10"
|
|
450
457
|
data-testid="image-tags-container-hover"
|
|
451
458
|
>
|
|
452
|
-
<div className=
|
|
453
|
-
{initialDescription &&
|
|
454
|
-
<div className="mb-6 fs-13 lh-20 dc__word-break-all">{initialDescription}</div>
|
|
455
|
-
)}
|
|
459
|
+
<div className='w-100'>
|
|
460
|
+
{initialDescription && <div className="mb-6 fs-13 lh-20 dc__word-break-all">{initialDescription}</div>}
|
|
456
461
|
<div className="flex-wrap flex left">
|
|
457
462
|
{initialTags?.map((tag, index) => (
|
|
458
463
|
<ImageTagButton
|
|
@@ -515,11 +520,11 @@ export const ImageTagButton = ({
|
|
|
515
520
|
const tabColor = () => {
|
|
516
521
|
if (duplicateTag) {
|
|
517
522
|
return 'cr-5 bcr-1 er-2'
|
|
518
|
-
}
|
|
519
|
-
if (isSoftDeleted) {
|
|
523
|
+
} else if (isSoftDeleted) {
|
|
520
524
|
return 'cy-7 bcy-1 dc__strike-through ey-2'
|
|
525
|
+
} else {
|
|
526
|
+
return 'cn-9'
|
|
521
527
|
}
|
|
522
|
-
return 'cn-9'
|
|
523
528
|
}
|
|
524
529
|
|
|
525
530
|
return (
|
|
@@ -533,7 +538,7 @@ export const ImageTagButton = ({
|
|
|
533
538
|
) : (
|
|
534
539
|
<Tippy
|
|
535
540
|
className="default-tt"
|
|
536
|
-
arrow
|
|
541
|
+
arrow={true}
|
|
537
542
|
placement="top"
|
|
538
543
|
content={isInSoftDeleteTags ? 'Restore tag' : 'Soft delete tag'}
|
|
539
544
|
>
|
|
@@ -551,7 +556,7 @@ export const ImageTagButton = ({
|
|
|
551
556
|
</Tippy>
|
|
552
557
|
)}
|
|
553
558
|
{text}
|
|
554
|
-
<Tippy className="default-tt" arrow placement="top" content="Remove tag">
|
|
559
|
+
<Tippy className="default-tt" arrow={true} placement="top" content="Remove tag">
|
|
555
560
|
<div className={`action-icon ml-4 lh-16 pt-3 ${canTagBeHardDelete ? 'show-icon' : ''}`}>
|
|
556
561
|
<Close
|
|
557
562
|
className="icon-dim-12 fcn-6 cursor"
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import React from 'react'
|
|
1
2
|
import { Link } from 'react-router-dom'
|
|
2
3
|
import { InfoColourBarType } from '../Types'
|
|
3
4
|
import './infoColourBar.scss'
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
function InfoColourBar({
|
|
6
7
|
message,
|
|
7
8
|
classname,
|
|
8
9
|
Icon,
|
|
@@ -15,12 +16,11 @@ const InfoColourBar = ({
|
|
|
15
16
|
linkClass,
|
|
16
17
|
internalLink,
|
|
17
18
|
styles,
|
|
18
|
-
}: InfoColourBarType)
|
|
19
|
+
}: InfoColourBarType) {
|
|
19
20
|
const renderLink = () => {
|
|
20
21
|
if (!linkText) {
|
|
21
22
|
return null
|
|
22
|
-
}
|
|
23
|
-
if (redirectLink) {
|
|
23
|
+
} else if (redirectLink) {
|
|
24
24
|
if (internalLink) {
|
|
25
25
|
return (
|
|
26
26
|
<Link
|
|
@@ -41,7 +41,6 @@ const InfoColourBar = ({
|
|
|
41
41
|
onClick={linkOnClick}
|
|
42
42
|
data-testid="info-bar-redirectLink"
|
|
43
43
|
className="cursor dc__link dc__underline-onhover mr-5"
|
|
44
|
-
rel="noreferrer"
|
|
45
44
|
>
|
|
46
45
|
{linkText}
|
|
47
46
|
</a>
|
|
@@ -50,11 +49,7 @@ const InfoColourBar = ({
|
|
|
50
49
|
|
|
51
50
|
return (
|
|
52
51
|
linkOnClick && (
|
|
53
|
-
<div
|
|
54
|
-
onClick={linkOnClick}
|
|
55
|
-
className="cursor dc__link dc__underline-onhover"
|
|
56
|
-
data-testid="info-bar-linkText"
|
|
57
|
-
>
|
|
52
|
+
<div onClick={linkOnClick} className="cursor dc__link dc__underline-onhover" data-testid="info-bar-linkText">
|
|
58
53
|
{linkText}
|
|
59
54
|
</div>
|
|
60
55
|
)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import React, { useEffect } from 'react'
|
|
2
2
|
import ReactDOM from 'react-dom'
|
|
3
3
|
import { ModalType } from '../Types'
|
|
4
4
|
|
|
@@ -12,7 +12,7 @@ export const Modal = ({
|
|
|
12
12
|
preventWheelDisable = false,
|
|
13
13
|
noBackDrop,
|
|
14
14
|
}: ModalType) => {
|
|
15
|
-
const innerRef = useRef(null)
|
|
15
|
+
const innerRef = React.useRef(null)
|
|
16
16
|
function handleClick(e) {
|
|
17
17
|
if (typeof onClick !== 'function') return
|
|
18
18
|
if (innerRef && innerRef.current?.contains(e.target)) {
|
|
@@ -35,7 +35,7 @@ export const Modal = ({
|
|
|
35
35
|
}
|
|
36
36
|
useEffect(() => {
|
|
37
37
|
document.addEventListener('click', handleClick)
|
|
38
|
-
|
|
38
|
+
let modal = document.getElementById('visible-modal')
|
|
39
39
|
if (modal) modal.classList.add('show')
|
|
40
40
|
if (noBackDrop) modal.classList.add('no-back-drop')
|
|
41
41
|
if (!preventWheelDisable) document.body.addEventListener('wheel', disableWheel, { passive: false })
|
|
@@ -1,43 +1,36 @@
|
|
|
1
|
-
import
|
|
2
|
-
import ReactDOM from 'react-dom'
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import ReactDOM from 'react-dom';
|
|
3
3
|
import closeIcon from '../../Assets/Icon/ic-cross.svg'
|
|
4
4
|
|
|
5
5
|
export interface OpaqueModalProps {
|
|
6
|
-
className?: string
|
|
7
|
-
onHide?: any
|
|
8
|
-
noBackground?: boolean
|
|
6
|
+
className?: string;
|
|
7
|
+
onHide?: any;
|
|
8
|
+
noBackground?: boolean;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export class OpaqueModal extends Component<OpaqueModalProps> {
|
|
12
|
-
modalRef = document.getElementById('full-screen-modal')
|
|
11
|
+
export class OpaqueModal extends React.Component<OpaqueModalProps> {
|
|
12
|
+
modalRef = document.getElementById('full-screen-modal');
|
|
13
13
|
|
|
14
14
|
componentDidMount() {
|
|
15
|
-
if (this.props.noBackground)
|
|
16
|
-
|
|
15
|
+
if (this.props.noBackground)
|
|
16
|
+
this.modalRef.classList.add("show");
|
|
17
|
+
else this.modalRef.classList.add("show-with-bg");
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
componentWillUnmount() {
|
|
20
|
-
this.modalRef.classList.remove(
|
|
21
|
-
this.modalRef.classList.remove(
|
|
21
|
+
this.modalRef.classList.remove("show");
|
|
22
|
+
this.modalRef.classList.remove("show-with-bg");
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
render() {
|
|
25
|
-
const { className =
|
|
26
|
+
const { className = "", onHide = null } = { ...this.props };
|
|
26
27
|
|
|
27
28
|
return ReactDOM.createPortal(
|
|
28
29
|
<div className={`full-screen-modal__body-container ${className}`}>
|
|
29
30
|
{this.props.children}
|
|
30
|
-
{typeof onHide === 'function' && (
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
data-testid="opaque-modal-close"
|
|
35
|
-
>
|
|
36
|
-
<img className="close-img" src={closeIcon} alt="close" />
|
|
37
|
-
</div>
|
|
38
|
-
)}
|
|
39
|
-
</div>,
|
|
40
|
-
document.getElementById('full-screen-modal'),
|
|
41
|
-
)
|
|
31
|
+
{typeof onHide === 'function' && <div className="close-btn icon-dim-24" onClick={e => onHide(false)} data-testid="opaque-modal-close">
|
|
32
|
+
<img className="close-img" src={closeIcon} alt="close" />
|
|
33
|
+
</div>}
|
|
34
|
+
</div>, document.getElementById('full-screen-modal'))
|
|
42
35
|
}
|
|
43
|
-
}
|
|
36
|
+
}
|