Skip to content

Commit

Permalink
Merge pull request #928 from akto-api-security/fix/fix_endpoint_name_ui
Browse files Browse the repository at this point in the history
Better inventory UI
  • Loading branch information
avneesh-akto authored Mar 8, 2024
2 parents a5e7a78 + cf8cd57 commit a83fc50
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,33 @@ function GithubCell(props){
}
</HorizontalStack>
</Box>
<HorizontalStack gap={"2"}>
{
headers?.filter((header) => {
return header.itemOrder==4
}).filter((header) => {
return data[header.value]!=undefined && data[header.value]!="";
}).map((header) => {
return data?.[header?.value]
?.map((item) =>
isBadgeClickable ?
<div onClick={() =>badgeClicked()} style={{cursor: "pointer"}} key={item}>
<Badge status={getStatus(item)}>
<Text {...header.dataProps}>
{item}
</Text>
</Badge>
</div>

: <Badge key={item} status={getStatus(item)}>
<Text {...header.dataProps}>
{item}
</Text>
</Badge>

)})
}
</HorizontalStack>
</VerticalStack>
</HorizontalStack>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@
padding-top: 12px !important;
padding-bottom: 12px !important;
}
.Polaris-IndexTable-Checkbox__TableCellContentContainer {
padding-top: 3px !important;
}

