Fix #5295 UI layout fixes on setting tab. (#5541)

Co-authored-by: Shailesh Parmar <shailesh.parmar.webdev@gmail.com>
This commit is contained in:
yug-shah0106 2022-06-22 22:49:10 +05:30 committed by GitHub
parent 2b05f6a17a
commit bdfee26533
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 335 additions and 282 deletions

View File

@ -96,13 +96,10 @@ describe('Glossary page should work properly', () => {
beforeEach(() => { beforeEach(() => {
cy.goToHomePage(); cy.goToHomePage();
// redirecting to glossary page // redirecting to glossary page
cy.get( cy.get('[data-testid="appbar-item-glossary"]')
'.tw-ml-5 > [data-testid="dropdown-item"] > div > [data-testid="menu-button"]'
)
.scrollIntoView() .scrollIntoView()
.should('be.visible') .should('be.visible')
.click(); .click();
cy.get('[data-testid="menu-item-Glossaries"]').should('be.visible').click();
// Todo: need to remove below uncaught exception once tree-view error resolves // Todo: need to remove below uncaught exception once tree-view error resolves
cy.on('uncaught:exception', () => { cy.on('uncaught:exception', () => {
// return false to prevent the error from // return false to prevent the error from
@ -321,13 +318,10 @@ describe('Glossary page should work properly', () => {
addNewTagToEntity(entity, term); addNewTagToEntity(entity, term);
cy.get( cy.get('[data-testid="appbar-item-glossary"]')
'.tw-ml-5 > [data-testid="dropdown-item"] > div > [data-testid="menu-button"]'
)
.scrollIntoView() .scrollIntoView()
.should('be.visible') .should('be.visible')
.click(); .click();
cy.get('[data-testid="menu-item-Glossaries"]').should('be.visible').click();
goToAssetsTab(term); goToAssetsTab(term);
cy.get('[data-testid="column"] > :nth-child(1)') cy.get('[data-testid="column"] > :nth-child(1)')
.contains(entity) .contains(entity)
@ -377,13 +371,11 @@ describe('Glossary page should work properly', () => {
.should('be.visible') .should('be.visible')
.click(); .click();
cy.get('[data-testid="saveAssociatedTag"]').scrollIntoView().click(); cy.get('[data-testid="saveAssociatedTag"]').scrollIntoView().click();
cy.get(
'.tw-ml-5 > [data-testid="dropdown-item"] > div > [data-testid="menu-button"]' cy.get('[data-testid="appbar-item-glossary"]')
)
.scrollIntoView() .scrollIntoView()
.should('be.visible') .should('be.visible')
.click(); .click();
cy.get('[data-testid="menu-item-Glossaries"]').should('be.visible').click();
cy.wait(500); cy.wait(500);
goToAssetsTab(term); goToAssetsTab(term);
cy.get('.tableBody-cell') cy.get('.tableBody-cell')

View File

@ -17,12 +17,7 @@ import { NEW_TAG, NEW_TAG_CATEGORY, SEARCH_ENTITY_TABLE } from '../../constants/
describe('Tags page should work', () => { describe('Tags page should work', () => {
beforeEach(() => { beforeEach(() => {
cy.goToHomePage(); cy.goToHomePage();
cy.get( cy.get('[data-testid="appbar-item-tags"]').should('be.visible').click();
'.tw-ml-5 > [data-testid="dropdown-item"] > div > [data-testid="menu-button"]'
)
.should('be.visible')
.click();
cy.get('[data-testid="menu-item-Tags"]').should('be.visible').click();
}); });
it('Required Details should be available', () => { it('Required Details should be available', () => {

View File

@ -12,6 +12,7 @@
*/ */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Card } from 'antd';
import { capitalize } from 'lodash'; import { capitalize } from 'lodash';
import React from 'react'; import React from 'react';
import { TITLE_FOR_NON_ADMIN_ACTION } from '../../constants/constants'; import { TITLE_FOR_NON_ADMIN_ACTION } from '../../constants/constants';
@ -22,7 +23,7 @@ import { getActiveCatClass, getCountBadge } from '../../utils/CommonUtils';
import { getActiveUsers } from '../../utils/TeamUtils'; import { getActiveUsers } from '../../utils/TeamUtils';
import { Button } from '../buttons/Button/Button'; import { Button } from '../buttons/Button/Button';
import NonAdminAction from '../common/non-admin-action/NonAdminAction'; import NonAdminAction from '../common/non-admin-action/NonAdminAction';
import PageLayout from '../containers/PageLayout'; import PageLayout, { leftPanelAntCardStyle } from '../containers/PageLayout';
import Loader from '../Loader/Loader'; import Loader from '../Loader/Loader';
import TeamDetails from '../TeamDetails/TeamDetails'; import TeamDetails from '../TeamDetails/TeamDetails';
import UserDetails from '../UserDetails/UserDetails'; import UserDetails from '../UserDetails/UserDetails';
@ -88,104 +89,106 @@ const TeamsAndUsers = ({
*/ */
const fetchLeftPanel = () => { const fetchLeftPanel = () => {
return ( return (
<> <Card data-testid="data-summary-container" style={leftPanelAntCardStyle}>
<div className="tw-mb-8"> <>
<div <div className="tw-mb-8">
className="tw-flex tw-justify-between tw-items-center tw-mb-2 tw-border-b"
data-testid="add-team-container">
<p className="tw-heading">Teams</p>
{hasAccess && (
<NonAdminAction
position="bottom"
title={TITLE_FOR_NON_ADMIN_ACTION}>
<Button
className="tw-h-7 tw-px-2 tw-mb-4"
data-testid="add-team-button"
size="small"
theme="primary"
variant="contained"
onClick={() => {
handleAddTeam(true);
}}>
<FontAwesomeIcon icon="plus" />
</Button>
</NonAdminAction>
)}
</div>
{teams.map((team) => (
<div <div
className="tw-flex tw-items-center tw-justify-between tw-mb-2 tw-cursor-pointer" className="tw-flex tw-justify-between tw-items-center tw-mb-2 tw-border-b"
data-testid={`team-${team.name}`} data-testid="add-team-container">
key={team.name} <p className="tw-heading">Teams</p>
onClick={() => {
changeCurrentTeam(team.name, false);
}}>
<div
className={`tw-group tw-text-grey-body tw-cursor-pointer tw-text-body tw-flex tw-justify-between ${getActiveCatClass(
team.name,
currentTeam?.name
)}`}>
<p
className="tag-category label-category tw-self-center tw-truncate tw-w-52"
data-testid="team-name"
title={team.displayName ?? team.name}>
{team.displayName ?? team.name}
</p>
</div>
{getCountBadge(
getActiveUsers(team.users).length,
'',
currentTeam?.name === team.name
)}
</div>
))}
</div>
{hasAccess && (
<div>
<div className="tw-flex tw-justify-between tw-items-center tw-mb-2 tw-border-b">
<p className="tw-heading">All Users</p>
{hasAccess && ( {hasAccess && (
<NonAdminAction <NonAdminAction
position="bottom" position="bottom"
title={TITLE_FOR_NON_ADMIN_ACTION}> title={TITLE_FOR_NON_ADMIN_ACTION}>
<Button <Button
className="tw-h-7 tw-px-2 tw-mb-4" className="tw-h-7 tw-px-2 tw-mb-4"
data-testid="add-user-button" data-testid="add-team-button"
size="small" size="small"
theme="primary" theme="primary"
variant="contained" variant="contained"
onClick={handleAddNewUser}> onClick={() => {
handleAddTeam(true);
}}>
<FontAwesomeIcon icon="plus" /> <FontAwesomeIcon icon="plus" />
</Button> </Button>
</NonAdminAction> </NonAdminAction>
)} )}
</div> </div>
{usersData.map((user) => ( {teams.map((team) => (
<div <div
className="tw-flex tw-items-center tw-justify-between tw-mb-2 tw-cursor-pointer" className="tw-flex tw-items-center tw-justify-between tw-mb-2 tw-cursor-pointer"
data-testid={user.name} data-testid={`team-${team.name}`}
key={user.name} key={team.name}
onClick={() => { onClick={() => {
changeCurrentTeam(user.name, true); changeCurrentTeam(team.name, false);
}}> }}>
<div <div
className={`tw-group tw-text-grey-body tw-cursor-pointer tw-text-body tw-flex tw-justify-between ${getActiveCatClass( className={`tw-group tw-text-grey-body tw-cursor-pointer tw-text-body tw-flex tw-justify-between ${getActiveCatClass(
user.name, team.name,
activeUserTab currentTeam?.name
)}`}> )}`}>
<p <p
className="tag-category label-category tw-self-center tw-truncate tw-w-52" className="tag-category label-category tw-self-center tw-truncate tw-w-52"
data-testid="user-type" data-testid="team-name"
title={capitalize(user.name)}> title={team.displayName ?? team.name}>
{capitalize(user.name)} {team.displayName ?? team.name}
</p> </p>
</div> </div>
{getCountBadge(user.count, '', activeUserTab === user.name)} {getCountBadge(
getActiveUsers(team.users).length,
'',
currentTeam?.name === team.name
)}
</div> </div>
))} ))}
</div> </div>
)} {hasAccess && (
</> <div>
<div className="tw-flex tw-justify-between tw-items-center tw-mb-2 tw-border-b">
<p className="tw-heading">All Users</p>
{hasAccess && (
<NonAdminAction
position="bottom"
title={TITLE_FOR_NON_ADMIN_ACTION}>
<Button
className="tw-h-7 tw-px-2 tw-mb-4"
data-testid="add-user-button"
size="small"
theme="primary"
variant="contained"
onClick={handleAddNewUser}>
<FontAwesomeIcon icon="plus" />
</Button>
</NonAdminAction>
)}
</div>
{usersData.map((user) => (
<div
className="tw-flex tw-items-center tw-justify-between tw-mb-2 tw-cursor-pointer"
data-testid={user.name}
key={user.name}
onClick={() => {
changeCurrentTeam(user.name, true);
}}>
<div
className={`tw-group tw-text-grey-body tw-cursor-pointer tw-text-body tw-flex tw-justify-between ${getActiveCatClass(
user.name,
activeUserTab
)}`}>
<p
className="tag-category label-category tw-self-center tw-truncate tw-w-52"
data-testid="user-type"
title={capitalize(user.name)}>
{capitalize(user.name)}
</p>
</div>
{getCountBadge(user.count, '', activeUserTab === user.name)}
</div>
))}
</div>
)}
</>
</Card>
); );
}; };
@ -195,8 +198,9 @@ const TeamsAndUsers = ({
<Loader /> <Loader />
) : ( ) : (
<div <div
className="tw-pb-3 tw-w-full tw-h-full tw-flex tw-flex-col" className="tw-pb-3 tw-w-full tw-h-full tw-flex tw-flex-col tw-bg-white"
data-testid="team-and-user-container"> data-testid="team-and-user-container"
style={{ padding: '14px' }}>
{!isTeamVisible ? ( {!isTeamVisible ? (
<UserDetails <UserDetails
currentUserPage={currentUserPage} currentUserPage={currentUserPage}

View File

@ -11,6 +11,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Card } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { cloneDeep, isNil, startCase } from 'lodash'; import { cloneDeep, isNil, startCase } from 'lodash';
import React, { FunctionComponent, useEffect, useState } from 'react'; import React, { FunctionComponent, useEffect, useState } from 'react';
@ -25,7 +26,7 @@ import ErrorPlaceHolder from '../common/error-with-placeholder/ErrorPlaceHolder'
import NextPrevious from '../common/next-previous/NextPrevious'; import NextPrevious from '../common/next-previous/NextPrevious';
import NonAdminAction from '../common/non-admin-action/NonAdminAction'; import NonAdminAction from '../common/non-admin-action/NonAdminAction';
import WebhookDataCard from '../common/webhook-data-card/WebhookDataCard'; import WebhookDataCard from '../common/webhook-data-card/WebhookDataCard';
import PageLayout from '../containers/PageLayout'; import PageLayout, { leftPanelAntCardStyle } from '../containers/PageLayout';
import { WebhooksProps } from './Webhooks.interface'; import { WebhooksProps } from './Webhooks.interface';
const statuses = [ const statuses = [
@ -86,55 +87,57 @@ const Webhooks: FunctionComponent<WebhooksProps> = ({
const fetchLeftPanel = () => { const fetchLeftPanel = () => {
return ( return (
<> <Card data-testid="data-summary-container" style={leftPanelAntCardStyle}>
<h6 className="tw-heading tw-text-base">Webhooks</h6> <>
<div className="tw-flex tw-justify-between tw-flex-col"> <h6 className="tw-heading tw-text-base">Webhooks</h6>
<h6 className="tw-heading tw-mb-0" data-testid="filter-heading"> <div className="tw-flex tw-justify-between tw-flex-col">
Status <h6 className="tw-heading tw-mb-0" data-testid="filter-heading">
</h6> Status
<div className="tw-flex tw-mt-2" /> </h6>
</div> <div className="tw-flex tw-mt-2" />
<div </div>
className="sidebar-my-data-holder" <div
data-testid="filter-containers-1"> className="sidebar-my-data-holder"
{statuses.map((statusType, index) => ( data-testid="filter-containers-1">
<div {statuses.map((statusType, index) => (
className="filter-group tw-justify-between tw-mb-3" <div
data-testid={`status-type-${statusType.value}`} className="filter-group tw-justify-between tw-mb-3"
key={index}> data-testid={`status-type-${statusType.value}`}
<div className="tw-flex"> key={index}>
<input <div className="tw-flex">
checked={selectedStatus.includes(statusType.value)} <input
className="tw-mr-1 custom-checkbox" checked={selectedStatus.includes(statusType.value)}
data-testid="checkbox" className="tw-mr-1 custom-checkbox"
type="checkbox" data-testid="checkbox"
onChange={() => { type="checkbox"
handleStatusSelection(statusType.value); onChange={() => {
}} handleStatusSelection(statusType.value);
/> }}
<div />
className="tw-flex tw-items-center filters-title tw-truncate custom-checkbox-label" <div
data-testid="checkbox-label"> className="tw-flex tw-items-center filters-title tw-truncate custom-checkbox-label"
<div className="tw-ml-1">{statusType.name}</div> data-testid="checkbox-label">
<div className="tw-ml-1">{statusType.name}</div>
</div>
</div> </div>
</div> </div>
</div> ))}
))} </div>
</div> </>
</> </Card>
); );
}; };
const fetchRightPanel = () => { const fetchRightPanel = () => {
return ( return (
<> <Card data-testid="data-summary-container" style={leftPanelAntCardStyle}>
<div className="tw-mb-5 tw-mt-11"> <div className="tw-my-2">
The webhook allows external services to be notified of the metadata The webhook allows external services to be notified of the metadata
change events happening in your organization through APIs. Register change events happening in your organization through APIs. Register
callback URLs with webhook integration to receive metadata event callback URLs with webhook integration to receive metadata event
notifications. You can add, list, update, and delete webhooks. notifications. You can add, list, update, and delete webhooks.
</div> </div>
</> </Card>
); );
}; };
@ -167,7 +170,7 @@ const Webhooks: FunctionComponent<WebhooksProps> = ({
return data.length ? ( return data.length ? (
<PageLayout leftPanel={fetchLeftPanel()} rightPanel={fetchRightPanel()}> <PageLayout leftPanel={fetchLeftPanel()} rightPanel={fetchRightPanel()}>
<div> <div className="tw-bg-white" style={{ padding: '14px' }}>
{filteredData.length ? ( {filteredData.length ? (
<> <>
<div className="tw-flex tw-justify-end tw-items-center"> <div className="tw-flex tw-justify-end tw-items-center">

View File

@ -24,6 +24,14 @@ interface PageLayoutProp {
classes?: string; classes?: string;
} }
export const leftPanelAntCardStyle = {
border: '1px rgb(221, 227, 234) solid',
borderRadius: '8px',
boxShadow: '1px 1px 6px rgb(0 0 0 / 12%)',
marginRight: '4px',
marginLeft: '4px',
};
const PageLayout: FC<PageLayoutProp> = ({ const PageLayout: FC<PageLayoutProp> = ({
leftPanel, leftPanel,
header, header,

View File

@ -134,7 +134,7 @@ const DropDown: React.FC<DropDownProp> = ({
{isDropDownIconVisible ? ( {isDropDownIconVisible ? (
<DropdownIcon <DropdownIcon
style={{ marginTop: '7px', color: normalLink }} style={{ marginTop: '5px', color: normalLink }}
/> />
) : null} ) : null}
</> </>

View File

@ -89,6 +89,26 @@ const NavBar = ({
label="Settings" label="Settings"
type="link" type="link"
/> />
<NavLink
className="tw-nav focus:tw-no-underline"
data-testid="appbar-item-glossary"
id="glossary"
style={navStyle(pathname.startsWith('/glossary'))}
to={{
pathname: '/glossary',
}}>
Glossaries
</NavLink>
<NavLink
className="tw-nav focus:tw-no-underline"
data-testid="appbar-item-tags"
id="tags"
style={navStyle(pathname.startsWith('/tags'))}
to={{
pathname: '/tags',
}}>
Tags
</NavLink>
</div> </div>
</div> </div>
<div <div

View File

@ -417,10 +417,8 @@ export const navLinkSettings = [
disabled: false, disabled: false,
isAdminOnly: true, isAdminOnly: true,
}, },
{ name: 'Glossaries', to: '/glossary', disabled: false },
{ name: 'Roles', to: '/roles', disabled: false, isAdminOnly: true }, { name: 'Roles', to: '/roles', disabled: false, isAdminOnly: true },
{ name: 'Services', to: '/services', disabled: false }, { name: 'Services', to: '/services', disabled: false },
{ name: 'Tags', to: '/tags', disabled: false },
{ {
name: 'Teams & Users', name: 'Teams & Users',
to: ROUTES.TEAMS_AND_USERS, to: ROUTES.TEAMS_AND_USERS,

View File

@ -11,6 +11,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Card } from 'antd';
import { AxiosError, AxiosResponse } from 'axios'; import { AxiosError, AxiosResponse } from 'axios';
import classNames from 'classnames'; import classNames from 'classnames';
import { compare } from 'fast-json-patch'; import { compare } from 'fast-json-patch';
@ -37,7 +38,9 @@ import Description from '../../components/common/description/Description';
import ErrorPlaceHolder from '../../components/common/error-with-placeholder/ErrorPlaceHolder'; import ErrorPlaceHolder from '../../components/common/error-with-placeholder/ErrorPlaceHolder';
import NonAdminAction from '../../components/common/non-admin-action/NonAdminAction'; import NonAdminAction from '../../components/common/non-admin-action/NonAdminAction';
import PageContainerV1 from '../../components/containers/PageContainerV1'; import PageContainerV1 from '../../components/containers/PageContainerV1';
import PageLayout from '../../components/containers/PageLayout'; import PageLayout, {
leftPanelAntCardStyle,
} from '../../components/containers/PageLayout';
import Loader from '../../components/Loader/Loader'; import Loader from '../../components/Loader/Loader';
import ConfirmationModal from '../../components/Modals/ConfirmationModal/ConfirmationModal'; import ConfirmationModal from '../../components/Modals/ConfirmationModal/ConfirmationModal';
import AddRoleModal from '../../components/Modals/RoleModal/AddRoleModal'; import AddRoleModal from '../../components/Modals/RoleModal/AddRoleModal';
@ -579,33 +582,39 @@ const RolesPage = () => {
const fetchLeftPanel = (roles: Array<Role>) => { const fetchLeftPanel = (roles: Array<Role>) => {
return ( return (
<Fragment> <Card
<div className="tw-flex tw-justify-between tw-items-center tw-mb-3 tw-border-b"> data-testid="data-summary-container"
<h6 style={leftPanelAntCardStyle}
className="tw-heading tw-text-base" title={
data-testid="left-panel-title"> <div className="tw-flex tw-justify-between tw-items-center">
Roles <h6
</h6> className="tw-heading tw-text-base"
</div> data-testid="left-panel-title">
{roles && Roles
roles.map((role) => ( </h6>
<div </div>
className={`tw-group tw-text-grey-body tw-cursor-pointer tw-text-body tw-mb-3 tw-flex tw-justify-between ${getActiveCatClass( }>
role.name, <Fragment>
currentRole?.name {roles &&
)}`} roles.map((role) => (
data-testid="role-name-container" <div
key={role.name} className={`tw-group tw-text-grey-body tw-cursor-pointer tw-text-body tw-mb-3 tw-flex tw-justify-between ${getActiveCatClass(
onClick={() => setCurrentRole(role)}> role.name,
<p currentRole?.name
className="tag-category label-category tw-self-center tw-truncate tw-w-52" )}`}
title={role.displayName}> data-testid="role-name-container"
<span>{role.displayName}</span>{' '} key={role.name}
</p> onClick={() => setCurrentRole(role)}>
{role.defaultRole ? getDefaultBadge() : null} <span
</div> className="tag-category label-category tw-self-center tw-truncate tw-w-52"
))} title={role.displayName}>
</Fragment> <span>{role.displayName}</span>{' '}
</span>
{role.defaultRole ? getDefaultBadge() : null}
</div>
))}
</Fragment>
</Card>
); );
}; };
@ -1113,7 +1122,10 @@ const RolesPage = () => {
{isLoading ? ( {isLoading ? (
<Loader /> <Loader />
) : ( ) : (
<div className="tw-pb-3" data-testid="role-container"> <div
className="tw-pb-3 tw-bg-white"
data-testid="role-container"
style={{ padding: '14px' }}>
{getRolesContainer()} {getRolesContainer()}
{getAddRoleForm()} {getAddRoleForm()}

View File

@ -11,6 +11,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Card } from 'antd';
import { AxiosError, AxiosResponse } from 'axios'; import { AxiosError, AxiosResponse } from 'axios';
import classNames from 'classnames'; import classNames from 'classnames';
import { isNil } from 'lodash'; import { isNil } from 'lodash';
@ -25,7 +26,9 @@ import NextPrevious from '../../components/common/next-previous/NextPrevious';
import NonAdminAction from '../../components/common/non-admin-action/NonAdminAction'; import NonAdminAction from '../../components/common/non-admin-action/NonAdminAction';
import RichTextEditorPreviewer from '../../components/common/rich-text-editor/RichTextEditorPreviewer'; import RichTextEditorPreviewer from '../../components/common/rich-text-editor/RichTextEditorPreviewer';
import PageContainerV1 from '../../components/containers/PageContainerV1'; import PageContainerV1 from '../../components/containers/PageContainerV1';
import PageLayout from '../../components/containers/PageLayout'; import PageLayout, {
leftPanelAntCardStyle,
} from '../../components/containers/PageLayout';
import Loader from '../../components/Loader/Loader'; import Loader from '../../components/Loader/Loader';
import { import {
getServiceDetailsPath, getServiceDetailsPath,
@ -231,36 +234,41 @@ const ServicesPage = () => {
const fetchLeftPanel = () => { const fetchLeftPanel = () => {
return ( return (
<> <Card
<div className="tw-flex tw-justify-between tw-items-center tw-mb-3 tw-border-b"> data-testid="data-summary-container"
<h6 className="tw-heading tw-text-base">Services</h6> style={leftPanelAntCardStyle}
</div> title={
<div className="tw-flex tw-justify-between tw-items-center">
<h6 className="tw-heading tw-text-base">Services</h6>
</div>
}>
<>
{getServiceTabs()?.map((tab, index) => {
return (
<div
className={`tw-group tw-text-grey-body tw-cursor-pointer tw-text-body tw-mb-3 tw-flex tw-justify-between ${getActiveCatClass(
tab.name,
serviceName
)}`}
data-testid="tab"
key={index}
onClick={() => {
handleTabChange(tab.name);
}}>
<p className="tw-text-center tw-self-center label-category">
{tab.displayName}
</p>
{getServiceTabs()?.map((tab, index) => { {getCountBadge(
return ( servicesCount[tab.name],
<div 'tw-self-center',
className={`tw-group tw-text-grey-body tw-cursor-pointer tw-text-body tw-mb-3 tw-flex tw-justify-between ${getActiveCatClass( tab.name === serviceName
tab.name, )}
serviceName </div>
)}`} );
data-testid="tab" })}
key={index} </>
onClick={() => { </Card>
handleTabChange(tab.name);
}}>
<p className="tw-text-center tw-self-center label-category">
{tab.displayName}
</p>
{getCountBadge(
servicesCount[tab.name],
'tw-self-center',
tab.name === serviceName
)}
</div>
);
})}
</>
); );
}; };
@ -406,53 +414,56 @@ const ServicesPage = () => {
className="tw-grid xl:tw-grid-cols-4 tw-grid-cols-2 tw-gap-4 tw-mb-4" className="tw-grid xl:tw-grid-cols-4 tw-grid-cols-2 tw-gap-4 tw-mb-4"
data-testid="data-container"> data-testid="data-container">
{serviceList.map((service, index) => ( {serviceList.map((service, index) => (
<div <Card key={index} style={leftPanelAntCardStyle}>
className="tw-card tw-flex tw-py-2 tw-px-3 tw-justify-between tw-text-grey-muted" <div
data-testid="service-card" className="tw-flex tw-py-2 tw-px-3 tw-justify-between tw-text-grey-muted"
key={index}> data-testid="service-card">
<div className="tw-flex tw-flex-col tw-justify-between tw-truncate"> <div className="tw-flex tw-flex-col tw-justify-between tw-truncate">
<div> <div>
<Link to={getServiceDetailsPath(service.name, serviceName)}> <Link to={getServiceDetailsPath(service.name, serviceName)}>
<button> <button>
<h6 <h6
className="tw-text-base tw-text-grey-body tw-font-medium tw-text-left tw-truncate tw-w-48" className="tw-text-base tw-text-grey-body tw-font-medium tw-text-left tw-truncate tw-w-48"
data-testid={`service-name-${getEntityName( data-testid={`service-name-${getEntityName(
service as EntityReference service as EntityReference
)}`} )}`}
title={getEntityName(service as EntityReference)}> title={getEntityName(service as EntityReference)}>
{getEntityName(service as EntityReference)} {getEntityName(service as EntityReference)}
</h6> </h6>
</button> </button>
</Link> </Link>
<div <div
className="tw-text-grey-body tw-pb-1 tw-break-all description-text" className="tw-text-grey-body tw-pb-1 tw-break-all description-text"
data-testid="service-description"> data-testid="service-description">
{service.description ? ( {service.description ? (
<RichTextEditorPreviewer <RichTextEditorPreviewer
enableSeeMoreVariant={false} enableSeeMoreVariant={false}
markdown={service.description} markdown={service.description}
/> />
) : ( ) : (
<span className="tw-no-description">No description</span> <span className="tw-no-description">
)} No description
</span>
)}
</div>
{getOptionalFields(service)}
</div>
<div className="" data-testid="service-type">
<label className="tw-mb-0">Type:</label>
<span className=" tw-ml-1 tw-font-normal tw-text-grey-body">
{service.serviceType}
</span>
</div> </div>
{getOptionalFields(service)}
</div> </div>
<div className="" data-testid="service-type"> <div className="tw-flex tw-flex-col tw-justify-between tw-flex-none">
<label className="tw-mb-0">Type:</label> <div
<span className=" tw-ml-1 tw-font-normal tw-text-grey-body"> className="tw-flex tw-justify-end"
{service.serviceType} data-testid="service-icon">
</span> {getServiceLogo(service.serviceType || '', 'tw-h-8')}
</div>
</div> </div>
</div> </div>
<div className="tw-flex tw-flex-col tw-justify-between tw-flex-none"> </Card>
<div
className="tw-flex tw-justify-end"
data-testid="service-icon">
{getServiceLogo(service.serviceType || '', 'tw-h-8')}
</div>
</div>
</div>
))} ))}
</div> </div>
</Fragment> </Fragment>
@ -490,7 +501,7 @@ const ServicesPage = () => {
<ErrorPlaceHolder>{errorMessage}</ErrorPlaceHolder> <ErrorPlaceHolder>{errorMessage}</ErrorPlaceHolder>
) : ( ) : (
<PageLayout leftPanel={fetchLeftPanel()}> <PageLayout leftPanel={fetchLeftPanel()}>
<div data-testid="services-container"> <div data-testid="services-container" style={{ padding: '14px' }}>
{getServiceList()} {getServiceList()}
{getPagination()} {getPagination()}

View File

@ -12,6 +12,7 @@
*/ */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Card } from 'antd';
import { AxiosError, AxiosResponse } from 'axios'; import { AxiosError, AxiosResponse } from 'axios';
import classNames from 'classnames'; import classNames from 'classnames';
import { isUndefined, toLower } from 'lodash'; import { isUndefined, toLower } from 'lodash';
@ -34,7 +35,9 @@ import ErrorPlaceHolder from '../../components/common/error-with-placeholder/Err
import NonAdminAction from '../../components/common/non-admin-action/NonAdminAction'; import NonAdminAction from '../../components/common/non-admin-action/NonAdminAction';
import RichTextEditorPreviewer from '../../components/common/rich-text-editor/RichTextEditorPreviewer'; import RichTextEditorPreviewer from '../../components/common/rich-text-editor/RichTextEditorPreviewer';
import PageContainerV1 from '../../components/containers/PageContainerV1'; import PageContainerV1 from '../../components/containers/PageContainerV1';
import PageLayout from '../../components/containers/PageLayout'; import PageLayout, {
leftPanelAntCardStyle,
} from '../../components/containers/PageLayout';
import Loader from '../../components/Loader/Loader'; import Loader from '../../components/Loader/Loader';
import ConfirmationModal from '../../components/Modals/ConfirmationModal/ConfirmationModal'; import ConfirmationModal from '../../components/Modals/ConfirmationModal/ConfirmationModal';
import FormModal from '../../components/Modals/FormModal'; import FormModal from '../../components/Modals/FormModal';
@ -397,52 +400,56 @@ const TagsPage = () => {
const fetchLeftPanel = () => { const fetchLeftPanel = () => {
return ( return (
<> <Card data-testid="data-summary-container" style={leftPanelAntCardStyle}>
<div className="tw-flex tw-justify-between tw-items-center tw-mb-3 tw-border-b"> <>
<h6 className="tw-heading tw-text-base">Tag Categories</h6> <div className="tw-flex tw-justify-between tw-items-center tw-mb-3 tw-border-b">
<NonAdminAction position="bottom" title={TITLE_FOR_NON_ADMIN_ACTION}> <h6 className="tw-heading tw-text-base">Tag Categories</h6>
<Button <NonAdminAction
className={classNames('tw-h-7 tw-px-2 tw-mb-4', { position="bottom"
'tw-opacity-40': !isAdminUser && !isAuthDisabled, title={TITLE_FOR_NON_ADMIN_ACTION}>
})} <Button
data-testid="add-category" className={classNames('tw-h-7 tw-px-2 tw-mb-4', {
size="small" 'tw-opacity-40': !isAdminUser && !isAuthDisabled,
theme="primary" })}
variant="contained" data-testid="add-category"
onClick={() => { size="small"
setIsAddingCategory((prevState) => !prevState); theme="primary"
setErrorDataCategory(undefined); variant="contained"
}}> onClick={() => {
<FontAwesomeIcon icon="plus" /> setIsAddingCategory((prevState) => !prevState);
</Button> setErrorDataCategory(undefined);
</NonAdminAction> }}>
</div> <FontAwesomeIcon icon="plus" />
{categories && </Button>
categories.map((category: TagCategory) => ( </NonAdminAction>
<div </div>
className={`tw-group tw-text-grey-body tw-cursor-pointer tw-text-body tw-mb-3 tw-flex tw-justify-between ${getActiveCatClass( {categories &&
category.name, categories.map((category: TagCategory) => (
currentCategory?.name <div
)}`} className={`tw-group tw-text-grey-body tw-cursor-pointer tw-text-body tw-mb-3 tw-flex tw-justify-between ${getActiveCatClass(
data-testid="side-panel-category" category.name,
key={category.name} currentCategory?.name
onClick={() => { )}`}
fetchCurrentCategory(category.name); data-testid="side-panel-category"
}}> key={category.name}
<p className="tw-text-center tw-self-center tag-category label-category"> onClick={() => {
{category.displayName ?? category.name} fetchCurrentCategory(category.name);
</p> }}>
<p className="tw-text-center tw-self-center tag-category label-category">
{category.displayName ?? category.name}
</p>
{getCountBadge( {getCountBadge(
currentCategory?.name === category.name currentCategory?.name === category.name
? currentCategory.children?.length ? currentCategory.children?.length
: category.children?.length || 0, : category.children?.length || 0,
'tw-self-center', 'tw-self-center',
currentCategory?.name === category.name currentCategory?.name === category.name
)} )}
</div> </div>
))} ))}
</> </>
</Card>
); );
}; };
@ -458,7 +465,10 @@ const TagsPage = () => {
{isLoading ? ( {isLoading ? (
<Loader /> <Loader />
) : ( ) : (
<div className="full-height" data-testid="tags-container"> <div
className="full-height tw-bg-white"
data-testid="tags-container"
style={{ padding: '14px' }}>
{currentCategory && ( {currentCategory && (
<div <div
className="tw-flex tw-justify-between tw-items-center" className="tw-flex tw-justify-between tw-items-center"