From 22f0a4078bafa671c9c564e02b128b4615ed1c1e Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Fri, 12 Sep 2025 09:22:02 -0500 Subject: [PATCH 01/11] Implement column resizing functionality in Channels Table, Streams Table and CustomTableHeader --- .../src/components/tables/ChannelsTable.jsx | 21 +++++++++++ .../tables/CustomTable/CustomTableHeader.jsx | 35 +++++++++++++++++++ .../components/tables/CustomTable/index.jsx | 3 ++ frontend/src/components/tables/table.css | 32 +++++++++++++++++ 4 files changed, 91 insertions(+) diff --git a/frontend/src/components/tables/ChannelsTable.jsx b/frontend/src/components/tables/ChannelsTable.jsx index 313d2b4b..d216d44a 100644 --- a/frontend/src/components/tables/ChannelsTable.jsx +++ b/frontend/src/components/tables/ChannelsTable.jsx @@ -306,6 +306,9 @@ const ChannelsTable = ({}) => { const [isBulkDelete, setIsBulkDelete] = useState(false); const [channelToDelete, setChannelToDelete] = useState(null); + // Column sizing state for resizable columns + const [columnSizing, setColumnSizing] = useLocalStorage('channels-table-column-sizing', {}); + // M3U and EPG URL configuration state const [m3uParams, setM3uParams] = useState({ cachedlogos: true, @@ -697,14 +700,17 @@ const ChannelsTable = ({}) => { { id: 'expand', size: 20, + enableResizing: false, }, { id: 'select', size: 30, + enableResizing: false, }, { id: 'enabled', size: 45, + enableResizing: false, cell: ({ row, table }) => { return ( { id: 'channel_number', accessorKey: 'channel_number', size: 40, + minSize: 30, + maxSize: 100, cell: ({ getValue }) => { const value = getValue(); // Format as integer if no decimal component @@ -739,6 +747,7 @@ const ChannelsTable = ({}) => { { id: 'name', accessorKey: 'name', + minSize: 100, cell: ({ getValue }) => ( { ); }, size: 120, + minSize: 80, + maxSize: 200, }, { id: 'channel_group', @@ -813,6 +824,8 @@ const ChannelsTable = ({}) => { ), size: 175, + minSize: 100, + maxSize: 300, }, { id: 'logo', @@ -821,6 +834,9 @@ const ChannelsTable = ({}) => { return row.logo_id; }, size: 75, + minSize: 50, + maxSize: 120, + enableResizing: false, header: '', cell: ({ getValue }) => { const logoId = getValue(); @@ -839,6 +855,7 @@ const ChannelsTable = ({}) => { { id: 'actions', size: tableSize == 'compact' ? 75 : 100, + enableResizing: false, header: '', cell: ({ row }) => ( { manualFiltering: true, enableRowSelection: true, onRowSelectionChange: onRowSelectionChange, + state: { + columnSizing, + }, + onColumnSizingChange: setColumnSizing, getExpandedRowHeight: (row) => { return 20 + 28 * row.original.streams.length; }, diff --git a/frontend/src/components/tables/CustomTable/CustomTableHeader.jsx b/frontend/src/components/tables/CustomTable/CustomTableHeader.jsx index 1e32e258..17ceecd7 100644 --- a/frontend/src/components/tables/CustomTable/CustomTableHeader.jsx +++ b/frontend/src/components/tables/CustomTable/CustomTableHeader.jsx @@ -67,6 +67,7 @@ const CustomTableHeader = ({ ? header.getSize() : undefined, minWidth: 0, + position: 'relative', // ...(tableCellProps && tableCellProps({ cell: header })), }} > @@ -80,6 +81,40 @@ const CustomTableHeader = ({ > {renderHeaderCell(header)} + {header.column.getCanResize() && ( + { + e.target.style.opacity = '1'; + e.target.style.backgroundColor = '#6b7280'; + }} + onMouseLeave={(e) => { + if (!header.column.getIsResizing()) { + e.target.style.opacity = '0.5'; + e.target.style.backgroundColor = 'transparent'; + } + }} + /> + )} ); })} diff --git a/frontend/src/components/tables/CustomTable/index.jsx b/frontend/src/components/tables/CustomTable/index.jsx index 3be2dc2f..3a1ab69b 100644 --- a/frontend/src/components/tables/CustomTable/index.jsx +++ b/frontend/src/components/tables/CustomTable/index.jsx @@ -92,8 +92,11 @@ const useTable = ({ state: { data: options.data, selectedTableIds, + columnSizing: options.state?.columnSizing || {}, }, getCoreRowModel: options.getCoreRowModel ?? getCoreRowModel(), + enableColumnResizing: true, + columnResizeMode: 'onChange', }); const selectedTableIdsSet = useMemo( diff --git a/frontend/src/components/tables/table.css b/frontend/src/components/tables/table.css index 5392d1f8..15304103 100644 --- a/frontend/src/components/tables/table.css +++ b/frontend/src/components/tables/table.css @@ -180,3 +180,35 @@ html { -ms-user-select: text !important; cursor: text !important; } + +/* Column resize handle styles */ +.resizer { + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 5px; + cursor: col-resize; + user-select: none; + touch-action: none; + background-color: transparent; + opacity: 0; + transition: all 0.2s ease; +} + +.resizer:hover { + opacity: 1 !important; + background-color: #6b7280 !important; +} + +.resizer.isResizing { + opacity: 1 !important; + background-color: #3b82f6 !important; + width: 3px; +} + +/* Show resize handle on header hover */ +.th:hover .resizer { + opacity: 0.5; + background-color: #6b7280; +} From 09ba42d36c57e13ac44b97e1660cfb9bfff61eda Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Fri, 12 Sep 2025 10:08:46 -0500 Subject: [PATCH 02/11] Enhance column resizing functionality in ChannelsTable, CustomTableHeader, and CustomTableBody components --- .../src/components/tables/ChannelsTable.jsx | 16 +++++++++---- .../tables/CustomTable/CustomTableBody.jsx | 15 ++++++++---- .../tables/CustomTable/CustomTableHeader.jsx | 23 +++++++++++++------ .../components/tables/CustomTable/index.jsx | 7 +++--- 4 files changed, 42 insertions(+), 19 deletions(-) diff --git a/frontend/src/components/tables/ChannelsTable.jsx b/frontend/src/components/tables/ChannelsTable.jsx index d216d44a..bd200c67 100644 --- a/frontend/src/components/tables/ChannelsTable.jsx +++ b/frontend/src/components/tables/ChannelsTable.jsx @@ -307,7 +307,10 @@ const ChannelsTable = ({}) => { const [channelToDelete, setChannelToDelete] = useState(null); // Column sizing state for resizable columns - const [columnSizing, setColumnSizing] = useLocalStorage('channels-table-column-sizing', {}); + const [columnSizing, setColumnSizing] = useLocalStorage( + 'channels-table-column-sizing', + {} + ); // M3U and EPG URL configuration state const [m3uParams, setM3uParams] = useState({ @@ -724,7 +727,7 @@ const ChannelsTable = ({}) => { { id: 'channel_number', accessorKey: 'channel_number', - size: 40, + size: columnSizing.channel_number || 40, minSize: 30, maxSize: 100, cell: ({ getValue }) => { @@ -747,6 +750,7 @@ const ChannelsTable = ({}) => { { id: 'name', accessorKey: 'name', + size: columnSizing.name || 200, minSize: 100, cell: ({ getValue }) => ( { ); }, - size: 120, + size: columnSizing.epg || 120, minSize: 80, maxSize: 200, }, @@ -823,7 +827,7 @@ const ChannelsTable = ({}) => { {getValue()} ), - size: 175, + size: columnSizing.channel_group || 175, minSize: 100, maxSize: 300, }, @@ -870,7 +874,7 @@ const ChannelsTable = ({}) => { ), }, ], - [selectedProfileId, channelGroups, logos, theme] + [selectedProfileId, channelGroups, logos, theme, columnSizing] ); const renderHeaderCell = (header) => { @@ -972,6 +976,8 @@ const ChannelsTable = ({}) => { onRowSelectionChange: onRowSelectionChange, state: { columnSizing, + pagination, + sorting, }, onColumnSizingChange: setColumnSizing, getExpandedRowHeight: (row) => { diff --git a/frontend/src/components/tables/CustomTable/CustomTableBody.jsx b/frontend/src/components/tables/CustomTable/CustomTableBody.jsx index 8a271373..81f73455 100644 --- a/frontend/src/components/tables/CustomTable/CustomTableBody.jsx +++ b/frontend/src/components/tables/CustomTable/CustomTableBody.jsx @@ -106,11 +106,18 @@ const CustomTableBody = ({ className="td" key={`td-${cell.id}`} style={{ - flex: cell.column.columnDef.size ? '0 0 auto' : '1 1 0', + flex: cell.column.columnDef.size + ? `0 0 ${cell.column.getSize()}px` + : '1 1 0%', width: cell.column.columnDef.size - ? cell.column.getSize() - : undefined, - minWidth: 0, + ? `${cell.column.getSize()}px` + : 'auto', + maxWidth: cell.column.columnDef.size + ? `${cell.column.getSize()}px` + : 'none', + minWidth: cell.column.columnDef.minSize + ? `${cell.column.columnDef.minSize}px` + : '0px', ...(tableCellProps && tableCellProps({ cell })), }} > diff --git a/frontend/src/components/tables/CustomTable/CustomTableHeader.jsx b/frontend/src/components/tables/CustomTable/CustomTableHeader.jsx index 17ceecd7..06ae5aba 100644 --- a/frontend/src/components/tables/CustomTable/CustomTableHeader.jsx +++ b/frontend/src/components/tables/CustomTable/CustomTableHeader.jsx @@ -62,11 +62,18 @@ const CustomTableHeader = ({ className="th" key={header.id} style={{ - flex: header.column.columnDef.size ? '0 0 auto' : '1 1 0', + flex: header.column.columnDef.size + ? `0 0 ${header.getSize()}px` + : '1 1 0%', width: header.column.columnDef.size - ? header.getSize() - : undefined, - minWidth: 0, + ? `${header.getSize()}px` + : 'auto', + maxWidth: header.column.columnDef.size + ? `${header.getSize()}px` + : 'none', + minWidth: header.column.columnDef.minSize + ? `${header.column.columnDef.minSize}px` + : '0px', position: 'relative', // ...(tableCellProps && tableCellProps({ cell: header })), }} @@ -77,12 +84,13 @@ const CustomTableHeader = ({ ...(header.column.columnDef.style && header.column.columnDef.style), height: '100%', + paddingRight: header.column.getCanResize() ? '8px' : '0px', // Add padding for resize handle }} > {renderHeaderCell(header)} {header.column.getCanResize() && ( - { e.target.style.opacity = '1'; diff --git a/frontend/src/components/tables/CustomTable/index.jsx b/frontend/src/components/tables/CustomTable/index.jsx index 3a1ab69b..ecd2e04d 100644 --- a/frontend/src/components/tables/CustomTable/index.jsx +++ b/frontend/src/components/tables/CustomTable/index.jsx @@ -85,15 +85,16 @@ const useTable = ({ const table = useReactTable({ defaultColumn: { - size: undefined, minSize: 0, + maxSize: Number.MAX_SAFE_INTEGER, + size: 150, }, ...options, state: { - data: options.data, + ...options.state, selectedTableIds, - columnSizing: options.state?.columnSizing || {}, }, + onStateChange: options.onStateChange, getCoreRowModel: options.getCoreRowModel ?? getCoreRowModel(), enableColumnResizing: true, columnResizeMode: 'onChange', From 51352ba734f21f113891a436da953d448a51d806 Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Fri, 12 Sep 2025 10:24:23 -0500 Subject: [PATCH 03/11] Save stream table header sizing to local storage. --- .../src/components/tables/CustomTable/index.jsx | 4 ++++ frontend/src/components/tables/StreamsTable.jsx | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/tables/CustomTable/index.jsx b/frontend/src/components/tables/CustomTable/index.jsx index ecd2e04d..ec5182c9 100644 --- a/frontend/src/components/tables/CustomTable/index.jsx +++ b/frontend/src/components/tables/CustomTable/index.jsx @@ -18,6 +18,8 @@ const useTable = ({ onRowSelectionChange = null, getExpandedRowHeight = null, state = [], + columnSizing, + setColumnSizing, ...options }) => { const [selectedTableIds, setSelectedTableIds] = useState([]); @@ -93,8 +95,10 @@ const useTable = ({ state: { ...options.state, selectedTableIds, + ...(columnSizing && { columnSizing }), }, onStateChange: options.onStateChange, + ...(setColumnSizing && { onColumnSizingChange: setColumnSizing }), getCoreRowModel: options.getCoreRowModel ?? getCoreRowModel(), enableColumnResizing: true, columnResizeMode: 'onChange', diff --git a/frontend/src/components/tables/StreamsTable.jsx b/frontend/src/components/tables/StreamsTable.jsx index 95d44bee..c5159e7e 100644 --- a/frontend/src/components/tables/StreamsTable.jsx +++ b/frontend/src/components/tables/StreamsTable.jsx @@ -212,6 +212,10 @@ const StreamsTable = ({}) => { channel_group: '', m3u_account: '', }); + const [columnSizing, setColumnSizing] = useLocalStorage( + 'streams-table-column-sizing', + {} + ); const debouncedFilters = useDebounce(filters, 500, () => { // Reset to first page whenever filters change to avoid "Invalid page" errors setPagination((prev) => ({ @@ -256,15 +260,16 @@ const StreamsTable = ({}) => { () => [ { id: 'actions', - size: tableSize == 'compact' ? 60 : 80, + size: columnSizing.actions || (tableSize == 'compact' ? 60 : 80), }, { id: 'select', - size: 30, + size: columnSizing.select || 30, }, { header: 'Name', accessorKey: 'name', + size: columnSizing.name || 200, cell: ({ getValue }) => ( { channelGroups[row.channel_group] ? channelGroups[row.channel_group].name : '', + size: columnSizing.group || 150, cell: ({ getValue }) => ( { }, { id: 'm3u', - size: 150, + size: columnSizing.m3u || 150, accessorFn: (row) => playlists.find((playlist) => playlist.id === row.m3u_account)?.name, cell: ({ getValue }) => ( @@ -315,7 +321,7 @@ const StreamsTable = ({}) => { ), }, ], - [channelGroups, playlists] + [channelGroups, playlists, columnSizing, tableSize] ); /** @@ -652,6 +658,8 @@ const StreamsTable = ({}) => { filters, pagination, sorting, + columnSizing, + setColumnSizing, onRowSelectionChange: onRowSelectionChange, manualPagination: true, manualSorting: true, From a9ca6502ed3cd308b70d4caef40616dae2fad0d7 Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Fri, 12 Sep 2025 10:31:35 -0500 Subject: [PATCH 04/11] Better calculation for horizontal scroll bar in channel and stream tables. --- frontend/src/components/tables/ChannelsTable.jsx | 2 +- frontend/src/components/tables/StreamsTable.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/tables/ChannelsTable.jsx b/frontend/src/components/tables/ChannelsTable.jsx index bd200c67..110c332f 100644 --- a/frontend/src/components/tables/ChannelsTable.jsx +++ b/frontend/src/components/tables/ChannelsTable.jsx @@ -1328,7 +1328,7 @@ const ChannelsTable = ({}) => { style={{ flex: 1, overflowY: 'auto', - overflowX: 'hidden', + overflowX: 'auto', border: 'solid 1px rgb(68,68,68)', borderRadius: 'var(--mantine-radius-default)', }} diff --git a/frontend/src/components/tables/StreamsTable.jsx b/frontend/src/components/tables/StreamsTable.jsx index c5159e7e..a0a95811 100644 --- a/frontend/src/components/tables/StreamsTable.jsx +++ b/frontend/src/components/tables/StreamsTable.jsx @@ -863,7 +863,7 @@ const StreamsTable = ({}) => { style={{ flex: 1, overflowY: 'auto', - overflowX: 'hidden', + overflowX: 'auto', border: 'solid 1px rgb(68,68,68)', borderRadius: 'var(--mantine-radius-default)', }} From 448ef16987d2d674635dd7f864b7acd82114f240 Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Fri, 12 Sep 2025 10:56:17 -0500 Subject: [PATCH 05/11] Expand header width to fill container. --- .../tables/CustomTable/CustomTable.jsx | 19 ++++++++++++++- .../tables/CustomTable/CustomTableBody.jsx | 11 +++++++++ .../tables/CustomTable/CustomTableHeader.jsx | 23 +++++++++++++++++-- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/tables/CustomTable/CustomTable.jsx b/frontend/src/components/tables/CustomTable/CustomTable.jsx index 7d811b6f..ee665188 100644 --- a/frontend/src/components/tables/CustomTable/CustomTable.jsx +++ b/frontend/src/components/tables/CustomTable/CustomTable.jsx @@ -1,6 +1,6 @@ import { Box, Flex } from '@mantine/core'; import CustomTableHeader from './CustomTableHeader'; -import { useCallback, useState, useRef } from 'react'; +import { useCallback, useState, useRef, useMemo } from 'react'; import { flexRender } from '@tanstack/react-table'; import table from '../../../helpers/table'; import CustomTableBody from './CustomTableBody'; @@ -9,11 +9,28 @@ import useLocalStorage from '../../../hooks/useLocalStorage'; const CustomTable = ({ table }) => { const [tableSize, _] = useLocalStorage('table-size', 'default'); + // Get column sizing state for dependency tracking + const columnSizing = table.getState().columnSizing; + + // Calculate minimum table width reactively based on column sizes + const minTableWidth = useMemo(() => { + const headerGroups = table.getHeaderGroups(); + if (!headerGroups || headerGroups.length === 0) return 0; + + const width = + headerGroups[0]?.headers.reduce((total, header) => { + return total + header.getSize(); + }, 0) || 0; + + return width; + }, [table, columnSizing]); + return ( { + if (rows.length === 0) return 0; + + return rows[0].getVisibleCells().reduce((total, cell) => { + return total + cell.column.getSize(); + }, 0); + }, [rows]); + const renderTableBodyContents = () => { const virtualized = false; @@ -94,6 +104,7 @@ const CustomTableBody = ({ style={{ display: 'flex', width: '100%', + minWidth: `${totalWidth}px`, ...(row.getIsSelected() && { backgroundColor: '#163632', }), diff --git a/frontend/src/components/tables/CustomTable/CustomTableHeader.jsx b/frontend/src/components/tables/CustomTable/CustomTableHeader.jsx index 06ae5aba..4aafccaa 100644 --- a/frontend/src/components/tables/CustomTable/CustomTableHeader.jsx +++ b/frontend/src/components/tables/CustomTable/CustomTableHeader.jsx @@ -1,6 +1,6 @@ import { Box, Center, Checkbox, Flex } from '@mantine/core'; import { flexRender } from '@tanstack/react-table'; -import { useCallback } from 'react'; +import { useCallback, useMemo } from 'react'; const CustomTableHeader = ({ getHeaderGroups, @@ -40,6 +40,21 @@ const CustomTableHeader = ({ } }; + // Get header groups for dependency tracking + const headerGroups = getHeaderGroups(); + + // Calculate total width of all columns reactively + const totalWidth = useMemo(() => { + if (!headerGroups || headerGroups.length === 0) return 0; + + const width = + headerGroups[0]?.headers.reduce((total, header) => { + return total + header.getSize(); + }, 0) || 0; + + return width; + }, [headerGroups]); + return ( {headerGroup.headers.map((header) => { return ( From fa41b8eb2301c234f71b9c892993d53c136572bb Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Fri, 12 Sep 2025 11:12:27 -0500 Subject: [PATCH 06/11] Save divider location in local storage. --- frontend/src/pages/Channels.jsx | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/Channels.jsx b/frontend/src/pages/Channels.jsx index c265e3ef..7663276d 100644 --- a/frontend/src/pages/Channels.jsx +++ b/frontend/src/pages/Channels.jsx @@ -5,9 +5,22 @@ import { Box } from '@mantine/core'; import { Allotment } from 'allotment'; import { USER_LEVELS } from '../constants'; import useAuthStore from '../store/auth'; +import useLocalStorage from '../hooks/useLocalStorage'; const ChannelsPage = () => { const authUser = useAuthStore((s) => s.user); + const [allotmentSizes, setAllotmentSizes] = useLocalStorage( + 'channels-splitter-sizes', + [50, 50] + ); + + const handleSplitChange = (sizes) => { + setAllotmentSizes(sizes); + }; + + const handleResize = (sizes) => { + setAllotmentSizes(sizes); + }; if (!authUser.id) { return <>; @@ -30,10 +43,12 @@ const ChannelsPage = () => { }} >
From 900ce7320014e7b218931d073e2d9d3c5f4e6926 Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Fri, 12 Sep 2025 16:38:18 -0500 Subject: [PATCH 07/11] Better sizing for epg and m3u tables. Rearranged m3u table slightly. --- .../tables/CustomTable/CustomTableBody.jsx | 37 +++++++++++-------- .../tables/CustomTable/CustomTableHeader.jsx | 34 +++++++++-------- frontend/src/components/tables/EPGsTable.jsx | 4 +- frontend/src/components/tables/M3UsTable.jsx | 16 ++++---- frontend/src/components/tables/table.css | 2 +- 5 files changed, 52 insertions(+), 41 deletions(-) diff --git a/frontend/src/components/tables/CustomTable/CustomTableBody.jsx b/frontend/src/components/tables/CustomTable/CustomTableBody.jsx index 50ff0581..9e43c57a 100644 --- a/frontend/src/components/tables/CustomTable/CustomTableBody.jsx +++ b/frontend/src/components/tables/CustomTable/CustomTableBody.jsx @@ -24,12 +24,16 @@ const CustomTableBody = ({ const rows = getRowModel().rows; - // Calculate total width of all columns reactively - const totalWidth = useMemo(() => { + // Calculate minimum width based only on fixed-size columns + const minTableWidth = useMemo(() => { if (rows.length === 0) return 0; return rows[0].getVisibleCells().reduce((total, cell) => { - return total + cell.column.getSize(); + // Only count columns with fixed sizes, flexible columns will expand + const columnSize = cell.column.columnDef.size + ? cell.column.getSize() + : cell.column.columnDef.minSize || 150; // Default min for flexible columns + return total + columnSize; }, 0); }, [rows]); @@ -104,7 +108,7 @@ const CustomTableBody = ({ style={{ display: 'flex', width: '100%', - minWidth: `${totalWidth}px`, + minWidth: '100%', // Force full width ...(row.getIsSelected() && { backgroundColor: '#163632', }), @@ -112,23 +116,24 @@ const CustomTableBody = ({ }} > {row.getVisibleCells().map((cell) => { + const hasFixedSize = cell.column.columnDef.size; + const isFlexible = !hasFixedSize; + return ( diff --git a/frontend/src/components/tables/CustomTable/CustomTableHeader.jsx b/frontend/src/components/tables/CustomTable/CustomTableHeader.jsx index 4aafccaa..92643fc9 100644 --- a/frontend/src/components/tables/CustomTable/CustomTableHeader.jsx +++ b/frontend/src/components/tables/CustomTable/CustomTableHeader.jsx @@ -43,13 +43,17 @@ const CustomTableHeader = ({ // Get header groups for dependency tracking const headerGroups = getHeaderGroups(); - // Calculate total width of all columns reactively - const totalWidth = useMemo(() => { + // Calculate minimum width based only on fixed-size columns + const minTableWidth = useMemo(() => { if (!headerGroups || headerGroups.length === 0) return 0; const width = headerGroups[0]?.headers.reduce((total, header) => { - return total + header.getSize(); + // Only count columns with fixed sizes, flexible columns will expand + const columnSize = header.column.columnDef.size + ? header.getSize() + : header.column.columnDef.minSize || 150; // Default min for flexible columns + return total + columnSize; }, 0) || 0; return width; @@ -72,7 +76,7 @@ const CustomTableHeader = ({ style={{ display: 'flex', width: '100%', - minWidth: `${totalWidth}px`, + minWidth: '100%', // Force full width }} > {headerGroup.headers.map((header) => { @@ -81,18 +85,16 @@ const CustomTableHeader = ({ className="th" key={header.id} style={{ - flex: header.column.columnDef.size - ? `0 0 ${header.getSize()}px` - : '1 1 0%', - width: header.column.columnDef.size - ? `${header.getSize()}px` - : 'auto', - maxWidth: header.column.columnDef.size - ? `${header.getSize()}px` - : 'none', - minWidth: header.column.columnDef.minSize - ? `${header.column.columnDef.minSize}px` - : '0px', + ...(header.column.columnDef.grow + ? { + flex: '1 1 0%', + minWidth: 0, + } + : { + flex: `0 0 ${header.getSize ? header.getSize() : 150}px`, + width: `${header.getSize ? header.getSize() : 150}px`, + maxWidth: `${header.getSize ? header.getSize() : 150}px`, + }), position: 'relative', // ...(tableCellProps && tableCellProps({ cell: header })), }} diff --git a/frontend/src/components/tables/EPGsTable.jsx b/frontend/src/components/tables/EPGsTable.jsx index 9c40a14a..4ea66b30 100644 --- a/frontend/src/components/tables/EPGsTable.jsx +++ b/frontend/src/components/tables/EPGsTable.jsx @@ -195,6 +195,7 @@ const EPGsTable = () => { header: 'URL / API Key / File Path', accessorKey: 'url', enableSorting: false, + minSize: 250, cell: ({ cell, row }) => { const value = cell.getValue() || @@ -220,7 +221,7 @@ const EPGsTable = () => { { header: 'Status', accessorKey: 'status', - size: 150, + size: 100, cell: ({ row }) => { const data = row.original; @@ -236,6 +237,7 @@ const EPGsTable = () => { header: 'Status Message', accessorKey: 'last_message', enableSorting: false, + grow: true, cell: ({ row }) => { const data = row.original; diff --git a/frontend/src/components/tables/M3UsTable.jsx b/frontend/src/components/tables/M3UsTable.jsx index d72fbeb4..d31da0e6 100644 --- a/frontend/src/components/tables/M3UsTable.jsx +++ b/frontend/src/components/tables/M3UsTable.jsx @@ -443,6 +443,7 @@ const M3UTable = () => { { header: 'URL / File', accessorKey: 'server_url', + size: 250, cell: ({ cell, row }) => { const value = cell.getValue() || row.original.file_path || ''; return ( @@ -461,16 +462,10 @@ const M3UTable = () => { ); }, }, - { - header: 'Max Streams', - accessorKey: 'max_streams', - sortable: true, - size: 150, - }, { header: 'Status', accessorKey: 'status', - size: 150, + size: 100, cell: ({ cell }) => { const value = cell.getValue(); if (!value) return null; @@ -486,6 +481,7 @@ const M3UTable = () => { { header: 'Status Message', accessorKey: 'last_message', + grow: true, cell: ({ cell, row }) => { const value = cell.getValue(); const data = row.original; @@ -569,6 +565,12 @@ const M3UTable = () => { ); }, }, + { + header: 'Max Streams', + accessorKey: 'max_streams', + sortable: true, + size: 125, + }, { header: 'Updated', accessorKey: 'updated_at', diff --git a/frontend/src/components/tables/table.css b/frontend/src/components/tables/table.css index 15304103..30fd033a 100644 --- a/frontend/src/components/tables/table.css +++ b/frontend/src/components/tables/table.css @@ -8,8 +8,8 @@ html { } .divTable { + width: 100%; /* border: 1px solid lightgray; */ - /* width: fit-content; */ /* display: flex; flex-direction: column; */ } From 65e947c95b9c235450c493cf6bc7287b87df5d41 Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Fri, 12 Sep 2025 16:40:30 -0500 Subject: [PATCH 08/11] Rename type columns. --- frontend/src/components/tables/EPGsTable.jsx | 4 ++-- frontend/src/components/tables/M3UsTable.jsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/tables/EPGsTable.jsx b/frontend/src/components/tables/EPGsTable.jsx index 4ea66b30..f16d404e 100644 --- a/frontend/src/components/tables/EPGsTable.jsx +++ b/frontend/src/components/tables/EPGsTable.jsx @@ -187,9 +187,9 @@ const EPGsTable = () => { size: 200, }, { - header: 'Source Type', + header: 'Type', accessorKey: 'source_type', - size: 150, + size: 100, }, { header: 'URL / API Key / File Path', diff --git a/frontend/src/components/tables/M3UsTable.jsx b/frontend/src/components/tables/M3UsTable.jsx index d31da0e6..fcbe1076 100644 --- a/frontend/src/components/tables/M3UsTable.jsx +++ b/frontend/src/components/tables/M3UsTable.jsx @@ -431,10 +431,10 @@ const M3UTable = () => { sortable: true, }, { - header: 'Account Type', + header: 'Type', accessorKey: 'account_type', sortable: true, - size: 150, + size: 100, cell: ({ cell }) => { const value = cell.getValue(); return value === 'XC' ? 'XC' : 'M3U'; From 5e2794a62ed7eb04cec5d10d99a1290d85935379 Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Fri, 12 Sep 2025 17:00:59 -0500 Subject: [PATCH 09/11] Fix sizing on logo table and user table. --- frontend/src/components/tables/EPGsTable.jsx | 1 + frontend/src/components/tables/LogosTable.jsx | 3 ++- frontend/src/components/tables/M3UsTable.jsx | 1 + frontend/src/components/tables/UsersTable.jsx | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/tables/EPGsTable.jsx b/frontend/src/components/tables/EPGsTable.jsx index f16d404e..7cac7d7d 100644 --- a/frontend/src/components/tables/EPGsTable.jsx +++ b/frontend/src/components/tables/EPGsTable.jsx @@ -237,6 +237,7 @@ const EPGsTable = () => { header: 'Status Message', accessorKey: 'last_message', enableSorting: false, + minSize: 250, grow: true, cell: ({ row }) => { const data = row.original; diff --git a/frontend/src/components/tables/LogosTable.jsx b/frontend/src/components/tables/LogosTable.jsx index 46c29e4c..0c4f32b4 100644 --- a/frontend/src/components/tables/LogosTable.jsx +++ b/frontend/src/components/tables/LogosTable.jsx @@ -394,7 +394,7 @@ const LogosTable = () => { { header: 'Name', accessorKey: 'name', - size: 200, + size: 250, cell: ({ getValue }) => ( {getValue()} @@ -479,6 +479,7 @@ const LogosTable = () => { { header: 'URL', accessorKey: 'url', + grow: true, cell: ({ getValue }) => ( { header: 'Status Message', accessorKey: 'last_message', grow: true, + minSize: 250, cell: ({ cell, row }) => { const value = cell.getValue(); const data = row.original; diff --git a/frontend/src/components/tables/UsersTable.jsx b/frontend/src/components/tables/UsersTable.jsx index 76d4d729..3e9e4971 100644 --- a/frontend/src/components/tables/UsersTable.jsx +++ b/frontend/src/components/tables/UsersTable.jsx @@ -184,6 +184,7 @@ const UsersTable = () => { { header: 'Email', accessorKey: 'email', + grow: true, cell: ({ getValue }) => ( Date: Fri, 12 Sep 2025 17:04:52 -0500 Subject: [PATCH 10/11] Better sizing of stream profiles table --- frontend/src/components/tables/StreamProfilesTable.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/tables/StreamProfilesTable.jsx b/frontend/src/components/tables/StreamProfilesTable.jsx index 76be0462..da2acd30 100644 --- a/frontend/src/components/tables/StreamProfilesTable.jsx +++ b/frontend/src/components/tables/StreamProfilesTable.jsx @@ -72,7 +72,7 @@ const StreamProfiles = () => { { header: 'Name', accessorKey: 'name', - size: 150, + size: 175, cell: ({ cell }) => (
{ { header: 'Command', accessorKey: 'command', - size: 150, + size: 100, cell: ({ cell }) => (
{ { header: 'Parameters', accessorKey: 'parameters', - // size: 200, + grow: true, cell: ({ cell }) => (
Date: Fri, 12 Sep 2025 17:10:49 -0500 Subject: [PATCH 11/11] Better sizing on user-agents table. --- frontend/src/components/tables/UserAgentsTable.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/src/components/tables/UserAgentsTable.jsx b/frontend/src/components/tables/UserAgentsTable.jsx index 265ed125..48573926 100644 --- a/frontend/src/components/tables/UserAgentsTable.jsx +++ b/frontend/src/components/tables/UserAgentsTable.jsx @@ -61,11 +61,13 @@ const UserAgentsTable = () => { { header: 'Name', accessorKey: 'name', + size: 125, }, { header: 'User-Agent', accessorKey: 'user_agent', enableSorting: false, + grow: true, cell: ({ cell }) => (