feat: add dynamic VM/LXC/PMG type filter for backups

When PMG host backups are detected in the backup list, a new type filter
automatically appears with options to filter by VM, LXC, or PMG (host) type.
This makes it easier to find specific backup types when host backups exist.

The filter is dynamic and only shows when there are host-type backups present.
This commit is contained in:
Pulse Monitor 2025-08-27 19:08:00 +00:00
parent 5d22ef6a0c
commit 2e905cc195
2 changed files with 61 additions and 1 deletions

View file

@ -9,6 +9,9 @@ interface BackupsFilterProps {
groupBy: () => 'date' | 'guest';
setGroupBy: (value: 'date' | 'guest') => void;
searchInputRef?: (el: HTMLInputElement) => void;
typeFilter?: () => 'all' | 'VM' | 'LXC' | 'Host';
setTypeFilter?: (value: 'all' | 'VM' | 'LXC' | 'Host') => void;
hasHostBackups?: () => boolean;
}
export const BackupsFilter: Component<BackupsFilterProps> = (props) => {
@ -107,6 +110,53 @@ export const BackupsFilter: Component<BackupsFilterProps> = (props) => {
<div class="h-5 w-px bg-gray-200 dark:bg-gray-600 hidden sm:block"></div>
{/* Type Filter - Only show when there are Host backups */}
<Show when={props.hasHostBackups && props.hasHostBackups() && props.typeFilter && props.setTypeFilter}>
<div class="inline-flex rounded-lg bg-gray-100 dark:bg-gray-700 p-0.5">
<button type="button"
onClick={() => props.setTypeFilter!('all')}
class={`px-2.5 py-1 text-xs font-medium rounded-md transition-all ${
props.typeFilter!() === 'all'
? 'bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 shadow-sm'
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'
}`}
>
All Types
</button>
<button type="button"
onClick={() => props.setTypeFilter!('VM')}
class={`px-2.5 py-1 text-xs font-medium rounded-md transition-all ${
props.typeFilter!() === 'VM'
? 'bg-white dark:bg-gray-800 text-blue-600 dark:text-blue-400 shadow-sm'
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'
}`}
>
VM
</button>
<button type="button"
onClick={() => props.setTypeFilter!('LXC')}
class={`px-2.5 py-1 text-xs font-medium rounded-md transition-all ${
props.typeFilter!() === 'LXC'
? 'bg-white dark:bg-gray-800 text-green-600 dark:text-green-400 shadow-sm'
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'
}`}
>
LXC
</button>
<button type="button"
onClick={() => props.setTypeFilter!('Host')}
class={`px-2.5 py-1 text-xs font-medium rounded-md transition-all ${
props.typeFilter!() === 'Host'
? 'bg-white dark:bg-gray-800 text-purple-600 dark:text-purple-400 shadow-sm'
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'
}`}
>
PMG
</button>
</div>
<div class="h-5 w-px bg-gray-200 dark:bg-gray-600 hidden sm:block"></div>
</Show>
{/* Group By Filter */}
<div class="inline-flex rounded-lg bg-gray-100 dark:bg-gray-700 p-0.5">
<button type="button"

View file

@ -9,6 +9,7 @@ import { BackupsFilter } from './BackupsFilter';
type BackupType = 'snapshot' | 'local' | 'remote';
type GuestType = 'VM' | 'LXC' | 'Host' | 'Template' | 'ISO';
type FilterableGuestType = 'VM' | 'LXC' | 'Host';
interface UnifiedBackup {
backupType: BackupType;
@ -42,7 +43,7 @@ interface DateGroup {
const UnifiedBackups: Component = () => {
const { state } = useWebSocket();
const [searchTerm, setSearchTerm] = createSignal('');
const [typeFilter, setTypeFilter] = createSignal<'all' | GuestType>('all');
const [typeFilter, setTypeFilter] = createSignal<'all' | FilterableGuestType>('all');
const [backupTypeFilter, setBackupTypeFilter] = createSignal<'all' | BackupType>('all');
const [groupByMode, setGroupByMode] = createSignal<'date' | 'guest'>('date');
@ -96,6 +97,12 @@ const UnifiedBackups: Component = () => {
// TODO: Add time format toggle to BackupsFilter component
// const setUseRelativeTime = ...;
// Check if there are any Host type backups
const hasHostBackups = createMemo(() => {
const data = normalizedData();
return data.some(backup => backup.type === 'Host');
});
// Helper functions
const getDaySuffix = (day: number) => {
if (day >= 11 && day <= 13) return 'th';
@ -1452,6 +1459,9 @@ const UnifiedBackups: Component = () => {
groupBy={groupByMode}
setGroupBy={setGroupByMode}
searchInputRef={(el) => searchInputRef = el}
typeFilter={typeFilter}
setTypeFilter={setTypeFilter}
hasHostBackups={hasHostBackups}
/>
{/* Table */}