mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-05-06 22:46:06 +02:00
fix datatable header reorder issue
This commit is contained in:
@@ -10,11 +10,11 @@
|
|||||||
<colgroup>
|
<colgroup>
|
||||||
<col v-for="col in table.getVisibleLeafColumns()" :key="col.id" :style="getColStyle(col)" />
|
<col v-for="col in table.getVisibleLeafColumns()" :key="col.id" :style="getColStyle(col)" />
|
||||||
</colgroup>
|
</colgroup>
|
||||||
<ContextMenu v-if="enableColumnVisibility">
|
<ContextMenu v-if="showHeaderContextMenu">
|
||||||
<ContextMenuTrigger as-child>
|
<ContextMenuTrigger as-child>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow v-for="headerGroup in table.getHeaderGroups()" :key="headerGroup.id">
|
<TableRow v-for="headerGroup in table.getHeaderGroups()" :key="headerGroup.id">
|
||||||
<template v-if="enableColumnReorder">
|
<template v-if="effectiveColumnReorder">
|
||||||
<DragDropProvider @dragEnd="onHeaderDragEnd">
|
<DragDropProvider @dragEnd="onHeaderDragEnd">
|
||||||
<template v-for="(header, hIdx) in headerGroup.headers" :key="header.id">
|
<template v-for="(header, hIdx) in headerGroup.headers" :key="header.id">
|
||||||
<SortableTableHead
|
<SortableTableHead
|
||||||
@@ -76,21 +76,60 @@
|
|||||||
@update:model-value="col.toggleVisibility(!!$event)">
|
@update:model-value="col.toggleVisibility(!!$event)">
|
||||||
{{ resolveHeaderLabel(col) }}
|
{{ resolveHeaderLabel(col) }}
|
||||||
</ContextMenuCheckboxItem>
|
</ContextMenuCheckboxItem>
|
||||||
|
<template v-if="tcColumnOrderLocked != null">
|
||||||
|
<ContextMenuSeparator />
|
||||||
|
<ContextMenuCheckboxItem
|
||||||
|
:model-value="tcColumnOrderLocked"
|
||||||
|
@update:model-value="table.options.meta.columnOrderLocked.value = $event">
|
||||||
|
{{ t('table.header_menu.lock_column_order') }}
|
||||||
|
</ContextMenuCheckboxItem>
|
||||||
|
</template>
|
||||||
|
<template v-if="tcResetAll">
|
||||||
|
<ContextMenuSeparator />
|
||||||
|
<ContextMenuItem inset @select="tcResetAll">
|
||||||
|
{{ t('table.header_menu.reset_all') }}
|
||||||
|
</ContextMenuItem>
|
||||||
|
</template>
|
||||||
</ContextMenuContent>
|
</ContextMenuContent>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
<TableHeader v-else>
|
<ContextMenu v-else-if="showHeaderContextMenuNoVisibility">
|
||||||
<TableRow v-for="headerGroup in table.getHeaderGroups()" :key="headerGroup.id">
|
<ContextMenuTrigger as-child>
|
||||||
<template v-if="enableColumnReorder">
|
<TableHeader>
|
||||||
<DragDropProvider @dragEnd="onHeaderDragEnd">
|
<TableRow v-for="headerGroup in table.getHeaderGroups()" :key="headerGroup.id">
|
||||||
<template v-for="(header, hIdx) in headerGroup.headers" :key="header.id">
|
<template v-if="effectiveColumnReorder">
|
||||||
<SortableTableHead
|
<DragDropProvider @dragEnd="onHeaderDragEnd">
|
||||||
v-if="isReorderable(header)"
|
<template v-for="(header, hIdx) in headerGroup.headers" :key="header.id">
|
||||||
:header="header"
|
<SortableTableHead
|
||||||
:index="reorderableIndex(headerGroup.headers, hIdx)"
|
v-if="isReorderable(header)"
|
||||||
:header-class="getHeaderClass(header)"
|
:header="header"
|
||||||
:pinned-style="getPinnedStyle(header.column)" />
|
:index="reorderableIndex(headerGroup.headers, hIdx)"
|
||||||
|
:header-class="getHeaderClass(header)"
|
||||||
|
:pinned-style="getPinnedStyle(header.column)" />
|
||||||
|
<TableHead
|
||||||
|
v-else
|
||||||
|
:class="getHeaderClass(header)"
|
||||||
|
:style="getPinnedStyle(header.column)">
|
||||||
|
<template v-if="!header.isPlaceholder">
|
||||||
|
<FlexRender
|
||||||
|
:render="header.column.columnDef.header"
|
||||||
|
:props="header.getContext()" />
|
||||||
|
<div
|
||||||
|
v-if="header.column.getCanResize?.()"
|
||||||
|
class="absolute right-0 top-0 h-full w-2 cursor-col-resize touch-none select-none opacity-0 transition-opacity group-hover:opacity-100"
|
||||||
|
@mousedown.stop="header.getResizeHandler?.()($event)"
|
||||||
|
@touchstart.stop="header.getResizeHandler?.()($event)">
|
||||||
|
<div
|
||||||
|
class="absolute right-0 top-0 h-full w-px bg-border dark:bg-border dark:brightness-[2]" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</TableHead>
|
||||||
|
</template>
|
||||||
|
</DragDropProvider>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
<TableHead
|
<TableHead
|
||||||
v-else
|
v-for="header in headerGroup.headers"
|
||||||
|
:key="header.id"
|
||||||
:class="getHeaderClass(header)"
|
:class="getHeaderClass(header)"
|
||||||
:style="getPinnedStyle(header.column)">
|
:style="getPinnedStyle(header.column)">
|
||||||
<template v-if="!header.isPlaceholder">
|
<template v-if="!header.isPlaceholder">
|
||||||
@@ -108,29 +147,44 @@
|
|||||||
</template>
|
</template>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
</template>
|
</template>
|
||||||
</DragDropProvider>
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
</ContextMenuTrigger>
|
||||||
|
<ContextMenuContent class="w-48">
|
||||||
|
<template v-if="tcColumnOrderLocked != null">
|
||||||
|
<ContextMenuCheckboxItem
|
||||||
|
:model-value="tcColumnOrderLocked"
|
||||||
|
@update:model-value="table.options.meta.columnOrderLocked.value = $event">
|
||||||
|
{{ t('table.header_menu.lock_column_order') }}
|
||||||
|
</ContextMenuCheckboxItem>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-if="tcResetAll">
|
||||||
<TableHead
|
<ContextMenuSeparator v-if="tcColumnOrderLocked != null" />
|
||||||
v-for="header in headerGroup.headers"
|
<ContextMenuItem inset @select="tcResetAll">
|
||||||
:key="header.id"
|
{{ t('table.header_menu.reset_all') }}
|
||||||
:class="getHeaderClass(header)"
|
</ContextMenuItem>
|
||||||
:style="getPinnedStyle(header.column)">
|
</template>
|
||||||
<template v-if="!header.isPlaceholder">
|
</ContextMenuContent>
|
||||||
<FlexRender
|
</ContextMenu>
|
||||||
:render="header.column.columnDef.header"
|
<TableHeader v-else>
|
||||||
:props="header.getContext()" />
|
<TableRow v-for="headerGroup in table.getHeaderGroups()" :key="headerGroup.id">
|
||||||
|
<TableHead
|
||||||
|
v-for="header in headerGroup.headers"
|
||||||
|
:key="header.id"
|
||||||
|
:class="getHeaderClass(header)"
|
||||||
|
:style="getPinnedStyle(header.column)">
|
||||||
|
<template v-if="!header.isPlaceholder">
|
||||||
|
<FlexRender :render="header.column.columnDef.header" :props="header.getContext()" />
|
||||||
|
<div
|
||||||
|
v-if="header.column.getCanResize?.()"
|
||||||
|
class="absolute right-0 top-0 h-full w-2 cursor-col-resize touch-none select-none opacity-0 transition-opacity group-hover:opacity-100"
|
||||||
|
@mousedown.stop="header.getResizeHandler?.()($event)"
|
||||||
|
@touchstart.stop="header.getResizeHandler?.()($event)">
|
||||||
<div
|
<div
|
||||||
v-if="header.column.getCanResize?.()"
|
class="absolute right-0 top-0 h-full w-px bg-border dark:bg-border dark:brightness-[2]" />
|
||||||
class="absolute right-0 top-0 h-full w-2 cursor-col-resize touch-none select-none opacity-0 transition-opacity group-hover:opacity-100"
|
</div>
|
||||||
@mousedown.stop="header.getResizeHandler?.()($event)"
|
</template>
|
||||||
@touchstart.stop="header.getResizeHandler?.()($event)">
|
</TableHead>
|
||||||
<div
|
|
||||||
class="absolute right-0 top-0 h-full w-px bg-border dark:bg-border dark:brightness-[2]" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</TableHead>
|
|
||||||
</template>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
@@ -254,6 +308,14 @@
|
|||||||
import { useAppearanceSettingsStore } from '@/stores/';
|
import { useAppearanceSettingsStore } from '@/stores/';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ContextMenu,
|
||||||
|
ContextMenuCheckboxItem,
|
||||||
|
ContextMenuContent,
|
||||||
|
ContextMenuItem,
|
||||||
|
ContextMenuSeparator,
|
||||||
|
ContextMenuTrigger
|
||||||
|
} from '../context-menu';
|
||||||
import {
|
import {
|
||||||
Pagination,
|
Pagination,
|
||||||
PaginationContent,
|
PaginationContent,
|
||||||
@@ -271,7 +333,6 @@
|
|||||||
isSpacer,
|
isSpacer,
|
||||||
resolveHeaderLabel
|
resolveHeaderLabel
|
||||||
} from './dataTableHelpers.js';
|
} from './dataTableHelpers.js';
|
||||||
import { ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuTrigger } from '../context-menu';
|
|
||||||
|
|
||||||
import DataTableEmpty from './DataTableEmpty.vue';
|
import DataTableEmpty from './DataTableEmpty.vue';
|
||||||
import SortableTableHead from './SortableTableHead.vue';
|
import SortableTableHead from './SortableTableHead.vue';
|
||||||
@@ -341,6 +402,25 @@
|
|||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const tableScrollRef = ref(null);
|
const tableScrollRef = ref(null);
|
||||||
|
|
||||||
|
const tableMeta = computed(() => props.table?.options?.meta ?? {});
|
||||||
|
|
||||||
|
const tcResetAll = computed(() => tableMeta.value.resetAll ?? null);
|
||||||
|
const tcColumnOrderLocked = computed(() => {
|
||||||
|
const val = tableMeta.value.columnOrderLocked;
|
||||||
|
if (val == null) return null;
|
||||||
|
return typeof val === 'object' && 'value' in val ? val.value : val;
|
||||||
|
});
|
||||||
|
|
||||||
|
const showHeaderContextMenu = computed(
|
||||||
|
() => props.enableColumnVisibility || tcResetAll.value || tcColumnOrderLocked.value != null
|
||||||
|
);
|
||||||
|
|
||||||
|
const showHeaderContextMenuNoVisibility = computed(
|
||||||
|
() => !props.enableColumnVisibility && (tcResetAll.value || tcColumnOrderLocked.value != null)
|
||||||
|
);
|
||||||
|
|
||||||
|
const effectiveColumnReorder = computed(() => props.enableColumnReorder && tcColumnOrderLocked.value !== true);
|
||||||
|
|
||||||
const emptyType = computed(() => {
|
const emptyType = computed(() => {
|
||||||
const totalRows = props.table?.getCoreRowModel?.().rows?.length ?? 0;
|
const totalRows = props.table?.getCoreRowModel?.().rows?.length ?? 0;
|
||||||
return totalRows === 0 ? 'nodata' : 'nomatch';
|
return totalRows === 0 ? 'nodata' : 'nomatch';
|
||||||
@@ -427,6 +507,7 @@
|
|||||||
const reorderableIds = allColumns
|
const reorderableIds = allColumns
|
||||||
.filter((col) => {
|
.filter((col) => {
|
||||||
if (isSpacer(col)) return false;
|
if (isSpacer(col)) return false;
|
||||||
|
if (!col.columnDef?.meta?.label) return false;
|
||||||
if (getPinnedState(col)) return false;
|
if (getPinnedState(col)) return false;
|
||||||
if (col.columnDef?.meta?.disableReorder) return false;
|
if (col.columnDef?.meta?.disableReorder) return false;
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -54,6 +54,7 @@
|
|||||||
<div
|
<div
|
||||||
v-if="header.column.getCanResize?.()"
|
v-if="header.column.getCanResize?.()"
|
||||||
class="absolute right-0 top-0 h-full w-2 cursor-col-resize touch-none select-none opacity-0 transition-opacity group-hover:opacity-100"
|
class="absolute right-0 top-0 h-full w-2 cursor-col-resize touch-none select-none opacity-0 transition-opacity group-hover:opacity-100"
|
||||||
|
@pointerdown.stop
|
||||||
@mousedown.stop="header.getResizeHandler?.()($event)"
|
@mousedown.stop="header.getResizeHandler?.()($event)"
|
||||||
@touchstart.stop="header.getResizeHandler?.()($event)">
|
@touchstart.stop="header.getResizeHandler?.()($event)">
|
||||||
<div class="absolute right-0 top-0 h-full w-px bg-border dark:bg-border dark:brightness-[2]" />
|
<div class="absolute right-0 top-0 h-full w-px bg-border dark:bg-border dark:brightness-[2]" />
|
||||||
|
|||||||
@@ -85,12 +85,12 @@ describe('getToggleableColumns', () => {
|
|||||||
expect(getToggleableColumns(cols)[0].id).toBe('name');
|
expect(getToggleableColumns(cols)[0].id).toBe('name');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('excludes stretch columns', () => {
|
it('includes stretch columns', () => {
|
||||||
const cols = [
|
const cols = [
|
||||||
mockCol('name', { label: 'Name' }),
|
mockCol('name', { label: 'Name' }),
|
||||||
mockCol('detail', { stretch: true, label: 'Detail' })
|
mockCol('detail', { stretch: true, label: 'Detail' })
|
||||||
];
|
];
|
||||||
expect(getToggleableColumns(cols)).toHaveLength(1);
|
expect(getToggleableColumns(cols)).toHaveLength(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('excludes columns with disableVisibilityToggle', () => {
|
it('excludes columns with disableVisibilityToggle', () => {
|
||||||
@@ -153,24 +153,31 @@ describe('getColStyle', () => {
|
|||||||
describe('isReorderable', () => {
|
describe('isReorderable', () => {
|
||||||
const noPinning = () => false;
|
const noPinning = () => false;
|
||||||
|
|
||||||
it('returns true for normal column', () => {
|
it('returns true for normal column with label', () => {
|
||||||
const header = { column: mockCol('name') };
|
const header = { column: mockCol('name', { label: 'Name' }) };
|
||||||
expect(isReorderable(header, noPinning)).toBe(true);
|
expect(isReorderable(header, noPinning)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('returns false for column without label', () => {
|
||||||
|
const header = { column: mockCol('expander') };
|
||||||
|
expect(isReorderable(header, noPinning)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
it('returns false for spacer column', () => {
|
it('returns false for spacer column', () => {
|
||||||
const header = { column: { id: '__spacer', columnDef: { meta: {} } } };
|
const header = { column: { id: '__spacer', columnDef: { meta: {} } } };
|
||||||
expect(isReorderable(header, noPinning)).toBe(false);
|
expect(isReorderable(header, noPinning)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns false for pinned column', () => {
|
it('returns false for pinned column', () => {
|
||||||
const header = { column: mockCol('name') };
|
const header = { column: mockCol('name', { label: 'Name' }) };
|
||||||
const isPinned = () => true;
|
const isPinned = () => true;
|
||||||
expect(isReorderable(header, isPinned)).toBe(false);
|
expect(isReorderable(header, isPinned)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns false for columns with disableReorder', () => {
|
it('returns false for columns with disableReorder', () => {
|
||||||
const header = { column: mockCol('name', { disableReorder: true }) };
|
const header = {
|
||||||
|
column: mockCol('name', { label: 'Name', disableReorder: true })
|
||||||
|
};
|
||||||
expect(isReorderable(header, noPinning)).toBe(false);
|
expect(isReorderable(header, noPinning)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ export function getToggleableColumns(cols) {
|
|||||||
if (!Array.isArray(cols)) return [];
|
if (!Array.isArray(cols)) return [];
|
||||||
return cols.filter((col) => {
|
return cols.filter((col) => {
|
||||||
if (isSpacer(col)) return false;
|
if (isSpacer(col)) return false;
|
||||||
if (isStretch(col)) return false;
|
|
||||||
if (col.columnDef?.meta?.disableVisibilityToggle) return false;
|
if (col.columnDef?.meta?.disableVisibilityToggle) return false;
|
||||||
if (!col.columnDef?.meta?.label) return false;
|
if (!col.columnDef?.meta?.label) return false;
|
||||||
return true;
|
return true;
|
||||||
@@ -71,6 +70,7 @@ export function isReorderable(header, getPinnedState) {
|
|||||||
const col = header?.column;
|
const col = header?.column;
|
||||||
if (!col) return false;
|
if (!col) return false;
|
||||||
if (isSpacer(col)) return false;
|
if (isSpacer(col)) return false;
|
||||||
|
if (!col.columnDef?.meta?.label) return false;
|
||||||
if (getPinnedState?.(col)) return false;
|
if (getPinnedState?.(col)) return false;
|
||||||
if (col.columnDef?.meta?.disableReorder) return false;
|
if (col.columnDef?.meta?.disableReorder) return false;
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -332,4 +332,88 @@ describe('useVrcxVueTable persistence', () => {
|
|||||||
);
|
);
|
||||||
expect(stored?.pageSize).toBeUndefined();
|
expect(stored?.pageSize).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('resetAll clears both columnSizing and columnOrder', async () => {
|
||||||
|
const { columnSizing, columnOrder, resetAll } = useVrcxVueTable({
|
||||||
|
data: [],
|
||||||
|
columns: makeColumns('name', 'date'),
|
||||||
|
persistKey: 'test-reset-all',
|
||||||
|
enableColumnResizing: true,
|
||||||
|
enableColumnReorder: true
|
||||||
|
});
|
||||||
|
|
||||||
|
columnSizing.value = { name: 200 };
|
||||||
|
columnOrder.value = ['date', 'name'];
|
||||||
|
await new Promise((r) => setTimeout(r, 300));
|
||||||
|
|
||||||
|
resetAll();
|
||||||
|
|
||||||
|
expect(columnSizing.value).toEqual({});
|
||||||
|
expect(columnOrder.value).toEqual([]);
|
||||||
|
|
||||||
|
const stored = JSON.parse(
|
||||||
|
localStorage.getItem('vrcx:table:test-reset-all')
|
||||||
|
);
|
||||||
|
expect(stored?.columnSizing).toBeUndefined();
|
||||||
|
expect(stored?.columnOrder).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('persists columnOrderLocked to localStorage', async () => {
|
||||||
|
const { columnOrderLocked } = useVrcxVueTable({
|
||||||
|
data: [],
|
||||||
|
columns: makeColumns('name', 'date'),
|
||||||
|
persistKey: 'test-lock-order'
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(columnOrderLocked.value).toBe(false);
|
||||||
|
|
||||||
|
columnOrderLocked.value = true;
|
||||||
|
|
||||||
|
// Watcher is async, wait for it to fire
|
||||||
|
await new Promise((r) => setTimeout(r, 50));
|
||||||
|
|
||||||
|
const stored = JSON.parse(
|
||||||
|
localStorage.getItem('vrcx:table:test-lock-order')
|
||||||
|
);
|
||||||
|
expect(stored?.columnOrderLocked).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('restores columnOrderLocked from localStorage on init', () => {
|
||||||
|
localStorage.setItem(
|
||||||
|
'vrcx:table:test-restore-lock',
|
||||||
|
JSON.stringify({ columnOrderLocked: true })
|
||||||
|
);
|
||||||
|
|
||||||
|
const { columnOrderLocked } = useVrcxVueTable({
|
||||||
|
data: [],
|
||||||
|
columns: makeColumns('name', 'date'),
|
||||||
|
persistKey: 'test-restore-lock'
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(columnOrderLocked.value).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('attaches controls to table.options.meta when persistKey is set', () => {
|
||||||
|
const { table } = useVrcxVueTable({
|
||||||
|
data: [],
|
||||||
|
columns: makeColumns('name', 'date'),
|
||||||
|
persistKey: 'test-meta'
|
||||||
|
});
|
||||||
|
|
||||||
|
const meta = table.options.meta;
|
||||||
|
expect(meta.resetAll).toBeTypeOf('function');
|
||||||
|
expect(meta.columnOrderLocked).toBeDefined();
|
||||||
|
expect(meta.columnOrderLocked.value).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not attach controls to meta without persistKey', () => {
|
||||||
|
const { table } = useVrcxVueTable({
|
||||||
|
data: [],
|
||||||
|
columns: makeColumns('name', 'date')
|
||||||
|
});
|
||||||
|
|
||||||
|
const meta = table.options.meta;
|
||||||
|
expect(meta.resetAll).toBeUndefined();
|
||||||
|
expect(meta.columnOrderLocked).toBeUndefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -273,6 +273,21 @@ export function useVrcxVueTable(options) {
|
|||||||
localStorage.setItem(storageKey, JSON.stringify(next));
|
localStorage.setItem(storageKey, JSON.stringify(next));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param keys
|
||||||
|
*/
|
||||||
|
function removePersisted(keys) {
|
||||||
|
if (!storageKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const cur = safeJsonParse(localStorage.getItem(storageKey)) ?? {};
|
||||||
|
for (const key of keys) {
|
||||||
|
delete cur[key];
|
||||||
|
}
|
||||||
|
cur.updatedAt = Date.now();
|
||||||
|
localStorage.setItem(storageKey, JSON.stringify(cur));
|
||||||
|
}
|
||||||
|
|
||||||
const persisted = readPersisted();
|
const persisted = readPersisted();
|
||||||
|
|
||||||
let resolvedSorting = initialSorting ?? [];
|
let resolvedSorting = initialSorting ?? [];
|
||||||
@@ -309,6 +324,9 @@ export function useVrcxVueTable(options) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Column order lock — persisted per-table
|
||||||
|
const columnOrderLocked = ref(persisted?.columnOrderLocked === true);
|
||||||
|
|
||||||
const state = {};
|
const state = {};
|
||||||
const handlers = {};
|
const handlers = {};
|
||||||
const rowModels = {};
|
const rowModels = {};
|
||||||
@@ -417,6 +435,11 @@ export function useVrcxVueTable(options) {
|
|||||||
|
|
||||||
state,
|
state,
|
||||||
|
|
||||||
|
meta: {
|
||||||
|
resetAll: storageKey ? resetAll : undefined,
|
||||||
|
columnOrderLocked: storageKey ? columnOrderLocked : undefined
|
||||||
|
},
|
||||||
|
|
||||||
...tableOptions
|
...tableOptions
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -505,6 +528,20 @@ export function useVrcxVueTable(options) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (storageKey) {
|
||||||
|
watch(columnOrderLocked, (val) => {
|
||||||
|
writePersisted({ columnOrderLocked: val });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
function resetAll() {
|
||||||
|
columnSizing.value = {};
|
||||||
|
columnOrder.value = [];
|
||||||
|
removePersisted(['columnSizing', 'columnOrder']);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
table,
|
table,
|
||||||
sorting,
|
sorting,
|
||||||
@@ -513,6 +550,8 @@ export function useVrcxVueTable(options) {
|
|||||||
columnPinning,
|
columnPinning,
|
||||||
columnSizing,
|
columnSizing,
|
||||||
columnOrder,
|
columnOrder,
|
||||||
columnVisibility
|
columnVisibility,
|
||||||
|
columnOrderLocked,
|
||||||
|
resetAll
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2417,6 +2417,10 @@
|
|||||||
"traveling": "Traveling"
|
"traveling": "Traveling"
|
||||||
},
|
},
|
||||||
"table": {
|
"table": {
|
||||||
|
"header_menu": {
|
||||||
|
"reset_all": "Reset All",
|
||||||
|
"lock_column_order": "Lock Column Order"
|
||||||
|
},
|
||||||
"pagination": {
|
"pagination": {
|
||||||
"rows_per_page": "Rows per page",
|
"rows_per_page": "Rows per page",
|
||||||
"first": "First",
|
"first": "First",
|
||||||
|
|||||||
@@ -187,7 +187,10 @@ export const createColumns = ({
|
|||||||
}),
|
}),
|
||||||
size: 110,
|
size: 110,
|
||||||
enableHiding: true,
|
enableHiding: true,
|
||||||
meta: { label: () => t('table.playerList.photonId') },
|
meta: {
|
||||||
|
label: () => t('table.playerList.photonId'),
|
||||||
|
disableVisibilityToggle: true
|
||||||
|
},
|
||||||
sortingFn: (rowA, rowB) =>
|
sortingFn: (rowA, rowB) =>
|
||||||
(rowA.original?.photonId ?? 0) - (rowB.original?.photonId ?? 0),
|
(rowA.original?.photonId ?? 0) - (rowB.original?.photonId ?? 0),
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user