Files
chimera-Public/renderer/modules/install-destination.js
T

78 lines
4.5 KiB
JavaScript

(function installDestinationSelector() {
'use strict';
let options = [];
let requiredBytes = 0;
const esc = value => String(value == null ? '' : value).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
const bytes = value => value == null ? 'unknown' : value >= 1024 ** 3 ? `${(value / 1024 ** 3).toFixed(1)} GB` : value >= 1024 ** 2 ? `${(value / 1024 ** 2).toFixed(1)} MB` : `${Math.max(0, value)} B`;
const age = value => value == null ? 'unknown age' : value < 60_000 ? 'just now' : value < 3_600_000 ? `${Math.ceil(value / 60_000)} min old` : `${Math.ceil(value / 3_600_000)} h old`;
const reason = code => ({
'offline-volume': 'offline',
'install-capability-disabled': 'install disabled by adapter',
'missing-mountpoint': 'mountpoint unavailable',
'capacity-unknown': 'capacity unknown',
'insufficient-capacity': 'not enough free space',
'stale-capacity-telemetry': 'capacity telemetry stale',
'stale-capability-telemetry': 'capability telemetry stale',
'compatibility-incompatible': 'blocked by applicable compatibility evidence',
}[code] || code);
function selected() {
const select = document.getElementById('install-destination-volume');
return options.find(item => item.volumeId === select?.value) || null;
}
function expertOpen() {
return document.getElementById('install-expert-destination')?.open === true;
}
function renderStatus() {
const status = document.getElementById('install-destination-status');
const option = selected();
if (!status) return;
if (option) {
status.className = `install-destination-status ${option.eligible ? 'is-eligible' : 'is-ineligible'}`;
status.innerHTML = `<strong>${esc(option.eligible ? 'Eligible destination' : 'Destination unavailable')}</strong><span>Required ${esc(bytes(requiredBytes))} · free ${esc(bytes(option.freeBytes))} · projected ${esc(bytes(option.projectedFreeBytes))} · evidence ${esc(age(option.capacityAgeMs))}${option.reasons.length ? ` · ${esc(option.reasons.map(reason).join(', '))}` : ''}</span>`;
const raw = document.getElementById('install-ftp-path');
if (option.compatibility) status.insertAdjacentHTML('beforeend', window.chimeraCompatibilityGuidance?.markup?.(option.compatibility) || '');
if (raw && option.suggestedRemotePath) raw.value = option.suggestedRemotePath;
} else {
status.className = 'install-destination-status is-ineligible';
status.innerHTML = '<strong>No eligible semantic destination</strong><span>Refresh console storage evidence or use the Expert raw-path override.</span>';
}
if (typeof updateInstallConfirmState === 'function') updateInstallConfirmState('pfs');
}
async function load({ titleId, required = 0, legacyPath = '' } = {}) {
requiredBytes = Math.max(0, Number(required) || 0);
const packet = await window.pork.installDestinations({ titleId, requiredBytes });
options = Array.isArray(packet?.destinations) ? packet.destinations : [];
const select = document.getElementById('install-destination-volume');
const raw = document.getElementById('install-ftp-path');
if (raw) raw.value = legacyPath || '';
if (!select) return packet;
select.innerHTML = '<option value="">Select a destination volume</option>' + options.map(option => {
const suffix = option.eligible ? `${bytes(option.freeBytes)} free` : option.reasons.map(reason).join(', ');
return `<option value="${esc(option.volumeId)}"${option.eligible ? '' : ' disabled'}>${esc(option.deviceName)} · ${esc(option.volumeKey)} · ${esc(suffix)}</option>`;
}).join('');
const preferred = options.find(option => option.eligible);
select.value = preferred?.volumeId || '';
renderStatus();
return packet;
}
function selection() {
const option = selected();
if (option?.eligible) return { destinationVolumeId: option.volumeId, remotePath: option.suggestedRemotePath, expertRawPath: false };
const raw = document.getElementById('install-ftp-path')?.value?.trim() || '';
return expertOpen() && raw ? { destinationVolumeId: null, remotePath: raw, expertRawPath: true } : null;
}
document.getElementById('install-destination-volume')?.addEventListener('change', renderStatus);
document.getElementById('install-expert-destination')?.addEventListener('toggle', renderStatus);
document.getElementById('install-ftp-path')?.addEventListener('input', renderStatus);
window.chimeraInstallDestination = Object.freeze({ load, selection, isReady: () => Boolean(selection()) });
})();