mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-07-25 02:57:57 +00:00
Add ability to cleanup all unused groups.
This commit is contained in:
parent
adc6604fa2
commit
9b7aa0c894
3 changed files with 93 additions and 9 deletions
|
|
@ -198,47 +198,78 @@ class ChannelGroupViewSet(viewsets.ModelViewSet):
|
|||
def update(self, request, *args, **kwargs):
|
||||
"""Override update to check M3U associations"""
|
||||
instance = self.get_object()
|
||||
|
||||
|
||||
# Check if group has M3U account associations
|
||||
if hasattr(instance, 'm3u_account') and instance.m3u_account.exists():
|
||||
return Response(
|
||||
{"error": "Cannot edit group with M3U account associations"},
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
|
||||
return super().update(request, *args, **kwargs)
|
||||
|
||||
def partial_update(self, request, *args, **kwargs):
|
||||
"""Override partial_update to check M3U associations"""
|
||||
instance = self.get_object()
|
||||
|
||||
|
||||
# Check if group has M3U account associations
|
||||
if hasattr(instance, 'm3u_account') and instance.m3u_account.exists():
|
||||
return Response(
|
||||
{"error": "Cannot edit group with M3U account associations"},
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
|
||||
return super().partial_update(request, *args, **kwargs)
|
||||
|
||||
@swagger_auto_schema(
|
||||
method="post",
|
||||
operation_description="Delete all channel groups that have no associations (no channels or M3U accounts)",
|
||||
responses={200: "Cleanup completed"},
|
||||
)
|
||||
@action(detail=False, methods=["post"], url_path="cleanup")
|
||||
def cleanup_unused_groups(self, request):
|
||||
"""Delete all channel groups with no channels or M3U account associations"""
|
||||
from django.db.models import Count
|
||||
|
||||
# Find groups with no channels and no M3U account associations
|
||||
unused_groups = ChannelGroup.objects.annotate(
|
||||
channel_count=Count('channels', distinct=True),
|
||||
m3u_account_count=Count('m3u_account', distinct=True)
|
||||
).filter(
|
||||
channel_count=0,
|
||||
m3u_account_count=0
|
||||
)
|
||||
|
||||
deleted_count = unused_groups.count()
|
||||
group_names = list(unused_groups.values_list('name', flat=True))
|
||||
|
||||
# Delete the unused groups
|
||||
unused_groups.delete()
|
||||
|
||||
return Response({
|
||||
"message": f"Successfully deleted {deleted_count} unused channel groups",
|
||||
"deleted_count": deleted_count,
|
||||
"deleted_groups": group_names
|
||||
})
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
"""Override destroy to check for associations before deletion"""
|
||||
instance = self.get_object()
|
||||
|
||||
|
||||
# Check if group has associated channels
|
||||
if instance.channels.exists():
|
||||
return Response(
|
||||
{"error": "Cannot delete group with associated channels"},
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
|
||||
# Check if group has M3U account associations
|
||||
if hasattr(instance, 'm3u_account') and instance.m3u_account.exists():
|
||||
return Response(
|
||||
{"error": "Cannot delete group with M3U account associations"},
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
|
||||
return super().destroy(request, *args, **kwargs)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -301,6 +301,22 @@ export default class API {
|
|||
}
|
||||
}
|
||||
|
||||
static async cleanupUnusedChannelGroups() {
|
||||
try {
|
||||
const response = await request(`${host}/api/channels/groups/cleanup/`, {
|
||||
method: 'POST',
|
||||
});
|
||||
|
||||
// Refresh channel groups to update the UI
|
||||
useChannelsStore.getState().fetchChannelGroups();
|
||||
|
||||
return response;
|
||||
} catch (e) {
|
||||
errorNotification('Failed to cleanup unused channel groups', e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
static async addChannel(channel) {
|
||||
try {
|
||||
let body = null;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ import {
|
|||
X,
|
||||
AlertCircle,
|
||||
Database,
|
||||
Tv
|
||||
Tv,
|
||||
Trash
|
||||
} from 'lucide-react';
|
||||
import { notifications } from '@mantine/notifications';
|
||||
import useChannelsStore from '../../store/channels';
|
||||
|
|
@ -135,6 +136,7 @@ const GroupManager = React.memo(({ isOpen, onClose }) => {
|
|||
const [groupUsage, setGroupUsage] = useState({});
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [isCleaningUp, setIsCleaningUp] = useState(false);
|
||||
|
||||
// Memoize the channel groups array to prevent unnecessary re-renders
|
||||
const channelGroupsArray = useMemo(() =>
|
||||
|
|
@ -305,6 +307,29 @@ const GroupManager = React.memo(({ isOpen, onClose }) => {
|
|||
setSearchTerm(e.target.value);
|
||||
}, []);
|
||||
|
||||
const handleCleanup = useCallback(async () => {
|
||||
setIsCleaningUp(true);
|
||||
try {
|
||||
const result = await API.cleanupUnusedChannelGroups();
|
||||
|
||||
notifications.show({
|
||||
title: 'Cleanup Complete',
|
||||
message: `Successfully deleted ${result.deleted_count} unused groups`,
|
||||
color: 'green',
|
||||
});
|
||||
|
||||
fetchGroupUsage(); // Refresh usage data
|
||||
} catch (error) {
|
||||
notifications.show({
|
||||
title: 'Cleanup Failed',
|
||||
message: 'Failed to cleanup unused groups',
|
||||
color: 'red',
|
||||
});
|
||||
} finally {
|
||||
setIsCleaningUp(false);
|
||||
}
|
||||
}, [fetchGroupUsage]);
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
|
|
@ -322,7 +347,19 @@ const GroupManager = React.memo(({ isOpen, onClose }) => {
|
|||
|
||||
{/* Create new group section */}
|
||||
<Stack>
|
||||
<Text size="sm" fw={600}>Create New Group</Text>
|
||||
<Group justify="space-between" align="center">
|
||||
<Text size="sm" fw={600}>Create New Group</Text>
|
||||
<Button
|
||||
leftSection={<Trash size={16} />}
|
||||
variant="light"
|
||||
size="sm"
|
||||
color="orange"
|
||||
onClick={handleCleanup}
|
||||
loading={isCleaningUp}
|
||||
>
|
||||
Cleanup Unused
|
||||
</Button>
|
||||
</Group>
|
||||
<Group>
|
||||
{isCreating ? (
|
||||
<>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue