diff --git a/web/default/src/components/data-table/index.ts b/web/default/src/components/data-table/index.ts index 0a7db461..41b3c567 100644 --- a/web/default/src/components/data-table/index.ts +++ b/web/default/src/components/data-table/index.ts @@ -61,7 +61,7 @@ export { export { useDebouncedColumnFilter } from './hooks/use-debounced-column-filter' export const DISABLED_ROW_DESKTOP = - '[--data-table-card-bg:var(--table-disabled)] hover:[--data-table-card-bg:var(--table-disabled-hover)] [background-color:var(--table-disabled)] hover:[background-color:var(--table-disabled-hover)] [&>td:first-child]:[border-left-color:var(--table-disabled-border)] [&>td:first-child]:border-l-4 [&>td:first-child]:pl-1' + '[--data-table-card-bg:var(--table-disabled)] hover:[--data-table-card-bg:var(--table-disabled-hover)] data-[state=selected]:![--data-table-card-bg:var(--table-disabled)] data-[state=selected]:hover:![--data-table-card-bg:var(--table-disabled-hover)] [background-color:var(--table-disabled)] hover:[background-color:var(--table-disabled-hover)] [&>td:first-child]:[border-left-color:var(--table-disabled-border)] [&>td:first-child]:border-l-4 [&>td:first-child]:pl-1' export const DISABLED_ROW_MOBILE = - '[--data-table-card-bg:var(--table-disabled)] [background-color:var(--table-disabled)]' + '[--data-table-card-bg:var(--table-disabled)] data-[state=selected]:![--data-table-card-bg:var(--table-disabled)] [background-color:var(--table-disabled)]' diff --git a/web/default/src/components/data-table/layout/card-grid.tsx b/web/default/src/components/data-table/layout/card-grid.tsx index 98b49f5e..c41292f7 100644 --- a/web/default/src/components/data-table/layout/card-grid.tsx +++ b/web/default/src/components/data-table/layout/card-grid.tsx @@ -41,6 +41,10 @@ export type DataTableCardHelpers = { * Provided so custom renderers can match the default layout decision. */ compact: boolean + /** + * Row selection state captured before entering memoized custom card renderers. + */ + isSelected: boolean } export interface DataTableCardGridProps { @@ -80,7 +84,7 @@ function CardGridSkeleton(props: { {[1, 2, 3, 4, 5, 6].map((i) => (
@@ -108,8 +112,8 @@ function CardGridSkeleton(props: { * the card view reusable across any table with zero per-feature work while * still allowing a bespoke card design when desired. * - * Selection (the `select` column) is intentionally not rendered in card mode; - * bulk selection remains a table-mode capability. + * The default generic card omits the `select` column. Custom `renderCard` + * implementations can use `helpers.isSelected` to keep selection UI in sync. */ export function DataTableCardGrid(props: DataTableCardGridProps) { const { t } = useTranslation() @@ -156,17 +160,19 @@ export function DataTableCardGrid(props: DataTableCardGridProps) {
{rows.map((row) => { const key = props.getRowKey ? props.getRowKey(row) : row.id + const isSelected = row.getIsSelected() return (
{props.renderCard ? ( - props.renderCard(row, { compact }) + props.renderCard(row, { compact, isSelected }) ) : ( )} diff --git a/web/default/src/features/channels/components/channel-card.tsx b/web/default/src/features/channels/components/channel-card.tsx index 166a6df3..89fc3a3e 100644 --- a/web/default/src/features/channels/components/channel-card.tsx +++ b/web/default/src/features/channels/components/channel-card.tsx @@ -37,7 +37,13 @@ const SENSITIVE_MASK = '••••' * priority/weight spinners, balance refresh, response/test times, tag * expand-collapse, and the per-row (or per-tag) actions menu. */ -function ChannelCardComponent({ row }: { row: Row }) { +function ChannelCardComponent({ + row, + isSelected, +}: { + row: Row + isSelected: boolean +}) { const { t } = useTranslation() const { sensitiveVisible } = useChannels() const isTagRow = isTagAggregateRow(row.original) @@ -81,16 +87,19 @@ function ChannelCardComponent({ row }: { row: Row }) { row.original.status !== CHANNEL_STATUS.MANUAL_DISABLED) return ( -
+
{/* Row 1: selection + type, with status badge + actions menu */}
{!isTagRow && selectCell && ( - {selectCell} + {selectCell} )}
{typeCell}
-
+
{showStatusBadge && statusCell} {actionsCell} @@ -122,7 +131,7 @@ function ChannelCardComponent({ row }: { row: Row }) { {/* Right column (sits on the right, content left-aligned). A single grid with content-sized columns keeps Priority/Weight and Response/Last Tested aligned without wasting horizontal space. */} -
+
{t('Priority')} {t('Weight')}
{priorityCell}
diff --git a/web/default/src/features/channels/components/channels-table.tsx b/web/default/src/features/channels/components/channels-table.tsx index 7e002b76..b649b237 100644 --- a/web/default/src/features/channels/components/channels-table.tsx +++ b/web/default/src/features/channels/components/channels-table.tsx @@ -370,7 +370,9 @@ export function ChannelsTable() { skeletonKeyPrefix='channel-skeleton' enableCardView viewModeStorageKey={CHANNELS_VIEW_MODE_STORAGE_KEY} - renderCard={(row) => } + renderCard={(row, { isSelected }) => ( + + )} cardGridClassName='grid grid-cols-1 gap-3 sm:gap-4 lg:grid-cols-3' applyHeaderSize toolbarProps={{