.Polaris-IndexTable {
border-radius: unset !important;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,9 @@

.Polaris-VideoThumbnail__Thumbnail{
border-radius: 8px !important;
}

.Polaris-Text--break {
white-space: normal !important;
word-break: break-all !important;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Avatar, Badge, Box, HorizontalStack, Text, Tooltip } from '@shopify/polaris'
import React, { useRef, useState } from 'react'
import func from '@/util/func'
import transform from '../onboarding/transform'
import observeFunc from "./transform"
function GetPrettifyEndpoint({method,url, isNew}){
const ref = useRef(null)
const [copyActive, setCopyActive] = useState(false)
return(
<div style={{display: 'flex', gap: '4px'}} ref={ref} onMouseEnter={() => setCopyActive(true)} onMouseLeave={() => setCopyActive(false)}>
<Box width="54px">
<HorizontalStack align="end">
<span style={{color: transform.getTextColor(method), fontSize: "14px", fontWeight: 500, lineHeight: '20px'}}>{method}</span>
</HorizontalStack>
</Box>
<Box width="30vw">
<div style={{display: "flex", justifyContent: "space-between", gap:"24px"}}>
<div style={{display: "flex"}}>
<Box>
<Text variant="bodyMd" fontWeight="medium" breakWord>{observeFunc.getTruncatedUrl(url)}</Text>
</Box>
{copyActive ?
<div onClick={(e) => {e.stopPropagation();func.copyToClipboard(url, ref, "URL copied");}}>
<Tooltip content="Copy endpoint" dismissOnMouseOut>
<div className="reduce-size">
<Avatar size="extraSmall" source="/public/copy_icon.svg" />
</div>
</Tooltip>
<Box ref={ref} />
</div>
:null}
</div>
<Box>
{isNew ? <Badge size="small">New</Badge> : null}
</Box>
</div>
</Box>
</div>
)
}


export default GetPrettifyEndpoint
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import LayoutWithTabs from "../../../components/layouts/LayoutWithTabs"
import { Box, Button, Modal } from "@shopify/polaris"
import { Avatar, Box, Button, Icon, Modal, Tooltip } from "@shopify/polaris"
import FlyLayout from "../../../components/layouts/FlyLayout";
import GithubCell from "../../../components/tables/cells/GithubCell";
import SampleDataList from "../../../components/shared/SampleDataList";
Expand All @@ -11,6 +11,7 @@ import AktoGptLayout from "../../../components/aktoGpt/AktoGptLayout";
import func from "@/util/func"
import transform from "../transform";
import ApiDependency from "./ApiDependency";
import { copy_icon } from "../../../components/icons";

function ApiDetails(props) {

Expand All @@ -24,6 +25,8 @@ function ApiDetails(props) {
const [loading, setLoading] = useState(false)
const [badgeActive, setBadgeActive] = useState(false)

const ref = useRef(null)

const fetchData = async() => {
if(showDetails){
setLoading(true)
Expand Down Expand Up @@ -128,17 +131,33 @@ function ApiDetails(props) {
/>
</Box>,
}
const components = [

const headingComp = (
<div style={{display: "flex", justifyContent: "space-between"}} key="heading">
<GithubCell
key="heading"
width="30vw"
nameWidth="27vw"
data={apiDetail}
headers={headers}
getStatus={getStatus}
isBadgeClickable={true}
badgeClicked={badgeClicked}
/>,
width="40vw"
data={apiDetail}
headers={headers}
getStatus={getStatus}
isBadgeClickable={true}
badgeClicked={badgeClicked}
/>
<Box paddingBlockStart={"05"}>
<Button plain onClick={() => func.copyToClipboard(apiDetail['endpoint'], ref, "URL copied")}>
<Tooltip content="Copy endpoint" dismissOnMouseOut>
<div className="reduce-size">
<Avatar size="extraSmall" source="/public/copy_icon.svg" />
</div>
</Tooltip>
<Box ref={ref} />
</Button>
</Box>
</div>
)

const components = [
headingComp
,
<LayoutWithTabs
key="tabs"
tabs={[SchemaTab, ValuesTab, DependencyTab]}
Expand All @@ -151,7 +170,7 @@ function ApiDetails(props) {
className={"gpt-button-fixed"}
key="akto-gpt"
>
<Button onClick={displayGPT}>Ask AktoGPT</Button>
<Button onClick={displayGPT} size="slim">Ask AktoGPT</Button>
</div>
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
.gpt-button-fixed {
position: absolute;
z-index: 400;
right: 24px !important;
right: 48px !important;
transition: right 0.3s ease-in-out;
top: 60px;
top: 15px;
}

.control-row .Polaris-IndexTable__TableCell {
Expand All @@ -19,6 +19,7 @@
.condensed-row .Polaris-IndexTable__TableCell {
padding-top: 8px !important;
padding-bottom: 8px !important;
vertical-align: top !important;
}

.icons-style {
Expand All @@ -31,3 +32,8 @@
border-radius: 32px;
box-shadow: 0px 2px 16px 0px rgba(33, 43, 54, 0.08), 0px 0px 0px 1px rgba(6, 44, 82, 0.10);
}

.full-url{
overflow-x: hidden;
word-break: break-all;
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Tooltip, Text, HorizontalStack, Box } from "@shopify/polaris"
import { Tooltip, Text, Box } from "@shopify/polaris"
import func from "@/util/func"
import "../api_inventory.css"
import { useRef, useEffect, useState } from "react"
import transform from "../../transform"

const StyledEndpoint = (data, fontSize, variant) => {
const StyledEndpoint = (data, fontSize, variant, shouldNotTruncate, showWithoutHost) => {
const { method, url } = func.toMethodUrlObject(data)
const arr = url.split("/")
let absoluteUrl = showWithoutHost ? transform.getTruncatedUrl(url) : url
const arr = absoluteUrl.split("/")
let colored = []
arr.forEach((item, index) => {
if (item.startsWith("{param")) {
Expand Down Expand Up @@ -35,28 +37,30 @@ const StyledEndpoint = (data, fontSize, variant) => {

useEffect(() => {
const element = ref.current;
setIsTruncated(element.scrollWidth > element.clientWidth);
if(!shouldNotTruncate){
setIsTruncated(element.scrollWidth > element.clientWidth);
}
}, []);

const endpoint = (
<HorizontalStack gap={"1"} wrap={false}>
<div style={{display: 'flex', gap: "8px"}}>
<div style={{color: getMethodColor(method), fontSize: finalFontSize, fontWeight: 600}}>
{method}
</div>
<div className="styled-endpoint" ref={ref}>
{
arr?.map((item, index) => {
return (
<Box key={index} as={"span"} color={colored.includes(index) ? "text-critical-active" : ""}>
<Text as="span" variant={finalVariant}>
{item + "/"}
</Text>
</Box>
)
})
}
</div>
</HorizontalStack>
{method}
</div>
<div className={shouldNotTruncate ? "full-url" : "styled-endpoint"} ref={ref}>
{
arr?.map((item, index) => {
return (
<Box key={index} as={"span"} color={colored.includes(index) ? "text-critical-active" : ""}>
<Text as="span" variant={finalVariant}>
{item + "/"}
</Text>
</Box>
)
})
}
</div>
</div>
)

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import func from "@/util/func";
import { Badge, Box, HorizontalStack, Icon, Text, Tooltip } from "@shopify/polaris";
import PersistStore from "../../../main/PersistStore";
import tranform from "../onboarding/transform"
import TooltipText from "../../components/shared/TooltipText";
import StyledEndpoint from "./api_collections/component/StyledEndpoint"
import { SearchMinor, InfoMinor, LockMinor, ClockMinor, PasskeyMinor, LinkMinor, DynamicSourceMinor, GlobeMinor, LocationsMinor, PriceLookupMinor } from "@shopify/polaris-icons"
import api from "./api";
import GetPrettifyEndpoint from "./GetPrettifyEndpoint";

const standardHeaders = [
'accept', 'accept-ch', 'accept-ch-lifetime', 'accept-charset', 'accept-encoding', 'accept-language', 'accept-patch', 'accept-post', 'accept-ranges', 'access-control-allow-credentials', 'access-control-allow-headers', 'access-control-allow-methods', 'access-control-allow-origin', 'access-control-expose-headers', 'access-control-max-age', 'access-control-request-headers', 'access-control-request-method', 'age', 'allow', 'alt-svc', 'alt-used', 'authorization',
Expand Down Expand Up @@ -41,7 +41,7 @@ const apiDetailsHeaders = [
value: "parameterisedEndpoint",
itemOrder: 1,
showFilter: true,
component: StyledEndpoint
component: (data) => StyledEndpoint(data, "14px", "headingSm", true, true)
},
{
text: 'Collection name',
Expand All @@ -58,8 +58,14 @@ const apiDetailsHeaders = [
{
text: 'Sensitive Params',
value: 'sensitiveTags',
itemOrder: 2,
showFilter: true
itemOrder: 4,
showFilter: true,
},
{
text: 'hostname',
itemOrder: 3,
value: 'hostName',
icon: GlobeMinor,
},
{
text: 'Last Seen',
Expand Down Expand Up @@ -248,7 +254,7 @@ const transform = {
},
prepareEndpointForTable(x, index) {
const idToNameMap = PersistStore.getState().collectionsMap;
const endpointComp = this.getPrettifyEndpoint(x.method, x.url, false);
const endpointComp = <GetPrettifyEndpoint method={x.method} url={x.url} isNew={false} />
const name = x.param.replaceAll("#", ".").replaceAll(".$", "")

return {
Expand Down Expand Up @@ -414,7 +420,8 @@ const transform = {
getTruncatedUrl(url){
try {
const parsedURL = new URL(url)
return parsedURL.pathname
const pathUrl = parsedURL.pathname.replace(/%7B/g, '{').replace(/%7D/g, '}');
return pathUrl
} catch (error) {
return url
}
Expand All @@ -428,26 +435,6 @@ const transform = {
return "No host"
}
},

getPrettifyEndpoint(method,url, isNew){
return(
<div style={{display: 'flex', gap: '4px'}}>
<Box width="54px">
<HorizontalStack align="end">
<span style={{color: tranform.getTextColor(method), fontSize: "14px", fontWeight: 500}}>{method}</span>
</HorizontalStack>
</Box>
<Box width="200px" maxWidth="200px">
<HorizontalStack align="space-between">
<Box maxWidth={isNew ? "140px" : '180px'}>
<TooltipText text={this.getTruncatedUrl(url)} tooltip={this.getTruncatedUrl(url)} textProps={{fontWeight: "medium"}} />
</Box>
{isNew ? <Badge size="small">New</Badge> : null}
</HorizontalStack>
</Box>
</div>
)
},

getRiskScoreValue(severity){
if(severity >= 100){
Expand Down Expand Up @@ -495,7 +482,7 @@ const transform = {
hostName: (hostNameMap[url.apiCollectionId] !== null ? hostNameMap[url.apiCollectionId] : this.getHostName(url.endpoint)),
access_type: url.access_type,
auth_type: url.auth_type,
endpointComp: this.getPrettifyEndpoint(url.method, url.endpoint, this.isNewEndpoint(url.lastSeenTs)),
endpointComp: <GetPrettifyEndpoint method={url.method} url={url.endpoint} isNew={this.isNewEndpoint(url.lastSeenTs)} />,
sensitiveTagsComp: this.prettifySubtypes(url.sensitiveTags),
riskScoreComp: <Badge status={this.getStatus(score)} size="small">{score.toString()}</Badge>,
riskScore: score,
Expand Down Expand Up @@ -583,4 +570,4 @@ const transform = {

}

export default transform
export default transform
3 changes: 3 additions & 0 deletions apps/dashboard/web/public/copy_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit a83fc50

Please sign in to comment.