diff --git a/frontend/resourceadm/components/ResourceAdmHeader/ResourceAdmHeader.tsx b/frontend/resourceadm/components/ResourceAdmHeader/ResourceAdmHeader.tsx index ff7c2ae54e6..ef2a6fee178 100644 --- a/frontend/resourceadm/components/ResourceAdmHeader/ResourceAdmHeader.tsx +++ b/frontend/resourceadm/components/ResourceAdmHeader/ResourceAdmHeader.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import classes from './ResourceAdmHeader.module.css'; import { useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { @@ -15,6 +16,7 @@ import { useLogoutMutation } from 'app-shared/hooks/mutations/useLogoutMutation' import type { User } from 'app-shared/types/Repository'; import { useUrlParams } from '../../hooks/useUrlParams'; import { getAppName } from '../../utils/stringUtils'; +import { GiteaHeader } from 'app-shared/components/GiteaHeader'; interface ResourceAdmHeaderProps { organizations: Organization[]; @@ -34,6 +36,9 @@ export const ResourceAdmHeader = ({ organizations, user }: ResourceAdmHeaderProp + + + ); }; diff --git a/frontend/resourceadm/pages/PageLayout/PageLayout.module.css b/frontend/resourceadm/components/ResourceAdmHeader/ResourceaAdmHeader.module.css similarity index 100% rename from frontend/resourceadm/pages/PageLayout/PageLayout.module.css rename to frontend/resourceadm/components/ResourceAdmHeader/ResourceaAdmHeader.module.css diff --git a/frontend/resourceadm/context/HeaderContext/HeaderContext.tsx b/frontend/resourceadm/context/HeaderContext/HeaderContext.tsx new file mode 100644 index 00000000000..b919d6f9912 --- /dev/null +++ b/frontend/resourceadm/context/HeaderContext/HeaderContext.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { type Organization } from 'app-shared/types/Organization'; +import { type User } from 'app-shared/types/Repository'; + +export enum SelectedContextType { + All = 'all', + Self = 'self', + None = 'none', +} + +export type HeaderContextType = { + selectableOrgs?: Organization[]; + user: User; +}; + +export const HeaderContext = React.createContext({ + selectableOrgs: undefined, + user: undefined, +}); diff --git a/frontend/resourceadm/context/HeaderContext/index.ts b/frontend/resourceadm/context/HeaderContext/index.ts new file mode 100644 index 00000000000..ec5587f9307 --- /dev/null +++ b/frontend/resourceadm/context/HeaderContext/index.ts @@ -0,0 +1 @@ +export { HeaderContext, type HeaderContextType, SelectedContextType } from './HeaderContext'; diff --git a/frontend/resourceadm/pages/PageLayout/PageLayout.tsx b/frontend/resourceadm/pages/PageLayout/PageLayout.tsx index 76600ed2b19..9ce62c6d9a4 100644 --- a/frontend/resourceadm/pages/PageLayout/PageLayout.tsx +++ b/frontend/resourceadm/pages/PageLayout/PageLayout.tsx @@ -1,10 +1,8 @@ import React, { useEffect, useRef } from 'react'; -import classes from './PageLayout.module.css'; import { Outlet, useLocation, useNavigate } from 'react-router-dom'; import { userHasAccessToOrganization } from '../../utils/userUtils'; import { useOrganizationsQuery } from '../../hooks/queries'; import { useRepoStatusQuery, useUserQuery } from 'app-shared/hooks/queries'; -import { GiteaHeader } from 'app-shared/components/GiteaHeader'; import { useUrlParams } from '../../hooks/useUrlParams'; import postMessages from 'app-shared/utils/postMessages'; import { MergeConflictModal } from '../../components/MergeConflictModal'; @@ -63,7 +61,6 @@ export const PageLayout = (): React.JSX.Element => { <> {organizations && user && } - ); diff --git a/frontend/resourceadm/utils/userUtils/userUtils.test.ts b/frontend/resourceadm/utils/userUtils/userUtils.test.ts index 081c8e62100..da463685fd7 100644 --- a/frontend/resourceadm/utils/userUtils/userUtils.test.ts +++ b/frontend/resourceadm/utils/userUtils/userUtils.test.ts @@ -1,60 +1,106 @@ -import { SelectedContextType } from 'app-shared/navigation/main-header/Header'; -import { userHasAccessToOrganization } from './index'; +import { SelectedContextType } from 'resourceadm/context/HeaderContext'; +import { getOrgNameByUsername, userHasAccessToOrganization } from './userUtils'; +import { type Organization } from 'app-shared/types/Organization'; -describe('userHasAccessToOrganization', () => { - it('should return true when context is self', () => { - const result = userHasAccessToOrganization({ - org: SelectedContextType.Self, - orgs: [], +const mockOrg1: Organization = { + avatar_url: '', + id: 12, + username: 'ttd', + full_name: 'Test', +}; +const mockOrg2: Organization = { + avatar_url: '', + id: 23, + username: 'unit-test-2', + full_name: 'unit-test-2', +}; +const mockOrganizations: Organization[] = [mockOrg1, mockOrg2]; + +describe('userUtils', () => { + describe('userHasAccessToOrganization', () => { + it('should return true when context is self', () => { + const result = userHasAccessToOrganization({ + org: SelectedContextType.Self, + orgs: [], + }); + + expect(result).toBe(true); }); - expect(result).toBe(true); - }); + it('should return true when context is all', () => { + const result = userHasAccessToOrganization({ + org: SelectedContextType.All, + orgs: [], + }); - it('should return true when context is all', () => { - const result = userHasAccessToOrganization({ - org: SelectedContextType.All, - orgs: [], + expect(result).toBe(true); }); - expect(result).toBe(true); - }); + it('should return true when context id is present in orgs list', () => { + const result = userHasAccessToOrganization({ + org: 'username1', + orgs: [ + { + avatar_url: 'avatar_url', + description: '', + full_name: 'full_name', + id: 1, + location: '', + username: 'username1', + website: '', + }, + ], + }); - it('should return true when context id is present in orgs list', () => { - const result = userHasAccessToOrganization({ - org: 'username1', - orgs: [ - { - avatar_url: 'avatar_url', - description: '', - full_name: 'full_name', - id: 1, - location: '', - username: 'username1', - website: '', - }, - ], - }); - - expect(result).toBe(true); + expect(result).toBe(true); + }); + + it('should return false when context id is not present in orgs list', () => { + const result = userHasAccessToOrganization({ + org: 'username2', + orgs: [ + { + avatar_url: 'avatar_url', + description: '', + full_name: 'full_name', + id: 1, + location: '', + username: 'username', + website: '', + }, + ], + }); + + expect(result).toBe(false); + }); }); - it('should return false when context id is not present in orgs list', () => { - const result = userHasAccessToOrganization({ - org: 'username2', - orgs: [ - { - avatar_url: 'avatar_url', - description: '', - full_name: 'full_name', - id: 1, - location: '', - username: 'username', - website: '', - }, - ], - }); - - expect(result).toBe(false); + describe('getOrgNameByUsername', () => { + it('should return the full name of the organization when a matching username is found', () => { + const result = getOrgNameByUsername(mockOrg1.username, mockOrganizations); + expect(result).toBe(mockOrg1.full_name); + }); + + it('should return the username if full name is not available', () => { + const mockOrg3: Organization = { + username: 'org3', + full_name: '', + id: 12, + avatar_url: '', + }; + const orgsWithoutFullName: Organization[] = [mockOrg3]; + const result = getOrgNameByUsername(mockOrg3.username, orgsWithoutFullName); + expect(result).toBe(mockOrg3.username); + }); + + it('should return undefined if the organization is not found', () => { + const result = getOrgNameByUsername('nonexistent-org', mockOrganizations); + expect(result).toBeUndefined(); + }); + + it('should return undefined if orgs array is undefined', () => { + const result = getOrgNameByUsername(mockOrg1.username, undefined); + expect(result).toBeUndefined(); + }); }); }); diff --git a/frontend/resourceadm/utils/userUtils/userUtils.ts b/frontend/resourceadm/utils/userUtils/userUtils.ts index 9373106c2b9..3ca2ede3737 100644 --- a/frontend/resourceadm/utils/userUtils/userUtils.ts +++ b/frontend/resourceadm/utils/userUtils/userUtils.ts @@ -1,4 +1,4 @@ -import { SelectedContextType } from 'app-shared/navigation/main-header/Header'; +import { SelectedContextType } from 'resourceadm/context/HeaderContext'; import type { Organization } from 'app-shared/types/Organization'; export const userHasAccessToOrganization = ({