Add sorting functionality to Group and M3U columns in Streams table

- Added m3u_account__name to backend ordering_fields in StreamViewSet
- Implemented field mapping in frontend to convert column IDs to backend field names
- Added sort buttons to both Group and M3U columns with proper icons
- Sort buttons show current sort state (ascending/descending/none)
- Maintains consistent UX with existing Name column sorting
This commit is contained in:
GitHub Copilot 2025-11-30 19:20:25 +00:00
parent fea7c99021
commit 641dcfc21e
2 changed files with 56 additions and 33 deletions

View file

@ -124,7 +124,7 @@ class StreamViewSet(viewsets.ModelViewSet):
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
filterset_class = StreamFilter
search_fields = ["name", "channel_group__name"]
ordering_fields = ["name", "channel_group__name"]
ordering_fields = ["name", "channel_group__name", "m3u_account__name"]
ordering = ["-name"]
def get_permissions(self):

View file

@ -385,7 +385,14 @@ const StreamsTable = () => {
// Apply sorting
if (sorting.length > 0) {
const sortField = sorting[0].id;
const columnId = sorting[0].id;
// Map frontend column IDs to backend field names
const fieldMapping = {
name: 'name',
group: 'channel_group__name',
m3u: 'm3u_account__name',
};
const sortField = fieldMapping[columnId] || columnId;
const sortDirection = sorting[0].desc ? '-' : '';
params.append('ordering', `${sortDirection}${sortField}`);
}
@ -747,41 +754,57 @@ const StreamsTable = () => {
case 'group':
return (
<Box onClick={handleSelectClick} style={{ width: '100%' }}>
<MultiSelect
placeholder="Group"
searchable
size="xs"
nothingFoundMessage="No options"
onClick={handleSelectClick}
onChange={handleGroupChange}
data={groupOptions}
variant="unstyled"
className="table-input-header custom-multiselect"
clearable
/>
</Box>
<Flex gap="sm">
<Box onClick={handleSelectClick} style={{ width: '100%' }}>
<MultiSelect
placeholder="Group"
searchable
size="xs"
nothingFoundMessage="No options"
onClick={handleSelectClick}
onChange={handleGroupChange}
data={groupOptions}
variant="unstyled"
className="table-input-header custom-multiselect"
clearable
/>
</Box>
<Center>
{React.createElement(sortingIcon, {
onClick: () => onSortingChange('group'),
size: 14,
})}
</Center>
</Flex>
);
case 'm3u':
return (
<Box onClick={handleSelectClick}>
<Select
placeholder="M3U"
searchable
clearable
size="xs"
nothingFoundMessage="No options"
onClick={handleSelectClick}
onChange={handleM3UChange}
data={playlists.map((playlist) => ({
label: playlist.name,
value: `${playlist.id}`,
}))}
variant="unstyled"
className="table-input-header"
/>
</Box>
<Flex gap="sm">
<Box onClick={handleSelectClick} style={{ width: '100%' }}>
<Select
placeholder="M3U"
searchable
clearable
size="xs"
nothingFoundMessage="No options"
onClick={handleSelectClick}
onChange={handleM3UChange}
data={playlists.map((playlist) => ({
label: playlist.name,
value: `${playlist.id}`,
}))}
variant="unstyled"
className="table-input-header"
/>
</Box>
<Center>
{React.createElement(sortingIcon, {
onClick: () => onSortingChange('m3u'),
size: 14,
})}
</Center>
</Flex>
);
}
};