Skip to content

Commit 8f172cd

Browse files
authored
Merge branch 'new-main-page-UX' into file-review-page
2 parents 9f68e71 + 3250f09 commit 8f172cd

31 files changed

+2304
-365
lines changed

.env.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
###> symfony/framework-bundle ###
1717
APP_ENV=prod
1818
APP_SECRET=eb2f09f8a21b0b7c57b9fc36eee250eb
19+
20+
# Add your sentry DSN if you want error tracking
21+
SENTRY_DSN=""
22+
1923
#TRUSTED_PROXIES=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
2024
#TRUSTED_HOSTS='^(localhost|example\.com)$'
2125
###< symfony/framework-bundle ###

.github/workflows/ci.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
php-versions: ['8.4']
2222
node-version: [20.19.0]
2323
steps:
24-
- uses: actions/checkout@v2
24+
- uses: actions/checkout@v4
2525

2626
- name: Log in to the Container registry
2727
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
@@ -35,27 +35,27 @@ jobs:
3535
uses: ASzc/change-string-case-action@v2
3636
with:
3737
string: ${{ github.repository }}
38-
38+
3939
- name: Display repository name
4040
run: echo ${{ steps.case.outputs.lowercase }}
4141

4242
- name: Find-and-replace strings
4343
id: slash
4444
uses: mad9000/actions-find-and-replace-string@2
4545
with:
46-
source: ${{ github.ref_name }}
47-
find: '/'
48-
replace: '-'
46+
source: ${{ github.ref_name }}
47+
find: '/'
48+
replace: '-'
4949

5050
- name: Display issue name
51-
run: echo ${{ steps.slash.outputs.value }}
51+
run: echo ${{ steps.slash.outputs.value }}
5252

5353
- name: Build Image
5454
run: |
5555
cp .env.example .env
5656
docker compose -f docker-compose.nginx.yml build
5757
docker compose -f docker-compose.nginx.yml run composer composer install --no-dev --no-interaction --no-progress --optimize-autoloader
58-
docker compose -f docker-compose.nginx.yml run yarn bash -c 'cd /app && yarn install && yarn build'
58+
docker compose -f docker-compose.nginx.yml run yarn bash -c 'cd /app && yarn install && yarn build'
5959
docker build . -t udoit:latest -f build/nginx/Dockerfile.build
6060
docker tag udoit:latest ${{ env.REGISTRY }}/${{ steps.case.outputs.lowercase }}:${{ steps.slash.outputs.value }}
6161

assets/js/Components/Admin/AdminApp.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ export default function AdminApp(initialData) {
132132
}
133133

