Skip to content

Commit 64a2fec

Browse files
authored
Improve add report page UX (#44)
* Improve the add report page UX
1 parent 5a12b24 commit 64a2fec

File tree

8 files changed

+83
-18
lines changed

8 files changed

+83
-18
lines changed

Backend/SorobanSecurityPortalApi/Controllers/ReportsController.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public async Task<IActionResult> GetImage(int reportId)
5555

5656
[RoleAuthorize(Role.Admin, Role.Moderator, Role.Contributor)]
5757
[HttpPost("add")]
58-
[RequestSizeLimit(10_000_000)]
58+
[RequestSizeLimit(60_000_000)]
5959
public async Task<IActionResult> Add([FromForm] string report, [FromForm] IFormFile? file = null)
6060
{
6161
if (string.IsNullOrWhiteSpace(report))
@@ -87,6 +87,10 @@ public async Task<IActionResult> Add([FromForm] string report, [FromForm] IFormF
8787
};
8888
if (file != null && file.Length > 0)
8989
{
90+
if (!await _userContextAccessor.IsLoginIdAdmin(userLoginId) && file.Length > 10 * 1024 * 1024)
91+
{
92+
return BadRequest("Report file size cannot exceed 10MB");
93+
}
9094
using var memoryStream = new MemoryStream();
9195
await file.CopyToAsync(memoryStream);
9296
parsedReport.BinFile = memoryStream.ToArray();

UI/src/features/pages/admin/admin-main-window/error-dialog.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,13 @@ export default function ErrorDialog() {
6464
>
6565
<DialogTitle color={getDialogColor()}>{getDialogTitle()}</DialogTitle>
6666
<DialogContent>
67-
<DialogContentText id="alert-dialog-slide-description">
68-
{currentError.errorText}
67+
<DialogContentText id="alert-dialog-slide-description" component="div">
68+
{currentError.errorText.split('\n').map((line, index) => (
69+
<React.Fragment key={index}>
70+
{line}
71+
{index < currentError.errorText.split('\n').length - 1 && <br />}
72+
</React.Fragment>
73+
))}
6974
</DialogContentText>
7075
</DialogContent>
7176
<DialogActions>

UI/src/features/pages/admin/company/list-view/list-companies.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import PersonAddIcon from '@mui/icons-material/PersonAdd';
21
import ClearIcon from '@mui/icons-material/Clear';
32
import {
43
IconButton,
@@ -23,6 +22,7 @@ import { useNavigate } from 'react-router-dom';
2322
import { defaultUiSettings } from '../../../../../api/soroban-security-portal/models/ui-settings.ts';
2423
import { AuthContextProps, useAuth } from 'react-oidc-context';
2524
import { Role } from '../../../../../api/soroban-security-portal/models/role.ts';
25+
import AddBusinessIcon from '@mui/icons-material/AddBusiness';
2626

2727
export const ListCompanies: FC = () => {
2828
const auth = useAuth();
@@ -110,7 +110,7 @@ export const ListCompanies: FC = () => {
110110
<Stack direction="row" spacing={2}>
111111
<Tooltip title="Add Company">
112112
<IconButton onClick={() => navigate('/admin/companies/add')}>
113-
<PersonAddIcon sx={{ color: 'green' }} />
113+
<AddBusinessIcon sx={{ color: 'green' }} />
114114
</IconButton>
115115
</Tooltip>
116116
</Stack>

UI/src/features/pages/admin/protocol/list-view/list-protocols.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import PersonAddIcon from '@mui/icons-material/PersonAdd';
21
import ClearIcon from '@mui/icons-material/Clear';
32
import {
43
IconButton,
@@ -23,6 +22,7 @@ import { useNavigate } from 'react-router-dom';
2322
import { defaultUiSettings } from '../../../../../api/soroban-security-portal/models/ui-settings.ts';
2423
import { AuthContextProps, useAuth } from 'react-oidc-context';
2524
import { Role } from '../../../../../api/soroban-security-portal/models/role.ts';
25+
import AddToQueueIcon from '@mui/icons-material/AddToQueue';
2626

2727
export const ListProtocols: FC = () => {
2828
const auth = useAuth();
@@ -118,7 +118,7 @@ export const ListProtocols: FC = () => {
118118
<Stack direction="row" spacing={2}>
119119
<Tooltip title="Add Protocol">
120120
<IconButton onClick={() => navigate('/admin/protocols/add')}>
121-
<PersonAddIcon sx={{ color: 'green' }} />
121+
<AddToQueueIcon sx={{ color: 'green' }} />
122122
</IconButton>
123123
</Tooltip>
124124
</Stack>

UI/src/features/pages/admin/reports/list-view/list-reports.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
Tooltip,
1010
Modal,
1111
Box,
12+
Stack,
1213
} from '@mui/material';
1314
import {
1415
DataGrid,
@@ -27,6 +28,7 @@ import { defaultUiSettings } from '../../../../../api/soroban-security-portal/mo
2728
import { environment } from '../../../../../environments/environment';
2829
import { AuthContextProps, useAuth } from 'react-oidc-context';
2930
import { Role } from '../../../../../api/soroban-security-portal/models/role';
31+
import AssignmentAddIcon from '@mui/icons-material/AssignmentAdd';
3032

3133
export const ReportManagement: FC = () => {
3234

@@ -169,6 +171,14 @@ export const ReportManagement: FC = () => {
169171

170172
return (
171173
<div style={defaultUiSettings.listAreaStyle}>
174+
<Stack direction="row" spacing={2}>
175+
<Tooltip title="Add Report">
176+
<IconButton onClick={() => navigate('/reports/add')}>
177+
<AssignmentAddIcon sx={{ color: 'green' }} />
178+
</IconButton>
179+
</Tooltip>
180+
</Stack>
181+
172182
<div style={{ height: 'calc(110vh - 64px)' }}>
173183
<DataGrid
174184
getRowId={(row: Report) => row.id}

UI/src/features/pages/admin/vulnerabilities/list-view/list-vulnerabilities.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
Link,
88
Tooltip,
99
Typography,
10+
Stack,
1011
} from '@mui/material';
1112
import {
1213
DataGrid,
@@ -28,6 +29,7 @@ import { useNavigate } from 'react-router-dom';
2829
import { MarkdownView } from '../../../../../components/MarkdownView.tsx';
2930
import { AuthContextProps, useAuth } from 'react-oidc-context';
3031
import { Role } from '../../../../../api/soroban-security-portal/models/role.ts';
32+
import PostAdd from '@mui/icons-material/PostAdd';
3133

3234
export const VulnerabilityManagement: FC = () => {
3335
const currentPageState: CurrentPageState = {
@@ -199,6 +201,14 @@ export const VulnerabilityManagement: FC = () => {
199201

200202
return (
201203
<div style={defaultUiSettings.listAreaStyle}>
204+
<Stack direction="row" spacing={2}>
205+
<Tooltip title="Add Vulnerability">
206+
<IconButton onClick={() => navigate('/vulnerabilities/add')}>
207+
<PostAdd sx={{ color: 'green' }} />
208+
</IconButton>
209+
</Tooltip>
210+
</Stack>
211+
202212
<div style={{ height: 'calc(110vh - 64px)' }}>
203213
<DataGrid
204214
getRowId={(row: Vulnerability) => row.id}

UI/src/features/pages/regular/reports-add/hooks/reports-add.hook.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ export const useReportAdd = () => {
2222
formData.append('report', JSON.stringify(report));
2323

2424
// Call API with file upload
25-
const response = await addReportCall(formData);
26-
console.log('Report added with file:', response);
25+
await addReportCall(formData);
2726
} catch (error) {
2827
console.error('Error adding report:', error);
2928
throw error;

UI/src/features/pages/regular/reports-add/reports-add.tsx

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export const AddReport: FC = () => {
3838
const [protocol, setProtocol] = useState<ProtocolItem | null>(null);
3939
const [company, setCompany] = useState<CompanyItem | null>(null);
4040
const [auditor, setAuditor] = useState<AuditorItem | null>(null);
41-
const [date, setDate] = useState<Date | null>(null);
41+
const [date, setDate] = useState<Date | null>(new Date());
4242
const [selectedFile, setSelectedFile] = useState<File | null>(null);
4343
const [fileError, setFileError] = useState('');
4444
const [isDragOver, setIsDragOver] = useState(false);
@@ -50,6 +50,10 @@ export const AddReport: FC = () => {
5050
const theme = useTheme();
5151
const [searchParams] = useSearchParams();
5252

53+
const isAdmin = auth.isAuthenticated && auth.user && (auth.user?.profile.role === Role.Admin);
54+
const isModerator = auth.isAuthenticated && auth.user && (auth.user?.profile.role === Role.Moderator);
55+
const isContributor = auth.isAuthenticated && auth.user && (auth.user?.profile.role === Role.Contributor);
56+
5357
const canAddReport = (auth: AuthContextProps) =>
5458
auth.user?.profile.role === Role.Admin || auth.user?.profile.role === Role.Contributor || auth.user?.profile.role === Role.Moderator;
5559

@@ -116,7 +120,7 @@ export const AddReport: FC = () => {
116120
}
117121

118122
// Check file size (max 10MB)
119-
if (file.size > 10 * 1024 * 1024) {
123+
if (!isAdmin && file.size > 10 * 1024 * 1024) {
120124
setFileError('File size must be less than 10MB');
121125
setSelectedFile(null);
122126
return;
@@ -163,13 +167,25 @@ export const AddReport: FC = () => {
163167
};
164168

165169
const addNewReport = async () => {
170+
let validationErrors: string[] = [];
166171
if (!title) {
167-
showError('Please fill all required fields');
168-
return;
172+
validationErrors.push('Please fill in the title');
173+
}
174+
if (!company) {
175+
validationErrors.push('Please select a company');
176+
}
177+
if (!protocol) {
178+
validationErrors.push('Please select a protocol');
179+
}
180+
if (!auditor) {
181+
validationErrors.push('Please select an auditor');
169182
}
170-
171183
if (!selectedFile && !url) {
172-
showError('Please provide either a PDF file or a URL');
184+
validationErrors.push('Please provide either a PDF file or a URL');
185+
}
186+
187+
if (validationErrors.length > 0) {
188+
showError(validationErrors.map(e => e + '.').join('\n'));
173189
return;
174190
}
175191

@@ -247,6 +263,7 @@ export const AddReport: FC = () => {
247263
label="Company"
248264
size="small"
249265
sx={{ minWidth: 290 }}
266+
required
250267
/>
251268
)}
252269
renderTags={(value, getTagProps) =>
@@ -261,6 +278,11 @@ export const AddReport: FC = () => {
261278
))
262279
}
263280
/>
281+
<Typography variant="caption" color="text.secondary" sx={{ mt: 1, display: 'block' }}>
282+
{isContributor ? "Company missed? Please contact a moderator or admin." : (
283+
(isModerator || isAdmin) ? <span>Company missed? <a href="/admin/companies/add" target="_blank" rel="noopener noreferrer" style={{ color: 'inherit', textDecoration: 'underline', cursor: 'pointer' }}>Add it here</a></span> : ""
284+
)}
285+
</Typography>
264286
</Grid>
265287
<Grid size={12}>
266288
<Autocomplete
@@ -274,6 +296,7 @@ export const AddReport: FC = () => {
274296
label="Protocol"
275297
size="small"
276298
sx={{ minWidth: 290 }}
299+
required
277300
/>
278301
)}
279302
renderTags={(value, getTagProps) =>
@@ -288,6 +311,11 @@ export const AddReport: FC = () => {
288311
))
289312
}
290313
/>
314+
<Typography variant="caption" color="text.secondary" sx={{ mt: 1, display: 'block' }}>
315+
{isContributor ? "Protocol missed? Please contact a moderator or admin." : (
316+
(isModerator || isAdmin) ? <span>Protocol missed? <a href="/admin/protocols/add" target="_blank" rel="noopener noreferrer" style={{ color: 'inherit', textDecoration: 'underline', cursor: 'pointer' }}>Add it here</a></span> : ""
317+
)}
318+
</Typography>
291319
</Grid>
292320
<Grid size={12}>
293321
<Autocomplete
@@ -301,6 +329,7 @@ export const AddReport: FC = () => {
301329
label="Auditor"
302330
size="small"
303331
sx={{ minWidth: 290 }}
332+
required
304333
/>
305334
)}
306335
renderTags={(value, getTagProps) =>
@@ -314,17 +343,25 @@ export const AddReport: FC = () => {
314343
/>
315344
))
316345
}
317-
/>
346+
/>
347+
<Typography variant="caption" color="text.secondary" sx={{ mt: 1, display: 'block' }}>
348+
{isContributor ? "Auditor missed? Please contact a moderator or admin." : (
349+
(isModerator || isAdmin) ? <span>Auditor missed? <a href="/admin/auditors/add" target="_blank" rel="noopener noreferrer" style={{ color: 'inherit', textDecoration: 'underline', cursor: 'pointer' }}>Add it here</a></span> : ""
350+
)}
351+
</Typography>
318352
</Grid>
319353
<Grid size={12}>
320354
<DatePicker
321-
label="Report Date"
355+
label="Report Date *"
322356
value={date}
323357
onChange={(newValue) => setDate(newValue)}
324358
slotProps={{
325359
textField: {
326360
size: 'small',
327-
sx: { width: '100%' }
361+
sx: { width: '100%' },
362+
onClick: (e) => {
363+
e.currentTarget.querySelector('button')?.click();
364+
}
328365
}
329366
}}
330367
/>

0 commit comments

Comments
 (0)