Skip to content

Commit f2d1253

Browse files
committed
Merge branch 'kubecon-2024' of https://github.com/devtron-labs/devtron-fe-common-lib into feat/events-ai-widget
2 parents 0f35569 + ca8efcb commit f2d1253

File tree

20 files changed

+253
-49
lines changed

20 files changed

+253
-49
lines changed

package-lock.json

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

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@devtron-labs/devtron-fe-common-lib",
3-
"version": "0.6.0-patch-1-beta-2",
3+
"version": "0.6.2-beta-9",
44
"description": "Supporting common component library",
55
"type": "module",
66
"main": "dist/index.js",
@@ -40,6 +40,7 @@
4040
"@testing-library/react": "^12.1.4",
4141
"@tippyjs/react": "^4.2.0",
4242
"@typeform/embed-react": "2.20.0",
43+
"@types/dompurify": "^3.0.5",
4344
"@types/react": "17.0.39",
4445
"@types/react-dom": "17.0.13",
4546
"@types/react-router-dom": "^5.3.3",

src/Common/Api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,4 +264,4 @@ export const abortPreviousRequests = <T>(
264264
*/
265265
export const getIsRequestAborted = (error) =>
266266
// The 0 code is common for aborted and blocked requests
267-
error && error.code === 0 && error.message.search('abort|aborted')
267+
error && error.code === 0 && error.message.search('abort|aborted') > -1

src/Common/CodeEditor/codeEditor.scss

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -105,18 +105,6 @@
105105
min-height: 300px;
106106
}
107107

108-
.code-editor__information {
109-
font-size: 12px;
110-
font-weight: 400;
111-
line-height: 1.33;
112-
letter-spacing: normal;
113-
color: var(--N900);
114-
height: auto;
115-
padding: 8px 16px;
116-
border-bottom: 1px solid #d6dbdf;
117-
background-color: var(--B100);
118-
}
119-
120108
.code-editor__information-info-icon {
121109
width: 16px;
122110
height: 16px;
@@ -140,16 +128,6 @@
140128
background: url('../../Assets/Icon/ic-compare.svg');
141129
}
142130

143-
.code-editor__error {
144-
background-color: #fde7e7;
145-
color: #862020;
146-
font-size: 12px;
147-
font-weight: 400;
148-
line-height: 1.33;
149-
padding: 8px 16px;
150-
border-bottom: 1px solid #d6dbdf;
151-
}
152-
153131
.monaco-editor-hover {
154132
margin-left: 40px;
155133
}

src/Common/Constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export const URLS = {
6666
GLOBAL_CONFIG_SCOPED_VARIABLES: '/global-config/scoped-variables',
6767
GLOBAL_CONFIG_DEPLOYMENT_CHARTS_LIST: '/global-config/deployment-charts',
6868
NETWORK_STATUS_INTERFACE: '/network-status-interface',
69+
RESOURCE_BROWSER: '/resource-browser',
6970
}
7071

