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 targetSyncTime = null;
|
||||||
let idleAnimationId = null;
|
let idleAnimationId = null;
|
||||||
|
|
||||||
|
// Pagination state
|
||||||
|
let currentMyPage = 1;
|
||||||
|
let currentPublicPage = 1;
|
||||||
|
const KML_PAGE_LIMIT = 10;
|
||||||
|
|
||||||
let apiKey = null;
|
let apiKey = null;
|
||||||
window.isGeneratingRoute = false;
|
window.isGeneratingRoute = false;
|
||||||
@@ -156,8 +160,38 @@ function setupKMLBrowser() {
|
|||||||
document.getElementById('kmlUploadInput').addEventListener('change', handleKMLUpload);
|
document.getElementById('kmlUploadInput').addEventListener('change', handleKMLUpload);
|
||||||
|
|
||||||
// Sort controls
|
// Sort controls
|
||||||
document.getElementById('myFilesSortSelect').addEventListener('change', () => loadKMLFiles());
|
document.getElementById('myFilesSortSelect').addEventListener('change', () => {
|
||||||
document.getElementById('publicFilesSortSelect').addEventListener('change', () => loadKMLFiles());
|
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() {
|
function openKMLBrowser() {
|
||||||
@@ -205,7 +239,19 @@ async function handleKMLUpload(e) {
|
|||||||
|
|
||||||
async function loadKMLFiles() {
|
async function loadKMLFiles() {
|
||||||
try {
|
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) {
|
if (!response.ok) {
|
||||||
console.error('Failed to load KML files');
|
console.error('Failed to load KML files');
|
||||||
return;
|
return;
|
||||||
@@ -216,8 +262,19 @@ async function loadKMLFiles() {
|
|||||||
// Render my files
|
// Render my files
|
||||||
renderKMLFiles('myFilesList', data.my_files || [], true);
|
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
|
// Render public files
|
||||||
renderKMLFiles('publicFilesList', data.public_files || [], false);
|
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) {
|
} catch (error) {
|
||||||
console.error('Error loading KML files:', error);
|
console.error('Error loading KML files:', error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,14 +153,21 @@
|
|||||||
<div class="sort-controls">
|
<div class="sort-controls">
|
||||||
<label>Sort by:</label>
|
<label>Sort by:</label>
|
||||||
<select id="myFilesSortSelect">
|
<select id="myFilesSortSelect">
|
||||||
<option value="date">Newest First</option>
|
<option value="date">Most Recent</option>
|
||||||
<option value="distance">Distance</option>
|
<option value="distance">Distance</option>
|
||||||
|
<option value="filename">Filename</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="myFilesList" class="kml-file-list">
|
<div id="myFilesList" class="kml-file-list">
|
||||||
<p class="empty-message">No KML files uploaded yet</p>
|
<p class="empty-message">No KML files uploaded yet</p>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
|
|
||||||
<!-- Public Files Tab -->
|
<!-- Public Files Tab -->
|
||||||
@@ -170,6 +177,7 @@
|
|||||||
<select id="publicFilesSortSelect">
|
<select id="publicFilesSortSelect">
|
||||||
<option value="votes">Highest Votes</option>
|
<option value="votes">Highest Votes</option>
|
||||||
<option value="date">Most Recent</option>
|
<option value="date">Most Recent</option>
|
||||||
|
<option value="distance">Distance</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
123
server/kml.go
123
server/kml.go
@@ -222,55 +222,43 @@ func HandleKMLList(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse pagination parameters
|
// Parse parameters for My Files
|
||||||
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
myLimit, _ := strconv.Atoi(r.URL.Query().Get("my_limit"))
|
||||||
if limit <= 0 {
|
if myLimit <= 0 {
|
||||||
limit = 10
|
myLimit = 10
|
||||||
}
|
}
|
||||||
page, _ := strconv.Atoi(r.URL.Query().Get("page"))
|
myPage, _ := strconv.Atoi(r.URL.Query().Get("my_page"))
|
||||||
if page <= 0 {
|
if myPage <= 0 {
|
||||||
page = 1
|
myPage = 1
|
||||||
}
|
}
|
||||||
offset := (page - 1) * limit
|
mySortBy := r.URL.Query().Get("my_sort_by")
|
||||||
|
if mySortBy == "" {
|
||||||
sortBy := r.URL.Query().Get("sort_by")
|
mySortBy = "date"
|
||||||
order := r.URL.Query().Get("order")
|
|
||||||
if order != "ASC" {
|
|
||||||
order = "DESC"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Get my files
|
// Parse parameters for Public Files
|
||||||
myFiles, err := queryKMLMetadata(`
|
publicLimit, _ := strconv.Atoi(r.URL.Query().Get("public_limit"))
|
||||||
SELECT m.filename, m.user_id, u.display_name, m.distance, m.is_public, m.uploaded_at,
|
if publicLimit <= 0 {
|
||||||
(SELECT COALESCE(SUM(v.vote_value), 0) FROM kml_votes v WHERE v.kml_id = m.id) as votes
|
publicLimit = 10
|
||||||
FROM kml_metadata m
|
}
|
||||||
JOIN users u ON m.user_id = u.fitbit_user_id
|
publicPage, _ := strconv.Atoi(r.URL.Query().Get("public_page"))
|
||||||
WHERE m.user_id = ?
|
if publicPage <= 0 {
|
||||||
ORDER BY m.uploaded_at DESC
|
publicPage = 1
|
||||||
`, userID)
|
}
|
||||||
|
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 {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Get public files (with pagination and sorting)
|
// 2. Get Public Files
|
||||||
sortClause := "votes"
|
publicFiles, publicTotal, err := fetchKMLList(userID, false, publicPage, publicLimit, publicSortBy)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@@ -279,12 +267,63 @@ func HandleKMLList(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||||
"my_files": myFiles,
|
"my_files": myFiles,
|
||||||
|
"my_total": myTotal,
|
||||||
|
"my_page": myPage,
|
||||||
"public_files": publicFiles,
|
"public_files": publicFiles,
|
||||||
"page": page,
|
"public_total": publicTotal,
|
||||||
"limit": limit,
|
"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) {
|
func queryKMLMetadata(query string, args ...interface{}) ([]KMLMetadata, error) {
|
||||||
rows, err := db.Query(query, args...)
|
rows, err := db.Query(query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user