mirror of
https://github.com/kubeshark/kubeshark.git
synced 2025-07-16 01:16:47 +00:00
TRA-4259 Service Map UI improvements (#753)
Co-authored-by: Amit Fainholts <amit@up9.com> Co-authored-by: gadotroee <55343099+gadotroee@users.noreply.github.com> Co-authored-by: Igor Gov <iggvrv@gmail.com>
This commit is contained in:
parent
b59c48528d
commit
a4066da5d7
@ -22,6 +22,8 @@ import OasModal from "../../OasModal/OasModal";
|
||||
import {useCommonStyles} from "../../../helpers/commonStyle"
|
||||
import {TLSWarning} from "../../TLSWarning/TLSWarning";
|
||||
import serviceMapModalOpenAtom from "../../../recoil/serviceMapModalOpen";
|
||||
import serviceMap from "../../assets/serviceMap.svg";
|
||||
import services from "../../assets/services.svg";
|
||||
|
||||
const useLayoutStyles = makeStyles(() => ({
|
||||
details: {
|
||||
@ -277,17 +279,21 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus}) => {
|
||||
</div>
|
||||
<div style={{ display: 'flex' }}>
|
||||
{window["isOasEnabled"] && <Button
|
||||
startIcon={<img className="custom" src={services} alt="services"></img>}
|
||||
size="large"
|
||||
type="submit"
|
||||
variant="contained"
|
||||
className={commonClasses.button}
|
||||
className={commonClasses.outlinedButton + " " + commonClasses.imagedButton}
|
||||
style={{ marginRight: 25 }}
|
||||
onClick={handleOpenModal}
|
||||
>
|
||||
Show OAS
|
||||
</Button>}
|
||||
{window["isServiceMapEnabled"] && <Button
|
||||
startIcon={<img src={serviceMap} className="custom" alt="service-map" style={{marginRight:"8%"}}></img>}
|
||||
size="large"
|
||||
variant="contained"
|
||||
className={commonClasses.button}
|
||||
className={commonClasses.outlinedButton + " " + commonClasses.imagedButton}
|
||||
onClick={openServiceMapModalDebounce}
|
||||
>
|
||||
Service Map
|
||||
|
32
ui/src/components/ServiceMapModal/ServiceMapModal.sass
Normal file
32
ui/src/components/ServiceMapModal/ServiceMapModal.sass
Normal file
@ -0,0 +1,32 @@
|
||||
@import "../../variables.module"
|
||||
|
||||
|
||||
.legend-scale ul
|
||||
margin-top: -29px
|
||||
margin-left: -27px
|
||||
padding: 0
|
||||
float: left
|
||||
list-style: none
|
||||
|
||||
li
|
||||
display: block
|
||||
float: left
|
||||
width: 50px
|
||||
margin-bottom: 6px
|
||||
text-align: center
|
||||
font-size: 80%
|
||||
list-style: none
|
||||
|
||||
ul.legend-labels li span
|
||||
display: block
|
||||
float: left
|
||||
height: 15px
|
||||
width: 50px
|
||||
|
||||
.legend-source
|
||||
font-size: 70%
|
||||
color: #999
|
||||
clear: both
|
||||
|
||||
a
|
||||
color: #777
|
@ -3,11 +3,15 @@ import { Box, Fade, Modal, Backdrop, Button } from "@material-ui/core";
|
||||
import { toast } from "react-toastify";
|
||||
import Api from "../../helpers/api";
|
||||
import spinnerStyle from '../style/Spinner.module.sass';
|
||||
import './ServiceMapModal.sass';
|
||||
import spinnerImg from '../assets/spinner.svg';
|
||||
import Graph from "react-graph-vis";
|
||||
import debounce from 'lodash/debounce';
|
||||
import ServiceMapOptions from './ServiceMapOptions'
|
||||
import { useCommonStyles } from "../../helpers/commonStyle";
|
||||
import refresh from "../assets/refresh.svg";
|
||||
import reset from "../assets/reset.svg";
|
||||
import close from "../assets/close.svg"
|
||||
|
||||
interface GraphData {
|
||||
nodes: Node[];
|
||||
@ -29,6 +33,7 @@ interface Edge {
|
||||
label: string;
|
||||
title?: string;
|
||||
color?: object;
|
||||
font?: object;
|
||||
}
|
||||
|
||||
interface ServiceMapNode {
|
||||
@ -104,7 +109,7 @@ export const ServiceMapModal: React.FC<ServiceMapModalProps> = ({ isOpen, onOpen
|
||||
const newGraphData: GraphData = { nodes: [], edges: [] }
|
||||
|
||||
if (serviceMapData.nodes) {
|
||||
newGraphData.nodes = serviceMapData.nodes.map(node => {
|
||||
newGraphData.nodes = serviceMapData.nodes.map<Node>(node => {
|
||||
return {
|
||||
id: node.id,
|
||||
value: node.count,
|
||||
@ -115,7 +120,7 @@ export const ServiceMapModal: React.FC<ServiceMapModalProps> = ({ isOpen, onOpen
|
||||
}
|
||||
|
||||
if (serviceMapData.edges) {
|
||||
newGraphData.edges = serviceMapData.edges.map(edge => {
|
||||
newGraphData.edges = serviceMapData.edges.map<Edge>(edge => {
|
||||
return {
|
||||
from: edge.source.id,
|
||||
to: edge.destination.id,
|
||||
@ -125,6 +130,10 @@ export const ServiceMapModal: React.FC<ServiceMapModalProps> = ({ isOpen, onOpen
|
||||
color: edge.protocol.backgroundColor,
|
||||
highlight: edge.protocol.backgroundColor
|
||||
},
|
||||
font: {
|
||||
color: edge.protocol.backgroundColor,
|
||||
strokeColor: edge.protocol.backgroundColor
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -141,7 +150,8 @@ export const ServiceMapModal: React.FC<ServiceMapModalProps> = ({ isOpen, onOpen
|
||||
}, [isOpen])
|
||||
|
||||
useEffect(() => {
|
||||
getServiceMapData()
|
||||
getServiceMapData();
|
||||
return () => setGraphData({ nodes: [], edges: [] })
|
||||
}, [getServiceMapData])
|
||||
|
||||
const resetServiceMap = debounce(async () => {
|
||||
@ -180,33 +190,44 @@ export const ServiceMapModal: React.FC<ServiceMapModalProps> = ({ isOpen, onOpen
|
||||
<img alt="spinner" src={spinnerImg} style={{ height: 50 }} />
|
||||
</div>}
|
||||
{!isLoading && <div style={{ height: "100%", width: "100%" }}>
|
||||
<div style={{ display: "flex", justifyContent: "space-between" }}>
|
||||
<div>
|
||||
<Button
|
||||
startIcon={<img src={reset} className="custom" alt="reset" style={{ marginRight:"8%"}}></img>}
|
||||
size="large"
|
||||
variant="contained"
|
||||
className={commonClasses.button}
|
||||
style={{ marginRight: 25 }}
|
||||
onClick={() => onClose()}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
className={commonClasses.button}
|
||||
style={{ marginRight: 25 }}
|
||||
className={commonClasses.outlinedButton + " " + commonClasses.imagedButton}
|
||||
style={{ marginRight: 25, paddingTop: "3px", paddingBottom: "1px"}}
|
||||
onClick={resetServiceMap}
|
||||
>
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
<Button
|
||||
startIcon={<img src={refresh} className="custom" alt="refresh" style={{ marginRight:"8%"}}></img>}
|
||||
size="medium"
|
||||
variant="contained"
|
||||
className={commonClasses.button}
|
||||
className={commonClasses.outlinedButton + " " + commonClasses.imagedButton}
|
||||
onClick={refreshServiceMap}
|
||||
>
|
||||
Refresh
|
||||
</Button>
|
||||
</div>
|
||||
<img src={close} alt="close" onClick={() => onClose()} style={{cursor:"pointer"}}></img>
|
||||
</div>
|
||||
<Graph
|
||||
graph={graphData}
|
||||
options={ServiceMapOptions}
|
||||
/>
|
||||
<div className='legend-scale'>
|
||||
<ul className='legend-labels'>
|
||||
<li><span style={{ background: '#205cf5' }}></span>HTTP</li>
|
||||
<li><span style={{ background: '#244c5a' }}></span>HTTP/2</li>
|
||||
<li><span style={{ background: '#244c5a' }}></span>gRPC</li>
|
||||
<li><span style={{ background: '#ff6600' }}></span>AMQP</li>
|
||||
<li><span style={{ background: '#000000' }}></span>KAFKA</li>
|
||||
<li><span style={{ background: '#a41e11' }}></span>REDIS</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>}
|
||||
</Box>
|
||||
</Fade>
|
||||
|
@ -1,3 +1,142 @@
|
||||
|
||||
const minNodeScaling = 10
|
||||
const maxNodeScaling = 30
|
||||
|
||||
const minEdgeScaling = 1
|
||||
const maxEdgeScaling = maxNodeScaling / 2
|
||||
|
||||
const minLabelScaling = 11
|
||||
const maxLabelScaling = 16
|
||||
const selectedNodeColor = "#0C0B1A"
|
||||
const selectedNodeBorderColor = "#205CF5"
|
||||
const selectedNodeLabelColor = "#205CF5"
|
||||
const selectedEdgeLabelColor = "#205CF5"
|
||||
|
||||
const customScaling = (min, max, total, value) => {
|
||||
if (max === min) {
|
||||
return 0.5;
|
||||
}
|
||||
else {
|
||||
const scale = 1 / (max - min);
|
||||
return Math.max(0, (value - min) * scale);
|
||||
}
|
||||
}
|
||||
|
||||
const nodeSelected = (values, id, selected, hovering) => {
|
||||
values.color = selectedNodeColor;
|
||||
values.borderColor = selectedNodeBorderColor;
|
||||
values.borderWidth = 4;
|
||||
}
|
||||
|
||||
const nodeLabelSelected = (values, id, selected, hovering) => {
|
||||
values.size = values.size + 1;
|
||||
values.color = selectedNodeLabelColor;
|
||||
values.strokeColor = selectedNodeLabelColor;
|
||||
values.strokeWidth = 0.2
|
||||
}
|
||||
|
||||
const edgeSelected = (values, id, selected, hovering) => {
|
||||
values.opacity = 0.4;
|
||||
values.width = values.width + 1;
|
||||
}
|
||||
|
||||
const edgeLabelSelected = (values, id, selected, hovering) => {
|
||||
values.size = values.size + 1;
|
||||
values.color = selectedEdgeLabelColor;
|
||||
values.strokeColor = selectedEdgeLabelColor;
|
||||
values.strokeWidth = 0.2
|
||||
}
|
||||
|
||||
const nodeOptions = {
|
||||
shape: 'dot',
|
||||
chosen: {
|
||||
node: nodeSelected,
|
||||
label: nodeLabelSelected,
|
||||
},
|
||||
color: {
|
||||
background: '#494677',
|
||||
border: selectedNodeColor,
|
||||
},
|
||||
font: {
|
||||
color: selectedNodeColor,
|
||||
size: 11, // px
|
||||
face: 'Roboto',
|
||||
background: '#FFFFFFBF',
|
||||
strokeWidth: 0.2, // px
|
||||
strokeColor: selectedNodeColor,
|
||||
align: 'center',
|
||||
multi: false,
|
||||
},
|
||||
// defines the node min and max sizes when zoom in/out, based on the node value
|
||||
scaling: {
|
||||
min: minNodeScaling,
|
||||
max: maxNodeScaling,
|
||||
// defines the label scaling size in px
|
||||
label: {
|
||||
enabled: true,
|
||||
min: minLabelScaling,
|
||||
max: maxLabelScaling,
|
||||
maxVisible: maxLabelScaling,
|
||||
drawThreshold: 5,
|
||||
},
|
||||
customScalingFunction: customScaling,
|
||||
},
|
||||
borderWidth: 2,
|
||||
labelHighlightBold: true,
|
||||
opacity: 1,
|
||||
shadow: true,
|
||||
}
|
||||
|
||||
const edgeOptions = {
|
||||
chosen: {
|
||||
edge: edgeSelected,
|
||||
label: edgeLabelSelected,
|
||||
},
|
||||
dashes: false,
|
||||
arrowStrikethrough: false,
|
||||
arrows: {
|
||||
to: {
|
||||
enabled: true,
|
||||
},
|
||||
middle: {
|
||||
enabled: false,
|
||||
},
|
||||
from: {
|
||||
enabled: false,
|
||||
}
|
||||
},
|
||||
smooth: {
|
||||
enabled: true,
|
||||
type: 'dynamic',
|
||||
roundness: 1.0
|
||||
},
|
||||
font: {
|
||||
color: '#000000',
|
||||
size: 11, // px
|
||||
face: 'Roboto',
|
||||
background: '#FFFFFFCC',
|
||||
strokeWidth: 0.2, // px
|
||||
strokeColor: '#000000',
|
||||
align: 'horizontal',
|
||||
multi: false,
|
||||
},
|
||||
scaling: {
|
||||
min: minEdgeScaling,
|
||||
max: maxEdgeScaling,
|
||||
label: {
|
||||
enabled: true,
|
||||
min: minLabelScaling,
|
||||
max: maxLabelScaling,
|
||||
maxVisible: maxLabelScaling,
|
||||
drawThreshold: 5
|
||||
},
|
||||
customScalingFunction: customScaling,
|
||||
},
|
||||
labelHighlightBold: true,
|
||||
selectionWidth: 1,
|
||||
shadow: true,
|
||||
}
|
||||
|
||||
const ServiceMapOptions = {
|
||||
physics: {
|
||||
enabled: true,
|
||||
@ -5,10 +144,10 @@ const ServiceMapOptions = {
|
||||
barnesHut: {
|
||||
theta: 0.5,
|
||||
gravitationalConstant: -2000,
|
||||
centralGravity: 0.3,
|
||||
centralGravity: 0.4,
|
||||
springLength: 180,
|
||||
springConstant: 0.04,
|
||||
damping: 0.09,
|
||||
damping: 0.2,
|
||||
avoidOverlap: 1
|
||||
},
|
||||
},
|
||||
@ -16,68 +155,20 @@ const ServiceMapOptions = {
|
||||
hierarchical: false,
|
||||
randomSeed: 1 // always on node 1
|
||||
},
|
||||
nodes: {
|
||||
shape: 'dot',
|
||||
chosen: true,
|
||||
color: {
|
||||
background: '#27AE60',
|
||||
border: '#000000',
|
||||
highlight: {
|
||||
background: '#27AE60',
|
||||
border: '#000000',
|
||||
},
|
||||
},
|
||||
font: {
|
||||
color: '#343434',
|
||||
size: 14, // px
|
||||
face: 'arial',
|
||||
background: 'none',
|
||||
strokeWidth: 0, // px
|
||||
strokeColor: '#ffffff',
|
||||
align: 'center',
|
||||
multi: false,
|
||||
},
|
||||
borderWidth: 1.5,
|
||||
borderWidthSelected: 2.5,
|
||||
labelHighlightBold: true,
|
||||
opacity: 1,
|
||||
shadow: true,
|
||||
},
|
||||
edges: {
|
||||
chosen: true,
|
||||
dashes: false,
|
||||
arrowStrikethrough: false,
|
||||
arrows: {
|
||||
to: {
|
||||
enabled: true,
|
||||
},
|
||||
middle: {
|
||||
enabled: false,
|
||||
},
|
||||
from: {
|
||||
enabled: false,
|
||||
}
|
||||
},
|
||||
smooth: {
|
||||
enabled: true,
|
||||
type: 'dynamic',
|
||||
roundness: 1.0
|
||||
},
|
||||
font: {
|
||||
color: '#343434',
|
||||
size: 12, // px
|
||||
face: 'arial',
|
||||
background: 'none',
|
||||
strokeWidth: 2, // px
|
||||
strokeColor: '#ffffff',
|
||||
align: 'horizontal',
|
||||
multi: false,
|
||||
},
|
||||
labelHighlightBold: true,
|
||||
selectionWidth: 1,
|
||||
shadow: true,
|
||||
},
|
||||
nodes: nodeOptions,
|
||||
edges: edgeOptions,
|
||||
autoResize: true,
|
||||
interaction: {
|
||||
selectable: true,
|
||||
selectConnectedEdges: true,
|
||||
multiselect: true,
|
||||
dragNodes: true,
|
||||
dragView: true,
|
||||
hover: true,
|
||||
hoverConnectedEdges: true,
|
||||
zoomView: true,
|
||||
zoomSpeed: 1,
|
||||
},
|
||||
};
|
||||
|
||||
export default ServiceMapOptions
|
4
ui/src/components/assets/close.svg
Normal file
4
ui/src/components/assets/close.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18.591 9.99997C18.591 14.7446 14.7447 18.5909 10.0001 18.5909C5.25546 18.5909 1.40918 14.7446 1.40918 9.99997C1.40918 5.25534 5.25546 1.40906 10.0001 1.40906C14.7447 1.40906 18.591 5.25534 18.591 9.99997Z" fill="#E9EBF8" stroke="#BCCEFD"/>
|
||||
<path d="M13.1604 8.23038L11.95 7.01994L10.1392 8.83078L8.32832 7.01994L7.11789 8.23038L8.92872 10.0412L7.12046 11.8495L8.33089 13.0599L10.1392 11.2517L11.9474 13.0599L13.1579 11.8495L11.3496 10.0412L13.1604 8.23038Z" fill="#205CF5"/>
|
||||
</svg>
|
After Width: | Height: | Size: 588 B |
3
ui/src/components/assets/refresh.svg
Normal file
3
ui/src/components/assets/refresh.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.8337 11.9167H7.69308L7.69416 11.907C7.83561 11.2143 8.11247 10.5564 8.50883 9.97105C9.09865 9.10202 9.92598 8.42097 10.8922 8.00913C11.2193 7.87046 11.5606 7.7643 11.9083 7.69388C12.6297 7.54762 13.3731 7.54762 14.0945 7.69388C15.1312 7.90631 16.0825 8.41908 16.8299 9.1683L18.3639 7.63863C17.6725 6.94707 16.8546 6.39501 15.9546 6.01255C15.4956 5.81823 15.0184 5.67016 14.53 5.57055C13.5223 5.36581 12.4838 5.36581 11.4761 5.57055C10.9873 5.67057 10.5098 5.819 10.0504 6.01363C8.69682 6.58791 7.53808 7.54123 6.71374 8.7588C6.15895 9.5798 5.77099 10.5019 5.57191 11.4725C5.54158 11.6188 5.52533 11.7683 5.50366 11.9167H2.16699L6.50033 16.25L10.8337 11.9167ZM15.167 14.0834H18.3076L18.3065 14.092C18.0234 15.4806 17.205 16.7019 16.0282 17.4915C15.443 17.8882 14.7851 18.1651 14.0923 18.3062C13.3713 18.4525 12.6283 18.4525 11.9072 18.3062C11.2146 18.1648 10.5567 17.8879 9.97133 17.4915C9.68383 17.2971 9.41541 17.0758 9.16966 16.8307L7.63783 18.3625C8.32954 19.0539 9.14791 19.6056 10.0482 19.9875C10.5076 20.1825 10.9875 20.331 11.4728 20.4295C12.4801 20.6344 13.5184 20.6344 14.5257 20.4295C16.4676 20.0265 18.1757 18.8819 19.2869 17.2391C19.8412 16.4187 20.2288 15.4974 20.4277 14.5275C20.4569 14.3813 20.4742 14.2318 20.4959 14.0834H23.8337L19.5003 9.75005L15.167 14.0834Z" fill="#205CF5"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
4
ui/src/components/assets/reset.svg
Normal file
4
ui/src/components/assets/reset.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11 14C12.114 14 13 13.1127 13 12C13 10.8873 12.114 10 11 10C9.886 10 9 10.8873 9 12C9 13.1127 9.886 14 11 14Z" fill="#205CF5"/>
|
||||
<path d="M19.0823 10.2539C18.8662 9.1982 18.4442 8.19548 17.8402 7.30312C17.2467 6.42521 16.4906 5.66909 15.6127 5.07562C14.7202 4.47184 13.7175 4.04978 12.6619 3.83354C12.1074 3.72109 11.5429 3.6658 10.9771 3.66854V1.83337L7.33333 4.58337L10.9771 7.33337V5.50187C11.4208 5.50004 11.8644 5.54221 12.2925 5.63021C13.1129 5.79833 13.8923 6.12632 14.586 6.59546C15.2702 7.05676 15.859 7.64561 16.3203 8.32979C17.0366 9.38875 17.4185 10.6383 17.4167 11.9167C17.4165 12.7746 17.2451 13.6238 16.9125 14.4146C16.7507 14.7955 16.5531 15.1602 16.3222 15.5036C16.0904 15.845 15.827 16.1639 15.5357 16.456C14.6483 17.3417 13.5219 17.9492 12.2943 18.2041C11.4407 18.3765 10.5612 18.3765 9.7075 18.2041C8.88668 18.0358 8.10704 17.7075 7.41308 17.238C6.72969 16.7771 6.14148 16.1888 5.68058 15.5055C4.96518 14.4454 4.58306 13.1956 4.58333 11.9167H2.75C2.75098 13.5609 3.24215 15.1675 4.16075 16.5312C4.75461 17.4077 5.50996 18.163 6.38642 18.7569C7.74824 19.6786 9.3556 20.1697 11 20.1667C11.5585 20.1667 12.1156 20.1105 12.6628 19.999C13.7177 19.7811 14.7197 19.3592 15.6127 18.7569C16.0511 18.4615 16.4597 18.1241 16.8328 17.7495C17.2063 17.3749 17.5439 16.9661 17.8411 16.5285C18.762 15.167 19.2528 13.5604 19.25 11.9167C19.25 11.3582 19.1938 10.8011 19.0823 10.2539Z" fill="#205CF5"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
15
ui/src/components/assets/serviceMap.svg
Normal file
15
ui/src/components/assets/serviceMap.svg
Normal file
@ -0,0 +1,15 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.2998 5.40002L8.9998 9.00002" stroke="#A0B2FF" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M15.2998 12.6L8.99976 8.99988" stroke="#A0B2FF" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M2.7002 5.40002L2.70024 12.5001" stroke="#A0B2FF" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9 8.99988V16.2" stroke="#A0B2FF" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M2.7 5.40005L9 1.80005" stroke="#A0B2FF" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M15.2998 5.40005L8.9998 1.80005" stroke="#A0B2FF" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M4.4999 5.39995C4.4999 6.39406 3.69402 7.19995 2.6999 7.19995C1.70579 7.19995 0.899902 6.39406 0.899902 5.39995C0.899902 4.40584 1.70579 3.59995 2.6999 3.59995C3.69402 3.59995 4.4999 4.40584 4.4999 5.39995Z" fill="#205CF5"/>
|
||||
<path d="M4.4999 12.6C4.4999 13.5941 3.69402 14.4 2.6999 14.4C1.70579 14.4 0.899902 13.5941 0.899902 12.6C0.899902 11.6059 1.70579 10.8 2.6999 10.8C3.69402 10.8 4.4999 11.6059 4.4999 12.6Z" fill="#205CF5"/>
|
||||
<path d="M17.1 5.39995C17.1 6.39406 16.2941 7.19995 15.3 7.19995C14.3059 7.19995 13.5 6.39406 13.5 5.39995C13.5 4.40584 14.3059 3.59995 15.3 3.59995C16.2941 3.59995 17.1 4.40584 17.1 5.39995Z" fill="#205CF5"/>
|
||||
<path d="M17.1 12.6C17.1 13.5941 16.2941 14.4 15.3 14.4C14.3059 14.4 13.5 13.5941 13.5 12.6C13.5 11.6059 14.3059 10.8 15.3 10.8C16.2941 10.8 17.1 11.6059 17.1 12.6Z" fill="#205CF5"/>
|
||||
<path d="M10.8002 1.79998C10.8002 2.79409 9.99431 3.59998 9.0002 3.59998C8.00608 3.59998 7.2002 2.79409 7.2002 1.79998C7.2002 0.805863 8.00608 -2.45571e-05 9.0002 -2.45571e-05C9.99431 -2.45571e-05 10.8002 0.805863 10.8002 1.79998Z" fill="#205CF5"/>
|
||||
<path d="M10.8002 9.00005C10.8002 9.99416 9.99431 10.8 9.0002 10.8C8.00608 10.8 7.2002 9.99416 7.2002 9.00005C7.2002 8.00594 8.00608 7.20005 9.0002 7.20005C9.99431 7.20005 10.8002 8.00594 10.8002 9.00005Z" fill="#205CF5"/>
|
||||
<path d="M10.8002 16.2C10.8002 17.1941 9.99431 18 9.0002 18C8.00608 18 7.2002 17.1941 7.2002 16.2C7.2002 15.2059 8.00608 14.4 9.0002 14.4C9.99431 14.4 10.8002 15.2059 10.8002 16.2Z" fill="#205CF5"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
10
ui/src/components/assets/services.svg
Normal file
10
ui/src/components/assets/services.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="5.5" y="6.5" width="20" height="17" rx="1.5" stroke="#A0B2FF"/>
|
||||
<path d="M18.5 6.5H24C24.8284 6.5 25.5 7.17157 25.5 8V22C25.5 22.8284 24.8284 23.5 24 23.5H18.5V6.5Z" fill="#BCCEFD" stroke="#A0B2FF"/>
|
||||
<rect x="19" y="9" width="5" height="2" rx="1" fill="white"/>
|
||||
<rect x="8" y="9" width="4" height="2" rx="1" fill="#205CF5"/>
|
||||
<rect x="8" y="14" width="7" height="2" rx="1" fill="#205CF5"/>
|
||||
<rect width="3" height="2" rx="1" transform="matrix(-1 0 0 1 22 14)" fill="white"/>
|
||||
<path d="M24 20C24 19.4477 23.5523 19 23 19H19V21H23C23.5523 21 24 20.5523 24 20Z" fill="white"/>
|
||||
<rect x="8" y="19" width="7" height="2" rx="1" fill="#205CF5"/>
|
||||
</svg>
|
After Width: | Height: | Size: 747 B |
@ -9,7 +9,7 @@ export const useCommonStyles = makeStyles(() => ({
|
||||
fontSize: 12,
|
||||
padding: "8px 12px",
|
||||
borderRadius: "6px ! important",
|
||||
|
||||
|
||||
"&:hover": {
|
||||
backgroundColor: "#205cf5",
|
||||
},
|
||||
@ -27,6 +27,11 @@ export const useCommonStyles = makeStyles(() => ({
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
},
|
||||
|
||||
imagedButton: {
|
||||
padding: "0px 14px"
|
||||
},
|
||||
|
||||
textField: {
|
||||
outline: 0,
|
||||
background: "white",
|
||||
|
Loading…
Reference in New Issue
Block a user