move sorting to the database
All checks were successful
pedestrian-simulator / build (push) Successful in 1m2s
All checks were successful
pedestrian-simulator / build (push) Successful in 1m2s
This commit is contained in:
@@ -25,6 +25,10 @@ let viewMode = 0; // 0: Street View, 1: Map View, 2: Satellite View
|
||||
let targetSyncTime = null;
|
||||
let idleAnimationId = null;
|
||||
|
||||
// Pagination state
|
||||
let currentMyPage = 1;
|
||||
let currentPublicPage = 1;
|
||||
const KML_PAGE_LIMIT = 10;
|
||||
|
||||
let apiKey = null;
|
||||
window.isGeneratingRoute = false;
|
||||
@@ -156,8 +160,38 @@ function setupKMLBrowser() {
|
||||
document.getElementById('kmlUploadInput').addEventListener('change', handleKMLUpload);
|
||||
|
||||
// Sort controls
|
||||
document.getElementById('myFilesSortSelect').addEventListener('change', () => loadKMLFiles());
|
||||
document.getElementById('publicFilesSortSelect').addEventListener('change', () => loadKMLFiles());
|
||||
document.getElementById('myFilesSortSelect').addEventListener('change', () => {
|
||||
currentMyPage = 1;
|
||||
loadKMLFiles();
|
||||
});
|
||||
document.getElementById('publicFilesSortSelect').addEventListener('change', () => {
|
||||
currentPublicPage = 1;
|
||||
loadKMLFiles();
|
||||
});
|
||||
|
||||
// Pagination buttons (My Files)
|
||||
document.getElementById('prevMyPage').addEventListener('click', () => {
|
||||
if (currentMyPage > 1) {
|
||||
currentMyPage--;
|
||||
loadKMLFiles();
|
||||
}
|
||||
});
|
||||
document.getElementById('nextMyPage').addEventListener('click', () => {
|
||||
currentMyPage++;
|
||||
loadKMLFiles();
|
||||
});
|
||||
|
||||
// Pagination buttons (Public Files)
|
||||
document.getElementById('prevPublicPage').addEventListener('click', () => {
|
||||
if (currentPublicPage > 1) {
|
||||
currentPublicPage--;
|
||||
loadKMLFiles();
|
||||
}
|
||||
});
|
||||
document.getElementById('nextPublicPage').addEventListener('click', () => {
|
||||
currentPublicPage++;
|
||||
loadKMLFiles();
|
||||
});
|
||||
}
|
||||
|
||||
function openKMLBrowser() {
|
||||
@@ -205,7 +239,19 @@ async function handleKMLUpload(e) {
|
||||
|
||||
async function loadKMLFiles() {
|
||||
try {
|
||||
const response = await fetch('/api/kml/list');
|
||||
const mySort = document.getElementById('myFilesSortSelect').value;
|
||||
const publicSort = document.getElementById('publicFilesSortSelect').value;
|
||||
|
||||
const params = new URLSearchParams({
|
||||
my_page: currentMyPage,
|
||||
my_limit: KML_PAGE_LIMIT,
|
||||
my_sort_by: mySort,
|
||||
public_page: currentPublicPage,
|
||||
public_limit: KML_PAGE_LIMIT,
|
||||
public_sort_by: publicSort
|
||||
});
|
||||
|
||||
const response = await fetch(`/api/kml/list?${params.toString()}`);
|
||||
if (!response.ok) {
|
||||
console.error('Failed to load KML files');
|
||||
return;
|
||||
@@ -216,8 +262,19 @@ async function loadKMLFiles() {
|
||||
// Render my files
|
||||
renderKMLFiles('myFilesList', data.my_files || [], true);
|
||||
|
||||
// Update my pagination UI
|
||||
document.getElementById('myPageNum').textContent = `Page ${data.my_page}`;
|
||||
document.getElementById('prevMyPage').disabled = data.my_page <= 1;
|
||||
document.getElementById('nextMyPage').disabled = (data.my_page * KML_PAGE_LIMIT) >= data.my_total;
|
||||
|
||||
// Render public files
|
||||
renderKMLFiles('publicFilesList', data.public_files || [], false);
|
||||
|
||||
// Update public pagination UI
|
||||
document.getElementById('publicPageNum').textContent = `Page ${data.public_page}`;
|
||||
document.getElementById('prevPublicPage').disabled = data.public_page <= 1;
|
||||
document.getElementById('nextPublicPage').disabled = (data.public_page * KML_PAGE_LIMIT) >= data.public_total;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error loading KML files:', error);
|
||||
}
|
||||
|
||||
@@ -153,14 +153,21 @@
|
||||
<div class="sort-controls">
|
||||
<label>Sort by:</label>
|
||||
<select id="myFilesSortSelect">
|
||||
<option value="date">Newest First</option>
|
||||
<option value="date">Most Recent</option>
|
||||
<option value="distance">Distance</option>
|
||||
<option value="filename">Filename</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="myFilesList" class="kml-file-list">
|
||||
<p class="empty-message">No KML files uploaded yet</p>
|
||||
</div>
|
||||
|
||||
<div class="pagination-controls">
|
||||
<button id="prevMyPage" class="pagination-btn" disabled>← Previous</button>
|
||||
<span id="myPageNum">Page 1</span>
|
||||
<button id="nextMyPage" class="pagination-btn">Next →</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Public Files Tab -->
|
||||
@@ -170,6 +177,7 @@
|
||||
<select id="publicFilesSortSelect">
|
||||
<option value="votes">Highest Votes</option>
|
||||
<option value="date">Most Recent</option>
|
||||
<option value="distance">Distance</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
123
server/kml.go
123
server/kml.go
@@ -222,55 +222,43 @@ func HandleKMLList(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Parse pagination parameters
|
||||
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||
if limit <= 0 {
|
||||
limit = 10
|
||||
// Parse parameters for My Files
|
||||
myLimit, _ := strconv.Atoi(r.URL.Query().Get("my_limit"))
|
||||
if myLimit <= 0 {
|
||||
myLimit = 10
|
||||
}
|
||||
page, _ := strconv.Atoi(r.URL.Query().Get("page"))
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
myPage, _ := strconv.Atoi(r.URL.Query().Get("my_page"))
|
||||
if myPage <= 0 {
|
||||
myPage = 1
|
||||
}
|
||||
offset := (page - 1) * limit
|
||||
|
||||
sortBy := r.URL.Query().Get("sort_by")
|
||||
order := r.URL.Query().Get("order")
|
||||
if order != "ASC" {
|
||||
order = "DESC"
|
||||
mySortBy := r.URL.Query().Get("my_sort_by")
|
||||
if mySortBy == "" {
|
||||
mySortBy = "date"
|
||||
}
|
||||
|
||||
// 1. Get my files
|
||||
myFiles, err := queryKMLMetadata(`
|
||||
SELECT m.filename, m.user_id, u.display_name, m.distance, m.is_public, m.uploaded_at,
|
||||
(SELECT COALESCE(SUM(v.vote_value), 0) FROM kml_votes v WHERE v.kml_id = m.id) as votes
|
||||
FROM kml_metadata m
|
||||
JOIN users u ON m.user_id = u.fitbit_user_id
|
||||
WHERE m.user_id = ?
|
||||
ORDER BY m.uploaded_at DESC
|
||||
`, userID)
|
||||
// Parse parameters for Public Files
|
||||
publicLimit, _ := strconv.Atoi(r.URL.Query().Get("public_limit"))
|
||||
if publicLimit <= 0 {
|
||||
publicLimit = 10
|
||||
}
|
||||
publicPage, _ := strconv.Atoi(r.URL.Query().Get("public_page"))
|
||||
if publicPage <= 0 {
|
||||
publicPage = 1
|
||||
}
|
||||
publicSortBy := r.URL.Query().Get("public_sort_by")
|
||||
if publicSortBy == "" {
|
||||
publicSortBy = "votes"
|
||||
}
|
||||
|
||||
// 1. Get My Files
|
||||
myFiles, myTotal, err := fetchKMLList(userID, true, myPage, myLimit, mySortBy)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// 2. Get public files (with pagination and sorting)
|
||||
sortClause := "votes"
|
||||
switch sortBy {
|
||||
case "date":
|
||||
sortClause = "m.uploaded_at"
|
||||
case "distance":
|
||||
sortClause = "m.distance"
|
||||
}
|
||||
|
||||
publicFiles, err := queryKMLMetadata(fmt.Sprintf(`
|
||||
SELECT m.filename, m.user_id, u.display_name, m.distance, m.is_public, m.uploaded_at,
|
||||
(SELECT COALESCE(SUM(v.vote_value), 0) FROM kml_votes v WHERE v.kml_id = m.id) as votes
|
||||
FROM kml_metadata m
|
||||
JOIN users u ON m.user_id = u.fitbit_user_id
|
||||
WHERE m.is_public = 1
|
||||
ORDER BY %s %s
|
||||
LIMIT ? OFFSET ?
|
||||
`, sortClause, order), limit, offset)
|
||||
// 2. Get Public Files
|
||||
publicFiles, publicTotal, err := fetchKMLList(userID, false, publicPage, publicLimit, publicSortBy)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@@ -279,12 +267,63 @@ func HandleKMLList(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"my_files": myFiles,
|
||||
"my_total": myTotal,
|
||||
"my_page": myPage,
|
||||
"public_files": publicFiles,
|
||||
"page": page,
|
||||
"limit": limit,
|
||||
"public_total": publicTotal,
|
||||
"public_page": publicPage,
|
||||
"limit": 10, // Default limit reference for UI
|
||||
})
|
||||
}
|
||||
|
||||
func fetchKMLList(userID string, mineOnly bool, page, limit int, sortBy string) ([]KMLMetadata, int, error) {
|
||||
offset := (page - 1) * limit
|
||||
|
||||
var whereClause string
|
||||
var args []interface{}
|
||||
if mineOnly {
|
||||
whereClause = "WHERE m.user_id = ?"
|
||||
args = append(args, userID)
|
||||
} else {
|
||||
whereClause = "WHERE m.is_public = 1"
|
||||
}
|
||||
|
||||
// Get total count first
|
||||
var total int
|
||||
err := db.QueryRow(fmt.Sprintf("SELECT COUNT(*) FROM kml_metadata m %s", whereClause), args...).Scan(&total)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
sortClause := "votes"
|
||||
order := "DESC"
|
||||
switch sortBy {
|
||||
case "date":
|
||||
sortClause = "m.uploaded_at"
|
||||
case "distance":
|
||||
sortClause = "m.distance"
|
||||
case "votes":
|
||||
sortClause = "votes"
|
||||
case "filename":
|
||||
sortClause = "m.filename"
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`
|
||||
SELECT m.filename, m.user_id, u.display_name, m.distance, m.is_public, m.uploaded_at,
|
||||
(SELECT COALESCE(SUM(v.vote_value), 0) FROM kml_votes v WHERE v.kml_id = m.id) as votes
|
||||
FROM kml_metadata m
|
||||
JOIN users u ON m.user_id = u.fitbit_user_id
|
||||
%s
|
||||
ORDER BY %s %s
|
||||
LIMIT ? OFFSET ?
|
||||
`, whereClause, sortClause, order)
|
||||
|
||||
args = append(args, limit, offset)
|
||||
files, err := queryKMLMetadata(query, args...)
|
||||
return files, total, err
|
||||
}
|
||||
|
||||
func queryKMLMetadata(query string, args ...interface{}) ([]KMLMetadata, error) {
|
||||
rows, err := db.Query(query, args...)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user