Update bface UI and security work
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { Button, Checkbox, ScrollView, Separator, Text, XStack, YStack } from 'tamagui';
|
||||
import { getIcon } from '../IconMapper.jsx';
|
||||
import { PageNavBar } from '../PageNavBar.jsx';
|
||||
import { useGridView } from './context.js';
|
||||
import { getTypographyRoleProps } from '../../styles/index.js';
|
||||
import {
|
||||
@@ -98,6 +99,16 @@ export function TableHeader({ visible = true, showTopBorder = true }) {
|
||||
const selectedCount = allIds.filter((id) => grid.selectedIds.has(id)).length;
|
||||
const allSelected = allIds.length > 0 && selectedCount === allIds.length;
|
||||
const someSelected = selectedCount > 0 && !allSelected;
|
||||
const getNextSortDirection = (column) => {
|
||||
const activeSort = grid.sortBy.find((entry) => entry.field === column.field);
|
||||
if (!activeSort) {
|
||||
return 'ascending';
|
||||
}
|
||||
if (activeSort.direction === 'asc') {
|
||||
return 'descending';
|
||||
}
|
||||
return 'none';
|
||||
};
|
||||
|
||||
return (
|
||||
<XStack
|
||||
@@ -105,8 +116,11 @@ export function TableHeader({ visible = true, showTopBorder = true }) {
|
||||
borderTopWidth={showTopBorder ? 1 : 0}
|
||||
borderBottomWidth={1}
|
||||
borderColor="$lineSubtle"
|
||||
backgroundColor="transparent"
|
||||
backgroundColor="$bgPanel"
|
||||
paddingHorizontal="$2"
|
||||
paddingTop="$1"
|
||||
paddingBottom="$1"
|
||||
gap="$1"
|
||||
>
|
||||
{grid.selectable || grid.nested ? (
|
||||
<XStack width={36} alignItems="center" justifyContent="center">
|
||||
@@ -132,41 +146,46 @@ export function TableHeader({ visible = true, showTopBorder = true }) {
|
||||
const activeSort = grid.sortBy.find((entry) => entry.field === column.field);
|
||||
const isActive = Boolean(activeSort);
|
||||
const direction = activeSort?.direction;
|
||||
const sortButtonLabel = `Sort ${column.label} ${getNextSortDirection(column)}`;
|
||||
const ChevronIcon = isActive
|
||||
? (direction === 'asc' ? CaretUp : CaretDown)
|
||||
: CaretDown;
|
||||
const iconColor = isActive ? '$textSecondary' : '$textMuted';
|
||||
|
||||
return (
|
||||
<Button
|
||||
<XStack
|
||||
key={column.field}
|
||||
chromeless
|
||||
disabled={!column.sortable}
|
||||
onPress={() => column.sortable && grid.toggleSort(column.field)}
|
||||
justifyContent={getColumnJustify(column.align)}
|
||||
alignItems="center"
|
||||
paddingVertical="$3"
|
||||
minHeight={44}
|
||||
paddingHorizontal="$2"
|
||||
paddingVertical="$2"
|
||||
gap="$2"
|
||||
{...getColumnLayoutStyle(column)}
|
||||
hoverStyle={column.sortable ? { backgroundColor: '$bgPage' } : undefined}
|
||||
pressStyle={column.sortable ? { backgroundColor: '$bgPanelElev' } : undefined}
|
||||
>
|
||||
<XStack width="100%" alignItems="center" justifyContent={getColumnJustify(column.align)} gap="$2">
|
||||
<Text
|
||||
width="auto"
|
||||
textAlign={column.align || 'left'}
|
||||
numberOfLines={1}
|
||||
{...getTypographyRoleProps('tableHeader')}
|
||||
>
|
||||
{column.label}
|
||||
</Text>
|
||||
{column.sortable ? (
|
||||
isActive ? (
|
||||
direction === 'asc'
|
||||
? (CaretUp ? <CaretUp size="xs" color="$textSecondary" /> : null)
|
||||
: (CaretDown ? <CaretDown size="xs" color="$textSecondary" /> : null)
|
||||
) : (
|
||||
CaretDown ? <CaretDown size="xs" color="$textMuted" style={{ opacity: 0.6 }} /> : null
|
||||
)
|
||||
) : null}
|
||||
</XStack>
|
||||
</Button>
|
||||
<Text
|
||||
flex={1}
|
||||
minWidth={0}
|
||||
textAlign={column.align || 'left'}
|
||||
numberOfLines={1}
|
||||
{...getTypographyRoleProps('tableHeader')}
|
||||
>
|
||||
{column.label}
|
||||
</Text>
|
||||
{column.sortable ? (
|
||||
<Button
|
||||
chromeless
|
||||
circular
|
||||
size="$2"
|
||||
flexShrink={0}
|
||||
aria-label={sortButtonLabel}
|
||||
onPress={() => grid.toggleSort(column.field)}
|
||||
hoverStyle={{ backgroundColor: '$bgPage' }}
|
||||
pressStyle={{ backgroundColor: '$bgPanelElev' }}
|
||||
icon={ChevronIcon ? <ChevronIcon size="xs" color={iconColor} /> : undefined}
|
||||
/>
|
||||
) : null}
|
||||
</XStack>
|
||||
);
|
||||
})}
|
||||
</XStack>
|
||||
@@ -247,10 +266,6 @@ export function TableBodyView({ visible = true }) {
|
||||
|
||||
export function TableFooter({ visible = true }) {
|
||||
const grid = useGridView();
|
||||
const FirstPageIcon = getIcon('first-page');
|
||||
const PreviousPageIcon = getIcon('chevron-left');
|
||||
const NextPageIcon = getIcon('chevron-right');
|
||||
const LastPageIcon = getIcon('last-page');
|
||||
|
||||
if (visible === false) {
|
||||
return null;
|
||||
@@ -261,8 +276,11 @@ export function TableFooter({ visible = true }) {
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
gap="$3"
|
||||
padding="$3"
|
||||
minHeight={56}
|
||||
paddingTop="$1"
|
||||
paddingRight="$3"
|
||||
paddingBottom="$1"
|
||||
paddingLeft="$3"
|
||||
minHeight={64}
|
||||
borderTopWidth={1}
|
||||
borderTopColor="$lineSubtle"
|
||||
backgroundColor="$bgPanel"
|
||||
@@ -272,43 +290,18 @@ export function TableFooter({ visible = true }) {
|
||||
{grid.total} records
|
||||
</Text>
|
||||
|
||||
<XStack gap="$1" alignItems="center" flexWrap="wrap" padding="$1" borderWidth={1} borderColor="$lineSubtle" borderRadius="$radiusMd" backgroundColor="$bgPanel">
|
||||
<Button
|
||||
size="$3"
|
||||
chromeless
|
||||
circular
|
||||
disabled={grid.currentPage <= 1}
|
||||
icon={FirstPageIcon ? <FirstPageIcon size="sm" color="$textSecondary" /> : undefined}
|
||||
onPress={() => grid.setPage(1)}
|
||||
/>
|
||||
<Button
|
||||
size="$3"
|
||||
chromeless
|
||||
circular
|
||||
disabled={grid.currentPage <= 1}
|
||||
icon={PreviousPageIcon ? <PreviousPageIcon size="sm" color="$textSecondary" /> : undefined}
|
||||
onPress={() => grid.setPage(grid.currentPage - 1)}
|
||||
/>
|
||||
<Text color="$textSecondary">
|
||||
Page {grid.currentPage} of {grid.pageCount}
|
||||
</Text>
|
||||
<Button
|
||||
size="$3"
|
||||
chromeless
|
||||
circular
|
||||
disabled={grid.currentPage >= grid.pageCount}
|
||||
icon={NextPageIcon ? <NextPageIcon size="sm" color="$textSecondary" /> : undefined}
|
||||
onPress={() => grid.setPage(grid.currentPage + 1)}
|
||||
/>
|
||||
<Button
|
||||
size="$3"
|
||||
chromeless
|
||||
circular
|
||||
disabled={grid.currentPage >= grid.pageCount}
|
||||
icon={LastPageIcon ? <LastPageIcon size="sm" color="$textSecondary" /> : undefined}
|
||||
onPress={() => grid.setPage(grid.pageCount)}
|
||||
/>
|
||||
</XStack>
|
||||
<PageNavBar
|
||||
outlined={false}
|
||||
label={`Page ${grid.currentPage} of ${grid.pageCount}`}
|
||||
onFirstPage={() => grid.setPage(1)}
|
||||
onPreviousPage={() => grid.setPage(grid.currentPage - 1)}
|
||||
onNextPage={() => grid.setPage(grid.currentPage + 1)}
|
||||
onLastPage={() => grid.setPage(grid.pageCount)}
|
||||
firstDisabled={grid.currentPage <= 1}
|
||||
previousDisabled={grid.currentPage <= 1}
|
||||
nextDisabled={grid.currentPage >= grid.pageCount}
|
||||
lastDisabled={grid.currentPage >= grid.pageCount}
|
||||
/>
|
||||
</XStack>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user