This commit is contained in:
Flatlogic Bot 2026-04-05 11:53:02 +00:00
parent cc09913585
commit 1b3f6ab743
4 changed files with 227 additions and 0 deletions

View File

@ -378,6 +378,174 @@ function channel_import_workspace_csv(PDO $pdo, string $path): int
return $imported;
}
function channel_ensure_visible_test_rows(PDO $pdo): int
{
$targetCount = 1000;
$baseDate = '2026-04-05';
$rows = [
[
'upper_ch_ref' => 'A TEST LOGISTICS ALPHA',
'country_iso' => 'US',
'country_client' => 'Test Tenant',
'sat_ref' => 'INTELSAT-TEST',
'sat_tpinfo' => '11001/H/30000',
'genre' => 'Test Feed',
'type' => 'free',
'resolution' => 'HD',
'langue' => 'EN',
'region' => 'North America',
'groupe' => 'QA Samples',
'active' => 1,
'idtype' => 1,
'six_id' => '199001',
'sid' => '9901',
'onid' => '91',
'tid' => '401',
'sat_in' => $baseDate,
'sat_out' => null,
'sat_update' => $baseDate,
'sat_ch_client_upper' => 'A TEST LOGISTICS ALPHA',
'sat_client' => 'QA Client',
'counting' => 12,
'lastview' => '2026-04-05 11:40:00',
'manually_edited' => 0,
'manually_edited_at' => null,
'date_in' => $baseDate,
'date_out' => null,
],
[
'upper_ch_ref' => 'A TEST LOGISTICS BETA',
'country_iso' => 'FR',
'country_client' => 'Test Tenant',
'sat_ref' => 'EUTELSAT-TEST',
'sat_tpinfo' => '11002/V/30000',
'genre' => 'Test Feed',
'type' => 'payed',
'resolution' => 'UHD',
'langue' => 'FR',
'region' => 'West Europe',
'groupe' => 'QA Samples',
'active' => 1,
'idtype' => 1,
'six_id' => '199002',
'sid' => '9902',
'onid' => '92',
'tid' => '402',
'sat_in' => $baseDate,
'sat_out' => null,
'sat_update' => $baseDate,
'sat_ch_client_upper' => 'A TEST LOGISTICS BETA',
'sat_client' => 'QA Client',
'counting' => 18,
'lastview' => '2026-04-05 11:41:00',
'manually_edited' => 1,
'manually_edited_at' => $baseDate,
'date_in' => $baseDate,
'date_out' => null,
],
[
'upper_ch_ref' => 'A TEST FILTER GAMMA',
'country_iso' => 'DE',
'country_client' => 'Test Tenant',
'sat_ref' => 'ASTRA-TEST',
'sat_tpinfo' => '11003/H/30000',
'genre' => 'QA Search',
'type' => 'free',
'resolution' => 'SD',
'langue' => 'DE',
'region' => 'DACH',
'groupe' => 'QA Samples',
'active' => 1,
'idtype' => 1,
'six_id' => '199003',
'sid' => '9903',
'onid' => '93',
'tid' => '403',
'sat_in' => $baseDate,
'sat_out' => null,
'sat_update' => $baseDate,
'sat_ch_client_upper' => 'A TEST FILTER GAMMA',
'sat_client' => 'QA Client',
'counting' => 27,
'lastview' => '2026-04-05 11:42:00',
'manually_edited' => 0,
'manually_edited_at' => null,
'date_in' => $baseDate,
'date_out' => null,
],
];
$countryPool = ['US', 'FR', 'DE', 'ES', 'IT', 'GB', 'CA', 'BR', 'AE', 'JP'];
$satellitePool = ['INTELSAT-TEST', 'EUTELSAT-TEST', 'ASTRA-TEST', 'SES-TEST', 'HISPASAT-TEST'];
$languagePool = ['EN', 'FR', 'DE', 'ES', 'IT', 'PT', 'AR', 'JP'];
$regionPool = ['North America', 'West Europe', 'DACH', 'LATAM', 'MENA', 'APAC'];
$resolutionPool = ['SD', 'HD', 'FHD', 'UHD'];
for ($i = 4; $i <= $targetCount; $i++) {
$country = $countryPool[($i - 1) % count($countryPool)];
$satellite = $satellitePool[($i - 1) % count($satellitePool)];
$language = $languagePool[($i - 1) % count($languagePool)];
$region = $regionPool[($i - 1) % count($regionPool)];
$resolution = $resolutionPool[($i - 1) % count($resolutionPool)];
$polarization = $i % 2 === 0 ? 'H' : 'V';
$frequency = 11000 + (($i - 1) % 120);
$symbolRate = 30000 + ((($i - 1) % 5) * 1000);
$hour = intdiv(($i - 1) % 1440, 60);
$minute = ($i - 1) % 60;
$name = sprintf('A TEST LOGISTICS %04d', $i);
$rows[] = [
'upper_ch_ref' => $name,
'country_iso' => $country,
'country_client' => 'Test Tenant',
'sat_ref' => $satellite,
'sat_tpinfo' => sprintf('%d/%s/%d', $frequency, $polarization, $symbolRate),
'genre' => $i % 3 === 0 ? 'QA Search' : 'Test Feed',
'type' => $i % 4 === 0 ? 'payed' : 'free',
'resolution' => $resolution,
'langue' => $language,
'region' => $region,
'groupe' => 'QA Samples',
'active' => 1,
'idtype' => 1,
'six_id' => (string) (200000 + $i),
'sid' => (string) (9900 + $i),
'onid' => (string) (90 + (($i - 1) % 50)),
'tid' => (string) (400 + $i),
'sat_in' => $baseDate,
'sat_out' => null,
'sat_update' => $baseDate,
'sat_ch_client_upper' => $name,
'sat_client' => 'QA Client',
'counting' => $i,
'lastview' => sprintf('2026-04-05 %02d:%02d:00', $hour, $minute),
'manually_edited' => $i % 10 === 0 ? 1 : 0,
'manually_edited_at' => $i % 10 === 0 ? $baseDate : null,
'date_in' => $baseDate,
'date_out' => null,
];
}
$existingStmt = $pdo->query("SELECT upper_ch_ref FROM channels WHERE date_out IS NULL AND upper_ch_ref LIKE 'A TEST %'");
$existingNames = [];
foreach ($existingStmt->fetchAll(PDO::FETCH_COLUMN) as $existingName) {
$existingNames[(string) $existingName] = true;
}
$inserted = 0;
foreach ($rows as $row) {
if (isset($existingNames[$row['upper_ch_ref']])) {
continue;
}
channel_insert($row, $pdo);
$existingNames[$row['upper_ch_ref']] = true;
$inserted++;
}
return $inserted;
}
function channel_app_bootstrap(): void
{
static $booted = false;
@ -555,6 +723,8 @@ function channel_app_bootstrap(): void
}
}
channel_ensure_visible_test_rows($pdo);
$booted = true;
}

