Skip to content

Commit a4a8626

Browse files
authored
Merge pull request #1301 from topcoder-platform/dev
Topgear Iterative Reviewer visibility fix
2 parents c958bd7 + bd29900 commit a4a8626

File tree

6 files changed

+316
-38
lines changed

6 files changed

+316
-38
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@
109109
"sass": "^1.79.0",
110110
"styled-components": "^5.3.6",
111111
"swr": "^1.3.0",
112-
"tc-auth-lib": "topcoder-platform/tc-auth-lib#1.0.27",
112+
"tc-auth-lib": "topcoder-platform/tc-auth-lib#master",
113113
"tinymce": "^7.9.1",
114114
"typescript": "^4.8.4",
115115
"universal-navigation": "https://github.com/topcoder-platform/universal-navigation#9fc50d938be7182",

src/apps/admin/src/permission-management/PermissionGroupsPage/PermissionGroupsPage.module.scss

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,29 @@
1919
text-align: center;
2020
}
2121

22-
.btnNewGroup {
23-
margin: $sp-8 $sp-8 $sp-4 $sp-8;
22+
.actions {
23+
display: flex;
24+
align-items: flex-end;
25+
gap: $sp-4;
26+
margin: $sp-8 $sp-8 $sp-4;
2427

2528
@include ltelg {
29+
flex-direction: column;
30+
align-items: stretch;
2631
margin: $sp-4;
32+
gap: $sp-3;
33+
}
34+
}
35+
36+
.searchField {
37+
flex: 1;
38+
}
39+
40+
.btnNewGroup {
41+
margin: 0;
42+
min-width: max-content;
43+
44+
@include ltelg {
45+
width: 100%;
2746
}
2847
}

src/apps/admin/src/permission-management/PermissionGroupsPage/PermissionGroupsPage.tsx

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/**
22
* Permission groups page.
33
*/
4-
import { FC, useContext, useState } from 'react'
4+
import { ChangeEvent, FC, useContext, useMemo, useState } from 'react'
55
import classNames from 'classnames'
66

7-
import { Button, LoadingSpinner, PageTitle } from '~/libs/ui'
7+
import { Button, InputText, LoadingSpinner, PageTitle } from '~/libs/ui'
88
import { PlusIcon } from '@heroicons/react/solid'
99

1010
import { DialogAddGroup } from '../../lib/components/DialogAddGroup'
@@ -24,6 +24,7 @@ const pageTitle = 'Groups'
2424

2525
export const PermissionGroupsPage: FC<Props> = (props: Props) => {
2626
const [openDialogAddGroup, setOpenDialogAddGroup] = useState(false)
27+
const [searchTerm, setSearchTerm] = useState('')
2728
const { loadUser, cancelLoadUser, usersMapping }: AdminAppContextType
2829
= useContext(AdminAppContext)
2930
const {
@@ -37,6 +38,26 @@ export const PermissionGroupsPage: FC<Props> = (props: Props) => {
3738
usersMapping,
3839
)
3940

41+
const filteredGroups = useMemo(() => {
42+
const normalized = searchTerm
43+
.trim()
44+
.toLowerCase()
45+
if (!normalized) {
46+
return groups
47+
}
48+
49+
return groups.filter(group => {
50+
const id = group.id ? group.id.toLowerCase() : ''
51+
const name = group.name ? group.name.toLowerCase() : ''
52+
53+
return id.includes(normalized) || name.includes(normalized)
54+
})
55+
}, [groups, searchTerm])
56+
const hasSearchTerm = useMemo(
57+
() => searchTerm.trim().length > 0,
58+
[searchTerm],
59+
)
60+
4061
return (
4162
<div className={classNames(styles.container, props.className)}>
4263
<PageTitle>{pageTitle}</PageTitle>
@@ -51,24 +72,40 @@ export const PermissionGroupsPage: FC<Props> = (props: Props) => {
5172
</div>
5273
) : (
5374
<>
54-
<Button
55-
primary
56-
size='lg'
57-
icon={PlusIcon}
58-
iconToLeft
59-
label='new group'
60-
onClick={function onClick() {
61-
setOpenDialogAddGroup(true)
62-
}}
63-
className={styles.btnNewGroup}
64-
/>
65-
{groups.length === 0 ? (
75+
<div className={styles.actions}>
76+
<InputText
77+
name='groupSearch'
78+
type='text'
79+
label='Search groups'
80+
placeholder='Search by name or ID'
81+
value={searchTerm}
82+
onChange={function onChange(event: ChangeEvent<HTMLInputElement>) {
83+
setSearchTerm(event.target.value)
84+
}}
85+
forceUpdateValue
86+
classNameWrapper={styles.searchField}
87+
/>
88+
<Button
89+
primary
90+
size='lg'
91+
icon={PlusIcon}
92+
iconToLeft
93+
label='new group'
94+
onClick={function onClick() {
95+
setOpenDialogAddGroup(true)
96+
}}
97+
className={styles.btnNewGroup}
98+
/>
99+
</div>
100+
{filteredGroups.length === 0 ? (
66101
<p className={styles.noRecordFound}>
67-
{MSG_NO_RECORD_FOUND}
102+
{hasSearchTerm
103+
? 'No groups match your search.'
104+
: MSG_NO_RECORD_FOUND}
68105
</p>
69106
) : (
70107
<GroupsTable
71-
datas={groups}
108+
datas={filteredGroups}
72109
usersMapping={usersMapping}
73110
/>
74111
)}

src/apps/review/src/lib/components/ChallengeDetailsContent/ChallengeDetailsContent.tsx

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { ActionLoading } from '~/apps/admin/src/lib'
99
import { ChallengeDetailContext } from '../../contexts'
1010
import {
1111
BackendSubmission,
12-
ChallengeInfo,
12+
ChallengeDetailContextModel,
1313
MappingReviewAppeal,
1414
Screening,
1515
SubmissionInfo,
@@ -120,6 +120,7 @@ const buildScreeningRows = ({
120120

121121
interface SubmissionTabParams {
122122
selectedTabNormalized: string
123+
allowTopgearSubmissionList: boolean
123124
submissions: BackendSubmission[]
124125
screeningRows: Screening[]
125126
screeningMinimumPassingScore: number | null | undefined
@@ -131,6 +132,7 @@ interface SubmissionTabParams {
131132

132133
const renderSubmissionTab = ({
133134
selectedTabNormalized,
135+
allowTopgearSubmissionList,
134136
submissions,
135137
screeningRows,
136138
screeningMinimumPassingScore,
@@ -149,7 +151,7 @@ const renderSubmissionTab = ({
149151
submission => normalizeType(submission.type) === 'contestsubmission',
150152
)
151153
: submissions
152-
const canShowSubmissionList = !isTopgearSubmissionTab
154+
const canShowSubmissionList = (allowTopgearSubmissionList || !isTopgearSubmissionTab)
153155
&& selectedTabNormalized !== 'screening'
154156
&& visibleSubmissions.length > 0
155157

@@ -178,8 +180,23 @@ const renderSubmissionTab = ({
178180
}
179181

180182
export const ChallengeDetailsContent: FC<Props> = (props: Props) => {
181-
const { challengeInfo }: { challengeInfo?: ChallengeInfo } = useContext(ChallengeDetailContext)
183+
const {
184+
challengeInfo,
185+
myResources,
186+
}: ChallengeDetailContextModel = useContext(ChallengeDetailContext)
182187
const { actionChallengeRole }: useRoleProps = useRole()
188+
const hasIterativeReviewerRole = useMemo(
189+
() => myResources.some(
190+
resource => resource.roleName
191+
?.toLowerCase()
192+
.includes('iterative reviewer'),
193+
),
194+
[myResources],
195+
)
196+
const allowTopgearSubmissionList = useMemo(
197+
() => actionChallengeRole !== SUBMITTER || hasIterativeReviewerRole,
198+
[actionChallengeRole, hasIterativeReviewerRole],
199+
)
183200
const { currentMemberId }: UseSubmissionDownloadAccessResult = useSubmissionDownloadAccess()
184201
const {
185202
isLoading: isDownloadingSubmission,
@@ -364,6 +381,7 @@ export const ChallengeDetailsContent: FC<Props> = (props: Props) => {
364381

365382
if (SUBMISSION_TAB_KEYS.has(selectedTabNormalized)) {
366383
return renderSubmissionTab({
384+
allowTopgearSubmissionList,
367385
downloadSubmission: handleSubmissionDownload,
368386
isActiveChallenge: props.isActiveChallenge,
369387
isDownloadingSubmission,

0 commit comments

Comments
 (0)