134134
{ !loadingCourses && (
135-
<div className="non-scrollable">
135+
<div className="mt-3">
136136

137137
{('courses' === navigation) &&
138138
<CoursesPage

assets/js/Components/Admin/CoursesPage.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,16 @@ export default function CoursePage({
1717

1818
const [filteredCourses, setFilteredCourses] = useState([])
1919
const [tableSettings, setTableSettings] = useState({
20-
sortBy: 'errors',
20+
sortBy: 'lastUpdated',
2121
ascending: false,
2222
pageNum: 0,
2323
rowsPerPage: (localStorage.getItem('rowsPerPage')) ? localStorage.getItem('rowsPerPage') : '10'
2424
})
25-
2625
const headers = [
2726
{ id: "courseName", text: t('report.header.course_name') },
2827
{ id: "accountName", text: t('report.header.account_name') },
2928
{ id: "lastUpdated", text: t('report.header.last_scanned') },
30-
{ id: "errors", text: t('report.header.issues'), alignText: "center" },
29+
{ id: "barriers", text: t('report.header.issues'), alignText: "center" },
3130
{ id: "suggestions", text: t('report.header.suggestions'), alignText: "center" },
3231
{ id: "contentFixed", text: t('report.header.items_fixed'), alignText: "center" },
3332
{ id: "contentResolved", text: t('report.header.items_resolved'), alignText: "center" },
@@ -59,15 +58,19 @@ export default function CoursePage({
5958
}
6059

6160
if (!excludeCourse) {
62-
// The Course data from the database is stored in the `course` object.
63-
// The data for the table is converted to the `row` object.
61+
const scanCounts = course.report?.scanCounts || {};
62+
const barriers = scanCounts.errors || 0;
63+
const suggestions = scanCounts.suggestions || 0;
6464
let row = {
6565
id: course.id,
6666
course,
6767
courseName: <a href={course.publicUrl} target="_blank" rel="noopener noreferrer">{course.title}</a>,
6868
courseTitle: course.title, // Used for sorting, not displayed outside of courseName element
6969
accountName: course.accountName,
70+
barriers,
71+
suggestions,
7072
lastUpdated: course.lastUpdated,
73+
7174
action: <div class="flex-row gap-1">
7275
<button key={`reportButton${course.id}`}
7376
onClick={() => { !course.loading && handleReportClick(course) }}
@@ -92,7 +95,7 @@ export default function CoursePage({
9295
</div>
9396

9497
}
95-
tempFilteredCourses.push({...row, ...course.report})
98+
tempFilteredCourses.push({...course.report, ...row,})
9699
}
97100
})
98101

@@ -102,6 +105,9 @@ export default function CoursePage({
102105
if (sortBy === 'courseName') {
103106
return (a['courseTitle'].toLowerCase() < b['courseTitle'].toLowerCase()) ? -1 : 1
104107
}
108+
if (sortBy === 'lastUpdated') {
109+
return new Date(a.lastUpdated) < new Date(b.lastUpdated) ? -1 : 1
110+
}
105111
if (isNaN(a[sortBy]) || isNaN(b[sortBy])) {
106112
return (a[sortBy].toLowerCase() < b[sortBy].toLowerCase()) ? -1 : 1
107113
}
@@ -177,7 +183,7 @@ export default function CoursePage({
177183
}
178184

179185
return (
180-
<div className="p-0 scrollable h-100">
186+
<div className="report-page-container scrollable">
181187
<div className="flex-row justify-content-center mt-3 mb-3">
182188
<h1 className="mt-0 mb-0 primary-dark">{t('report.header.courses')}</h1>
183189
</div>

assets/js/Components/Admin/ReportsPage.js

Lines changed: 70 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,71 +6,87 @@ import ReportsTable from '../Reports/ReportsTable'
66
import IssuesTable from '../Reports/IssuesTable'
77
import ProgressIcon from '../Icons/ProgressIcon'
88
import '../ReportsPage.css'
9+
import { analyzeReport } from '../../Services/Report'
910

1011
export default function ReportsPage({
1112
t,
1213
settings,
1314
filters,
1415
selectedCourse
1516
}) {
17+
const [groupedReports, setGroupedReports] = useState(null)
18+
const [issues, setIssues] = useState(null)
1619

17-
const [reports, setReports] = useState(null)
18-
const [issues, setIssues] = useState(null)
20+
const ISSUE_STATE = {
21+
UNCHANGED: 0,
22+
SAVING: 1,
23+
RESOLVING: 2,
24+
SAVED: 3,
25+
RESOLVED: 4,
26+
ERROR: 5,
27+
}
1928

20-
const getReportHistory = () => {
21-
const api = new Api(settings)
22-
if(selectedCourse === null) {
23-
api.getAdminReportHistory(filters)
24-
.then((responseStr) => responseStr.json())
25-
.then((response) => {
26-
if (!Array.isArray(response.data)) {
27-
let tempReports = Object.values(response.data.reports)
28-
for (let report of tempReports) {
29-
report.id = report.created
30-
}
31-
setReports(tempReports)
32-
setIssues(response.data.issues)
33-
}
34-
else {
35-
setReports(null)
36-
setIssues(null)
37-
}
38-
39-
})
40-
}
41-
else {
42-
api.getCourseReport(selectedCourse.id)
43-
.then((responseStr) => responseStr.json())
44-
.then((response) => {
45-
if (response.data) {
46-
let tempReports = Object.values(response.data.reports)
47-
for (let report of tempReports) {
48-
report.id = report.created
49-
}
50-
setReports(tempReports)
51-
setIssues(response.data.issues)
52-
}
53-
else {
54-
setReports(null)
55-
setIssues(null)
56-
}
57-
})
58-
}
29+
const getReportHistory = () => {
30+
const api = new Api(settings);
31+
api.getAdminReportHistory(filters)
32+
.then((responseStr) => responseStr.json())
33+
.then((response) => {
34+
if (!Array.isArray(response.data)) {
35+
36+
const groupedReports = {}; // Initialize groupedReports
37+
// Iterate through each course
38+
Object.entries(response.data.reports).forEach(([courseName, courseDates]) => {
39+
groupedReports[courseName] = {}; // Initialize course in groupedReports
40+
41+
// Iterate through each date in this course
42+
Object.entries(courseDates).forEach(([date, reportData]) => {
43+
const analyzedReport = analyzeReport(reportData, ISSUE_STATE);
44+
45+
if (date.match(/^\d{4}-\d{2}-\d{2}$/) || date.match(/^\d{2}\/\d{2}\/\d{4}$/)) {
46+
// Update groupedReports with the analyzed report
47+
groupedReports[courseName][date] = {
48+
...analyzedReport,
49+
};
50+
}
51+
});
52+
});
5953

60-
}
54+
// Update state with analyzed reports
55+
setGroupedReports(groupedReports);
56+
setIssues(response.data.issues);
57+
} else {
58+
setGroupedReports(null);
59+
setIssues(null);
60+
}
61+
})
62+
.catch((error) => {
63+
console.error("Error fetching reports:", error);
64+
});
65+
};
6166

6267
useEffect(() => {
63-
if (reports === null) {
68+
if (groupedReports === null) {
6469
getReportHistory()
6570
}
6671
}, [])
6772

6873
return (
69-
<div className="p-0 scrollable h-100">
74+
<div className="report-page-container scrollable">
7075
<div className="flex-row justify-content-center mt-3">
71-
<h1 className="mt-0 mb-0 primary-dark">{selectedCourse?.title || t('report.header.all_courses')}</h1>
76+
<div className="flex-column w-100">
77+
<h1 className="mt-0 mb-0 primary-dark" style={{ textAlign: "center" }}>
78+
{selectedCourse?.title || t('report.header.all_courses')}
79+
</h1>
80+
<hr
81+
style={{
82+
margin: "8px auto 0 auto",
83+
borderTop: "1px solid",
84+
width: "90%"
85+
}}
86+
/>
87+
</div>
7288
</div>
73-
{ (reports === null) ? (
89+
{ (groupedReports === null) ? (
7490
<div className="mt-3 mb-3 flex-row justify-content-center">
7591
<div className="flex-column justify-content-center me-3">
7692
<ProgressIcon className="icon-lg udoit-suggestion spinner" />
@@ -81,31 +97,33 @@ export default function ReportsPage({
8197
</div>
8298
) : (
8399
<div>
84-
{(reports.length === 0) ?
100+
{(groupedReports.length === 0) ?
85101
<div className="flex-row justify-content-center mt-3">
86102
<div>{t('report.label.no_results')}</div>
87103
</div>
88104
:
89105
<div className="flex-column">
90106
<div className="mt-4">
91-
<div className="flex-row w-100 justify-content-center">
92-
<h2 className="primary-dark mt-0 mb-2">{t('report.title.barriers_remaining')}</h2>
93-
</div>
94107
<div id="resolutionsReport" className="graph-container">
95-
<ResolutionsReport t={t} reports={reports}/>
108+
<ResolutionsReport
109+
t={t}
110+
reports={groupedReports}
111+
selectedCourse={selectedCourse}
112+
/>
96113
</div>
97114
</div>
98115
<div className="mt-3">
99116
<IssuesTable
100117
t={t}
101118
issues={issues}
102119
isAdmin={true}
120+
selectedCourse={selectedCourse}
103121
/>
104122
</div>
105123
<div className="mt-3">
106124
<ReportsTable
107125
t={t}
108-
reports={reports}
126+
reports={groupedReports}
109127
isAdmin={true}
110128
/>
111129
</div>

0 commit comments

Comments
 (0)