Cuts bug fixes and updates
This commit is contained in:
parent
f44cb35253
commit
ebf9ff23ab
@ -19,7 +19,8 @@ class CutsController {
|
||||
|
||||
// For NocoDB v2 API, we need to get all records and filter in memory
|
||||
// since the where clause syntax may be different
|
||||
const response = await nocodbService.getAll(
|
||||
// Use paginated method to get ALL records (not just the default 25 limit)
|
||||
const response = await nocodbService.getAllPaginated(
|
||||
config.nocodb.cutsSheetId
|
||||
);
|
||||
|
||||
|
||||
@ -791,10 +791,19 @@
|
||||
<option value="Neighborhood">Neighborhood</option>
|
||||
<option value="District">District</option>
|
||||
</select>
|
||||
<select id="cuts-per-page" class="form-control">
|
||||
<option value="5" selected>5 per page</option>
|
||||
<option value="10">10 per page</option>
|
||||
<option value="20">20 per page</option>
|
||||
<option value="50">50 per page</option>
|
||||
<option value="100">100 per page</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="cuts-list" class="cuts-list">
|
||||
<!-- Cuts will be populated here -->
|
||||
</div>
|
||||
<!-- Pagination Controls (will be dynamically created after cuts-list) -->
|
||||
<div id="cuts-pagination" class="cuts-pagination" style="display: none;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -516,3 +516,91 @@
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
/* Cuts Pagination Styles */
|
||||
.cuts-pagination {
|
||||
margin-top: var(--padding-sm);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: var(--padding-sm) 0;
|
||||
border-top: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.pagination-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.pagination-btn {
|
||||
background: var(--bg-secondary);
|
||||
border: 1px solid var(--border-color);
|
||||
color: var(--text-primary);
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: var(--border-radius);
|
||||
font-size: 0.875rem;
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-base);
|
||||
min-width: 2.5rem;
|
||||
text-align: center;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.pagination-btn:hover:not(.active):not(:disabled) {
|
||||
background: var(--bg-hover);
|
||||
border-color: var(--primary-color);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.pagination-btn.active {
|
||||
background: var(--primary-color);
|
||||
border-color: var(--primary-color);
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.pagination-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.pagination-ellipsis {
|
||||
color: var(--text-secondary);
|
||||
padding: 0.5rem 0.25rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
/* Cuts list header with count information */
|
||||
.cuts-list-header {
|
||||
padding: var(--padding-sm);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
background: var(--bg-tertiary);
|
||||
border-radius: var(--border-radius) var(--border-radius) 0 0;
|
||||
}
|
||||
|
||||
.cuts-count {
|
||||
font-size: 0.875rem;
|
||||
color: var(--text-secondary);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Updated cuts filters to accommodate items per page selector */
|
||||
.cuts-filters {
|
||||
display: flex;
|
||||
gap: var(--padding-sm);
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: var(--padding-sm);
|
||||
}
|
||||
|
||||
.cuts-filters .form-control {
|
||||
flex: 1;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.cuts-filters .form-control:last-child {
|
||||
flex: 0 0 auto;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
@ -23,6 +23,11 @@ class AdminCutsManager {
|
||||
// Location markers for map display
|
||||
this.locationMarkers = null;
|
||||
|
||||
// Pagination properties
|
||||
this.currentPage = 1;
|
||||
this.itemsPerPage = 5;
|
||||
this.totalPages = 1;
|
||||
|
||||
// Bind event handler once to avoid issues with removing listeners
|
||||
this.boundHandleCutActionClick = this.handleCutActionClick.bind(this);
|
||||
}
|
||||
@ -354,6 +359,16 @@ class AdminCutsManager {
|
||||
categoryFilter.addEventListener('change', () => this.filterCuts());
|
||||
}
|
||||
|
||||
// Set up items per page selector
|
||||
const itemsPerPageSelect = document.getElementById('cuts-per-page');
|
||||
if (itemsPerPageSelect) {
|
||||
itemsPerPageSelect.addEventListener('change', (e) => {
|
||||
this.itemsPerPage = parseInt(e.target.value);
|
||||
this.currentPage = 1; // Reset to first page
|
||||
this.renderCutsList();
|
||||
});
|
||||
}
|
||||
|
||||
// Add drawing toolbar button handlers
|
||||
const finishDrawingBtn = document.getElementById('finish-cut-btn');
|
||||
if (finishDrawingBtn) {
|
||||
@ -1036,6 +1051,12 @@ class AdminCutsManager {
|
||||
|
||||
this.allCuts = data.list || [];
|
||||
this.filteredCuts = [...this.allCuts];
|
||||
|
||||
console.log(`Loaded ${this.allCuts.length} cuts from server`);
|
||||
if (this.allCuts.length >= 100) {
|
||||
console.warn('Large dataset detected. Consider implementing pagination or server-side filtering.');
|
||||
}
|
||||
|
||||
this.renderCutsList();
|
||||
|
||||
} catch (error) {
|
||||
@ -1056,11 +1077,31 @@ class AdminCutsManager {
|
||||
|
||||
if (this.filteredCuts.length === 0) {
|
||||
this.cutsList.innerHTML = '<p class="no-data">No cuts found</p>';
|
||||
this.renderPagination(0);
|
||||
return;
|
||||
}
|
||||
|
||||
const html = this.filteredCuts.map(cut => this.renderCutItem(cut)).join('');
|
||||
this.cutsList.innerHTML = html;
|
||||
// Calculate pagination
|
||||
this.totalPages = Math.ceil(this.filteredCuts.length / this.itemsPerPage);
|
||||
const startIndex = (this.currentPage - 1) * this.itemsPerPage;
|
||||
const endIndex = startIndex + this.itemsPerPage;
|
||||
const cutsToShow = this.filteredCuts.slice(startIndex, endIndex);
|
||||
|
||||
// Render header with count and pagination info
|
||||
const headerHtml = `
|
||||
<div class="cuts-list-header">
|
||||
<div class="cuts-count">
|
||||
Showing ${startIndex + 1}-${Math.min(endIndex, this.filteredCuts.length)} of ${this.filteredCuts.length} cuts
|
||||
${this.filteredCuts.length !== this.allCuts.length ? `(filtered from ${this.allCuts.length} total)` : ''}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const cutsHtml = cutsToShow.map(cut => this.renderCutItem(cut)).join('');
|
||||
this.cutsList.innerHTML = headerHtml + cutsHtml;
|
||||
|
||||
// Render pagination controls
|
||||
this.renderPagination(this.filteredCuts.length);
|
||||
|
||||
// Add event delegation for cut action buttons
|
||||
this.cutsList.addEventListener('click', this.boundHandleCutActionClick);
|
||||
@ -1426,20 +1467,148 @@ class AdminCutsManager {
|
||||
let filteredCuts = this.allCuts;
|
||||
|
||||
if (searchTerm) {
|
||||
filteredCuts = filteredCuts.filter(cut =>
|
||||
cut.name.toLowerCase().includes(searchTerm) ||
|
||||
(cut.description && cut.description.toLowerCase().includes(searchTerm))
|
||||
);
|
||||
filteredCuts = filteredCuts.filter(cut => {
|
||||
// Handle different possible field names and null/undefined values
|
||||
const cutName = cut.name || cut.Name || '';
|
||||
const cutDescription = cut.description || cut.Description || '';
|
||||
|
||||
// Prioritize name matches - if name matches, return true immediately
|
||||
if (cutName.toLowerCase().includes(searchTerm)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only check description if name doesn't match
|
||||
return cutDescription.toLowerCase().includes(searchTerm);
|
||||
});
|
||||
|
||||
// Sort results to prioritize name matches at the top
|
||||
filteredCuts.sort((a, b) => {
|
||||
const nameA = a.name || a.Name || '';
|
||||
const nameB = b.name || b.Name || '';
|
||||
const nameAMatches = nameA.toLowerCase().includes(searchTerm);
|
||||
const nameBMatches = nameB.toLowerCase().includes(searchTerm);
|
||||
|
||||
// If both match by name or both don't match by name, maintain original order
|
||||
if (nameAMatches === nameBMatches) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Prioritize name matches (true comes before false)
|
||||
return nameBMatches - nameAMatches;
|
||||
});
|
||||
}
|
||||
|
||||
if (categoryFilter) {
|
||||
filteredCuts = filteredCuts.filter(cut => cut.category === categoryFilter);
|
||||
filteredCuts = filteredCuts.filter(cut => {
|
||||
const cutCategory = cut.category || cut.Category || '';
|
||||
return cutCategory === categoryFilter;
|
||||
});
|
||||
}
|
||||
|
||||
this.filteredCuts = filteredCuts;
|
||||
|
||||
// Reset to first page when filtering
|
||||
this.currentPage = 1;
|
||||
|
||||
this.renderCutsList();
|
||||
}
|
||||
|
||||
renderPagination(totalItems) {
|
||||
const paginationContainer = document.getElementById('cuts-pagination') || this.createPaginationContainer();
|
||||
|
||||
if (totalItems <= this.itemsPerPage) {
|
||||
paginationContainer.innerHTML = '';
|
||||
paginationContainer.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
paginationContainer.style.display = 'block';
|
||||
|
||||
let paginationHtml = '<div class="pagination-controls">';
|
||||
|
||||
// Previous button
|
||||
if (this.currentPage > 1) {
|
||||
paginationHtml += `<button class="pagination-btn" data-page="${this.currentPage - 1}">‹ Previous</button>`;
|
||||
}
|
||||
|
||||
// Page numbers (show max 7 pages)
|
||||
const maxVisiblePages = 7;
|
||||
let startPage = Math.max(1, this.currentPage - Math.floor(maxVisiblePages / 2));
|
||||
let endPage = Math.min(this.totalPages, startPage + maxVisiblePages - 1);
|
||||
|
||||
// Adjust if we're near the end
|
||||
if (endPage - startPage < maxVisiblePages - 1) {
|
||||
startPage = Math.max(1, endPage - maxVisiblePages + 1);
|
||||
}
|
||||
|
||||
// First page and ellipsis
|
||||
if (startPage > 1) {
|
||||
paginationHtml += `<button class="pagination-btn" data-page="1">1</button>`;
|
||||
if (startPage > 2) {
|
||||
paginationHtml += '<span class="pagination-ellipsis">...</span>';
|
||||
}
|
||||
}
|
||||
|
||||
// Page numbers
|
||||
for (let i = startPage; i <= endPage; i++) {
|
||||
const isActive = i === this.currentPage ? 'active' : '';
|
||||
paginationHtml += `<button class="pagination-btn ${isActive}" data-page="${i}">${i}</button>`;
|
||||
}
|
||||
|
||||
// Last page and ellipsis
|
||||
if (endPage < this.totalPages) {
|
||||
if (endPage < this.totalPages - 1) {
|
||||
paginationHtml += '<span class="pagination-ellipsis">...</span>';
|
||||
}
|
||||
paginationHtml += `<button class="pagination-btn" data-page="${this.totalPages}">${this.totalPages}</button>`;
|
||||
}
|
||||
|
||||
// Next button
|
||||
if (this.currentPage < this.totalPages) {
|
||||
paginationHtml += `<button class="pagination-btn" data-page="${this.currentPage + 1}">Next ›</button>`;
|
||||
}
|
||||
|
||||
paginationHtml += '</div>';
|
||||
|
||||
paginationContainer.innerHTML = paginationHtml;
|
||||
|
||||
// Add click handlers for pagination
|
||||
paginationContainer.addEventListener('click', (e) => {
|
||||
if (e.target.classList.contains('pagination-btn') && e.target.dataset.page) {
|
||||
this.goToPage(parseInt(e.target.dataset.page));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
createPaginationContainer() {
|
||||
let container = document.getElementById('cuts-pagination');
|
||||
if (!container) {
|
||||
container = document.createElement('div');
|
||||
container.id = 'cuts-pagination';
|
||||
container.className = 'cuts-pagination';
|
||||
|
||||
// Insert after cuts list
|
||||
const cutsList = document.getElementById('cuts-list');
|
||||
if (cutsList && cutsList.parentNode) {
|
||||
cutsList.parentNode.insertBefore(container, cutsList.nextSibling);
|
||||
}
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
goToPage(page) {
|
||||
if (page < 1 || page > this.totalPages) return;
|
||||
|
||||
this.currentPage = page;
|
||||
this.renderCutsList();
|
||||
|
||||
// Scroll to top of cuts list
|
||||
const cutsList = document.getElementById('cuts-list');
|
||||
if (cutsList) {
|
||||
cutsList.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
}
|
||||
|
||||
exportCuts() {
|
||||
const exportData = {
|
||||
version: '1.0',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user