From c3c5ef3e05e9c1369e1e3f17d940b1aff6ced380 Mon Sep 17 00:00:00 2001 From: Bonsai8863 <131906254+Bonsai8863@users.noreply.github.com> Date: Thu, 20 Jun 2024 12:43:07 -0400 Subject: [PATCH] [frontend] Add page titles to Settings pages Revert WIP conversion of Sectors test commit Fix paginationOptions issue for Groups, KillChainPhases, Roles Fix MarkingDefinitions, update KillChainPhases to reflect master Remove changes established in PR #7753 Add Malwares.tsx to removed changes Post-rebase cleanup Remove changes from PR 7753 Remove outdated changes to KillChainPhases Fix translations Align GroupLine design with master Fix typing on GroupLines; --- .../opencti-front/lang/front/de.json | 4 + .../opencti-front/lang/front/en.json | 4 + .../opencti-front/lang/front/es.json | 4 + .../opencti-front/lang/front/fr.json | 4 + .../opencti-front/lang/front/ja.json | 4 + .../opencti-front/lang/front/ko.json | 4 + .../opencti-front/lang/front/zh.json | 4 + .../settings/{Groups.jsx => Groups.tsx} | 135 +++---- .../settings/MarkingDefinitions.jsx | 142 -------- .../settings/MarkingDefinitions.tsx | 134 +++++++ .../src/private/components/settings/Roles.jsx | 134 ------- .../src/private/components/settings/Roles.tsx | 131 +++++++ .../private/components/settings/Sessions.jsx | 111 +++--- .../components/settings/SessionsList.jsx | 328 ++++++++---------- .../settings/groups/GroupsLines.tsx | 5 +- 15 files changed, 553 insertions(+), 595 deletions(-) rename opencti-platform/opencti-front/src/private/components/settings/{Groups.jsx => Groups.tsx} (50%) delete mode 100644 opencti-platform/opencti-front/src/private/components/settings/MarkingDefinitions.jsx create mode 100644 opencti-platform/opencti-front/src/private/components/settings/MarkingDefinitions.tsx delete mode 100644 opencti-platform/opencti-front/src/private/components/settings/Roles.jsx create mode 100644 opencti-platform/opencti-front/src/private/components/settings/Roles.tsx diff --git a/opencti-platform/opencti-front/lang/front/de.json b/opencti-platform/opencti-front/lang/front/de.json index 7d260d41bad5e..3906a5f3bbe19 100644 --- a/opencti-platform/opencti-front/lang/front/de.json +++ b/opencti-platform/opencti-front/lang/front/de.json @@ -2326,6 +2326,10 @@ "Sectors": "Sektoren", "Sectors and organizations": "Sektoren und Organisationen", "Security": "Sicherheit", + "Security: Groups | Settings": "Sicherheit: Gruppen | Einstellungen", + "Security: Marking Definitions | Settings": "Sicherheit: Markierungsdefinitionen | Einstellungen", + "Security: Roles | Settings": "Sicherheit: Rollen | Einstellungen", + "Security: Sessions | Settings": "Sicherheit: Sitzungen | Einstellungen", "See all entities created by user": "Alle vom Benutzer erstellten Entitäten anzeigen", "See all relationships created by user": "Alle vom Benutzer erstellten Beziehungen anzeigen", "Select": "Wählen Sie", diff --git a/opencti-platform/opencti-front/lang/front/en.json b/opencti-platform/opencti-front/lang/front/en.json index 7161031945a12..abef50018356c 100644 --- a/opencti-platform/opencti-front/lang/front/en.json +++ b/opencti-platform/opencti-front/lang/front/en.json @@ -2326,6 +2326,10 @@ "Sectors": "Sectors", "Sectors and organizations": "Sectors and organizations", "Security": "Security", + "Security: Groups | Settings": "Security: Groups | Settings", + "Security: Marking Definitions | Settings": "Security: Marking Definitions | Settings", + "Security: Roles | Settings": "Security: Roles | Settings", + "Security: Sessions | Settings": "Security: Sessions | Settings", "See all entities created by user": "See all entities created by user", "See all relationships created by user": "See all relationships created by user", "Select": "Select", diff --git a/opencti-platform/opencti-front/lang/front/es.json b/opencti-platform/opencti-front/lang/front/es.json index 275937f3efd44..4ec68a6798a32 100644 --- a/opencti-platform/opencti-front/lang/front/es.json +++ b/opencti-platform/opencti-front/lang/front/es.json @@ -2326,6 +2326,10 @@ "Sectors": "Sectores", "Sectors and organizations": "Sectores y organizaciones", "Security": "Seguridad", + "Security: Groups | Settings": "Seguridad: Grupos | Configuración", + "Security: Marking Definitions | Settings": "Seguridad: Definiciones de marcado | Configuración", + "Security: Roles | Settings": "Seguridad: Roles | Configuración", + "Security: Sessions | Settings": "Seguridad: Sesiones | Configuración", "See all entities created by user": "Ver todas las entidades creadas por el usuario", "See all relationships created by user": "Ver todas las relaciones creadas por el usuario", "Select": "Seleccione", diff --git a/opencti-platform/opencti-front/lang/front/fr.json b/opencti-platform/opencti-front/lang/front/fr.json index ea7a0e50058e8..5bdeab7324566 100644 --- a/opencti-platform/opencti-front/lang/front/fr.json +++ b/opencti-platform/opencti-front/lang/front/fr.json @@ -2326,6 +2326,10 @@ "Sectors": "Secteurs", "Sectors and organizations": "Secteurs et organisations", "Security": "Sécurité", + "Security: Groups | Settings": "Sécurité : Groupes | Paramètres", + "Security: Marking Definitions | Settings": "Sécurité : définitions de marquage | Paramètres", + "Security: Roles | Settings": "Sécurité : Rôles | Paramètres", + "Security: Sessions | Settings": "Sécurité : Sessions | Paramètres", "See all entities created by user": "Voir toutes les entités crées par l'utilisateur", "See all relationships created by user": "Voir toutes les relations crées par l'utilisateur", "Select": "Sélectionnez", diff --git a/opencti-platform/opencti-front/lang/front/ja.json b/opencti-platform/opencti-front/lang/front/ja.json index 7b13e72356777..154a23a54333a 100644 --- a/opencti-platform/opencti-front/lang/front/ja.json +++ b/opencti-platform/opencti-front/lang/front/ja.json @@ -2326,6 +2326,10 @@ "Sectors": "セクター", "Sectors and organizations": "セクターと組織", "Security": "安全", + "Security: Groups | Settings": "セキュリティ:グループ|設定", + "Security: Marking Definitions | Settings": "セキュリティ:マーキング定義|設定", + "Security: Roles | Settings": "セキュリティ:ロール|設定", + "Security: Sessions | Settings": "セキュリティ:セッション|設定", "See all entities created by user": "ユーザーが作成したすべてのエンティティを見る", "See all relationships created by user": "ユーザーが作成したすべての関係を見る", "Select": "選択する", diff --git a/opencti-platform/opencti-front/lang/front/ko.json b/opencti-platform/opencti-front/lang/front/ko.json index 4623f77e88aa0..c60265ab8e720 100644 --- a/opencti-platform/opencti-front/lang/front/ko.json +++ b/opencti-platform/opencti-front/lang/front/ko.json @@ -2326,6 +2326,10 @@ "Sectors": "부문", "Sectors and organizations": "부문 및 조직", "Security": "보안", + "Security: Groups | Settings": "보안: 그룹 | 설정", + "Security: Marking Definitions | Settings": "보안: 정의 표시 | 설정", + "Security: Roles | Settings": "보안: 역할 | 설정", + "Security: Sessions | Settings": "보안: 세션 | 설정", "See all entities created by user": "사용자가 만든 모든 엔터티 보기", "See all relationships created by user": "사용자가 만든 모든 관계 보기", "Select": "선택", diff --git a/opencti-platform/opencti-front/lang/front/zh.json b/opencti-platform/opencti-front/lang/front/zh.json index a1ccce25ac007..cd0c2841624b5 100644 --- a/opencti-platform/opencti-front/lang/front/zh.json +++ b/opencti-platform/opencti-front/lang/front/zh.json @@ -2326,6 +2326,10 @@ "Sectors": "部门", "Sectors and organizations": "部门和组织", "Security": "安全", + "Security: Groups | Settings": "安全:组|设置", + "Security: Marking Definitions | Settings": "安全性:标记定义|设置", + "Security: Roles | Settings": "安全:角色|设置", + "Security: Sessions | Settings": "安全:会话|设置", "See all entities created by user": "查看用户创建的所有实体", "See all relationships created by user": "查看用户创建的所有关系", "Select": "选择", diff --git a/opencti-platform/opencti-front/src/private/components/settings/Groups.jsx b/opencti-platform/opencti-front/src/private/components/settings/Groups.tsx similarity index 50% rename from opencti-platform/opencti-front/src/private/components/settings/Groups.jsx rename to opencti-platform/opencti-front/src/private/components/settings/Groups.tsx index f1b28a00fa28f..64d72f8db10a5 100644 --- a/opencti-platform/opencti-front/src/private/components/settings/Groups.jsx +++ b/opencti-platform/opencti-front/src/private/components/settings/Groups.tsx @@ -1,17 +1,26 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose, propOr } from 'ramda'; -import withStyles from '@mui/styles/withStyles'; +import React, { useState, useEffect } from 'react'; +import makeStyles from '@mui/styles/makeStyles'; import { graphql } from 'react-relay'; -import { QueryRenderer } from '../../../relay/environment'; +import { useLocation, useNavigate } from 'react-router-dom'; import { buildViewParamsFromUrlAndStorage, saveViewParameters } from '../../../utils/ListParameters'; -import inject18n from '../../../components/i18n'; +import type { Theme } from '../../../components/Theme'; +import { useFormatter } from '../../../components/i18n'; import ListLines from '../../../components/list_lines/ListLines'; import GroupsLines, { groupsLinesQuery } from './groups/GroupsLines'; import GroupCreation from './groups/GroupCreation'; -import AccessesMenu from './AccessesMenu'; +import { OrderMode, PaginationOptions } from '../../../components/list_lines'; import Breadcrumbs from '../../../components/Breadcrumbs'; -import withRouter from '../../../utils/compat_router/withRouter'; +import useConnectedDocumentModifier from '../../../utils/hooks/useConnectedDocumentModifier'; +import { GroupsLinesPaginationQuery$data } from './groups/__generated__/GroupsLinesPaginationQuery.graphql'; +import AccessesMenu from './AccessesMenu'; +import { QueryRenderer } from '../../../relay/environment'; + +const useStyles = makeStyles(() => ({ + container: { + margin: 0, + padding: '0 200px 50px 0', + }, +})); export const groupsSearchQuery = graphql` query GroupsSearchQuery($search: String) { @@ -40,49 +49,51 @@ export const groupsSearchQuery = graphql` } `; -const styles = () => ({ - container: { - margin: 0, - padding: '0 200px 50px 0', - }, -}); - const LOCAL_STORAGE_KEY = 'groups'; -class Groups extends Component { - constructor(props) { - super(props); - const params = buildViewParamsFromUrlAndStorage( - props.navigate, - props.location, - LOCAL_STORAGE_KEY, - ); - this.state = { - sortBy: propOr('name', 'sortBy', params), - orderAsc: propOr(true, 'orderAsc', params), - searchTerm: propOr('', 'searchTerm', params), - view: propOr('lines', 'view', params), - }; - } - saveView() { +const Groups = () => { + const classes = useStyles(); + const { t_i18n } = useFormatter(); + const navigate = useNavigate(); + const location = useLocation(); + const { setTitle } = useConnectedDocumentModifier(); + setTitle(t_i18n('Security: Groups | Settings')); + const params = buildViewParamsFromUrlAndStorage( + navigate, + location, + LOCAL_STORAGE_KEY, + ); + + const [groupState, setGroupState] = useState<{ orderAsc: boolean, searchTerm: string, view: string, sortBy: string }>({ + sortBy: params.sortBy ?? 'name', + orderAsc: params.orderAsc !== false, + searchTerm: params.searchTerm ?? '', + view: params.view ?? 'lines', + }); + + function saveView() { saveViewParameters( - this.props.navigate, - this.props.location, + navigate, + location, LOCAL_STORAGE_KEY, - this.state, + groupState, ); } - handleSearch(value) { - this.setState({ searchTerm: value }, () => this.saveView()); + function handleSearch(value: string) { + setGroupState({ ...groupState, searchTerm: value }); } - handleSort(field, orderAsc) { - this.setState({ sortBy: field, orderAsc }, () => this.saveView()); + function handleSort(field: string, orderAsc: boolean) { + setGroupState({ ...groupState, sortBy: field, orderAsc }); } - renderLines(paginationOptions) { - const { sortBy, orderAsc, searchTerm } = this.state; + useEffect(() => { + saveView(); + }, [groupState]); + + function renderLines(paginationOptions: PaginationOptions) { + const { sortBy, orderAsc, searchTerm } = groupState; const dataColumns = { name: { label: 'Name', @@ -125,8 +136,8 @@ class Groups extends Component { sortBy={sortBy} orderAsc={orderAsc} dataColumns={dataColumns} - handleSort={this.handleSort.bind(this)} - handleSearch={this.handleSearch.bind(this)} + handleSort={handleSort} + handleSearch={handleSearch} displayImport={false} secondaryAction={false} keyword={searchTerm} @@ -134,7 +145,7 @@ class Groups extends Component { ( + render={({ props }: { props: GroupsLinesPaginationQuery$data }) => ( - - - {view === 'lines' ? this.renderLines(paginationOptions) : ''} - - - ); - } -} + const paginationOptions: PaginationOptions = { + search: groupState.searchTerm, + orderBy: groupState.sortBy ? groupState.sortBy : null, + orderMode: groupState.orderAsc ? OrderMode.asc : OrderMode.desc, + }; -Groups.propTypes = { - t: PropTypes.func, - classes: PropTypes.object, - navigate: PropTypes.func, - location: PropTypes.object, + return ( +
+ + + {groupState.view === 'lines' ? renderLines(paginationOptions) : ''} + +
+ ); }; -export default compose(inject18n, withRouter, withStyles(styles))(Groups); +export default Groups; diff --git a/opencti-platform/opencti-front/src/private/components/settings/MarkingDefinitions.jsx b/opencti-platform/opencti-front/src/private/components/settings/MarkingDefinitions.jsx deleted file mode 100644 index 12f6dc28d5bc2..0000000000000 --- a/opencti-platform/opencti-front/src/private/components/settings/MarkingDefinitions.jsx +++ /dev/null @@ -1,142 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose, propOr } from 'ramda'; -import withStyles from '@mui/styles/withStyles'; -import { QueryRenderer } from '../../../relay/environment'; -import { buildViewParamsFromUrlAndStorage, saveViewParameters } from '../../../utils/ListParameters'; -import inject18n from '../../../components/i18n'; -import ListLines from '../../../components/list_lines/ListLines'; -import MarkingDefinitionsLines, { markingDefinitionsLinesQuery } from './marking_definitions/MarkingDefinitionsLines'; -import MarkingDefinitionCreation from './marking_definitions/MarkingDefinitionCreation'; -import AccessesMenu from './AccessesMenu'; -import withRouter from '../../../utils/compat_router/withRouter'; -import Breadcrumbs from '../../../components/Breadcrumbs'; - -const styles = () => ({ - container: { - margin: 0, - padding: '0 200px 0 0', - }, -}); - -const LOCAL_STORAGE_KEY = 'MarkingDefinitions'; -class MarkingDefinitions extends Component { - constructor(props) { - super(props); - const params = buildViewParamsFromUrlAndStorage( - props.navigate, - props.location, - LOCAL_STORAGE_KEY, - ); - this.state = { - sortBy: propOr('definition', 'sortBy', params), - orderAsc: propOr(true, 'orderAsc', params), - searchTerm: propOr('', 'searchTerm', params), - view: propOr('lines', 'view', params), - }; - } - - saveView() { - saveViewParameters( - this.props.navigate, - this.props.location, - LOCAL_STORAGE_KEY, - this.state, - ); - } - - handleSearch(value) { - this.setState({ searchTerm: value }, () => this.saveView()); - } - - handleSort(field, orderAsc) { - this.setState({ sortBy: field, orderAsc }, () => this.saveView()); - } - - renderLines(paginationOptions) { - const { sortBy, orderAsc, searchTerm } = this.state; - const dataColumns = { - definition_type: { - label: 'Type', - width: '25%', - isSortable: true, - }, - definition: { - label: 'Definition', - width: '25%', - isSortable: true, - }, - x_opencti_color: { - label: 'Color', - width: '15%', - isSortable: true, - }, - x_opencti_order: { - label: 'Order', - width: '10%', - isSortable: true, - }, - created: { - label: 'Original creation date', - width: '15%', - isSortable: true, - }, - }; - return ( - - ( - - )} - /> - - ); - } - - render() { - const { t, classes } = this.props; - const { view, sortBy, orderAsc, searchTerm } = this.state; - const paginationOptions = { - search: searchTerm, - orderBy: sortBy, - orderMode: orderAsc ? 'asc' : 'desc', - }; - return ( -
- - - {view === 'lines' ? this.renderLines(paginationOptions) : ''} - -
- ); - } -} - -MarkingDefinitions.propTypes = { - t: PropTypes.func, - classes: PropTypes.object, - navigate: PropTypes.func, - location: PropTypes.object, -}; - -export default compose( - inject18n, - withRouter, - withStyles(styles), -)(MarkingDefinitions); diff --git a/opencti-platform/opencti-front/src/private/components/settings/MarkingDefinitions.tsx b/opencti-platform/opencti-front/src/private/components/settings/MarkingDefinitions.tsx new file mode 100644 index 0000000000000..74be8fc5b2232 --- /dev/null +++ b/opencti-platform/opencti-front/src/private/components/settings/MarkingDefinitions.tsx @@ -0,0 +1,134 @@ +import React, { useEffect, useState } from 'react'; +import { useLocation, useNavigate } from 'react-router-dom'; +import { useFormatter } from '../../../components/i18n'; +import { buildViewParamsFromUrlAndStorage, saveViewParameters } from '../../../utils/ListParameters'; +import ListLines from '../../../components/list_lines/ListLines'; +import MarkingDefinitionsLines, { markingDefinitionsLinesQuery } from './marking_definitions/MarkingDefinitionsLines'; +import AccessesMenu from './AccessesMenu'; +import { OrderMode, PaginationOptions } from '../../../components/list_lines'; +import MarkingDefinitionCreation from './marking_definitions/MarkingDefinitionCreation'; +import Breadcrumbs from '../../../components/Breadcrumbs'; +import { MarkingDefinitionsLinesPaginationQuery$data } from './marking_definitions/__generated__/MarkingDefinitionsLinesPaginationQuery.graphql'; +import { QueryRenderer } from '../../../relay/environment'; +import useConnectedDocumentModifier from '../../../utils/hooks/useConnectedDocumentModifier'; + +const LOCAL_STORAGE_KEY = 'MarkingDefinitions'; + +const MarkingDefinitions = () => { + const { t_i18n } = useFormatter(); + const navigate = useNavigate(); + const location = useLocation(); + const { setTitle } = useConnectedDocumentModifier(); + setTitle(t_i18n('Security: Marking Definitions | Settings')); + const params = buildViewParamsFromUrlAndStorage( + navigate, + location, + LOCAL_STORAGE_KEY, + ); + + const [markingDefinitionsState, setMarkingDefinitionsState] = useState<{ orderAsc: boolean, searchTerm: string, view: string, sortBy: string }>({ + orderAsc: params.orderAsc !== false, + searchTerm: params.searchTerm ?? '', + view: params.view ?? 'lines', + sortBy: params.sortBy ?? 'name', + }); + + function saveView() { + saveViewParameters( + navigate, + location, + LOCAL_STORAGE_KEY, + markingDefinitionsState, + ); + } + + function handleSearch(value: string) { + setMarkingDefinitionsState({ ...markingDefinitionsState, searchTerm: value }); + } + + function handleSort(field: string, orderAsc: boolean) { + setMarkingDefinitionsState({ ...markingDefinitionsState, sortBy: field, orderAsc }); + } + + useEffect(() => { + saveView(); + }, [markingDefinitionsState]); + + function renderLines(paginationOptions: PaginationOptions) { + const { sortBy, orderAsc, searchTerm } = markingDefinitionsState; + const dataColumns = { + definition_type: { + label: 'Type', + width: '25%', + isSortable: true, + }, + definition: { + label: 'Definition', + width: '25%', + isSortable: true, + }, + x_opencti_color: { + label: 'Color', + width: '15%', + isSortable: true, + }, + x_opencti_order: { + label: 'Order', + width: '10%', + isSortable: true, + }, + created: { + label: 'Original creation date', + width: '15%', + isSortable: true, + }, + }; + return ( + + ( + + )} + /> + + ); + } + + const paginationOptions: PaginationOptions = { + search: markingDefinitionsState.searchTerm, + orderBy: markingDefinitionsState.sortBy ? markingDefinitionsState.sortBy : null, + orderMode: markingDefinitionsState.orderAsc ? OrderMode.asc : OrderMode.desc, + }; + + return ( +
+ + + {markingDefinitionsState.view === 'lines' ? renderLines(paginationOptions) : ''} + +
+ ); +}; + +export default MarkingDefinitions; diff --git a/opencti-platform/opencti-front/src/private/components/settings/Roles.jsx b/opencti-platform/opencti-front/src/private/components/settings/Roles.jsx deleted file mode 100644 index a8e7b56662a9a..0000000000000 --- a/opencti-platform/opencti-front/src/private/components/settings/Roles.jsx +++ /dev/null @@ -1,134 +0,0 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose, propOr } from 'ramda'; -import withStyles from '@mui/styles/withStyles'; -import { QueryRenderer } from '../../../relay/environment'; -import { buildViewParamsFromUrlAndStorage, saveViewParameters } from '../../../utils/ListParameters'; -import inject18n from '../../../components/i18n'; -import ListLines from '../../../components/list_lines/ListLines'; -import RolesLines, { rolesLinesQuery } from './roles/RolesLines'; -import AccessesMenu from './AccessesMenu'; -import RoleCreation from './roles/RoleCreation'; -import withRouter from '../../../utils/compat_router/withRouter'; -import Breadcrumbs from '../../../components/Breadcrumbs'; - -const styles = () => ({ - container: { - margin: 0, - padding: '0 200px 50px 0', - }, -}); - -const LOCAL_STORAGE_KEY = 'roles'; - -class Roles extends Component { - constructor(props) { - super(props); - const params = buildViewParamsFromUrlAndStorage( - props.navigate, - props.location, - LOCAL_STORAGE_KEY, - ); - this.state = { - sortBy: propOr('name', 'sortBy', params), - orderAsc: propOr(true, 'orderAsc', params), - searchTerm: propOr('', 'searchTerm', params), - view: propOr('lines', 'view', params), - }; - } - - saveView() { - saveViewParameters( - this.props.navigate, - this.props.location, - LOCAL_STORAGE_KEY, - this.state, - ); - } - - handleSort(field, orderAsc) { - this.setState({ sortBy: field, orderAsc }, () => this.saveView()); - } - - handleSearch(value) { - this.setState({ searchTerm: value }, () => this.saveView()); - } - - renderLines(paginationOptions) { - const { sortBy, orderAsc, searchTerm } = this.state; - const dataColumns = { - name: { - label: 'Name', - width: '40%', - isSortable: true, - }, - groups: { - label: 'Groups with this role', - width: '20%', - isSortable: false, - }, - created_at: { - label: 'Platform creation date', - width: '20%', - isSortable: true, - }, - updated_at: { - label: 'Modification date', - width: '20%', - isSortable: true, - }, - }; - return ( - - ( - - )} - /> - - ); - } - - render() { - const { view, sortBy, orderAsc, searchTerm } = this.state; - const { classes, t } = this.props; - const paginationOptions = { - search: searchTerm, - orderBy: sortBy, - orderMode: orderAsc ? 'asc' : 'desc', - }; - return ( -
- - - {view === 'lines' ? this.renderLines(paginationOptions) : ''} - -
- ); - } -} - -Roles.propTypes = { - t: PropTypes.func, - classes: PropTypes.object, - navigate: PropTypes.func, - location: PropTypes.object, -}; - -export default compose(inject18n, withRouter, withStyles(styles))(Roles); diff --git a/opencti-platform/opencti-front/src/private/components/settings/Roles.tsx b/opencti-platform/opencti-front/src/private/components/settings/Roles.tsx new file mode 100644 index 0000000000000..7314402aa335a --- /dev/null +++ b/opencti-platform/opencti-front/src/private/components/settings/Roles.tsx @@ -0,0 +1,131 @@ +import React, { useEffect, useState } from 'react'; +import { useLocation, useNavigate } from 'react-router-dom'; +import makeStyles from '@mui/styles/makeStyles'; +import { useFormatter } from '../../../components/i18n'; +import { buildViewParamsFromUrlAndStorage, saveViewParameters } from '../../../utils/ListParameters'; +import ListLines from '../../../components/list_lines/ListLines'; +import RolesLines, { rolesLinesQuery } from './roles/RolesLines'; +import AccessesMenu from './AccessesMenu'; +import { OrderMode, PaginationOptions } from '../../../components/list_lines'; +import RoleCreation from './roles/RoleCreation'; +import Breadcrumbs from '../../../components/Breadcrumbs'; +import { RolesLinesPaginationQuery$data } from './roles/__generated__/RolesLinesPaginationQuery.graphql'; +import { QueryRenderer } from '../../../relay/environment'; +import useConnectedDocumentModifier from '../../../utils/hooks/useConnectedDocumentModifier'; + +const LOCAL_STORAGE_KEY = 'roles'; + +const useStyles = makeStyles(() => ({ + container: { + margin: 0, + padding: '0 200px 50px 0', + }, +})); + +const Role = () => { + const { t_i18n } = useFormatter(); + const navigate = useNavigate(); + const location = useLocation(); + const { setTitle } = useConnectedDocumentModifier(); + setTitle(t_i18n('Security: Roles | Settings')); + const params = buildViewParamsFromUrlAndStorage( + navigate, + location, + LOCAL_STORAGE_KEY, + ); + const classes = useStyles(); + const [rolesState, setRolesState] = useState<{ orderAsc: boolean, searchTerm: string, view: string, sortBy: string }>({ + orderAsc: params.orderAsc !== false, + searchTerm: params.searchTerm ?? '', + view: params.view ?? 'lines', + sortBy: params.sortBy ?? 'name', + }); + + function saveView() { + saveViewParameters( + navigate, + location, + LOCAL_STORAGE_KEY, + rolesState, + ); + } + + function handleSearch(value: string) { + setRolesState({ ...rolesState, searchTerm: value }); + } + + function handleSort(field: string, orderAsc: boolean) { + setRolesState({ ...rolesState, sortBy: field, orderAsc }); + } + + useEffect(() => { + saveView(); + }, [rolesState]); + + function renderLines(paginationOptions: PaginationOptions) { + const { sortBy, orderAsc } = rolesState; + const dataColumns = { + name: { + label: 'Name', + width: '40%', + isSortable: true, + }, + groups: { + label: 'Groups with this role', + width: '20%', + isSortable: false, + }, + created_at: { + label: 'Platform creation date', + width: '20%', + isSortable: true, + }, + updated_at: { + label: 'Modification date', + width: '20%', + isSortable: true, + }, + }; + return ( + + ( + + )} + /> + + ); + } + + const paginationOptions: PaginationOptions = { + search: rolesState.searchTerm, + orderBy: rolesState.sortBy ? rolesState.sortBy : null, + orderMode: rolesState.orderAsc ? OrderMode.asc : OrderMode.desc, + }; + return ( +
+ + + {rolesState.view === 'lines' ? renderLines(paginationOptions) : ''} + +
+ ); +}; + +export default Role; diff --git a/opencti-platform/opencti-front/src/private/components/settings/Sessions.jsx b/opencti-platform/opencti-front/src/private/components/settings/Sessions.jsx index 39201b6dd6fbc..3e8a563e28e28 100644 --- a/opencti-platform/opencti-front/src/private/components/settings/Sessions.jsx +++ b/opencti-platform/opencti-front/src/private/components/settings/Sessions.jsx @@ -1,17 +1,15 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; -import { compose, propOr } from 'ramda'; -import withStyles from '@mui/styles/withStyles'; +import React from 'react'; +import makeStyles from '@mui/styles/makeStyles'; import AccessesMenu from './AccessesMenu'; -import inject18n from '../../../components/i18n'; import { QueryRenderer } from '../../../relay/environment'; import SessionsList, { sessionsListQuery } from './SessionsList'; import SearchInput from '../../../components/SearchInput'; -import { buildViewParamsFromUrlAndStorage, saveViewParameters } from '../../../utils/ListParameters'; -import withRouter from '../../../utils/compat_router/withRouter'; import Breadcrumbs from '../../../components/Breadcrumbs'; +import { useFormatter } from '../../../components/i18n'; +import { usePaginationLocalStorage } from '../../../utils/hooks/useLocalStorage'; +import useConnectedDocumentModifier from '../../../utils/hooks/useConnectedDocumentModifier'; -const styles = () => ({ +const useStyles = makeStyles(() => ({ container: { margin: 0, padding: '0 200px 50px 0', @@ -20,73 +18,44 @@ const styles = () => ({ float: 'left', marginTop: -10, }, -}); +})); const LOCAL_STORAGE_KEY = 'sessions'; -class Sessions extends Component { - constructor(props) { - super(props); - const params = buildViewParamsFromUrlAndStorage( - props.navigate, - props.location, - LOCAL_STORAGE_KEY, - ); - this.state = { - searchTerm: propOr('', 'searchTerm', params), - openExports: false, - }; - } - - saveView() { - saveViewParameters( - this.props.navigate, - this.props.location, - LOCAL_STORAGE_KEY, - this.state, - ); - } - - handleSearch(value) { - this.setState({ searchTerm: value }, () => this.saveView()); - } - - render() { - const { searchTerm } = this.state; - const { t, classes } = this.props; - return ( -
- - -
-
- -
+const Sessions = () => { + const classes = useStyles(); + const { t_i18n } = useFormatter(); + const { setTitle } = useConnectedDocumentModifier(); + setTitle(t_i18n('Security: Sessions | Settings')); + const { viewStorage, helpers } = usePaginationLocalStorage( + LOCAL_STORAGE_KEY, + {}, + ); + return ( +
+ + +
+
+
-
- { - if (props) { - return ; - } - return
; - }} - />
- ); - } -} - -Sessions.propTypes = { - t: PropTypes.func, - classes: PropTypes.object, - navigate: PropTypes.func, - location: PropTypes.object, +
+ { + if (props) { + return ; + } + return
; + }} + /> +
+ ); }; -export default compose(inject18n, withRouter, withStyles(styles))(Sessions); +export default Sessions; diff --git a/opencti-platform/opencti-front/src/private/components/settings/SessionsList.jsx b/opencti-platform/opencti-front/src/private/components/settings/SessionsList.jsx index b6ab3dacf78d8..25107fe42e94e 100644 --- a/opencti-platform/opencti-front/src/private/components/settings/SessionsList.jsx +++ b/opencti-platform/opencti-front/src/private/components/settings/SessionsList.jsx @@ -1,8 +1,6 @@ -import React, { Component } from 'react'; -import * as PropTypes from 'prop-types'; +import React, { useEffect, useState } from 'react'; import * as R from 'ramda'; import { Link } from 'react-router-dom'; -import withStyles from '@mui/styles/withStyles'; import List from '@mui/material/List'; import ListItem from '@mui/material/ListItem'; import ListItemIcon from '@mui/material/ListItemIcon'; @@ -17,17 +15,17 @@ import Button from '@mui/material/Button'; import ListItemSecondaryAction from '@mui/material/ListItemSecondaryAction'; import IconButton from '@mui/material/IconButton'; import { graphql, createRefetchContainer } from 'react-relay'; -import inject18n from '../../../components/i18n'; +import makeStyles from '@mui/styles/makeStyles'; import { commitMutation } from '../../../relay/environment'; import { FIVE_SECONDS, timestamp } from '../../../utils/Time'; import { userSessionKillMutation } from './users/User'; import ItemIcon from '../../../components/ItemIcon'; import Transition from '../../../components/Transition'; -import withRouter from '../../../utils/compat_router/withRouter'; +import { useFormatter } from '../../../components/i18n'; const interval$ = interval(FIVE_SECONDS); -const styles = (theme) => ({ +const useStyles = makeStyles((theme) => ({ item: {}, itemNested: { paddingLeft: theme.spacing(4), @@ -76,187 +74,167 @@ const styles = (theme) => ({ position: 'absolute', right: -10, }, -}); +})); -class SessionsListComponent extends Component { - constructor(props) { - super(props); - this.state = { - displayUpdate: false, - displayKillSession: false, - killing: false, - sessionToKill: null, - }; - } +const SessionsListComponent = ({ relay, data, keyword }) => { + const classes = useStyles(); + const { t_i18n, nsdt } = useFormatter(); + const [displayKillSession, setDisplayKillSession] = useState(false); + const [killing, setKilling] = useState(false); + const [sessionToKill, setSessionToKill] = useState(null); - componentDidMount() { - this.subscription = interval$.subscribe(() => { - this.props.relay.refetch(); - }); - } - - componentWillUnmount() { - this.subscription.unsubscribe(); - } + useEffect(() => { + const subscription = interval$.subscribe(() => relay.refetch()); + return () => { + subscription.unsubscribe(); + }; + }, []); - handleOpenKillSession(session) { - this.setState({ displayKillSession: true, sessionToKill: session }); - } + const handleOpenKillSession = (session) => { + setDisplayKillSession(true); + setSessionToKill(session); + }; - handleCloseKillSession() { - this.setState({ displayKillSession: false, sessionToKill: null }); - } + const handleCloseKillSession = () => { + setDisplayKillSession(false); + setSessionToKill(null); + }; - submitKillSession() { - this.setState({ killing: true }); + const submitKillSession = () => { + setKilling(true); commitMutation({ mutation: userSessionKillMutation, variables: { - id: this.state.sessionToKill, + id: sessionToKill, }, onCompleted: () => { - this.setState({ killing: false }); - this.handleCloseKillSession(); + setKilling(false); + handleCloseKillSession(); }, onError: () => { - this.setState({ killing: false }); + setKilling(false); }, }); - } + }; - render() { - const { classes, nsdt, t, data, keyword } = this.props; - const sortByNameCaseInsensitive = R.sortBy( - R.compose(R.toLower, R.path(['user', 'name'])), - ); - const filterByKeyword = (n) => keyword === '' - || n.user.name.toLowerCase().indexOf(keyword.toLowerCase()) !== -1; - const sessions = R.pipe( - R.propOr([], 'sessions'), - R.filter(filterByKeyword), - sortByNameCaseInsensitive, - )(data); - return ( - <> - - {sessions.map((session) => { - const { user, sessions: userSessions } = session; - const orderedSessions = R.sort( - (a, b) => timestamp(a.created) - timestamp(b.created), - userSessions, - ); - return ( -
- - - - - -
{user.name}
-
{user.email}
-
- } - /> - -   - - - - {orderedSessions.map((userSession) => ( - - - - - -
- {nsdt(userSession.created)} -
-
- {Math.round(userSession.ttl / 60)}{' '} - {t('minutes left')} /{' '} - {Math.round(userSession.originalMaxAge / 60)} -
+ const sortByNameCaseInsensitive = R.sortBy( + R.compose(R.toLower, R.path(['user', 'name'])), + ); + const filterByKeyword = (n) => keyword === '' + || n.user.name.toLowerCase().indexOf(keyword.toLowerCase()) !== -1; + const sessions = R.pipe( + R.propOr([], 'sessions'), + R.filter(filterByKeyword), + sortByNameCaseInsensitive, + )(data); + return ( + <> + + {sessions.map((session) => { + const { user, sessions: userSessions } = session; + const orderedSessions = R.sort( + (a, b) => timestamp(a.created) - timestamp(b.created), + userSessions, + ); + return ( +
+ + + + + +
{user.name}
+
{user.email}
+
+ } + /> + +   + +
+ + {orderedSessions.map((userSession) => ( + + + + + +
+ {nsdt(userSession.created)}
- } - /> - - - - - -
- ))} -
-
- ); - })} - - - - - {t('Do you want to kill this session?')} - - - - - - - - - ); - } -} - -SessionsListComponent.propTypes = { - t: PropTypes.func, - classes: PropTypes.object, - navigate: PropTypes.func, - location: PropTypes.object, - nsdt: PropTypes.func, - data: PropTypes.object, +
+ {Math.round(userSession.ttl / 60)}{' '} + {t_i18n('minutes left')} /{' '} + {Math.round(userSession.originalMaxAge / 60)} +
+
+ } + /> + + handleOpenKillSession(userSession.id)} + size="large" + color="primary" + > + + + + + ))} + +
+ ); + })} + + + + + {t_i18n('Do you want to kill this session?')} + + + + + + + + + ); }; export const sessionsListQuery = graphql` @@ -265,7 +243,7 @@ export const sessionsListQuery = graphql` } `; -const SessionsList = createRefetchContainer( +export default createRefetchContainer( SessionsListComponent, { data: graphql` @@ -287,9 +265,3 @@ const SessionsList = createRefetchContainer( }, sessionsListQuery, ); - -export default R.compose( - inject18n, - withRouter, - withStyles(styles), -)(SessionsList); diff --git a/opencti-platform/opencti-front/src/private/components/settings/groups/GroupsLines.tsx b/opencti-platform/opencti-front/src/private/components/settings/groups/GroupsLines.tsx index 0ffdaeec2cc05..8d7ecbf71b805 100644 --- a/opencti-platform/opencti-front/src/private/components/settings/groups/GroupsLines.tsx +++ b/opencti-platform/opencti-front/src/private/components/settings/groups/GroupsLines.tsx @@ -1,11 +1,10 @@ import React from 'react'; import { graphql, createPaginationContainer, RelayPaginationProp } from 'react-relay'; import { pathOr } from 'ramda'; -import { GroupsLinesPaginationQuery$variables } from '@components/settings/groups/__generated__/GroupsLinesPaginationQuery.graphql'; import { GroupsLines_data$data } from '@components/settings/groups/__generated__/GroupsLines_data.graphql'; import ListLinesContent from '../../../../components/list_lines/ListLinesContent'; import { GroupLine, GroupLineDummy } from './GroupLine'; -import { DataColumns } from '../../../../components/list_lines'; +import { DataColumns, PaginationOptions } from '../../../../components/list_lines'; const nbOfRowsToLoad = 50; @@ -13,7 +12,7 @@ interface GroupsLinesProps { initialLoading: boolean dataColumns: DataColumns relay: RelayPaginationProp, - paginationOptions: GroupsLinesPaginationQuery$variables + paginationOptions: PaginationOptions, data: GroupsLines_data$data }