7172
export const ROUTES = {
@@ -113,6 +114,7 @@ export const ROUTES = {
113114
DEPLOYMENT_CHARTS_LIST: 'deployment/template/fetch',
114115
USER_LIST_MIN: 'user/list/min',
115116
CONFIG_DATA: 'config/data',
117+
K8S_RESOURCE_LIST: 'k8s/resource/list',
116118
}
117119

118120
export enum KEY_VALUE {

src/Common/Helper.tsx

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
*/
1616

1717
import React, { SyntheticEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react'
18+
import DOMPurify from 'dompurify'
1819
import { JSONPath, JSONPathOptions } from 'jsonpath-plus'
19-
import { compare as compareJSON, applyPatch } from 'fast-json-patch'
20+
import { compare as compareJSON, applyPatch, unescapePathComponent } from 'fast-json-patch'
2021
import { components } from 'react-select'
2122
import * as Sentry from '@sentry/browser'
2223
import moment from 'moment'
@@ -594,7 +595,7 @@ const buildObjectFromPathTokens = (index: number, tokens: string[], value: any)
594595
const isKeyNumber = !Number.isNaN(numberKey)
595596
return isKeyNumber
596597
? [...Array(numberKey).fill(null), buildObjectFromPathTokens(index + 1, tokens, value)]
597-
: { [key]: buildObjectFromPathTokens(index + 1, tokens, value) }
598+
: { [unescapePathComponent(key)]: buildObjectFromPathTokens(index + 1, tokens, value) }
598599
}
599600

600601
/**
@@ -642,7 +643,8 @@ export const powerSetOfSubstringsFromStart = (strings: string[], regex: RegExp)
642643
return _keys
643644
})
644645

645-
export const convertJSONPointerToJSONPath = (pointer: string) => pointer.replace(/\/([\*0-9]+)\//g, '[$1].').replace(/\//g, '.').replace(/\./, '$.')
646+
export const convertJSONPointerToJSONPath = (pointer: string) =>
647+
unescapePathComponent(pointer.replace(/\/([\*0-9]+)\//g, '[$1].').replace(/\//g, '.').replace(/\./, '$.'))
646648

647649
export const flatMapOfJSONPaths = (
648650
paths: string[],
@@ -953,3 +955,42 @@ export const throttle = <T extends (...args: unknown[]) => unknown>(
953955
}
954956
}
955957
}
958+
959+
// TODO: Might need to expose sandbox and referrer policy
960+
export const getSanitizedIframe = (iframeString: string) =>
961+
DOMPurify.sanitize(iframeString, {
962+
ADD_TAGS: ['iframe'],
963+
ADD_ATTR: ['allow', 'allowfullscreen', 'frameborder', 'scrolling'],
964+
})
965+
966+
/**
967+
* This method adds default attributes to iframe - title, loading ="lazy", width="100%", height="100%"
968+
*/
969+
export const getIframeWithDefaultAttributes = (iframeString: string, defaultName?: string): string => {
970+
const parentDiv = document.createElement('div')
971+
parentDiv.innerHTML = getSanitizedIframe(iframeString)
972+
973+
974+
const iframe = parentDiv.querySelector('iframe')
975+
if (iframe) {
976+
if (!iframe.hasAttribute('title') && !!defaultName) {
977+
iframe.setAttribute('title', defaultName)
978+
}
979+
980+
if (!iframe.hasAttribute('loading')) {
981+
iframe.setAttribute('loading', 'lazy')
982+
}
983+
984+
if (!iframe.hasAttribute('width')) {
985+
iframe.setAttribute('width', '100%')
986+
}
987+
988+
if (!iframe.hasAttribute('height')) {
989+
iframe.setAttribute('height', '100%')
990+
}
991+
992+
return parentDiv.innerHTML
993+
}
994+
995+
return iframeString
996+
}

src/Common/RJSF/Form.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17+
import { forwardRef } from 'react'
1718
import RJSF from '@rjsf/core'
1819
import RJSFValidator from '@rjsf/validator-ajv8'
1920

@@ -27,7 +28,7 @@ import './rjsfForm.scss'
2728
const Form = RJSF
2829
const validator = RJSFValidator
2930

30-
export const RJSFForm = (props: FormProps) => (
31+
export const RJSFForm = forwardRef((props: FormProps, ref: FormProps['ref']) => (
3132
<Form
3233
noHtml5Validate
3334
showErrorList={false}
@@ -42,5 +43,6 @@ export const RJSFForm = (props: FormProps) => (
4243
formContext={props.formData}
4344
widgets={{ ...widgets, ...props.widgets }}
4445
translateString={translateString}
46+
ref={ref}
4547
/>
46-
)
48+
))

src/Pages/ResourceBrowser/ResourceBrowser.Types.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616

1717
import { NodeType, Nodes } from '@Shared/types'
18+
import { RefObject } from 'react'
1819

1920
export interface GVKType {
2021
Group: string
@@ -38,3 +39,57 @@ export interface K8SObjectBaseType {
3839
name: string
3940
isExpanded: boolean
4041
}
42+
43+
interface K8sRequestResourceIdentifierType {
44+
groupVersionKind: GVKType
45+
namespace?: string
46+
name?: string
47+
}
48+
49+
interface ResourceListPayloadK8sRequestType {
50+
resourceIdentifier: K8sRequestResourceIdentifierType
51+
patch?: string
52+
forceDelete?: boolean
53+
}
54+
55+
export interface K8sResourceListPayloadType {
56+
clusterId: number
57+
filter?: string
58+
k8sRequest: ResourceListPayloadK8sRequestType
59+
}
60+
61+
export type K8sResourceDetailDataType = {
62+
[key: string]: string | number | object
63+
}
64+
65+
export interface K8sResourceDetailType {
66+
headers: string[]
67+
data: K8sResourceDetailDataType[]
68+
}
69+
70+
export interface BulkSelectionActionWidgetProps {
71+
count: number
72+
handleOpenBulkDeleteModal: () => void
73+
handleClearBulkSelection: () => void
74+
handleOpenRestartWorkloadModal: () => void
75+
parentRef: RefObject<HTMLDivElement>
76+
showBulkRestartOption: boolean
77+
}
78+
79+
export interface BulkOperation {
80+
name: string
81+
operation: (signal: AbortSignal, data?: unknown) => Promise<void>
82+
}
83+
84+
export type BulkOperationModalProps = {
85+
operationType: 'restart' | 'delete'
86+
clusterName: string
87+
operations: NonNullable<BulkOperation[]>
88+
handleModalClose: () => void
89+
resourceKind: string
90+
handleReloadDataAfterBulkOperation?: () => void
91+
hideResultsDrawer?: boolean
92+
shouldAllowForceOperation?: true
93+
}
94+
95+
export type BulkOperationModalState = BulkOperationModalProps['operationType'] | 'closed'

src/Pages/ResourceBrowser/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@
1616

1717
export * from './ResourceBrowser.Types'
1818
export * from './Helper'
19+
export * from './types'
20+
export * from './service'

src/Pages/ResourceBrowser/service.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { post } from '@Common/Api'
2+
import { ROUTES } from '@Common/Constants'
3+
import { ResponseType } from '@Common/Types'
4+
import { K8sResourceDetailType, K8sResourceListPayloadType } from './ResourceBrowser.Types'
5+
6+
export const getK8sResourceList = (
7+
resourceListPayload: K8sResourceListPayloadType,
8+
signal?: AbortSignal,
9+
): Promise<ResponseType<K8sResourceDetailType>> =>
10+
post(ROUTES.K8S_RESOURCE_LIST, resourceListPayload, {
11+
signal,
12+
})

0 commit comments

Comments
 (0)