Projects STRLCPY opencti Commits cb82f7dd
🤬
  • ■ ■ ■ ■ ■ ■
    opencti-platform/opencti-front/src/components/Transition.js
    1  -import React from 'react';
    2  -import Slide from '@mui/material/Slide';
    3  - 
    4  -const Transition = React.forwardRef((props, ref) => (
    5  - <Slide direction="up" ref={ref} {...props} />
    6  -));
    7  -Transition.displayName = 'TransitionSlide';
    8  - 
    9  -export default Transition;
    10  - 
  • ■ ■ ■ ■ ■ ■
    opencti-platform/opencti-front/src/components/Transition.tsx
     1 +import Slide from '@mui/material/Slide';
     2 +import { TransitionProps } from '@mui/material/transitions/transition';
     3 +import React from 'react';
     4 + 
     5 +const Transition = React.forwardRef(function Transition(
     6 + props: TransitionProps & {
     7 + children: React.ReactElement<any, any>;
     8 + },
     9 + ref: React.Ref<unknown>,
     10 +) {
     11 + return <Slide direction="up" ref={ref} {...props} />;
     12 +});
     13 + 
     14 +export default Transition;
     15 + 
  • ■ ■ ■ ■ ■ ■
    opencti-platform/opencti-front/src/private/components/common/form/CreatedByField.js
    skipped 28 lines
    29 29   },
    30 30  });
    31 31   
     32 +export class CreatedBy {
     33 + constructor(label,
     34 + value,
     35 + type,
     36 + entity) {
     37 + this.label = label;
     38 + this.value = value;
     39 + this.type = type;
     40 + this.entity = entity;
     41 + }
     42 +}
     43 + 
    32 44  class CreatedByField extends Component {
    33 45   constructor(props) {
    34 46   super(props);
    skipped 134 lines
  • ■ ■ ■ ■ ■ ■
    opencti-platform/opencti-front/src/private/components/common/form/ObjectMarkingField.js
    skipped 34 lines
    35 35   }
    36 36  `;
    37 37   
     38 +export class ObjectMarking {
     39 + constructor(label,
     40 + value,
     41 + color,
     42 + entity) {
     43 + this.label = label;
     44 + this.value = value;
     45 + this.color = color;
     46 + this.entity = entity;
     47 + }
     48 +}
     49 + 
    38 50  class ObjectMarkingField extends Component {
    39 51   constructor(props) {
    40 52   super(props);
    skipped 67 lines
  • ■ ■ ■ ■ ■ ■
    opencti-platform/opencti-front/src/private/components/techniques/data_components/DataComponent.tsx
    1  -import React from 'react';
    2  -import { graphql, createFragmentContainer } from 'react-relay';
     1 +import React, { FunctionComponent } from 'react';
     2 +import { createFragmentContainer, graphql } from 'react-relay';
    3 3  import makeStyles from '@mui/styles/makeStyles';
    4  -import Grid from '@mui/material/Grid';
    5 4  import { useFormatter } from '../../../../components/i18n';
     5 +import StixDomainObjectHeader from '../../common/stix_domain_objects/StixDomainObjectHeader';
     6 +import DataComponentPopover from './DataComponentPopover';
     7 +import Security, { KNOWLEDGE_KNUPDATE } from '../../../../utils/Security';
    6 8  import DataComponentEdition from './DataComponentEdition';
    7  -import StixCoreObjectOrStixCoreRelationshipLastReports from '../../analysis/reports/StixCoreObjectOrStixCoreRelationshipLastReports';
    8  -import StixDomainObjectHeader from '../../common/stix_domain_objects/StixDomainObjectHeader';
    9  -import StixCoreObjectOrStixCoreRelationshipNotes from '../../analysis/notes/StixCoreObjectOrStixCoreRelationshipNotes';
     9 +import Grid from '@mui/material/Grid';
    10 10  import StixDomainObjectOverview from '../../common/stix_domain_objects/StixDomainObjectOverview';
     11 +import DataComponentDetails from './DataComponentDetails';
     12 +import SimpleStixObjectOrStixRelationshipStixCoreRelationships from '../../common/stix_core_relationships/SimpleStixObjectOrStixRelationshipStixCoreRelationships';
     13 +import StixCoreObjectOrStixCoreRelationshipLastReports from '../../analysis/reports/StixCoreObjectOrStixCoreRelationshipLastReports';
    11 14  import StixCoreObjectExternalReferences from '../../analysis/external_references/StixCoreObjectExternalReferences';
    12 15  import StixCoreObjectLatestHistory from '../../common/stix_core_objects/StixCoreObjectLatestHistory';
    13  -import SimpleStixObjectOrStixRelationshipStixCoreRelationships from '../../common/stix_core_relationships/SimpleStixObjectOrStixRelationshipStixCoreRelationships';
    14  -import DataComponentPopover from './DataComponentPopover';
    15  -import DataComponentDetails from './DataComponentDetails';
    16  -import Security, { KNOWLEDGE_KNUPDATE } from '../../../../utils/Security';
     16 +import StixCoreObjectOrStixCoreRelationshipNotes from '../../analysis/notes/StixCoreObjectOrStixCoreRelationshipNotes';
     17 +import { DataComponent_dataComponent$data } from './__generated__/DataComponent_dataComponent.graphql';
     18 +import ChannelPopover from '../../arsenal/channels/ChannelPopover';
    17 19   
    18 20  const useStyles = makeStyles(() => ({
    19 21   container: {
    skipped 5 lines
    25 27  }));
    26 28   
    27 29  interface DataComponentComponentProps {
    28  - enableReferences: boolean,
    29  - DataComponent_dataComponent: {
    30  - id: string
    31  - }
     30 + dataComponent: DataComponent_dataComponent$data
     31 + enableReferences: boolean
    32 32  }
    33 33   
    34  -const DataComponentComponent: React.FC<DataComponentComponentProps> = ({ enableReferences, DataComponent_dataComponent }) => {
     34 +const DataComponentComponent: FunctionComponent<DataComponentComponentProps> = ({ dataComponent, enableReferences }) => {
    35 35   const classes = useStyles();
    36 36   const { t } = useFormatter();
    37 37   return (
    38 38   <div className={classes.container}>
    39 39   <StixDomainObjectHeader
    40  - stixDomainObject={DataComponent_dataComponent}
     40 + stixDomainObject={dataComponent}
     41 + PopoverComponent={<DataComponentPopover dataComponentId={dataComponent.id}/>}
    41 42   enableReferences={enableReferences}
    42  - PopoverComponent={DataComponentPopover}
    43 43   />
    44 44   <Grid
    45 45   container={true}
    skipped 1 lines
    47 47   classes={{ container: classes.gridContainer }}
    48 48   >
    49 49   <Grid item={true} xs={6} style={{ paddingTop: 10 }}>
    50  - <StixDomainObjectOverview stixDomainObject={DataComponent_dataComponent} />
     50 + <StixDomainObjectOverview stixDomainObject={dataComponent} />
    51 51   </Grid>
    52 52   <Grid item={true} xs={6} style={{ paddingTop: 10 }}>
    53  - <DataComponentDetails dataComponent={DataComponent_dataComponent} />
     53 + <DataComponentDetails dataComponent={dataComponent} />
    54 54   </Grid>
    55 55   </Grid>
    56 56   <Grid
    skipped 4 lines
    61 61   >
    62 62   <Grid item={true} xs={6}>
    63 63   <SimpleStixObjectOrStixRelationshipStixCoreRelationships
    64  - stixObjectOrStixRelationshipId={DataComponent_dataComponent.id}
    65  - stixObjectOrStixRelationshipLink={`/dashboard/techniques/data_component/${DataComponent_dataComponent.id}/knowledge`}
     64 + stixObjectOrStixRelationshipId={dataComponent.id}
     65 + stixObjectOrStixRelationshipLink={`/dashboard/techniques/data_component/${dataComponent.id}/knowledge`}
    66 66   />
    67 67   </Grid>
    68 68   <Grid item={true} xs={6}>
    69 69   <StixCoreObjectOrStixCoreRelationshipLastReports
    70  - stixCoreObjectOrStixCoreRelationshipId={DataComponent_dataComponent.id}
     70 + stixCoreObjectOrStixCoreRelationshipId={dataComponent.id}
    71 71   />
    72 72   </Grid>
    73 73   </Grid>
    skipped 4 lines
    78 78   style={{ marginTop: 25 }}
    79 79   >
    80 80   <Grid item={true} xs={6}>
    81  - <StixCoreObjectExternalReferences stixCoreObjectId={DataComponent_dataComponent.id} />
     81 + <StixCoreObjectExternalReferences stixCoreObjectId={dataComponent.id} />
    82 82   </Grid>
    83 83   <Grid item={true} xs={6}>
    84  - <StixCoreObjectLatestHistory stixCoreObjectId={DataComponent_dataComponent.id} />
     84 + <StixCoreObjectLatestHistory stixCoreObjectId={dataComponent.id} />
    85 85   </Grid>
    86 86   </Grid>
    87 87   <StixCoreObjectOrStixCoreRelationshipNotes
    88  - stixCoreObjectOrStixCoreRelationshipId={DataComponent_dataComponent.id}
     88 + stixCoreObjectOrStixCoreRelationshipId={dataComponent.id}
    89 89   />
    90 90   <Security needs={[KNOWLEDGE_KNUPDATE]}>
    91  - <DataComponentEdition dataComponentId={DataComponent_dataComponent.id} />
     91 + <DataComponentEdition dataComponentId={dataComponent.id} />
    92 92   </Security>
    93 93   </div>
    94 94   );
    skipped 62 lines
  • ■ ■ ■ ■ ■ ■
    opencti-platform/opencti-front/src/private/components/techniques/data_components/DataComponentCreation.js
    1  -import React, { Component } from 'react';
    2  -import * as PropTypes from 'prop-types';
    3  -import * as R from 'ramda';
    4  -import { Formik, Form, Field } from 'formik';
    5  -import withStyles from '@mui/styles/withStyles';
    6  -import Drawer from '@mui/material/Drawer';
    7  -import Typography from '@mui/material/Typography';
    8  -import Button from '@mui/material/Button';
    9  -import IconButton from '@mui/material/IconButton';
    10  -import Fab from '@mui/material/Fab';
    11  -import { Add, Close } from '@mui/icons-material';
    12  -import * as Yup from 'yup';
    13  -import { graphql } from 'react-relay';
    14  -import { ConnectionHandler } from 'relay-runtime';
    15  -import Dialog from '@mui/material/Dialog';
    16  -import DialogTitle from '@mui/material/DialogTitle';
    17  -import DialogContent from '@mui/material/DialogContent';
    18  -import DialogActions from '@mui/material/DialogActions';
    19  -import inject18n from '../../../../components/i18n';
    20  -import {
    21  - commitMutation,
    22  - handleErrorInForm,
    23  -} from '../../../../relay/environment';
    24  -import TextField from '../../../../components/TextField';
    25  -import CreatedByField from '../../common/form/CreatedByField';
    26  -import ObjectLabelField from '../../common/form/ObjectLabelField';
    27  -import ObjectMarkingField from '../../common/form/ObjectMarkingField';
    28  -import MarkDownField from '../../../../components/MarkDownField';
    29  -import ExternalReferencesField from '../../common/form/ExternalReferencesField';
    30  - 
    31  -const styles = (theme) => ({
    32  - drawerPaper: {
    33  - minHeight: '100vh',
    34  - width: '50%',
    35  - position: 'fixed',
    36  - transition: theme.transitions.create('width', {
    37  - easing: theme.transitions.easing.sharp,
    38  - duration: theme.transitions.duration.enteringScreen,
    39  - }),
    40  - padding: 0,
    41  - },
    42  - dialogActions: {
    43  - padding: '0 17px 20px 0',
    44  - },
    45  - createButton: {
    46  - position: 'fixed',
    47  - bottom: 30,
    48  - right: 30,
    49  - },
    50  - createButtonContextual: {
    51  - position: 'fixed',
    52  - bottom: 30,
    53  - right: 30,
    54  - zIndex: 2000,
    55  - },
    56  - buttons: {
    57  - marginTop: 20,
    58  - textAlign: 'right',
    59  - },
    60  - button: {
    61  - marginLeft: theme.spacing(2),
    62  - },
    63  - header: {
    64  - backgroundColor: theme.palette.background.nav,
    65  - padding: '20px 20px 20px 60px',
    66  - },
    67  - closeButton: {
    68  - position: 'absolute',
    69  - top: 12,
    70  - left: 5,
    71  - color: 'inherit',
    72  - },
    73  - importButton: {
    74  - position: 'absolute',
    75  - top: 15,
    76  - right: 20,
    77  - },
    78  - container: {
    79  - padding: '10px 20px 20px 20px',
    80  - },
    81  -});
    82  - 
    83  -const dataComponentMutation = graphql`
    84  - mutation DataComponentCreationMutation($input: DataComponentAddInput!) {
    85  - dataComponentAdd(input: $input) {
    86  - id
    87  - name
    88  - description
    89  - }
    90  - }
    91  -`;
    92  - 
    93  -const dataComponentValidation = (t) => Yup.object().shape({
    94  - name: Yup.string().required(t('This field is required')),
    95  - description: Yup.string()
    96  - .min(3, t('The value is too short'))
    97  - .max(5000, t('The value is too long'))
    98  - .required(t('This field is required')),
    99  -});
    100  - 
    101  -const sharedUpdater = (store, userId, paginationOptions, newEdge) => {
    102  - const userProxy = store.get(userId);
    103  - const conn = ConnectionHandler.getConnection(
    104  - userProxy,
    105  - 'Pagination_dataComponents',
    106  - paginationOptions,
    107  - );
    108  - ConnectionHandler.insertEdgeBefore(conn, newEdge);
    109  -};
    110  - 
    111  -class DataComponentCreation extends Component {
    112  - constructor(props) {
    113  - super(props);
    114  - this.state = { open: false };
    115  - }
    116  - 
    117  - handleOpen() {
    118  - this.setState({ open: true });
    119  - }
    120  - 
    121  - handleClose() {
    122  - this.setState({ open: false });
    123  - }
    124  - 
    125  - onSubmit(values, { setSubmitting, setErrors, resetForm }) {
    126  - const finalValues = R.pipe(
    127  - R.assoc('createdBy', values.createdBy?.value),
    128  - R.assoc('objectMarking', R.pluck('value', values.objectMarking)),
    129  - R.assoc('objectLabel', R.pluck('value', values.objectLabel)),
    130  - )(values);
    131  - commitMutation({
    132  - mutation: dataComponentMutation,
    133  - variables: {
    134  - input: finalValues,
    135  - },
    136  - updater: (store) => {
    137  - const payload = store.getRootField('dataComponentAdd');
    138  - const newEdge = payload.setLinkedRecord(payload, 'node'); // Creation of the pagination container.
    139  - const container = store.getRoot();
    140  - sharedUpdater(
    141  - store,
    142  - container.getDataID(),
    143  - this.props.paginationOptions,
    144  - newEdge,
    145  - );
    146  - },
    147  - onError: (error) => {
    148  - handleErrorInForm(error, setErrors);
    149  - setSubmitting(false);
    150  - },
    151  - setSubmitting,
    152  - onCompleted: () => {
    153  - setSubmitting(false);
    154  - resetForm();
    155  - this.handleClose();
    156  - },
    157  - });
    158  - }
    159  - 
    160  - onReset() {
    161  - this.handleClose();
    162  - }
    163  - 
    164  - renderClassic() {
    165  - const { t, classes } = this.props;
    166  - return (
    167  - <div>
    168  - <Fab
    169  - onClick={this.handleOpen.bind(this)}
    170  - color="secondary"
    171  - aria-label="Add"
    172  - className={classes.createButton}
    173  - >
    174  - <Add />
    175  - </Fab>
    176  - <Drawer
    177  - open={this.state.open}
    178  - anchor="right"
    179  - elevation={1}
    180  - sx={{ zIndex: 1202 }}
    181  - classes={{ paper: classes.drawerPaper }}
    182  - onClose={this.handleClose.bind(this)}
    183  - >
    184  - <div className={classes.header}>
    185  - <IconButton
    186  - aria-label="Close"
    187  - className={classes.closeButton}
    188  - onClick={this.handleClose.bind(this)}
    189  - size="large"
    190  - color="primary"
    191  - >
    192  - <Close fontSize="small" color="primary" />
    193  - </IconButton>
    194  - <Typography variant="h6">{t('Create a Data Component')}</Typography>
    195  - </div>
    196  - <div className={classes.container}>
    197  - <Formik
    198  - initialValues={{
    199  - name: '',
    200  - description: '',
    201  - createdBy: '',
    202  - objectMarking: [],
    203  - objectLabel: [],
    204  - externalReferences: [],
    205  - }}
    206  - validationSchema={dataComponentValidation(t)}
    207  - onSubmit={this.onSubmit.bind(this)}
    208  - onReset={this.onReset.bind(this)}
    209  - >
    210  - {({
    211  - submitForm,
    212  - handleReset,
    213  - isSubmitting,
    214  - setFieldValue,
    215  - values,
    216  - }) => (
    217  - <Form style={{ margin: '20px 0 20px 0' }}>
    218  - <Field
    219  - component={TextField}
    220  - variant="standard"
    221  - name="name"
    222  - label={t('Name')}
    223  - fullWidth={true}
    224  - detectDuplicate={['Data Component']}
    225  - />
    226  - <Field
    227  - component={MarkDownField}
    228  - name="description"
    229  - label={t('Description')}
    230  - fullWidth={true}
    231  - multiline={true}
    232  - rows="4"
    233  - style={{ marginTop: 20 }}
    234  - />
    235  - <CreatedByField
    236  - name="createdBy"
    237  - style={{ marginTop: 20, width: '100%' }}
    238  - setFieldValue={setFieldValue}
    239  - />
    240  - <ObjectLabelField
    241  - name="objectLabel"
    242  - style={{ marginTop: 20, width: '100%' }}
    243  - setFieldValue={setFieldValue}
    244  - values={values.objectLabel}
    245  - />
    246  - <ObjectMarkingField
    247  - name="objectMarking"
    248  - style={{ marginTop: 20, width: '100%' }}
    249  - />
    250  - <ExternalReferencesField
    251  - name="externalReferences"
    252  - style={{ marginTop: 20, width: '100%' }}
    253  - setFieldValue={setFieldValue}
    254  - values={values.externalReferences}
    255  - />
    256  - <div className={classes.buttons}>
    257  - <Button
    258  - variant="contained"
    259  - onClick={handleReset}
    260  - disabled={isSubmitting}
    261  - classes={{ root: classes.button }}
    262  - >
    263  - {t('Cancel')}
    264  - </Button>
    265  - <Button
    266  - variant="contained"
    267  - color="secondary"
    268  - onClick={submitForm}
    269  - disabled={isSubmitting}
    270  - classes={{ root: classes.button }}
    271  - >
    272  - {t('Create')}
    273  - </Button>
    274  - </div>
    275  - </Form>
    276  - )}
    277  - </Formik>
    278  - </div>
    279  - </Drawer>
    280  - </div>
    281  - );
    282  - }
    283  - 
    284  - renderContextual() {
    285  - const { t, classes, display } = this.props;
    286  - return (
    287  - <div style={{ display: display ? 'block' : 'none' }}>
    288  - <Fab
    289  - onClick={this.handleOpen.bind(this)}
    290  - color="secondary"
    291  - aria-label="Add"
    292  - className={classes.createButtonContextual}
    293  - >
    294  - <Add />
    295  - </Fab>
    296  - <Dialog
    297  - open={this.state.open}
    298  - onClose={this.handleClose.bind(this)}
    299  - PaperProps={{ elevation: 1 }}
    300  - >
    301  - <Formik
    302  - initialValues={{
    303  - name: '',
    304  - description: '',
    305  - createdBy: '',
    306  - objectMarking: [],
    307  - objectLabel: [],
    308  - externalReferences: [],
    309  - }}
    310  - validationSchema={dataComponentValidation(t)}
    311  - onSubmit={this.onSubmit.bind(this)}
    312  - onReset={this.onReset.bind(this)}
    313  - >
    314  - {({
    315  - submitForm,
    316  - handleReset,
    317  - isSubmitting,
    318  - setFieldValue,
    319  - values,
    320  - }) => (
    321  - <Form>
    322  - <DialogTitle>{t('Create a Data Component')}</DialogTitle>
    323  - <DialogContent>
    324  - <Field
    325  - component={TextField}
    326  - variant="standard"
    327  - name="name"
    328  - label={t('Name')}
    329  - fullWidth={true}
    330  - />
    331  - <Field
    332  - component={MarkDownField}
    333  - name="description"
    334  - label={t('Description')}
    335  - fullWidth={true}
    336  - multiline={true}
    337  - rows="4"
    338  - style={{ marginTop: 20 }}
    339  - />
    340  - <CreatedByField
    341  - name="createdBy"
    342  - style={{ marginTop: 20, width: '100%' }}
    343  - setFieldValue={setFieldValue}
    344  - />
    345  - <ObjectLabelField
    346  - name="objectLabel"
    347  - style={{ marginTop: 20, width: '100%' }}
    348  - setFieldValue={setFieldValue}
    349  - values={values.objectLabel}
    350  - />
    351  - <ObjectMarkingField
    352  - name="objectMarking"
    353  - style={{ marginTop: 20, width: '100%' }}
    354  - />
    355  - <ExternalReferencesField
    356  - name="externalReferences"
    357  - style={{ marginTop: 20, width: '100%' }}
    358  - setFieldValue={setFieldValue}
    359  - values={values.externalReferences}
    360  - />
    361  - </DialogContent>
    362  - <DialogActions>
    363  - <Button onClick={handleReset} disabled={isSubmitting}>
    364  - {t('Cancel')}
    365  - </Button>
    366  - <Button
    367  - color="secondary"
    368  - onClick={submitForm}
    369  - disabled={isSubmitting}
    370  - >
    371  - {t('Create')}
    372  - </Button>
    373  - </DialogActions>
    374  - </Form>
    375  - )}
    376  - </Formik>
    377  - </Dialog>
    378  - </div>
    379  - );
    380  - }
    381  - 
    382  - render() {
    383  - const { contextual } = this.props;
    384  - if (contextual) {
    385  - return this.renderContextual();
    386  - }
    387  - return this.renderClassic();
    388  - }
    389  -}
    390  - 
    391  -DataComponentCreation.propTypes = {
    392  - paginationOptions: PropTypes.object,
    393  - classes: PropTypes.object,
    394  - theme: PropTypes.object,
    395  - t: PropTypes.func,
    396  -};
    397  - 
    398  -export default R.compose(
    399  - inject18n,
    400  - withStyles(styles, { withTheme: true }),
    401  -)(DataComponentCreation);
    402  - 
  • ■ ■ ■ ■ ■ ■
    opencti-platform/opencti-front/src/private/components/techniques/data_components/DataComponentCreation.tsx
     1 +import React, { FunctionComponent, useState } from 'react';
     2 +import * as R from 'ramda';
     3 +import { Field, Form, Formik } from 'formik';
     4 +import Drawer from '@mui/material/Drawer';
     5 +import Typography from '@mui/material/Typography';
     6 +import Button from '@mui/material/Button';
     7 +import IconButton from '@mui/material/IconButton';
     8 +import Fab from '@mui/material/Fab';
     9 +import { Add, Close } from '@mui/icons-material';
     10 +import * as Yup from 'yup';
     11 +import { graphql } from 'react-relay';
     12 +import { ConnectionHandler, RecordProxy, RecordSourceSelectorProxy } from 'relay-runtime';
     13 +import { useFormatter } from '../../../../components/i18n';
     14 +import { commitMutation, handleErrorInForm, } from '../../../../relay/environment';
     15 +import TextField from '../../../../components/TextField';
     16 +import CreatedByField, { CreatedBy } from '../../common/form/CreatedByField';
     17 +import ObjectLabelField from '../../common/form/ObjectLabelField';
     18 +import ObjectMarkingField from '../../common/form/ObjectMarkingField';
     19 +import MarkDownField from '../../../../components/MarkDownField';
     20 +import makeStyles from '@mui/styles/makeStyles';
     21 +import { Theme } from '../../../../components/Theme';
     22 +import { PaginationOptions } from '../../../../components/list_lines';
     23 +import { FormikHelpers } from 'formik/dist/types';
     24 + 
     25 +const styles = makeStyles<Theme>((theme) => ({
     26 + drawerPaper: {
     27 + minHeight: '100vh',
     28 + width: '50%',
     29 + position: 'fixed',
     30 + transition: theme.transitions.create('width', {
     31 + easing: theme.transitions.easing.sharp,
     32 + duration: theme.transitions.duration.enteringScreen,
     33 + }),
     34 + padding: 0,
     35 + },
     36 + dialogActions: {
     37 + padding: '0 17px 20px 0',
     38 + },
     39 + createButton: {
     40 + position: 'fixed',
     41 + bottom: 30,
     42 + right: 30,
     43 + },
     44 + createButtonContextual: {
     45 + position: 'fixed',
     46 + bottom: 30,
     47 + right: 30,
     48 + zIndex: 2000,
     49 + },
     50 + buttons: {
     51 + marginTop: 20,
     52 + textAlign: 'right',
     53 + },
     54 + button: {
     55 + marginLeft: theme.spacing(2),
     56 + },
     57 + header: {
     58 + backgroundColor: theme.palette.background.nav,
     59 + padding: '20px 20px 20px 60px',
     60 + },
     61 + closeButton: {
     62 + position: 'absolute',
     63 + top: 12,
     64 + left: 5,
     65 + color: 'inherit',
     66 + },
     67 + importButton: {
     68 + position: 'absolute',
     69 + top: 15,
     70 + right: 20,
     71 + },
     72 + container: {
     73 + padding: '10px 20px 20px 20px',
     74 + },
     75 +}));
     76 + 
     77 +const dataComponentMutation = graphql`
     78 + mutation DataComponentCreationMutation($input: DataComponentAddInput!) {
     79 + dataComponentAdd(input: $input) {
     80 + id
     81 + name
     82 + description
     83 + }
     84 + }
     85 +`;
     86 + 
     87 +const dataComponentValidation = (t: (message: string) => string) => Yup.object()
     88 + .shape({
     89 + name: Yup.string()
     90 + .required(t('This field is required')),
     91 + description: Yup.string()
     92 + .min(3, t('The value is too short'))
     93 + .max(5000, t('The value is too long'))
     94 + .required(t('This field is required')),
     95 + });
     96 + 
     97 +const sharedUpdater = (store: RecordSourceSelectorProxy, userId: string, paginationOptions: PaginationOptions, newEdge: RecordProxy) => {
     98 + const userProxy = store.get(userId);
     99 + if (userProxy) {
     100 + const conn: RecordProxy | null | undefined = ConnectionHandler.getConnection(
     101 + userProxy,
     102 + 'Pagination_dataComponents',
     103 + paginationOptions,
     104 + );
     105 + if (conn) {
     106 + ConnectionHandler.insertEdgeBefore(conn, newEdge);
     107 + }
     108 + }
     109 +};
     110 + 
     111 +interface DataComponentCreationProps {
     112 + paginationOptions: PaginationOptions
     113 +}
     114 + 
     115 +interface DataComponentForm { // TODO: handle this type
     116 + name: string,
     117 + description: string,
     118 + createdBy: CreatedBy,
     119 + objectMarking: Array<any>,
     120 + objectLabel: Array<any>,
     121 +}
     122 + 
     123 +const DataComponentCreation: FunctionComponent<DataComponentCreationProps> = ({
     124 + paginationOptions
     125 +}) => {
     126 + const { t } = useFormatter();
     127 + const classes = styles();
     128 + 
     129 + const [open, setOpen] = useState(false);
     130 + 
     131 + const handleOpen = () => {
     132 + setOpen(true);
     133 + }
     134 + 
     135 + const handleClose = () => {
     136 + setOpen(false);
     137 + }
     138 + 
     139 + const onSubmit = (values: DataComponentForm, { setSubmitting, setErrors, resetForm }: FormikHelpers<DataComponentForm>) => {
     140 + const finalValues = R.pipe(
     141 + R.assoc('createdBy', values.createdBy?.value),
     142 + R.assoc('objectMarking', R.pluck('value', values.objectMarking)),
     143 + R.assoc('objectLabel', R.pluck('value', values.objectLabel)),
     144 + // TODO: externalReferences
     145 + )(values);
     146 + commitMutation({
     147 + mutation: dataComponentMutation,
     148 + variables: {
     149 + input: finalValues,
     150 + },
     151 + updater: (store: RecordSourceSelectorProxy) => {
     152 + const payload: RecordProxy | null = store.getRootField('dataComponentAdd');
     153 + if (payload) {
     154 + const newEdge: RecordProxy = payload.setLinkedRecord(payload, 'node'); // Creation of the pagination container.
     155 + const container: RecordProxy = store.getRoot();
     156 + sharedUpdater(
     157 + store,
     158 + container.getDataID(),
     159 + paginationOptions,
     160 + newEdge,
     161 + );
     162 + }
     163 + },
     164 + onError: (error: Error) => {
     165 + handleErrorInForm(error, setErrors);
     166 + setSubmitting(false);
     167 + },
     168 + setSubmitting,
     169 + onCompleted: () => {
     170 + setSubmitting(false);
     171 + resetForm();
     172 + handleClose();
     173 + },
     174 + optimisticUpdater: undefined,
     175 + optimisticResponse: undefined,
     176 + });
     177 + }
     178 + 
     179 + const onReset = () => {
     180 + handleClose();
     181 + }
     182 + 
     183 + return (
     184 + <div>
     185 + <Fab
     186 + onClick={handleOpen}
     187 + color="secondary"
     188 + aria-label="Add"
     189 + className={classes.createButton}
     190 + >
     191 + <Add />
     192 + </Fab>
     193 + <Drawer
     194 + open={open}
     195 + anchor="right"
     196 + elevation={1}
     197 + sx={{ zIndex: 1202 }}
     198 + classes={{ paper: classes.drawerPaper }}
     199 + onClose={handleClose}
     200 + >
     201 + <div className={classes.header}>
     202 + <IconButton
     203 + aria-label="Close"
     204 + className={classes.closeButton}
     205 + onClick={handleClose}
     206 + size="large"
     207 + color="primary"
     208 + >
     209 + <Close fontSize="small" color="primary" />
     210 + </IconButton>
     211 + <Typography variant="h6">{t('Create a Data Component')}</Typography>
     212 + </div>
     213 + <div className={classes.container}>
     214 + <Formik
     215 + initialValues={{
     216 + name: '',
     217 + description: '',
     218 + createdBy: {} as CreatedBy,
     219 + objectMarking: [],
     220 + objectLabel: [],
     221 + }}
     222 + validationSchema={dataComponentValidation(t)}
     223 + onSubmit={onSubmit}
     224 + onReset={onReset}
     225 + >
     226 + {({
     227 + submitForm,
     228 + handleReset,
     229 + isSubmitting,
     230 + setFieldValue,
     231 + values,
     232 + }) => (
     233 + <Form style={{ margin: '20px 0 20px 0' }}>
     234 + <Field
     235 + component={TextField}
     236 + variant="standard"
     237 + name="name"
     238 + label={t('Name')}
     239 + fullWidth={true}
     240 + detectDuplicate={['Data Component']}
     241 + />
     242 + <Field
     243 + component={MarkDownField}
     244 + name="description"
     245 + label={t('Description')}
     246 + fullWidth={true}
     247 + multiline={true}
     248 + rows="4"
     249 + style={{ marginTop: 20 }}
     250 + />
     251 + <CreatedByField
     252 + name="createdBy"
     253 + style={{
     254 + marginTop: 20,
     255 + width: '100%'
     256 + }}
     257 + setFieldValue={setFieldValue}
     258 + />
     259 + <ObjectLabelField
     260 + name="objectLabel"
     261 + style={{
     262 + marginTop: 20,
     263 + width: '100%'
     264 + }}
     265 + setFieldValue={setFieldValue}
     266 + values={values.objectLabel}
     267 + />
     268 + <ObjectMarkingField
     269 + name="objectMarking"
     270 + style={{
     271 + marginTop: 20,
     272 + width: '100%'
     273 + }}
     274 + />
     275 + <div className={classes.buttons}>
     276 + <Button
     277 + variant="contained"
     278 + onClick={handleReset}
     279 + disabled={isSubmitting}
     280 + classes={{ root: classes.button }}
     281 + >
     282 + {t('Cancel')}
     283 + </Button>
     284 + <Button
     285 + variant="contained"
     286 + color="secondary"
     287 + onClick={submitForm}
     288 + disabled={isSubmitting}
     289 + classes={{ root: classes.button }}
     290 + >
     291 + {t('Create')}
     292 + </Button>
     293 + </div>
     294 + </Form>
     295 + )}
     296 + </Formik>
     297 + </div>
     298 + </Drawer>
     299 + </div>
     300 + )
     301 +}
     302 + 
     303 +export default DataComponentCreation;
     304 + 
  • ■ ■ ■ ■ ■ ■
    opencti-platform/opencti-front/src/private/components/techniques/data_components/DataComponentDetails.js opencti-platform/opencti-front/src/private/components/techniques/data_components/DataComponentDetails.tsx
    1  -import React, { Component } from 'react';
    2  -import * as PropTypes from 'prop-types';
    3  -import { compose } from 'ramda';
     1 +import React, { FunctionComponent } from 'react';
    4 2  import { createFragmentContainer, graphql } from 'react-relay';
    5  -import withStyles from '@mui/styles/withStyles';
    6 3  import Paper from '@mui/material/Paper';
    7 4  import Typography from '@mui/material/Typography';
    8 5  import Grid from '@mui/material/Grid';
    9 6  import ExpandableMarkdown from '../../../../components/ExpandableMarkdown';
    10  -import inject18n from '../../../../components/i18n';
     7 +import { useFormatter } from '../../../../components/i18n';
     8 +import makeStyles from '@mui/styles/makeStyles';
    11 9   
    12  -const styles = () => ({
     10 +const styles = makeStyles(() => ({
    13 11   paper: {
    14 12   height: '100%',
    15 13   minHeight: '100%',
    skipped 1 lines
    17 15   padding: '15px',
    18 16   borderRadius: 6,
    19 17   },
    20  -});
     18 +}));
     19 + 
     20 +interface DataComponentDetailsProps {
     21 + dataComponent: any // TODO: fix this type
     22 +}
     23 + 
     24 +const DataComponentDetailsComponent: FunctionComponent<DataComponentDetailsProps> = ({dataComponent}) => {
     25 + const { t } = useFormatter();
     26 + const classes = styles();
    21 27   
    22  -class DataComponentDetailsComponent extends Component {
    23  - render() {
    24  - const { t, classes, dataComponent } = this.props;
    25 28   return (
    26 29   <div style={{ height: '100%' }}>
    27 30   <Typography variant="h4" gutterBottom={true}>
    skipped 14 lines
    42 45   </Paper>
    43 46   </div>
    44 47   );
    45  - }
    46 48  }
    47 49   
    48  -DataComponentDetailsComponent.propTypes = {
    49  - dataComponent: PropTypes.object,
    50  - classes: PropTypes.object,
    51  - t: PropTypes.func,
    52  - fld: PropTypes.func,
    53  -};
    54  - 
    55 50  const DataComponentDetails = createFragmentContainer(
    56 51   DataComponentDetailsComponent,
    57 52   {
    skipped 6 lines
    64 59   },
    65 60  );
    66 61   
    67  -export default compose(inject18n, withStyles(styles))(DataComponentDetails);
     62 +export default DataComponentDetails;
    68 63   
  • ■ ■ ■ ■ ■ ■
    opencti-platform/opencti-front/src/private/components/techniques/data_components/DataComponentEdition.js
    1  -import React, { Component } from 'react';
    2  -import * as PropTypes from 'prop-types';
    3  -import { compose } from 'ramda';
    4  -import withStyles from '@mui/styles/withStyles';
    5  -import Drawer from '@mui/material/Drawer';
    6  -import Fab from '@mui/material/Fab';
    7  -import { Edit } from '@mui/icons-material';
    8  -import { graphql } from 'react-relay';
    9  -import { commitMutation, QueryRenderer } from '../../../../relay/environment';
    10  -import inject18n from '../../../../components/i18n';
    11  -import Loader from '../../../../components/Loader';
    12  -import DataComponentEditionContainer from './DataComponentEditionContainer';
    13  -import { dataComponentEditionOverviewFocus } from './DataComponentEditionOverview';
    14  - 
    15  -const styles = (theme) => ({
    16  - editButton: {
    17  - position: 'fixed',
    18  - bottom: 30,
    19  - right: 30,
    20  - },
    21  - drawerPaper: {
    22  - minHeight: '100vh',
    23  - width: '50%',
    24  - position: 'fixed',
    25  - overflow: 'auto',
    26  - transition: theme.transitions.create('width', {
    27  - easing: theme.transitions.easing.sharp,
    28  - duration: theme.transitions.duration.enteringScreen,
    29  - }),
    30  - padding: 0,
    31  - },
    32  -});
    33  - 
    34  -export const dataComponentEditionQuery = graphql`
    35  - query DataComponentEditionContainerQuery($id: String!) {
    36  - dataComponent(id: $id) {
    37  - ...DataComponentEditionContainer_dataComponent
    38  - }
    39  - settings {
    40  - platform_enable_reference
    41  - }
    42  - }
    43  -`;
    44  - 
    45  -class DataComponentEdition extends Component {
    46  - constructor(props) {
    47  - super(props);
    48  - this.state = { open: false };
    49  - }
    50  - 
    51  - handleOpen() {
    52  - this.setState({ open: true });
    53  - }
    54  - 
    55  - handleClose() {
    56  - commitMutation({
    57  - mutation: dataComponentEditionOverviewFocus,
    58  - variables: {
    59  - id: this.props.dataComponentId,
    60  - input: { focusOn: '' },
    61  - },
    62  - });
    63  - this.setState({ open: false });
    64  - }
    65  - 
    66  - render() {
    67  - const { classes, dataComponentId } = this.props;
    68  - return (
    69  - <div>
    70  - <Fab
    71  - onClick={this.handleOpen.bind(this)}
    72  - color="secondary"
    73  - aria-label="Edit"
    74  - className={classes.editButton}
    75  - >
    76  - <Edit />
    77  - </Fab>
    78  - <Drawer
    79  - open={this.state.open}
    80  - anchor="right"
    81  - elevation={1}
    82  - sx={{ zIndex: 1202 }}
    83  - classes={{ paper: classes.drawerPaper }}
    84  - onClose={this.handleClose.bind(this)}
    85  - >
    86  - <QueryRenderer
    87  - query={dataComponentEditionQuery}
    88  - variables={{ id: dataComponentId }}
    89  - render={({ props }) => {
    90  - if (props) {
    91  - return (
    92  - <DataComponentEditionContainer
    93  - dataComponent={props.dataComponent}
    94  - enableReferences={props.settings.platform_enable_reference?.includes(
    95  - 'Data-Component',
    96  - )}
    97  - handleClose={this.handleClose.bind(this)}
    98  - />
    99  - );
    100  - }
    101  - return <Loader variant="inElement" />;
    102  - }}
    103  - />
    104  - </Drawer>
    105  - </div>
    106  - );
    107  - }
    108  -}
    109  - 
    110  -DataComponentEdition.propTypes = {
    111  - dataComponentId: PropTypes.string,
    112  - classes: PropTypes.object,
    113  - theme: PropTypes.object,
    114  - t: PropTypes.func,
    115  -};
    116  - 
    117  -export default compose(
    118  - inject18n,
    119  - withStyles(styles, { withTheme: true }),
    120  -)(DataComponentEdition);
    121  - 
  • ■ ■ ■ ■ ■ ■
    opencti-platform/opencti-front/src/private/components/techniques/data_components/DataComponentEdition.tsx
     1 +import React, { FunctionComponent, useState } from 'react';
     2 +import Drawer from '@mui/material/Drawer';
     3 +import Fab from '@mui/material/Fab';
     4 +import { Edit } from '@mui/icons-material';
     5 +import { graphql } from 'react-relay';
     6 +import { commitMutation, QueryRenderer } from '../../../../relay/environment';
     7 +import Loader, { LoaderVariant } from '../../../../components/Loader';
     8 +import DataComponentEditionContainer from './DataComponentEditionContainer';
     9 +import { dataComponentEditionOverviewFocus } from './DataComponentEditionOverview';
     10 +import makeStyles from '@mui/styles/makeStyles';
     11 +import { Theme } from '../../../../components/Theme';
     12 + 
     13 +const styles = makeStyles<Theme>((theme) => ({
     14 + editButton: {
     15 + position: 'fixed',
     16 + bottom: 30,
     17 + right: 30,
     18 + },
     19 + drawerPaper: {
     20 + minHeight: '100vh',
     21 + width: '50%',
     22 + position: 'fixed',
     23 + overflow: 'auto',
     24 + transition: theme.transitions.create('width', {
     25 + easing: theme.transitions.easing.sharp,
     26 + duration: theme.transitions.duration.enteringScreen,
     27 + }),
     28 + padding: 0,
     29 + },
     30 +}));
     31 + 
     32 +export const dataComponentEditionQuery = graphql`
     33 + query DataComponentEditionContainerQuery($id: String!) {
     34 + dataComponent(id: $id) {
     35 + ...DataComponentEditionContainer_dataComponent
     36 + }
     37 + settings {
     38 + platform_enable_reference
     39 + }
     40 + }
     41 +`;
     42 + 
     43 +interface DataComponentEditionProps {
     44 + dataComponentId: string
     45 +}
     46 + 
     47 +const DataComponentEdition: FunctionComponent<DataComponentEditionProps> = ({dataComponentId}) => {
     48 + const classes = styles();
     49 + const [open, setOpen] = useState(false);
     50 + 
     51 + const handleOpen = () => {
     52 + setOpen(true)
     53 + }
     54 + 
     55 + const handleClose = () => {
     56 + commitMutation({
     57 + mutation: dataComponentEditionOverviewFocus,
     58 + variables: {
     59 + id: dataComponentId,
     60 + input: { focusOn: '' },
     61 + },
     62 + updater: undefined,
     63 + optimisticUpdater: undefined,
     64 + optimisticResponse: undefined,
     65 + onCompleted: undefined,
     66 + onError: undefined,
     67 + setSubmitting: undefined,
     68 + });
     69 + setOpen(false)
     70 + }
     71 + 
     72 + return (
     73 + <div>
     74 + <Fab
     75 + onClick={handleOpen}
     76 + color="secondary"
     77 + aria-label="Edit"
     78 + className={classes.editButton}
     79 + >
     80 + <Edit />
     81 + </Fab>
     82 + <Drawer
     83 + open={open}
     84 + anchor="right"
     85 + elevation={1}
     86 + sx={{ zIndex: 1202 }}
     87 + classes={{ paper: classes.drawerPaper }}
     88 + onClose={handleClose}
     89 + >
     90 + <QueryRenderer
     91 + query={dataComponentEditionQuery}
     92 + variables={{ id: dataComponentId }}
     93 + render={(result: { props: any }) => { // TODO: fix this type
     94 + if (result.props) {
     95 + return (
     96 + <DataComponentEditionContainer
     97 + dataComponent={result.props.dataComponent}
     98 + // TODO: what is references ?
     99 + enableReferences={result.props.settings.platform_enable_reference?.includes(
     100 + 'Data-Component',
     101 + )}
     102 + handleClose={handleClose}
     103 + />
     104 + );
     105 + }
     106 + return <Loader variant={LoaderVariant.inElement} />;
     107 + }}
     108 + />
     109 + </Drawer>
     110 + </div>
     111 + );
     112 +}
     113 + 
     114 +export default DataComponentEdition;
     115 + 
  • ■ ■ ■ ■ ■ ■
    opencti-platform/opencti-front/src/private/components/techniques/data_components/DataComponentEditionOverview.js
    1  -import React, { Component } from 'react';
    2  -import * as PropTypes from 'prop-types';
    3  -import { createFragmentContainer, graphql } from 'react-relay';
    4  -import { Field, Form, Formik } from 'formik';
    5  -import withStyles from '@mui/styles/withStyles';
    6  -import { assoc, compose, difference, head, map, pathOr, pick, pipe, split, } from 'ramda';
    7  -import * as Yup from 'yup';
    8  -import inject18n from '../../../../components/i18n';
    9  -import TextField from '../../../../components/TextField';
    10  -import { SubscriptionFocus } from '../../../../components/Subscription';
    11  -import { commitMutation } from '../../../../relay/environment';
    12  -import CreatedByField from '../../common/form/CreatedByField';
    13  -import ObjectMarkingField from '../../common/form/ObjectMarkingField';
    14  -import MarkDownField from '../../../../components/MarkDownField';
    15  -import { convertCreatedBy, convertMarkings, convertStatus, } from '../../../../utils/Edition';
    16  -import StatusField from '../../common/form/StatusField';
    17  - 
    18  -const styles = (theme) => ({
    19  - drawerPaper: {
    20  - minHeight: '100vh',
    21  - width: '50%',
    22  - position: 'fixed',
    23  - overflow: 'hidden',
    24  - 
    25  - transition: theme.transitions.create('width', {
    26  - easing: theme.transitions.easing.sharp,
    27  - duration: theme.transitions.duration.enteringScreen,
    28  - }),
    29  - padding: '30px 30px 30px 30px',
    30  - },
    31  - createButton: {
    32  - position: 'fixed',
    33  - bottom: 30,
    34  - right: 30,
    35  - },
    36  - importButton: {
    37  - position: 'absolute',
    38  - top: 30,
    39  - right: 30,
    40  - },
    41  -});
    42  - 
    43  -const dataComponentMutationFieldPatch = graphql`
    44  - mutation DataComponentEditionOverviewFieldPatchMutation(
    45  - $id: ID!
    46  - $input: [EditInput]!
    47  - $commitMessage: String
    48  - $references: [String]
    49  - ) {
    50  - dataComponentFieldPatch(
    51  - id: $id
    52  - input: $input
    53  - commitMessage: $commitMessage
    54  - references: $references
    55  - ) {
    56  - ...DataComponentEditionOverview_dataComponent
    57  - ...DataComponent_dataComponent
    58  - }
    59  - }
    60  -`;
    61  - 
    62  -export const dataComponentEditionOverviewFocus = graphql`
    63  - mutation DataComponentEditionOverviewFocusMutation($id: ID!, $input: EditContext!) {
    64  - dataComponentContextPatch(id: $id, input: $input) {
    65  - id
    66  - }
    67  - }
    68  -`;
    69  - 
    70  -const dataComponentMutationRelationAdd = graphql`
    71  - mutation DataComponentEditionOverviewRelationAddMutation(
    72  - $id: ID!
    73  - $input: StixMetaRelationshipAddInput!
    74  - ) {
    75  - dataComponentRelationAdd(id: $id, input: $input) {
    76  - from {
    77  - ...DataComponentEditionOverview_dataComponent
    78  - }
    79  - }
    80  - }
    81  -`;
    82  - 
    83  -const dataComponentMutationRelationDelete = graphql`
    84  - mutation DataComponentEditionOverviewRelationDeleteMutation(
    85  - $id: ID!
    86  - $toId: StixRef!
    87  - $relationship_type: String!
    88  - ) {
    89  - dataComponentRelationDelete(
    90  - id: $id
    91  - toId: $toId
    92  - relationship_type: $relationship_type
    93  - ) {
    94  - ...DataComponentEditionOverview_dataComponent
    95  - }
    96  - }
    97  -`;
    98  - 
    99  -const dataComponentValidation = (t) => Yup.object()
    100  - .shape({
    101  - name: Yup.string()
    102  - .required(t('This field is required')),
    103  - description: Yup.string()
    104  - .min(3, t('The value is too short'))
    105  - .max(5000, t('The value is too long'))
    106  - .required(t('This field is required')),
    107  - x_opencti_threat_hunting: Yup.string()
    108  - .nullable(),
    109  - x_opencti_log_sources: Yup.string()
    110  - .nullable(),
    111  - references: Yup.array()
    112  - .required(t('This field is required')),
    113  - x_opencti_workflow_id: Yup.object(),
    114  - x_mitre_id: Yup.string()
    115  - .nullable(),
    116  - });
    117  - 
    118  -class DataComponentEditionOverviewComponent extends Component {
    119  - handleChangeFocus(name) {
    120  - commitMutation({
    121  - mutation: dataComponentEditionOverviewFocus,
    122  - variables: {
    123  - id: this.props.dataComponent.id,
    124  - input: {
    125  - focusOn: name,
    126  - },
    127  - },
    128  - });
    129  - }
    130  - 
    131  - handleSubmitField(name, value) {
    132  - let finalValue = value;
    133  - if (name === 'x_opencti_log_sources') {
    134  - finalValue = split('\n', value);
    135  - }
    136  - if (name === 'x_opencti_workflow_id') {
    137  - finalValue = value.value;
    138  - }
    139  - dataComponentValidation(this.props.t)
    140  - .validateAt(name, { [name]: value })
    141  - .then(() => {
    142  - commitMutation({
    143  - mutation: dataComponentMutationFieldPatch,
    144  - variables: {
    145  - id: this.props.dataComponent.id,
    146  - input: {
    147  - key: name,
    148  - value: finalValue ?? ''
    149  - },
    150  - },
    151  - });
    152  - })
    153  - .catch(() => false);
    154  - }
    155  - 
    156  - handleChangeCreatedBy(name, value) {
    157  - if (!this.props.enableReferences) {
    158  - commitMutation({
    159  - mutation: dataComponentMutationFieldPatch,
    160  - variables: {
    161  - id: this.props.dataComponent.id,
    162  - input: {
    163  - key: 'createdBy',
    164  - value: value.value || ''
    165  - },
    166  - },
    167  - });
    168  - }
    169  - }
    170  - 
    171  - handleChangeObjectMarking(name, values) {
    172  - const { dataComponent } = this.props;
    173  - const currentMarkingDefinitions = pipe(
    174  - pathOr([], ['objectMarking', 'edges']),
    175  - map((n) => ({
    176  - label: n.node.definition,
    177  - value: n.node.id,
    178  - })),
    179  - )(dataComponent);
    180  - 
    181  - const added = difference(values, currentMarkingDefinitions);
    182  - const removed = difference(currentMarkingDefinitions, values);
    183  - 
    184  - if (added.length > 0) {
    185  - commitMutation({
    186  - mutation: dataComponentMutationRelationAdd,
    187  - variables: {
    188  - id: this.props.dataComponent.id,
    189  - input: {
    190  - toId: head(added).value,
    191  - relationship_type: 'object-marking',
    192  - },
    193  - },
    194  - });
    195  - }
    196  - 
    197  - if (removed.length > 0) {
    198  - commitMutation({
    199  - mutation: dataComponentMutationRelationDelete,
    200  - variables: {
    201  - id: this.props.dataComponent.id,
    202  - toId: head(removed).value,
    203  - relationship_type: 'object-marking',
    204  - },
    205  - });
    206  - }
    207  - }
    208  - 
    209  - render() {
    210  - const {
    211  - t,
    212  - dataComponent,
    213  - context
    214  - } = this.props;
    215  - const createdBy = convertCreatedBy(dataComponent);
    216  - const objectMarking = convertMarkings(dataComponent);
    217  - const status = convertStatus(t, dataComponent);
    218  - const initialValues = pipe(
    219  - assoc('createdBy', createdBy),
    220  - assoc('objectMarking', objectMarking),
    221  - assoc('x_opencti_workflow_id', status),
    222  - pick([
    223  - 'name',
    224  - 'description',
    225  - 'x_mitre_id',
    226  - 'x_opencti_threat_hunting',
    227  - 'x_opencti_log_sources',
    228  - 'createdBy',
    229  - 'killChainPhases',
    230  - 'objectMarking',
    231  - 'x_opencti_workflow_id',
    232  - 'x_mitre_id',
    233  - ]),
    234  - )(dataComponent);
    235  - return (
    236  - <Formik
    237  - enableReinitialize={true}
    238  - initialValues={initialValues}
    239  - validationSchema={dataComponentValidation(t)}
    240  - onSubmit={() => true}
    241  - >
    242  - {({ setFieldValue }) => (
    243  - <Form style={{ margin: '20px 0 20px 0' }}>
    244  - <Field
    245  - component={TextField}
    246  - variant="standard"
    247  - name="name"
    248  - label={t('Name')}
    249  - fullWidth={true}
    250  - onFocus={this.handleChangeFocus.bind(this)}
    251  - onSubmit={this.handleSubmitField.bind(this)}
    252  - helperText={
    253  - <SubscriptionFocus context={context} fieldName="name" />
    254  - }
    255  - />
    256  - <Field
    257  - component={TextField}
    258  - variant="standard"
    259  - name="x_mitre_id"
    260  - label={t('External ID')}
    261  - fullWidth={true}
    262  - style={{ marginTop: 20 }}
    263  - onFocus={this.handleChangeFocus.bind(this)}
    264  - onSubmit={this.handleSubmitField.bind(this)}
    265  - helperText={
    266  - <SubscriptionFocus context={context} fieldName="x_mitre_id" />
    267  - }
    268  - />
    269  - <Field
    270  - component={MarkDownField}
    271  - name="description"
    272  - label={t('Description')}
    273  - fullWidth={true}
    274  - multiline={true}
    275  - rows="4"
    276  - style={{ marginTop: 20 }}
    277  - onFocus={this.handleChangeFocus.bind(this)}
    278  - onSubmit={this.handleSubmitField.bind(this)}
    279  - helperText={
    280  - <SubscriptionFocus context={context} fieldName="description" />
    281  - }
    282  - />
    283  - <Field
    284  - component={MarkDownField}
    285  - name="x_opencti_threat_hunting"
    286  - label={t('Threat hunting techniques')}
    287  - fullWidth={true}
    288  - multiline={true}
    289  - rows="4"
    290  - style={{ marginTop: 20 }}
    291  - onFocus={this.handleChangeFocus.bind(this)}
    292  - onSubmit={this.handleSubmitField.bind(this)}
    293  - helperText={
    294  - <SubscriptionFocus
    295  - context={context}
    296  - fieldName="x_opencti_threat_hunting"
    297  - />
    298  - }
    299  - />
    300  - <Field
    301  - component={TextField}
    302  - variant="standard"
    303  - name="x_opencti_log_sources"
    304  - label={t('Log sources (1 / line)')}
    305  - fullWidth={true}
    306  - multiline={true}
    307  - rows="4"
    308  - style={{ marginTop: 20 }}
    309  - onFocus={this.handleChangeFocus.bind(this)}
    310  - onSubmit={this.handleSubmitField.bind(this)}
    311  - helperText={
    312  - <SubscriptionFocus
    313  - context={context}
    314  - fieldName="x_opencti_log_sources"
    315  - />
    316  - }
    317  - />
    318  - {dataComponent.workflowEnabled && (
    319  - <StatusField
    320  - name="x_opencti_workflow_id"
    321  - type="Course-Of-Action"
    322  - onFocus={this.handleChangeFocus.bind(this)}
    323  - onChange={this.handleSubmitField.bind(this)}
    324  - setFieldValue={setFieldValue}
    325  - style={{ marginTop: 20 }}
    326  - helpertext={
    327  - <SubscriptionFocus
    328  - context={context}
    329  - fieldName="x_opencti_workflow_id"
    330  - />
    331  - }
    332  - />
    333  - )}
    334  - <CreatedByField
    335  - name="createdBy"
    336  - style={{
    337  - marginTop: 20,
    338  - width: '100%'
    339  - }}
    340  - setFieldValue={setFieldValue}
    341  - helpertext={
    342  - <SubscriptionFocus context={context} fieldName="createdBy" />
    343  - }
    344  - onChange={this.handleChangeCreatedBy.bind(this)}
    345  - />
    346  - <ObjectMarkingField
    347  - name="objectMarking"
    348  - style={{
    349  - marginTop: 20,
    350  - width: '100%'
    351  - }}
    352  - helpertext={
    353  - <SubscriptionFocus
    354  - context={context}
    355  - fieldname="objectMarking"
    356  - />
    357  - }
    358  - onChange={this.handleChangeObjectMarking.bind(this)}
    359  - />
    360  - </Form>
    361  - )}
    362  - </Formik>
    363  - );
    364  - }
    365  -}
    366  - 
    367  -DataComponentEditionOverviewComponent.propTypes = {
    368  - classes: PropTypes.object,
    369  - theme: PropTypes.object,
    370  - t: PropTypes.func,
    371  - dataComponent: PropTypes.object,
    372  - context: PropTypes.array,
    373  -};
    374  - 
    375  -const DataComponentEditionOverview = createFragmentContainer(
    376  - DataComponentEditionOverviewComponent,
    377  - {
    378  - dataComponent: graphql`
    379  - fragment DataComponentEditionOverview_dataComponent on DataComponent {
    380  - id
    381  - name
    382  - description
    383  - # x_opencti_threat_hunting
    384  - # x_opencti_log_sources
    385  - # x_mitre_id
    386  - createdBy {
    387  - ... on Identity {
    388  - id
    389  - name
    390  - entity_type
    391  - }
    392  - }
    393  - objectMarking {
    394  - edges {
    395  - node {
    396  - id
    397  - definition
    398  - definition_type
    399  - }
    400  - }
    401  - }
    402  - status {
    403  - id
    404  - order
    405  - template {
    406  - name
    407  - color
    408  - }
    409  - }
    410  - workflowEnabled
    411  - }
    412  - `,
    413  - },
    414  -);
    415  - 
    416  -export default compose(
    417  - inject18n,
    418  - withStyles(styles, { withTheme: true }),
    419  -)(DataComponentEditionOverview);
    420  - 
  • ■ ■ ■ ■ ■ ■
    opencti-platform/opencti-front/src/private/components/techniques/data_components/DataComponentEditionOverview.tsx
     1 +import React, { FunctionComponent } from 'react';
     2 +import { createFragmentContainer, graphql } from 'react-relay';
     3 +import { Field, Form, Formik } from 'formik';
     4 +import { assoc, pick, pipe, } from 'ramda';
     5 +import * as Yup from 'yup';
     6 +import TextField from '../../../../components/TextField';
     7 +import { SubscriptionFocus } from '../../../../components/Subscription';
     8 +import { commitMutation } from '../../../../relay/environment';
     9 +import CreatedByField, { CreatedBy } from '../../common/form/CreatedByField';
     10 +import ObjectMarkingField, { ObjectMarking } from '../../common/form/ObjectMarkingField';
     11 +import MarkDownField from '../../../../components/MarkDownField';
     12 +import { convertCreatedBy, convertMarkings, convertStatus, } from '../../../../utils/Edition';
     13 +import { useFormatter } from '../../../../components/i18n';
     14 +import { DataComponentEditionOverview_dataComponent$data } from './__generated__/DataComponentEditionOverview_dataComponent.graphql';
     15 +import StatusField from '../../common/form/StatusField';
     16 +import CommitMessage from '../../common/form/CommitMessage';
     17 + 
     18 +const dataComponentMutationFieldPatch = graphql`
     19 + mutation DataComponentEditionOverviewFieldPatchMutation(
     20 + $id: ID!
     21 + $input: [EditInput]!
     22 + ) {
     23 + dataComponentFieldPatch(
     24 + id: $id
     25 + input: $input
     26 + ) {
     27 + ...DataComponentEditionOverview_dataComponent
     28 + ...DataComponent_dataComponent
     29 + }
     30 + }
     31 +`;
     32 + 
     33 +export const dataComponentEditionOverviewFocus = graphql`
     34 + mutation DataComponentEditionOverviewFocusMutation($id: ID!, $input: EditContext!) {
     35 + dataComponentContextPatch(id: $id, input: $input) {
     36 + id
     37 + }
     38 + }
     39 +`;
     40 + 
     41 +const dataComponentMutationRelationAdd = graphql`
     42 + mutation DataComponentEditionOverviewRelationAddMutation(
     43 + $id: ID!
     44 + $input: StixMetaRelationshipAddInput!
     45 + ) {
     46 + dataComponentRelationAdd(id: $id, input: $input) {
     47 + from {
     48 + ...DataComponentEditionOverview_dataComponent
     49 + }
     50 + }
     51 + }
     52 +`;
     53 + 
     54 +const dataComponentMutationRelationDelete = graphql`
     55 + mutation DataComponentEditionOverviewRelationDeleteMutation(
     56 + $id: ID!
     57 + $toId: StixRef!
     58 + $relationship_type: String!
     59 + ) {
     60 + dataComponentRelationDelete(
     61 + id: $id
     62 + toId: $toId
     63 + relationship_type: $relationship_type
     64 + ) {
     65 + ...DataComponentEditionOverview_dataComponent
     66 + }
     67 + }
     68 +`;
     69 + 
     70 +const dataComponentValidation = (t: (message: string) => string) => Yup.object()
     71 + .shape({
     72 + name: Yup.string().required(t('This field is required')),
     73 + description: Yup.string()
     74 + .min(3, t('The value is too short'))
     75 + .max(5000, t('The value is too long'))
     76 + .required(t('This field is required')),
     77 + references: Yup.array().required(t('This field is required')),
     78 + x_opencti_workflow_id: Yup.object(),
     79 + });
     80 + 
     81 +interface DataComponentEditionOverviewComponentProps {
     82 + dataComponent: DataComponentEditionOverview_dataComponent$data
     83 + context: ReadonlyArray<{ // TODO: extract
     84 + readonly focusOn: string | null;
     85 + readonly name: string;
     86 + } | null> | null
     87 + enableReferences: boolean,
     88 +}
     89 + 
     90 +const DataComponentEditionOverviewComponent: FunctionComponent<DataComponentEditionOverviewComponentProps> = ({
     91 + dataComponent,
     92 + context,
     93 + enableReferences
     94 +}) => {
     95 + const { t } = useFormatter();
     96 + 
     97 + const handleChangeFocus = (name: string) => {
     98 + commitMutation({
     99 + mutation: dataComponentEditionOverviewFocus,
     100 + variables: {
     101 + id: dataComponent.id,
     102 + input: {
     103 + focusOn: name,
     104 + },
     105 + },
     106 + updater: undefined,
     107 + optimisticUpdater: undefined,
     108 + optimisticResponse: undefined,
     109 + onCompleted: undefined,
     110 + onError: undefined,
     111 + setSubmitting: undefined,
     112 + });
     113 + }
     114 + 
     115 + const handleSubmitField = (name: string, value: any) => { // TODO: find valid type
     116 + let finalValue = value;
     117 + if (name === 'x_opencti_workflow_id') {
     118 + finalValue = value.value;
     119 + }
     120 + dataComponentValidation(t)
     121 + .validateAt(name, { [name]: value })
     122 + .then(() => {
     123 + commitMutation({
     124 + mutation: dataComponentMutationFieldPatch,
     125 + variables: {
     126 + id: dataComponent.id,
     127 + input: {
     128 + key: name,
     129 + value: finalValue ?? ''
     130 + },
     131 + },
     132 + updater: undefined,
     133 + optimisticUpdater: undefined,
     134 + optimisticResponse: undefined,
     135 + onCompleted: undefined,
     136 + onError: undefined,
     137 + setSubmitting: undefined,
     138 + });
     139 + })
     140 + .catch(() => false);
     141 + }
     142 + 
     143 + const handleChangeCreatedBy = (name: string, value: CreatedBy) => {
     144 + commitMutation({
     145 + mutation: dataComponentMutationFieldPatch,
     146 + variables: {
     147 + id: dataComponent.id,
     148 + input: {
     149 + key: 'createdBy',
     150 + value: value.value || ''
     151 + },
     152 + },
     153 + updater: undefined,
     154 + optimisticUpdater: undefined,
     155 + optimisticResponse: undefined,
     156 + onCompleted: undefined,
     157 + onError: undefined,
     158 + setSubmitting: undefined,
     159 + });
     160 + }
     161 + 
     162 + const handleChangeObjectMarking = (name: string, values: ObjectMarking[]) => {
     163 + const currentMarkingDefinitions: ObjectMarking[] = dataComponent?.objectMarking?.edges?.map((n) => ({
     164 + label: n?.node.definition,
     165 + value: n?.node.id,
     166 + color: null,
     167 + entity: null,
     168 + })) || [];
     169 + 
     170 + const added = values.filter(x => currentMarkingDefinitions.includes(x));
     171 + const removed = currentMarkingDefinitions.filter(x => values.includes(x));
     172 + 
     173 + if (added.length > 0) {
     174 + commitMutation({
     175 + mutation: dataComponentMutationRelationAdd,
     176 + variables: {
     177 + id: dataComponent.id,
     178 + input: {
     179 + toId: added[0].value,
     180 + relationship_type: 'object-marking',
     181 + },
     182 + },
     183 + updater: undefined,
     184 + optimisticUpdater: undefined,
     185 + optimisticResponse: undefined,
     186 + onCompleted: undefined,
     187 + onError: undefined,
     188 + setSubmitting: undefined,
     189 + });
     190 + }
     191 + 
     192 + if (removed.length > 0) {
     193 + commitMutation({
     194 + mutation: dataComponentMutationRelationDelete,
     195 + variables: {
     196 + id: dataComponent.id,
     197 + toId: removed[0].value,
     198 + relationship_type: 'object-marking',
     199 + },
     200 + updater: undefined,
     201 + optimisticUpdater: undefined,
     202 + optimisticResponse: undefined,
     203 + onCompleted: undefined,
     204 + onError: undefined,
     205 + setSubmitting: undefined,
     206 + });
     207 + }
     208 + }
     209 + 
     210 + const createdBy = convertCreatedBy(dataComponent);
     211 + const objectMarking = convertMarkings(dataComponent);
     212 + const status = convertStatus(t, dataComponent);
     213 + const initialValues = pipe(
     214 + assoc('createdBy', createdBy),
     215 + assoc('objectMarking', objectMarking),
     216 + assoc('x_opencti_workflow_id', status),
     217 + pick([
     218 + 'name',
     219 + 'description',
     220 + 'createdBy',
     221 + 'objectMarking',
     222 + 'x_opencti_workflow_id',
     223 + ]),
     224 + )(dataComponent);
     225 + return (
     226 + <Formik
     227 + enableReinitialize={true}
     228 + initialValues={initialValues}
     229 + validationSchema={dataComponentValidation(t)}
     230 + onSubmit={() => true} // TODO: fix it
     231 + >
     232 + {({
     233 + submitForm,
     234 + isSubmitting,
     235 + validateForm,
     236 + setFieldValue,
     237 + values,
     238 + }) => (
     239 + <Form style={{ margin: '20px 0 20px 0' }}>
     240 + <Field
     241 + component={TextField}
     242 + variant="standard"
     243 + name="name"
     244 + label={t('Name')}
     245 + fullWidth={true}
     246 + onFocus={handleChangeFocus}
     247 + onSubmit={handleSubmitField}
     248 + helperText={
     249 + <SubscriptionFocus context={context} fieldName="name" />
     250 + }
     251 + />
     252 + <Field
     253 + component={MarkDownField}
     254 + name="description"
     255 + label={t('Description')}
     256 + fullWidth={true}
     257 + multiline={true}
     258 + rows="4"
     259 + style={{ marginTop: 20 }}
     260 + onFocus={handleChangeFocus}
     261 + onSubmit={handleSubmitField}
     262 + helperText={
     263 + <SubscriptionFocus context={context} fieldName="description" />
     264 + }
     265 + />
     266 + {dataComponent.workflowEnabled && (
     267 + <StatusField
     268 + name="x_opencti_workflow_id"
     269 + type="Data-Component"
     270 + onFocus={handleChangeFocus}
     271 + onChange={handleSubmitField}
     272 + setFieldValue={setFieldValue}
     273 + style={{ marginTop: 20 }}
     274 + helpertext={
     275 + <SubscriptionFocus
     276 + context={context}
     277 + fieldName="x_opencti_workflow_id"
     278 + />
     279 + }
     280 + />
     281 + )}
     282 + <CreatedByField
     283 + name="createdBy"
     284 + style={{
     285 + marginTop: 20,
     286 + width: '100%'
     287 + }}
     288 + setFieldValue={setFieldValue}
     289 + helpertext={
     290 + <SubscriptionFocus context={context} fieldName="createdBy" />
     291 + }
     292 + onChange={handleChangeCreatedBy}
     293 + />
     294 + <ObjectMarkingField
     295 + name="objectMarking"
     296 + style={{
     297 + marginTop: 20,
     298 + width: '100%'
     299 + }}
     300 + helpertext={
     301 + <SubscriptionFocus
     302 + context={context}
     303 + fieldname="objectMarking"
     304 + />
     305 + }
     306 + onChange={handleChangeObjectMarking}
     307 + />
     308 + {enableReferences && (
     309 + <CommitMessage
     310 + submitForm={submitForm}
     311 + disabled={isSubmitting}
     312 + validateForm={validateForm}
     313 + setFieldValue={setFieldValue}
     314 + values={values}
     315 + id={dataComponent.id}
     316 + />
     317 + )}
     318 + </Form>
     319 + )}
     320 + </Formik>
     321 + );
     322 +}
     323 + 
     324 +const DataComponentEditionOverview = createFragmentContainer(
     325 + DataComponentEditionOverviewComponent,
     326 + {
     327 + dataComponent: graphql`
     328 + fragment DataComponentEditionOverview_dataComponent on DataComponent {
     329 + id
     330 + name
     331 + description
     332 + createdBy {
     333 + ... on Identity {
     334 + id
     335 + name
     336 + entity_type
     337 + }
     338 + }
     339 + objectMarking {
     340 + edges {
     341 + node {
     342 + id
     343 + definition
     344 + definition_type
     345 + }
     346 + }
     347 + }
     348 + status {
     349 + id
     350 + order
     351 + template {
     352 + name
     353 + color
     354 + }
     355 + }
     356 + workflowEnabled
     357 + }
     358 + `,
     359 + },
     360 +);
     361 + 
     362 +export default DataComponentEditionOverview;
     363 + 
  • ■ ■ ■ ■ ■ ■
    opencti-platform/opencti-front/src/private/components/techniques/data_components/DataComponentKnowledge.js
    1  -import React, { Component } from 'react';
    2  -import PropTypes from 'prop-types';
    3  -import { Route, Switch, withRouter } from 'react-router-dom';
    4  -import { compose } from 'ramda';
    5  -import { graphql, createFragmentContainer } from 'react-relay';
    6  -import withStyles from '@mui/styles/withStyles';
    7  -import inject18n from '../../../../components/i18n';
    8  -import StixCoreRelationship from '../../common/stix_core_relationships/StixCoreRelationship';
    9  -import StixDomainObjectHeader from '../../common/stix_domain_objects/StixDomainObjectHeader';
    10  -import DataComponentPopover from "./DataComponentPopover";
    11  - 
    12  -const styles = () => ({
    13  - container: {
    14  - margin: 0,
    15  - },
    16  -});
    17  - 
    18  -class DataComponentKnowledgeComponent extends Component {
    19  - render() {
    20  - const { classes, dataComponent, enableReferences } = this.props;
    21  - return (
    22  - <div className={classes.container}>
    23  - <StixDomainObjectHeader
    24  - stixDomainObject={dataComponent}
    25  - PopoverComponent={<DataComponentPopover />}
    26  - enableReferences={enableReferences}
    27  - isOpenctiAlias={true}
    28  - />
    29  - <Switch>
    30  - <Route
    31  - exact
    32  - path="/dashboard/techniques/data_component/:dataComponentId/knowledge/relations/:relationId"
    33  - render={(routeProps) => (
    34  - <StixCoreRelationship
    35  - entityId={dataComponent.id}
    36  - {...routeProps}
    37  - />
    38  - )}
    39  - />
    40  - </Switch>
    41  - </div>
    42  - );
    43  - }
    44  -}
    45  - 
    46  -DataComponentKnowledgeComponent.propTypes = {
    47  - dataComponent: PropTypes.object,
    48  - classes: PropTypes.object,
    49  - t: PropTypes.func,
    50  -};
    51  - 
    52  -const DataComponentKnowledge = createFragmentContainer(
    53  - DataComponentKnowledgeComponent,
    54  - {
    55  - dataComponent: graphql`
    56  - fragment DataComponentKnowledge_dataComponent on DataComponent {
    57  - id
    58  - name
    59  -# x_opencti_aliases
    60  - }
    61  - `,
    62  - },
    63  -);
    64  - 
    65  -export default compose(
    66  - inject18n,
    67  - withRouter,
    68  - withStyles(styles),
    69  -)(DataComponentKnowledge);
    70  - 
  • ■ ■ ■ ■ ■ ■
    opencti-platform/opencti-front/src/private/components/techniques/data_components/DataComponentKnowledge.tsx
     1 +import React, { FunctionComponent } from 'react';
     2 +import { Route, Switch } from 'react-router-dom';
     3 +import { createFragmentContainer, graphql } from 'react-relay';
     4 +import StixCoreRelationship from '../../common/stix_core_relationships/StixCoreRelationship';
     5 +import StixDomainObjectHeader from '../../common/stix_domain_objects/StixDomainObjectHeader';
     6 +import DataComponentPopover from './DataComponentPopover';
     7 +import makeStyles from '@mui/styles/makeStyles';
     8 +import { DataComponentKnowledge_dataComponent$data } from './__generated__/DataComponentKnowledge_dataComponent.graphql';
     9 + 
     10 +const styles = makeStyles(() => ({
     11 + container: {
     12 + margin: 0,
     13 + },
     14 +}));
     15 + 
     16 +interface DataComponentKnowledgeComponentProps {
     17 + dataComponent: DataComponentKnowledge_dataComponent$data
     18 + enableReferences: boolean
     19 +}
     20 + 
     21 +const DataComponentKnowledgeComponent: FunctionComponent<DataComponentKnowledgeComponentProps> = ({dataComponent, enableReferences}) => {
     22 + const classes = styles();
     23 + 
     24 + return (
     25 + <div className={classes.container}>
     26 + <StixDomainObjectHeader
     27 + stixDomainObject={dataComponent}
     28 + PopoverComponent={<DataComponentPopover dataComponentId={dataComponent.id}/>}
     29 + enableReferences={enableReferences}
     30 + // isOpenctiAlias={true} // TODO: ask to Samuel
     31 + />
     32 + <Switch>
     33 + <Route
     34 + path="/dashboard/techniques/data_component/:dataComponentId/knowledge/relations/:relationId"
     35 + render={(routeProps) => ( // TODO: fix it
     36 + <StixCoreRelationship
     37 + entityId={dataComponent.id}
     38 + {...routeProps}
     39 + />
     40 + )}
     41 + />
     42 + {/* TODO: other route ? */}
     43 + </Switch>
     44 + </div>
     45 + );
     46 +}
     47 + 
     48 +const DataComponentKnowledge = createFragmentContainer(
     49 + DataComponentKnowledgeComponent,
     50 + {
     51 + dataComponent: graphql`
     52 + fragment DataComponentKnowledge_dataComponent on DataComponent {
     53 + id
     54 + name
     55 + aliases
     56 + }
     57 + `,
     58 + },
     59 +);
     60 + 
     61 +export default DataComponentKnowledge;
     62 + 
  • ■ ■ ■ ■
    opencti-platform/opencti-front/src/private/components/techniques/data_components/DataComponentLine.tsx
    skipped 8 lines
    9 9  import { Theme } from '@mui/material/styles/createTheme';
    10 10  import Skeleton from '@mui/material/Skeleton';
    11 11  import { useFormatter } from '../../../../components/i18n';
     12 +import { DataColumns, PaginationOptions } from '../../../../components/list_lines';
    12 13   
    13 14  const useStyles = makeStyles((theme: Theme) => ({
    14 15   item: {},
    skipped 42 lines
    57 58   name: string
    58 59   description: string
    59 60   }
     61 + dataColumns: DataColumns,
     62 + paginationOptions: PaginationOptions
    60 63  }
    61 64   
    62  -const DataComponentLineComponent: React.FC<DataComponentLineProps> = ({ node }) => {
     65 +const DataComponentLineComponent: React.FC<DataComponentLineProps> = ({ node, dataColumns, paginationOptions }) => {
    63 66   const classes = useStyles();
    64 67   const { t } = useFormatter();
    65 68   
    skipped 64 lines
  • ■ ■ ■ ■ ■ ■
    opencti-platform/opencti-front/src/private/components/techniques/data_components/DataComponentOverview.tsx
    1  -import React from 'react';
     1 +import React, { FunctionComponent } from 'react';
    2 2  import { map, propOr } from 'ramda';
    3  -import { graphql, createFragmentContainer } from 'react-relay';
    4  -import makeStyles from '@mui/styles/makeStyles';
     3 +import { createFragmentContainer, graphql } from 'react-relay';
    5 4  import Paper from '@mui/material/Paper';
    6 5  import Typography from '@mui/material/Typography';
    7 6  import { useFormatter } from '../../../../components/i18n';
    8 7  import ItemAuthor from '../../../../components/ItemAuthor';
    9 8  import ItemMarking from '../../../../components/ItemMarking';
    10 9  import ExpandableMarkdown from '../../../../components/ExpandableMarkdown';
    11  -import { DataComponentOverview_dataComponent$data } from './__generated__/DataComponentOverview_dataComponent.graphql';
     10 +import makeStyles from '@mui/styles/makeStyles';
    12 11   
    13  -const useStyles = makeStyles(() => ({
     12 +const styles = makeStyles(() => ({
    14 13   paper: {
    15 14   height: '100%',
    16 15   minHeight: '100%',
    skipped 3 lines
    20 19   },
    21 20  }));
    22 21   
    23  -interface DataComponentOverviewProps {
    24  - dataComponent: DataComponentOverview_dataComponent$data,
     22 +interface DataComponentOverviewComponentProps {
     23 + dataComponent: any
    25 24  }
    26 25   
    27  -const DataComponentOverviewComponent: React.FC<DataComponentOverviewProps> = ({ dataComponent }) => {
    28  - const classes = useStyles();
     26 +const DataComponentOverviewComponent: FunctionComponent<DataComponentOverviewComponentProps> = ({ dataComponent }) => {
    29 27   const { t, fldt } = useFormatter();
     28 + const classes = styles();
     29 + 
    30 30   return (
    31  - <div style={{ height: '100%' }} className="break">
    32  - <Typography variant="h4" gutterBottom={true}>
    33  - {t('Information')}
     31 + <div style={{ height: '100%' }} className="break">
     32 + <Typography variant="h4" gutterBottom={true}>
     33 + {t('Information')}
     34 + </Typography>
     35 + <Paper classes={{ root: classes.paper }} variant="outlined">
     36 + <Typography variant="h3" gutterBottom={true}>
     37 + {t('Marking')}
    34 38   </Typography>
    35  - <Paper classes={{ root: classes.paper }} variant="outlined">
    36  - <Typography variant="h3" gutterBottom={true}>
    37  - {t('Marking')}
    38  - </Typography>
    39  - {dataComponent.objectMarking.edges.length > 0 ? (
    40  - map(
    41  - (markingDefinition) => (
    42  - <ItemMarking
    43  - key={markingDefinition.node.id}
    44  - label={markingDefinition.node.definition}
    45  - />
    46  - ),
    47  - dataComponent.objectMarking.edges,
    48  - )
    49  - ) : (
    50  - <ItemMarking label="TLP:CLEAR" />
    51  - )}
    52  - <Typography
    53  - variant="h3"
    54  - gutterBottom={true}
    55  - style={{ marginTop: 20 }}
    56  - >
    57  - {t('Creation date')}
    58  - </Typography>
    59  - {fldt(dataComponent.created)}
    60  - <Typography
    61  - variant="h3"
    62  - gutterBottom={true}
    63  - style={{ marginTop: 20 }}
    64  - >
    65  - {t('Modification date')}
    66  - </Typography>
    67  - {fldt(dataComponent.modified)}
    68  - <Typography
    69  - variant="h3"
    70  - gutterBottom={true}
    71  - style={{ marginTop: 20 }}
    72  - >
    73  - {t('Author')}
    74  - </Typography>
    75  - <ItemAuthor createdBy={propOr(null, 'createdBy', dataComponent)} />
    76  - <Typography
    77  - variant="h3"
    78  - gutterBottom={true}
    79  - style={{ marginTop: 20 }}
    80  - >
    81  - {t('Description')}
    82  - </Typography>
    83  - <ExpandableMarkdown
    84  - className="markdown"
    85  - source={dataComponent.description}
    86  - limit={250}
    87  - />
    88  - </Paper>
    89  - </div>
     39 + {dataComponent.objectMarking.edges.length > 0 ? (
     40 + map(
     41 + (markingDefinition) => (
     42 + <ItemMarking
     43 + key={markingDefinition.node.id}
     44 + label={markingDefinition.node.definition}
     45 + />
     46 + ),
     47 + dataComponent.objectMarking.edges,
     48 + )
     49 + ) : (
     50 + <ItemMarking label="TLP:CLEAR" />
     51 + )}
     52 + <Typography
     53 + variant="h3"
     54 + gutterBottom={true}
     55 + style={{ marginTop: 20 }}
     56 + >
     57 + {t('Creation date')}
     58 + </Typography>
     59 + {fldt(dataComponent.created)}
     60 + <Typography
     61 + variant="h3"
     62 + gutterBottom={true}
     63 + style={{ marginTop: 20 }}
     64 + >
     65 + {t('Modification date')}
     66 + </Typography>
     67 + {fldt(dataComponent.modified)}
     68 + <Typography
     69 + variant="h3"
     70 + gutterBottom={true}
     71 + style={{ marginTop: 20 }}
     72 + >
     73 + {t('Author')}
     74 + </Typography>
     75 + <ItemAuthor createdBy={propOr(null, 'createdBy', dataComponent)} />
     76 + <Typography
     77 + variant="h3"
     78 + gutterBottom={true}
     79 + style={{ marginTop: 20 }}
     80 + >
     81 + {t('Description')}
     82 + </Typography>
     83 + <ExpandableMarkdown
     84 + className="markdown"
     85 + source={dataComponent.description}
     86 + limit={250}
     87 + />
     88 + </Paper>
     89 + </div>
    90 90   );
    91  -};
     91 +}
    92 92   
    93 93  const DataComponentOverview = createFragmentContainer(
    94 94   DataComponentOverviewComponent,
    skipped 25 lines
    120 120   },
    121 121  );
    122 122   
     123 +export default DataComponentOverview;
     124 + 
Please wait...
Page is in error, reload to recover