diff --git a/app/localization/translated/be.json b/app/localization/translated/be.json
index 72ad550050..1f94f69efe 100644
--- a/app/localization/translated/be.json
+++ b/app/localization/translated/be.json
@@ -1784,6 +1784,7 @@
"ProjectStatusPage.oneMonth": "1 месяц",
"ProjectStatusPage.sixMonths": "6 месяцаў",
"ProjectStatusPage.threeMonths": "3 месяца",
+ "ProjectTeamPage.allOrganizations": "Усе арганізацыі",
"ProjectTeamPage.description": "Спіс карыстальнікаў у дадзены момант пусты. Каб атрымаць максімальную аддачу ад свайго праекта, Запрасіце членаў сваёй каманды і эфектыўна супрацоўнічайце.",
"ProjectTeamPage.inviteUser": "Запрасіць карыстальніка",
"ProjectTeamPage.noResultsDescription": "Вынікі пошуку або фільтрацыі не супалі ні з адным з крытэраў. Калі ласка, паспрабуйце выкарыстоўваць іншыя ключавыя словы або змяніць налады фільтра.",
diff --git a/app/localization/translated/es.json b/app/localization/translated/es.json
index 6fddeb4049..00ab123867 100644
--- a/app/localization/translated/es.json
+++ b/app/localization/translated/es.json
@@ -1783,6 +1783,7 @@
"ProjectStatusPage.oneMonth": "1 mes",
"ProjectStatusPage.sixMonths": "6 meses",
"ProjectStatusPage.threeMonths": "3 meses",
+ "ProjectTeamPage.allOrganizations": "All Organizations",
"ProjectTeamPage.description": "User list is currently empty. To make the most out of your project, invite your team members and collaborate efficiently.",
"ProjectTeamPage.inviteUser": "Invite user",
"ProjectTeamPage.noResultsDescription": "Your search or filter criteria didn't match any results. Please try different keywords or adjust your filter settings.",
diff --git a/app/localization/translated/ru.json b/app/localization/translated/ru.json
index 767665618e..aac3f200fe 100644
--- a/app/localization/translated/ru.json
+++ b/app/localization/translated/ru.json
@@ -1780,6 +1780,7 @@
"ProjectStatusPage.oneMonth": "1 месяц",
"ProjectStatusPage.sixMonths": "6 месяцев",
"ProjectStatusPage.threeMonths": "3 месяца",
+ "ProjectTeamPage.allOrganizations": "Все организации",
"ProjectTeamPage.description": "Список пользователей в данный момент пуст. Чтобы получить максимальную отдачу от своего проекта, пригласите членов своей команды и эффективно сотрудничайте.",
"ProjectTeamPage.inviteUser": "Пригласить пользователя",
"ProjectTeamPage.noResultsDescription": "Результаты поиска или фильтрации не совпали ни с одним из критериев. Пожалуйста, попробуйте использовать другие ключевые слова или измените настройки фильтра.",
diff --git a/app/localization/translated/uk.json b/app/localization/translated/uk.json
index 80d30adf13..1c304afdec 100644
--- a/app/localization/translated/uk.json
+++ b/app/localization/translated/uk.json
@@ -1782,6 +1782,7 @@
"ProjectStatusPage.oneMonth": "1 місяць",
"ProjectStatusPage.sixMonths": "6 місяців",
"ProjectStatusPage.threeMonths": "3 місяці",
+ "ProjectTeamPage.allOrganizations": "Всі організації",
"ProjectTeamPage.description": "Список користувачів на даний момент порожній. Щоб отримати максимальну віддачу від свого проекту, запросіть членів своєї команди та ефективно співпрацюйте.",
"ProjectTeamPage.inviteUser": "Запросити користувача",
"ProjectTeamPage.noResultsDescription": "Результати пошуку або фільтрації не співпали з жодним із критеріїв. Будь ласка, спробуйте використовувати інші ключові слова або змініть налаштування фільтра.",
diff --git a/app/localization/translated/zh.json b/app/localization/translated/zh.json
index 8277f49306..3dad4c944c 100644
--- a/app/localization/translated/zh.json
+++ b/app/localization/translated/zh.json
@@ -1782,6 +1782,7 @@
"ProjectStatusPage.oneMonth": "1个月",
"ProjectStatusPage.sixMonths": "6个月",
"ProjectStatusPage.threeMonths": "3个月",
+ "ProjectTeamPage.allOrganizations": "All Organizations",
"ProjectTeamPage.description": "User list is currently empty. To make the most out of your project, invite your team members and collaborate efficiently.",
"ProjectTeamPage.inviteUser": "Invite user",
"ProjectTeamPage.noResultsDescription": "Your search or filter criteria didn't match any results. Please try different keywords or adjust your filter settings.",
diff --git a/app/src/common/urls.js b/app/src/common/urls.js
index 6e6ecaa61b..d57283ad43 100644
--- a/app/src/common/urls.js
+++ b/app/src/common/urls.js
@@ -243,7 +243,6 @@ export const URLS = {
logSearch: (projectKey, itemId) => `${urlBase}${projectKey}/log/search/${itemId}`,
bulkLastLogs: (projectKey) => `${urlBase}${projectKey}/log/under`,
users: (ids = []) => `${urlCommonBase}users?ids=${ids.join(',')}`,
- usersMe: () => `${urlCommonBase}users/me`,
userRegistration: () => `${urlCommonBase}users/registration`,
userValidateRegistrationInfo: () => `${urlCommonBase}users/registration/info`,
userPasswordReset: () => `${urlCommonBase}users/password/reset`,
@@ -266,7 +265,7 @@ export const URLS = {
events: () => `${urlBase}activities/searches`,
searchEventsBySubjectName: (projectName) => (searchTerm = '') =>
`${urlBase}activities/${projectName}/subjectName?filter.cnt.subjectName=${searchTerm}`,
- allUsers: () => `${urlCommonBase}users`,
+ allUsers: () => `${urlCommonBase}users/all`,
exportUsers: (filterEntities) =>
`${urlCommonBase}users/export${getQueryParams({
diff --git a/app/src/controllers/user/sagas.js b/app/src/controllers/user/sagas.js
index 94c610042a..5eb052b208 100644
--- a/app/src/controllers/user/sagas.js
+++ b/app/src/controllers/user/sagas.js
@@ -126,7 +126,7 @@ function* unassignFromProject({ payload: project }) {
function* fetchUserWorker() {
let user;
try {
- user = yield call(fetch, URLS.usersMe());
+ user = yield call(fetch, URLS.users());
yield put(fetchUserSuccessAction(user));
} catch (err) {
yield put(fetchUserErrorAction());
diff --git a/app/src/pages/organization/common/membersPage/membersPageHeader/membersPageHeader.jsx b/app/src/pages/organization/common/membersPage/membersPageHeader/membersPageHeader.jsx
index 61b598ec47..b5e95c7dfd 100644
--- a/app/src/pages/organization/common/membersPage/membersPageHeader/membersPageHeader.jsx
+++ b/app/src/pages/organization/common/membersPage/membersPageHeader/membersPageHeader.jsx
@@ -17,13 +17,15 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames/bind';
+import { UserPageLocationLevel } from './userPageLocationLevel';
import styles from './membersPageHeader.scss';
const cx = classNames.bind(styles);
-export const MembersPageHeader = ({ title, children }) => {
+export const MembersPageHeader = ({ title, children, organizationName, projectName }) => {
return (
+
{title}
{children}
@@ -35,8 +37,11 @@ export const MembersPageHeader = ({ title, children }) => {
MembersPageHeader.propTypes = {
title: PropTypes.string.isRequired,
children: PropTypes.node,
+ organizationName: PropTypes.string.isRequired,
+ projectName: PropTypes.string,
};
MembersPageHeader.defaultProps = {
children: null,
+ projectName: null,
};
diff --git a/app/src/pages/organization/common/membersPage/membersPageHeader/membersPageHeader.scss b/app/src/pages/organization/common/membersPage/membersPageHeader/membersPageHeader.scss
index 0ab16a39b4..a5a599d0b9 100644
--- a/app/src/pages/organization/common/membersPage/membersPageHeader/membersPageHeader.scss
+++ b/app/src/pages/organization/common/membersPage/membersPageHeader/membersPageHeader.scss
@@ -15,7 +15,7 @@
*/
.members-page-header-container {
- padding: 48px 32px 16px 32px;
+ padding: 16px 32px 16px 32px;
border-bottom: 1px solid $COLOR--e-100;
background: $COLOR--bg-000;
box-sizing: border-box;
diff --git a/app/src/pages/organization/common/membersPage/membersPageHeader/messages.js b/app/src/pages/organization/common/membersPage/membersPageHeader/messages.js
index c963bc3650..e625b85c85 100644
--- a/app/src/pages/organization/common/membersPage/membersPageHeader/messages.js
+++ b/app/src/pages/organization/common/membersPage/membersPageHeader/messages.js
@@ -47,4 +47,8 @@ export const messages = defineMessages({
defaultMessage:
"Your search or filter criteria didn't match any results. Please try different keywords or adjust your filter settings.",
},
+ allOrganizations: {
+ id: 'ProjectTeamPage.allOrganizations',
+ defaultMessage: 'All Organizations',
+ },
});
diff --git a/app/src/pages/organization/common/membersPage/membersPageHeader/userPageLocationLevel/img/sub-level-inline.svg b/app/src/pages/organization/common/membersPage/membersPageHeader/userPageLocationLevel/img/sub-level-inline.svg
new file mode 100644
index 0000000000..87cbd65e2c
--- /dev/null
+++ b/app/src/pages/organization/common/membersPage/membersPageHeader/userPageLocationLevel/img/sub-level-inline.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/src/pages/organization/common/membersPage/membersPageHeader/userPageLocationLevel/img/tree-inline.svg b/app/src/pages/organization/common/membersPage/membersPageHeader/userPageLocationLevel/img/tree-inline.svg
new file mode 100644
index 0000000000..9efe01b5c1
--- /dev/null
+++ b/app/src/pages/organization/common/membersPage/membersPageHeader/userPageLocationLevel/img/tree-inline.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/src/pages/organization/common/membersPage/membersPageHeader/userPageLocationLevel/index.js b/app/src/pages/organization/common/membersPage/membersPageHeader/userPageLocationLevel/index.js
new file mode 100644
index 0000000000..45adab2eb6
--- /dev/null
+++ b/app/src/pages/organization/common/membersPage/membersPageHeader/userPageLocationLevel/index.js
@@ -0,0 +1,17 @@
+/*!
+ * Copyright 2024 EPAM Systems
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export { UserPageLocationLevel } from './userPageLocationLevel';
diff --git a/app/src/pages/organization/common/membersPage/membersPageHeader/userPageLocationLevel/userPageLocationLevel.jsx b/app/src/pages/organization/common/membersPage/membersPageHeader/userPageLocationLevel/userPageLocationLevel.jsx
new file mode 100644
index 0000000000..9464033373
--- /dev/null
+++ b/app/src/pages/organization/common/membersPage/membersPageHeader/userPageLocationLevel/userPageLocationLevel.jsx
@@ -0,0 +1,76 @@
+/*!
+ * Copyright 2024 EPAM Systems
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { useState } from 'react';
+import PropTypes from 'prop-types';
+import { useIntl } from 'react-intl';
+import Parser from 'html-react-parser';
+import classNames from 'classnames/bind';
+import { BaseIconButton, Popover } from '@reportportal/ui-kit';
+import TreeIcon from './img/tree-inline.svg';
+import SubLevelIcon from './img/sub-level-inline.svg';
+import { messages } from '../messages';
+import styles from './userPageLocationLevel.scss';
+
+const cx = classNames.bind(styles);
+
+export const UserPageLocationLevel = ({ organizationName, projectName }) => {
+ const { formatMessage } = useIntl();
+ const [isOpen, setIsOpen] = useState(false);
+
+ const getContent = () => (
+
+
{formatMessage(messages.allOrganizations)}
+
+ {Parser(SubLevelIcon)}
+ {organizationName}
+
+ {projectName && (
+
+ {Parser(SubLevelIcon)}
+ {projectName}
+
+ )}
+
+ );
+
+ return (
+
+
+
+ {Parser(TreeIcon)}
+
+
+
{projectName || organizationName}
+
+ );
+};
+
+UserPageLocationLevel.propTypes = {
+ organizationName: PropTypes.string.isRequired,
+ projectName: PropTypes.string,
+};
+
+UserPageLocationLevel.defaultProps = {
+ projectName: null,
+};
diff --git a/app/src/pages/organization/common/membersPage/membersPageHeader/userPageLocationLevel/userPageLocationLevel.scss b/app/src/pages/organization/common/membersPage/membersPageHeader/userPageLocationLevel/userPageLocationLevel.scss
new file mode 100644
index 0000000000..f428ea6eed
--- /dev/null
+++ b/app/src/pages/organization/common/membersPage/membersPageHeader/userPageLocationLevel/userPageLocationLevel.scss
@@ -0,0 +1,74 @@
+/*!
+ * Copyright 2024 EPAM Systems
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+.user-page-location-level {
+ display: flex;
+ align-items: center;
+ gap: 16px;
+ color: $COLOR--e-300;
+ font-size: 13px;
+ margin-bottom: 12px;
+
+ svg {
+ width: 16px;
+ height: 16px;
+ }
+}
+
+.tree-button {
+ width: 16px;
+ height: 16px;
+}
+
+.name {
+ font-size: 13px;
+ line-height: 20px;
+}
+
+.open {
+ svg path {
+ fill: $COLOR--topaz-pressed;
+ }
+
+ &:hover:not(.disabled) {
+ svg path {
+ fill: $COLOR--topaz-2;
+ }
+ }
+}
+
+.popover {
+ font-size: 13px;
+ line-height: 20px;
+ min-width: 175px;
+}
+
+.project-name,
+.organization-name {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ margin-top: 8px;
+}
+
+.project-name {
+ color: $COLOR--topaz-2;
+ margin-left: 16px;
+}
+
+.active {
+ color: $COLOR--topaz-2;
+}
diff --git a/app/src/pages/organization/organizationUsersPage/organizationUsersPageHeader/organizationUsersPageHeader.jsx b/app/src/pages/organization/organizationUsersPage/organizationUsersPageHeader/organizationUsersPageHeader.jsx
index 5290658f02..d891e44df3 100644
--- a/app/src/pages/organization/organizationUsersPage/organizationUsersPageHeader/organizationUsersPageHeader.jsx
+++ b/app/src/pages/organization/organizationUsersPage/organizationUsersPageHeader/organizationUsersPageHeader.jsx
@@ -47,7 +47,10 @@ export const OrganizationUsersPageHeader = ({
const isNotEmpty = usersCount > 0;
return (
-
+
{isNotEmpty && (
<>
diff --git a/app/src/pages/organization/projectTeamPage/projectTeamPageHeader/projectTeamPageHeader.jsx b/app/src/pages/organization/projectTeamPage/projectTeamPageHeader/projectTeamPageHeader.jsx
index f943909ce2..bfcff49831 100644
--- a/app/src/pages/organization/projectTeamPage/projectTeamPageHeader/projectTeamPageHeader.jsx
+++ b/app/src/pages/organization/projectTeamPage/projectTeamPageHeader/projectTeamPageHeader.jsx
@@ -21,12 +21,13 @@ import Parser from 'html-react-parser';
import classNames from 'classnames/bind';
import { Button } from '@reportportal/ui-kit';
import { useIntl } from 'react-intl';
-import { projectMembersSelector } from 'controllers/project';
+import { projectMembersSelector, projectNameSelector } from 'controllers/project';
import { SearchField } from 'components/fields/searchField';
import { NAMESPACE, SEARCH_KEY } from 'controllers/members/constants';
import { withFilter } from 'controllers/filter';
import filterIcon from 'common/img/newIcons/filters-outline-inline.svg';
import { PROJECT_PAGE_EVENTS } from 'components/main/analytics/events/ga4Events/projectPageEvents';
+import { activeOrganizationNameSelector } from 'controllers/organization';
import { messages } from '../../common/membersPage/membersPageHeader/messages';
import { MembersPageHeader } from '../../common/membersPage/membersPageHeader';
import styles from './projectTeamPageHeader.scss';
@@ -46,10 +47,16 @@ export const ProjectTeamPageHeader = ({
}) => {
const { formatMessage } = useIntl();
const projectMembers = useSelector(projectMembersSelector);
+ const projectName = useSelector(projectNameSelector);
+ const organizationName = useSelector(activeOrganizationNameSelector);
const isNotEmptyMembers = projectMembers.length !== 0;
return (
-
+