Skip to content

Commit 8efbd07

Browse files
committed
Merge branch 'kubecon-2024' of github.com:devtron-labs/devtron-fe-common-lib into feat/kubecon-lock-manifest
2 parents 72a9d1f + f5edc56 commit 8efbd07

File tree

8 files changed

+131
-11
lines changed

8 files changed

+131
-11
lines changed

package-lock.json

Lines changed: 18 additions & 10 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.2-beta-7",
3+
"version": "0.6.2-beta-8",
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/Constants.ts

Lines changed: 1 addition & 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 = {

src/Common/Helper.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
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'
1920
import { compare as compareJSON, applyPatch, unescapePathComponent } from 'fast-json-patch'
2021
import { components } from 'react-select'
@@ -954,3 +955,42 @@ export const throttle = <T extends (...args: unknown[]) => unknown>(
954955
}
955956
}
956957
}
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/Pages/ResourceBrowser/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@
1616

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

src/Pages/ResourceBrowser/types.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export enum ClusterFiltersType {
2+
ALL_CLUSTERS = 'all',
3+
HEALTHY = 'healthy',
4+
UNHEALTHY = 'unhealthy',
5+
}
6+
7+
export enum ClusterStatusType {
8+
HEALTHY = 'healthy',
9+
UNHEALTHY = 'unhealthy',
10+
CONNECTION_FAILED = 'connection failed',
11+
}

src/Shared/types.ts

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

17+
import { Dayjs } from 'dayjs'
1718
import {
1819
OptionType,
1920
CommonNodeAttr,
@@ -118,6 +119,7 @@ export enum Nodes {
118119
Event = 'Event',
119120
Namespace = 'Namespace',
120121
Overview = 'Overview',
122+
MonitoringDashboard = 'MonitoringDashboard',
121123
}
122124

123125
// FIXME: This should be `typeof Nodes[keyof typeof Nodes]` instead since the key and values are not the same. Same to be removed from duplications in dashboard
@@ -680,6 +682,7 @@ export enum ConfigurationType {
680682
export interface BaseURLParams {
681683
appId: string
682684
envId: string
685+
clusterId: string
683686
}
684687

685688
export interface ConfigKeysWithLockType {
@@ -738,3 +741,31 @@ export interface CustomRoleAndMeta {
738741
possibleRolesMetaForCluster: MetaPossibleRoles
739742
possibleRolesMetaForJob: MetaPossibleRoles
740743
}
744+
745+
interface CommonTabArgsType {
746+
name: string
747+
kind?: string
748+
url: string
749+
isSelected: boolean
750+
title?: string
751+
isDeleted?: boolean
752+
position: number
753+
iconPath?: string
754+
dynamicTitle?: string
755+
showNameOnSelect?: boolean
756+
/**
757+
* @default false
758+
*/
759+
hideName?: boolean
760+
isAlive?: boolean
761+
lastSyncMoment?: Dayjs
762+
componentKey?: string
763+
}
764+
765+
export interface InitTabType extends CommonTabArgsType {
766+
idPrefix: string
767+
}
768+
769+
export interface DynamicTabType extends CommonTabArgsType {
770+
id: string
771+
}

src/Shared/validations.tsx

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

17+
import { getSanitizedIframe } from '@Common/Helper'
1718
import { URLProtocolType } from './types'
1819

1920
export interface ValidationResponseType {
@@ -342,3 +343,29 @@ export const validateJSON = (json: string): ValidationResponseType => {
342343
}
343344
}
344345
}
346+
347+
export const validateIframe = (input: string): ValidationResponseType => {
348+
const sanitizedInput = getSanitizedIframe(input)
349+
const parentDiv = document.createElement('div')
350+
parentDiv.innerHTML = sanitizedInput
351+
352+
const iframe = parentDiv.querySelector('iframe')
353+
354+
// TODO: Can also check for accessability and security tags like sandbox, title, lazy, etc
355+
if (!iframe || parentDiv.children.length !== 1) {
356+
return { isValid: false, message: 'Input must contain a single iframe tag.' }
357+
}
358+
359+
const src = iframe.getAttribute('src')
360+
if (!src) {
361+
return { isValid: false, message: 'Iframe must have a valid src attribute.' }
362+
}
363+
364+
const urlValidationResponse = validateURL(src)
365+
366+
if (!urlValidationResponse.isValid) {
367+
return urlValidationResponse
368+
}
369+
370+
return { isValid: true }
371+
}

0 commit comments

Comments
 (0)