Enhancement: Visual stale indicators for streams and groups: Added is_stale field to Stream and both is_stale and last_seen fields to ChannelGroupM3UAccount models to track items in their retention grace period. Stale groups display with orange buttons and a warning tooltip, while stale streams show with a red background color matching the visual treatment of empty channels.
Some checks failed
CI Pipeline / prepare (push) Has been cancelled
Build and Push Multi-Arch Docker Image / build-and-push (push) Has been cancelled
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Has been cancelled
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Has been cancelled
CI Pipeline / create-manifest (push) Has been cancelled

This commit is contained in:
SergeantPanda 2026-01-09 14:57:07 -06:00
parent a84553d15c
commit 719a975210
4 changed files with 47 additions and 18 deletions

View file

@ -10,7 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Group retention policy for M3U accounts: Groups now follow the same stale retention logic as streams, using the account's `stale_stream_days` setting. Groups that temporarily disappear from an M3U source are retained for the configured retention period instead of being immediately deleted, preserving user settings and preventing data loss when providers temporarily remove/re-add groups. (Closes #809)
- Stale status indicators for streams and groups: Added `is_stale` field to both Stream and ChannelGroupM3UAccount models to track items in their grace period (seen in previous refresh but not current).
- Visual stale indicators for streams and groups: Added `is_stale` field to Stream and both `is_stale` and `last_seen` fields to ChannelGroupM3UAccount models to track items in their retention grace period. Stale groups display with orange buttons and a warning tooltip, while stale streams show with a red background color matching the visual treatment of empty channels.
### Changed

View file

@ -263,25 +263,42 @@ const LiveGroupFilter = ({
}}
>
{/* Group Enable/Disable Button */}
<Button
color={group.enabled ? 'green' : 'gray'}
variant="filled"
onClick={() => toggleGroupEnabled(group.channel_group)}
radius="md"
size="xs"
leftSection={
group.enabled ? (
<CircleCheck size={14} />
) : (
<CircleX size={14} />
)
<Tooltip
label={
group.enabled && group.is_stale
? 'This group was not seen in the last M3U refresh and will be deleted after the retention period expires'
: ''
}
fullWidth
disabled={!group.enabled || !group.is_stale}
multiline
w={220}
>
<Text size="xs" truncate>
{group.name}
</Text>
</Button>
<Button
color={
group.enabled
? group.is_stale
? 'orange'
: 'green'
: 'gray'
}
variant="filled"
onClick={() => toggleGroupEnabled(group.channel_group)}
radius="md"
size="xs"
leftSection={
group.enabled ? (
<CircleCheck size={14} />
) : (
<CircleX size={14} />
)
}
fullWidth
>
<Text size="xs" truncate>
{group.name}
</Text>
</Button>
</Tooltip>
{/* Auto Sync Controls */}
<Stack spacing="xs" style={{ '--stack-gap': '4px' }}>

View file

@ -105,6 +105,7 @@ const DraggableRow = ({ row, index }) => {
}}
>
{row.getVisibleCells().map((cell) => {
const isStale = row.original.is_stale;
return (
<Box
className="td"
@ -115,6 +116,9 @@ const DraggableRow = ({ row, index }) => {
? cell.column.getSize()
: undefined,
minWidth: 0,
...(isStale && {
backgroundColor: 'rgba(239, 68, 68, 0.15)',
}),
}}
>
<Flex align="center" style={{ height: '100%' }}>

View file

@ -885,6 +885,14 @@ const StreamsTable = ({ onReady }) => {
bodyCellRenderFns: {
actions: renderBodyCell,
},
getRowStyles: (row) => {
if (row.original.is_stale) {
return {
backgroundColor: 'rgba(239, 68, 68, 0.15)',
};
}
return {};
},
});
/**