Skip to content

Commit

Permalink
EPMRPP-91268 || Table view (#4082)
Browse files Browse the repository at this point in the history
  • Loading branch information
BlazarQSO authored Nov 6, 2024
1 parent 3f2ae89 commit c9785c0
Show file tree
Hide file tree
Showing 33 changed files with 583 additions and 72 deletions.
5 changes: 5 additions & 0 deletions app/localization/translated/be.json
Original file line number Diff line number Diff line change
Expand Up @@ -1565,13 +1565,18 @@
"OrganizationsPage.noOrganizationsAvailableYet": "Пакуль няма даступных арганізацый",
"OrganizationsPage.noLaunches": "Ніякіх запускаў",
"OrganizationsPage.noResultsDescription": "Вашым крытэрам пошуку або фільтра не знойдзена ніводнага выніку. Калі ласка, паспрабуйце іншыя ключавыя словы або змяніце налады фільтра.",
"OrganizationsPage.organizationName": "Назва арганізацыі",
"OrganizationsPage.searchPlaceholder": "Пошук па назве",
"OrganizationsPage.synchedOrganization": "Сінхранізаваная арганізацыя",
"OrganizationsPage.lastLaunch": "Апошні запуск быў ажыццёўлены больш 3 месяцаў таму",
"OrganizationsPage.lastLaunchDate": "Дата апошняга запуску",
"OrganizationsPage.latestLaunch": "Апошняе выкананне запуску",
"OrganizationsPage.launches": "Запускі",
"OrganizationsPage.organizationUsers": "Карыстальнікі арганізацыі",
"OrganizationsPage.organizationProjects": "Арганізацыйныя праекты",
"OrganizationsPage.personalOrganization": "Асабістая арганізацыя",
"OrganizationsPage.projects": "Праекты",
"OrganizationsPage.users": "Карыстальнікі",
"OrganizationsPopover.allOrganizations": "Усе арганізацыі",
"OrganizationsControl.assignmentsList": "Прызначаны спіс",
"OverallStatisticsControls.ContentFieldsValidationError": "Абярыце па меншай меры адзін элемент",
Expand Down
5 changes: 5 additions & 0 deletions app/localization/translated/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -1563,13 +1563,18 @@
"OrganizationsPage.noOrganizationsAvailableYet": "No organizations available yet",
"OrganizationsPage.noLaunches": "No launches",
"OrganizationsPage.noResultsDescription": "Your search or filter criteria didn't match any results. Please try different keywords or adjust your filter settings.",
"OrganizationsPage.organizationName": "Organization name",
"OrganizationsPage.searchPlaceholder": "Buscar por nombre",
"OrganizationsPage.synchedOrganization": "Synched organization",
"OrganizationsPage.lastLaunch": "The last launch was executed more than 3 months ago",
"OrganizationsPage.lastLaunchDate": "Last launch date",
"OrganizationsPage.latestLaunch": "The latest launch execution",
"OrganizationsPage.launches": "Launches",
"OrganizationsPage.organizationUsers": "Organization users",
"OrganizationsPage.organizationProjects": "Organization projects",
"OrganizationsPage.personalOrganization": "Personal organization",
"OrganizationsPage.projects": "Projects",
"OrganizationsPage.users": "Users",
"OrganizationsPopover.allOrganizations": "All organizatoins",
"OrganizationsControl.assignmentsList": "Assignments list",
"OverallStatisticsControls.ContentFieldsValidationError": "Seleccione al menos un elemento",
Expand Down
5 changes: 5 additions & 0 deletions app/localization/translated/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -1560,13 +1560,18 @@
"OrganizationsPage.noOrganizationsAvailableYet": "Пока нет доступных организаций",
"OrganizationsPage.noLaunches": "Никаких запусков",
"OrganizationsPage.noResultsDescription": "Ваши критерии поиска или фильтра не дали никаких результатов. Попробуйте другие ключевые слова или измените настройки фильтра.",
"OrganizationsPage.organizationName": "Название организации",
"OrganizationsPage.searchPlaceholder": "Поиск по названию",
"OrganizationsPage.synchedOrganization": "Синхронизированная организация",
"OrganizationsPage.lastLaunch": "Последний запуск был осуществлен более 3 месяцев назад",
"OrganizationsPage.lastLaunchDate": "Дата последнего запуска",
"OrganizationsPage.latestLaunch": "Последнее выполнение запуска",
"OrganizationsPage.launches": "Запуски",
"OrganizationsPage.organizationUsers": "Пользователи организации",
"OrganizationsPage.organizationProjects": "Организационные проекты",
"OrganizationsPage.personalOrganization": "Персональная организация",
"OrganizationsPage.projects": "Проекты",
"OrganizationsPage.users": "Пользователи",
"OrganizationsPopover.allOrganizations": "Все организации",
"OrganizationsControl.assignmentsList": "Назначенный список",
"OverallStatisticsControls.ContentFieldsValidationError": "Выберите не меньше одного элемента",
Expand Down
5 changes: 5 additions & 0 deletions app/localization/translated/uk.json
Original file line number Diff line number Diff line change
Expand Up @@ -1562,13 +1562,18 @@
"OrganizationsPage.noOrganizationsAvailableYet": "Поки що немає доступних організацій",
"OrganizationsPage.noLaunches": "Ніяких запусків",
"OrganizationsPage.noResultsDescription": "Ваші критерії пошуку чи фільтра не відповідають жодному результату. Будь ласка, спробуйте інші ключові слова або змініть налаштування фільтра.",
"OrganizationsPage.organizationName": "Назва організації",
"OrganizationsPage.searchPlaceholder": "Пошук по назві",
"OrganizationsPage.synchedOrganization": "Синхронізована організація",
"OrganizationsPage.lastLaunch": "Останній запуск був здійснений більше 3 місяців тому",
"OrganizationsPage.lastLaunchDate": "Дата останнього запуску",
"OrganizationsPage.latestLaunch": "Останнє виконання запуску",
"OrganizationsPage.launches": "Запуски",
"OrganizationsPage.organizationUsers": "Користувачі організації",
"OrganizationsPage.organizationProjects": "Організаційні проекти",
"OrganizationsPage.personalOrganization": "Особиста організація",
"OrganizationsPage.projects": "Проекти",
"OrganizationsPage.users": "Користувачі",
"OrganizationsPopover.allOrganizations": "Всі організації",
"OrganizationsControl.assignmentsList": "Призначений список",
"OverallStatisticsControls.ContentFieldsValidationError": "Виберіть не менше одного елемента",
Expand Down
5 changes: 5 additions & 0 deletions app/localization/translated/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -1562,13 +1562,18 @@
"OrganizationsPage.noOrganizationsAvailableYet": "No organizations available yet",
"OrganizationsPage.noLaunches": "No launches",
"OrganizationsPage.noResultsDescription": "Your search or filter criteria didn't match any results. Please try different keywords or adjust your filter settings.",
"OrganizationsPage.organizationName": "Organization name",
"OrganizationsPage.searchPlaceholder": "按名称搜索",
"OrganizationsPage.synchedOrganization": "Synched organization",
"OrganizationsPage.lastLaunch": "The last launch was executed more than 3 months ago",
"OrganizationsPage.lastLaunchDate": "Last launch date",
"OrganizationsPage.latestLaunch": "The latest launch execution",
"OrganizationsPage.launches": "Launches",
"OrganizationsPage.organizationUsers": "Organization users",
"OrganizationsPage.organizationProjects": "Organization projects",
"OrganizationsPage.personalOrganization": "Personal organization",
"OrganizationsPage.projects": "Projects",
"OrganizationsPage.users": "Users",
"OrganizationsPopover.allOrganizations": "All organizations",
"OrganizationsControl.assignmentsList": "Assignments list",
"OverallStatisticsControls.ContentFieldsValidationError": "您必须选中至少一个测试项",
Expand Down
11 changes: 11 additions & 0 deletions app/src/pages/instance/organizationsPage/img/panel-view-inline.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions app/src/pages/instance/organizationsPage/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,24 @@ export const messages = defineMessages({
id: 'OrganizationsPage.personalOrganization',
defaultMessage: 'Personal organization',
},
organizationName: {
id: 'OrganizationsPage.organizationName',
defaultMessage: 'Organization name',
},
projects: {
id: 'OrganizationsPage.projects',
defaultMessage: 'Projects',
},
users: {
id: 'OrganizationsPage.users',
defaultMessage: 'Users',
},
launches: {
id: 'OrganizationsPage.launches',
defaultMessage: 'Launches',
},
lastLaunchDate: {
id: 'OrganizationsPage.lastLaunchDate',
defaultMessage: 'Last launch date',
},
});
30 changes: 27 additions & 3 deletions app/src/pages/instance/organizationsPage/organizationsPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,40 @@ import {
} from 'controllers/instance/organizations';
import { COMMON_LOCALE_KEYS } from 'common/constants/localization';
import NoResultsIcon from 'common/img/newIcons/no-results-icon-inline.svg';
import { getStorageItem, updateStorageItem } from 'common/utils/storageUtils';
import { userIdSelector } from 'controllers/user';
import EmptyIcon from './img/empty-organizations-inline.svg';
import { messages } from './messages';
import styles from './organizationsPage.scss';
import { OrganizationsPageHeader } from './organizationsPageHeader';
import { OrganizationsPanelView } from './organizationsPanelView';
import { messages } from './messages';
import styles from './organizationsPage.scss';

