Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[backend/frontend] Implement full text search for documents (#1483) #4275

Merged
merged 35 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f215f90
[backend/frontend] Implement full text search for documents (#1483)
marieflorescontact Sep 6, 2023
c44d898
[backend] Create ManagerConfiguration module
marieflorescontact Oct 24, 2023
d0c7b80
[backend] Write ManagerConfiguration into cache
marieflorescontact Oct 25, 2023
77d026f
[backend] Replace saveFileIndexStatus by saveManagerConfiguration
marieflorescontact Oct 25, 2023
7d8d603
[backend] Change enabled condition
marieflorescontact Oct 26, 2023
80da6be
[frontend] Start FileIndexingConfiguration component
marieflorescontact Oct 26, 2023
cfcbec6
[backend/frontend] Add warning on modules manager
marieflorescontact Oct 26, 2023
19bb814
[frontend] Ui file indexing configuration
marieflorescontact Oct 26, 2023
8216eed
[backend] Implement files metrics and fileListingForIndexing
marieflorescontact Oct 27, 2023
9b4366b
[backend] update migration timestamp after rebase
marieflorescontact Oct 30, 2023
43965fa
[frontend] fetch metrics
marieflorescontact Oct 30, 2023
3d7f698
[frontend] FilIndexingConfiguration splitting
marieflorescontact Oct 30, 2023
2107f66
[frontend] localization
marieflorescontact Oct 31, 2023
85e6e48
[frontend] typo in requirements
marieflorescontact Oct 31, 2023
db539b1
[backend] Init ManagerConfiguration at plateform start
marieflorescontact Nov 2, 2023
ac196f6
[backend/frontend] Implement start and pause
marieflorescontact Nov 2, 2023
8258136
[backend] Get indexed files metrics
marieflorescontact Nov 2, 2023
55fd5cc
[backend] fix tests after adding ManagerConfiguration
SouadHadjiat Nov 2, 2023
9ae1921
[backend] fix engine getStats to return stats for primary shards
SouadHadjiat Nov 2, 2023
69b9284
[frontend] Display indexed files metrics
marieflorescontact Nov 2, 2023
b8ebd39
[frontend] Add default mimeTypes
marieflorescontact Nov 3, 2023
961e0fd
[frontend] Renaming
marieflorescontact Nov 3, 2023
97cf02f
[frontend] Add maxfileSize variable for filemetrics query and rename …
marieflorescontact Nov 3, 2023
0953a82
[frontend] Refresh indexedFilesMetrics evry 5 sec
marieflorescontact Nov 3, 2023
63153a9
[backend] filter files to index by excluded paths list
SouadHadjiat Nov 3, 2023
7eb5192
[frontend] Refresh indexedFilesMetrics every 10 sec
marieflorescontact Nov 3, 2023
4d3359a
[frontend] Add success message for indexing
marieflorescontact Nov 3, 2023
6ab5427
[backend/frontend] exclude global files by default
SouadHadjiat Nov 3, 2023
c436a07
[backend] index files one by one
SouadHadjiat Nov 3, 2023
44ae1cc
[backend] index by bulk with pause
SouadHadjiat Nov 3, 2023
ab9150c
[frontend] PR review refactoring
SouadHadjiat Nov 6, 2023
09afd60
[frontend] add missing translations
SouadHadjiat Nov 6, 2023
c75ad18
[backend] add EE licence comment and add lock signal check
SouadHadjiat Nov 8, 2023
851707d
[backend] set file index internal id based on file id
SouadHadjiat Nov 8, 2023
77a0c22
[backend] PR review fix
SouadHadjiat Nov 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions opencti-platform/opencti-front/src/components/ItemEntityType.tsx
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;
3 changes: 3 additions & 0 deletions opencti-platform/opencti-front/src/components/ItemIcon.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ import {
DatabaseExportOutline,
DiamondOutline,
FileDelimitedOutline,
FileOutline,
Fire,
HexagonOutline,
LabelOutline,
Expand Down Expand Up @@ -172,6 +173,8 @@ const iconSelector = (type, variant, fontSize, color, isReversed) => {
);
case 'label':
return <LabelOutline style={style} fontSize={fontSize} role="img" />;
case 'file':
return <FileOutline style={style} fontSize={fontSize} role="img" />;
case 'attack-pattern':
return <LockPattern style={style} fontSize={fontSize} role="img" />;
case 'campaign':
Expand Down
1 change: 1 addition & 0 deletions opencti-platform/opencti-front/src/private/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ const rootPrivateQuery = graphql`
id
enable
running
warning
}
enterprise_edition
...AppThemeProvider_settings
Expand Down
23 changes: 21 additions & 2 deletions opencti-platform/opencti-front/src/private/components/Search.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import React, { useState } from 'react';
import { KeyboardDoubleArrowDownOutlined } from '@mui/icons-material';
import Typography from '@mui/material/Typography';
import { SearchStixCoreObjectLineDummy } from '@components/search/SearchStixCoreObjectLine';
import {
Expand All @@ -9,6 +10,8 @@ import {
SearchStixCoreObjectsLinesPaginationQuery$variables,
} from '@components/search/__generated__/SearchStixCoreObjectsLinesPaginationQuery.graphql';
import { useParams } from 'react-router-dom';
import Button from '@mui/material/Button';
import SearchIndexedFiles from '@components/search/SearchIndexedFiles';
import TopBar from './nav/TopBar';
import ListLines from '../../components/list_lines/ListLines';
import ToolBar from './data/ToolBar';
Expand All @@ -25,7 +28,7 @@ const LOCAL_STORAGE_KEY = 'view-search';

const Search = () => {
const {
platformModuleHelpers: { isRuntimeFieldEnable },
platformModuleHelpers: { isRuntimeFieldEnable, isFileIndexManagerEnable },
} = useAuth();
const { t } = useFormatter();
const { keyword } = useParams() as { keyword: string };
Expand All @@ -35,6 +38,7 @@ const Search = () => {
} catch (e) {
// Do nothing
}
const fileSearchEnabled = isFileIndexManagerEnable();
const { viewStorage, helpers: storageHelpers, paginationOptions } = usePaginationLocalStorage<SearchStixCoreObjectsLinesPaginationQuery$variables>(
LOCAL_STORAGE_KEY,
{
Expand Down Expand Up @@ -65,6 +69,10 @@ const Search = () => {
searchStixCoreObjectsLinesQuery,
{ ...paginationOptions, search: searchTerm },
);
const [searchOpen, setSearchOpen] = useState(false);
const handleSearchIndexFiles = () => {
setSearchOpen(true);
};

const renderLines = () => {
const isRuntimeSort = isRuntimeFieldEnable() ?? false;
Expand Down Expand Up @@ -196,6 +204,17 @@ const Search = () => {
{t('Search for an entity')}
</Typography>
{renderLines()}
{fileSearchEnabled && searchTerm && (
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<Button
size="small"
onClick={handleSearchIndexFiles}
>
<KeyboardDoubleArrowDownOutlined /> {t('Extend this search to indexed files')} <KeyboardDoubleArrowDownOutlined />
</Button>
</div>
)}
{ searchOpen ? (<SearchIndexedFiles search={searchTerm}/>) : ('')}
</div>
</ExportContextProvider>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,26 @@ const TopMenuSettings = () => {
{t('Activity')}
</Button>
</Security>
<Security needs={[SETTINGS]}>
<Button
component={Link}
size="small"
to="/dashboard/settings/file_indexing"
variant={
location.pathname.includes('/dashboard/settings/file_indexing')
? 'contained'
: 'text'
}
color={
location.pathname.includes('/dashboard/settings/file_indexing')
? 'secondary'
: 'primary'
}
classes={{ root: classes.button }}
>
{t('File indexing')}
</Button>
</Security>
</div>
);
};
Expand Down
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to use ListItemButton

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>
SouadHadjiat marked this conversation as resolved.
Show resolved Hide resolved
{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;
Loading