-
Notifications
You must be signed in to change notification settings - Fork 941
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[backend/frontend] Implement full text search for documents (#1483)
Co-authored-by: marie flores <[email protected]>
- Loading branch information
1 parent
2b6a9a2
commit 184383d
Showing
50 changed files
with
2,591 additions
and
69 deletions.
There are no files selected for viewing
51 changes: 51 additions & 0 deletions
51
opencti-platform/opencti-front/src/components/ItemEntityType.tsx
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,51 @@ | ||
import Chip from '@mui/material/Chip'; | ||
import React, { FunctionComponent } from 'react'; | ||
import makeStyles from '@mui/styles/makeStyles'; | ||
import { hexToRGB, itemColor } from '../utils/Colors'; | ||
import { useFormatter } from './i18n'; | ||
|
||
const useStyles = makeStyles(() => ({ | ||
chip: { | ||
fontSize: 13, | ||
lineHeight: '12px', | ||
height: 20, | ||
textTransform: 'uppercase', | ||
borderRadius: '0', | ||
width: 120, | ||
}, | ||
chipInList: { | ||
fontSize: 12, | ||
height: 20, | ||
float: 'left', | ||
width: 120, | ||
textTransform: 'uppercase', | ||
borderRadius: '0', | ||
}, | ||
})); | ||
|
||
interface ItemEntityTypeProps { | ||
entityType: string; | ||
variant?: string; | ||
} | ||
|
||
const ItemEntityType: FunctionComponent<ItemEntityTypeProps> = ({ | ||
variant = 'inList', | ||
entityType, | ||
}) => { | ||
const classes = useStyles(); | ||
const { t } = useFormatter(); | ||
const style = variant === 'inList' ? classes.chipInList : classes.chip; | ||
return ( | ||
<Chip | ||
classes={{ root: style }} | ||
style={{ | ||
backgroundColor: hexToRGB(itemColor(entityType), 0.08), | ||
color: itemColor(entityType), | ||
border: `1px solid ${itemColor(entityType)}`, | ||
}} | ||
label={t(`entity_${entityType}`)} | ||
/> | ||
); | ||
}; | ||
|
||
export default ItemEntityType; |
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
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
135 changes: 135 additions & 0 deletions
135
opencti-platform/opencti-front/src/private/components/search/SearchIndexedFileLine.tsx
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,135 @@ | ||
import React, { FunctionComponent } from 'react'; | ||
import { Link } from 'react-router-dom'; | ||
import { createFragmentContainer, graphql } from 'react-relay'; | ||
import ListItem from '@mui/material/ListItem'; | ||
import ListItemText from '@mui/material/ListItemText'; | ||
import makeStyles from '@mui/styles/makeStyles'; | ||
import { SearchIndexedFileLine_node$data } from '@components/search/__generated__/SearchIndexedFileLine_node.graphql'; | ||
import ListItemIcon from '@mui/material/ListItemIcon'; | ||
import { OpenInNewOutlined } from '@mui/icons-material'; | ||
import IconButton from '@mui/material/IconButton'; | ||
import ListItemSecondaryAction from '@mui/material/ListItemSecondaryAction'; | ||
import Tooltip from '@mui/material/Tooltip'; | ||
import { DataColumns } from '../../../components/list_lines'; | ||
import { Theme } from '../../../components/Theme'; | ||
import { useFormatter } from '../../../components/i18n'; | ||
import ItemIcon from '../../../components/ItemIcon'; | ||
import { getFileUri } from '../../../utils/utils'; | ||
import { resolveLink } from '../../../utils/Entity'; | ||
import useGranted, { KNOWLEDGE_KNGETEXPORT, KNOWLEDGE_KNUPLOAD } from '../../../utils/hooks/useGranted'; | ||
|
||
const useStyles = makeStyles<Theme>((theme) => ({ | ||
item: { | ||
paddingLeft: 10, | ||
height: 50, | ||
}, | ||
itemIcon: { | ||
color: theme.palette.primary.main, | ||
}, | ||
bodyItem: { | ||
height: 20, | ||
fontSize: 13, | ||
float: 'left', | ||
whiteSpace: 'nowrap', | ||
overflow: 'hidden', | ||
textOverflow: 'ellipsis', | ||
paddingRight: 10, | ||
}, | ||
})); | ||
|
||
interface SearchIndexedFileLineComponentProps { | ||
node: SearchIndexedFileLine_node$data; | ||
dataColumns: DataColumns; | ||
} | ||
|
||
const SearchIndexedFileLineComponent: FunctionComponent<SearchIndexedFileLineComponentProps> = ({ | ||
node, | ||
dataColumns, | ||
}) => { | ||
const classes = useStyles(); | ||
const { t } = useFormatter(); | ||
let entityLink = node.entity ? `${resolveLink(node.entity.entity_type)}/${node.entity.id}` : ''; | ||
const isGrantedToFiles = useGranted([KNOWLEDGE_KNUPLOAD, KNOWLEDGE_KNGETEXPORT]); | ||
if (entityLink && isGrantedToFiles) { | ||
entityLink = entityLink.concat('/files'); | ||
} | ||
return ( | ||
<ListItem | ||
classes={{ root: classes.item }} | ||
divider={true} | ||
button={true} | ||
component="a" | ||
href={getFileUri(node.file_id)} | ||
target="_blank" | ||
> | ||
<ListItemIcon classes={{ root: classes.itemIcon }}> | ||
<ItemIcon type="File" /> | ||
</ListItemIcon> | ||
<ListItemText | ||
primary={ | ||
<div> | ||
{Object.values(dataColumns).map((value) => ( | ||
<div | ||
key={value.label} | ||
className={classes.bodyItem} | ||
style={{ width: value.width }} | ||
> | ||
{value.render?.(node)} | ||
</div> | ||
))} | ||
</div> | ||
} | ||
/> | ||
<ListItemSecondaryAction> | ||
{node.entity && entityLink && ( | ||
<Tooltip title={t('Open the entity overview in a separated tab')}> | ||
<IconButton | ||
component={Link} | ||
target="_blank" | ||
to={entityLink} | ||
size="medium" | ||
> | ||
<OpenInNewOutlined fontSize="medium" /> | ||
</IconButton> | ||
</Tooltip> | ||
)} | ||
</ListItemSecondaryAction> | ||
</ListItem> | ||
); | ||
}; | ||
|
||
const SearchIndexedFileLine = createFragmentContainer(SearchIndexedFileLineComponent, { | ||
node: graphql` | ||
fragment SearchIndexedFileLine_node on IndexedFile { | ||
id | ||
name | ||
uploaded_at | ||
file_id | ||
searchOccurrences | ||
entity { | ||
...on StixObject { | ||
id | ||
entity_type | ||
representative { | ||
main | ||
} | ||
} | ||
...on StixCoreObject { | ||
objectMarking { | ||
edges { | ||
node { | ||
id | ||
definition_type | ||
definition | ||
x_opencti_order | ||
x_opencti_color | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
`, | ||
}); | ||
|
||
export default SearchIndexedFileLine; |
Oops, something went wrong.