feat: custom show/hide datatable col

This commit is contained in:
pa
2026-03-04 23:12:41 +09:00
parent 1decec4c69
commit 1be9d13cd4
11 changed files with 400 additions and 104 deletions
+5 -1
View File
@@ -225,6 +225,7 @@ export const columns = [
{
accessorKey: 'created_at',
size: 140,
meta: { label: () => t('table.feed.date') },
header: ({ column }) => (
<Button
variant="ghost"
@@ -257,6 +258,7 @@ export const columns = [
accessorKey: 'type',
size: 130,
header: () => t('table.feed.type'),
meta: { label: () => t('table.feed.type') },
cell: ({ row }) => {
const type = row.getValue('type');
return (
@@ -272,6 +274,7 @@ export const columns = [
accessorKey: 'displayName',
size: 190,
header: () => t('table.feed.user'),
meta: { label: () => t('table.feed.user') },
cell: ({ row }) => {
const { showUserDialog } = useUserStore();
const original = row.original;
@@ -291,7 +294,8 @@ export const columns = [
enableSorting: false,
minSize: 100,
meta: {
stretch: true
stretch: true,
label: () => t('table.feed.detail')
},
cell: ({ row }) => {
const original = row.original;
+62 -35
View File
@@ -17,24 +17,27 @@ import {
const { t } = i18n.global;
const sortButton = ({ column, label, descFirst = false }) => (
<Button
variant="ghost"
size="sm"
class="-ml-2 h-8 px-2"
onClick={() => {
const sorted = column.getIsSorted();
if (!sorted && descFirst) {
column.toggleSorting(true);
return;
}
column.toggleSorting(sorted === 'asc');
}}
>
{label}
<ArrowUpDown class="ml-1 h-4 w-4" />
</Button>
);
const sortButton = ({ column, label, descFirst = false }) => {
const resolvedLabel = typeof label === 'function' ? label() : label;
return (
<Button
variant="ghost"
size="sm"
class="-ml-2 h-8 px-2"
onClick={() => {
const sorted = column.getIsSorted();
if (!sorted && descFirst) {
column.toggleSorting(true);
return;
}
column.toggleSorting(sorted === 'asc');
}}
>
{resolvedLabel}
<ArrowUpDown class="ml-1 h-4 w-4" />
</Button>
);
};
const compareNumbers = (a, b) => (a ?? 0) - (b ?? 0);
@@ -143,10 +146,11 @@ export const createColumns = ({
header: ({ column }) =>
sortButton({
column,
label: t('table.friendList.no'),
label: () => t('table.friendList.no'),
descFirst: true
}),
size: 100,
meta: { label: () => t('table.friendList.no') },
sortingFn: sortByNumber((row) => row?.$friendNumber ?? 0),
cell: ({ row }) => <span>{row.original?.$friendNumber || ''}</span>
},
@@ -156,6 +160,7 @@ export const createColumns = ({
header: () => t('table.friendList.avatar'),
size: 90,
enableSorting: false,
meta: { label: () => t('table.friendList.avatar') },
cell: ({ row }) => {
const src = userImage(row.original, true);
return src ? (
@@ -175,9 +180,10 @@ export const createColumns = ({
header: ({ column }) =>
sortButton({
column,
label: t('table.friendList.displayName')
label: () => t('table.friendList.displayName')
}),
size: 200,
meta: { label: () => t('table.friendList.displayName') },
sortingFn: sortByString((row) => row?.displayName ?? ''),
cell: ({ row }) => {
const style = randomUserColours?.value
@@ -196,9 +202,10 @@ export const createColumns = ({
header: ({ column }) =>
sortButton({
column,
label: t('table.friendList.rank')
label: () => t('table.friendList.rank')
}),
size: 140,
meta: { label: () => t('table.friendList.rank') },
sortingFn: sortByNumber((row) => row?.$trustSortNum ?? 0),
cell: ({ row }) => {
if (randomUserColours?.value) {
@@ -222,11 +229,15 @@ export const createColumns = ({
id: 'status',
accessorFn: (row) => row?.status,
header: ({ column }) =>
sortButton({ column, label: t('table.friendList.status') }),
sortButton({
column,
label: () => t('table.friendList.status')
}),
minSize: 200,
sortingFn: sortByStatus,
meta: {
stretch: true
stretch: true,
label: () => t('table.friendList.status')
},
cell: ({ row }) => {
const status = row.original?.status;
@@ -250,8 +261,12 @@ export const createColumns = ({
id: 'language',
accessorFn: (row) => row?.$languages,
header: ({ column }) =>
sortButton({ column, label: t('table.friendList.language') }),
sortButton({
column,
label: () => t('table.friendList.language')
}),
size: 130,
meta: { label: () => t('table.friendList.language') },
sortingFn: sortByLanguages,
cell: ({ row }) => (
<div class="flex items-center">
@@ -279,6 +294,7 @@ export const createColumns = ({
header: () => t('table.friendList.bioLink'),
size: 130,
enableSorting: false,
meta: { label: () => t('table.friendList.bioLink') },
cell: ({ row }) => (
<div class="flex items-center">
{(row.original?.bioLinks ?? [])
@@ -305,12 +321,13 @@ export const createColumns = ({
header: ({ column }) =>
sortButton({
column,
label: t('table.friendList.joinCount')
label: () => t('table.friendList.joinCount')
}),
size: 120,
sortingFn: sortByNumber((row) => row?.$joinCount ?? 0),
meta: {
class: 'text-right'
class: 'text-right',
label: () => t('table.friendList.joinCount')
}
},
{
@@ -319,12 +336,13 @@ export const createColumns = ({
header: ({ column }) =>
sortButton({
column,
label: t('table.friendList.timeTogether')
label: () => t('table.friendList.timeTogether')
}),
size: 140,
sortingFn: sortByNumber((row) => row?.$timeSpent ?? 0),
meta: {
class: 'text-right'
class: 'text-right',
label: () => t('table.friendList.timeTogether')
},
cell: ({ row }) => {
const time = row.original?.$timeSpent;
@@ -337,9 +355,10 @@ export const createColumns = ({
header: ({ column }) =>
sortButton({
column,
label: t('table.friendList.lastSeen')
label: () => t('table.friendList.lastSeen')
}),
size: 170,
meta: { label: () => t('table.friendList.lastSeen') },
sortingFn: sortByString((row) => row?.$lastSeen ?? ''),
cell: ({ row }) => {
const text = formatDateFilter(row.original?.$lastSeen, 'long');
@@ -352,12 +371,13 @@ export const createColumns = ({
header: ({ column }) =>
sortButton({
column,
label: t('table.friendList.mutualFriends')
label: () => t('table.friendList.mutualFriends')
}),
size: 120,
sortingFn: sortByNumber((row) => row?.$mutualCount ?? 0),
meta: {
class: 'text-right'
class: 'text-right',
label: () => t('table.friendList.mutualFriends')
},
cell: ({ row }) => {
const count = row.original?.$mutualCount;
@@ -370,9 +390,10 @@ export const createColumns = ({
header: ({ column }) =>
sortButton({
column,
label: t('table.friendList.lastActivity')
label: () => t('table.friendList.lastActivity')
}),
size: 200,
meta: { label: () => t('table.friendList.lastActivity') },
sortingFn: sortByString((row) => row?.last_activity ?? ''),
cell: ({ row }) => (
<span>
@@ -384,8 +405,12 @@ export const createColumns = ({
id: 'lastLogin',
accessorFn: (row) => row?.last_login,
header: ({ column }) =>
sortButton({ column, label: t('table.friendList.lastLogin') }),
sortButton({
column,
label: () => t('table.friendList.lastLogin')
}),
size: 200,
meta: { label: () => t('table.friendList.lastLogin') },
sortingFn: sortByString((row) => row?.last_login ?? ''),
cell: ({ row }) => (
<span>
@@ -399,9 +424,10 @@ export const createColumns = ({
header: ({ column }) =>
sortButton({
column,
label: t('table.friendList.dateJoined')
label: () => t('table.friendList.dateJoined')
}),
size: 120,
meta: { label: () => t('table.friendList.dateJoined') },
sortingFn: sortByString((row) => row?.date_joined ?? ''),
cell: ({ row }) => <span>{row.original?.date_joined ?? ''}</span>
},
@@ -411,7 +437,8 @@ export const createColumns = ({
size: 100,
enableSorting: false,
meta: {
class: 'text-center'
class: 'text-center',
label: t('table.friendList.unfriend')
},
cell: ({ row }) => (
// TODO(icon): verify unfollow icon replacement
+6 -2
View File
@@ -31,6 +31,7 @@ export const createColumns = ({ onDelete, onDeletePrompt }) => {
{
accessorKey: 'created_at',
size: 120,
meta: { label: () => t('table.friendLog.date') },
header: ({ column }) => (
<Button
variant="ghost"
@@ -64,6 +65,7 @@ export const createColumns = ({ onDelete, onDeletePrompt }) => {
size: 160,
header: () => t('table.friendLog.type'),
meta: { label: () => t('table.friendLog.type') },
cell: ({ row }) => {
const type = row.getValue('type');
return (
@@ -79,7 +81,8 @@ export const createColumns = ({ onDelete, onDeletePrompt }) => {
minSize: 80,
header: () => t('table.friendLog.user'),
meta: {
stretch: true
stretch: true,
label: () => t('table.friendLog.user')
},
cell: ({ row }) => {
const original = row.original;
@@ -113,7 +116,8 @@ export const createColumns = ({ onDelete, onDeletePrompt }) => {
{
id: 'action',
meta: {
class: 'w-[80px] max-w-[80px] text-right'
class: 'w-[80px] max-w-[80px] text-right',
label: () => t('table.friendLog.action')
},
size: 80,
maxSize: 80,
+7 -2
View File
@@ -43,6 +43,7 @@ export const createColumns = ({ getCreatedAt, onDelete, onDeletePrompt }) => {
accessorFn: (row) => getCreatedAt(row),
id: 'created_at',
size: 140,
meta: { label: () => t('table.gameLog.date') },
header: ({ column }) => (
<Button
variant="ghost"
@@ -70,6 +71,7 @@ export const createColumns = ({ getCreatedAt, onDelete, onDeletePrompt }) => {
accessorKey: 'type',
size: 150,
header: () => t('table.gameLog.type'),
meta: { label: () => t('table.gameLog.type') },
cell: ({ row }) => {
const original = row.original;
const label = t(`view.game_log.filters.${original.type}`);
@@ -94,6 +96,7 @@ export const createColumns = ({ getCreatedAt, onDelete, onDeletePrompt }) => {
accessorKey: 'displayName',
size: 200,
header: () => t('table.gameLog.user'),
meta: { label: () => t('table.gameLog.user') },
cell: ({ row }) => {
const original = row.original;
const isFriend = original.isFriend;
@@ -121,7 +124,8 @@ export const createColumns = ({ getCreatedAt, onDelete, onDeletePrompt }) => {
enableSorting: false,
minSize: 150,
meta: {
stretch: true
stretch: true,
label: () => t('table.gameLog.detail')
},
cell: ({ row }) => {
const original = row.original;
@@ -248,7 +252,8 @@ export const createColumns = ({ getCreatedAt, onDelete, onDeletePrompt }) => {
{
id: 'action',
meta: {
class: 'text-right'
class: 'text-right',
label: () => t('table.gameLog.action')
},
size: 90,
minSize: 90,
+8 -3
View File
@@ -32,6 +32,7 @@ export const createColumns = ({ onDelete, onDeletePrompt }) => {
{
accessorKey: 'created',
size: 120,
meta: { label: () => t('table.moderation.date') },
header: ({ column }) => (
<Button
variant="ghost"
@@ -64,6 +65,7 @@ export const createColumns = ({ onDelete, onDeletePrompt }) => {
accessorKey: 'type',
size: 140,
header: () => t('table.moderation.type'),
meta: { label: () => t('table.moderation.type') },
cell: ({ row }) => {
const type = row.getValue('type');
const typeKey = `view.moderation.filters.${type}`;
@@ -79,7 +81,8 @@ export const createColumns = ({ onDelete, onDeletePrompt }) => {
{
accessorKey: 'sourceDisplayName',
meta: {
class: 'overflow-hidden'
class: 'overflow-hidden',
label: () => t('table.moderation.source')
},
size: 120,
header: () => t('table.moderation.source'),
@@ -100,7 +103,8 @@ export const createColumns = ({ onDelete, onDeletePrompt }) => {
size: 200,
minSize: 80,
meta: {
stretch: true
stretch: true,
label: () => t('table.moderation.target')
},
header: () => t('table.moderation.target'),
cell: ({ row }) => {
@@ -118,7 +122,8 @@ export const createColumns = ({ onDelete, onDeletePrompt }) => {
{
id: 'action',
meta: {
class: 'text-right'
class: 'text-right',
label: () => t('table.moderation.action')
},
size: 80,
minSize: 80,
+45 -28
View File
@@ -31,24 +31,27 @@ import { i18n } from '../../plugin';
const { t } = i18n.global;
const sortButton = ({ column, label, descFirst = false }) => (
<Button
variant="ghost"
size="sm"
class="-ml-2 h-8 px-2"
onClick={() => {
const sorted = column.getIsSorted();
if (!sorted && descFirst) {
column.toggleSorting(true);
return;
}
column.toggleSorting(sorted === 'asc');
}}
>
{label}
<ArrowUpDown class="ml-1 h-4 w-4" />
</Button>
);
const sortButton = ({ column, label, descFirst = false }) => {
const resolvedLabel = typeof label === 'function' ? label() : label;
return (
<Button
variant="ghost"
size="sm"
class="-ml-2 h-8 px-2"
onClick={() => {
const sorted = column.getIsSorted();
if (!sorted && descFirst) {
column.toggleSorting(true);
return;
}
column.toggleSorting(sorted === 'asc');
}}
>
{resolvedLabel}
<ArrowUpDown class="ml-1 h-4 w-4" />
</Button>
);
};
export function getColumns({
onShowAvatarDialog,
@@ -102,8 +105,12 @@ export function getColumns({
id: 'name',
accessorKey: 'Name',
header: ({ column }) =>
sortButton({ column, label: t('dialog.avatar.info.name') }),
sortButton({
column,
label: () => t('dialog.avatar.info.name')
}),
size: 200,
meta: { label: () => t('dialog.avatar.info.name') },
cell: ({ row }) => {
const ref = row.original;
return (
@@ -124,6 +131,7 @@ export function getColumns({
header: () => t('dialog.avatar.info.platform'),
size: 120,
enableSorting: false,
meta: { label: () => t('dialog.avatar.info.platform') },
cell: ({ row }) => {
const ref = row.original;
const platforms = getAvailablePlatforms(ref.unityPackages);
@@ -160,6 +168,7 @@ export function getColumns({
header: () => t('dialog.avatar.info.tags'),
size: 150,
enableSorting: false,
meta: { label: () => t('dialog.avatar.info.tags') },
cell: ({ row }) => {
const tags = row.original.$tags || [];
if (!tags.length) return null;
@@ -198,6 +207,7 @@ export function getColumns({
accessorKey: 'releaseStatus',
header: () => t('dialog.avatar.tags.public'),
size: 120,
meta: { label: () => t('dialog.avatar.tags.public') },
cell: ({ row }) => {
const ref = row.original;
return (
@@ -215,12 +225,13 @@ export function getColumns({
header: ({ column }) =>
sortButton({
column,
label: t('dialog.avatar.info.time_spent'),
label: () => t('dialog.avatar.info.time_spent'),
descFirst: true
}),
size: 140,
meta: {
class: 'text-right'
class: 'text-right',
label: () => t('dialog.avatar.info.time_spent')
},
cell: ({ row }) => {
const time = row.original?.$timeSpent;
@@ -237,12 +248,13 @@ export function getColumns({
header: ({ column }) =>
sortButton({
column,
label: t('dialog.avatar.info.version'),
label: () => t('dialog.avatar.info.version'),
descFirst: true
}),
size: 90,
meta: {
class: 'text-right'
class: 'text-right',
label: () => t('dialog.avatar.info.version')
},
cell: ({ row }) => (
<span class=" text-sm">{row.original.version ?? '-'}</span>
@@ -255,9 +267,10 @@ export function getColumns({
header: ({ column }) =>
sortButton({
column,
label: t('dialog.avatar.info.pc_performance')
label: () => t('dialog.avatar.info.pc_performance')
}),
size: 140,
meta: { label: () => t('dialog.avatar.info.pc_performance') },
cell: ({ row }) => {
const perf = getPlatformInfo(row.original.unityPackages)?.pc
?.performanceRating;
@@ -276,9 +289,10 @@ export function getColumns({
header: ({ column }) =>
sortButton({
column,
label: t('dialog.avatar.info.android_performance')
label: () => t('dialog.avatar.info.android_performance')
}),
size: 140,
meta: { label: () => t('dialog.avatar.info.android_performance') },
cell: ({ row }) => {
const perf = getPlatformInfo(row.original.unityPackages)
?.android?.performanceRating;
@@ -297,9 +311,10 @@ export function getColumns({
header: ({ column }) =>
sortButton({
column,
label: t('dialog.avatar.info.ios_performance')
label: () => t('dialog.avatar.info.ios_performance')
}),
size: 140,
meta: { label: () => t('dialog.avatar.info.ios_performance') },
cell: ({ row }) => {
const perf = getPlatformInfo(row.original.unityPackages)?.ios
?.performanceRating;
@@ -316,10 +331,11 @@ export function getColumns({
header: ({ column }) =>
sortButton({
column,
label: t('dialog.avatar.info.last_updated'),
label: () => t('dialog.avatar.info.last_updated'),
descFirst: true
}),
size: 160,
meta: { label: () => t('dialog.avatar.info.last_updated') },
cell: ({ row }) => {
const ref = row.original;
return (
@@ -335,10 +351,11 @@ export function getColumns({
header: ({ column }) =>
sortButton({
column,
label: t('dialog.avatar.info.created_at'),
label: () => t('dialog.avatar.info.created_at'),
descFirst: true
}),
size: 160,
meta: { label: () => t('dialog.avatar.info.created_at') },
cell: ({ row }) => {
const ref = row.original;
return (
+11 -4
View File
@@ -102,6 +102,7 @@ export const createColumns = ({
accessorFn: (row) => getNotificationCreatedAtTs(row),
id: 'created_at',
size: 120,
meta: { label: () => t('table.notification.date') },
header: ({ column }) => (
<Button
variant="ghost"
@@ -151,6 +152,7 @@ export const createColumns = ({
accessorKey: 'type',
size: 180,
header: () => t('table.notification.type'),
meta: { label: () => t('table.notification.type') },
cell: ({ row }) => {
const original = row.original;
const typeKey = `view.notification.filters.${original.type}`;
@@ -228,7 +230,8 @@ export const createColumns = ({
{
accessorKey: 'senderUsername',
meta: {
class: 'overflow-hidden'
class: 'overflow-hidden',
label: () => t('table.notification.user')
},
size: 150,
header: () => t('table.notification.user'),
@@ -284,7 +287,8 @@ export const createColumns = ({
{
accessorKey: 'groupName',
meta: {
class: 'overflow-hidden'
class: 'overflow-hidden',
label: () => t('table.notification.group')
},
size: 150,
header: () => t('table.notification.group'),
@@ -390,6 +394,7 @@ export const createColumns = ({
accessorKey: 'photo',
size: 80,
header: () => t('table.notification.photo'),
meta: { label: () => t('table.notification.photo') },
cell: ({ row }) => {
const original = row.original;
if (original.type === 'boop') {
@@ -458,7 +463,8 @@ export const createColumns = ({
enableSorting: false,
meta: {
class: 'min-w-0 overflow-hidden',
stretch: true
stretch: true,
label: () => t('table.notification.message')
},
minSize: 100,
cell: ({ row }) => {
@@ -548,7 +554,8 @@ export const createColumns = ({
{
id: 'action',
meta: {
class: 'text-right'
class: 'text-right',
label: () => t('table.notification.action')
},
size: 120,
minSize: 120,
+46 -26
View File
@@ -20,24 +20,27 @@ import { i18n } from '../../plugin';
const { t } = i18n.global;
const sortButton = ({ column, label, descFirst = false }) => (
<Button
variant="ghost"
size="sm"
class="-ml-2 h-8 px-2"
onClick={() => {
const sorted = column.getIsSorted();
if (!sorted && descFirst) {
column.toggleSorting(true);
return;
}
column.toggleSorting(sorted === 'asc');
}}
>
{label}
<ArrowUpDown class="ml-1 h-4 w-4" />
</Button>
);
const sortButton = ({ column, label, descFirst = false }) => {
const resolvedLabel = typeof label === 'function' ? label() : label;
return (
<Button
variant="ghost"
size="sm"
class="-ml-2 h-8 px-2"
onClick={() => {
const sorted = column.getIsSorted();
if (!sorted && descFirst) {
column.toggleSorting(true);
return;
}
column.toggleSorting(sorted === 'asc');
}}
>
{resolvedLabel}
<ArrowUpDown class="ml-1 h-4 w-4" />
</Button>
);
};
const getInstanceIconWeight = (item) => {
if (!item) return 0;
@@ -70,6 +73,7 @@ export const createColumns = ({
header: () => t('table.playerList.avatar'),
size: 70,
enableSorting: false,
meta: { label: () => t('table.playerList.avatar') },
cell: ({ row }) => {
const userRef = row.original?.ref;
const src = userImage(userRef);
@@ -89,8 +93,12 @@ export const createColumns = ({
id: 'timer',
accessorFn: (row) => row?.timer,
header: ({ column }) =>
sortButton({ column, label: t('table.playerList.timer') }),
sortButton({
column,
label: () => t('table.playerList.timer')
}),
size: 90,
meta: { label: () => t('table.playerList.timer') },
sortingFn: (rowA, rowB) =>
(rowA.original?.timer ?? 0) - (rowB.original?.timer ?? 0),
cell: ({ row }) => <Timer epoch={row.original?.timer} />
@@ -101,9 +109,10 @@ export const createColumns = ({
header: ({ column }) =>
sortButton({
column,
label: t('table.playerList.displayName')
label: () => t('table.playerList.displayName')
}),
size: 200,
meta: { label: () => t('table.playerList.displayName') },
sortingFn: (rowA, rowB) =>
sortAlphabetically(rowA.original, rowB.original, 'displayName'),
cell: ({ row }) => {
@@ -118,8 +127,9 @@ export const createColumns = ({
id: 'rank',
accessorFn: (row) => row?.ref?.$trustSortNum,
header: ({ column }) =>
sortButton({ column, label: t('table.playerList.rank') }),
sortButton({ column, label: () => t('table.playerList.rank') }),
size: 110,
meta: { label: () => t('table.playerList.rank') },
sortingFn: (rowA, rowB) =>
(rowA.original?.ref?.$trustSortNum ?? 0) -
(rowB.original?.ref?.$trustSortNum ?? 0),
@@ -143,7 +153,8 @@ export const createColumns = ({
size: 200,
minSize: 100,
meta: {
stretch: true
stretch: true,
label: () => t('table.playerList.status')
},
enableSorting: false,
cell: ({ row }) => {
@@ -170,9 +181,13 @@ export const createColumns = ({
id: 'photonId',
accessorFn: (row) => row?.photonId,
header: ({ column }) =>
sortButton({ column, label: t('table.playerList.photonId') }),
sortButton({
column,
label: () => t('table.playerList.photonId')
}),
size: 110,
enableHiding: true,
meta: { label: () => t('table.playerList.photonId') },
sortingFn: (rowA, rowB) =>
(rowA.original?.photonId ?? 0) - (rowB.original?.photonId ?? 0),
cell: ({ row }) => {
@@ -212,13 +227,14 @@ export const createColumns = ({
header: ({ column }) =>
sortButton({
column,
label: t('table.playerList.icon'),
label: () => t('table.playerList.icon'),
descFirst: true
}),
size: 90,
accessorFn: (row) => getInstanceIconWeight(row),
meta: {
class: 'text-center'
class: 'text-center',
label: () => t('table.playerList.icon')
},
sortingFn: (rowA, rowB, columnId) => {
const a = rowA.original;
@@ -291,6 +307,7 @@ export const createColumns = ({
header: () => t('table.playerList.platform'),
size: 90,
enableSorting: false,
meta: { label: () => t('table.playerList.platform') },
cell: ({ row }) => {
const userRef = row.original?.ref;
const platform = userRef?.$platform;
@@ -330,6 +347,7 @@ export const createColumns = ({
header: () => t('table.playerList.language'),
size: 100,
enableSorting: false,
meta: { label: () => t('table.playerList.language') },
cell: ({ row }) => {
const userRef = row.original?.ref;
const langs = userRef?.$languages ?? [];
@@ -366,6 +384,7 @@ export const createColumns = ({
header: () => t('table.playerList.bioLink'),
size: 100,
enableSorting: false,
meta: { label: () => t('table.playerList.bioLink') },
cell: ({ row }) => {
const links =
row.original?.ref?.bioLinks?.filter(Boolean) ?? [];
@@ -402,7 +421,8 @@ export const createColumns = ({
size: 150,
minSize: 20,
meta: {
stretch: true
stretch: true,
label: () => t('table.playerList.note')
},
enableSorting: false,
cell: ({ row }) => {