Skip to content

Commit

Permalink
[Frontend] New Datatables :)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kedae committed May 17, 2024
1 parent 08c0c70 commit 62d7e06
Show file tree
Hide file tree
Showing 36 changed files with 4,972 additions and 2,587 deletions.
1 change: 1 addition & 0 deletions opencti-platform/opencti-front/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ module.exports = {
'custom-rules',
],
rules: {
'@typescript-eslint/no-non-null-assertion': 'off',
'custom-rules/classes-rule': 1,
'no-restricted-syntax': 0,
'react/no-unused-prop-types': 0,
Expand Down
3 changes: 3 additions & 0 deletions opencti-platform/opencti-front/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@rjsf/core": "5.18.1",
"@rjsf/mui": "5.18.1",
"@rjsf/utils": "5.18.1",
"@types/react-beautiful-dnd": "^13.1.8",
"analytics": "0.8.11",
"apexcharts": "3.48.0",
"axios": "1.6.8",
Expand Down Expand Up @@ -52,10 +53,12 @@
"ramda": "0.29.1",
"react": "18.2.0",
"react-apexcharts": "1.4.1",
"react-beautiful-dnd": "13.1.1",
"react-color": "2.19.3",
"react-cookie": "7.1.4",
"react-csv": "2.2.2",
"react-dom": "18.2.0",
"react-draggable": "4.4.6",
"react-force-graph-2d": "1.25.4",
"react-force-graph-3d": "1.24.2",
"react-grid-layout": "1.4.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import { handleFilterHelpers } from '../utils/hooks/useLocalStorage';
import { filterValuesContentQuery } from './FilterValuesContent';
import { FilterValuesContentQuery } from './__generated__/FilterValuesContentQuery.graphql';

interface FilterIconButtonProps {
availableFilterKeys?: string[];
export interface FilterIconButtonProps {
availableFilterKeys?: string[] | undefined;
filters?: FilterGroup;
handleRemoveFilter?: (key: string, op?: string) => void;
handleSwitchGlobalMode?: () => void;
Expand All @@ -20,7 +20,7 @@ interface FilterIconButtonProps {
disabledPossible?: boolean;
redirection?: boolean;
helpers?: handleFilterHelpers;
availableRelationFilterTypes?: Record<string, string[]>;
availableRelationFilterTypes?: Record<string, string[]> | undefined;
entityTypes?: string[];
filtersRestrictions?: FiltersRestrictions;
searchContext?: FilterSearchContext
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ const StyledBadge = styled(Badge)(() => ({
},
}));

const ItemMarkings = ({ variant, markingDefinitions, limit }) => {
const ItemMarkings = ({ variant, markingDefinitions, limit, handleAddFilter }) => {
const markings = markingDefinitions ?? [];
const classes = useStyles();
const theme = useTheme();
Expand Down Expand Up @@ -134,6 +134,11 @@ const ItemMarkings = ({ variant, markingDefinitions, limit }) => {
border,
}}
label={markingDefinition.definition}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
handleAddFilter('objectMarking', markingDefinition.id);
}}
/>
);
}
Expand Down Expand Up @@ -238,6 +243,7 @@ const ItemMarkings = ({ variant, markingDefinitions, limit }) => {
ItemMarkings.propTypes = {
variant: PropTypes.string,
limit: PropTypes.number,
handleAddFilter: PropTypes.func,
};

export default ItemMarkings;
19 changes: 17 additions & 2 deletions opencti-platform/opencti-front/src/components/ItemStatus.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,30 @@ const styles = () => ({
borderRadius: 4,
width: 80,
},
chipInline: {
fontSize: 12,
lineHeight: '10px',
height: 20,
float: 'left',
textTransform: 'uppercase',
borderRadius: 4,
},
});