View File

@ -34,6 +34,7 @@ document.addEventListener('DOMContentLoaded', () => {
clearAdvancedFiltersBtn: document.getElementById('clearAdvancedFiltersBtn'),
applyAdvancedFiltersBtn: document.getElementById('applyAdvancedFiltersBtn'),
selectPageBtn: document.getElementById('selectPageBtn'),
saveCurrentViewBtn: document.getElementById('saveCurrentViewBtn'),
selectAllPageCheckbox: document.getElementById('selectAllPageCheckbox'),
bulkEditBtn: document.getElementById('bulkEditBtn'),
selectionBar: document.getElementById('selectionBar'),
@ -142,6 +143,13 @@ document.addEventListener('DOMContentLoaded', () => {
is_empty: 'is empty',
is_not_empty: 'is not empty'
};
const exportFields = [
'upper_ch_ref', 'country_iso', 'country_client', 'sat_ref', 'sat_tpinfo',
'genre', 'type', 'resolution', 'langue', 'region', 'groupe', 'active',
'idtype', 'six_id', 'sid', 'onid', 'tid', 'sat_in', 'sat_out',
'sat_update', 'sat_ch_client_upper', 'sat_client', 'counting', 'lastview',
'manually_edited_at'
];
const formatValue = (value) => {
if (value === null || value === undefined || value === '') return '—';
@ -335,6 +343,48 @@ document.addEventListener('DOMContentLoaded', () => {
elements.selectAllPageCheckbox.checked = allSelected;
};
const csvCell = (value) => {
const normalized = value === null || value === undefined ? '' : String(value);
return `"${normalized.replaceAll('"', '""')}"`;
};
const timestampForFilename = () => {
const now = new Date();
const pad = (part) => String(part).padStart(2, '0');
return `${now.getUTCFullYear()}${pad(now.getUTCMonth() + 1)}${pad(now.getUTCDate())}-${pad(now.getUTCHours())}${pad(now.getUTCMinutes())}${pad(now.getUTCSeconds())}`;
};
const updateSaveViewButton = () => {
if (!elements.saveCurrentViewBtn) return;
const count = state.currentRows.length;
elements.saveCurrentViewBtn.disabled = count === 0;
elements.saveCurrentViewBtn.textContent = count > 0 ? `Save visible page (${count})` : 'Save visible page';
};
const exportCurrentView = () => {
if (!state.currentRows.length) {
notify('There is no visible row to save on this page yet.', 'danger');
return;
}
const headers = exportFields.map((field) => labels[field] || field);
const rows = state.currentRows.map((row) => exportFields.map((field) => csvCell(row[field])));
const csvLines = [headers.map(csvCell).join(','), ...rows.map((cells) => cells.join(','))];
const csv = `${csvLines.join('\n')}`;
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
const downloadUrl = URL.createObjectURL(blob);
const link = document.createElement('a');
const page = Number(state.filters.page || 1);
link.href = downloadUrl;
link.download = `channels-visible-page-${page}-${timestampForFilename()}.csv`;
document.body.appendChild(link);
link.click();
link.remove();
URL.revokeObjectURL(downloadUrl);
notify(`Saved ${state.currentRows.length} visible row(s) from page ${page} as CSV.`);
};
const rowClasses = (row) => {
const classes = ['channel-row'];
if (Number(row.manually_edited) === 1) classes.push('row-manual');
@ -398,6 +448,7 @@ document.addEventListener('DOMContentLoaded', () => {
elements.prevPageBtn.disabled = pagination.page <= 1;
elements.nextPageBtn.disabled = pagination.page >= pagination.pages;
updateSelectionUI();
updateSaveViewButton();
};
const fetchChannels = async () => {
@ -877,6 +928,10 @@ document.addEventListener('DOMContentLoaded', () => {
notify('Current page selected.');
});
elements.saveCurrentViewBtn?.addEventListener('click', () => {
exportCurrentView();
});
elements.clearSelectionBtn?.addEventListener('click', () => {
state.selectedIds.clear();
document.querySelectorAll('.row-checkbox').forEach(box => { box.checked = false; });
@ -1106,6 +1161,7 @@ document.addEventListener('DOMContentLoaded', () => {
syncFilterForm();
renderAdvancedFilters();
updateSaveViewButton();
renderHistoryEmpty('Click a row in Dataset to load its previous and current versions.');
refreshAll();
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 KiB

View File

@ -229,6 +229,7 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
</div>
<div class="d-flex flex-wrap gap-2 align-items-center">
<button class="btn btn-outline-secondary btn-sm" id="selectPageBtn">Select page</button>
<button class="btn btn-outline-secondary btn-sm" id="saveCurrentViewBtn">Save visible page</button>
<button class="btn btn-dark btn-sm" id="bulkEditBtn" data-bs-toggle="modal" data-bs-target="#bulkEditModal" disabled>Bulk edit (0)</button>
</div>
</div>