-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' of https://github.com/Vulcanun/BloodHound into …
…foss_vnext_prebuilt � Conflicts: � package-lock.json � src/components/SearchContainer/Tabs/PrebuiltQueries.json
- Loading branch information
Showing
8 changed files
with
937 additions
and
170 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,227 @@ | ||
import React, { useEffect, useState, useContext } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { | ||
Panel, | ||
Button, | ||
FormControl, | ||
ControlLabel, | ||
FormGroup, | ||
Form, | ||
Col, | ||
Checkbox, | ||
Row | ||
} from 'react-bootstrap'; | ||
import { Typeahead } from 'react-bootstrap-typeahead'; | ||
import styles from './QueryCustomCreate.module.css'; | ||
import Draggable from 'react-draggable'; | ||
import clsx from 'clsx'; | ||
import { AppContext } from '../../AppContext'; | ||
import PoseContainer from '../PoseContainer'; | ||
import { useDragControls } from 'framer-motion'; | ||
|
||
import { remote } from 'electron'; | ||
const { app } = remote; | ||
import path from 'path'; | ||
import fs from 'fs'; | ||
import { select } from 'async'; | ||
|
||
const QueryCustomCreate = () => { | ||
const [nodeCollapse, setNodeCollapse] = useState(appStore.performance.edge); | ||
const [open, setOpen] = useState(false); | ||
const [query, setQuery] = useState(''); | ||
const dragControl = useDragControls(); | ||
const [categories, setCategories] = useState([]); | ||
const [singleSelections, setSingleSelections] = useState([]); | ||
const [queryName, setQueryName] = useState(''); | ||
const [selectedCategory, setSelectedCategory] = useState(''); | ||
|
||
const context = useContext(AppContext); | ||
|
||
const handleOpen = () => { | ||
setOpen(true); | ||
}; | ||
|
||
const handleClose = () => { | ||
setOpen(false); | ||
}; | ||
|
||
const changeNodeCollapse = (e) => { | ||
let val = parseInt(e.target.value); | ||
setNodeCollapse(val); | ||
appStore.performance.edge = val; | ||
conf.set('performance', appStore.performance); | ||
}; | ||
|
||
const edgeLabelChange = (e) => { | ||
let val = parseInt(e.target.value); | ||
context.setEdgeLabels(val); | ||
}; | ||
|
||
const nodeLabelChange = (e) => { | ||
let val = parseInt(e.target.value); | ||
context.setNodeLabels(val); | ||
}; | ||
|
||
const onKeyDown = (e) => { | ||
let key = e.keyCode ? e.keyCode : e.which; | ||
|
||
if (key === 13) { | ||
emitter.emit('query', query); | ||
} | ||
}; | ||
|
||
const runQuery = () => { | ||
emitter.emit('query', query); | ||
} | ||
|
||
const saveQuery = () => { | ||
|
||
let filePath = path.join( | ||
app.getPath('userData'), | ||
'/customqueries.json' | ||
); | ||
|
||
fs.readFile(filePath, 'utf8', (err, data) => { | ||
let j = JSON.parse(data); | ||
j.queries.push({ "name": queryName, "category": selectedCategory, "queryList": [{ "final": true, "query": query, "allowColapse": true }] }) | ||
fs.writeFile(filePath, JSON.stringify(j, null, "\t"), function (err) { emitter.emit('updateCustomQueries'); }) | ||
}); | ||
|
||
setSingleSelections([]); | ||
setSelectedCategory(''); | ||
setQueryName(''); | ||
setQuery(''); | ||
handleClose(); | ||
}; | ||
|
||
const onChange = (e) => { | ||
setQuery(e.target.value); | ||
}; | ||
|
||
const registerCategories = (e) => { | ||
let tempCategories = categories; | ||
for (var queryCategory in e) { | ||
if (['last', 'chunk', 'allEdgesSameType'].includes(queryCategory) || categories.includes(queryCategory)) { | ||
continue; | ||
} | ||
tempCategories.push(queryCategory); | ||
} | ||
setCategories(tempCategories); | ||
} | ||
|
||
useEffect(() => { | ||
emitter.on('openQueryCreate', handleOpen); | ||
emitter.on('registerQueryCategories', registerCategories); | ||
return () => { | ||
emitter.removeListener('openQueryCreate', handleOpen); | ||
emitter.removeListener('registerQueryCategories', registerCategories); | ||
}; | ||
}, []); | ||
|
||
return ( | ||
<PoseContainer | ||
visible={open} | ||
className={clsx( | ||
styles.container, | ||
context.darkMode ? styles.dark : null | ||
)} | ||
dragHandle={dragControl} | ||
> | ||
<Panel | ||
style={{ width: "800px" }} | ||
> | ||
<Panel.Heading | ||
onMouseDown={(e) => { | ||
dragControl.start(e); | ||
}} | ||
> | ||
Create Custom Query | ||
<Button | ||
onClick={handleClose} | ||
className='close' | ||
aria-label='close' | ||
> | ||
<span aria-hidden='true'>×</span> | ||
</Button> | ||
</Panel.Heading> | ||
|
||
<Panel.Body> | ||
<FormGroup> | ||
<Row> | ||
<Col componentClass={ControlLabel} sm={6}> | ||
<input | ||
id='queryName' | ||
type='text' | ||
className={clsx(styles.input, 'form-control')} | ||
value={queryName} | ||
autoComplete='off' | ||
placeholder='Name your query.' | ||
onChange={event => setQueryName(event.target.value)} | ||
/> | ||
</Col> | ||
<Col componentClass={ControlLabel} sm={1}> | ||
|
||
</Col> | ||
<Col componentClass={ControlLabel} sm={5}> | ||
<Typeahead | ||
placeholder='Select query category' | ||
onChange={setSingleSelections} | ||
options={categories} | ||
selected={singleSelections} | ||
maxHeight={100} | ||
onBlur={event => setSelectedCategory(event.target.defaultValue)} | ||
/> | ||
</Col> | ||
</Row> | ||
</FormGroup> | ||
<FormGroup> | ||
<Row> | ||
<Col componentClass={ControlLabel} sm={11}> | ||
<input | ||
type='text' | ||
onKeyDown={onKeyDown} | ||
onChange={onChange} | ||
value={query} | ||
className={clsx(styles.input, 'form-control')} | ||
autoComplete='off' | ||
placeholder='Enter a cypher query. Your query must return nodes or paths.' | ||
/> | ||
</Col> | ||
<Col componentClass={ControlLabel} style={{ margin: "auto", cursor: "pointer"}} sm={1}> | ||
<i class="fa fa-play fa-2x" onClick={runQuery}></i> | ||
</Col> | ||
</Row> | ||
</FormGroup> | ||
<FormGroup> | ||
<Row> | ||
<Col componentClass={ControlLabel} sm={2}> | ||
<Button | ||
onClick={handleClose} | ||
> | ||
Cancel | ||
</Button> | ||
</Col> | ||
<Col componentClass={ControlLabel} sm={8}> | ||
|
||
</Col> | ||
<Col | ||
componentClass={ControlLabel} | ||
style={{"text-align": "right"}} | ||
sm={2} | ||
> | ||
<Button | ||
onClick={saveQuery} | ||
> | ||
Save | ||
</Button> | ||
</Col> | ||
</Row> | ||
</FormGroup> | ||
</Panel.Body> | ||
</Panel> | ||
</PoseContainer> | ||
); | ||
}; | ||
|
||
QueryCustomCreate.propTypes = {}; | ||
export default QueryCustomCreate; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
.inputWidth { | ||
width: 6ch; | ||
margin-right: 5px; | ||
} | ||
|
||
.glyphMargin { | ||
margin-left: 5px; | ||
} | ||
|
||
.container :global { | ||
position: absolute; | ||
top: 50%; | ||
left: 50%; | ||
transform: translate(-50%, -50%); | ||
overflow: hidden; | ||
box-shadow: 0 5px 15px 0 black; | ||
} | ||
|
||
.container :global .panel { | ||
margin-bottom: 0; | ||
border: none; | ||
overflow: hidden; | ||
} | ||
|
||
.container :global .panel-heading { | ||
border: none; | ||
border-top-right-radius: 10px; | ||
border-top-left-radius: 10px; | ||
} | ||
|
||
.dark :global .panel-heading { | ||
background: #444b55; | ||
font-family: Helvetica; | ||
font-size: 20px; | ||
font-weight: 400; | ||
color: white; | ||
} | ||
|
||
.dark :global .panel-body { | ||
background: #151d29; | ||
color: white; | ||
} | ||
|
||
.dark :global button.close { | ||
opacity: 1; | ||
background-color: 151d29; | ||
color: white; | ||
} | ||
|
||
.dark :global select { | ||
background-color: #444b55; | ||
font-family: Helvetica; | ||
color: white; | ||
border: none; | ||
} | ||
|
||
.dark :global input { | ||
background-color: #444b55; | ||
font-family: Helvetica; | ||
font-weight: 400; | ||
color: white; | ||
border: none; | ||
} | ||
|
||
label { | ||
font-family: Helvetica; | ||
font-weight: 400 !important; | ||
} | ||
|
||
/* Below adapted from https://stackoverflow.com/a/24465732 */ | ||
|
||
#slider { | ||
width: 400px; | ||
height: 17px; | ||
position: relative; | ||
margin: 100px auto; | ||
background: white; | ||
} | ||
|
||
#slider .bar { | ||
width: 388px; | ||
height: 5px; | ||
background: #333; | ||
position: relative; | ||
top: 1px; | ||
left: 1px; | ||
} | ||
|
||
#slider .highlight { | ||
height: 2px; | ||
position: absolute; | ||
width: 388px; | ||
top: 6px; | ||
left: 6px; | ||
|
||
-webkit-border-radius: 40px; | ||
-moz-border-radius: 40px; | ||
border-radius: 40px; | ||
|
||
background: rgba(255, 255, 255, 0.25); | ||
} | ||
|
||
input[type='range'] { | ||
-webkit-appearance: none; | ||
background-color: #444b55; | ||
height: 5px; | ||
padding: 0px 0px; | ||
} | ||
|
||
input[type='range']::-webkit-slider-thumb { | ||
-webkit-appearance: none; | ||
position: relative; | ||
top: 0px; | ||
z-index: 1; | ||
width: 16px; | ||
height: 16px; | ||
cursor: pointer; | ||
-webkit-border-radius: 40px; | ||
-moz-border-radius: 40px; | ||
border-radius: 40px; | ||
background-color: #4f80a1; | ||
} | ||
|
||
input[type='range']:hover ~ #rangevalue, | ||
input[type='range']:active ~ #rangevalue { | ||
-ms-filter: 'progid:DXImageTransform.Microsoft.Alpha(Opacity=100)'; | ||
filter: alpha(opacity=100); | ||
opacity: 1; | ||
top: -75px; | ||
} | ||
|
||
input[type='range']:focus { | ||
outline: none; | ||
} | ||
|
||
.slider { | ||
top: 11px; | ||
} |
Oops, something went wrong.