const cx = classNames.bind(styles);
const PANEL_VIEW = 'PanelView';
const TABLE_VIEW = 'TableView';

export const OrganizationsPage = () => {
const { formatMessage } = useIntl();
const userRoles = useSelector(userRolesSelector);
const hasPermission = canCreateOrganization(userRoles);
const organizationsList = useSelector(organizationsListSelector);
const isOrganizationsLoading = useSelector(organizationsListLoadingSelector);
const userId = useSelector(userIdSelector);
const [searchValue, setSearchValue] = useState(null);
const isEmptyOrganizations = !isOrganizationsLoading && organizationsList.length === 0;
const [isOpenTableView, setIsOpenTableView] = useState(
getStorageItem(`${userId}_settings`)?.organizationsPanel === TABLE_VIEW,
);

const openPanelView = () => {
setIsOpenTableView(false);
updateStorageItem(`${userId}_settings`, { organizationsPanel: PANEL_VIEW });
};

const openTableView = () => {
setIsOpenTableView(true);
updateStorageItem(`${userId}_settings`, { organizationsPanel: TABLE_VIEW });
};

const getEmptyPageState = () => {
if (isOrganizationsLoading) {
Expand Down Expand Up @@ -87,11 +105,17 @@ export const OrganizationsPage = () => {
isEmpty={isEmptyOrganizations && searchValue === null}
searchValue={searchValue}
setSearchValue={setSearchValue}
openPanelView={openPanelView}
openTableView={openTableView}
isOpenTableView={isOpenTableView}
/>
{isEmptyOrganizations ? (
getEmptyPageState()
) : (
<OrganizationsPanelView organizationsList={organizationsList} />
<OrganizationsPanelView
organizationsList={organizationsList}
isOpenTableView={isOpenTableView}
/>
)}
</div>
</ScrollWrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,24 @@ import { withFilter } from 'controllers/filter';
import { useSelector } from 'react-redux';
import { organizationsListLoadingSelector } from 'controllers/instance/organizations';
import { ORGANIZATION_PAGE_EVENTS } from 'components/main/analytics/events/ga4Events/organizationsPageEvents';
import { BaseIconButton } from '@reportportal/ui-kit';
import PanelViewIcon from '../img/panel-view-inline.svg';
import TableViewIcon from '../img/table-view-inline.svg';
import { messages } from '../messages';
import styles from './organizationsPageHeader.scss';

const cx = classNames.bind(styles);

const SearchFieldWithFilter = withFilter({ filterKey: SEARCH_KEY })(SearchField);

export const OrganizationsPageHeader = ({ isEmpty, searchValue, setSearchValue }) => {
export const OrganizationsPageHeader = ({
isEmpty,
searchValue,
setSearchValue,
openPanelView,
openTableView,
isOpenTableView,
}) => {
const { formatMessage } = useIntl();
const projectsLoading = useSelector(organizationsListLoadingSelector);

Expand All @@ -52,6 +62,20 @@ export const OrganizationsPageHeader = ({ isEmpty, searchValue, setSearchValue }
event={ORGANIZATION_PAGE_EVENTS.SEARCH_ORGANIZATION_FIELD}
/>
<i className={cx('filters-icon')}>{Parser(filterIcon)}</i>
<BaseIconButton
className={cx('panel-icon', { active: !isOpenTableView })}
onClick={openPanelView}
variant={'text'}
>
{Parser(PanelViewIcon)}
</BaseIconButton>
<BaseIconButton
className={cx('panel-icon', { active: isOpenTableView })}
onClick={openTableView}
variant={'text'}
>
{Parser(TableViewIcon)}
</BaseIconButton>
</div>
)}
</div>
Expand All @@ -64,6 +88,9 @@ OrganizationsPageHeader.propTypes = {
isEmpty: PropTypes.bool,
searchValue: PropTypes.string || null,
setSearchValue: PropTypes.func.isRequired,
openPanelView: PropTypes.func.isRequired,
openTableView: PropTypes.func.isRequired,
isOpenTableView: PropTypes.bool.isRequired,
};

OrganizationsPageHeader.defaultProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,17 @@
}
}
}

.panel-icon {
width: 16px;
height: 16px;
margin: 10px 12px;
}

.active {
&:not(.disabled, :active) {
svg path {
fill: $COLOR--topaz-pressed;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* 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 classNames from 'classnames/bind';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import {
ORGANIZATION_EXTERNAL_TYPE,
ORGANIZATION_INTERNAL_TYPE,
} from 'common/constants/organizationTypes';
import Parser from 'html-react-parser';
import { Tooltip } from '@reportportal/ui-kit';
import SynchedIcon from './img/synched-organization-inline.svg';
import OutdatedIcon from './img/outdated-inline.svg';
import PersonalIcon from './img/personal-organization-inline.svg';
import { messages } from '../../messages';
import styles from './iconsBlock.scss';

const cx = classNames.bind(styles);
const THREE_MONTHS_IN_MS = 1000 * 60 * 60 * 24 * 30 * 3;

export const IconsBlock = ({ lastLaunchDate, hasPermission, organizationType }) => {
const { formatMessage } = useIntl();
const isOutdated =
lastLaunchDate && Date.now() - new Date(lastLaunchDate).getTime() > THREE_MONTHS_IN_MS;

return (
<>
{hasPermission &&
(organizationType === ORGANIZATION_EXTERNAL_TYPE ? (
<Tooltip
content={formatMessage(messages.synchedOrganization)}
placement={'top'}
wrapperClassName={cx('tooltip-wrapper')}
>
<i className={cx('icon')}>{Parser(SynchedIcon)}</i>
</Tooltip>
) : (
organizationType !== ORGANIZATION_INTERNAL_TYPE && (
<Tooltip
content={formatMessage(messages.personalOrganization)}
placement={'top'}
wrapperClassName={cx('tooltip-wrapper')}
>
<i className={cx('icon')}>{Parser(PersonalIcon)}</i>
</Tooltip>
)
))}
{hasPermission && isOutdated && (
<Tooltip
content={formatMessage(messages.lastLaunch)}
placement={'top'}
wrapperClassName={cx('tooltip-wrapper')}
>
<i className={cx('icon')}>{Parser(OutdatedIcon)}</i>
</Tooltip>
)}
</>
);
};

IconsBlock.propTypes = {
organizationType: PropTypes.string.isRequired,
lastLaunchDate: PropTypes.string.isRequired,
hasPermission: PropTypes.bool.isRequired,
};
Loading

0 comments on commit c9785c0

Please sign in to comment.