diff --git a/opencti-platform/opencti-front/src/components/dashboard/WidgetDistributionList.tsx b/opencti-platform/opencti-front/src/components/dashboard/WidgetDistributionList.tsx index 6b281b7ef0dc..81a6c6bf3e54 100644 --- a/opencti-platform/opencti-front/src/components/dashboard/WidgetDistributionList.tsx +++ b/opencti-platform/opencti-front/src/components/dashboard/WidgetDistributionList.tsx @@ -9,6 +9,7 @@ import ItemIcon from '../ItemIcon'; import { computeLink } from '../../utils/Entity'; import type { Theme } from '../Theme'; import { useFormatter } from '../i18n'; +import { getMainRepresentative } from '../../utils/defaultRepresentatives'; interface WidgetDistributionListProps { // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -38,6 +39,8 @@ const WidgetDistributionList = ({ > {data.map((entry, key) => { + const label = getMainRepresentative(entry.entity) || entry.label; + let link: string | null = null; if (entry.type !== 'User' || hasSettingAccess) { const node: { @@ -49,7 +52,7 @@ const WidgetDistributionList = ({ id: entry.id, entity_type: entry.type, }; - link = entry.id ? computeLink(node) : null; + link = entry.id && entry.label !== 'Restricted' ? computeLink(node) : null; } let linkProps = {}; if (link) { @@ -61,7 +64,7 @@ const WidgetDistributionList = ({ return ( - {entry.label} + {label} } /> diff --git a/opencti-platform/opencti-front/src/components/dashboard/WidgetDonut.tsx b/opencti-platform/opencti-front/src/components/dashboard/WidgetDonut.tsx index 4a4beee20b63..f8267b446288 100644 --- a/opencti-platform/opencti-front/src/components/dashboard/WidgetDonut.tsx +++ b/opencti-platform/opencti-front/src/components/dashboard/WidgetDonut.tsx @@ -2,10 +2,9 @@ import Chart from '@components/common/charts/Chart'; import React from 'react'; import { useTheme } from '@mui/styles'; import type { ApexOptions } from 'apexcharts'; -import { defaultValue } from '../../utils/Graph'; import { donutChartOptions } from '../../utils/Charts'; -import { useFormatter } from '../i18n'; import type { Theme } from '../Theme'; +import useDistributionGraphData from '../../utils/hooks/useDistributionGraphData'; interface WidgetDonutProps { // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -22,32 +21,25 @@ const WidgetDonut = ({ readonly = false, }: WidgetDonutProps) => { const theme = useTheme(); - const { t_i18n } = useFormatter(); + const { buildWidgetLabelsOption } = useDistributionGraphData(); const chartData = data.map((n) => n.value); - // eslint-disable-next-line no-nested-ternary - const labels = data.map((n) => (groupBy.endsWith('_id') - ? defaultValue(n.entity) - : groupBy === 'entity_type' && t_i18n(`entity_${n.label}`) !== `entity_${n.label}` - ? t_i18n(`entity_${n.label}`) - : n.label)); - + const labels = buildWidgetLabelsOption(data, groupBy); let chartColors = []; if (data.at(0)?.entity?.color) { - chartColors = data.map((n) => (theme.palette.mode === 'light' && n.entity.color === '#ffffff' + chartColors = data.map((n) => (theme.palette.mode === 'light' && n.entity?.color === '#ffffff' ? '#000000' - : n.entity.color)); + : n.entity?.color)); } if (data.at(0)?.entity?.x_opencti_color) { - chartColors = data.map((n) => (theme.palette.mode === 'light' - && n.entity.x_opencti_color === '#ffffff' + chartColors = data.map((n) => (theme.palette.mode === 'light' && n.entity?.x_opencti_color === '#ffffff' ? '#000000' - : n.entity.x_opencti_color)); + : n.entity?.x_opencti_color)); } if (data.at(0)?.entity?.template?.color) { - chartColors = data.map((n) => (theme.palette.mode === 'light' && n.entity.template.color === '#ffffff' + chartColors = data.map((n) => (theme.palette.mode === 'light' && n.entity?.template.color === '#ffffff' ? '#000000' - : n.entity.template.color)); + : n.entity?.template.color)); } return ( diff --git a/opencti-platform/opencti-front/src/components/dashboard/WidgetListCoreObjects.tsx b/opencti-platform/opencti-front/src/components/dashboard/WidgetListCoreObjects.tsx index d79fa4fc0537..45c7bcfeaa51 100644 --- a/opencti-platform/opencti-front/src/components/dashboard/WidgetListCoreObjects.tsx +++ b/opencti-platform/opencti-front/src/components/dashboard/WidgetListCoreObjects.tsx @@ -8,7 +8,7 @@ import StixCoreObjectLabels from '@components/common/stix_core_objects/StixCoreO import React, { CSSProperties } from 'react'; import { resolveLink } from '../../utils/Entity'; import ItemIcon from '../ItemIcon'; -import { defaultValue } from '../../utils/Graph'; +import { getMainRepresentative } from '../../utils/defaultRepresentatives'; import ItemStatus from '../ItemStatus'; import ItemMarkings from '../ItemMarkings'; import { useFormatter } from '../i18n'; @@ -72,7 +72,7 @@ const WidgetListCoreObjects = ({ primary={ <>
- {defaultValue(stixCoreObject)} + {getMainRepresentative(stixCoreObject)}
{fsd(date)} diff --git a/opencti-platform/opencti-front/src/components/dashboard/WidgetListRelationships.tsx b/opencti-platform/opencti-front/src/components/dashboard/WidgetListRelationships.tsx index 244b9a374045..b302a4157db7 100644 --- a/opencti-platform/opencti-front/src/components/dashboard/WidgetListRelationships.tsx +++ b/opencti-platform/opencti-front/src/components/dashboard/WidgetListRelationships.tsx @@ -7,7 +7,7 @@ import React, { CSSProperties } from 'react'; import { useTheme } from '@mui/styles'; import { ListItemButton } from '@mui/material'; import ItemIcon from '../ItemIcon'; -import { defaultValue } from '../../utils/Graph'; +import { getMainRepresentative } from '../../utils/defaultRepresentatives'; import ItemMarkings from '../ItemMarkings'; import { computeLink } from '../../utils/Entity'; import type { Theme } from '../Theme'; @@ -116,7 +116,7 @@ const WidgetListRelationships = ({
{stixRelationship.from - ? defaultValue(stixRelationship.from) + ? getMainRepresentative(stixRelationship.from) : t_i18n('Restricted')}
@@ -149,7 +149,7 @@ const WidgetListRelationships = ({
{stixRelationship.to - ? defaultValue(stixRelationship.to) + ? getMainRepresentative(stixRelationship.to) : t_i18n('Restricted')}
diff --git a/opencti-platform/opencti-front/src/components/dashboard/WidgetRadar.tsx b/opencti-platform/opencti-front/src/components/dashboard/WidgetRadar.tsx index c2d6b8148bf0..d494fd8757f2 100644 --- a/opencti-platform/opencti-front/src/components/dashboard/WidgetRadar.tsx +++ b/opencti-platform/opencti-front/src/components/dashboard/WidgetRadar.tsx @@ -3,9 +3,9 @@ import React from 'react'; import { useTheme } from '@mui/styles'; import { ApexOptions } from 'apexcharts'; import { radarChartOptions } from '../../utils/Charts'; -import { defaultValue } from '../../utils/Graph'; import { useFormatter } from '../i18n'; import type { Theme } from '../Theme'; +import useDistributionGraphData from '../../utils/hooks/useDistributionGraphData'; interface WidgetRadarProps { // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -25,19 +25,14 @@ const WidgetRadar = ({ }: WidgetRadarProps) => { const theme = useTheme(); const { t_i18n } = useFormatter(); + const { buildWidgetLabelsOption } = useDistributionGraphData(); const chartData = [{ name: label || t_i18n('Number of relationships'), data: data.map((n) => n.value), }]; - // eslint-disable-next-line no-nested-ternary,implicit-arrow-linebreak - const labels = data.map((n) => (groupBy.endsWith('_id') - ? defaultValue(n.entity) - : groupBy === 'entity_type' && t_i18n(`entity_${n.label}`) !== `entity_${n.label}` - ? t_i18n(`entity_${n.label}`) - : n.label)); - + const labels = buildWidgetLabelsOption(data, groupBy); return ( { }} > - {data.map(({ value, link }) => { + {data.map(({ value, link }, index) => { return ( - + { - {defaultValue(value)} + {getMainRepresentative(value)}
diff --git a/opencti-platform/opencti-front/src/components/dashboard/WidgetTree.tsx b/opencti-platform/opencti-front/src/components/dashboard/WidgetTree.tsx index 4672b6067834..24746df78b48 100644 --- a/opencti-platform/opencti-front/src/components/dashboard/WidgetTree.tsx +++ b/opencti-platform/opencti-front/src/components/dashboard/WidgetTree.tsx @@ -4,7 +4,7 @@ import { useTheme } from '@mui/styles'; import { ApexOptions } from 'apexcharts'; import { useFormatter } from '../i18n'; import { treeMapOptions } from '../../utils/Charts'; -import { defaultValue } from '../../utils/Graph'; +import { getMainRepresentative, isFieldForIdentifier } from '../../utils/defaultRepresentatives'; interface WidgetTreeProps { // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -25,15 +25,16 @@ const WidgetTree = ({ const theme = useTheme(); const { t_i18n } = useFormatter(); - const chartData = data.map((n) => ({ - // eslint-disable-next-line no-nested-ternary - x: groupBy.endsWith('_id') - ? defaultValue(n.entity) - : groupBy === 'entity_type' && t_i18n(`entity_${n.label}`) !== `entity_${n.label}` - ? t_i18n(`entity_${n.label}`) - : n.label, - y: n.value, - })); + const chartData = data.map((n) => { + const item = { x: n.label, y: n.value }; + if (isFieldForIdentifier(groupBy)) { + item.x = getMainRepresentative(n.entity); + } else if (groupBy === 'entity_type' && t_i18n(`entity_${n.label}`) !== `entity_${n.label}`) { + item.x = t_i18n(`entity_${n.label}`); + } + return item; + }); + const series = [{ data: chartData }]; return ( diff --git a/opencti-platform/opencti-front/src/private/components/SearchBulk.jsx b/opencti-platform/opencti-front/src/private/components/SearchBulk.jsx index 80b5b7d3cf03..26cdd5595b26 100644 --- a/opencti-platform/opencti-front/src/private/components/SearchBulk.jsx +++ b/opencti-platform/opencti-front/src/private/components/SearchBulk.jsx @@ -21,7 +21,7 @@ import ItemIcon from '../../components/ItemIcon'; import { searchStixCoreObjectsLinesSearchQuery } from './search/SearchStixCoreObjectsLines'; import { fetchQuery } from '../../relay/environment'; import { useFormatter } from '../../components/i18n'; -import { defaultValue } from '../../utils/Graph'; +import { getMainRepresentative } from '../../utils/defaultRepresentatives'; import { resolveLink } from '../../utils/Entity'; import StixCoreObjectLabels from './common/stix_core_objects/StixCoreObjectLabels'; import StixCoreObjectsExports from './common/stix_core_objects/StixCoreObjectsExports'; @@ -341,7 +341,7 @@ const SearchBulk = () => { (resolvedStixCoreObject) => ({ id: resolvedStixCoreObject.id, type: resolvedStixCoreObject.entity_type, - value: defaultValue(resolvedStixCoreObject), + value: getMainRepresentative(resolvedStixCoreObject), labels: resolvedStixCoreObject.objectLabel, markings: resolvedStixCoreObject.objectMarking, containersNumber: resolvedStixCoreObject.containersNumber, diff --git a/opencti-platform/opencti-front/src/private/components/analyses/groupings/GroupingKnowledgeGraph.jsx b/opencti-platform/opencti-front/src/private/components/analyses/groupings/GroupingKnowledgeGraph.jsx index b5384c91df4d..0bb46993f8fa 100644 --- a/opencti-platform/opencti-front/src/private/components/analyses/groupings/GroupingKnowledgeGraph.jsx +++ b/opencti-platform/opencti-front/src/private/components/analyses/groupings/GroupingKnowledgeGraph.jsx @@ -25,14 +25,13 @@ import { computeTimeRangeInterval, computeTimeRangeValues, decodeGraphData, - defaultSecondaryValue, - defaultValue, encodeGraphData, linkPaint, nodeAreaPaint, nodePaint, nodeThreePaint, } from '../../../../utils/Graph'; +import { getSecondaryRepresentative, getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import { buildViewParamsFromUrlAndStorage, saveViewParameters } from '../../../../utils/ListParameters'; import GroupingKnowledgeGraphBar from './GroupingKnowledgeGraphBar'; import { groupingMutationFieldPatch } from './GroupingEditionOverview'; @@ -955,9 +954,9 @@ class GroupingKnowledgeGraphComponent extends Component { this.selectedNodes.clear(); if (isNotEmptyField(keyword)) { const filterByKeyword = (n) => keyword === '' - || (defaultValue(n) || '').toLowerCase().indexOf(keyword.toLowerCase()) + || (getMainRepresentative(n) || '').toLowerCase().indexOf(keyword.toLowerCase()) !== -1 - || (defaultSecondaryValue(n) || '') + || (getSecondaryRepresentative(n) || '') .toLowerCase() .indexOf(keyword.toLowerCase()) !== -1 || (n.entity_type || '').toLowerCase().indexOf(keyword.toLowerCase()) diff --git a/opencti-platform/opencti-front/src/private/components/analyses/groupings/GroupingsAreaChart.jsx b/opencti-platform/opencti-front/src/private/components/analyses/groupings/GroupingsAreaChart.jsx deleted file mode 100644 index c048bc638a59..000000000000 --- a/opencti-platform/opencti-front/src/private/components/analyses/groupings/GroupingsAreaChart.jsx +++ /dev/null @@ -1,167 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose } from 'ramda'; -import { graphql } from 'react-relay'; -import withStyles from '@mui/styles/withStyles'; -import withTheme from '@mui/styles/withTheme'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import inject18n from '../../../../components/i18n'; -import { monthsAgo, now } from '../../../../utils/Time'; -import { areaChartOptions } from '../../../../utils/Charts'; -import { simpleNumberFormat } from '../../../../utils/Number'; - -const styles = () => ({ - paper: { - minHeight: 280, - height: '100%', - margin: '4px 0 0 0', - padding: '0 0 10px 0', - borderRadius: 4, - }, - chip: { - fontSize: 10, - height: 20, - marginLeft: 10, - }, -}); - -const groupingsAreaChartTimeSeriesQuery = graphql` - query GroupingsAreaChartTimeSeriesQuery( - $field: String! - $operation: StatsOperation! - $startDate: DateTime! - $endDate: DateTime! - $interval: String! - ) { - groupingsTimeSeries( - field: $field - operation: $operation - startDate: $startDate - endDate: $endDate - interval: $interval - ) { - date - value - } - } -`; - -class GroupingsAreaChart extends Component { - renderContent() { - const { t, fsd, groupingType, startDate, endDate, theme } = this.props; - const interval = 'day'; - const finalStartDate = startDate || monthsAgo(12); - const finalEndDate = endDate || now(); - const groupingsTimeSeriesVariables = { - groupingType: groupingType || null, - field: 'created_at', - operation: 'count', - startDate: finalStartDate, - endDate: finalEndDate, - interval, - }; - return ( - { - if (props && props.groupingsTimeSeries) { - const chartData = props.groupingsTimeSeries.map((entry) => ({ - x: new Date(entry.date), - y: entry.value, - })); - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - } - - render() { - const { t, classes, title, variant, height } = this.props; - return ( -
- - {title || t('Groupings distribution')} - - {variant !== 'inLine' ? ( - - {this.renderContent()} - - ) : ( - this.renderContent() - )} -
- ); - } -} - -GroupingsAreaChart.propTypes = { - classes: PropTypes.object, - theme: PropTypes.object, - t: PropTypes.func, - md: PropTypes.func, -}; - -export default compose( - inject18n, - withTheme, - withStyles(styles), -)(GroupingsAreaChart); diff --git a/opencti-platform/opencti-front/src/private/components/analyses/groupings/GroupingsDonut.jsx b/opencti-platform/opencti-front/src/private/components/analyses/groupings/GroupingsDonut.jsx deleted file mode 100644 index f6c69364d4ad..000000000000 --- a/opencti-platform/opencti-front/src/private/components/analyses/groupings/GroupingsDonut.jsx +++ /dev/null @@ -1,143 +0,0 @@ -import React from 'react'; -import { graphql } from 'react-relay'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import * as R from 'ramda'; -import makeStyles from '@mui/styles/makeStyles'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import { donutChartOptions } from '../../../../utils/Charts'; - -const useStyles = makeStyles(() => ({ - paper: { - height: 300, - minHeight: 300, - maxHeight: 300, - margin: '10px 0 0 0', - padding: 0, - borderRadius: 4, - }, -})); - -const groupingsDonutDistributionQuery = graphql` - query GroupingsDonutDistributionQuery( - $field: String! - $operation: StatsOperation! - $limit: Int - $startDate: DateTime - $endDate: DateTime - ) { - groupingsDistribution( - field: $field - operation: $operation - limit: $limit - startDate: $startDate - endDate: $endDate - ) { - label - value - entity { - ... on Identity { - name - } - } - } - } -`; - -const GroupingsDonut = (props) => { - const { t, field, startDate, endDate, theme, height, title, variant } = props; - const classes = useStyles(); - const renderContent = () => { - const groupingsDistributionVariables = { - field: field || 'grouping_types', - operation: 'count', - limit: 8, - startDate, - endDate, - }; - return ( - { - if ( - resultProps - && resultProps.groupingsDistribution - && resultProps.groupingsDistribution.length > 0 - ) { - let data = resultProps.groupingsDistribution; - if (field && field.includes('internal_id')) { - data = R.map( - (n) => R.assoc('label', n.entity.name, n), - resultProps.groupingsDistribution, - ); - } - const chartData = data.map((n) => n.value); - const labels = data.map((n) => n.label); - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - }; - return ( -
- - {title || t('Groupings distribution')} - - {variant !== 'inLine' ? ( - - {renderContent()} - - ) : ( - renderContent() - )} -
- ); -}; - -export default GroupingsDonut; diff --git a/opencti-platform/opencti-front/src/private/components/analyses/groupings/GroupingsHorizontalBars.jsx b/opencti-platform/opencti-front/src/private/components/analyses/groupings/GroupingsHorizontalBars.jsx deleted file mode 100644 index f5edae6aff11..000000000000 --- a/opencti-platform/opencti-front/src/private/components/analyses/groupings/GroupingsHorizontalBars.jsx +++ /dev/null @@ -1,166 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose } from 'ramda'; -import { graphql } from 'react-relay'; -import withTheme from '@mui/styles/withTheme'; -import withStyles from '@mui/styles/withStyles'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import inject18n from '../../../../components/i18n'; -import { horizontalBarsChartOptions } from '../../../../utils/Charts'; -import { simpleNumberFormat } from '../../../../utils/Number'; - -const styles = () => ({ - paper: { - height: 300, - minHeight: 300, - maxHeight: 300, - margin: '10px 0 0 0', - padding: 0, - borderRadius: 4, - }, -}); - -const groupingsHorizontalBarsDistributionQuery = graphql` - query GroupingsHorizontalBarsDistributionQuery( - $field: String! - $operation: StatsOperation! - $limit: Int - $startDate: DateTime - $endDate: DateTime - ) { - groupingsDistribution( - field: $field - operation: $operation - limit: $limit - startDate: $startDate - endDate: $endDate - ) { - label - value - entity { - ... on Identity { - name - } - } - } - } -`; - -class GroupingsHorizontalBars extends Component { - renderContent() { - const { t, field, startDate, endDate, theme } = this.props; - const groupingsDistributionVariables = { - field: field || 'grouping_types', - operation: 'count', - limit: 8, - startDate, - endDate, - }; - return ( - { - if ( - props - && props.groupingsDistribution - && props.groupingsDistribution.length > 0 - ) { - const data = props.groupingsDistribution.map((n) => ({ - x: n.entity.name, - y: n.value, - })); - const chartData = [{ name: t('Number of groupings'), data }]; - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - } - - render() { - const { t, classes, title, variant, height } = this.props; - return ( -
- - {title || t('Groupings distribution')} - - {variant !== 'inLine' ? ( - - {this.renderContent()} - - ) : ( - this.renderContent() - )} -
- ); - } -} - -GroupingsHorizontalBars.propTypes = { - title: PropTypes.string, - field: PropTypes.string, - startDate: PropTypes.string, - endDate: PropTypes.string, - classes: PropTypes.object, - theme: PropTypes.object, - t: PropTypes.func, -}; - -export default compose( - inject18n, - withTheme, - withStyles(styles), -)(GroupingsHorizontalBars); diff --git a/opencti-platform/opencti-front/src/private/components/analyses/groupings/GroupingsVerticalBars.jsx b/opencti-platform/opencti-front/src/private/components/analyses/groupings/GroupingsVerticalBars.jsx deleted file mode 100644 index 5d956c870fcb..000000000000 --- a/opencti-platform/opencti-front/src/private/components/analyses/groupings/GroupingsVerticalBars.jsx +++ /dev/null @@ -1,167 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose } from 'ramda'; -import { graphql } from 'react-relay'; -import withTheme from '@mui/styles/withTheme'; -import withStyles from '@mui/styles/withStyles'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import inject18n from '../../../../components/i18n'; -import { monthsAgo, now } from '../../../../utils/Time'; -import { verticalBarsChartOptions } from '../../../../utils/Charts'; -import { simpleNumberFormat } from '../../../../utils/Number'; - -const styles = () => ({ - paper: { - minHeight: 280, - height: '100%', - margin: '4px 0 0 0', - padding: '0 0 10px 0', - borderRadius: 4, - }, - chip: { - fontSize: 10, - height: 20, - marginLeft: 10, - }, -}); - -const reporstVerticalBarsTimeSeriesQuery = graphql` - query GroupingsVerticalBarsTimeSeriesQuery( - $field: String! - $operation: StatsOperation! - $startDate: DateTime! - $endDate: DateTime! - $interval: String! - ) { - groupingsTimeSeries( - field: $field - operation: $operation - startDate: $startDate - endDate: $endDate - interval: $interval - ) { - date - value - } - } -`; - -class GroupingsVerticalBars extends Component { - renderContent() { - const { t, fsd, groupingType, startDate, endDate, theme } = this.props; - const interval = 'day'; - const finalStartDate = startDate || monthsAgo(12); - const finalEndDate = endDate || now(); - const groupingsTimeSeriesVariables = { - groupingType: groupingType || null, - field: 'created_at', - operation: 'count', - startDate: finalStartDate, - endDate: finalEndDate, - interval, - }; - return ( - { - if (props && props.groupingsTimeSeries) { - const chartData = props.groupingsTimeSeries.map((entry) => ({ - x: new Date(entry.date), - y: entry.value, - })); - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - } - - render() { - const { t, classes, title, variant, height } = this.props; - return ( -
- - {title || t('Groupings history')} - - {variant !== 'inLine' ? ( - - {this.renderContent()} - - ) : ( - this.renderContent() - )} -
- ); - } -} - -GroupingsVerticalBars.propTypes = { - classes: PropTypes.object, - theme: PropTypes.object, - t: PropTypes.func, - md: PropTypes.func, -}; - -export default compose( - inject18n, - withTheme, - withStyles(styles), -)(GroupingsVerticalBars); diff --git a/opencti-platform/opencti-front/src/private/components/analyses/groupings/StixCoreObjectGroupingsAreaChart.jsx b/opencti-platform/opencti-front/src/private/components/analyses/groupings/StixCoreObjectGroupingsAreaChart.jsx deleted file mode 100644 index 3fd365a2790a..000000000000 --- a/opencti-platform/opencti-front/src/private/components/analyses/groupings/StixCoreObjectGroupingsAreaChart.jsx +++ /dev/null @@ -1,201 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose } from 'ramda'; -import { graphql } from 'react-relay'; -import withStyles from '@mui/styles/withStyles'; -import withTheme from '@mui/styles/withTheme'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import inject18n from '../../../../components/i18n'; -import { monthsAgo, now } from '../../../../utils/Time'; -import { areaChartOptions } from '../../../../utils/Charts'; -import { simpleNumberFormat } from '../../../../utils/Number'; - -const styles = () => ({ - paper: { - minHeight: 280, - height: '100%', - margin: '4px 0 0 0', - padding: '0 0 10px 0', - borderRadius: 4, - }, - chip: { - fontSize: 10, - height: 20, - marginLeft: 10, - }, -}); - -const stixCoreObjectGroupingsAreaChartTimeSeriesQuery = graphql` - query StixCoreObjectGroupingsAreaChartTimeSeriesQuery( - $objectId: String - $authorId: String - $groupingClass: String - $field: String! - $operation: StatsOperation! - $startDate: DateTime! - $endDate: DateTime! - $interval: String! - ) { - groupingsTimeSeries( - objectId: $objectId - authorId: $authorId - groupingType: $groupingClass - field: $field - operation: $operation - startDate: $startDate - endDate: $endDate - interval: $interval - ) { - date - value - } - } -`; - -class StixCoreObjectGroupingsAreaChart extends Component { - renderContent() { - const { - t, - fsd, - groupingType, - startDate, - endDate, - stixCoreObjectId, - authorId, - theme, - } = this.props; - const interval = 'day'; - const finalStartDate = startDate || monthsAgo(12); - const finalEndDate = endDate || now(); - let groupingsTimeSeriesVariables; - if (authorId) { - groupingsTimeSeriesVariables = { - authorId, - objectId: null, - groupingType: groupingType || null, - field: 'created_at', - operation: 'count', - startDate: finalStartDate, - endDate: finalEndDate, - interval, - }; - } else { - groupingsTimeSeriesVariables = { - authorId: null, - objectId: stixCoreObjectId, - groupingType: groupingType || null, - field: 'created_at', - operation: 'count', - startDate: finalStartDate, - endDate: finalEndDate, - interval, - }; - } - return ( - { - if (props && props.groupingsTimeSeries) { - const chartData = props.groupingsTimeSeries.map((entry) => ({ - x: new Date(entry.date), - y: entry.value, - })); - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - } - - render() { - const { t, classes, title, variant, height } = this.props; - return ( -
- - {title || t('Groupings history')} - - {variant !== 'inLine' ? ( - - {this.renderContent()} - - ) : ( - this.renderContent() - )} -
- ); - } -} - -StixCoreObjectGroupingsAreaChart.propTypes = { - classes: PropTypes.object, - theme: PropTypes.object, - stixCoreObjectId: PropTypes.string, - authorId: PropTypes.string, - t: PropTypes.func, - md: PropTypes.func, - nsd: PropTypes.func, -}; - -export default compose( - inject18n, - withTheme, - withStyles(styles), -)(StixCoreObjectGroupingsAreaChart); diff --git a/opencti-platform/opencti-front/src/private/components/analyses/groupings/StixCoreObjectGroupingsDonut.jsx b/opencti-platform/opencti-front/src/private/components/analyses/groupings/StixCoreObjectGroupingsDonut.jsx deleted file mode 100644 index 15c6a291c4e6..000000000000 --- a/opencti-platform/opencti-front/src/private/components/analyses/groupings/StixCoreObjectGroupingsDonut.jsx +++ /dev/null @@ -1,162 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import * as R from 'ramda'; -import { graphql } from 'react-relay'; -import withTheme from '@mui/styles/withTheme'; -import withStyles from '@mui/styles/withStyles'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import inject18n from '../../../../components/i18n'; -import { donutChartOptions } from '../../../../utils/Charts'; - -const styles = () => ({ - paper: { - height: 300, - minHeight: 300, - maxHeight: 300, - margin: '10px 0 0 0', - padding: 0, - borderRadius: 4, - }, -}); - -const stixCoreObjectGroupingsDonutDistributionQuery = graphql` - query StixCoreObjectGroupingsDonutDistributionQuery( - $objectId: String - $field: String! - $operation: StatsOperation! - $limit: Int - ) { - groupingsDistribution( - objectId: $objectId - field: $field - operation: $operation - limit: $limit - ) { - label - value - entity { - ... on Identity { - name - } - ... on Malware { - name - } - } - } - } -`; - -class StixCoreObjectGroupingsDonut extends Component { - renderContent() { - const { t, stixCoreObjectId, field, theme } = this.props; - const groupingsDistributionVariables = { - objectId: stixCoreObjectId, - field: field || 'grouping_types', - operation: 'count', - limit: 8, - }; - return ( - { - if ( - props - && props.groupingsDistribution - && props.groupingsDistribution.length > 0 - ) { - let data = props.groupingsDistribution; - if (field && field.includes('internal_id')) { - data = R.map( - (n) => R.assoc('label', n.entity.name, n), - props.groupingsDistribution, - ); - } - const chartData = data.map((n) => n.value); - const labels = data.map((n) => n.label); - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - } - - render() { - const { t, classes, title, variant, height } = this.props; - return ( -
- - {title || t('Groupings distribution')} - - {variant !== 'inLine' ? ( - - {this.renderContent()} - - ) : ( - this.renderContent() - )} -
- ); - } -} - -StixCoreObjectGroupingsDonut.propTypes = { - stixCoreObjectId: PropTypes.string, - title: PropTypes.string, - field: PropTypes.string, - classes: PropTypes.object, - theme: PropTypes.object, - t: PropTypes.func, -}; - -export default R.compose( - inject18n, - withTheme, - withStyles(styles), -)(StixCoreObjectGroupingsDonut); diff --git a/opencti-platform/opencti-front/src/private/components/analyses/groupings/StixCoreObjectGroupingsHorizontalBars.jsx b/opencti-platform/opencti-front/src/private/components/analyses/groupings/StixCoreObjectGroupingsHorizontalBars.jsx deleted file mode 100644 index 5063739ddfd0..000000000000 --- a/opencti-platform/opencti-front/src/private/components/analyses/groupings/StixCoreObjectGroupingsHorizontalBars.jsx +++ /dev/null @@ -1,162 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose } from 'ramda'; -import { graphql } from 'react-relay'; -import withTheme from '@mui/styles/withTheme'; -import withStyles from '@mui/styles/withStyles'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import inject18n from '../../../../components/i18n'; -import { horizontalBarsChartOptions } from '../../../../utils/Charts'; -import { simpleNumberFormat } from '../../../../utils/Number'; - -const styles = () => ({ - paper: { - height: 300, - minHeight: 300, - maxHeight: 300, - margin: '10px 0 0 0', - padding: '0 10px 0 0', - borderRadius: 4, - }, -}); - -const stixCoreObjectGroupingsHorizontalBarsDistributionQuery = graphql` - query StixCoreObjectGroupingsHorizontalBarsDistributionQuery( - $objectId: String - $field: String! - $operation: StatsOperation! - $limit: Int - ) { - groupingsDistribution( - objectId: $objectId - field: $field - operation: $operation - limit: $limit - ) { - label - value - entity { - ... on Identity { - name - } - } - } - } -`; - -class StixCoreObjectGroupingsHorizontalBars extends Component { - renderContent() { - const { t, stixCoreObjectId, field, theme } = this.props; - const groupingsDistributionVariables = { - objectId: stixCoreObjectId, - field: field || 'context', - operation: 'count', - limit: 8, - }; - return ( - { - if ( - props - && props.groupingsDistribution - && props.groupingsDistribution.length > 0 - ) { - const data = props.groupingsDistribution.map((n) => ({ - x: n.entity.name, - y: n.value, - })); - const chartData = [{ name: t('Number of groupings'), data }]; - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - } - - render() { - const { t, classes, title, variant, height } = this.props; - return ( -
- - {title || t('Groupings distribution')} - - {variant !== 'inLine' ? ( - - {this.renderContent()} - - ) : ( - this.renderContent() - )} -
- ); - } -} - -StixCoreObjectGroupingsHorizontalBars.propTypes = { - stixCoreObjectId: PropTypes.string, - title: PropTypes.string, - field: PropTypes.string, - theme: PropTypes.object, - classes: PropTypes.object, - t: PropTypes.func, -}; - -export default compose( - inject18n, - withTheme, - withStyles(styles), -)(StixCoreObjectGroupingsHorizontalBars); diff --git a/opencti-platform/opencti-front/src/private/components/analyses/groupings/StixCoreObjectGroupingsVerticalBars.jsx b/opencti-platform/opencti-front/src/private/components/analyses/groupings/StixCoreObjectGroupingsVerticalBars.jsx deleted file mode 100644 index 169a8c5af91c..000000000000 --- a/opencti-platform/opencti-front/src/private/components/analyses/groupings/StixCoreObjectGroupingsVerticalBars.jsx +++ /dev/null @@ -1,200 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose } from 'ramda'; -import { graphql } from 'react-relay'; -import withStyles from '@mui/styles/withStyles'; -import withTheme from '@mui/styles/withTheme'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import inject18n from '../../../../components/i18n'; -import { monthsAgo, now } from '../../../../utils/Time'; -import { verticalBarsChartOptions } from '../../../../utils/Charts'; -import { simpleNumberFormat } from '../../../../utils/Number'; - -const styles = () => ({ - paper: { - minHeight: 280, - height: '100%', - margin: '4px 0 0 0', - padding: '0 0 10px 0', - borderRadius: 4, - }, - chip: { - fontSize: 10, - height: 20, - marginLeft: 10, - }, -}); - -const stixCoreObjectReporstVerticalBarsTimeSeriesQuery = graphql` - query StixCoreObjectGroupingsVerticalBarsTimeSeriesQuery( - $objectId: String - $authorId: String - $groupingClass: String - $field: String! - $operation: StatsOperation! - $startDate: DateTime! - $endDate: DateTime! - $interval: String! - ) { - groupingsTimeSeries( - objectId: $objectId - authorId: $authorId - groupingType: $groupingClass - field: $field - operation: $operation - startDate: $startDate - endDate: $endDate - interval: $interval - ) { - date - value - } - } -`; - -class GroupingsVerticalBars extends Component { - renderContent() { - const { - t, - fsd, - groupingType, - startDate, - endDate, - stixCoreObjectId, - authorId, - theme, - } = this.props; - const interval = 'day'; - const finalStartDate = startDate || monthsAgo(12); - const finalEndDate = endDate || now(); - let groupingsTimeSeriesVariables; - if (authorId) { - groupingsTimeSeriesVariables = { - authorId, - objectId: null, - groupingType: groupingType || null, - field: 'created_at', - operation: 'count', - startDate: finalStartDate, - endDate: finalEndDate, - interval, - }; - } else { - groupingsTimeSeriesVariables = { - authorId: null, - objectId: stixCoreObjectId, - groupingType: groupingType || null, - field: 'created_at', - operation: 'count', - startDate: finalStartDate, - endDate: finalEndDate, - interval, - }; - } - return ( - { - if (props && props.groupingsTimeSeries) { - const chartData = props.groupingsTimeSeries.map((entry) => ({ - x: new Date(entry.date), - y: entry.value, - })); - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - } - - render() { - const { t, classes, title, variant, height } = this.props; - return ( -
- - {title || t('Groupings history')} - - {variant !== 'inLine' ? ( - - {this.renderContent()} - - ) : ( - this.renderContent() - )} -
- ); - } -} - -GroupingsVerticalBars.propTypes = { - classes: PropTypes.object, - theme: PropTypes.object, - stixCoreObjectId: PropTypes.string, - authorId: PropTypes.string, - t: PropTypes.func, - md: PropTypes.func, -}; - -export default compose( - inject18n, - withTheme, - withStyles(styles), -)(GroupingsVerticalBars); diff --git a/opencti-platform/opencti-front/src/private/components/analyses/malware_analyses/Root.tsx b/opencti-platform/opencti-front/src/private/components/analyses/malware_analyses/Root.tsx index 4bd93e245354..9fb80ca704b0 100644 --- a/opencti-platform/opencti-front/src/private/components/analyses/malware_analyses/Root.tsx +++ b/opencti-platform/opencti-front/src/private/components/analyses/malware_analyses/Root.tsx @@ -24,7 +24,7 @@ import StixCoreObjectHistory from '../../common/stix_core_objects/StixCoreObject import StixCoreRelationship from '../../common/stix_core_relationships/StixCoreRelationship'; import { useFormatter } from '../../../../components/i18n'; import Breadcrumbs from '../../../../components/Breadcrumbs'; -import { defaultValue } from '../../../../utils/Graph'; +import { getMainRepresentative } from '../../../../utils/defaultRepresentatives'; const subscription = graphql` subscription RootMalwareAnalysisSubscription($id: ID!) { @@ -92,7 +92,7 @@ const RootMalwareAnalysis = () => { keyword === '' - || (defaultValue(n) || '').toLowerCase().indexOf(keyword.toLowerCase()) + || (getMainRepresentative(n) || '').toLowerCase().indexOf(keyword.toLowerCase()) !== -1 - || (defaultSecondaryValue(n) || '') + || (getSecondaryRepresentative(n) || '') .toLowerCase() .indexOf(keyword.toLowerCase()) !== -1 || (n.entity_type || '').toLowerCase().indexOf(keyword.toLowerCase()) diff --git a/opencti-platform/opencti-front/src/private/components/analyses/reports/ReportKnowledgeTimeLine.jsx b/opencti-platform/opencti-front/src/private/components/analyses/reports/ReportKnowledgeTimeLine.jsx index c60d112fab02..e2da68fd10a7 100644 --- a/opencti-platform/opencti-front/src/private/components/analyses/reports/ReportKnowledgeTimeLine.jsx +++ b/opencti-platform/opencti-front/src/private/components/analyses/reports/ReportKnowledgeTimeLine.jsx @@ -11,7 +11,7 @@ import TimelineConnector from '@mui/lab/TimelineConnector'; import TimelineContent from '@mui/lab/TimelineContent'; import Paper from '@mui/material/Paper'; import Typography from '@mui/material/Typography'; -import { defaultSecondaryValue, defaultValue } from '../../../../utils/Graph'; +import { getSecondaryRepresentative, getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import ItemIcon from '../../../../components/ItemIcon'; import { resolveLink } from '../../../../utils/Entity'; import { useFormatter } from '../../../../components/i18n'; @@ -99,10 +99,10 @@ const ReportKnowledgeTimeLineComponent = ({ - {defaultValue(node)} + {getMainRepresentative(node)}
diff --git a/opencti-platform/opencti-front/src/private/components/analyses/reports/ReportsAreaChart.jsx b/opencti-platform/opencti-front/src/private/components/analyses/reports/ReportsAreaChart.jsx deleted file mode 100644 index 051097c87690..000000000000 --- a/opencti-platform/opencti-front/src/private/components/analyses/reports/ReportsAreaChart.jsx +++ /dev/null @@ -1,167 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose } from 'ramda'; -import { graphql } from 'react-relay'; -import withStyles from '@mui/styles/withStyles'; -import withTheme from '@mui/styles/withTheme'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import inject18n from '../../../../components/i18n'; -import { monthsAgo, now } from '../../../../utils/Time'; -import { areaChartOptions } from '../../../../utils/Charts'; -import { simpleNumberFormat } from '../../../../utils/Number'; - -const styles = () => ({ - paper: { - minHeight: 280, - height: '100%', - margin: '4px 0 0 0', - padding: '0 0 10px 0', - borderRadius: 4, - }, - chip: { - fontSize: 10, - height: 20, - marginLeft: 10, - }, -}); - -const reportsAreaChartTimeSeriesQuery = graphql` - query ReportsAreaChartTimeSeriesQuery( - $field: String! - $operation: StatsOperation! - $startDate: DateTime! - $endDate: DateTime! - $interval: String! - ) { - reportsTimeSeries( - field: $field - operation: $operation - startDate: $startDate - endDate: $endDate - interval: $interval - ) { - date - value - } - } -`; - -class ReportsAreaChart extends Component { - renderContent() { - const { t, fsd, reportType, startDate, endDate, theme } = this.props; - const interval = 'day'; - const finalStartDate = startDate || monthsAgo(12); - const finalEndDate = endDate || now(); - const reportsTimeSeriesVariables = { - reportType: reportType || null, - field: 'created_at', - operation: 'count', - startDate: finalStartDate, - endDate: finalEndDate, - interval, - }; - return ( - { - if (props && props.reportsTimeSeries) { - const chartData = props.reportsTimeSeries.map((entry) => ({ - x: new Date(entry.date), - y: entry.value, - })); - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - } - - render() { - const { t, classes, title, variant, height } = this.props; - return ( -
- - {title || t('Reports distribution')} - - {variant !== 'inLine' ? ( - - {this.renderContent()} - - ) : ( - this.renderContent() - )} -
- ); - } -} - -ReportsAreaChart.propTypes = { - classes: PropTypes.object, - theme: PropTypes.object, - t: PropTypes.func, - md: PropTypes.func, -}; - -export default compose( - inject18n, - withTheme, - withStyles(styles), -)(ReportsAreaChart); diff --git a/opencti-platform/opencti-front/src/private/components/analyses/reports/ReportsDonut.jsx b/opencti-platform/opencti-front/src/private/components/analyses/reports/ReportsDonut.jsx deleted file mode 100644 index 6dca43294782..000000000000 --- a/opencti-platform/opencti-front/src/private/components/analyses/reports/ReportsDonut.jsx +++ /dev/null @@ -1,160 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose } from 'ramda'; -import { graphql } from 'react-relay'; -import withTheme from '@mui/styles/withTheme'; -import withStyles from '@mui/styles/withStyles'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import * as R from 'ramda'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import inject18n from '../../../../components/i18n'; -import { donutChartOptions } from '../../../../utils/Charts'; - -const styles = () => ({ - paper: { - height: 300, - minHeight: 300, - maxHeight: 300, - margin: '10px 0 0 0', - padding: 0, - borderRadius: 4, - }, -}); - -const reportsDonutDistributionQuery = graphql` - query ReportsDonutDistributionQuery( - $field: String! - $operation: StatsOperation! - $limit: Int - $startDate: DateTime - $endDate: DateTime - ) { - reportsDistribution( - field: $field - operation: $operation - limit: $limit - startDate: $startDate - endDate: $endDate - ) { - label - value - entity { - ... on Identity { - name - } - } - } - } -`; - -class ReportsDonut extends Component { - renderContent() { - const { t, field, startDate, endDate, theme } = this.props; - const reportsDistributionVariables = { - field: field || 'report_types', - operation: 'count', - limit: 8, - startDate, - endDate, - }; - return ( - { - if ( - props - && props.reportsDistribution - && props.reportsDistribution.length > 0 - ) { - let data = props.reportsDistribution; - if (field && field.includes('internal_id')) { - data = R.map( - (n) => R.assoc('label', n.entity.name, n), - props.reportsDistribution, - ); - } - const chartData = data.map((n) => n.value); - const labels = data.map((n) => n.label); - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - } - - render() { - const { t, classes, title, variant, height } = this.props; - return ( -
- - {title || t('Reports distribution')} - - {variant !== 'inLine' ? ( - - {this.renderContent()} - - ) : ( - this.renderContent() - )} -
- ); - } -} - -ReportsDonut.propTypes = { - title: PropTypes.string, - field: PropTypes.string, - startDate: PropTypes.string, - endDate: PropTypes.string, - classes: PropTypes.object, - theme: PropTypes.object, - t: PropTypes.func, -}; - -export default compose(inject18n, withTheme, withStyles(styles))(ReportsDonut); diff --git a/opencti-platform/opencti-front/src/private/components/analyses/reports/ReportsHorizontalBars.jsx b/opencti-platform/opencti-front/src/private/components/analyses/reports/ReportsHorizontalBars.jsx deleted file mode 100644 index df5822db5aa2..000000000000 --- a/opencti-platform/opencti-front/src/private/components/analyses/reports/ReportsHorizontalBars.jsx +++ /dev/null @@ -1,166 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose } from 'ramda'; -import { graphql } from 'react-relay'; -import withTheme from '@mui/styles/withTheme'; -import withStyles from '@mui/styles/withStyles'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import inject18n from '../../../../components/i18n'; -import { horizontalBarsChartOptions } from '../../../../utils/Charts'; -import { simpleNumberFormat } from '../../../../utils/Number'; - -const styles = () => ({ - paper: { - height: 300, - minHeight: 300, - maxHeight: 300, - margin: '10px 0 0 0', - padding: 0, - borderRadius: 4, - }, -}); - -const reportsHorizontalBarsDistributionQuery = graphql` - query ReportsHorizontalBarsDistributionQuery( - $field: String! - $operation: StatsOperation! - $limit: Int - $startDate: DateTime - $endDate: DateTime - ) { - reportsDistribution( - field: $field - operation: $operation - limit: $limit - startDate: $startDate - endDate: $endDate - ) { - label - value - entity { - ... on Identity { - name - } - } - } - } -`; - -class ReportsHorizontalBars extends Component { - renderContent() { - const { t, field, startDate, endDate, theme } = this.props; - const reportsDistributionVariables = { - field: field || 'report_types', - operation: 'count', - limit: 8, - startDate, - endDate, - }; - return ( - { - if ( - props - && props.reportsDistribution - && props.reportsDistribution.length > 0 - ) { - const data = props.reportsDistribution.map((n) => ({ - x: n.entity.name, - y: n.value, - })); - const chartData = [{ name: t('Number of reports'), data }]; - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - } - - render() { - const { t, classes, title, variant, height } = this.props; - return ( -
- - {title || t('Reports distribution')} - - {variant !== 'inLine' ? ( - - {this.renderContent()} - - ) : ( - this.renderContent() - )} -
- ); - } -} - -ReportsHorizontalBars.propTypes = { - title: PropTypes.string, - field: PropTypes.string, - startDate: PropTypes.string, - endDate: PropTypes.string, - classes: PropTypes.object, - theme: PropTypes.object, - t: PropTypes.func, -}; - -export default compose( - inject18n, - withTheme, - withStyles(styles), -)(ReportsHorizontalBars); diff --git a/opencti-platform/opencti-front/src/private/components/analyses/reports/ReportsVerticalBars.jsx b/opencti-platform/opencti-front/src/private/components/analyses/reports/ReportsVerticalBars.jsx deleted file mode 100644 index 631e10388e7a..000000000000 --- a/opencti-platform/opencti-front/src/private/components/analyses/reports/ReportsVerticalBars.jsx +++ /dev/null @@ -1,167 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose } from 'ramda'; -import { graphql } from 'react-relay'; -import withTheme from '@mui/styles/withTheme'; -import withStyles from '@mui/styles/withStyles'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import inject18n from '../../../../components/i18n'; -import { monthsAgo, now } from '../../../../utils/Time'; -import { verticalBarsChartOptions } from '../../../../utils/Charts'; -import { simpleNumberFormat } from '../../../../utils/Number'; - -const styles = () => ({ - paper: { - minHeight: 280, - height: '100%', - margin: '4px 0 0 0', - padding: '0 0 10px 0', - borderRadius: 4, - }, - chip: { - fontSize: 10, - height: 20, - marginLeft: 10, - }, -}); - -const reporstVerticalBarsTimeSeriesQuery = graphql` - query ReportsVerticalBarsTimeSeriesQuery( - $field: String! - $operation: StatsOperation! - $startDate: DateTime! - $endDate: DateTime! - $interval: String! - ) { - reportsTimeSeries( - field: $field - operation: $operation - startDate: $startDate - endDate: $endDate - interval: $interval - ) { - date - value - } - } -`; - -class ReportsVerticalBars extends Component { - renderContent() { - const { t, fsd, reportType, startDate, endDate, theme } = this.props; - const interval = 'day'; - const finalStartDate = startDate || monthsAgo(12); - const finalEndDate = endDate || now(); - const reportsTimeSeriesVariables = { - reportType: reportType || null, - field: 'created_at', - operation: 'count', - startDate: finalStartDate, - endDate: finalEndDate, - interval, - }; - return ( - { - if (props && props.reportsTimeSeries) { - const chartData = props.reportsTimeSeries.map((entry) => ({ - x: new Date(entry.date), - y: entry.value, - })); - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - } - - render() { - const { t, classes, title, variant, height } = this.props; - return ( -
- - {title || t('Reports history')} - - {variant !== 'inLine' ? ( - - {this.renderContent()} - - ) : ( - this.renderContent() - )} -
- ); - } -} - -ReportsVerticalBars.propTypes = { - classes: PropTypes.object, - theme: PropTypes.object, - t: PropTypes.func, - md: PropTypes.func, -}; - -export default compose( - inject18n, - withTheme, - withStyles(styles), -)(ReportsVerticalBars); diff --git a/opencti-platform/opencti-front/src/private/components/analyses/reports/StixCoreObjectReportsHorizontalBars.jsx b/opencti-platform/opencti-front/src/private/components/analyses/reports/StixCoreObjectReportsHorizontalBars.jsx index 25c91e5d2971..16f93bd7ccbf 100644 --- a/opencti-platform/opencti-front/src/private/components/analyses/reports/StixCoreObjectReportsHorizontalBars.jsx +++ b/opencti-platform/opencti-front/src/private/components/analyses/reports/StixCoreObjectReportsHorizontalBars.jsx @@ -12,6 +12,7 @@ import { QueryRenderer } from '../../../../relay/environment'; import inject18n from '../../../../components/i18n'; import { horizontalBarsChartOptions } from '../../../../utils/Charts'; import { simpleNumberFormat } from '../../../../utils/Number'; +import { getMainRepresentative } from '../../../../utils/defaultRepresentatives'; const styles = () => ({ paper: { @@ -40,8 +41,10 @@ const stixCoreObjectReportsHorizontalBarsDistributionQuery = graphql` label value entity { - ... on Identity { - name + ... on StixObject { + representative { + main + } } } } @@ -68,7 +71,7 @@ class StixCoreObjectReportsHorizontalBars extends Component { && props.reportsDistribution.length > 0 ) { const data = props.reportsDistribution.map((n) => ({ - x: n.entity.name, + x: getMainRepresentative(n.entity) || n.label, y: n.value, })); const chartData = [{ name: t('Number of reports'), data }]; diff --git a/opencti-platform/opencti-front/src/private/components/cases/case_incidents/IncidentKnowledgeGraph.jsx b/opencti-platform/opencti-front/src/private/components/cases/case_incidents/IncidentKnowledgeGraph.jsx index 38b10cef0a4e..abcb04cd2f4f 100644 --- a/opencti-platform/opencti-front/src/private/components/cases/case_incidents/IncidentKnowledgeGraph.jsx +++ b/opencti-platform/opencti-front/src/private/components/cases/case_incidents/IncidentKnowledgeGraph.jsx @@ -26,14 +26,13 @@ import { computeTimeRangeInterval, computeTimeRangeValues, decodeGraphData, - defaultSecondaryValue, - defaultValue, encodeGraphData, linkPaint, nodeAreaPaint, nodePaint, nodeThreePaint, } from '../../../../utils/Graph'; +import { getSecondaryRepresentative, getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import EntitiesDetailsRightsBar from '../../../../utils/graph/EntitiesDetailsRightBar'; import LassoSelection from '../../../../utils/graph/LassoSelection'; import { buildViewParamsFromUrlAndStorage, saveViewParameters } from '../../../../utils/ListParameters'; @@ -958,9 +957,9 @@ class IncidentKnowledgeGraphComponent extends Component { this.selectedNodes.clear(); if (isNotEmptyField(keyword)) { const filterByKeyword = (n) => keyword === '' - || (defaultValue(n) || '').toLowerCase().indexOf(keyword.toLowerCase()) + || (getMainRepresentative(n) || '').toLowerCase().indexOf(keyword.toLowerCase()) !== -1 - || (defaultSecondaryValue(n) || '') + || (getSecondaryRepresentative(n) || '') .toLowerCase() .indexOf(keyword.toLowerCase()) !== -1 || (n.entity_type || '').toLowerCase().indexOf(keyword.toLowerCase()) diff --git a/opencti-platform/opencti-front/src/private/components/cases/case_incidents/IncidentKnowledgeTimeLine.jsx b/opencti-platform/opencti-front/src/private/components/cases/case_incidents/IncidentKnowledgeTimeLine.jsx index e31b10ff7a71..d0f96270d9d9 100644 --- a/opencti-platform/opencti-front/src/private/components/cases/case_incidents/IncidentKnowledgeTimeLine.jsx +++ b/opencti-platform/opencti-front/src/private/components/cases/case_incidents/IncidentKnowledgeTimeLine.jsx @@ -11,7 +11,7 @@ import TimelineConnector from '@mui/lab/TimelineConnector'; import TimelineContent from '@mui/lab/TimelineContent'; import Paper from '@mui/material/Paper'; import Typography from '@mui/material/Typography'; -import { defaultSecondaryValue, defaultValue } from '../../../../utils/Graph'; +import { getSecondaryRepresentative, getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import ItemIcon from '../../../../components/ItemIcon'; import { resolveLink } from '../../../../utils/Entity'; import { useFormatter } from '../../../../components/i18n'; @@ -99,10 +99,10 @@ const IncidentKnowledgeTimeLineComponent = ({ - {defaultValue(node)} + {getMainRepresentative(node)}
diff --git a/opencti-platform/opencti-front/src/private/components/cases/case_rfis/CaseRfiKnowledgeGraph.jsx b/opencti-platform/opencti-front/src/private/components/cases/case_rfis/CaseRfiKnowledgeGraph.jsx index ffa9f748c266..6a54105c27b7 100644 --- a/opencti-platform/opencti-front/src/private/components/cases/case_rfis/CaseRfiKnowledgeGraph.jsx +++ b/opencti-platform/opencti-front/src/private/components/cases/case_rfis/CaseRfiKnowledgeGraph.jsx @@ -26,14 +26,13 @@ import { computeTimeRangeInterval, computeTimeRangeValues, decodeGraphData, - defaultSecondaryValue, - defaultValue, encodeGraphData, linkPaint, nodeAreaPaint, nodePaint, nodeThreePaint, } from '../../../../utils/Graph'; +import { getSecondaryRepresentative, getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import EntitiesDetailsRightsBar from '../../../../utils/graph/EntitiesDetailsRightBar'; import LassoSelection from '../../../../utils/graph/LassoSelection'; import { buildViewParamsFromUrlAndStorage, saveViewParameters } from '../../../../utils/ListParameters'; @@ -958,9 +957,9 @@ class CaseRfiKnowledgeGraphComponent extends Component { this.selectedNodes.clear(); if (isNotEmptyField(keyword)) { const filterByKeyword = (n) => keyword === '' - || (defaultValue(n) || '').toLowerCase().indexOf(keyword.toLowerCase()) + || (getMainRepresentative(n) || '').toLowerCase().indexOf(keyword.toLowerCase()) !== -1 - || (defaultSecondaryValue(n) || '') + || (getSecondaryRepresentative(n) || '') .toLowerCase() .indexOf(keyword.toLowerCase()) !== -1 || (n.entity_type || '').toLowerCase().indexOf(keyword.toLowerCase()) diff --git a/opencti-platform/opencti-front/src/private/components/cases/case_rfis/CaseRfiKnowledgeTimeLine.jsx b/opencti-platform/opencti-front/src/private/components/cases/case_rfis/CaseRfiKnowledgeTimeLine.jsx index 0532ebc394dc..9d90f6063690 100644 --- a/opencti-platform/opencti-front/src/private/components/cases/case_rfis/CaseRfiKnowledgeTimeLine.jsx +++ b/opencti-platform/opencti-front/src/private/components/cases/case_rfis/CaseRfiKnowledgeTimeLine.jsx @@ -11,7 +11,7 @@ import TimelineConnector from '@mui/lab/TimelineConnector'; import TimelineContent from '@mui/lab/TimelineContent'; import Paper from '@mui/material/Paper'; import Typography from '@mui/material/Typography'; -import { defaultSecondaryValue, defaultValue } from '../../../../utils/Graph'; +import { getSecondaryRepresentative, getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import ItemIcon from '../../../../components/ItemIcon'; import { resolveLink } from '../../../../utils/Entity'; import { useFormatter } from '../../../../components/i18n'; @@ -99,10 +99,10 @@ const CaseRfiKnowledgeTimeLineComponent = ({ - {defaultValue(node)} + {getMainRepresentative(node)}
diff --git a/opencti-platform/opencti-front/src/private/components/cases/case_rfts/CaseRftKnowledgeGraph.jsx b/opencti-platform/opencti-front/src/private/components/cases/case_rfts/CaseRftKnowledgeGraph.jsx index b9089f09bc79..93806e838fc1 100644 --- a/opencti-platform/opencti-front/src/private/components/cases/case_rfts/CaseRftKnowledgeGraph.jsx +++ b/opencti-platform/opencti-front/src/private/components/cases/case_rfts/CaseRftKnowledgeGraph.jsx @@ -26,14 +26,13 @@ import { computeTimeRangeInterval, computeTimeRangeValues, decodeGraphData, - defaultSecondaryValue, - defaultValue, encodeGraphData, linkPaint, nodeAreaPaint, nodePaint, nodeThreePaint, } from '../../../../utils/Graph'; +import { getSecondaryRepresentative, getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import EntitiesDetailsRightsBar from '../../../../utils/graph/EntitiesDetailsRightBar'; import LassoSelection from '../../../../utils/graph/LassoSelection'; import { buildViewParamsFromUrlAndStorage, saveViewParameters } from '../../../../utils/ListParameters'; @@ -957,9 +956,9 @@ class CaseRftKnowledgeGraphComponent extends Component { this.selectedNodes.clear(); if (isNotEmptyField(keyword)) { const filterByKeyword = (n) => keyword === '' - || (defaultValue(n) || '').toLowerCase().indexOf(keyword.toLowerCase()) + || (getMainRepresentative(n) || '').toLowerCase().indexOf(keyword.toLowerCase()) !== -1 - || (defaultSecondaryValue(n) || '') + || (getSecondaryRepresentative(n) || '') .toLowerCase() .indexOf(keyword.toLowerCase()) !== -1 || (n.entity_type || '').toLowerCase().indexOf(keyword.toLowerCase()) diff --git a/opencti-platform/opencti-front/src/private/components/cases/case_rfts/CaseRftKnowledgeTimeLine.jsx b/opencti-platform/opencti-front/src/private/components/cases/case_rfts/CaseRftKnowledgeTimeLine.jsx index caa393b384fb..81a972e4b790 100644 --- a/opencti-platform/opencti-front/src/private/components/cases/case_rfts/CaseRftKnowledgeTimeLine.jsx +++ b/opencti-platform/opencti-front/src/private/components/cases/case_rfts/CaseRftKnowledgeTimeLine.jsx @@ -11,7 +11,7 @@ import TimelineConnector from '@mui/lab/TimelineConnector'; import TimelineContent from '@mui/lab/TimelineContent'; import Paper from '@mui/material/Paper'; import Typography from '@mui/material/Typography'; -import { defaultSecondaryValue, defaultValue } from '../../../../utils/Graph'; +import { getSecondaryRepresentative, getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import ItemIcon from '../../../../components/ItemIcon'; import { resolveLink } from '../../../../utils/Entity'; import { useFormatter } from '../../../../components/i18n'; @@ -99,10 +99,10 @@ const CaseRftKnowledgeTimeLineComponent = ({ - {defaultValue(node)} + {getMainRepresentative(node)}
diff --git a/opencti-platform/opencti-front/src/private/components/common/audits/AuditsDistributionList.jsx b/opencti-platform/opencti-front/src/private/components/common/audits/AuditsDistributionList.jsx index 4ee8c0a11c2f..858474f1f332 100644 --- a/opencti-platform/opencti-front/src/private/components/common/audits/AuditsDistributionList.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/audits/AuditsDistributionList.jsx @@ -17,7 +17,7 @@ import React from 'react'; import { graphql } from 'react-relay'; import { QueryRenderer } from '../../../../relay/environment'; import { useFormatter } from '../../../../components/i18n'; -import { defaultValue } from '../../../../utils/Graph'; +import { getMainRepresentative, isFieldForIdentifier } from '../../../../utils/defaultRepresentatives'; import useGranted, { SETTINGS, SETTINGS_SETACCESSES } from '../../../../utils/hooks/useGranted'; import useEnterpriseEdition from '../../../../utils/hooks/useEnterpriseEdition'; import WidgetContainer from '../../../../components/dashboard/WidgetContainer'; @@ -54,147 +54,27 @@ const auditsDistributionListDistributionQuery = graphql` value entity { ... on BasicObject { - entity_type id + entity_type } ... on BasicRelationship { - entity_type id + entity_type } - ... on AttackPattern { - name - description - } - ... on Campaign { - name - description - } - ... on CourseOfAction { - name - description - } - ... on Individual { - name - description - } - ... on Organization { - name - description - } - ... on Sector { - name - description - } - ... on System { - name - description - } - ... on Indicator { - name - description - } - ... on Infrastructure { - name - description - } - ... on IntrusionSet { - name - description - } - ... on Position { - name - description - } - ... on City { - name - description - } - ... on AdministrativeArea { - name - description - } - ... on Country { - name - description - } - ... on Region { - name - description - } - ... on Malware { - name - description - } - ... on MalwareAnalysis { - result_name - } - ... on ThreatActor { - name - description - } - ... on Tool { - name - description - } - ... on Vulnerability { - name - description - } - ... on Incident { - name - description - } - ... on Event { - name - description - } - ... on Channel { - name - description - } - ... on Narrative { - name - description - } - ... on Language { - name - } - ... on DataComponent { - name - } - ... on DataSource { - name - } - ... on Case { - name - } - ... on Task { - name - } - ... on StixCyberObservable { - observable_value + ... on StixObject { + representative { + main + } } - ... on MarkingDefinition { - definition_type - definition + ... on StixRelationship { + representative { + main + } } + # objects without representative ... on Creator { - entity_type - name - } - ... on Report { name } - ... on Grouping { - name - } - ... on Note { - attribute_abstract - content - } - ... on Opinion { - opinion - } ... on Group { name } @@ -258,30 +138,24 @@ const AuditsDistributionList = ({ && props.auditsDistribution && props.auditsDistribution.length > 0 ) { - const data = props.auditsDistribution.map((o) => ({ - label: - // eslint-disable-next-line no-nested-ternary - selection.attribute.endsWith('.id') - || selection.attribute.endsWith('_id') - || selection.attribute.endsWith('_ids') - ? defaultValue(o.entity) - : selection.attribute === 'entity_type' - ? t_i18n(`entity_${o.label}`) - : o.label, - value: o.value, - id: - selection.attribute.endsWith('.id') - || selection.attribute.endsWith('_id') - || selection.attribute.endsWith('_ids') - ? o.entity.id - : null, - type: - selection.attribute.endsWith('.id') - || selection.attribute.endsWith('_id') - || selection.attribute.endsWith('_ids') - ? o.entity.entity_type - : o.label, - })); + const data = props.auditsDistribution.map((n) => { + let { label } = n; + let id = null; + let type = n.label; + if (isFieldForIdentifier(selection.attribute)) { + label = getMainRepresentative(n.entity) || n.label; + id = n.entity?.id; + type = n.entity?.entity_type; + } else if (selection.attribute === 'entity_type' && t_i18n(`entity_${n.label}`) !== `entity_${n.label}`) { + label = t_i18n(`entity_${n.label}`); + } + return { + label, + value: n.value, + id, + type, + }; + }); return ; } if (props) { diff --git a/opencti-platform/opencti-front/src/private/components/common/audits/AuditsDonut.jsx b/opencti-platform/opencti-front/src/private/components/common/audits/AuditsDonut.jsx index f610b07e1a98..34d06faaffdb 100644 --- a/opencti-platform/opencti-front/src/private/components/common/audits/AuditsDonut.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/audits/AuditsDonut.jsx @@ -54,125 +54,19 @@ const auditsDonutDistributionQuery = graphql` value entity { ... on BasicObject { + id entity_type } ... on BasicRelationship { + id entity_type } - ... on AttackPattern { - name - description - } - ... on Campaign { - name - description - } - ... on CourseOfAction { - name - description - } - ... on Individual { - name - description - } - ... on Organization { - name - description - } - ... on Sector { - name - description - } - ... on System { - name - description - } - ... on Indicator { - name - description - } - ... on Infrastructure { - name - description - } - ... on IntrusionSet { - name - description - } - ... on Position { - name - description - } - ... on City { - name - description - } - ... on AdministrativeArea { - name - description - } - ... on Country { - name - description - } - ... on Region { - name - description - } - ... on Malware { - name - description - } - ... on MalwareAnalysis { - result_name - } - ... on ThreatActor { - name - description - } - ... on Tool { - name - description - } - ... on Vulnerability { - name - description - } - ... on Incident { - name - description - } - ... on Event { - name - description - } - ... on Channel { - name - description - } - ... on Narrative { - name - description - } - ... on Language { - name - } - ... on DataComponent { - name - } - ... on DataSource { - name - } - ... on Case { - name - } - ... on StixCyberObservable { - observable_value - } - ... on MarkingDefinition { - definition_type - definition + ... on StixObject { + representative { + main + } } + # objects without representative ... on Creator { name } diff --git a/opencti-platform/opencti-front/src/private/components/common/audits/AuditsHorizontalBars.jsx b/opencti-platform/opencti-front/src/private/components/common/audits/AuditsHorizontalBars.jsx index d9a57376d9a7..43c4ca955482 100644 --- a/opencti-platform/opencti-front/src/private/components/common/audits/AuditsHorizontalBars.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/audits/AuditsHorizontalBars.jsx @@ -25,11 +25,10 @@ import Chart from '../charts/Chart'; import { QueryRenderer } from '../../../../relay/environment'; import { useFormatter } from '../../../../components/i18n'; import { horizontalBarsChartOptions } from '../../../../utils/Charts'; -import { itemColor } from '../../../../utils/Colors'; import { simpleNumberFormat } from '../../../../utils/Number'; -import { defaultValue } from '../../../../utils/Graph'; import useGranted, { SETTINGS } from '../../../../utils/hooks/useGranted'; import useEnterpriseEdition from '../../../../utils/hooks/useEnterpriseEdition'; +import useDistributionGraphData from '../../../../utils/hooks/useDistributionGraphData'; const useStyles = makeStyles(() => ({ paper: { @@ -69,143 +68,27 @@ const auditsHorizontalBarsDistributionQuery = graphql` value entity { ... on BasicObject { - entity_type id + entity_type } ... on BasicRelationship { - entity_type id + entity_type } - ... on AttackPattern { - name - description - } - ... on Campaign { - name - description - } - ... on CourseOfAction { - name - description - } - ... on Individual { - name - description - } - ... on Organization { - name - description - } - ... on Sector { - name - description - } - ... on System { - name - description - } - ... on Indicator { - name - description - } - ... on Infrastructure { - name - description - } - ... on IntrusionSet { - name - description - } - ... on Position { - name - description - } - ... on City { - name - description - } - ... on AdministrativeArea { - name - description - } - ... on Country { - name - description - } - ... on Region { - name - description - } - ... on Malware { - name - description - } - ... on MalwareAnalysis { - result_name - } - ... on ThreatActor { - name - description - } - ... on Tool { - name - description - } - ... on Vulnerability { - name - description - } - ... on Incident { - name - description - } - ... on Event { - name - description - } - ... on Channel { - name - description - } - ... on Narrative { - name - description - } - ... on Language { - name - } - ... on DataComponent { - name - } - ... on DataSource { - name - } - ... on Case { - name - } - ... on StixCyberObservable { - observable_value + ... on StixObject { + representative { + main + } } - ... on MarkingDefinition { - definition_type - definition + ... on StixRelationship { + representative { + main + } } + # objects without representative ... on Creator { name } - ... on Report { - name - } - ... on Grouping { - name - } - ... on Note { - attribute_abstract - content - } - ... on Opinion { - opinion - } ... on Group { name } @@ -234,6 +117,8 @@ const AuditsHorizontalBars = ({ const navigate = useNavigate(); const isGrantedToSettings = useGranted([SETTINGS]); const isEnterpriseEdition = useEnterpriseEdition(); + const { buildWidgetProps } = useDistributionGraphData(); + const renderContent = () => { if (!isGrantedToSettings || !isEnterpriseEdition) { return ( @@ -277,41 +162,7 @@ const AuditsHorizontalBars = ({ && props.auditsDistribution && props.auditsDistribution.length > 0 ) { - const data = props.auditsDistribution.map((n) => ({ - x: - // eslint-disable-next-line no-nested-ternary - selection.attribute.endsWith('.id') - || selection.attribute.endsWith('_id') - || selection.attribute.endsWith('_ids') - ? defaultValue(n.entity) - : selection.attribute === 'entity_type' - ? t_i18n(`entity_${n.label}`) - : n.label, - y: n.value, - fillColor: - selection.attribute.endsWith('.id') - || selection.attribute.endsWith('_id') - || selection.attribute.endsWith('_ids') - ? itemColor(n.entity.entity_type) - : itemColor(n.label), - })); - const chartData = [ - { - name: selection.label || t_i18n('Number of history entries'), - data, - }, - ]; - const redirectionUtils = selection.attribute.endsWith('.id') - || selection.attribute.endsWith('_id') - || selection.attribute.endsWith('_ids') - ? props.auditsDistribution.map((n) => ({ - id: n.entity.id, - entity_type: - n.entity.entity_type === 'Workspace' - ? n.entity.type - : n.entity.entity_type, - })) - : null; + const { series, redirectionUtils } = buildWidgetProps(props.auditsDistribution, selection, 'Number of history entries'); return ( ({ @@ -102,7 +102,7 @@ const ContainerAddStixCoreObjectsLineComponent = ({ className={classes.bodyItem} style={{ width: dataColumns.value.width }} > - {defaultValue(node)} + {getMainRepresentative(node)}
{ key={object.id} value={object.id} > - {defaultValue(object)} + {getMainRepresentative(object)} ))} @@ -1061,7 +1061,7 @@ const ContainerHeader = (props) => { {enableQuickSubscription && ( @@ -1070,7 +1070,7 @@ const ContainerHeader = (props) => { )} diff --git a/opencti-platform/opencti-front/src/private/components/common/containers/ContainerStixCoreObjectsMappingLine.jsx b/opencti-platform/opencti-front/src/private/components/common/containers/ContainerStixCoreObjectsMappingLine.jsx index 34f894aa2694..f1f71b497be6 100644 --- a/opencti-platform/opencti-front/src/private/components/common/containers/ContainerStixCoreObjectsMappingLine.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/containers/ContainerStixCoreObjectsMappingLine.jsx @@ -16,7 +16,7 @@ import IconButton from '@mui/material/IconButton'; import { useFormatter } from '../../../../components/i18n'; import ItemIcon from '../../../../components/ItemIcon'; import { resolveLink } from '../../../../utils/Entity'; -import { defaultValue } from '../../../../utils/Graph'; +import { getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import ItemMarkings from '../../../../components/ItemMarkings'; import { hexToRGB, itemColor } from '../../../../utils/Colors'; import ContainerStixCoreObjectPopover from './ContainerStixCoreObjectPopover'; @@ -100,7 +100,7 @@ const ContainerStixCoreObjectLineComponent = (props) => { > {node.x_mitre_id ? `[${node.x_mitre_id}] ${node.name}` - : defaultValue(node)} + : getMainRepresentative(node)}
{ > {node.x_mitre_id ? `[${node.x_mitre_id}] ${node.name}` - : defaultValue(node)} + : getMainRepresentative(node)}
({ @@ -109,7 +109,7 @@ const ContainerStixObjectOrStixRelationshipLineComponent = ({ className={classes.bodyItem} style={{ width: dataColumns.name.width }} > - {defaultValue(node)} + {getMainRepresentative(node)}
- {defaultValue(node)} + {getMainRepresentative(node)}
keyword === '' - || (defaultValue(n) || '').toLowerCase().indexOf(keyword.toLowerCase()) + || (getMainRepresentative(n) || '').toLowerCase().indexOf(keyword.toLowerCase()) !== -1 - || (defaultSecondaryValue(n) || '') + || (getSecondaryRepresentative(n) || '') .toLowerCase() .indexOf(keyword.toLowerCase()) !== -1 || (n.entity_type || '').toLowerCase().indexOf(keyword.toLowerCase()) diff --git a/opencti-platform/opencti-front/src/private/components/common/files/workbench/WorkbenchFileContent.jsx b/opencti-platform/opencti-front/src/private/components/common/files/workbench/WorkbenchFileContent.jsx index d37f1b0bee26..a150c96f37c1 100644 --- a/opencti-platform/opencti-front/src/private/components/common/files/workbench/WorkbenchFileContent.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/files/workbench/WorkbenchFileContent.jsx @@ -40,7 +40,7 @@ import SwitchField from '../../../../../components/SwitchField'; import TextField from '../../../../../components/TextField'; import { APP_BASE_PATH, commitMutation, handleError, MESSAGING$, QueryRenderer } from '../../../../../relay/environment'; import { observableValue, resolveIdentityClass, resolveIdentityType, resolveLink, resolveLocationType, resolveThreatActorType } from '../../../../../utils/Entity'; -import { defaultKey, defaultValue } from '../../../../../utils/Graph'; +import { defaultKey, getMainRepresentative } from '../../../../../utils/defaultRepresentatives'; import useAttributes from '../../../../../utils/hooks/useAttributes'; import useVocabularyCategory from '../../../../../utils/hooks/useVocabularyCategory'; import { computeDuplicates, convertFromStixType, convertToStixType, truncate, uniqWithByFields } from '../../../../../utils/String'; @@ -2819,14 +2819,14 @@ const WorkbenchFileContentComponent = ({ n.type === 'relationship' ? t_i18n(`relationship_${n.relationship_type}`) : t_i18n(`entity_${convertFromStixType(n.type)}`), - default_value: defaultValue({ + default_value: getMainRepresentative({ ...n, - source_ref_name: defaultValue( + source_ref_name: getMainRepresentative( indexedStixObjects[n.source_ref] || indexedStixObjects[n.sighting_of_ref] || {}, ), - target_ref_name: defaultValue( + target_ref_name: getMainRepresentative( indexedStixObjects[n.target_ref] || indexedStixObjects[n.where_sighted_refs?.at(0)] || {}, @@ -2998,7 +2998,7 @@ const WorkbenchFileContentComponent = ({ const resolvedStixDomainObjects = stixDomainObjects.map((n) => ({ ...n, ttype: t_i18n(`entity_${convertFromStixType(n.type)}`), - default_value: defaultValue(n, null), + default_value: getMainRepresentative(n, null), markings: resolveMarkings(stixDomainObjects, n.object_marking_refs), })); const sort = R.sortWith( @@ -3241,7 +3241,7 @@ const WorkbenchFileContentComponent = ({ const resolvedStixCyberObservables = stixCyberObservables.map((n) => ({ ...n, ttype: t_i18n(`entity_${convertFromStixType(n.type)}`), - default_value: defaultValue(n, null), + default_value: getMainRepresentative(n, null), markings: resolveMarkings(stixDomainObjects, n.object_marking_refs), })); const sort = R.sortWith( @@ -3481,13 +3481,13 @@ const WorkbenchFileContentComponent = ({ const resolvedStixCoreRelationships = stixCoreRelationships.map((n) => ({ ...n, ttype: t_i18n(`relationship_${n.relationship_type}`), - default_value: defaultValue({ + default_value: getMainRepresentative({ ...n, - source_ref_name: defaultValue(indexedStixObjects[n.source_ref] || {}), - target_ref_name: defaultValue(indexedStixObjects[n.target_ref] || {}), + source_ref_name: getMainRepresentative(indexedStixObjects[n.source_ref] || {}), + target_ref_name: getMainRepresentative(indexedStixObjects[n.target_ref] || {}), }, null), - source_ref_name: defaultValue(indexedStixObjects[n.source_ref] || {}), - target_ref_name: defaultValue(indexedStixObjects[n.target_ref] || {}), + source_ref_name: getMainRepresentative(indexedStixObjects[n.source_ref] || {}), + target_ref_name: getMainRepresentative(indexedStixObjects[n.target_ref] || {}), markings: resolveMarkings(stixDomainObjects, n.object_marking_refs), })); const sort = R.sortWith( @@ -3625,19 +3625,19 @@ const WorkbenchFileContentComponent = ({ const resolvedStixSightings = stixSightings.map((n) => ({ ...n, ttype: t_i18n('Sighting'), - default_value: defaultValue({ + default_value: getMainRepresentative({ ...n, - source_ref_name: defaultValue( + source_ref_name: getMainRepresentative( indexedStixObjects[n.sighting_of_ref] || {}, ), - target_ref_name: defaultValue( + target_ref_name: getMainRepresentative( indexedStixObjects[n.where_sighted_refs?.at(0)] || {}, ), }, null), - source_ref_name: defaultValue( + source_ref_name: getMainRepresentative( indexedStixObjects[n.sighting_of_ref] || {}, ), - target_ref_name: defaultValue( + target_ref_name: getMainRepresentative( indexedStixObjects[n.where_sighted_refs?.at(0)] || {}, ), markings: resolveMarkings(stixDomainObjects, n.object_marking_refs), @@ -3805,7 +3805,7 @@ const WorkbenchFileContentComponent = ({ const resolvedContainers = containers.map((n) => ({ ...n, ttype: t_i18n(`entity_${convertFromStixType(n.type)}`), - default_value: defaultValue(n, null), + default_value: getMainRepresentative(n, null), markings: resolveMarkings(stixDomainObjects, n.object_marking_refs), })); const sort = R.sortWith( diff --git a/opencti-platform/opencti-front/src/private/components/common/form/DynamicResolutionField.jsx b/opencti-platform/opencti-front/src/private/components/common/form/DynamicResolutionField.jsx index 943e6577cc66..f814de976776 100644 --- a/opencti-platform/opencti-front/src/private/components/common/form/DynamicResolutionField.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/form/DynamicResolutionField.jsx @@ -17,7 +17,7 @@ import ItemIcon from '../../../../components/ItemIcon'; import ItemBoolean from '../../../../components/ItemBoolean'; import { convertFromStixType, convertToStixType } from '../../../../utils/String'; import { useFormatter } from '../../../../components/i18n'; -import { defaultValue } from '../../../../utils/Graph'; +import { getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import { isEmptyField } from '../../../../utils/utils'; const inlineStyles = { @@ -86,7 +86,7 @@ const DynamicResolutionField = ({ return { id: firstStixDomainObject.id, type: targetSelectedType, - name: defaultValue(firstStixDomainObject), + name: getMainRepresentative(firstStixDomainObject), in_platform: null, }; } diff --git a/opencti-platform/opencti-front/src/private/components/common/form/StixCoreObjectsField.jsx b/opencti-platform/opencti-front/src/private/components/common/form/StixCoreObjectsField.jsx index 17bf2c0618b1..8f610e343a33 100644 --- a/opencti-platform/opencti-front/src/private/components/common/form/StixCoreObjectsField.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/form/StixCoreObjectsField.jsx @@ -12,7 +12,7 @@ import ListItemText from '@mui/material/ListItemText'; import makeStyles from '@mui/styles/makeStyles'; import IconButton from '@mui/material/IconButton'; import ItemIcon from '../../../../components/ItemIcon'; -import { defaultValue } from '../../../../utils/Graph'; +import { getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import { useFormatter } from '../../../../components/i18n'; import AutocompleteField from '../../../../components/AutocompleteField'; import { fetchQuery } from '../../../../relay/environment'; @@ -234,7 +234,7 @@ const StixCoreObjectsField = (props) => { const finalStixCoreObjects = R.pipe( R.pathOr([], ['stixCoreObjects', 'edges']), R.map((n) => ({ - label: defaultValue(n.node), + label: getMainRepresentative(n.node), value: n.node.id, type: n.node.entity_type, })), diff --git a/opencti-platform/opencti-front/src/private/components/common/form/StixDomainObjectsField.jsx b/opencti-platform/opencti-front/src/private/components/common/form/StixDomainObjectsField.jsx index dcfa7bf25466..fca6a9cfd79e 100644 --- a/opencti-platform/opencti-front/src/private/components/common/form/StixDomainObjectsField.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/form/StixDomainObjectsField.jsx @@ -8,7 +8,7 @@ import { graphql } from 'react-relay'; import { fetchQuery } from '../../../../relay/environment'; import AutocompleteField from '../../../../components/AutocompleteField'; import inject18n from '../../../../components/i18n'; -import { defaultValue } from '../../../../utils/Graph'; +import { getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import ItemIcon from '../../../../components/ItemIcon'; const SEARCH$ = new Subject().pipe(debounce(() => timer(1500))); @@ -207,7 +207,7 @@ class StixDomainObjectsField extends Component { const labels = pipe( pathOr([], ['stixDomainObjects', 'edges']), map((n) => ({ - label: defaultValue(n.node), + label: getMainRepresentative(n.node), value: n.node.id, type: n.node.entity_type, })), diff --git a/opencti-platform/opencti-front/src/private/components/common/location/GlobalVictimologyMap.jsx b/opencti-platform/opencti-front/src/private/components/common/location/GlobalVictimologyMap.jsx index bb5344b4acc7..f39d0c3e40de 100644 --- a/opencti-platform/opencti-front/src/private/components/common/location/GlobalVictimologyMap.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/location/GlobalVictimologyMap.jsx @@ -96,14 +96,14 @@ class GlobalVictimologyMap extends Component { x.entity, ), R.filter( - (n) => n.entity.entity_type === 'Country', + (n) => n.entity?.entity_type === 'Country', props.stixCoreRelationshipsDistribution, ), ); const cities = R.map( (x) => x.entity, R.filter( - (n) => n.entity.entity_type === 'City', + (n) => n.entity?.entity_type === 'City', props.stixCoreRelationshipsDistribution, ), ); diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsDistributionList.jsx b/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsDistributionList.jsx index f45782f5159a..550cd137c6a4 100644 --- a/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsDistributionList.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsDistributionList.jsx @@ -8,6 +8,7 @@ import WidgetContainer from '../../../../components/dashboard/WidgetContainer'; import WidgetNoData from '../../../../components/dashboard/WidgetNoData'; import WidgetLoader from '../../../../components/dashboard/WidgetLoader'; import WidgetDistributionList from '../../../../components/dashboard/WidgetDistributionList'; +import { getMainRepresentative, isFieldForIdentifier } from '../../../../utils/defaultRepresentatives'; const stixCoreObjectsDistributionListDistributionQuery = graphql` query StixCoreObjectsDistributionListDistributionQuery( @@ -43,34 +44,33 @@ const stixCoreObjectsDistributionListDistributionQuery = graphql` label value entity { - ... on StixObject { + ... on BasicObject { id entity_type - representative { - main - } } - ... on StixRelationship { + ... on BasicRelationship { id entity_type - representative { - main - } } - ... on Creator { - id - entity_type + ... on StixObject { representative { main } } + # use colors when available ... on Label { - value color } ... on MarkingDefinition { x_opencti_color } + # objects without representative + ... on Creator { + name + } + ... on Group { + name + } ... on Status { template { name @@ -121,19 +121,21 @@ const StixCoreObjectsDistributionList = ({ && props.stixCoreObjectsDistribution && props.stixCoreObjectsDistribution.length > 0 ) { - const data = props.stixCoreObjectsDistribution.map((o) => ({ - label: - // eslint-disable-next-line no-nested-ternary - selection.attribute.endsWith('_id') - ? o.entity?.representative?.main - : selection.attribute === 'entity_type' - ? t_i18n(`entity_${o.label}`) - : o.label, - value: o.value, - color: o.entity?.color ?? o.entity?.x_opencti_color, - id: selection.attribute.endsWith('_id') ? o.entity.id : null, - type: o.entity?.entity_type ?? o.label, - })); + const data = props.stixCoreObjectsDistribution.map((n) => { + let { label } = n; + if (isFieldForIdentifier(selection.attribute)) { + label = getMainRepresentative(n.entity); + } else if (selection.attribute === 'entity_type' && t_i18n(`entity_${n.label}`) !== `entity_${n.label}`) { + label = t_i18n(`entity_${n.label}`); + } + return { + label, + value: n.value, + color: n.entity?.color ?? n.entity?.x_opencti_color, + id: selection.attribute.endsWith('_id') ? n.entity?.id : null, + type: n.entity?.entity_type ?? n.label, + }; + }); return ; } if (props) { diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsDonut.jsx b/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsDonut.jsx index 06b03b5053db..668a8782ad6a 100644 --- a/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsDonut.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsDonut.jsx @@ -45,136 +45,36 @@ const stixCoreObjectsDonutDistributionQuery = graphql` value entity { ... on BasicObject { + id entity_type } ... on BasicRelationship { + id entity_type } - ... on AttackPattern { - name - description - } - ... on Campaign { - name - description - } - ... on CourseOfAction { - name - description - } - ... on Individual { - name - description - } - ... on Organization { - name - description - } - ... on Sector { - name - description - } - ... on System { - name - description - } - ... on Indicator { - name - description - } - ... on Infrastructure { - name - description - } - ... on IntrusionSet { - name - description - } - ... on Position { - name - description - } - ... on City { - name - description - } - ... on AdministrativeArea { - name - description - } - ... on Country { - name - description - } - ... on Region { - name - description - } - ... on Malware { - name - description - } - ... on MalwareAnalysis { - result_name - } - ... on ThreatActor { - name - description - } - ... on Tool { - name - description - } - ... on Vulnerability { - name - description - } - ... on Incident { - name - description - } - ... on Event { - name - description - } - ... on Channel { - name - description - } - ... on Narrative { - name - description - } - ... on Language { - name - } - ... on DataComponent { - name - } - ... on DataSource { - name + ... on StixObject { + representative { + main + } } - ... on Case { - name + ... on StixRelationship { + representative { + main + } } - ... on StixCyberObservable { - observable_value + # use colors when available + ... on Label { + color } ... on MarkingDefinition { - definition_type - definition x_opencti_color } - ... on KillChainPhase { - kill_chain_name - phase_name - } + # objects without representative ... on Creator { name } - ... on Label { - value - color + ... on Group { + name } ... on Status { template { diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsHorizontalBars.jsx b/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsHorizontalBars.jsx index fc5db087e43d..4dbef617ee58 100644 --- a/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsHorizontalBars.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsHorizontalBars.jsx @@ -1,15 +1,13 @@ import React from 'react'; import { graphql } from 'react-relay'; -import { useTheme } from '@mui/styles'; import { QueryRenderer } from '../../../../relay/environment'; import { useFormatter } from '../../../../components/i18n'; -import { itemColor } from '../../../../utils/Colors'; -import { defaultValue } from '../../../../utils/Graph'; import { buildFiltersAndOptionsForWidgets } from '../../../../utils/filters/filtersUtils'; import WidgetContainer from '../../../../components/dashboard/WidgetContainer'; import WidgetNoData from '../../../../components/dashboard/WidgetNoData'; import WidgetLoader from '../../../../components/dashboard/WidgetLoader'; import WidgetHorizontalBars from '../../../../components/dashboard/WidgetHorizontalBars'; +import useDistributionGraphData from '../../../../utils/hooks/useDistributionGraphData'; const stixCoreObjectsHorizontalBarsDistributionQuery = graphql` query StixCoreObjectsHorizontalBarsDistributionQuery( @@ -45,155 +43,47 @@ const stixCoreObjectsHorizontalBarsDistributionQuery = graphql` label value entity { - ... on BasicObject { - entity_type - id - } - ... on BasicRelationship { - entity_type - id - } - ... on AttackPattern { - name - description - } - ... on Campaign { - name - description - } - ... on CourseOfAction { - name - description - } - ... on Individual { - name - description - } - ... on Organization { - name - description - } - ... on Sector { - name - description - } - ... on System { - name - description - } - ... on Indicator { - name - description - } - ... on Infrastructure { - name - description - } - ... on IntrusionSet { - name - description - } - ... on Position { - name - description - } - ... on City { - name - description - } - ... on AdministrativeArea { - name - description - } - ... on Country { - name - description - } - ... on Region { - name - description - } - ... on Malware { - name - description - } - ... on MalwareAnalysis { - result_name - } - ... on ThreatActor { - name - description - } - ... on Tool { - name - description - } - ... on Vulnerability { - name - description - } - ... on Incident { - name - description - } - ... on Event { - name - description - } - ... on Channel { - name - description - } - ... on Narrative { - name - description - } - ... on Language { - name - } - ... on DataComponent { - name - } - ... on DataSource { - name - } - ... on Case { - name - } - ... on StixCyberObservable { - observable_value - } - ... on MarkingDefinition { - definition_type - definition - x_opencti_color - } - ... on Creator { - name - } - ... on Report { - name - } - ... on Grouping { - name - } - ... on Note { - attribute_abstract - content - } - ... on Opinion { - opinion + ... on BasicObject { + id + entity_type + } + ... on BasicRelationship { + id + entity_type + } + ... on StixObject { + representative { + main } - ... on Label { - value - color + } + ... on StixRelationship { + representative { + main } - ... on Status { - template { - name - color - } + } + # internal objects + ... on Creator { + id + name + } + ... on Group { + id + name + } + # need colors when available + ... on Label { + value + color + } + ... on MarkingDefinition { + x_opencti_color + } + ... on Status { + template { + name + color } + } } } } @@ -209,8 +99,9 @@ const StixCoreObjectsHorizontalBars = ({ withExportPopover = false, isReadOnly = false, }) => { - const theme = useTheme(); const { t_i18n } = useFormatter(); + const { buildWidgetProps } = useDistributionGraphData(); + const renderContent = () => { const selection = dataSelection[0]; const dataSelectionTypes = ['Stix-Core-Object']; @@ -239,53 +130,10 @@ const StixCoreObjectsHorizontalBars = ({ && props.stixCoreObjectsDistribution && props.stixCoreObjectsDistribution.length > 0 ) { - const data = props.stixCoreObjectsDistribution.map((n) => { - let color = selection.attribute.endsWith('_id') - ? itemColor(n.entity.entity_type) - : itemColor(n.label); - if (n.entity?.color) { - color = theme.palette.mode === 'light' && n.entity.color === '#ffffff' - ? '#000000' - : n.entity.color; - } - if (n.entity?.x_opencti_color) { - color = theme.palette.mode === 'light' - && n.entity.x_opencti_color === '#ffffff' - ? '#000000' - : n.entity.x_opencti_color; - } - if (n.entity?.template?.color) { - color = theme.palette.mode === 'light' - && n.entity.template.color === '#ffffff' - ? '#000000' - : n.entity.template.color; - } - return { - // eslint-disable-next-line no-nested-ternary - x: selection.attribute.endsWith('_id') - ? defaultValue(n.entity) - : selection.attribute === 'entity_type' - ? t_i18n(`entity_${n.label}`) - : n.label, - y: n.value, - fillColor: color, - }; - }); - const chartData = [ - { - name: selection.label || t_i18n('Number of relationships'), - data, - }, - ]; - const redirectionUtils = selection.attribute === 'name' - ? props.stixCoreObjectsDistribution.map((n) => ({ - id: n.entity.id, - entity_type: n.entity.entity_type, - })) - : undefined; + const { series, redirectionUtils } = buildWidgetProps(props.stixCoreObjectsDistribution, selection, 'Number of relationships'); return ( 0 ) { const data = props.stixCoreObjectsDistribution.map((n) => { - let color = selection.attribute.endsWith('_id') - ? itemColor(n.entity.entity_type) + let color = isFieldForIdentifier(selection.attribute) + ? itemColor(n.entity?.entity_type) : itemColor(n.label); if (n.entity?.color) { color = theme.palette.mode === 'light' && n.entity.color === '#ffffff' @@ -467,7 +467,7 @@ const stixCoreObjectsMultiHorizontalBars = ({ x: // eslint-disable-next-line no-nested-ternary selection.attribute.endsWith('_id') - ? defaultValue(n.entity) + ? getMainRepresentative(n.entity, t_i18n('Restricted')) : selection.attribute === 'entity_type' ? t_i18n(`entity_${n.label}`) : n.label, @@ -483,8 +483,8 @@ const stixCoreObjectsMultiHorizontalBars = ({ ]; const redirectionUtils = selection.attribute === 'name' ? props.stixCoreObjectsDistribution.map((n) => ({ - id: n.entity.id, - entity_type: n.entity.entity_type, + id: n.entity?.id, + entity_type: n.entity?.entity_type, })) : null; return ( diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsRadar.jsx b/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsRadar.jsx index bcd9a5ee9a87..541b0e58b69c 100644 --- a/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsRadar.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsRadar.jsx @@ -43,139 +43,41 @@ const stixCoreObjectsRadarDistributionQuery = graphql` value entity { ... on BasicObject { + id entity_type } ... on BasicRelationship { + id entity_type } - ... on AttackPattern { - name - description - x_mitre_id - } - ... on Campaign { - name - description - } - ... on CourseOfAction { - name - description - } - ... on Individual { - name - description - } - ... on Organization { - name - description - } - ... on Sector { - name - description - } - ... on System { - name - description - } - ... on Indicator { - name - description - } - ... on Infrastructure { - name - description - } - ... on IntrusionSet { - name - description - } - ... on Position { - name - description - } - ... on City { - name - description - } - ... on AdministrativeArea { - name - description - } - ... on Country { - name - description - } - ... on Region { - name - description - } - ... on Malware { - name - description - } - ... on MalwareAnalysis { - result_name - } - ... on ThreatActor { - name - description - } - ... on Tool { - name - description - } - ... on Vulnerability { - name - description - } - ... on Incident { - name - description - } - ... on Event { - name - description - } - ... on Channel { - name - description - } - ... on Narrative { - name - description - } - ... on Language { - name - } - ... on DataComponent { - name - } - ... on DataSource { - name + ... on StixObject { + representative { + main + } } - ... on Case { - name + ... on StixRelationship { + representative { + main + } } - ... on StixCyberObservable { - observable_value + # use colors when available + ... on Label { + color } ... on MarkingDefinition { - definition_type - definition - } - ... on KillChainPhase { - kill_chain_name - phase_name + x_opencti_color } + # objects without representative ... on Creator { name } - ... on Label { - value + ... on Group { + name } ... on Status { template { name + color } } } diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsTimeline.jsx b/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsTimeline.jsx index f317def339a9..cf95d5768166 100644 --- a/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsTimeline.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsTimeline.jsx @@ -29,149 +29,6 @@ const stixCoreObjectsTimelineQuery = graphql` id entity_type created_at - ... on StixDomainObject { - created - modified - } - ... on AttackPattern { - name - description - } - ... on Campaign { - name - description - } - ... on Note { - attribute_abstract - } - ... on Opinion { - opinion - } - ... on ObservedData { - first_observed - last_observed - } - ... on Opinion { - opinion - } - ... on Report { - name - description - published - } - ... on Grouping { - name - description - } - ... on CourseOfAction { - name - description - } - ... on Individual { - name - description - } - ... on Organization { - name - description - } - ... on Sector { - name - description - } - ... on System { - name - description - } - ... on Indicator { - name - description - } - ... on Infrastructure { - name - description - } - ... on IntrusionSet { - name - description - } - ... on Position { - name - description - } - ... on City { - name - description - } - ... on AdministrativeArea { - name - description - } - ... on Country { - name - description - } - ... on Region { - name - description - } - ... on Malware { - name - description - } - ... on MalwareAnalysis { - result_name - } - ... on ThreatActor { - name - description - } - ... on Tool { - name - description - } - ... on Vulnerability { - name - description - } - ... on Incident { - name - description - } - ... on Event { - name - description - } - ... on Channel { - name - description - } - ... on Narrative { - name - description - } - ... on Language { - name - } - ... on DataComponent { - name - } - ... on DataSource { - name - } - ... on Case { - name - } - ... on Note { - attribute_abstract - content - } - ... on Opinion { - opinion - } - ... on StixCyberObservable { - observable_value - } createdBy { ... on Identity { id @@ -186,6 +43,23 @@ const stixCoreObjectsTimelineQuery = graphql` x_opencti_order x_opencti_color } + ... on BasicObject { + id + entity_type + } + ... on StixObject { + representative { + main + secondary + } + } + ... on StixDomainObject { + created + modified + } + ... on StixCyberObservable { + observable_value + } } } } diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsTreeMap.jsx b/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsTreeMap.jsx index d04b18dbe9b4..55028a3bca6a 100644 --- a/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsTreeMap.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectsTreeMap.jsx @@ -43,135 +43,22 @@ const stixCoreObjectsTreeMapDistributionQuery = graphql` value entity { ... on BasicObject { + id entity_type } ... on BasicRelationship { + id entity_type } - ... on AttackPattern { - name - description - } - ... on Campaign { - name - description - } - ... on CourseOfAction { - name - description - } - ... on Individual { - name - description - } - ... on Organization { - name - description - } - ... on Sector { - name - description - } - ... on System { - name - description - } - ... on Indicator { - name - description - } - ... on Infrastructure { - name - description - } - ... on IntrusionSet { - name - description - } - ... on Position { - name - description - } - ... on City { - name - description - } - ... on AdministrativeArea { - name - description - } - ... on Country { - name - description - } - ... on Region { - name - description - } - ... on Malware { - name - description - } - ... on MalwareAnalysis { - result_name - } - ... on ThreatActor { - name - description - } - ... on Tool { - name - description - } - ... on Vulnerability { - name - description - } - ... on Incident { - name - description - } - ... on Event { - name - description - } - ... on Channel { - name - description - } - ... on Narrative { - name - description - } - ... on Language { - name - } - ... on DataComponent { - name - } - ... on DataSource { - name - } - ... on Case { - name - } - ... on StixCyberObservable { - observable_value - } - ... on MarkingDefinition { - definition_type - definition - } - ... on KillChainPhase { - kill_chain_name - phase_name + ... on StixObject { + representative { + main + } } + # objects without representative ... on Creator { name } - ... on Label { - value - } ... on Status { template { name diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_core_objects_or_stix_relationships/StixCoreObjectOrCoreRelationshipLabelsView.js b/opencti-platform/opencti-front/src/private/components/common/stix_core_objects_or_stix_relationships/StixCoreObjectOrCoreRelationshipLabelsView.js index 7b139d1353af..69e21765af37 100644 --- a/opencti-platform/opencti-front/src/private/components/common/stix_core_objects_or_stix_relationships/StixCoreObjectOrCoreRelationshipLabelsView.js +++ b/opencti-platform/opencti-front/src/private/components/common/stix_core_objects_or_stix_relationships/StixCoreObjectOrCoreRelationshipLabelsView.js @@ -325,7 +325,7 @@ const StixCoreObjectOrCoreRelationshipLabelsView = (props) => { StixCoreObjectOrCoreRelationshipLabelsView.propTypes = { id: PropTypes.string, - labels: PropTypes.object, + labels: PropTypes.array, mutationRelationsAdd: PropTypes.object, mutationRelationDelete: PropTypes.object, }; diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/EntityStixCoreRelationshipLineAll.jsx b/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/EntityStixCoreRelationshipLineAll.jsx index 9984954f6bea..6c04873dbdaf 100644 --- a/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/EntityStixCoreRelationshipLineAll.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/EntityStixCoreRelationshipLineAll.jsx @@ -18,7 +18,7 @@ import inject18n from '../../../../components/i18n'; import ItemIcon from '../../../../components/ItemIcon'; import ItemConfidence from '../../../../components/ItemConfidence'; import StixCoreRelationshipPopover from './StixCoreRelationshipPopover'; -import { defaultValue } from '../../../../utils/Graph'; +import { getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import { hexToRGB, itemColor } from '../../../../utils/Colors'; import ItemMarkings from '../../../../components/ItemMarkings'; @@ -165,7 +165,7 @@ class EntityStixCoreRelationshipLineAllComponent extends Component { : dataColumns.observable_value.width, }} > - {!restricted ? defaultValue(remoteNode) : t('Restricted')} + {!restricted ? getMainRepresentative(remoteNode) : t('Restricted')}
- {!restricted ? defaultValue(node.to) : t('Restricted')} + {!restricted ? getMainRepresentative(node.to) : t('Restricted')}
- {!restricted ? defaultValue(node.from) : t('Restricted')} + {!restricted ? getMainRepresentative(node.from) : t('Restricted')}
({ paper: { @@ -238,14 +238,14 @@ const EntityStixCoreRelationshipsHorizontalBars = ( x: // eslint-disable-next-line no-nested-ternary field === 'internal_id' - ? defaultValue(n.entity) + ? getMainRepresentative(n.entity, t_i18n('Restricted')) : field === 'entity_type' ? t_i18n(`entity_${n.label}`) : n.label, y: n.value, fillColor: field === 'internal_id' - ? itemColor(n.entity.entity_type) + ? itemColor(n.entity?.entity_type) : itemColor(n.label), })); const chartData = [ @@ -257,7 +257,7 @@ const EntityStixCoreRelationshipsHorizontalBars = ( const redirectionUtils = (field === 'internal_id') ? props.stixCoreRelationshipsDistribution.map( (n) => ({ id: n.label, - entity_type: n.entity.entity_type, + entity_type: n.entity?.entity_type, }), ) : null; return ( diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/SimpleStixObjectOrStixRelationshipStixCoreRelationshipLine.jsx b/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/SimpleStixObjectOrStixRelationshipStixCoreRelationshipLine.jsx index 045866fb4f9a..e9b1d328f313 100644 --- a/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/SimpleStixObjectOrStixRelationshipStixCoreRelationshipLine.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/SimpleStixObjectOrStixRelationshipStixCoreRelationshipLine.jsx @@ -21,7 +21,7 @@ import Security from '../../../../utils/Security'; import { KNOWLEDGE_KNUPDATE } from '../../../../utils/hooks/useGranted'; import ItemIcon from '../../../../components/ItemIcon'; import { hexToRGB, itemColor } from '../../../../utils/Colors'; -import { defaultValue } from '../../../../utils/Graph'; +import { getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import ItemMarkings from '../../../../components/ItemMarkings'; const styles = (theme) => ({ @@ -134,7 +134,7 @@ class SimpleStixObjectOrStixRelationshipStixCoreRelationshipLineComponent extend className={classes.bodyItem} style={{ width: dataColumns.name.width }} > - {element.restricted ? element.name : defaultValue(element)} + {element.restricted ? element.name : getMainRepresentative(element)}
({ containerRelation: { @@ -193,7 +193,7 @@ const StixCoreRelationshipCreationForm = ({ {isMultipleFrom ? ({t_i18n('Multiple entities selected')}) - : (defaultValue(fromEntity))} + : (getMainRepresentative(fromEntity))}
@@ -242,7 +242,7 @@ const StixCoreRelationshipCreationForm = ({ {isMultipleTo ? ({t_i18n('Multiple entities selected')}) - : (defaultValue(toEntity))} + : (getMainRepresentative(toEntity))} diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/StixCoreRelationshipCreationFromEntityStixCoreObjectsLine.jsx b/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/StixCoreRelationshipCreationFromEntityStixCoreObjectsLine.jsx index 8f87501e460b..7df9b15fd812 100644 --- a/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/StixCoreRelationshipCreationFromEntityStixCoreObjectsLine.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/StixCoreRelationshipCreationFromEntityStixCoreObjectsLine.jsx @@ -13,7 +13,7 @@ import { useFormatter } from '../../../../components/i18n'; import StixCoreObjectLabels from '../stix_core_objects/StixCoreObjectLabels'; import ItemIcon from '../../../../components/ItemIcon'; import ItemMarkings from '../../../../components/ItemMarkings'; -import { defaultValue } from '../../../../utils/Graph'; +import { getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import { hexToRGB, itemColor } from '../../../../utils/Colors'; import { APP_BASE_PATH } from '../../../../relay/environment'; @@ -128,7 +128,7 @@ const StixCoreRelationshipCreationFromEntityStixCoreObjectsLineComponent = ({ className={classes.bodyItem} style={{ width: dataColumns.value.width }} > - {defaultValue(node)} + {getMainRepresentative(node)}
{!fromRestricted ? truncate( - defaultValue(from) !== 'Unknown' - ? defaultValue(from) + getMainRepresentative(from) !== 'Unknown' + ? getMainRepresentative(from) : t(`relationship_${from.entity_type}`), 50, ) @@ -362,8 +362,8 @@ class StixCoreRelationshipContainer extends Component { {!toRestricted ? truncate( - defaultValue(to) !== 'Unknown' - ? defaultValue(to) + getMainRepresentative(to) !== 'Unknown' + ? getMainRepresentative(to) : t(`relationship_${to.entity_type}`), 50, ) diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/views/EntityStixCoreRelationshipsContextualView.tsx b/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/views/EntityStixCoreRelationshipsContextualView.tsx index 6d393bc1dc3e..c1a2f2c712ef 100644 --- a/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/views/EntityStixCoreRelationshipsContextualView.tsx +++ b/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/views/EntityStixCoreRelationshipsContextualView.tsx @@ -11,7 +11,7 @@ import useEntityToggle from '../../../../../utils/hooks/useEntityToggle'; import EntityStixCoreRelationshipsContextualViewLines from './EntityStixCoreRelationshipsContextualViewLines'; import { hexToRGB, itemColor } from '../../../../../utils/Colors'; import { useFormatter } from '../../../../../components/i18n'; -import { defaultValue } from '../../../../../utils/Graph'; +import { getMainRepresentative } from '../../../../../utils/defaultRepresentatives'; import StixCoreObjectLabels from '../../stix_core_objects/StixCoreObjectLabels'; import ItemMarkings from '../../../../../components/ItemMarkings'; import { DataColumns, PaginationOptions } from '../../../../../components/list_lines'; @@ -153,7 +153,7 @@ const EntityStixCoreRelationshipsContextualViewComponent: FunctionComponent defaultValue(stixCoreObject), + render: (stixCoreObject: EntityStixCoreRelationshipsContextualViewLine_node$data) => getMainRepresentative(stixCoreObject), }, createdBy: { label: 'Author', diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/views/EntityStixCoreRelationshipsEntitiesViewLine.tsx b/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/views/EntityStixCoreRelationshipsEntitiesViewLine.tsx index 26e0c27ce8d3..813b24bddcf3 100644 --- a/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/views/EntityStixCoreRelationshipsEntitiesViewLine.tsx +++ b/opencti-platform/opencti-front/src/private/components/common/stix_core_relationships/views/EntityStixCoreRelationshipsEntitiesViewLine.tsx @@ -18,7 +18,7 @@ import { useFormatter } from '../../../../../components/i18n'; import { DataColumns } from '../../../../../components/list_lines'; import { UseEntityToggle } from '../../../../../utils/hooks/useEntityToggle'; import ItemIcon from '../../../../../components/ItemIcon'; -import { defaultValue } from '../../../../../utils/Graph'; +import { getMainRepresentative } from '../../../../../utils/defaultRepresentatives'; import { hexToRGB, itemColor } from '../../../../../utils/Colors'; import { EntityStixCoreRelationshipsEntitiesViewLine_node$data, @@ -293,7 +293,7 @@ EntityStixCoreRelationshipsEntitiesLineProps : dataColumns.observable_value.width, }} > - {defaultValue(stixCoreObject)} + {getMainRepresentative(stixCoreObject)}
defaultValue(stixCoreObject), + render: (stixCoreObject: EntityStixCoreRelationshipsIndicatorsContextualViewLine_node$data) => getMainRepresentative(stixCoreObject), }, objectLabel: { label: 'Labels', diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_domain_objects/StixDomainObjectHeader.jsx b/opencti-platform/opencti-front/src/private/components/common/stix_domain_objects/StixDomainObjectHeader.jsx index 8a9fa3166e26..249514518952 100644 --- a/opencti-platform/opencti-front/src/private/components/common/stix_domain_objects/StixDomainObjectHeader.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/stix_domain_objects/StixDomainObjectHeader.jsx @@ -39,7 +39,7 @@ import StixCoreObjectSharing from '../stix_core_objects/StixCoreObjectSharing'; import { truncate } from '../../../../utils/String'; import { useIsEnforceReference } from '../../../../utils/hooks/useEntitySettings'; import StixCoreObjectQuickSubscription from '../stix_core_objects/StixCoreObjectQuickSubscription'; -import { defaultValue } from '../../../../utils/Graph'; +import { getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import Transition from '../../../../components/Transition'; import Loader, { LoaderVariant } from '../../../../components/Loader'; @@ -341,13 +341,13 @@ const StixDomainObjectHeader = (props) => { return ( }> - + - {truncate(defaultValue(stixDomainObject), 80)} + {truncate(getMainRepresentative(stixDomainObject), 80)} {typeof onViewAs === 'function' && ( @@ -515,7 +515,7 @@ const StixDomainObjectHeader = (props) => { {enableQuickSubscription && ( @@ -524,7 +524,7 @@ const StixDomainObjectHeader = (props) => { )} diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_domain_objects/StixDomainObjectNestedEntitiesLines.jsx b/opencti-platform/opencti-front/src/private/components/common/stix_domain_objects/StixDomainObjectNestedEntitiesLines.jsx index 4b3fa9801a9d..b3b7d0776b57 100644 --- a/opencti-platform/opencti-front/src/private/components/common/stix_domain_objects/StixDomainObjectNestedEntitiesLines.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/stix_domain_objects/StixDomainObjectNestedEntitiesLines.jsx @@ -13,7 +13,7 @@ import inject18n from '../../../../components/i18n'; import ItemIcon from '../../../../components/ItemIcon'; import StixNestedRefRelationshipPopover from '../stix_nested_ref_relationships/StixNestedRefRelationshipPopover'; import { resolveLink } from '../../../../utils/Entity'; -import { defaultValue } from '../../../../utils/Graph'; +import { getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import { hexToRGB, itemColor } from '../../../../utils/Colors'; const styles = (theme) => ({ @@ -134,7 +134,7 @@ class StixDomainObjectNestedEntitiesLinesComponent extends Component { className={classes.bodyItem} style={{ width: '40%' }} > - {defaultValue(stixCoreObject)} + {getMainRepresentative(stixCoreObject)}
{fsd(node.start_time)} diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_domain_objects/StixDomainObjectTimeline.jsx b/opencti-platform/opencti-front/src/private/components/common/stix_domain_objects/StixDomainObjectTimeline.jsx index a58947806fb1..9f27cc241bbf 100644 --- a/opencti-platform/opencti-front/src/private/components/common/stix_domain_objects/StixDomainObjectTimeline.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/stix_domain_objects/StixDomainObjectTimeline.jsx @@ -20,7 +20,7 @@ import ItemIcon from '../../../../components/ItemIcon'; import inject18n from '../../../../components/i18n'; import { stixDomainObjectThreatKnowledgeStixRelationshipsQuery } from './StixDomainObjectThreatKnowledgeQuery'; import { truncate } from '../../../../utils/String'; -import { defaultSecondaryValue, defaultValue } from '../../../../utils/Graph'; +import { getSecondaryRepresentative, getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import { itemColor } from '../../../../utils/Colors'; const Transition = React.forwardRef((props, ref) => ( @@ -95,7 +95,7 @@ class StixDomainObjectTimelineComponent extends Component { @@ -123,7 +123,7 @@ class StixDomainObjectTimelineComponent extends Component { @@ -154,7 +154,7 @@ class StixDomainObjectTimelineComponent extends Component { {!restricted ? truncate( - defaultValue(stixRelationship.targetEntity), + getMainRepresentative(stixRelationship.targetEntity), 50, ) : t('Restricted')} @@ -166,7 +166,7 @@ class StixDomainObjectTimelineComponent extends Component { && stixRelationship.description.length > 0 ? stixRelationship.description : !restricted - ? defaultSecondaryValue( + ? getSecondaryRepresentative( stixRelationship.targetEntity, ) : t('Restricted'), diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_domain_objects/StixDomainObjectsTimeline.jsx b/opencti-platform/opencti-front/src/private/components/common/stix_domain_objects/StixDomainObjectsTimeline.jsx index 021a80ac8c0e..e4311e1f8db3 100644 --- a/opencti-platform/opencti-front/src/private/components/common/stix_domain_objects/StixDomainObjectsTimeline.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/stix_domain_objects/StixDomainObjectsTimeline.jsx @@ -17,7 +17,7 @@ import CircularProgress from '@mui/material/CircularProgress'; import { QueryRenderer } from '../../../../relay/environment'; import ItemIcon from '../../../../components/ItemIcon'; import inject18n from '../../../../components/i18n'; -import { defaultValue } from '../../../../utils/Graph'; +import { getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import { resolveLink } from '../../../../utils/Entity'; import { itemColor } from '../../../../utils/Colors'; import MarkdownDisplay from '../../../../components/MarkdownDisplay'; @@ -229,7 +229,7 @@ class StixDomainObjectsTimeline extends Component { - {defaultValue(stixDomainObject)} + {getMainRepresentative(stixDomainObject)}
- {truncate(defaultValue(fromEntity), 20)} + {truncate(getMainRepresentative(fromEntity), 20)}
@@ -773,7 +773,7 @@ const StixNestedRefRelationshipCreationFromEntity = ({
- {truncate(defaultValue(toEntity[0]), 20)} + {truncate(getMainRepresentative(toEntity[0]), 20)}
diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_nested_ref_relationships/StixNestedRefRelationshipCreationFromEntityLine.tsx b/opencti-platform/opencti-front/src/private/components/common/stix_nested_ref_relationships/StixNestedRefRelationshipCreationFromEntityLine.tsx index 0625fe8c880b..fe7d7e17bf71 100644 --- a/opencti-platform/opencti-front/src/private/components/common/stix_nested_ref_relationships/StixNestedRefRelationshipCreationFromEntityLine.tsx +++ b/opencti-platform/opencti-front/src/private/components/common/stix_nested_ref_relationships/StixNestedRefRelationshipCreationFromEntityLine.tsx @@ -16,7 +16,7 @@ import StixCoreObjectLabels from '../stix_core_objects/StixCoreObjectLabels'; import { APP_BASE_PATH } from '../../../../relay/environment'; import ItemIcon from '../../../../components/ItemIcon'; import { hexToRGB, itemColor } from '../../../../utils/Colors'; -import { defaultValue } from '../../../../utils/Graph'; +import { getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import ItemMarkings from '../../../../components/ItemMarkings'; import { useFormatter } from '../../../../components/i18n'; import type { Theme } from '../../../../components/Theme'; @@ -323,7 +323,7 @@ export const StixNestedRefRelationshipCreationFromEntityLine: FunctionComponent< className={classes.bodyItem} style={{ width: dataColumns.value.width }} > - {defaultValue(data)} + {getMainRepresentative(data)}
0 ) { - const data = props.stixRelationshipsDistribution.map((o) => ({ - label: finalField.endsWith('_id') - ? defaultValue(o.entity) - : o.label, - value: o.value, - id: finalField.endsWith('_id') ? o.entity.id : null, - type: finalField.endsWith('_id') ? o.entity.entity_type : o.label, - })); + const data = props.stixRelationshipsDistribution.map((n) => { + let { label } = n; + let id = null; + let type = n.label; + if (isFieldForIdentifier(finalField)) { + label = getMainRepresentative(n.entity); + id = n.entity?.id; + type = n.entity?.entity_type; + } + return { + label, + value: n.value, + id, + type, + }; + }); return ( { - const theme = useTheme(); const { t_i18n } = useFormatter(); + const { buildWidgetProps } = useDistributionGraphData(); const renderContent = () => { let selection = {}; let filtersAndOptions; @@ -258,45 +153,10 @@ const StixRelationshipsHorizontalBars = ({ && props.stixRelationshipsDistribution && props.stixRelationshipsDistribution.length > 0 ) { - const data = props.stixRelationshipsDistribution.map((n) => { - let color = selection.attribute.endsWith('_id') - ? itemColor(n.entity.entity_type) - : itemColor(n.label); - if (n.entity?.color) { - color = theme.palette.mode === 'light' && n.entity.color === '#ffffff' - ? '#000000' - : n.entity.color; - } - if (n.entity?.x_opencti_color) { - color = theme.palette.mode === 'light' - && n.entity.x_opencti_color === '#ffffff' - ? '#000000' - : n.entity.x_opencti_color; - } - if (n.entity?.template?.color) { - color = theme.palette.mode === 'light' - && n.entity.template.color === '#ffffff' - ? '#000000' - : n.entity.template.color; - } - return { - x: finalField.endsWith('_id') - ? defaultValue(n.entity) - : n.label, - y: n.value, - fillColor: color, - }; - }); - const chartData = [{ name: t_i18n('Number of relationships'), data }]; - const redirectionUtils = finalField.endsWith('_id') - ? props.stixRelationshipsDistribution.map((n) => ({ - id: n.label, - entity_type: n.entity.entity_type, - })) - : undefined; + const { series, redirectionUtils } = buildWidgetProps(props.stixRelationshipsDistribution, selection, 'Number of relationships'); return ( 0 ) { - const categories = props.stixRelationshipsDistribution.map((n) => defaultValue(n.entity)); + const categories = props.stixRelationshipsDistribution.map((n) => getMainRepresentative(n.entity, t_i18n('Restricted'))); const entitiesMapping = {}; for (const distrib of props.stixRelationshipsDistribution) { for (const subDistrib of distrib.entity[key]) { entitiesMapping[ finalSubDistributionField === 'internal_id' - ? defaultValue(subDistrib.entity) + ? getMainRepresentative(subDistrib.entity, t_i18n('Restricted')) : subDistrib.label ] = (entitiesMapping[ finalSubDistributionField === 'internal_id' - ? defaultValue(subDistrib.entity) + ? getMainRepresentative(subDistrib.entity, t_i18n('Restricted')) : subDistrib.label ] || 0) + subDistrib.value; } @@ -849,9 +468,9 @@ const StixRelationshipsMultiHorizontalBars = ({ for (const distrib of props.stixRelationshipsDistribution) { for (const sortedEntity of sortedEntityMapping) { const entityData = R.head( - distrib.entity[key].filter( + distrib.entity?.[key].filter( (n) => (finalSubDistributionField === 'internal_id' - ? defaultValue(n.entity) + ? getMainRepresentative(n.entity) : n.label) === sortedEntity[0], ), ); @@ -859,21 +478,21 @@ const StixRelationshipsMultiHorizontalBars = ({ if (entityData) { value = entityData.value; } - if (categoriesValues[defaultValue(distrib.entity)]) { - categoriesValues[defaultValue(distrib.entity)].push(value); + if (categoriesValues[getMainRepresentative(distrib.entity)]) { + categoriesValues[getMainRepresentative(distrib.entity)].push(value); } else { - categoriesValues[defaultValue(distrib.entity)] = [value]; + categoriesValues[getMainRepresentative(distrib.entity)] = [value]; } } const sum = ( - categoriesValues[defaultValue(distrib.entity)] || [] + categoriesValues[getMainRepresentative(distrib.entity)] || [] ).reduce((partialSum, a) => partialSum + a, 0); - if (categoriesValues[defaultValue(distrib.entity)]) { - categoriesValues[defaultValue(distrib.entity)].push( + if (categoriesValues[getMainRepresentative(distrib.entity)]) { + categoriesValues[getMainRepresentative(distrib.entity)].push( distrib.value - sum, ); } else { - categoriesValues[defaultValue(distrib.entity)] = [ + categoriesValues[getMainRepresentative(distrib.entity)] = [ distrib.value - sum, ]; } @@ -907,14 +526,14 @@ const StixRelationshipsMultiHorizontalBars = ({ const redirectionUtils = finalField === 'internal_id' ? props.stixRelationshipsDistribution.map((n) => ({ id: n.label, - entity_type: n.entity.entity_type, + entity_type: n.entity?.entity_type, series: subSectionIdsOrder.map((subSectionId) => { - const [entity] = n.entity[key].filter( + const [entity] = n.entity[key]?.filter( (e) => e.label === subSectionId, - ); + ) ?? []; return { id: subSectionId, - entity_type: entity ? entity.entity.entity_type : null, + entity_type: entity ? entity.entity?.entity_type : null, }; }), })) diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_relationships/StixRelationshipsPolarArea.jsx b/opencti-platform/opencti-front/src/private/components/common/stix_relationships/StixRelationshipsPolarArea.jsx index 6a645cca8527..e20d402cd519 100644 --- a/opencti-platform/opencti-front/src/private/components/common/stix_relationships/StixRelationshipsPolarArea.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/stix_relationships/StixRelationshipsPolarArea.jsx @@ -1,9 +1,8 @@ import React from 'react'; -import * as R from 'ramda'; import { graphql } from 'react-relay'; import { QueryRenderer } from '../../../../relay/environment'; import { useFormatter } from '../../../../components/i18n'; -import { defaultValue } from '../../../../utils/Graph'; +import { getMainRepresentative, isFieldForIdentifier } from '../../../../utils/defaultRepresentatives'; import { buildFiltersAndOptionsForWidgets } from '../../../../utils/filters/filtersUtils'; import WidgetNoData from '../../../../components/dashboard/WidgetNoData'; import WidgetLoader from '../../../../components/dashboard/WidgetLoader'; @@ -61,140 +60,42 @@ const stixRelationshipsPolarAreasDistributionQuery = graphql` value entity { ... on BasicObject { + id entity_type } ... on BasicRelationship { + id entity_type } - ... on AttackPattern { - name - description - } - ... on Campaign { - name - description - } - ... on CourseOfAction { - name - description - } - ... on Individual { - name - description - } - ... on Organization { - name - description - } - ... on Sector { - name - description - } - ... on System { - name - description - } - ... on Indicator { - name - description - } - ... on Infrastructure { - name - description - } - ... on IntrusionSet { - name - description - } - ... on Position { - name - description - } - ... on City { - name - description - } - ... on Country { - name - description - } - ... on Region { - name - description - } - ... on Malware { - name - description - } - ... on ThreatActor { - name - description - } - ... on Tool { - name - description - } - ... on Vulnerability { - name - description - } - ... on Incident { - name - description - } - ... on Event { - name - description - } - ... on Channel { - name - description - } - ... on Narrative { - name - description - } - ... on Language { - name - } - ... on DataComponent { - name - description - } - ... on DataSource { - name - description - } - ... on Case { - name - description - } - ... on StixCyberObservable { - observable_value - } - ... on MarkingDefinition { - definition_type - definition + ... on StixObject { + representative { + main + } } - ... on KillChainPhase { - kill_chain_name - phase_name + ... on StixRelationship { + representative { + main + } } + # internal objects ... on Creator { name } - ... on Report { + ... on Group { name } - ... on Grouping { - name + # need colors when available + ... on Label { + color } - ... on Note { - attribute_abstract - content + ... on MarkingDefinition { + x_opencti_color } - ... on Opinion { - opinion + ... on Status { + template { + name + color + } } } } @@ -243,16 +144,13 @@ const StixRelationshipsPolarArea = ({ render={({ props }) => { if (props && props.stixRelationshipsDistribution && props.stixRelationshipsDistribution.length > 0) { let data = props.stixRelationshipsDistribution; - if (finalField.endsWith('_id')) { - data = R.map( - (n) => R.assoc( - 'label', - defaultValue(n.entity), - n, - ), - props.stixRelationshipsDistribution, - ); + if (isFieldForIdentifier(finalField)) { + data = data.map((n) => ({ + ...n, + label: getMainRepresentative(n.entity), + })); } + // TODO: take into account the entity color to send it to the widget (that shall handle it) return ( defaultValue(o), + (o) => getMainRepresentative(o), R.values(selectedElements || {}), ), ), @@ -1704,7 +1704,7 @@ class ToolBar extends Component { R.map( (p) => (typeof p === 'string' ? p - : defaultValue(p)), + : getMainRepresentative(p)), R.pathOr([], ['context', 'values'], o), ), ), @@ -1867,7 +1867,7 @@ class ToolBar extends Component { textOverflow: 'ellipsis', }, }} - primary={defaultValue(element)} + primary={getMainRepresentative(element)} secondary={truncate( element.description || element.x_opencti_description @@ -1920,7 +1920,7 @@ class ToolBar extends Component { {t('Name')}
- {defaultValue(keptElement)} + {getMainRepresentative(keptElement)}
({ item: { @@ -115,7 +115,7 @@ const EntitiesStixDomainObjectLineComponent = ({ className={classes.bodyItem} style={{ width: dataColumns.name.width }} > - {defaultValue(node)} + {getMainRepresentative(node)}
- {node.from ? defaultValue(node.from) : t_i18n('Restricted')} + {getMainRepresentative(node.from)}
- {node.to ? defaultValue(node.to) : t_i18n('Restricted')} + {getMainRepresentative(node.to)}
({ paper: { @@ -219,11 +220,9 @@ class EntityStixSightingRelationshipsDonut extends Component { (n) => R.assoc( 'label', `${ - toTypes.length > 1 - ? `[${t(`entity_${n.entity.entity_type}`)}] ${ - n.entity.name - }` - : `${n.entity.name}` + toTypes.length > 1 && n.entity + ? `[${t(`entity_${n.entity.entity_type}`)}] ${n.entity.name}` + : `${getMainRepresentative(n.entity) || n.label}` }`, n, ), diff --git a/opencti-platform/opencti-front/src/private/components/events/stix_sighting_relationships/StixSightingRelationshipCreation.jsx b/opencti-platform/opencti-front/src/private/components/events/stix_sighting_relationships/StixSightingRelationshipCreation.jsx index 6c69cbd92587..410d8df9cca7 100644 --- a/opencti-platform/opencti-front/src/private/components/events/stix_sighting_relationships/StixSightingRelationshipCreation.jsx +++ b/opencti-platform/opencti-front/src/private/components/events/stix_sighting_relationships/StixSightingRelationshipCreation.jsx @@ -16,7 +16,7 @@ import { itemColor } from '../../../../utils/Colors'; import { formatDate } from '../../../../utils/Time'; import ItemIcon from '../../../../components/ItemIcon'; import { truncate } from '../../../../utils/String'; -import { defaultValue } from '../../../../utils/Graph'; +import { getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import StixSightingRelationshipCreationForm from './StixSightingRelationshipCreationForm'; const styles = (theme) => ({ @@ -498,7 +498,7 @@ class StixSightingRelationshipCreation extends Component {
- {truncate(defaultValue(toObjects[0]), 20)} + {truncate(getMainRepresentative(toObjects[0]), 20)}
@@ -539,7 +539,7 @@ class StixSightingRelationshipCreation extends Component { {fromObjects.length > 1 ? ( {t('Multiple entities selected')} ) : ( - truncate(defaultValue(fromObjects[0])) + truncate(getMainRepresentative(fromObjects[0])) )} diff --git a/opencti-platform/opencti-front/src/private/components/observations/indicators/IndicatorsAreaChart.jsx b/opencti-platform/opencti-front/src/private/components/observations/indicators/IndicatorsAreaChart.jsx deleted file mode 100644 index 61d1d4beef9b..000000000000 --- a/opencti-platform/opencti-front/src/private/components/observations/indicators/IndicatorsAreaChart.jsx +++ /dev/null @@ -1,167 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose } from 'ramda'; -import { graphql } from 'react-relay'; -import withStyles from '@mui/styles/withStyles'; -import withTheme from '@mui/styles/withTheme'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import inject18n from '../../../../components/i18n'; -import { monthsAgo, now } from '../../../../utils/Time'; -import { areaChartOptions } from '../../../../utils/Charts'; -import { simpleNumberFormat } from '../../../../utils/Number'; - -const styles = () => ({ - paper: { - minHeight: 280, - height: '100%', - margin: '4px 0 0 0', - padding: '0 0 10px 0', - borderRadius: 4, - }, - chip: { - fontSize: 10, - height: 20, - marginLeft: 10, - }, -}); - -const indicatorsAreaChartTimeSeriesQuery = graphql` - query IndicatorsAreaChartTimeSeriesQuery( - $field: String! - $operation: StatsOperation! - $startDate: DateTime! - $endDate: DateTime! - $interval: String! - ) { - indicatorsTimeSeries( - field: $field - operation: $operation - startDate: $startDate - endDate: $endDate - interval: $interval - ) { - date - value - } - } -`; - -class IndicatorsAreaChart extends Component { - renderContent() { - const { t, fsd, indicatorType, startDate, endDate, theme } = this.props; - const interval = 'day'; - const finalStartDate = startDate || monthsAgo(12); - const finalEndDate = endDate || now(); - const indicatorsTimeSeriesVariables = { - indicatorType: indicatorType || null, - field: 'created_at', - operation: 'count', - startDate: finalStartDate, - endDate: finalEndDate, - interval, - }; - return ( - { - if (props && props.indicatorsTimeSeries) { - const chartData = props.indicatorsTimeSeries.map((entry) => ({ - x: new Date(entry.date), - y: entry.value, - })); - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - } - - render() { - const { t, classes, title, variant, height } = this.props; - return ( -
- - {title || t('Indicators distribution')} - - {variant !== 'inLine' ? ( - - {this.renderContent()} - - ) : ( - this.renderContent() - )} -
- ); - } -} - -IndicatorsAreaChart.propTypes = { - classes: PropTypes.object, - theme: PropTypes.object, - t: PropTypes.func, - md: PropTypes.func, -}; - -export default compose( - inject18n, - withTheme, - withStyles(styles), -)(IndicatorsAreaChart); diff --git a/opencti-platform/opencti-front/src/private/components/observations/indicators/IndicatorsDonut.jsx b/opencti-platform/opencti-front/src/private/components/observations/indicators/IndicatorsDonut.jsx deleted file mode 100644 index 948f73e259a2..000000000000 --- a/opencti-platform/opencti-front/src/private/components/observations/indicators/IndicatorsDonut.jsx +++ /dev/null @@ -1,168 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { assoc, compose, map } from 'ramda'; -import { graphql } from 'react-relay'; -import withTheme from '@mui/styles/withTheme'; -import withStyles from '@mui/styles/withStyles'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import inject18n from '../../../../components/i18n'; -import { donutChartOptions } from '../../../../utils/Charts'; - -const styles = () => ({ - paper: { - height: 300, - minHeight: 300, - maxHeight: 300, - margin: '10px 0 0 0', - padding: 0, - borderRadius: 4, - }, -}); - -const indicatorsDonutDistributionQuery = graphql` - query IndicatorsDonutDistributionQuery( - $field: String! - $operation: StatsOperation! - $limit: Int - $startDate: DateTime - $endDate: DateTime - ) { - indicatorsDistribution( - field: $field - operation: $operation - limit: $limit - startDate: $startDate - endDate: $endDate - ) { - label - value - entity { - ... on Identity { - name - } - } - } - } -`; - -class IndicatorsDonut extends Component { - renderContent() { - const { t, field, startDate, endDate, theme } = this.props; - const indicatorsDistributionVariables = { - field: field || 'pattern_type', - operation: 'count', - limit: 8, - startDate, - endDate, - }; - return ( - { - if ( - props - && props.indicatorsDistribution - && props.indicatorsDistribution.length > 0 - ) { - let data = props.indicatorsDistribution; - if (field && field.includes('internal_id')) { - data = map( - (n) => assoc('label', n.entity.name, n), - props.indicatorsDistribution, - ); - } - const chartData = data.map((n) => n.value); - const labels = data.map((n) => n.label); - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - } - - render() { - const { t, classes, title, variant, height } = this.props; - return ( -
- - {title || t('Indicators distribution')} - - {variant !== 'inLine' ? ( - - {this.renderContent()} - - ) : ( - this.renderContent() - )} -
- ); - } -} - -IndicatorsDonut.propTypes = { - title: PropTypes.string, - field: PropTypes.string, - startDate: PropTypes.string, - endDate: PropTypes.string, - classes: PropTypes.object, - theme: PropTypes.object, - t: PropTypes.func, -}; - -export default compose( - inject18n, - withTheme, - withStyles(styles), -)(IndicatorsDonut); diff --git a/opencti-platform/opencti-front/src/private/components/observations/indicators/IndicatorsHorizontalBars.jsx b/opencti-platform/opencti-front/src/private/components/observations/indicators/IndicatorsHorizontalBars.jsx deleted file mode 100644 index 81bf73ce9330..000000000000 --- a/opencti-platform/opencti-front/src/private/components/observations/indicators/IndicatorsHorizontalBars.jsx +++ /dev/null @@ -1,166 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose } from 'ramda'; -import { graphql } from 'react-relay'; -import withTheme from '@mui/styles/withTheme'; -import withStyles from '@mui/styles/withStyles'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import inject18n from '../../../../components/i18n'; -import { horizontalBarsChartOptions } from '../../../../utils/Charts'; -import { simpleNumberFormat } from '../../../../utils/Number'; - -const styles = () => ({ - paper: { - height: 300, - minHeight: 300, - maxHeight: 300, - margin: '10px 0 0 0', - padding: 0, - borderRadius: 4, - }, -}); - -const indicatorsHorizontalBarsDistributionQuery = graphql` - query IndicatorsHorizontalBarsDistributionQuery( - $field: String! - $operation: StatsOperation! - $limit: Int - $startDate: DateTime - $endDate: DateTime - ) { - indicatorsDistribution( - field: $field - operation: $operation - limit: $limit - startDate: $startDate - endDate: $endDate - ) { - label - value - entity { - ... on Indicator { - name - } - } - } - } -`; - -class IndicatorsHorizontalBars extends Component { - renderContent() { - const { t, field, startDate, endDate, theme } = this.props; - const indicatorsDistributionVariables = { - field: field || 'pattern_type', - operation: 'count', - limit: 8, - startDate, - endDate, - }; - return ( - { - if ( - props - && props.indicatorsDistribution - && props.indicatorsDistribution.length > 0 - ) { - const data = props.indicatorsDistribution.map((n) => ({ - x: n.label, - y: n.value, - })); - const chartData = [{ name: t('Number of indicators'), data }]; - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - } - - render() { - const { t, classes, title, variant, height } = this.props; - return ( -
- - {title || t('Indicators distribution')} - - {variant !== 'inLine' ? ( - - {this.renderContent()} - - ) : ( - this.renderContent() - )} -
- ); - } -} - -IndicatorsHorizontalBars.propTypes = { - title: PropTypes.string, - field: PropTypes.string, - startDate: PropTypes.string, - endDate: PropTypes.string, - classes: PropTypes.object, - theme: PropTypes.object, - t: PropTypes.func, -}; - -export default compose( - inject18n, - withTheme, - withStyles(styles), -)(IndicatorsHorizontalBars); diff --git a/opencti-platform/opencti-front/src/private/components/observations/indicators/IndicatorsVerticalBars.jsx b/opencti-platform/opencti-front/src/private/components/observations/indicators/IndicatorsVerticalBars.jsx deleted file mode 100644 index 2ec7666b7363..000000000000 --- a/opencti-platform/opencti-front/src/private/components/observations/indicators/IndicatorsVerticalBars.jsx +++ /dev/null @@ -1,167 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose } from 'ramda'; -import { graphql } from 'react-relay'; -import withTheme from '@mui/styles/withTheme'; -import withStyles from '@mui/styles/withStyles'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import inject18n from '../../../../components/i18n'; -import { monthsAgo, now } from '../../../../utils/Time'; -import { verticalBarsChartOptions } from '../../../../utils/Charts'; -import { simpleNumberFormat } from '../../../../utils/Number'; - -const styles = () => ({ - paper: { - minHeight: 280, - height: '100%', - margin: '4px 0 0 0', - padding: '0 0 10px 0', - borderRadius: 4, - }, - chip: { - fontSize: 10, - height: 20, - marginLeft: 10, - }, -}); - -const reporstVerticalBarsTimeSeriesQuery = graphql` - query IndicatorsVerticalBarsTimeSeriesQuery( - $field: String! - $operation: StatsOperation! - $startDate: DateTime! - $endDate: DateTime! - $interval: String! - ) { - indicatorsTimeSeries( - field: $field - operation: $operation - startDate: $startDate - endDate: $endDate - interval: $interval - ) { - date - value - } - } -`; - -class IndicatorsVerticalBars extends Component { - renderContent() { - const { t, fsd, indicatorType, startDate, endDate, theme } = this.props; - const interval = 'day'; - const finalStartDate = startDate || monthsAgo(12); - const finalEndDate = endDate || now(); - const indicatorsTimeSeriesVariables = { - indicatorType: indicatorType || null, - field: 'created_at', - operation: 'count', - startDate: finalStartDate, - endDate: finalEndDate, - interval, - }; - return ( - { - if (props && props.indicatorsTimeSeries) { - const chartData = props.indicatorsTimeSeries.map((entry) => ({ - x: new Date(entry.date), - y: entry.value, - })); - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - } - - render() { - const { t, classes, title, variant, height } = this.props; - return ( -
- - {title || t('Indicators history')} - - {variant !== 'inLine' ? ( - - {this.renderContent()} - - ) : ( - this.renderContent() - )} -
- ); - } -} - -IndicatorsVerticalBars.propTypes = { - classes: PropTypes.object, - theme: PropTypes.object, - t: PropTypes.func, - md: PropTypes.func, -}; - -export default compose( - inject18n, - withTheme, - withStyles(styles), -)(IndicatorsVerticalBars); diff --git a/opencti-platform/opencti-front/src/private/components/observations/indicators/StixCoreObjectIndicatorsAreaChart.jsx b/opencti-platform/opencti-front/src/private/components/observations/indicators/StixCoreObjectIndicatorsAreaChart.jsx deleted file mode 100644 index 6f694f5bb923..000000000000 --- a/opencti-platform/opencti-front/src/private/components/observations/indicators/StixCoreObjectIndicatorsAreaChart.jsx +++ /dev/null @@ -1,182 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose } from 'ramda'; -import { graphql } from 'react-relay'; -import withTheme from '@mui/styles/withTheme'; -import withStyles from '@mui/styles/withStyles'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import inject18n from '../../../../components/i18n'; -import { monthsAgo, now } from '../../../../utils/Time'; -import { areaChartOptions } from '../../../../utils/Charts'; -import { simpleNumberFormat } from '../../../../utils/Number'; - -const styles = () => ({ - paper: { - minHeight: 280, - height: '100%', - margin: '4px 0 0 0', - padding: '0 0 10px 0', - borderRadius: 4, - }, - chip: { - fontSize: 10, - height: 20, - marginLeft: 10, - }, -}); - -const stixCoreObjectIndicatorsAreaChartTimeSeriesQuery = graphql` - query StixCoreObjectIndicatorsAreaChartTimeSeriesQuery( - $objectId: String - $field: String! - $operation: StatsOperation! - $startDate: DateTime! - $endDate: DateTime! - $interval: String! - ) { - indicatorsTimeSeries( - objectId: $objectId - field: $field - operation: $operation - startDate: $startDate - endDate: $endDate - interval: $interval - ) { - date - value - } - } -`; - -class StixCoreObjectIndicatorsAreaChart extends Component { - renderContent() { - const { - t, - fsd, - indicatorType, - startDate, - endDate, - dateAttribute, - stixCoreObjectId, - theme, - } = this.props; - const interval = 'day'; - const finalStartDate = startDate || monthsAgo(12); - const finalEndDate = endDate || now(); - const indicatorsTimeSeriesVariables = { - authorId: null, - objectId: stixCoreObjectId, - indicatorType: indicatorType || null, - field: dateAttribute, - operation: 'count', - startDate: finalStartDate, - endDate: finalEndDate, - interval, - }; - return ( - { - if (props && props.indicatorsTimeSeries) { - const chartData = props.indicatorsTimeSeries.map((entry) => ({ - x: new Date(entry.date), - y: entry.value, - })); - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - } - - render() { - const { t, classes, title, variant, height } = this.props; - return ( -
- - {title || t('Indicators history')} - - {variant !== 'inLine' ? ( - - {this.renderContent()} - - ) : ( - this.renderContent() - )} -
- ); - } -} - -StixCoreObjectIndicatorsAreaChart.propTypes = { - classes: PropTypes.object, - theme: PropTypes.object, - stixCoreObjectId: PropTypes.string, - dateAttribute: PropTypes.string, - t: PropTypes.func, - md: PropTypes.func, -}; - -export default compose( - inject18n, - withTheme, - withStyles(styles), -)(StixCoreObjectIndicatorsAreaChart); diff --git a/opencti-platform/opencti-front/src/private/components/observations/indicators/StixCoreObjectIndicatorsDonut.jsx b/opencti-platform/opencti-front/src/private/components/observations/indicators/StixCoreObjectIndicatorsDonut.jsx deleted file mode 100644 index 98865f033979..000000000000 --- a/opencti-platform/opencti-front/src/private/components/observations/indicators/StixCoreObjectIndicatorsDonut.jsx +++ /dev/null @@ -1,148 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose } from 'ramda'; -import { graphql } from 'react-relay'; -import withTheme from '@mui/styles/withTheme'; -import withStyles from '@mui/styles/withStyles'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import inject18n from '../../../../components/i18n'; -import { donutChartOptions } from '../../../../utils/Charts'; - -const styles = () => ({ - paper: { - height: 300, - minHeight: 300, - maxHeight: 300, - margin: '10px 0 0 0', - padding: 0, - borderRadius: 4, - }, -}); - -const stixCoreObjectIndicatorsDonutDistributionQuery = graphql` - query StixCoreObjectIndicatorsDonutDistributionQuery( - $objectId: String - $field: String! - $operation: StatsOperation! - $limit: Int - ) { - indicatorsDistribution( - objectId: $objectId - field: $field - operation: $operation - limit: $limit - ) { - label - value - } - } -`; - -class StixCoreObjectIndicatorsDonut extends Component { - renderContent() { - const { t, stixCoreObjectId, field, theme } = this.props; - const indicatorsDistributionVariables = { - objectId: stixCoreObjectId, - field: field || 'indicator_types', - operation: 'count', - limit: 8, - }; - return ( - { - if ( - props - && props.indicatorsDistribution - && props.indicatorsDistribution.length > 0 - ) { - const data = props.indicatorsDistribution; - const chartData = data.map((n) => n.value); - const labels = data.map((n) => n.label); - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - } - - render() { - const { t, classes, title, variant, height } = this.props; - return ( -
- - {title || t('Indicators distribution')} - - {variant !== 'inLine' ? ( - - {this.renderContent()} - - ) : ( - this.renderContent() - )} -
- ); - } -} - -StixCoreObjectIndicatorsDonut.propTypes = { - stixCoreObjectId: PropTypes.string, - title: PropTypes.string, - field: PropTypes.string, - classes: PropTypes.object, - theme: PropTypes.object, - t: PropTypes.func, -}; - -export default compose( - inject18n, - withTheme, - withStyles(styles), -)(StixCoreObjectIndicatorsDonut); diff --git a/opencti-platform/opencti-front/src/private/components/observations/indicators/StixCoreObjectIndicatorsHorizontalBars.jsx b/opencti-platform/opencti-front/src/private/components/observations/indicators/StixCoreObjectIndicatorsHorizontalBars.jsx deleted file mode 100644 index 2fe0b5433bab..000000000000 --- a/opencti-platform/opencti-front/src/private/components/observations/indicators/StixCoreObjectIndicatorsHorizontalBars.jsx +++ /dev/null @@ -1,162 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose } from 'ramda'; -import { graphql } from 'react-relay'; -import withStyles from '@mui/styles/withStyles'; -import withTheme from '@mui/styles/withTheme'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import inject18n from '../../../../components/i18n'; -import { horizontalBarsChartOptions } from '../../../../utils/Charts'; -import { simpleNumberFormat } from '../../../../utils/Number'; - -const styles = () => ({ - paper: { - height: 300, - minHeight: 300, - maxHeight: 300, - margin: '10px 0 0 0', - padding: 0, - borderRadius: 4, - }, -}); - -const stixCoreObjectIndicatorsHorizontalBarsDistributionQuery = graphql` - query StixCoreObjectIndicatorsHorizontalBarsDistributionQuery( - $objectId: String - $field: String! - $operation: StatsOperation! - $limit: Int - ) { - indicatorsDistribution( - objectId: $objectId - field: $field - operation: $operation - limit: $limit - ) { - label - value - entity { - ... on Identity { - name - } - } - } - } -`; - -class StixCoreObjectIndicatorsHorizontalBars extends Component { - renderContent() { - const { t, stixCoreObjectId, field, theme } = this.props; - const indicatorsDistributionVariables = { - objectId: stixCoreObjectId, - field: field || 'indicator_types', - operation: 'count', - limit: 8, - }; - return ( - { - if ( - props - && props.indicatorsDistribution - && props.indicatorsDistribution.length > 0 - ) { - const data = props.indicatorsDistribution.map((n) => ({ - x: n.label, - y: n.value, - })); - const chartData = [{ name: t('Number of indicators'), data }]; - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - } - - render() { - const { t, classes, title, variant, height } = this.props; - return ( -
- - {title || t('Indicators distribution')} - - {variant !== 'inLine' ? ( - - {this.renderContent()} - - ) : ( - this.renderContent() - )} -
- ); - } -} - -StixCoreObjectIndicatorsHorizontalBars.propTypes = { - stixCoreObjectId: PropTypes.string, - title: PropTypes.string, - field: PropTypes.string, - classes: PropTypes.object, - theme: PropTypes.object, - t: PropTypes.func, -}; - -export default compose( - inject18n, - withTheme, - withStyles(styles), -)(StixCoreObjectIndicatorsHorizontalBars); diff --git a/opencti-platform/opencti-front/src/private/components/observations/indicators/StixCoreObjectIndicatorsVerticalBars.jsx b/opencti-platform/opencti-front/src/private/components/observations/indicators/StixCoreObjectIndicatorsVerticalBars.jsx deleted file mode 100644 index e8d79268354d..000000000000 --- a/opencti-platform/opencti-front/src/private/components/observations/indicators/StixCoreObjectIndicatorsVerticalBars.jsx +++ /dev/null @@ -1,182 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose } from 'ramda'; -import { graphql } from 'react-relay'; -import withTheme from '@mui/styles/withTheme'; -import withStyles from '@mui/styles/withStyles'; -import CircularProgress from '@mui/material/CircularProgress'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Chart from '../../common/charts/Chart'; -import { QueryRenderer } from '../../../../relay/environment'; -import inject18n from '../../../../components/i18n'; -import { monthsAgo, now } from '../../../../utils/Time'; -import { verticalBarsChartOptions } from '../../../../utils/Charts'; -import { simpleNumberFormat } from '../../../../utils/Number'; - -const styles = () => ({ - paper: { - minHeight: 280, - height: '100%', - margin: '4px 0 0 0', - padding: '0 0 10px 0', - borderRadius: 4, - }, - chip: { - fontSize: 10, - height: 20, - marginLeft: 10, - }, -}); - -const stixCoreObjectReporstVerticalBarsTimeSeriesQuery = graphql` - query StixCoreObjectIndicatorsVerticalBarsTimeSeriesQuery( - $objectId: String - $field: String! - $operation: StatsOperation! - $startDate: DateTime! - $endDate: DateTime! - $interval: String! - ) { - indicatorsTimeSeries( - objectId: $objectId - field: $field - operation: $operation - startDate: $startDate - endDate: $endDate - interval: $interval - ) { - date - value - } - } -`; - -class IndicatorsVerticalBars extends Component { - renderContent() { - const { - t, - fsd, - indicatorType, - startDate, - endDate, - dateAttribute, - stixCoreObjectId, - theme, - } = this.props; - const interval = 'day'; - const finalStartDate = startDate || monthsAgo(12); - const finalEndDate = endDate || now(); - const indicatorsTimeSeriesVariables = { - authorId: null, - objectId: stixCoreObjectId, - indicatorType: indicatorType || null, - field: dateAttribute, - operation: 'count', - startDate: finalStartDate, - endDate: finalEndDate, - interval, - }; - return ( - { - if (props && props.indicatorsTimeSeries) { - const chartData = props.indicatorsTimeSeries.map((entry) => ({ - x: new Date(entry.date), - y: entry.value, - })); - return ( - - ); - } - if (props) { - return ( -
- - {t('No entities of this type has been found.')} - -
- ); - } - return ( -
- - - -
- ); - }} - /> - ); - } - - render() { - const { t, classes, title, variant, height } = this.props; - return ( -
- - {title || t('Indicators history')} - - {variant !== 'inLine' ? ( - - {this.renderContent()} - - ) : ( - this.renderContent() - )} -
- ); - } -} - -IndicatorsVerticalBars.propTypes = { - classes: PropTypes.object, - theme: PropTypes.object, - stixCoreObjectId: PropTypes.string, - dateAttribute: PropTypes.string, - t: PropTypes.func, - md: PropTypes.func, -}; - -export default compose( - inject18n, - withTheme, - withStyles(styles), -)(IndicatorsVerticalBars); diff --git a/opencti-platform/opencti-front/src/private/components/observations/stix_cyber_observables/StixCyberObservableEntitiesLines.jsx b/opencti-platform/opencti-front/src/private/components/observations/stix_cyber_observables/StixCyberObservableEntitiesLines.jsx index bfb7fa590585..ceddb8cabd17 100644 --- a/opencti-platform/opencti-front/src/private/components/observations/stix_cyber_observables/StixCyberObservableEntitiesLines.jsx +++ b/opencti-platform/opencti-front/src/private/components/observations/stix_cyber_observables/StixCyberObservableEntitiesLines.jsx @@ -14,7 +14,7 @@ import * as R from 'ramda'; import { AutoFix } from 'mdi-material-ui'; import Chip from '@mui/material/Chip'; import ItemIcon from '../../../../components/ItemIcon'; -import { defaultValue } from '../../../../utils/Graph'; +import { getMainRepresentative } from '../../../../utils/defaultRepresentatives'; import inject18n from '../../../../components/i18n'; import { resolveLink } from '../../../../utils/Entity'; import { TEN_SECONDS } from '../../../../utils/Time'; @@ -229,8 +229,8 @@ class StixCyberObservableEntitiesLinesComponent extends Component { || targetEntity.entity_type === 'stix-relation' ? `${targetEntity.from.name} ${String.fromCharCode( 8594, - )} ${defaultValue(targetEntity.to)}` - : defaultValue(targetEntity) + )} ${getMainRepresentative(targetEntity.to)}` + : getMainRepresentative(targetEntity) : t('Restricted')}
- {defaultValue(stixCoreObject)} + {getMainRepresentative(stixCoreObject)}
= ({ {truncate( Object.values(selectedElements || {}) - .map((o) => defaultValue(o)) + .map((o) => getMainRepresentative(o)) .join(', '), 80, )} @@ -371,7 +371,7 @@ const NotificationsToolBar: FunctionComponent = ({ {truncate( (o.context?.values ?? []) - .map((p) => (typeof p === 'string' ? p : defaultValue(p))) + .map((p) => (typeof p === 'string' ? p : getMainRepresentative(p))) .join(', '), 80, )} diff --git a/opencti-platform/opencti-front/src/private/components/search/SearchStixCoreObjectLine.jsx b/opencti-platform/opencti-front/src/private/components/search/SearchStixCoreObjectLine.jsx index ae7fc8d4717f..2c5acdaa1186 100644 --- a/opencti-platform/opencti-front/src/private/components/search/SearchStixCoreObjectLine.jsx +++ b/opencti-platform/opencti-front/src/private/components/search/SearchStixCoreObjectLine.jsx @@ -15,7 +15,7 @@ import StixCoreObjectLabels from '../common/stix_core_objects/StixCoreObjectLabe import ItemIcon from '../../../components/ItemIcon'; import ItemMarkings from '../../../components/ItemMarkings'; import { resolveLink } from '../../../utils/Entity'; -import { defaultValue } from '../../../utils/Graph'; +import { getMainRepresentative } from '../../../utils/defaultRepresentatives'; import ItemEntityType from '../../../components/ItemEntityType'; const useStyles = makeStyles((theme) => ({ @@ -118,7 +118,7 @@ const SearchStixCoreObjectLineComponent = ({ className={classes.bodyItem} style={{ width: dataColumns.value.width }} > - {defaultValue(node)} + {getMainRepresentative(node)}
- {defaultValue(node)} + {getMainRepresentative(node)}
keyword === '' - || (defaultValue(n) || '').toLowerCase().indexOf(keyword.toLowerCase()) + || (getMainRepresentative(n) || '').toLowerCase().indexOf(keyword.toLowerCase()) !== -1 - || (defaultSecondaryValue(n) || '') + || (getSecondaryRepresentative(n) || '') .toLowerCase() .indexOf(keyword.toLowerCase()) !== -1 || (n.entity_type || '').toLowerCase().indexOf(keyword.toLowerCase()) diff --git a/opencti-platform/opencti-front/src/public/components/dashboard/stix_core_objects/PublicStixCoreObjectsDistributionList.tsx b/opencti-platform/opencti-front/src/public/components/dashboard/stix_core_objects/PublicStixCoreObjectsDistributionList.tsx index 6074af33abcf..4a42cd3da85d 100644 --- a/opencti-platform/opencti-front/src/public/components/dashboard/stix_core_objects/PublicStixCoreObjectsDistributionList.tsx +++ b/opencti-platform/opencti-front/src/public/components/dashboard/stix_core_objects/PublicStixCoreObjectsDistributionList.tsx @@ -8,6 +8,7 @@ import WidgetContainer from '../../../../components/dashboard/WidgetContainer'; import WidgetLoader from '../../../../components/dashboard/WidgetLoader'; import WidgetDistributionList from '../../../../components/dashboard/WidgetDistributionList'; import { PublicStixCoreObjectsDistributionListQuery } from './__generated__/PublicStixCoreObjectsDistributionListQuery.graphql'; +import { getMainRepresentative } from '../../../../utils/defaultRepresentatives'; const publicStixCoreObjectsDistributionListQuery = graphql` query PublicStixCoreObjectsDistributionListQuery( @@ -25,39 +26,34 @@ const publicStixCoreObjectsDistributionListQuery = graphql` label value entity { - ... on StixObject { + ... on BasicObject { id entity_type - representative { - main - } } - ... on StixRelationship { + ... on BasicRelationship { id entity_type - representative { - main - } } - ... on Creator { - id - entity_type + ... on StixObject { representative { main } } + + # need colors when available ... on Label { - value color } ... on MarkingDefinition { x_opencti_color } - ... on Status { - template { - name - color - } + + # internal objects + ... on Creator { + name + } + ... on Group { + name } } } @@ -78,20 +74,21 @@ const PublicStixCoreObjectsDistributionListComponent = ({ ); if (publicStixCoreObjectsDistribution && publicStixCoreObjectsDistribution.length > 0) { - const data = publicStixCoreObjectsDistribution.flatMap((o) => { - if (!o) return []; + const data = publicStixCoreObjectsDistribution.flatMap((n) => { + if (!n) return []; + let { label } = n; + if (t_i18n(`entity_${n.label}`) !== `entity_${n.label}`) { + label = t_i18n(`entity_${n.label}`); + } + if (n.entity) { + label = getMainRepresentative(n.entity); + } return { - label: - // eslint-disable-next-line no-nested-ternary - o.entity?.representative?.main - ? o.entity?.representative?.main - : t_i18n(`entity_${o.label}`) !== `entity_${o.label}` - ? t_i18n(`entity_${o.label}`) - : o.label, - value: o.value, - color: o.entity?.color ?? o.entity?.x_opencti_color, - id: o.entity?.id ?? null, - type: o.entity?.entity_type ?? o.label, + label, + value: n.value, + color: n.entity?.color ?? n.entity?.x_opencti_color, + id: n.entity?.id ?? null, + type: n.entity?.entity_type ?? n.label, }; }); return ; diff --git a/opencti-platform/opencti-front/src/public/components/dashboard/stix_core_objects/PublicStixCoreObjectsDonut.tsx b/opencti-platform/opencti-front/src/public/components/dashboard/stix_core_objects/PublicStixCoreObjectsDonut.tsx index a9adbf3ce447..4d1253daae57 100644 --- a/opencti-platform/opencti-front/src/public/components/dashboard/stix_core_objects/PublicStixCoreObjectsDonut.tsx +++ b/opencti-platform/opencti-front/src/public/components/dashboard/stix_core_objects/PublicStixCoreObjectsDonut.tsx @@ -27,137 +27,37 @@ const publicStixCoreObjectsDonutQuery = graphql` value entity { ... on BasicObject { + id entity_type } ... on BasicRelationship { + id entity_type } - ... on AttackPattern { - name - description - } - ... on Campaign { - name - description - } - ... on CourseOfAction { - name - description - } - ... on Individual { - name - description - } - ... on Organization { - name - description - } - ... on Sector { - name - description - } - ... on System { - name - description - } - ... on Indicator { - name - description - } - ... on Infrastructure { - name - description - } - ... on IntrusionSet { - name - description - } - ... on Position { - name - description - } - ... on City { - name - description - } - ... on AdministrativeArea { - name - description - } - ... on Country { - name - description - } - ... on Region { - name - description - } - ... on Malware { - name - description - } - ... on MalwareAnalysis { - result_name - } - ... on ThreatActor { - name - description - } - ... on Tool { - name - description - } - ... on Vulnerability { - name - description - } - ... on Incident { - name - description - } - ... on Event { - name - description - } - ... on Channel { - name - description - } - ... on Narrative { - name - description - } - ... on Language { - name + ... on StixObject { + representative { + main + } } - ... on DataComponent { - name + ... on StixRelationship { + representative { + main + } } - ... on DataSource { + # internal objects + ... on Creator { name } - ... on Case { + ... on Group { name } - ... on StixCyberObservable { - observable_value + # need colors when available + ... on Label { + color } ... on MarkingDefinition { - definition_type - definition x_opencti_color } - ... on KillChainPhase { - kill_chain_name - phase_name - } - ... on Creator { - name - } - ... on Label { - value - color - } ... on Status { template { name diff --git a/opencti-platform/opencti-front/src/public/components/dashboard/stix_core_objects/PublicStixCoreObjectsHorizontalBars.tsx b/opencti-platform/opencti-front/src/public/components/dashboard/stix_core_objects/PublicStixCoreObjectsHorizontalBars.tsx index bf05a5b6a007..8984bc5a880d 100644 --- a/opencti-platform/opencti-front/src/public/components/dashboard/stix_core_objects/PublicStixCoreObjectsHorizontalBars.tsx +++ b/opencti-platform/opencti-front/src/public/components/dashboard/stix_core_objects/PublicStixCoreObjectsHorizontalBars.tsx @@ -1,18 +1,15 @@ import { graphql, PreloadedQuery, usePreloadedQuery } from 'react-relay'; import React from 'react'; -import { useTheme } from '@mui/styles'; import type { PublicManifestWidget } from '../PublicManifest'; import { useFormatter } from '../../../../components/i18n'; import WidgetNoData from '../../../../components/dashboard/WidgetNoData'; -import { itemColor } from '../../../../utils/Colors'; -import { defaultValue } from '../../../../utils/Graph'; import WidgetHorizontalBars from '../../../../components/dashboard/WidgetHorizontalBars'; -import type { Theme } from '../../../../components/Theme'; import type { PublicWidgetContainerProps } from '../PublicWidgetContainerProps'; import useQueryLoading from '../../../../utils/hooks/useQueryLoading'; import WidgetContainer from '../../../../components/dashboard/WidgetContainer'; import WidgetLoader from '../../../../components/dashboard/WidgetLoader'; import { PublicStixCoreObjectsHorizontalBarsQuery } from './__generated__/PublicStixCoreObjectsHorizontalBarsQuery.graphql'; +import useDistributionGraphData from '../../../../utils/hooks/useDistributionGraphData'; const publicStixCoreObjectsHorizontalBarsQuery = graphql` query PublicStixCoreObjectsHorizontalBarsQuery( @@ -31,148 +28,37 @@ const publicStixCoreObjectsHorizontalBarsQuery = graphql` value entity { ... on BasicObject { - entity_type id + entity_type } ... on BasicRelationship { - entity_type id + entity_type } - ... on AttackPattern { - name - description - } - ... on Campaign { - name - description - } - ... on CourseOfAction { - name - description - } - ... on Individual { - name - description - } - ... on Organization { - name - description - } - ... on Sector { - name - description - } - ... on System { - name - description - } - ... on Indicator { - name - description - } - ... on Infrastructure { - name - description - } - ... on IntrusionSet { - name - description - } - ... on Position { - name - description - } - ... on City { - name - description - } - ... on AdministrativeArea { - name - description - } - ... on Country { - name - description - } - ... on Region { - name - description - } - ... on Malware { - name - description - } - ... on MalwareAnalysis { - result_name - } - ... on ThreatActor { - name - description - } - ... on Tool { - name - description - } - ... on Vulnerability { - name - description - } - ... on Incident { - name - description - } - ... on Event { - name - description - } - ... on Channel { - name - description - } - ... on Narrative { - name - description - } - ... on Language { - name - } - ... on DataComponent { - name - } - ... on DataSource { - name - } - ... on Case { - name - } - ... on StixCyberObservable { - observable_value + ... on StixObject { + representative { + main + } } - ... on MarkingDefinition { - definition_type - definition - x_opencti_color + ... on StixRelationship { + representative { + main + } } + # internal objects ... on Creator { name } - ... on Report { - name - } - ... on Grouping { + ... on Group { name } - ... on Note { - attribute_abstract - content - } - ... on Opinion { - opinion - } + # need colors when available ... on Label { - value color } + ... on MarkingDefinition { + x_opencti_color + } ... on Status { template { name @@ -195,8 +81,7 @@ const PublicStixCoreObjectsHorizontalBarsComponent = ({ dataSelection, queryRef, }: PublicStixCoreObjectsHorizontalBarsComponentProps) => { - const theme = useTheme(); - const { t_i18n } = useFormatter(); + const { buildWidgetProps } = useDistributionGraphData(); const { publicStixCoreObjectsDistribution } = usePreloadedQuery( publicStixCoreObjectsHorizontalBarsQuery, queryRef, @@ -207,57 +92,10 @@ const PublicStixCoreObjectsHorizontalBarsComponent = ({ && publicStixCoreObjectsDistribution.length > 0 ) { const selection = dataSelection[0]; - const data = publicStixCoreObjectsDistribution.map((n) => { - let color = selection.attribute?.endsWith('_id') - ? itemColor(n?.entity?.entity_type) - : itemColor(n?.label); - if (n?.entity?.color) { - color = theme.palette.mode === 'light' && n.entity.color === '#ffffff' - ? '#000000' - : n.entity.color; - } - if (n?.entity?.x_opencti_color) { - color = theme.palette.mode === 'light' - && n.entity.x_opencti_color === '#ffffff' - ? '#000000' - : n.entity.x_opencti_color; - } - if (n?.entity?.template?.color) { - color = theme.palette.mode === 'light' - && n.entity.template.color === '#ffffff' - ? '#000000' - : n.entity.template.color; - } - return { - // eslint-disable-next-line no-nested-ternary - x: selection.attribute?.endsWith('_id') - ? defaultValue(n?.entity) - : selection.attribute === 'entity_type' - ? t_i18n(`entity_${n?.label}`) - : n?.label, - y: n?.value, - fillColor: color, - }; - }); - const chartData = [ - { - name: selection.label || t_i18n('Number of relationships'), - data, - }, - ]; - const redirectionUtils = selection.attribute === 'name' - ? publicStixCoreObjectsDistribution.flatMap((n) => { - if (!n || !n.entity) return []; - return { - id: n.entity.id, - entity_type: n.entity.entity_type, - }; - }) - : undefined; - + const { series, redirectionUtils } = buildWidgetProps(publicStixCoreObjectsDistribution, selection, 'Entities number'); return ( 0) { const finalField = dataSelection[0].attribute || 'entity_type'; const data = publicStixRelationshipsDistribution.flatMap((o) => { if (!o) return []; return { label: finalField.endsWith('_id') - ? defaultValue(o.entity) + ? getMainRepresentative(o.entity, t_i18n('Restricted')) : o.label, value: o.value, id: o.entity?.id ?? null, diff --git a/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsDonut.tsx b/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsDonut.tsx index 02a4a9401cff..0fbd549b2ad4 100644 --- a/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsDonut.tsx +++ b/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsDonut.tsx @@ -27,145 +27,43 @@ const publicStixRelationshipsDonutQuery = graphql` value entity { ... on BasicObject { + id entity_type } ... on BasicRelationship { + id entity_type } - ... on AttackPattern { - name - description - } - ... on Campaign { - name - description - } - ... on CourseOfAction { - name - description - } - ... on Individual { - name - description - } - ... on Organization { - name - description - } - ... on Sector { - name - description - } - ... on System { - name - description - } - ... on Indicator { - name - description + ... on StixObject { + representative { + main + } } - ... on Infrastructure { - name - description - } - ... on IntrusionSet { - name - description - } - ... on Position { - name - description - } - ... on City { - name - description - } - ... on Country { - name - description - } - ... on Region { - name - description - } - ... on Malware { - name - description - } - ... on ThreatActor { - name - description - } - ... on Tool { - name - description - } - ... on Vulnerability { - name - description - } - ... on Incident { - name - description - } - ... on Event { - name - description - } - ... on Channel { - name - description - } - ... on Narrative { - name - description - } - ... on Language { - name - } - ... on DataComponent { - name - description - } - ... on DataSource { - name - description - } - ... on Case { - name - description - } - ... on StixCyberObservable { - observable_value - } - ... on MarkingDefinition { - definition_type - definition - } - ... on KillChainPhase { - kill_chain_name - phase_name + ... on StixRelationship { + representative { + main + } } + # internal objects ... on Creator { name } - ... on Report { + ... on Group { name } - ... on Grouping { - name - } - ... on Note { - attribute_abstract - content - } - ... on Opinion { - opinion - } + # need colors when available ... on Label { - value color } + ... on MarkingDefinition { + x_opencti_color + } + ... on Status { + template { + name + color + } + } } } } diff --git a/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsHorizontalBars.tsx b/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsHorizontalBars.tsx index 39fa5e1d5b99..3ec87173c760 100644 --- a/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsHorizontalBars.tsx +++ b/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsHorizontalBars.tsx @@ -1,11 +1,7 @@ import { graphql, PreloadedQuery, usePreloadedQuery } from 'react-relay'; -import { useTheme } from '@mui/styles'; import React from 'react'; import type { PublicManifestWidget } from '../PublicManifest'; -import type { Theme } from '../../../../components/Theme'; import { useFormatter } from '../../../../components/i18n'; -import { itemColor } from '../../../../utils/Colors'; -import { defaultValue } from '../../../../utils/Graph'; import WidgetHorizontalBars from '../../../../components/dashboard/WidgetHorizontalBars'; import WidgetNoData from '../../../../components/dashboard/WidgetNoData'; import type { PublicWidgetContainerProps } from '../PublicWidgetContainerProps'; @@ -13,6 +9,7 @@ import useQueryLoading from '../../../../utils/hooks/useQueryLoading'; import WidgetContainer from '../../../../components/dashboard/WidgetContainer'; import WidgetLoader from '../../../../components/dashboard/WidgetLoader'; import { PublicStixRelationshipsHorizontalBarsQuery } from './__generated__/PublicStixRelationshipsHorizontalBarsQuery.graphql'; +import useDistributionGraphData from '../../../../utils/hooks/useDistributionGraphData'; const publicStixRelationshipsHorizontalBarsQuery = graphql` query PublicStixRelationshipsHorizontalBarsQuery( @@ -31,147 +28,42 @@ const publicStixRelationshipsHorizontalBarsQuery = graphql` value entity { ... on BasicObject { - entity_type id + entity_type } ... on BasicRelationship { - entity_type id + entity_type } - ... on AttackPattern { - name - description - } - ... on Campaign { - name - description - } - ... on CourseOfAction { - name - description - } - ... on Individual { - name - description - } - ... on Organization { - name - description - } - ... on Sector { - name - description - } - ... on System { - name - description - } - ... on Indicator { - name - description - } - ... on Infrastructure { - name - description - } - ... on IntrusionSet { - name - description - } - ... on Position { - name - description - } - ... on City { - name - description - } - ... on Country { - name - description - } - ... on Region { - name - description - } - ... on Malware { - name - description - } - ... on ThreatActor { - name - description - } - ... on Tool { - name - description - } - ... on Vulnerability { - name - description - } - ... on Incident { - name - description - } - ... on Event { - name - description - } - ... on Channel { - name - description - } - ... on Narrative { - name - description + ... on StixObject { + representative { + main + } } - ... on Language { - name - } - ... on DataComponent { - name + ... on StixRelationship { + representative { + main + } } - ... on DataSource { - name - } - ... on Case { + # internal objects + ... on Creator { name } - ... on Report { + ... on Group { name } - ... on StixCyberObservable { - observable_value + # need colors when available + ... on Label { + color } ... on MarkingDefinition { - definition_type - definition x_opencti_color } - ... on KillChainPhase { - kill_chain_name - phase_name - } - ... on Creator { - name - } - ... on Report { - name - } - ... on Grouping { - name - } - ... on Note { - attribute_abstract - content - } - ... on Opinion { - opinion - } - ... on Label { - value - color + ... on Status { + template { + name + color + } } } } @@ -189,8 +81,7 @@ const PublicStixRelationshipsHorizontalBarsComponent = ({ dataSelection, queryRef, }: PublicStixRelationshipsHorizontalBarsComponentProps) => { - const theme = useTheme(); - const { t_i18n } = useFormatter(); + const { buildWidgetProps } = useDistributionGraphData(); const { publicStixRelationshipsDistribution } = usePreloadedQuery( publicStixRelationshipsHorizontalBarsQuery, queryRef, @@ -201,47 +92,10 @@ const PublicStixRelationshipsHorizontalBarsComponent = ({ && publicStixRelationshipsDistribution.length > 0 ) { const selection = dataSelection[0]; - const finalField = selection.attribute || 'entity_type'; - const data = publicStixRelationshipsDistribution.map((n) => { - let color = selection.attribute?.endsWith('_id') - ? itemColor(n?.entity?.entity_type) - : itemColor(n?.label); - if (n?.entity?.color) { - color = theme.palette.mode === 'light' && n.entity.color === '#ffffff' - ? '#000000' - : n.entity.color; - } - if (n?.entity?.x_opencti_color) { - color = theme.palette.mode === 'light' - && n.entity.x_opencti_color === '#ffffff' - ? '#000000' - : n.entity.x_opencti_color; - } - return { - x: finalField.endsWith('_id') - ? defaultValue(n?.entity) - : n?.label, - y: n?.value, - fillColor: color, - }; - }); - const chartData = [{ - name: selection.label || t_i18n('Number of relationships'), - data, - }]; - const redirectionUtils = finalField.endsWith('_id') - ? publicStixRelationshipsDistribution.flatMap((n) => { - if (!n || !n.entity) return []; - return { - id: n.entity.id, - entity_type: n.entity.entity_type, - }; - }) - : undefined; - + const { series, redirectionUtils } = buildWidgetProps(publicStixRelationshipsDistribution, selection, 'Number of relationships'); return ( 0 @@ -358,19 +145,21 @@ const PublicStixRelationshipsMultiHorizontalBarsComponent = ({ const subSelection = dataSelection[1]; const finalSubDistributionField = subSelection.attribute || 'entity_type'; - const categories = publicStixRelationshipsDistribution.map((n) => defaultValue(n?.entity)); + const categories = publicStixRelationshipsDistribution.map((n) => getMainRepresentative(n?.entity)); const entitiesMapping: Record = {}; for (const distrib of publicStixRelationshipsDistribution) { for (const subDistrib of distrib?.breakdownDistribution ?? []) { - entitiesMapping[ - finalSubDistributionField === 'internal_id' - ? defaultValue(subDistrib?.entity) - : subDistrib?.label - ] = (entitiesMapping[ - finalSubDistributionField === 'internal_id' - ? defaultValue(subDistrib?.entity) - : subDistrib?.label - ] || 0) + (subDistrib?.value ?? 0); + if (distrib && subDistrib) { + entitiesMapping[ + finalSubDistributionField === 'internal_id' + ? getMainRepresentative(subDistrib?.entity) + : subDistrib?.label + ] = (entitiesMapping[ + finalSubDistributionField === 'internal_id' + ? getMainRepresentative(subDistrib?.entity) + : subDistrib?.label + ] || 0) + (subDistrib?.value ?? 0); + } } } const sortedEntityMapping = R.take( @@ -383,7 +172,7 @@ const PublicStixRelationshipsMultiHorizontalBarsComponent = ({ const entityData = R.head( (distrib?.breakdownDistribution ?? []).filter( (n) => (finalSubDistributionField === 'internal_id' - ? defaultValue(n?.entity) + ? getMainRepresentative(n?.entity, t_i18n('Restricted')) : n?.label) === sortedEntity[0], ), ); @@ -391,21 +180,21 @@ const PublicStixRelationshipsMultiHorizontalBarsComponent = ({ if (entityData && entityData.value) { value = entityData.value; } - if (categoriesValues[defaultValue(distrib?.entity)]) { - categoriesValues[defaultValue(distrib?.entity)].push(value); + if (categoriesValues[getMainRepresentative(distrib?.entity)]) { + categoriesValues[getMainRepresentative(distrib?.entity)].push(value); } else { - categoriesValues[defaultValue(distrib?.entity)] = [value]; + categoriesValues[getMainRepresentative(distrib?.entity)] = [value]; } } const sum = ( - categoriesValues[defaultValue(distrib?.entity)] || [] + categoriesValues[getMainRepresentative(distrib?.entity)] || [] ).reduce((partialSum, a) => partialSum + a, 0); - if (categoriesValues[defaultValue(distrib?.entity)]) { - categoriesValues[defaultValue(distrib?.entity)].push( + if (categoriesValues[getMainRepresentative(distrib?.entity)]) { + categoriesValues[getMainRepresentative(distrib?.entity)].push( (distrib?.value ?? 0) - sum, ); } else { - categoriesValues[defaultValue(distrib?.entity)] = [ + categoriesValues[getMainRepresentative(distrib?.entity)] = [ (distrib?.value ?? 0) - sum, ]; } diff --git a/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsPolarArea.tsx b/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsPolarArea.tsx index 670105bf8f05..80e0be1602d9 100644 --- a/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsPolarArea.tsx +++ b/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsPolarArea.tsx @@ -9,7 +9,7 @@ import WidgetContainer from '../../../../components/dashboard/WidgetContainer'; import WidgetLoader from '../../../../components/dashboard/WidgetLoader'; import { PublicStixRelationshipsPolarAreaQuery } from './__generated__/PublicStixRelationshipsPolarAreaQuery.graphql'; import WidgetPolarArea from '../../../../components/dashboard/WidgetPolarArea'; -import { defaultValue } from '../../../../utils/Graph'; +import { getMainRepresentative, isFieldForIdentifier } from '../../../../utils/defaultRepresentatives'; const publicStixRelationshipsPolarAreaQuery = graphql` query PublicStixRelationshipsPolarAreaQuery( @@ -28,140 +28,42 @@ const publicStixRelationshipsPolarAreaQuery = graphql` value entity { ... on BasicObject { + id entity_type } ... on BasicRelationship { + id entity_type } - ... on AttackPattern { - name - description - } - ... on Campaign { - name - description - } - ... on CourseOfAction { - name - description - } - ... on Individual { - name - description - } - ... on Organization { - name - description - } - ... on Sector { - name - description - } - ... on System { - name - description - } - ... on Indicator { - name - description - } - ... on Infrastructure { - name - description - } - ... on IntrusionSet { - name - description - } - ... on Position { - name - description - } - ... on City { - name - description - } - ... on Country { - name - description - } - ... on Region { - name - description - } - ... on Malware { - name - description - } - ... on ThreatActor { - name - description - } - ... on Tool { - name - description - } - ... on Vulnerability { - name - description - } - ... on Incident { - name - description - } - ... on Event { - name - description - } - ... on Channel { - name - description - } - ... on Narrative { - name - description - } - ... on Language { - name - } - ... on DataComponent { - name - description - } - ... on DataSource { - name - description - } - ... on Case { - name - description - } - ... on StixCyberObservable { - observable_value - } - ... on MarkingDefinition { - definition_type - definition + ... on StixObject { + representative { + main + } } - ... on KillChainPhase { - kill_chain_name - phase_name + ... on StixRelationship { + representative { + main + } } + # internal objects ... on Creator { name } - ... on Report { + ... on Group { name } - ... on Grouping { - name + # need colors when available + ... on Label { + color } - ... on Note { - attribute_abstract - content + ... on MarkingDefinition { + x_opencti_color } - ... on Opinion { - opinion + ... on Status { + template { + name + color + } } } } @@ -188,6 +90,7 @@ const PublicStixRelationshipsPolarAreaComponent = ({ ) { const attributeField = dataSelection[0].attribute || 'entity_type'; + // TODO: take into account the entity color to send it to the widget (that shall handle it) return ( { @@ -195,7 +98,9 @@ const PublicStixRelationshipsPolarAreaComponent = ({ return []; } return { - label: attributeField.endsWith('_id') ? defaultValue(item.entity) : item.label, + label: isFieldForIdentifier(attributeField) + ? getMainRepresentative(item.entity) + : item.label, value: item.value ?? 0, }; })} diff --git a/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsRadar.tsx b/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsRadar.tsx index 02fc0c3b879f..eebe0cb310a9 100644 --- a/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsRadar.tsx +++ b/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsRadar.tsx @@ -27,142 +27,45 @@ const publicStixRelationshipsRadarsQuery = graphql` value entity { ... on BasicObject { + id entity_type } ... on BasicRelationship { + id entity_type } - ... on AttackPattern { - name - description - x_mitre_id - } - ... on Campaign { - name - description - } - ... on CourseOfAction { - name - description - } - ... on Individual { - name - description - } - ... on Organization { - name - description - } - ... on Sector { - name - description - } - ... on System { - name - description - } - ... on Indicator { - name - description - } - ... on Infrastructure { - name - description - } - ... on IntrusionSet { - name - description - } - ... on Position { - name - description - } - ... on City { - name - description - } - ... on AdministrativeArea { - name - description - } - ... on Country { - name - description - } - ... on Region { - name - description + ... on StixObject { + representative { + main + } } - ... on Malware { - name - description - } - ... on ThreatActor { - name - description - } - ... on Tool { - name - description - } - ... on Vulnerability { - name - description - } - ... on Incident { - name - description - } - ... on Event { - name - description - } - ... on Channel { - name - description - } - ... on Narrative { - name - description - } - ... on Language { - name - } - ... on DataComponent { - name - } - ... on DataSource { - name - } - ... on Case { - name - } - ... on StixCyberObservable { - observable_value - } - ... on MarkingDefinition { - definition_type - definition - } - ... on KillChainPhase { - kill_chain_name - phase_name + ... on StixRelationship { + representative { + main + } } + # internal objects ... on Creator { + id name } - ... on Report { + ... on Group { + id name } - ... on Grouping { - name + # need colors when available + ... on Label { + value + color } - ... on Note { - attribute_abstract - content + ... on MarkingDefinition { + x_opencti_color } - ... on Opinion { - opinion + ... on Status { + template { + name + color + } } } } diff --git a/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsTimeline.tsx b/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsTimeline.tsx index effb416aaa52..9250ce32ded6 100644 --- a/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsTimeline.tsx +++ b/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsTimeline.tsx @@ -54,6 +54,16 @@ const publicStixRelationshipsTimelineQuery = graphql` last_seen } from { + ... on BasicObject { + id + entity_type + } + ... on StixObject { + representative { + main + secondary + } + } ... on StixDomainObject { id entity_type @@ -66,10 +76,13 @@ const publicStixRelationshipsTimelineQuery = graphql` color } } + # additional info used by the timeline display + ... on Report { + description + published + } ... on AttackPattern { - name description - x_mitre_id killChainPhases { id phase_name @@ -88,112 +101,71 @@ const publicStixRelationshipsTimelineQuery = graphql` } } ... on Campaign { - name description } ... on CourseOfAction { - name description } ... on Individual { - name description } ... on Organization { - name description } ... on Sector { - name description } ... on System { - name description } ... on Indicator { - name description } ... on Infrastructure { - name description } ... on IntrusionSet { - name description } ... on Position { - name description } ... on City { - name description } ... on AdministrativeArea { - name description } ... on Country { - name description } ... on Region { - name description } ... on Malware { - name description } ... on ThreatActor { - name description } ... on Tool { - name description } ... on Vulnerability { - name description } ... on Incident { - name description } ... on Event { - name description } ... on Channel { - name description } ... on Narrative { - name description } - ... on Language { - name - } - ... on DataComponent { - name - } - ... on DataSource { - name - } - ... on Case { - name - } - ... on Note { - attribute_abstract - content - } - ... on Opinion { - opinion - } ... on StixCyberObservable { id entity_type @@ -213,7 +185,6 @@ const publicStixRelationshipsTimelineQuery = graphql` } ... on Indicator { id - name pattern_type pattern_version description @@ -241,6 +212,18 @@ const publicStixRelationshipsTimelineQuery = graphql` created created_at from { + ... on StixObject { + representative { + main + secondary + } + } + ... on StixRelationship { + representative { + main + secondary + } + } ... on StixDomainObject { id entity_type @@ -254,7 +237,6 @@ const publicStixRelationshipsTimelineQuery = graphql` } } ... on AttackPattern { - name description x_mitre_id killChainPhases { @@ -275,75 +257,57 @@ const publicStixRelationshipsTimelineQuery = graphql` } } ... on Campaign { - name description } ... on CourseOfAction { - name description } ... on Individual { - name description } ... on Organization { - name description } ... on Sector { - name description } ... on System { - name description } ... on Indicator { - name description } ... on Infrastructure { - name description } ... on IntrusionSet { - name description } ... on Position { - name description } ... on City { - name description } ... on Country { - name description } ... on Region { - name description } ... on Malware { - name description } ... on ThreatActor { - name description } ... on Tool { - name description } ... on Vulnerability { - name description } ... on Incident { - name description } ... on StixCyberObservable { @@ -365,7 +329,6 @@ const publicStixRelationshipsTimelineQuery = graphql` } ... on Indicator { id - name pattern_type pattern_version description @@ -395,6 +358,18 @@ const publicStixRelationshipsTimelineQuery = graphql` } } to { + ... on StixObject { + representative { + main + secondary + } + } + ... on StixRelationship { + representative { + main + secondary + } + } ... on StixDomainObject { id entity_type @@ -429,75 +404,57 @@ const publicStixRelationshipsTimelineQuery = graphql` } } ... on Campaign { - name description } ... on CourseOfAction { - name description } ... on Individual { - name description } ... on Organization { - name description } ... on Sector { - name description } ... on System { - name description } ... on Indicator { - name description } ... on Infrastructure { - name description } ... on IntrusionSet { - name description } ... on Position { - name description } ... on City { - name description } ... on Country { - name description } ... on Region { - name description } ... on Malware { - name description } ... on ThreatActor { - name description } ... on Tool { - name description } ... on Vulnerability { - name description } ... on Incident { - name description } ... on StixCyberObservable { @@ -519,7 +476,6 @@ const publicStixRelationshipsTimelineQuery = graphql` } ... on Indicator { id - name pattern_type pattern_version description @@ -551,6 +507,18 @@ const publicStixRelationshipsTimelineQuery = graphql` } } to { + ... on StixObject { + representative { + main + secondary + } + } + ... on StixRelationship { + representative { + main + secondary + } + } ... on StixDomainObject { id entity_type @@ -564,7 +532,6 @@ const publicStixRelationshipsTimelineQuery = graphql` } } ... on AttackPattern { - name description x_mitre_id killChainPhases { @@ -585,75 +552,57 @@ const publicStixRelationshipsTimelineQuery = graphql` } } ... on Campaign { - name description } ... on CourseOfAction { - name description } ... on Individual { - name description } ... on Organization { - name description } ... on Sector { - name description } ... on System { - name description } ... on Indicator { - name description } ... on Infrastructure { - name description } ... on IntrusionSet { - name description } ... on Position { - name description } ... on City { - name description } ... on Country { - name description } ... on Region { - name description } ... on Malware { - name description } ... on ThreatActor { - name description } ... on Tool { - name description } ... on Vulnerability { - name description } ... on Incident { - name description } ... on StixCyberObservable { @@ -675,7 +624,6 @@ const publicStixRelationshipsTimelineQuery = graphql` } ... on Indicator { id - name pattern_type pattern_version description @@ -703,6 +651,18 @@ const publicStixRelationshipsTimelineQuery = graphql` created_at parent_types from { + ... on StixObject { + representative { + main + secondary + } + } + ... on StixRelationship { + representative { + main + secondary + } + } ... on StixDomainObject { id entity_type @@ -716,7 +676,6 @@ const publicStixRelationshipsTimelineQuery = graphql` } } ... on AttackPattern { - name description x_mitre_id killChainPhases { @@ -737,75 +696,57 @@ const publicStixRelationshipsTimelineQuery = graphql` } } ... on Campaign { - name description } ... on CourseOfAction { - name description } ... on Individual { - name description } ... on Organization { - name description } ... on Sector { - name description } ... on System { - name description } ... on Indicator { - name description } ... on Infrastructure { - name description } ... on IntrusionSet { - name description } ... on Position { - name description } ... on City { - name description } ... on Country { - name description } ... on Region { - name description } ... on Malware { - name description } ... on ThreatActor { - name description } ... on Tool { - name description } ... on Vulnerability { - name description } ... on Incident { - name description } ... on StixCyberObservable { @@ -827,7 +768,6 @@ const publicStixRelationshipsTimelineQuery = graphql` } ... on Indicator { id - name pattern_type pattern_version description @@ -857,6 +797,18 @@ const publicStixRelationshipsTimelineQuery = graphql` } } to { + ... on StixObject { + representative { + main + secondary + } + } + ... on StixRelationship { + representative { + main + secondary + } + } ... on StixDomainObject { id entity_type @@ -870,7 +822,6 @@ const publicStixRelationshipsTimelineQuery = graphql` } } ... on AttackPattern { - name description x_mitre_id killChainPhases { @@ -891,75 +842,57 @@ const publicStixRelationshipsTimelineQuery = graphql` } } ... on Campaign { - name description } ... on CourseOfAction { - name description } ... on Individual { - name description } ... on Organization { - name description } ... on Sector { - name description } ... on System { - name description } ... on Indicator { - name description } ... on Infrastructure { - name description } ... on IntrusionSet { - name description } ... on Position { - name description } ... on City { - name description } ... on Country { - name description } ... on Region { - name description } ... on Malware { - name description } ... on ThreatActor { - name description } ... on Tool { - name description } ... on Vulnerability { - name description } ... on Incident { - name description } ... on StixCyberObservable { @@ -981,7 +914,6 @@ const publicStixRelationshipsTimelineQuery = graphql` } ... on Indicator { id - name pattern_type pattern_version description diff --git a/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsTreeMap.tsx b/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsTreeMap.tsx index 95e653607e11..b9fbcee05c49 100644 --- a/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsTreeMap.tsx +++ b/opencti-platform/opencti-front/src/public/components/dashboard/stix_relationships/PublicStixRelationshipsTreeMap.tsx @@ -27,141 +27,26 @@ const publicStixRelationshipsTreeMapsQuery = graphql` value entity { ... on BasicObject { + id entity_type } ... on BasicRelationship { + id entity_type } - ... on AttackPattern { - name - description - } - ... on Campaign { - name - description - } - ... on CourseOfAction { - name - description - } - ... on Individual { - name - description - } - ... on Organization { - name - description - } - ... on Sector { - name - description - } - ... on System { - name - description - } - ... on Indicator { - name - description - } - ... on Infrastructure { - name - description - } - ... on IntrusionSet { - name - description - } - ... on Position { - name - description - } - ... on City { - name - description - } - ... on AdministrativeArea { - name - description - } - ... on Country { - name - description - } - ... on Region { - name - description - } - ... on Malware { - name - description - } - ... on ThreatActor { - name - description - } - ... on Tool { - name - description - } - ... on Vulnerability { - name - description - } - ... on Incident { - name - description - } - ... on Event { - name - description - } - ... on Channel { - name - description - } - ... on Narrative { - name - description - } - ... on Language { - name - } - ... on DataComponent { - name - } - ... on DataSource { - name - } - ... on Case { - name - } - ... on StixCyberObservable { - observable_value - } - ... on MarkingDefinition { - definition_type - definition - } - ... on KillChainPhase { - kill_chain_name - phase_name + ... on StixObject { + representative { + main + } } + # objects without representative ... on Creator { name } - ... on Report { - name - } - ... on Grouping { - name - } - ... on Note { - attribute_abstract - content - } - ... on Opinion { - opinion + ... on Status { + template { + name + } } } } diff --git a/opencti-platform/opencti-front/src/utils/Graph.js b/opencti-platform/opencti-front/src/utils/Graph.js index 125f5a8a6f2f..9a934586a239 100644 --- a/opencti-platform/opencti-front/src/utils/Graph.js +++ b/opencti-platform/opencti-front/src/utils/Graph.js @@ -51,6 +51,7 @@ import { dateFormat, dayEndDate, daysAfter, daysAgo, jsDate, minutesBefore, minu import { isDateStringNone, isNone } from '../components/i18n'; import { fileUri } from '../relay/environment'; import { isNotEmptyField } from './utils'; +import { defaultDate, getMainRepresentative } from './defaultRepresentatives'; const genImage = (src) => { const img = new Image(); @@ -306,135 +307,6 @@ export const decodeMappingData = (encodedMappingData) => { return {}; }; -export const defaultDate = (n) => { - if (!n) return ''; - if (!isDateStringNone(n.start_time)) { - return n.start_time; - } - if (!isDateStringNone(n.first_seen)) { - return n.first_seen; - } - if (!isDateStringNone(n.first_observed)) { - return n.first_observed; - } - if (!isDateStringNone(n.valid_from)) { - return n.valid_from; - } - if (!isDateStringNone(n.published)) { - return n.published; - } - if (!isDateStringNone(n.created)) { - return n.created; - } - if (!isDateStringNone(n.created_at)) { - return n.created_at; - } - return null; -}; - -export const defaultType = (n, t) => { - if (n.parent_types.includes('basic-relationship')) { - return t(`relationship_${n.entity_type}`); - } - return t(`entity_${n.entity_type}`); -}; - -export const defaultValueMarking = (n) => { - let def = 'Unknown'; - if (n.definition) { - const definition = R.toPairs(n.definition); - if (definition[0]) { - if (definition[0][1].includes(':')) { - // eslint-disable-next-line prefer-destructuring - def = definition[0][1]; - } else { - def = `${definition[0][0]}:${definition[0][1]}`; - } - } - } - return def; -}; - -export const defaultKey = (n) => { - if (!n) return null; - if (n.hashes) { - return 'hashes'; - } - if (n.name) { - return 'name'; - } - if (n.value) { - return 'value'; - } - if (n.observable_value) { - return 'observable_value'; - } - if (n.attribute_abstract) { - return 'attribute_abstract'; - } - if (n.opinion) { - return null; - } - if (n.abstract) { - return 'abstract'; - } - return null; -}; - -export const defaultValue = (n, fallback = 'Unknown') => { - if (!n) return ''; - if (typeof n.definition === 'object') { - return defaultValueMarking(n); - } - const mainValue = n.name - || n.label - || n.observableName - || n.observable_value - || n.pattern - || n.attribute_abstract - || n.opinion - || n.value - || n.definition - || n.source_name - || n.phase_name - || n.result_name - || n.country - || n.key - || (n.template && n.template.name) - || (n.content && truncate(n.content, 30)) - || (n.hashes - && (n.hashes.MD5 - || n.hashes['SHA-1'] - || n.hashes['SHA-256'] - || n.hashes['SHA-512'])) - || (n.source_ref_name - && n.target_ref_name - && `${truncate(n.source_ref_name, 20)} ➡️ ${truncate( - n.target_ref_name, - 20, - )}`) - || defaultValue(R.head(R.pathOr([], ['objects', 'edges'], n))?.node) - || (n.from - && n.to - && `${truncate(defaultValue(n.from), 20)} ➡️ ${truncate( - defaultValue(n.to), - 20, - )}`) - || fallback; - return n.x_mitre_id ? `[${n.x_mitre_id}] ${mainValue}` : mainValue; -}; - -export const defaultSecondaryValue = (n) => { - if (!n) return ''; - return ( - n.description - || n.x_opencti_description - || n.content - || n.entity_type - || dateFormat(n.created_at) - ); -}; - export const computeTimeRangeInterval = (objects) => { const filteredDates = objects .filter( @@ -676,10 +548,10 @@ export const buildCorrelationData = ( id: n.id, disabled: n.disabled, val: graphLevel[n.entity_type] || graphLevel.Unknown, - name: defaultValue(n), + name: getMainRepresentative(n), defaultDate: jsDate(defaultDate(n)), label: truncate( - defaultValue(n), + getMainRepresentative(n), n.entity_type === 'Attack-Pattern' ? 30 : 20, ), img: graphImages[n.entity_type] || graphImages.Unknown, @@ -903,13 +775,13 @@ export const buildGraphData = (objects, graphData, t) => { ? '-' : dateFormat(n.stop_time || n.last_seen) }` - : defaultValue(n) + : getMainRepresentative(n) }\n${dateFormat(defaultDate(n))}`, defaultDate: jsDate(defaultDate(n)), label: n.parent_types.includes('basic-relationship') ? t(`relationship_${n.relationship_type}`) : truncate( - defaultValue(n), + getMainRepresentative(n), n.entity_type === 'Attack-Pattern' ? 30 : 20, ), img: diff --git a/opencti-platform/opencti-front/src/utils/defaultRepresentatives.ts b/opencti-platform/opencti-front/src/utils/defaultRepresentatives.ts new file mode 100644 index 000000000000..7a27d0e34a7f --- /dev/null +++ b/opencti-platform/opencti-front/src/utils/defaultRepresentatives.ts @@ -0,0 +1,148 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import * as R from 'ramda'; +import { isDateStringNone } from '../components/i18n'; +import { truncate } from './String'; +import { dateFormat } from './Time'; + +export const isFieldForIdentifier = (fieldName?: string) => { + if (!fieldName) { + return false; + } + return fieldName === 'id' + || fieldName.endsWith('.id') + || fieldName.endsWith('_id') + || fieldName.endsWith('_ids'); +}; + +export const defaultDate = (n: any) => { + if (!n) return ''; + if (!isDateStringNone(n.start_time)) { + return n.start_time; + } + if (!isDateStringNone(n.first_seen)) { + return n.first_seen; + } + if (!isDateStringNone(n.first_observed)) { + return n.first_observed; + } + if (!isDateStringNone(n.valid_from)) { + return n.valid_from; + } + if (!isDateStringNone(n.published)) { + return n.published; + } + if (!isDateStringNone(n.created)) { + return n.created; + } + if (!isDateStringNone(n.created_at)) { + return n.created_at; + } + return null; +}; + +export const defaultType = (n: any, t: (key: string) => string) => { + if (n.parent_types.includes('basic-relationship')) { + return t(`relationship_${n.entity_type}`); + } + return t(`entity_${n.entity_type}`); +}; + +export const defaultValueMarking = (n: any) => { + let def = 'Unknown'; + if (n.definition) { + const definition = R.toPairs(n.definition); + if (definition[0]) { + if (definition[0][1].includes(':')) { + // eslint-disable-next-line prefer-destructuring + def = definition[0][1]; + } else { + def = `${definition[0][0]}:${definition[0][1]}`; + } + } + } + return def; +}; + +export const defaultKey = (n: any) => { + if (!n) return null; + if (n.hashes) { + return 'hashes'; + } + if (n.name) { + return 'name'; + } + if (n.value) { + return 'value'; + } + if (n.observable_value) { + return 'observable_value'; + } + if (n.attribute_abstract) { + return 'attribute_abstract'; + } + if (n.opinion) { + return null; + } + if (n.abstract) { + return 'abstract'; + } + return null; +}; + +// equivalent to querying representative.main +export const getMainRepresentative = (n: any, fallback = 'Unknown') => { + if (!n) return ''; + if (typeof n.definition === 'object') { + return defaultValueMarking(n); + } + const mainValue: string = n.representative?.main + || n.name + || n.label + || n.observableName + || n.observable_value + || n.pattern + || n.attribute_abstract + || n.opinion + || n.value + || n.definition + || n.source_name + || n.phase_name + || n.result_name + || n.country + || n.key + || (n.template && n.template.name) + || (n.content && truncate(n.content, 30)) + || (n.hashes + && (n.hashes.MD5 + || n.hashes['SHA-1'] + || n.hashes['SHA-256'] + || n.hashes['SHA-512'])) + || (n.source_ref_name + && n.target_ref_name + && `${truncate(n.source_ref_name, 20)} ➡️ ${truncate( + n.target_ref_name, + 20, + )}`) + || getMainRepresentative((R.head(R.pathOr([], ['objects', 'edges'], n)) as any)?.node) + || (n.from + && n.to + && `${truncate(getMainRepresentative(n.from), 20)} ➡️ ${truncate( + getMainRepresentative(n.to), + 20, + )}`) + || fallback; + return n.x_mitre_id ? `[${n.x_mitre_id}] ${mainValue}` : mainValue; +}; + +// equivalent to querying representative.secondary +export const getSecondaryRepresentative = (n: any) => { + if (!n) return ''; + return ( + n.representative?.secondary + || n.description + || n.x_opencti_description + || n.content + || n.entity_type + || dateFormat(n.created_at) + ); +}; diff --git a/opencti-platform/opencti-front/src/utils/filters/useSearchEntities.tsx b/opencti-platform/opencti-front/src/utils/filters/useSearchEntities.tsx index aa037089ebd2..e3d28e912474 100644 --- a/opencti-platform/opencti-front/src/utils/filters/useSearchEntities.tsx +++ b/opencti-platform/opencti-front/src/utils/filters/useSearchEntities.tsx @@ -30,7 +30,7 @@ import { NotifierFieldSearchQuery$data } from '@components/common/form/__generat import useAuth, { FilterDefinition } from '../hooks/useAuth'; import { useSearchEntitiesStixCoreObjectsSearchQuery$data } from './__generated__/useSearchEntitiesStixCoreObjectsSearchQuery.graphql'; import { useFormatter } from '../../components/i18n'; -import { defaultValue } from '../Graph'; +import { getMainRepresentative } from '../defaultRepresentatives'; import { fetchQuery } from '../../relay/environment'; import { useSearchEntitiesSchemaSCOSearchQuery$data } from './__generated__/useSearchEntitiesSchemaSCOSearchQuery.graphql'; import type { Theme } from '../../components/Theme'; @@ -438,7 +438,7 @@ const useSearchEntities = ({ const elementIdEntities = ( (data as useSearchEntitiesStixCoreObjectsSearchQuery$data)?.stixCoreObjects?.edges ?? [] ).map((n) => ({ - label: defaultValue(n?.node), + label: getMainRepresentative(n?.node), value: n?.node.id, type: n?.node.entity_type, parentTypes: n?.node.parent_types, diff --git a/opencti-platform/opencti-front/src/utils/graph/EntityDetails.tsx b/opencti-platform/opencti-front/src/utils/graph/EntityDetails.tsx index 4d3a7239dffb..7e5084c0b709 100644 --- a/opencti-platform/opencti-front/src/utils/graph/EntityDetails.tsx +++ b/opencti-platform/opencti-front/src/utils/graph/EntityDetails.tsx @@ -21,7 +21,7 @@ import type { SelectedEntity } from './EntitiesDetailsRightBar'; import ErrorNotFound from '../../components/ErrorNotFound'; import ItemIcon from '../../components/ItemIcon'; import type { Theme } from '../../components/Theme'; -import { defaultValue } from '../Graph'; +import { getMainRepresentative } from '../defaultRepresentatives'; import { hexToRGB, itemColor } from '../Colors'; import { truncate } from '../String'; import ItemCreators from '../../components/ItemCreators'; @@ -322,8 +322,8 @@ EntityDetailsComponentProps {t_i18n('Value')} - - {truncate(defaultValue(stixCoreObject), 40)} + + {truncate(getMainRepresentative(stixCoreObject), 40)} {t_i18n('Type')} diff --git a/opencti-platform/opencti-front/src/utils/graph/RelationShipFromAndTo.tsx b/opencti-platform/opencti-front/src/utils/graph/RelationShipFromAndTo.tsx index 43cbda258827..2e71eebe0a21 100644 --- a/opencti-platform/opencti-front/src/utils/graph/RelationShipFromAndTo.tsx +++ b/opencti-platform/opencti-front/src/utils/graph/RelationShipFromAndTo.tsx @@ -7,7 +7,7 @@ import { useFormatter } from '../../components/i18n'; import useQueryLoading from '../hooks/useQueryLoading'; import { RelationShipFromAndToQuery } from './__generated__/RelationShipFromAndToQuery.graphql'; import { truncate } from '../String'; -import { defaultValue } from '../Graph'; +import { getMainRepresentative } from '../defaultRepresentatives'; const useStyles = makeStyles(() => ({ label: { @@ -20,6 +20,11 @@ const relationShipFromAndToQuery = graphql` stixCoreObject(id: $id) { id entity_type + ... on StixObject { + representative { + main + } + } ... on StixDomainObject { created } @@ -152,8 +157,8 @@ RelationShipFromAndToComponentProps {t_i18n(direction === 'From' ? 'Source' : 'Target')} - - {truncate(defaultValue(stixCoreObject), 40)} + + {truncate(getMainRepresentative(stixCoreObject), 40)} ); diff --git a/opencti-platform/opencti-front/src/utils/graph/StixMetaObjectDetails.tsx b/opencti-platform/opencti-front/src/utils/graph/StixMetaObjectDetails.tsx index ea2c22396fd9..2de36eeee6a0 100644 --- a/opencti-platform/opencti-front/src/utils/graph/StixMetaObjectDetails.tsx +++ b/opencti-platform/opencti-front/src/utils/graph/StixMetaObjectDetails.tsx @@ -9,7 +9,7 @@ import useQueryLoading from '../hooks/useQueryLoading'; import Loader, { LoaderVariant } from '../../components/Loader'; import type { SelectedEntity } from './EntitiesDetailsRightBar'; import ErrorNotFound from '../../components/ErrorNotFound'; -import { defaultValue } from '../Graph'; +import { getMainRepresentative } from '../defaultRepresentatives'; import { hexToRGB, itemColor } from '../Colors'; import { truncate } from '../String'; import ItemCreators from '../../components/ItemCreators'; @@ -97,15 +97,15 @@ StixMetaObjectDetailsComponentProps {t_i18n('Value')} {stixMetaObject.entity_type === 'Marking-Definition' ? ( - + ) : ( - - {truncate(defaultValue(stixMetaObject), 40)} + + {truncate(getMainRepresentative(stixMetaObject), 40)} )} diff --git a/opencti-platform/opencti-front/src/utils/hooks/useDistributionGraphData.ts b/opencti-platform/opencti-front/src/utils/hooks/useDistributionGraphData.ts new file mode 100644 index 000000000000..7b3033952fbd --- /dev/null +++ b/opencti-platform/opencti-front/src/utils/hooks/useDistributionGraphData.ts @@ -0,0 +1,133 @@ +import { useTheme } from '@mui/material/styles'; +import { useFormatter } from '../../components/i18n'; +import { getMainRepresentative, isFieldForIdentifier } from '../defaultRepresentatives'; +import { itemColor } from '../Colors'; + +// common type compatible with all distribution queries +type DistributionNode = { + readonly label: string, + readonly value?: number | null, + + readonly entity?: { + readonly entity_type?: string, + readonly id?: string, + // when colors are requested from Labels, Markings or Status for instance + readonly color?: string | null, + readonly x_opencti_color?: string | null, + readonly template?: { + readonly color?: string | null + } | null + // workspaces + readonly type?: string, + } | null, +}; + +type DistributionQueryData = ReadonlyArray; + +type Selection = { + attribute?: string, + label?: string, +}; + +const useDistributionGraphData = () => { + const { t_i18n } = useFormatter(); + const theme = useTheme(); + + const getColorFromDistributionNode = (n: DistributionNode, selection: Selection) => { + let color = isFieldForIdentifier(selection.attribute) + ? itemColor(n.entity?.entity_type) + : itemColor(n.label); + if (n.entity?.color) { + color = theme.palette.mode === 'light' && n.entity.color === '#ffffff' + ? '#000000' + : n.entity.color; + } + if (n.entity?.x_opencti_color) { + color = theme.palette.mode === 'light' + && n.entity.x_opencti_color === '#ffffff' + ? '#000000' + : n.entity.x_opencti_color; + } + if (n.entity?.template?.color) { + color = theme.palette.mode === 'light' + && n.entity.template.color === '#ffffff' + ? '#000000' + : n.entity.template.color; + } + + return color; + }; + + const buildDistributionGraphData = (distributionData: DistributionQueryData, selection: Selection) => { + return distributionData.map((n) => { + if (!n) return { x: 'Unknown', y: 'Unknown' }; + let { label } = n; + if (isFieldForIdentifier(selection.attribute)) { + label = getMainRepresentative(n.entity) || n.label; + } else if (selection.attribute === 'entity_type' && t_i18n(`entity_${n.label}`) !== `entity_${n.label}`) { + label = t_i18n(`entity_${n.label}`); + } + return { + x: label, + y: n.value, + fillColor: getColorFromDistributionNode(n, selection), + }; + }); + }; + + const buildDistributionRedirectionUtils = (distributionData: DistributionQueryData, selection: Selection) => { + // only build redirections on names distribution + if (selection.attribute === 'name') { + return distributionData.flatMap((n) => { + if (!n || !n.entity) return []; + return { + id: n.entity.id, + entity_type: n.entity?.entity_type === 'Workspace' ? n.entity.type : n.entity.entity_type, + }; + }); + } + return undefined; + }; + + /** + * Conveniently build the series (chart data) and redirectionUtils props for a Widget + * from the distribution query results and the selection config. + * @param distributionData + * @param selection + * @param defaultGraphLabel + */ + const buildWidgetProps = (distributionData: DistributionQueryData, selection: Selection, defaultGraphLabel: string) => { + return { + series: [{ + name: selection.label || t_i18n(defaultGraphLabel), + data: buildDistributionGraphData(distributionData, selection), + }], + redirectionUtils: buildDistributionRedirectionUtils(distributionData, selection), + }; + }; + + /** + * Build from query data the labels to use in the graph. + * @param distributionData + * @param groupBy + */ + const buildWidgetLabelsOption = (distributionData: DistributionQueryData, groupBy: string) => { + return distributionData.map((n) => { + if (!n) return 'Unknown'; + if (isFieldForIdentifier(groupBy)) { + return getMainRepresentative(n.entity); + } + if (groupBy === 'entity_type' && t_i18n(`entity_${n.label}`) !== `entity_${n.label}`) { + return t_i18n(`entity_${n.label}`); + } + return n.label; + }); + }; + + return { + buildWidgetProps, + buildWidgetLabelsOption, + }; +}; + +export default useDistributionGraphData; diff --git a/opencti-platform/opencti-graphql/src/database/engine.js b/opencti-platform/opencti-graphql/src/database/engine.js index 6c4f6e71f2dd..3c2696a9b8b3 100644 --- a/opencti-platform/opencti-graphql/src/database/engine.js +++ b/opencti-platform/opencti-graphql/src/database/engine.js @@ -2698,7 +2698,7 @@ const buildAggregationRelationFilters = async (context, user, aggregationFilters export const elAggregationRelationsCount = async (context, user, indexName, options = {}) => { const { types = [], field = null, searchOptions, aggregationOptions, aggregateOnConnections = true } = options; if (!R.includes(field, ['entity_type', 'internal_id', 'rel_object-marking.internal_id', 'rel_kill-chain-phase.internal_id', 'creator_id', 'rel_created-by.internal_id', null])) { - throw FunctionalError('Aggregation computing use and unsupported field', { field }); + throw FunctionalError('Aggregation computing use an unsupported field', { field }); } const body = await elQueryBodyBuilder(context, user, { ...searchOptions, noSize: true, noSort: true }); const aggregationFilters = await buildAggregationRelationFilters(context, user, aggregationOptions); diff --git a/opencti-platform/opencti-graphql/src/database/entity-representative.js b/opencti-platform/opencti-graphql/src/database/entity-representative.js index 05ef9ed62b62..5fd77a46e88d 100644 --- a/opencti-platform/opencti-graphql/src/database/entity-representative.js +++ b/opencti-platform/opencti-graphql/src/database/entity-representative.js @@ -100,6 +100,11 @@ const extractEntityRepresentative = (entityData) => { // -- ENTITY | RELATIONSHIP export const extractRepresentative = (entityData) => { + // the representative can already be given (happens when the internals set it to "Restricted") + if (entityData.representative) { + return entityData.representative; + } + // otherwise we find extract it depending on the entity type if (isStixRelationship(entityData.entity_type)) { return extractRelationshipRepresentative(entityData); } diff --git a/opencti-platform/opencti-graphql/src/database/middleware.js b/opencti-platform/opencti-graphql/src/database/middleware.js index 9abfa56f0eb1..e36b6fc98c80 100644 --- a/opencti-platform/opencti-graphql/src/database/middleware.js +++ b/opencti-platform/opencti-graphql/src/database/middleware.js @@ -450,10 +450,38 @@ export const stixLoadByFilters = async (context, user, types, args) => { // region Graphics const convertAggregateDistributions = async (context, user, limit, orderingFunction, distribution) => { const data = R.take(limit, R.sortWith([orderingFunction(R.prop('value'))])(distribution)); - const resolveLabels = await elFindByIds(context, user, data.map((d) => d.label), { toMap: true }); - return data // Depending of user access, info can be empty, must be filtered - .filter((n) => isNotEmptyField(resolveLabels[n.label.toLowerCase()])) - .map((n) => R.assoc('entity', resolveLabels[n.label.toLowerCase()], n)); + // resolve all of them with system user + const allResolveLabels = await elFindByIds(context, SYSTEM_USER, data.map((d) => d.label), { toMap: true }); + // entities not granted shall be sent as "restricted" with limited information + const grantedIds = []; + for (let i = 0; i < data.length; i += 1) { + const resolved = allResolveLabels[data[i].label.toLowerCase()]; + const canAccess = await isUserCanAccessStoreElement(context, user, resolved); + if (canAccess) { + grantedIds.push(data[i].label.toLowerCase()); + } + } + return data + // filter out unresolved data (like the SYSTEM user for instance) + .filter((n) => isNotEmptyField(allResolveLabels[n.label.toLowerCase()])) + .map((n) => { + const element = allResolveLabels[n.label.toLowerCase()]; + if (grantedIds.includes(n.label.toLowerCase())) { + return { + ...n, + entity: element + }; + } + return { + ...n, + entity: { + id: element.id, + entity_type: element.entity_type, + parent_types: element.parent_types, + representative: { main: 'Restricted', secondary: 'Restricted' } + } + }; + }); }; export const timeSeriesHistory = async (context, user, types, args) => { const { startDate, endDate, interval } = args; diff --git a/opencti-platform/opencti-graphql/tests/02-integration/01-database/middleware-test.js b/opencti-platform/opencti-graphql/tests/02-integration/01-database/middleware-test.js index 54923915f7ea..742fc8026723 100644 --- a/opencti-platform/opencti-graphql/tests/02-integration/01-database/middleware-test.js +++ b/opencti-platform/opencti-graphql/tests/02-integration/01-database/middleware-test.js @@ -15,7 +15,7 @@ import { updateAttribute, } from '../../../src/database/middleware'; import { elFindByIds, elLoadById, elRawSearch } from '../../../src/database/engine'; -import { ADMIN_USER, testContext } from '../../utils/testQuery'; +import { ADMIN_USER, buildStandardUser, testContext } from '../../utils/testQuery'; import { ENTITY_TYPE_CAMPAIGN, ENTITY_TYPE_CONTAINER_OBSERVED_DATA, @@ -711,6 +711,47 @@ describe('Relations distribution', () => { const aggregationMap = new Map(distribution.map((i) => [i.label, i.value])); expect(aggregationMap.get('Attack-Pattern')).toEqual(2); }); + it('should relation distribution give entity details', async () => { + // const { limit = 50, order, inferred = false } = options; + // const { startDate, endDate, relationship_type, toTypes, fromId, field, operation } = options; + const malware = await elLoadById(testContext, ADMIN_USER, 'malware--faa5b705-cf44-4e50-8472-29e5fec43c3c'); + const options = { + fromOrToId: [malware.internal_id], + relationship_type: ['uses'], + field: 'internal_id', + operation: 'count', + }; + const distribution = await distributionRelations(testContext, ADMIN_USER, options); + expect(distribution.length).toEqual(3); + expect(distribution[0].entity.representative).toBeUndefined(); + expect(distribution[1].entity.representative).toBeUndefined(); + expect(distribution[2].entity.representative).toBeUndefined(); + expect(distribution[0].entity.name).toBeDefined(); + expect(distribution[1].entity.name).toBeDefined(); + expect(distribution[2].entity.name).toBeDefined(); + }); + it('should relation distribution give restricted entity data', async () => { + // const { limit = 50, order, inferred = false } = options; + // const { startDate, endDate, relationship_type, toTypes, fromId, field, operation } = options; + const malware = await elLoadById(testContext, ADMIN_USER, 'malware--faa5b705-cf44-4e50-8472-29e5fec43c3c'); + const options = { + fromOrToId: [malware.internal_id], + relationship_type: ['uses'], + field: 'internal_id', + operation: 'count', + }; + const WHITE_TLP = { standard_id: 'marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9', internal_id: null }; + const WHITE_USER = buildStandardUser([WHITE_TLP]); + const distribution = await distributionRelations(testContext, WHITE_USER, options); + expect(distribution.length).toEqual(3); + + expect(distribution[0].entity.representative).toEqual({ main: 'Restricted', secondary: 'Restricted' }); + expect(distribution[1].entity.representative).toEqual({ main: 'Restricted', secondary: 'Restricted' }); + expect(distribution[2].entity.representative).toEqual({ main: 'Restricted', secondary: 'Restricted' }); + expect(distribution[0].entity.name).toBeUndefined(); + expect(distribution[1].entity.name).toBeUndefined(); + expect(distribution[2].entity.name).toBeUndefined(); + }); }); // Some utils