|
|
@ -586,7 +586,7 @@ func UploadDocumentsHandler(w http.ResponseWriter, r *http.Request) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Return first page of results with configurable page size
|
|
|
// Return first page of results with configurable page size
|
|
|
renderUploadResultsPage(w, sessionID, utils.DefaultPage, limit) |
|
|
renderUploadResultsPage(w, sessionID, utils.DefaultPage, limit, "all") |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// UploadResultsHandler handles pagination for upload results
|
|
|
// UploadResultsHandler handles pagination for upload results
|
|
|
@ -607,18 +607,93 @@ func UploadResultsHandler(w http.ResponseWriter, r *http.Request) { |
|
|
limit = utils.DefaultPageSize |
|
|
limit = utils.DefaultPageSize |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
renderUploadResultsPage(w, sessionID, page, limit) |
|
|
// Optional filter: all|success|failed
|
|
|
|
|
|
filter := strings.ToLower(strings.TrimSpace(r.URL.Query().Get("filter"))) |
|
|
|
|
|
if filter != "success" && filter != "failed" { |
|
|
|
|
|
filter = "all" |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
renderUploadResultsPage(w, sessionID, page, limit, filter) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// renderUploadResultsPage renders a paginated page of upload results
|
|
|
// renderUploadResultsPage renders a paginated page of upload results
|
|
|
func renderUploadResultsPage(w http.ResponseWriter, sessionID string, page, limit int) { |
|
|
func renderUploadResultsPage(w http.ResponseWriter, sessionID string, page, limit int, filter string) { |
|
|
uploadSession, exists := uploadSessions[sessionID] |
|
|
uploadSession, exists := uploadSessions[sessionID] |
|
|
if !exists { |
|
|
if !exists { |
|
|
http.Error(w, "Upload session not found", http.StatusNotFound) |
|
|
http.Error(w, "Upload session not found", http.StatusNotFound) |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
totalResults := len(uploadSession.GroupedResults) |
|
|
// Build a filtered view per job at the file level
|
|
|
|
|
|
var filteredJobs []struct { |
|
|
|
|
|
JobID string |
|
|
|
|
|
FilesFound int |
|
|
|
|
|
FilesUploaded int |
|
|
|
|
|
Success bool |
|
|
|
|
|
ErrorMsg string |
|
|
|
|
|
Files []struct { |
|
|
|
|
|
Name string |
|
|
|
|
|
Success bool |
|
|
|
|
|
Error string |
|
|
|
|
|
FileSize int64 |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for _, jr := range uploadSession.GroupedResults { |
|
|
|
|
|
// Filter files per job
|
|
|
|
|
|
var files []struct { |
|
|
|
|
|
Name string |
|
|
|
|
|
Success bool |
|
|
|
|
|
Error string |
|
|
|
|
|
FileSize int64 |
|
|
|
|
|
} |
|
|
|
|
|
for _, f := range jr.Files { |
|
|
|
|
|
if filter == "success" && !f.Success { |
|
|
|
|
|
continue |
|
|
|
|
|
} |
|
|
|
|
|
if filter == "failed" && f.Success { |
|
|
|
|
|
continue |
|
|
|
|
|
} |
|
|
|
|
|
files = append(files, f) |
|
|
|
|
|
} |
|
|
|
|
|
if len(files) == 0 { |
|
|
|
|
|
// Skip jobs that have no files matching the filter
|
|
|
|
|
|
if filter != "all" { |
|
|
|
|
|
continue |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
// Copy job with filtered files
|
|
|
|
|
|
copy := struct { |
|
|
|
|
|
JobID string |
|
|
|
|
|
FilesFound int |
|
|
|
|
|
FilesUploaded int |
|
|
|
|
|
Success bool |
|
|
|
|
|
ErrorMsg string |
|
|
|
|
|
Files []struct { |
|
|
|
|
|
Name string |
|
|
|
|
|
Success bool |
|
|
|
|
|
Error string |
|
|
|
|
|
FileSize int64 |
|
|
|
|
|
} |
|
|
|
|
|
}{ |
|
|
|
|
|
JobID: jr.JobID, |
|
|
|
|
|
FilesFound: jr.FilesFound, |
|
|
|
|
|
FilesUploaded: jr.FilesUploaded, |
|
|
|
|
|
Success: jr.Success, |
|
|
|
|
|
ErrorMsg: jr.ErrorMsg, |
|
|
|
|
|
Files: func() []struct { |
|
|
|
|
|
Name string |
|
|
|
|
|
Success bool |
|
|
|
|
|
Error string |
|
|
|
|
|
FileSize int64 |
|
|
|
|
|
} { |
|
|
|
|
|
return files |
|
|
|
|
|
}(), |
|
|
|
|
|
} |
|
|
|
|
|
filteredJobs = append(filteredJobs, copy) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
totalResults := len(filteredJobs) |
|
|
pagination := utils.CalculatePagination(totalResults, page, limit) |
|
|
pagination := utils.CalculatePagination(totalResults, page, limit) |
|
|
|
|
|
|
|
|
// Get results for this page
|
|
|
// Get results for this page
|
|
|
@ -627,21 +702,25 @@ func renderUploadResultsPage(w http.ResponseWriter, sessionID string, page, limi |
|
|
if endIndex > totalResults { |
|
|
if endIndex > totalResults { |
|
|
endIndex = totalResults |
|
|
endIndex = totalResults |
|
|
} |
|
|
} |
|
|
pageResults := utils.GetPageResults(uploadSession.GroupedResults, startIndex, endIndex) |
|
|
pageResults := utils.GetPageResults(filteredJobs, startIndex, endIndex) |
|
|
|
|
|
|
|
|
// Add pagination info to each job result for the template
|
|
|
// Add pagination info to each job result for the template
|
|
|
var resultsWithPagination []map[string]interface{} |
|
|
var resultsWithPagination []map[string]interface{} |
|
|
for _, jobResult := range pageResults { |
|
|
for _, jobResult := range pageResults { |
|
|
|
|
|
filesLen := len(jobResult.Files) |
|
|
|
|
|
displaySuccess := (filter == "success") || (filter != "failed" && jobResult.Success) |
|
|
resultMap := map[string]interface{}{ |
|
|
resultMap := map[string]interface{}{ |
|
|
"JobID": jobResult.JobID, |
|
|
"JobID": jobResult.JobID, |
|
|
"FilesFound": jobResult.FilesFound, |
|
|
"FilesFound": jobResult.FilesFound, |
|
|
"FilesUploaded": jobResult.FilesUploaded, |
|
|
"FilesUploaded": jobResult.FilesUploaded, |
|
|
"Success": jobResult.Success, |
|
|
"Success": jobResult.Success, |
|
|
"ErrorMsg": jobResult.ErrorMsg, |
|
|
"ErrorMsg": jobResult.ErrorMsg, |
|
|
"Files": jobResult.Files, |
|
|
"Files": jobResult.Files, |
|
|
"FilePage": 1, // Default to first file
|
|
|
"FilePage": 1, // Default to first file
|
|
|
"TotalFiles": len(jobResult.Files), |
|
|
"TotalFiles": filesLen, |
|
|
"SessionID": sessionID, |
|
|
"SessionID": sessionID, |
|
|
|
|
|
"Filter": filter, |
|
|
|
|
|
"DisplaySuccess": displaySuccess, |
|
|
} |
|
|
} |
|
|
resultsWithPagination = append(resultsWithPagination, resultMap) |
|
|
resultsWithPagination = append(resultsWithPagination, resultMap) |
|
|
} |
|
|
} |
|
|
@ -662,13 +741,12 @@ func renderUploadResultsPage(w http.ResponseWriter, sessionID string, page, limi |
|
|
"StartPage": pagination.StartPage, |
|
|
"StartPage": pagination.StartPage, |
|
|
"EndPage": pagination.EndPage, |
|
|
"EndPage": pagination.EndPage, |
|
|
"SessionID": sessionID, |
|
|
"SessionID": sessionID, |
|
|
|
|
|
"Filter": filter, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
tmpl := root.WebTemplates |
|
|
tmpl := root.WebTemplates |
|
|
if err := tmpl.ExecuteTemplate(w, "upload_results_pagination", data); err != nil { |
|
|
if err := tmpl.ExecuteTemplate(w, "upload_results_pagination", data); err != nil { |
|
|
log.Printf("Template execution error: %v", err) |
|
|
log.Printf("Template execution error: %v", err) |
|
|
// Don't call http.Error here as the response may have already started
|
|
|
|
|
|
// Just log the error and return
|
|
|
|
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
@ -692,7 +770,6 @@ func (r *readCloserWithSize) Close() error { |
|
|
return nil // Allow closing nil reader safely
|
|
|
return nil // Allow closing nil reader safely
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Size returns the current size of data read
|
|
|
|
|
|
func (r *readCloserWithSize) Size() int64 { |
|
|
func (r *readCloserWithSize) Size() int64 { |
|
|
return r.size |
|
|
return r.size |
|
|
} |
|
|
} |
|
|
@ -711,6 +788,10 @@ func UploadJobFileHandler(w http.ResponseWriter, r *http.Request) { |
|
|
filePage = parsed |
|
|
filePage = parsed |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
filter := strings.ToLower(strings.TrimSpace(r.URL.Query().Get("filter"))) |
|
|
|
|
|
if filter != "success" && filter != "failed" { |
|
|
|
|
|
filter = "all" |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
uploadSession, exists := uploadSessions[sessionID] |
|
|
uploadSession, exists := uploadSessions[sessionID] |
|
|
if !exists { |
|
|
if !exists { |
|
|
@ -743,19 +824,37 @@ func UploadJobFileHandler(w http.ResponseWriter, r *http.Request) { |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
totalFiles := len(jobResult.Files) |
|
|
// Apply file-level filter
|
|
|
|
|
|
var filteredFiles []struct { |
|
|
|
|
|
Name string |
|
|
|
|
|
Success bool |
|
|
|
|
|
Error string |
|
|
|
|
|
FileSize int64 |
|
|
|
|
|
} |
|
|
|
|
|
for _, f := range jobResult.Files { |
|
|
|
|
|
if filter == "success" && !f.Success { |
|
|
|
|
|
continue |
|
|
|
|
|
} |
|
|
|
|
|
if filter == "failed" && f.Success { |
|
|
|
|
|
continue |
|
|
|
|
|
} |
|
|
|
|
|
filteredFiles = append(filteredFiles, f) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
totalFiles := len(filteredFiles) |
|
|
if totalFiles == 0 { |
|
|
if totalFiles == 0 { |
|
|
// No files to show
|
|
|
|
|
|
data := map[string]interface{}{ |
|
|
data := map[string]interface{}{ |
|
|
"JobID": jobResult.JobID, |
|
|
"JobID": jobResult.JobID, |
|
|
"FilesFound": jobResult.FilesFound, |
|
|
"FilesFound": jobResult.FilesFound, |
|
|
"FilesUploaded": jobResult.FilesUploaded, |
|
|
"FilesUploaded": jobResult.FilesUploaded, |
|
|
"Success": jobResult.Success, |
|
|
"Success": jobResult.Success, |
|
|
"ErrorMsg": jobResult.ErrorMsg, |
|
|
"ErrorMsg": jobResult.ErrorMsg, |
|
|
"Files": nil, |
|
|
"Files": nil, |
|
|
"FilePage": 1, |
|
|
"FilePage": 1, |
|
|
"TotalFiles": 0, |
|
|
"TotalFiles": 0, |
|
|
"SessionID": sessionID, |
|
|
"SessionID": sessionID, |
|
|
|
|
|
"Filter": filter, |
|
|
|
|
|
"DisplaySuccess": (filter == "success") || (filter != "failed" && jobResult.Success), |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
tmpl := root.WebTemplates |
|
|
tmpl := root.WebTemplates |
|
|
@ -798,20 +897,22 @@ func UploadJobFileHandler(w http.ResponseWriter, r *http.Request) { |
|
|
Success bool |
|
|
Success bool |
|
|
Error string |
|
|
Error string |
|
|
FileSize int64 |
|
|
FileSize int64 |
|
|
}{jobResult.Files[filePage-1]}, |
|
|
}{filteredFiles[filePage-1]}, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Add pagination info for the template
|
|
|
// Add pagination info for the template
|
|
|
data := map[string]interface{}{ |
|
|
data := map[string]interface{}{ |
|
|
"JobID": jobResultCopy.JobID, |
|
|
"JobID": jobResultCopy.JobID, |
|
|
"FilesFound": jobResultCopy.FilesFound, |
|
|
"FilesFound": jobResultCopy.FilesFound, |
|
|
"FilesUploaded": jobResultCopy.FilesUploaded, |
|
|
"FilesUploaded": jobResultCopy.FilesUploaded, |
|
|
"Success": jobResultCopy.Success, |
|
|
"Success": jobResultCopy.Success, |
|
|
"ErrorMsg": jobResultCopy.ErrorMsg, |
|
|
"ErrorMsg": jobResultCopy.ErrorMsg, |
|
|
"Files": jobResultCopy.Files, |
|
|
"Files": jobResultCopy.Files, |
|
|
"FilePage": filePage, |
|
|
"FilePage": filePage, |
|
|
"TotalFiles": totalFiles, |
|
|
"TotalFiles": totalFiles, |
|
|
"SessionID": sessionID, |
|
|
"SessionID": sessionID, |
|
|
|
|
|
"Filter": filter, |
|
|
|
|
|
"DisplaySuccess": (filter == "success") || (filter != "failed" && jobResult.Success), |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
tmpl := root.WebTemplates |
|
|
tmpl := root.WebTemplates |
|
|
|