Enhancement: Streams table UI: Added descriptive tooltips to top-toolbar buttons (Add to Channel, Create Channels, Filters, Create Stream, Delete) and to row action icons (Add to Channel, Create New Channel). Tooltips now use a 500ms open delay for consistent behavior with existing table header tooltips.

Streams table button labels: Renamed "Remove" to "Delete" and "Add Stream to Channel" to "Add to Channel" for clarity and consistency with other UI terminology.
This commit is contained in:
SergeantPanda 2026-01-20 18:01:17 -06:00
parent 8bc88112aa
commit c9b454431c
2 changed files with 90 additions and 69 deletions

View file

@ -38,10 +38,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- User-level content filtering: Non-admin users can opt to hide mature content channels across all interfaces (web UI, M3U playlists, EPG data, XtreamCodes API) via "Hide Mature Content" toggle in user settings (stored in custom_properties, admin users always see all content)
- Table header pin toggle: Pin/unpin table headers to keep them visible while scrolling. Toggle available in channel table menu and UI Settings page. Setting persists across sessions and applies to all tables. (Closes #663)
- Cascading filters for streams table: Improved filter usability with hierarchical M3U and Group dropdowns. M3U acts as the parent filter showing only active/enabled accounts, while Group options dynamically update to display only groups available in the selected M3U(s). Only enabled M3U's are displayed. (Closes #647)
- Streams table UI: Added descriptive tooltips to top-toolbar buttons (Add to Channel, Create Channels, Filters, Create Stream, Delete) and to row action icons (Add to Channel, Create New Channel). Tooltips now use a 500ms open delay for consistent behavior with existing table header tooltips.
### Changed
- Table preferences (header pin and table size) now managed together with centralized state management and localStorage persistence.
- Streams table button labels: Renamed "Remove" to "Delete" and "Add Stream to Channel" to "Add to Channel" for clarity and consistency with other UI terminology.
- Frontend tests GitHub workflow now uses Node.js 24 (matching Dockerfile) and runs on both `main` and `dev` branch pushes and pull requests for comprehensive CI coverage.
- Table preferences architecture refactored: Migrated `table-size` preference from individual `useLocalStorage` calls to centralized `useTablePreferences` hook. All table components now read preferences from the table instance (`table.tableSize`, `.g maintainability and providing consistent API across all tables.
- Optimized unassociated streams filter performance: Replaced inefficient reverse foreign key NULL check (`channels__isnull=True`) with Count annotation approach, reducing query time from 4-5 seconds to under 500ms for large datasets (75k+ streams)

View file

@ -117,7 +117,7 @@ const StreamRowActions = ({
return (
<>
<Tooltip label="Add to Channel">
<Tooltip label="Add to Channel" openDelay={500}>
<ActionIcon
size={iconSize}
color={theme.tailwind.blue[6]}
@ -136,7 +136,7 @@ const StreamRowActions = ({
</ActionIcon>
</Tooltip>
<Tooltip label="Create New Channel">
<Tooltip label="Create New Channel" openDelay={500}>
<ActionIcon
size={iconSize}
color={theme.tailwind.green[5]}
@ -1115,58 +1115,73 @@ const StreamsTable = ({ onReady }) => {
gap={6}
>
<Flex gap={6} wrap="nowrap" style={{ flexShrink: 0 }}>
<Button
leftSection={<SquarePlus size={18} />}
variant={
selectedStreamIds.length > 0 && selectedChannelIds.length === 1
? 'light'
: 'default'
}
size="xs"
onClick={addStreamsToChannel}
p={5}
color={
selectedStreamIds.length > 0 && selectedChannelIds.length === 1
? theme.tailwind.green[5]
: undefined
}
style={
selectedStreamIds.length > 0 && selectedChannelIds.length === 1
? {
borderWidth: '1px',
borderColor: theme.tailwind.green[5],
color: 'white',
}
: undefined
}
disabled={
!(
<Tooltip
label="Add selected stream(s) to the selected channel"
openDelay={500}
>
<Button
leftSection={<SquarePlus size={18} />}
variant={
selectedStreamIds.length > 0 &&
selectedChannelIds.length === 1
)
}
>
Add Streams to Channel
</Button>
? 'light'
: 'default'
}
size="xs"
onClick={addStreamsToChannel}
p={5}
color={
selectedStreamIds.length > 0 &&
selectedChannelIds.length === 1
? theme.tailwind.green[5]
: undefined
}
style={
selectedStreamIds.length > 0 &&
selectedChannelIds.length === 1
? {
borderWidth: '1px',
borderColor: theme.tailwind.green[5],
color: 'white',
}
: undefined
}
disabled={
!(
selectedStreamIds.length > 0 &&
selectedChannelIds.length === 1
)
}
>
Add to Channel
</Button>
</Tooltip>
<Button
leftSection={<SquarePlus size={18} />}
variant="default"
size="xs"
onClick={createChannelsFromStreams}
p={5}
disabled={selectedStreamIds.length == 0}
<Tooltip
label={`Create channels from ${selectedStreamIds.length} stream(s)`}
openDelay={500}
>
{`Create Channels (${selectedStreamIds.length})`}
</Button>
<Button
leftSection={<SquarePlus size={18} />}
variant="default"
size="xs"
onClick={createChannelsFromStreams}
p={5}
disabled={selectedStreamIds.length == 0}
>
{`Create Channels (${selectedStreamIds.length})`}
</Button>
</Tooltip>
</Flex>
<Flex gap={6} wrap="nowrap" style={{ flexShrink: 0 }}>
<Menu shadow="md" width={200}>
<Menu.Target>
<Button size="xs" variant="default">
<Filter size={18} />
</Button>
<Tooltip label="Filters" openDelay={500}>
<Button size="xs" variant="default">
<Filter size={18} />
</Button>
</Tooltip>
</Menu.Target>
<Menu.Dropdown>
@ -1185,31 +1200,35 @@ const StreamsTable = ({ onReady }) => {
</Menu.Dropdown>
</Menu>
<Button
leftSection={<SquarePlus size={18} />}
variant="light"
size="xs"
onClick={() => editStream()}
p={5}
color={theme.tailwind.green[5]}
style={{
borderWidth: '1px',
borderColor: theme.tailwind.green[5],
color: 'white',
}}
>
Create Stream
</Button>
<Tooltip label="Create a new custom stream" openDelay={500}>
<Button
leftSection={<SquarePlus size={18} />}
variant="light"
size="xs"
onClick={() => editStream()}
p={5}
color={theme.tailwind.green[5]}
style={{
borderWidth: '1px',
borderColor: theme.tailwind.green[5],
color: 'white',
}}
>
Create Stream
</Button>
</Tooltip>
<Button
leftSection={<SquareMinus size={18} />}
variant="default"
size="xs"
onClick={deleteStreams}
disabled={selectedStreamIds.length == 0}
>
Remove
</Button>
<Tooltip label="Delete selected stream(s)" openDelay={500}>
<Button
leftSection={<SquareMinus size={18} />}
variant="default"
size="xs"
onClick={deleteStreams}
disabled={selectedStreamIds.length == 0}
>
Delete
</Button>
</Tooltip>
</Flex>
</Flex>