mirror of
https://github.com/armbian/imager.git
synced 2026-01-06 12:31:28 -08:00
feat: add system devices toggle in device selection modal
Add a toggle button to show/hide system devices in the device selection modal. This prevents users from accidentally selecting system drives while still allowing advanced users to access them when needed. Changes: - Add showSystemDevices state toggle in DeviceModal - Filter devices based on toggle state (default: hide system devices) - Redesign warning banner with toggle badge button - Add Shield icon and translations for all 15 languages - Update CSS with new banner layout and toggle button styles
This commit is contained in:
@@ -75,6 +75,7 @@ export function DeviceModal({ isOpen, onClose, onSelect }: DeviceModalProps) {
|
||||
const [selectedDevice, setSelectedDevice] = useState<BlockDevice | null>(null);
|
||||
const [showConfirm, setShowConfirm] = useState(false);
|
||||
const [showSkeleton, setShowSkeleton] = useState(false);
|
||||
const [showSystemDevices, setShowSystemDevices] = useState(false);
|
||||
|
||||
// Track previous devices for change detection
|
||||
const prevDevicesRef = useRef<BlockDevice[] | null>(null);
|
||||
@@ -92,6 +93,14 @@ export function DeviceModal({ isOpen, onClose, onSelect }: DeviceModalProps) {
|
||||
return devices && devices.length > 0;
|
||||
}, [devices]);
|
||||
|
||||
// Filter devices based on showSystemDevices toggle
|
||||
const filteredDevices = useMemo(() => {
|
||||
if (showSystemDevices) {
|
||||
return devices;
|
||||
}
|
||||
return devices.filter(d => !d.is_system);
|
||||
}, [devices, showSystemDevices]);
|
||||
|
||||
// Show skeleton with minimum delay
|
||||
useEffect(() => {
|
||||
let skeletonTimeout: NodeJS.Timeout;
|
||||
@@ -158,10 +167,28 @@ export function DeviceModal({ isOpen, onClose, onSelect }: DeviceModalProps) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal isOpen={isOpen && !showConfirm} onClose={onClose} title={t('modal.selectDevice')}>
|
||||
<div className="modal-warning-banner">
|
||||
<AlertTriangle size={16} />
|
||||
<span>{t('flash.dataWarning')}</span>
|
||||
<Modal
|
||||
isOpen={isOpen && !showConfirm}
|
||||
onClose={onClose}
|
||||
title={t('modal.selectDevice')}
|
||||
>
|
||||
<div className="device-warning-banner">
|
||||
<div className="device-warning-banner-content">
|
||||
<div className="device-warning-banner-icon">
|
||||
<AlertTriangle size={16} />
|
||||
</div>
|
||||
<div className="device-warning-banner-title">
|
||||
{t('flash.dataWarning')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => setShowSystemDevices(!showSystemDevices)}
|
||||
className={`system-devices-badge ${showSystemDevices ? 'active' : ''}`}
|
||||
>
|
||||
<Shield size={13} />
|
||||
<span>{showSystemDevices ? t('device.hideSystemDevices') : t('device.showSystemDevices')}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{error ? (
|
||||
@@ -169,7 +196,7 @@ export function DeviceModal({ isOpen, onClose, onSelect }: DeviceModalProps) {
|
||||
) : (
|
||||
<>
|
||||
{showSkeleton && <ListItemSkeleton count={4} />}
|
||||
{devices.length === 0 && !showSkeleton && (
|
||||
{filteredDevices.length === 0 && !showSkeleton && (
|
||||
<div className="no-results">
|
||||
<Usb size={40} />
|
||||
<p>{t('modal.noDevices')}</p>
|
||||
@@ -183,7 +210,7 @@ export function DeviceModal({ isOpen, onClose, onSelect }: DeviceModalProps) {
|
||||
</div>
|
||||
)}
|
||||
<div className="modal-list no-animations">
|
||||
{!showSkeleton && devices.map((device) => {
|
||||
{!showSkeleton && filteredDevices.map((device) => {
|
||||
const deviceType = getDeviceType(device);
|
||||
const badge = getDeviceBadge(deviceType, t);
|
||||
return (
|
||||
@@ -217,7 +244,7 @@ export function DeviceModal({ isOpen, onClose, onSelect }: DeviceModalProps) {
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{!showSkeleton && devices.length > 0 && (
|
||||
{!showSkeleton && filteredDevices.length > 0 && (
|
||||
<div className="modal-refresh-bottom">
|
||||
<button className="btn btn-secondary" onClick={reload} disabled={loading}>
|
||||
<RefreshCw size={14} className={loading ? 'spin' : ''} />
|
||||
|
||||
@@ -63,7 +63,9 @@
|
||||
"sata": "SATA",
|
||||
"sas": "SAS",
|
||||
"nvme": "NVMe",
|
||||
"refresh": "Aktualisieren"
|
||||
"refresh": "Aktualisieren",
|
||||
"showSystemDevices": "Systemlaufwerke anzeigen",
|
||||
"hideSystemDevices": "Systemlaufwerke ausblenden"
|
||||
},
|
||||
"header": {
|
||||
"stepManufacturer": "Hersteller",
|
||||
|
||||
@@ -63,7 +63,9 @@
|
||||
"sata": "SATA",
|
||||
"sas": "SAS",
|
||||
"nvme": "NVMe",
|
||||
"refresh": "Refresh"
|
||||
"refresh": "Refresh",
|
||||
"showSystemDevices": "Show system drives",
|
||||
"hideSystemDevices": "Hide system drives"
|
||||
},
|
||||
"header": {
|
||||
"stepManufacturer": "Manufacturer",
|
||||
|
||||
@@ -63,7 +63,9 @@
|
||||
"sata": "SATA",
|
||||
"sas": "SAS",
|
||||
"nvme": "NVMe",
|
||||
"refresh": "Actualizar"
|
||||
"refresh": "Actualizar",
|
||||
"showSystemDevices": "Mostrar unidades del sistema",
|
||||
"hideSystemDevices": "Ocultar unidades del sistema"
|
||||
},
|
||||
"header": {
|
||||
"stepManufacturer": "Fabricante",
|
||||
|
||||
@@ -63,7 +63,9 @@
|
||||
"sata": "SATA",
|
||||
"sas": "SAS",
|
||||
"nvme": "NVMe",
|
||||
"refresh": "Actualiser"
|
||||
"refresh": "Actualiser",
|
||||
"showSystemDevices": "Afficher les disques système",
|
||||
"hideSystemDevices": "Masquer les disques système"
|
||||
},
|
||||
"header": {
|
||||
"stepManufacturer": "Fabricant",
|
||||
|
||||
@@ -63,7 +63,9 @@
|
||||
"sata": "SATA",
|
||||
"sas": "SAS",
|
||||
"nvme": "NVMe",
|
||||
"refresh": "Aggiorna"
|
||||
"refresh": "Aggiorna",
|
||||
"showSystemDevices": "Mostra dischi di sistema",
|
||||
"hideSystemDevices": "Nascondi dischi di sistema"
|
||||
},
|
||||
"header": {
|
||||
"stepManufacturer": "Produttore",
|
||||
|
||||
@@ -63,7 +63,9 @@
|
||||
"sata": "SATA",
|
||||
"sas": "SAS",
|
||||
"nvme": "NVMe",
|
||||
"refresh": "更新"
|
||||
"refresh": "更新",
|
||||
"showSystemDevices": "システムドライブを表示",
|
||||
"hideSystemDevices": "システムドライブを非表示"
|
||||
},
|
||||
"header": {
|
||||
"stepManufacturer": "メーカー",
|
||||
|
||||
@@ -63,7 +63,9 @@
|
||||
"sata": "SATA",
|
||||
"sas": "SAS",
|
||||
"nvme": "NVMe",
|
||||
"refresh": "새로고침"
|
||||
"refresh": "새로고침",
|
||||
"showSystemDevices": "시스템 드라이브 표시",
|
||||
"hideSystemDevices": "시스템 드라이브 숨기기"
|
||||
},
|
||||
"header": {
|
||||
"stepManufacturer": "제조사",
|
||||
|
||||
@@ -63,7 +63,9 @@
|
||||
"sata": "SATA",
|
||||
"sas": "SAS",
|
||||
"nvme": "NVMe",
|
||||
"refresh": "Vernieuwen"
|
||||
"refresh": "Vernieuwen",
|
||||
"showSystemDevices": "Systeemstations weergeven",
|
||||
"hideSystemDevices": "Systeemstations verbergen"
|
||||
},
|
||||
"header": {
|
||||
"stepManufacturer": "Fabrikant",
|
||||
|
||||
@@ -63,7 +63,9 @@
|
||||
"sata": "SATA",
|
||||
"sas": "SAS",
|
||||
"nvme": "NVMe",
|
||||
"refresh": "Odśwież"
|
||||
"refresh": "Odśwież",
|
||||
"showSystemDevices": "Pokaż dyski systemowe",
|
||||
"hideSystemDevices": "Ukryj dyski systemowe"
|
||||
},
|
||||
"header": {
|
||||
"stepManufacturer": "Producent",
|
||||
|
||||
@@ -63,7 +63,9 @@
|
||||
"sata": "SATA",
|
||||
"sas": "SAS",
|
||||
"nvme": "NVMe",
|
||||
"refresh": "Atualizar"
|
||||
"refresh": "Atualizar",
|
||||
"showSystemDevices": "Mostrar unidades do sistema",
|
||||
"hideSystemDevices": "Ocultar unidades do sistema"
|
||||
},
|
||||
"header": {
|
||||
"stepManufacturer": "Fabricante",
|
||||
|
||||
@@ -63,7 +63,9 @@
|
||||
"sata": "SATA",
|
||||
"sas": "SAS",
|
||||
"nvme": "NVMe",
|
||||
"refresh": "Обновить"
|
||||
"refresh": "Обновить",
|
||||
"showSystemDevices": "Показать системные диски",
|
||||
"hideSystemDevices": "Скрыть системные диски"
|
||||
},
|
||||
"header": {
|
||||
"stepManufacturer": "Производитель",
|
||||
|
||||
@@ -63,7 +63,9 @@
|
||||
"sata": "SATA",
|
||||
"sas": "SAS",
|
||||
"nvme": "NVMe",
|
||||
"refresh": "Osveži"
|
||||
"refresh": "Osveži",
|
||||
"showSystemDevices": "Prikaži sistemske pogone",
|
||||
"hideSystemDevices": "Skrij sistemske pogone"
|
||||
},
|
||||
"header": {
|
||||
"stepManufacturer": "Proizvajalec",
|
||||
|
||||
@@ -63,7 +63,9 @@
|
||||
"sata": "SATA",
|
||||
"sas": "SAS",
|
||||
"nvme": "NVMe",
|
||||
"refresh": "Yenile"
|
||||
"refresh": "Yenile",
|
||||
"showSystemDevices": "Sistem sürücülerini göster",
|
||||
"hideSystemDevices": "Sistem sürücülerini gizle"
|
||||
},
|
||||
"header": {
|
||||
"stepManufacturer": "Üretici",
|
||||
|
||||
@@ -63,7 +63,9 @@
|
||||
"sata": "SATA",
|
||||
"sas": "SAS",
|
||||
"nvme": "NVMe",
|
||||
"refresh": "Оновити"
|
||||
"refresh": "Оновити",
|
||||
"showSystemDevices": "Показати системні диски",
|
||||
"hideSystemDevices": "Приховати системні диски"
|
||||
},
|
||||
"header": {
|
||||
"stepManufacturer": "Виробник",
|
||||
|
||||
@@ -63,7 +63,9 @@
|
||||
"sata": "SATA",
|
||||
"sas": "SAS",
|
||||
"nvme": "NVMe",
|
||||
"refresh": "刷新"
|
||||
"refresh": "刷新",
|
||||
"showSystemDevices": "显示系统驱动器",
|
||||
"hideSystemDevices": "隐藏系统驱动器"
|
||||
},
|
||||
"header": {
|
||||
"stepManufacturer": "制造商",
|
||||
|
||||
@@ -695,7 +695,121 @@
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
DEVICE SECTION
|
||||
DEVICE WARNING BANNER
|
||||
======================================== */
|
||||
.device-warning-banner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
padding: 12px 16px;
|
||||
background: rgba(239, 68, 68, 0.08);
|
||||
border-bottom: 1px solid rgba(239, 68, 68, 0.15);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.device-warning-banner {
|
||||
background: rgba(239, 68, 68, 0.12);
|
||||
border-bottom-color: rgba(239, 68, 68, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.device-warning-banner-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.device-warning-banner-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 8px;
|
||||
background: rgba(239, 68, 68, 0.15);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.device-warning-banner-icon {
|
||||
background: rgba(239, 68, 68, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.device-warning-banner-icon svg {
|
||||
color: var(--armbian-red);
|
||||
}
|
||||
|
||||
.device-warning-banner-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* System Devices Badge */
|
||||
.system-devices-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 12px;
|
||||
border-radius: 8px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
border: 1px solid var(--border-color);
|
||||
background-color: var(--bg-secondary);
|
||||
color: var(--text-secondary);
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.system-devices-badge:hover {
|
||||
background-color: var(--bg-hover);
|
||||
border-color: var(--text-muted);
|
||||
}
|
||||
|
||||
.system-devices-badge.active {
|
||||
background-color: rgba(239, 68, 68, 0.12);
|
||||
border-color: rgba(239, 68, 68, 0.3);
|
||||
color: var(--armbian-red);
|
||||
animation: badge-pulse 2s infinite;
|
||||
}
|
||||
|
||||
.system-devices-badge.active:hover {
|
||||
background-color: rgba(239, 68, 68, 0.18);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.system-devices-badge.active {
|
||||
background-color: rgba(239, 68, 68, 0.18);
|
||||
border-color: rgba(239, 68, 68, 0.4);
|
||||
}
|
||||
|
||||
.system-devices-badge.active:hover {
|
||||
background-color: rgba(239, 68, 68, 0.24);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes badge-pulse {
|
||||
0%, 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.3); }
|
||||
50% { box-shadow: 0 0 0 6px rgba(239, 68, 68, 0); }
|
||||
}
|
||||
|
||||
/* Respect user motion preferences */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.system-devices-badge {
|
||||
transition: background-color 0.2s ease, color 0.2s ease;
|
||||
}
|
||||
|
||||
.system-devices-badge.active {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
DEVICE SECTION (Legacy)
|
||||
======================================== */
|
||||
.device-warning {
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user