const ItemStatus = (props) => {
const { classes, t, status, variant, disabled } = props;
const style = variant === 'inList' ? classes.chipInList : classes.chip;
const { classes, t, status, variant, disabled, onClick } = props;
let style = classes.chip;
if (variant === 'inList') {
style = classes.chipInList;
} else if (variant === 'inLine') {
style = classes.chipInline;
}
if (status && status.template) {
return (
<Chip
classes={{ root: style }}
variant="outlined"
onClick={onClick}
label={status.template.name}
style={{
color: status.template.color,
Expand All @@ -55,6 +69,7 @@ const ItemStatus = (props) => {

ItemStatus.propTypes = {
classes: PropTypes.object.isRequired,
onClick: PropTypes.func,
status: PropTypes.object,
variant: PropTypes.string,
t: PropTypes.func,
Expand Down
185 changes: 185 additions & 0 deletions opencti-platform/opencti-front/src/components/dataGrid/DataTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import React from 'react';
import { useSettingsMessagesBannerHeight } from '@components/settings/settings_messages/SettingsMessagesBanner';
import * as R from 'ramda';
import DataTableToolBar from '@components/data/DataTableToolBar';
import makeStyles from '@mui/styles/makeStyles';
import { OperationType } from 'relay-runtime';
import DataTableFilters, { DataTableDisplayFilters } from './DataTableFilters';
import SearchInput from '../SearchInput';
import type { DataTableProps } from './dataTableTypes';
import { usePaginationLocalStorage } from '../../utils/hooks/useLocalStorage';
import useAuth from '../../utils/hooks/useAuth';
import { useComputeLink, useDataCellHelpers, useDataTable, useDataTableLocalStorage, useDataTableToggle, useLineData } from './dataTableHooks';
import DataTableComponent from './DataTableComponent';
import { useFormatter } from '../i18n';
import { SELECT_COLUMN_SIZE } from './DataTableHeader';
import type { Theme } from '../Theme';
import { getDefaultFilterObject } from '../../utils/filters/filtersUtils';
import { UsePreloadedPaginationFragment } from '../../utils/hooks/usePreloadedPaginationFragment';
import { FilterIconButtonProps } from '../FilterIconButton';
import { DataTableVariant } from './dataTableTypes';

type OCTIDataTableProps = Pick<DataTableProps, 'dataColumns'
| 'resolvePath'
| 'storageKey'
| 'initialValues'
| 'parametersWithPadding'
| 'toolbarFilters'
| 'lineFragment'
| 'availableFilterKeys'
| 'redirectionModeEnabled'
| 'additionalFilterKeys'
| 'variant'
| 'entityTypes'> & {
preloadedPaginationProps: UsePreloadedPaginationFragment<OperationType>,
availableRelationFilterTypes?: FilterIconButtonProps['availableRelationFilterTypes']
availableEntityTypes?: string[]
availableRelationshipTypes?: string[]
searchContextFinal?: { entityTypes: string[]; elementId?: string[] | undefined; } | undefined
filterExportContext?: { entity_type?: string, entity_id?: string }
additionalHeaderButtons?: React.ReactNode
currentView?: string
};

const useStyles = makeStyles<Theme>((theme) => ({
toolbar: {
background: theme.palette.background.paper,
width: `calc(( var(--header-table-size) - ${SELECT_COLUMN_SIZE} ) * 1px)`,
},
}));
const DataTable = (props: OCTIDataTableProps) => {
const { schema } = useAuth();
const classes = useStyles();
const formatter = useFormatter();

const {
storageKey,
initialValues,
availableFilterKeys: defaultAvailableFilterKeys,
searchContextFinal,
availableEntityTypes,
availableRelationshipTypes,
availableRelationFilterTypes,
preloadedPaginationProps: dataQueryArgs,
additionalFilterKeys,
lineFragment,
filterExportContext,
entityTypes,
toolbarFilters,
variant = DataTableVariant.default,
additionalHeaderButtons,
currentView,
} = props;

const {
viewStorage: {
searchTerm,
redirectionMode,
numberOfElements,
sortBy,
orderAsc,
},
helpers,
paginationOptions,
} = usePaginationLocalStorage(storageKey, initialValues!, variant !== DataTableVariant.default);

const settingsMessagesBannerHeight = useSettingsMessagesBannerHeight();

const computedEntityTypes = entityTypes ?? (filterExportContext?.entity_type ? [filterExportContext.entity_type] : []);
let availableFilterKeys = defaultAvailableFilterKeys ?? [];
if (availableFilterKeys.length === 0 && computedEntityTypes) {
const filterKeysMap = new Map();
computedEntityTypes.forEach((entityType: string) => {
const currentMap = schema.filterKeysSchema.get(entityType);
currentMap?.forEach((value, key) => filterKeysMap.set(key, value));
});
availableFilterKeys = R.uniq(Array.from(filterKeysMap.keys())); // keys of the entity type if availableFilterKeys is not specified
}
if (additionalFilterKeys) {
availableFilterKeys = availableFilterKeys.concat(additionalFilterKeys);
}

const {
selectedElements,
deSelectedElements,
numberOfSelectedElements,
selectAll,
handleClearSelectedElements,
} = useDataTableToggle(storageKey);

return (
<DataTableComponent
{...props}
availableFilterKeys={availableFilterKeys}
dataQueryArgs={dataQueryArgs}
useLineData={useLineData(lineFragment!)}
useDataTable={useDataTable}
useDataCellHelpers={useDataCellHelpers(helpers, variant)}
useDataTableToggle={useDataTableToggle}
useComputeLink={useComputeLink}
useDataTableLocalStorage={useDataTableLocalStorage}
onAddFilter={(id) => helpers.handleAddFilterWithEmptyValue(getDefaultFilterObject(id))}
formatter={formatter}
settingsMessagesBannerHeight={settingsMessagesBannerHeight}
storageHelpers={helpers}
redirectionMode={redirectionMode}
numberOfElements={numberOfElements}
onSort={helpers.handleSort}
sortBy={sortBy}
orderAsc={orderAsc}
filtersComponent={(
<>
<div
style={{
display: 'flex',
...(variant === DataTableVariant.default ? { marginTop: -10 } : { marginTop: 10, marginLeft: 10 }),
}}
>
<SearchInput
variant={'small'}
onSubmit={helpers.handleSearch}
keyword={searchTerm}
/>
<DataTableFilters
availableFilterKeys={availableFilterKeys}
searchContextFinal={searchContextFinal}
availableEntityTypes={availableEntityTypes}
availableRelationshipTypes={availableRelationshipTypes}
availableRelationFilterTypes={availableRelationFilterTypes}
filterExportContext={filterExportContext}
paginationOptions={paginationOptions}
additionalHeaderButtons={additionalHeaderButtons}
currentView={currentView}
/>
</div>
<DataTableDisplayFilters
availableFilterKeys={availableFilterKeys}
availableRelationFilterTypes={availableRelationFilterTypes}
additionalFilterKeys={additionalFilterKeys}
entityTypes={computedEntityTypes}
paginationOptions={paginationOptions}
/>
</>
)}
dataTableToolBarComponent={(
<>
<div
className={classes.toolbar}
>
<DataTableToolBar
selectedElements={selectedElements}
deSelectedElements={deSelectedElements}
numberOfSelectedElements={numberOfSelectedElements}
selectAll={selectAll}
search={searchTerm}
filters={toolbarFilters}
handleClearSelectedElements={handleClearSelectedElements}
/>
</div>
</>
)}
/>
);
};

export default DataTable;
Loading

0 comments on commit 62d7e06

Please sign in to comment.