Merge pull request #707 from bobey6/main

Enhancement: Add sort by 'Group' or 'M3U' buttons to Streams
This commit is contained in:
SergeantPanda 2025-12-03 17:27:42 -06:00 committed by GitHub
commit 6a96b6b485
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 51 additions and 16 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

@ -105,6 +105,7 @@ const CustomTableHeader = ({
...(header.column.columnDef.style &&
header.column.columnDef.style),
height: '100%',
width: '100%',
paddingRight: header.column.getCanResize() ? '8px' : '0px', // Add padding for resize handle
}}
>

View file

@ -183,7 +183,7 @@ const StreamsTable = () => {
const [pageCount, setPageCount] = useState(0);
const [paginationString, setPaginationString] = useState('');
const [isLoading, setIsLoading] = useState(true);
const [sorting, setSorting] = useState([{ id: 'name', desc: '' }]);
const [sorting, setSorting] = useState([{ id: 'name', desc: false }]);
const [selectedStreamIds, setSelectedStreamIds] = useState([]);
// Channel numbering modal state
@ -299,6 +299,7 @@ const StreamsTable = () => {
),
},
{
header: 'Group',
id: 'group',
accessorFn: (row) =>
channelGroups[row.channel_group]
@ -320,6 +321,7 @@ const StreamsTable = () => {
),
},
{
header: 'M3U',
id: 'm3u',
size: columnSizing.m3u || 150,
accessorFn: (row) =>
@ -386,7 +388,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}`);
}
@ -692,8 +701,8 @@ const StreamsTable = () => {
const sortField = sorting[0]?.id;
const sortDirection = sorting[0]?.desc;
if (sortField == column) {
if (sortDirection == false) {
if (sortField === column) {
if (sortDirection === false) {
setSorting([
{
id: column,
@ -701,7 +710,8 @@ const StreamsTable = () => {
},
]);
} else {
setSorting([]);
// Reset to default sort (name ascending) instead of clearing
setSorting([{ id: 'name', desc: false }]);
}
} else {
setSorting([
@ -726,7 +736,7 @@ const StreamsTable = () => {
switch (header.id) {
case 'name':
return (
<Flex gap="sm">
<Flex align="center" style={{ width: '100%', flex: 1 }}>
<TextInput
name="name"
placeholder="Name"
@ -737,19 +747,23 @@ const StreamsTable = () => {
variant="unstyled"
className="table-input-header"
leftSection={<Search size={14} opacity={0.5} />}
/>
<Center>
{React.createElement(sortingIcon, {
onClick: () => onSortingChange('name'),
style={{ flex: 1, minWidth: 0 }}
rightSectionPointerEvents="auto"
rightSection={React.createElement(sortingIcon, {
onClick: (e) => {
e.stopPropagation();
onSortingChange('name');
},
size: 14,
style: { cursor: 'pointer' },
})}
</Center>
/>
</Flex>
);
case 'group':
return (
<Box onClick={handleSelectClick} style={{ width: '100%' }}>
<Flex align="center" style={{ width: '100%', flex: 1 }}>
<MultiSelect
placeholder="Group"
searchable
@ -761,13 +775,23 @@ const StreamsTable = () => {
variant="unstyled"
className="table-input-header custom-multiselect"
clearable
style={{ flex: 1, minWidth: 0 }}
rightSectionPointerEvents="auto"
rightSection={React.createElement(sortingIcon, {
onClick: (e) => {
e.stopPropagation();
onSortingChange('group');
},
size: 14,
style: { cursor: 'pointer' },
})}
/>
</Box>
</Flex>
);
case 'm3u':
return (
<Box onClick={handleSelectClick}>
<Flex align="center" style={{ width: '100%', flex: 1 }}>
<Select
placeholder="M3U"
searchable
@ -782,8 +806,18 @@ const StreamsTable = () => {
}))}
variant="unstyled"
className="table-input-header"
style={{ flex: 1, minWidth: 0 }}
rightSectionPointerEvents="auto"
rightSection={React.createElement(sortingIcon, {
onClick: (e) => {
e.stopPropagation();
onSortingChange('m3u');
},
size: 14,
style: { cursor: 'pointer' },
})}
/>
</Box>
</Flex>
);
}
};