Skip to content

Commit

Permalink
Result page is very important
Browse files Browse the repository at this point in the history
  • Loading branch information
ZihengSun committed Sep 15, 2024
1 parent 039403f commit 9b40d33
Show file tree
Hide file tree
Showing 7 changed files with 415 additions and 70 deletions.
18 changes: 18 additions & 0 deletions src/main/java/com/gw/utils/BaseTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ public class BaseTool {
@Value("${geoweaver.upload_file_path}")
String upload_file_path;

@Value("${geoweaver.result_file_path}")
String result_file_path;

@Value("${geoweaver.prefixurl}")
String prefixurl;

Expand Down Expand Up @@ -375,6 +378,21 @@ public String getFileTransferFolder() {
return tempfolder;
}

public String getResultsFolder() {

String resultfolder =
this.normalizedPath(workspace)
+ FileSystems.getDefault().getSeparator()
+ this.result_file_path
+ FileSystems.getDefault().getSeparator();

File tf = new File(resultfolder);

if (!tf.exists()) tf.mkdirs();

return resultfolder;
}

/**
* Judge whether an object is null
*
Expand Down
102 changes: 84 additions & 18 deletions src/main/java/com/gw/web/ResultBrowserController.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
package com.gw.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.gw.utils.BaseTool;

import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.*;
import java.nio.file.attribute.FileTime;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.stream.Collectors;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
public class ResultBrowserController {
Expand All @@ -28,33 +38,89 @@ public class ResultBrowserController {
// Endpoint to list image files in the directory
@GetMapping("/results")
@ResponseBody
public List<String> listImageFiles() throws IOException {
String resultfolder = bt.getFileTransferFolder();
Path rootLocation = Paths.get(resultfolder);
return Files.walk(rootLocation, 1) // 1: only files in the current folder
.filter(Files::isRegularFile)
.map(path -> path.getFileName().toString()) // Return file names
public List<Map<String, Object>> listFiles(@RequestParam(defaultValue = "") String subfolder) throws IOException {
String resultfolder = bt.getResultsFolder();

// Navigate into the subfolder if it's provided
Path rootLocation = Paths.get(resultfolder, subfolder);

return Files.walk(rootLocation, 1) // 1: look at files in the current folder and subfolders
.map(path -> {
Map<String, Object> fileDetails = new HashMap<>();
try {
Path relativePath = rootLocation.relativize(path);
String pathWithSubfolder = subfolder + "/" + relativePath.toString();
pathWithSubfolder = pathWithSubfolder.replaceAll("^/+","");

fileDetails.put("name", rootLocation.relativize(path).toString()); // Relative path
fileDetails.put("path", pathWithSubfolder); // Relative path
fileDetails.put("isDirectory", Files.isDirectory(path)); // Check if it's a directory
if (!Files.isDirectory(path)) {
fileDetails.put("size", Files.size(path)); // File size for files
}

// Get last modified time
FileTime fileTime = Files.getLastModifiedTime(path);

// Convert FileTime to LocalDateTime
LocalDateTime dateTime = LocalDateTime.ofInstant(fileTime.toInstant(), ZoneId.systemDefault());

// Format date-time to remove nanoseconds
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
String formattedDateTime = dateTime.format(formatter);

// Add formatted last modified time to file details
fileDetails.put("modified", formattedDateTime);
} catch (IOException e) {
e.printStackTrace();
}
return fileDetails;
})
.collect(Collectors.toList());
}

// Endpoint to serve images by filename
@GetMapping("/results/{filename:.+}")
@ResponseBody
public ResponseEntity<Resource> serveFile(@PathVariable String filename) {

@GetMapping("/download")
public ResponseEntity<Resource> downloadFile(@RequestParam String path) {
try {
String resultfolder = bt.getFileTransferFolder();
Path file = Paths.get(resultfolder).resolve(filename);
Resource resource = new UrlResource(file.toUri());
String resultfolder = bt.getResultsFolder();
Path filePath = Paths.get(resultfolder).resolve(path).normalize();
System.out.println("File path: " + filePath.toAbsolutePath());

// Create a FileSystemResource instead of UrlResource
Resource resource = new FileSystemResource(filePath.toFile());
if (resource.exists() || resource.isReadable()) {
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
"inline; filename=\"" + filename + "\"")
.header(
HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + filePath.getFileName().toString() + "\""
)
.body(resource);
} else {
throw new RuntimeException("Could not read file: " + filename);
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
} catch (MalformedURLException e) {
throw new RuntimeException("Could not read file: " + filename, e);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}

// Endpoint to serve images by filename
@GetMapping("/results/{filename:.+}")
@ResponseBody
public ResponseEntity<Resource> serveFile(@PathVariable String filename) {
String resultfolder = bt.getResultsFolder();
Path filePath = Paths.get(resultfolder).resolve(filename).normalize();
System.out.println("File path: " + filePath.toAbsolutePath());

// Create a FileSystemResource instead of UrlResource
Resource resource = new FileSystemResource(filePath.toFile());
if (resource.exists() || resource.isReadable()) {
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
"inline; filename=\"" + filename + "\"")
.body(resource);
} else {
throw new RuntimeException("Could not read file: " + filename);
}
}
}
6 changes: 4 additions & 2 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ logging.level.com.gw=INFO
logging.level.org.hibernate=INFO
logging.level.org.apache.catalina=FATAL

# import the external configuration file if exists
# import the external configuration file if exists - this will overwrite all the above configuration
spring.config.import=optional:file:${user.home}/geoweaver/application.properties


###### To use H2 Database
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.event.merge.entity_copy_observer=allow
Expand Down Expand Up @@ -89,9 +88,12 @@ geoweaver.prefixurl=http://localhost:8080
#database_docker_url=jdbc:mysql://db:3306/Geoweaver
geoweaver.upload_file_path=temp
geoweaver.temp_file_path=temp
geoweaver.result_file_path=results
geoweaver.workspace=~/gw-workspace
# list the allowed ssh hosts. Input * if allowing all hosts. Input localhost if only allowing the local host.
geoweaver.allowed_ssh_hosts=*
# list the allowed ssh clients. Input * if allowing all client IPs. Input localhost if only allowing access from local host.
geoweaver.allowed_ssh_clients=*
geoweaver.secret_properties_path=cc_secret.properties


167 changes: 137 additions & 30 deletions src/main/resources/static/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -432,44 +432,151 @@ form .progress {

}

.result-full-height {
height: calc(100%-20px);
/* Result page style */

.search-box .form-control {
border-radius: 10px;
padding-left: 40px
}

.search-box .search-icon {
position: absolute;
left: 13px;
top: 50%;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
fill: #545965;
width: 16px;
height: 16px
}
.card {
margin-bottom: 24px;
-webkit-box-shadow: 0 2px 3px #e4e8f0;
box-shadow: 0 2px 3px #e4e8f0;
}
.card {
position: relative;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
min-width: 0;
word-wrap: break-word;
background-color: #fff;
background-clip: border-box;
border: 1px solid #eff0f2;
border-radius: 1rem;
}
.me-3 {
margin-right: 1rem!important;
}

.font-size-24 {
font-size: 24px!important;
}
.avatar-title {
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
background-color: #3b76e1;
color: #fff;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
font-weight: 500;
height: 100%;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
width: 100%;
}
#result-left-panel {
height: 100%; /* Full height within the parent */
overflow-y: auto; /* Scrollable when content overflows */

.bg-soft-info {
background-color: rgba(87,201,235,.25)!important;
}
#result-file-list {
max-height: 100vh; /* Limit the height to viewport height */
overflow-y: auto; /* Scrollable */
padding: 0;

.bg-soft-primary {
background-color: rgba(59,118,225,.25)!important;
}
.result-list-group-item {
cursor: pointer;
transition: background-color 0.2s, color 0.2s;

.avatar-xs {
height: 1rem;
width: 1rem
}
.result-list-group-item:hover {
background-color: #007bff;
color: #fff;

.avatar-sm {
height: 2rem;
width: 2rem
}

.avatar {
height: 3rem;
width: 3rem
}

.avatar-md {
height: 4rem;
width: 4rem
}

.avatar-lg {
height: 5rem;
width: 5rem
}
.result-card {
border-radius: 0.5rem;

.avatar-xl {
height: 6rem;
width: 6rem
}

.avatar-title {
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
background-color: #3b76e1;
color: #fff;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
font-weight: 500;
height: 100%;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
width: 100%
}
.result-card-body {
padding: 1.25rem;

.avatar-group {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
padding-left: 8px
}
.result-dark-theme {
background-color: #343a40;
color: #f8f9fa;

.avatar-group .avatar-group-item {
margin-left: -8px;
border: 2px solid #fff;
border-radius: 50%;
-webkit-transition: all .2s;
transition: all .2s
}
.result-dark-theme .card {
background-color: #495057;
border: 1px solid #6c757d;

.avatar-group .avatar-group-item:hover {
position: relative;
-webkit-transform: translateY(-2px);
transform: translateY(-2px)
}
.result-dark-theme .list-group-item {
background-color: #495057;
border-color: #6c757d;

.fw-medium {
font-weight: 500;
}
.result-dark-theme .list-group-item:hover {
background-color: #6c757d;

a {
text-decoration: none!important;
}

Loading

0 comments on commit 9b40d33

Please sign in to comment.