feat: unify table page size handling with useVrcxVueTable

This commit is contained in:
pa
2026-03-06 23:14:29 +09:00
parent 318f0b141c
commit cf1577cb44
10 changed files with 175 additions and 117 deletions

View File

@@ -503,6 +503,19 @@
set: (size) => handlePageSizeChange(size)
});
// When the current pageSize is not in the available pageSizes list
watch(
[pageSizeProxy, () => props.pageSizes],
([current, sizes]) => {
if (!sizes?.length || sizes.includes(current)) {
return;
}
const nearest = sizes.reduce((prev, s) => (Math.abs(s - current) < Math.abs(prev - current) ? s : prev));
handlePageSizeChange(nearest);
},
{ immediate: true }
);
const pageSizeValue = computed({
get: () => String(pageSizeProxy.value),
set: (value) => handlePageSizeChange(Number(value))

View File

@@ -267,4 +267,69 @@ describe('useVrcxVueTable persistence', () => {
);
expect(stored?.columnVisibility).toBeUndefined();
});
it('persists pageSize to localStorage when pagination changes', async () => {
const { table } = useVrcxVueTable({
data: [],
columns: makeColumns('name', 'date'),
persistKey: 'test-page-size',
initialPagination: { pageIndex: 0, pageSize: 10 }
});
table.setPageSize(25);
await new Promise((r) => setTimeout(r, 300));
const stored = JSON.parse(
localStorage.getItem('vrcx:table:test-page-size')
);
expect(stored).toBeTruthy();
expect(stored.pageSize).toBe(25);
});
it('restores persisted pageSize on init, overriding initialPagination', () => {
localStorage.setItem(
'vrcx:table:test-restore-ps',
JSON.stringify({ pageSize: 50 })
);
const { pagination } = useVrcxVueTable({
data: [],
columns: makeColumns('name', 'date'),
persistKey: 'test-restore-ps',
initialPagination: { pageIndex: 0, pageSize: 10 }
});
expect(pagination.value.pageSize).toBe(50);
});
it('uses initialPagination.pageSize when no persisted data exists', () => {
const { pagination } = useVrcxVueTable({
data: [],
columns: makeColumns('name', 'date'),
persistKey: 'test-initial-ps',
initialPagination: { pageIndex: 0, pageSize: 25 }
});
expect(pagination.value.pageSize).toBe(25);
});
it('does not persist pageSize when persistPageSize is false', async () => {
const { table } = useVrcxVueTable({
data: [],
columns: makeColumns('name', 'date'),
persistKey: 'test-no-persist-ps',
persistPageSize: false,
initialPagination: { pageIndex: 0, pageSize: 10 }
});
table.setPageSize(50);
await new Promise((r) => setTimeout(r, 300));
const stored = JSON.parse(
localStorage.getItem('vrcx:table:test-no-persist-ps')
);
expect(stored?.pageSize).toBeUndefined();
});
});

View File

@@ -230,6 +230,7 @@ export function useVrcxVueTable(options) {
persistSorting = true,
persistColumnOrder = true,
persistColumnVisibility = true,
persistPageSize = true,
persistDebounceMs = 200,
tableOptions = {}
@@ -296,6 +297,18 @@ export function useVrcxVueTable(options) {
columnVisibility.value = persisted.columnVisibility;
}
if (
persisted &&
persistPageSize &&
typeof persisted.pageSize === 'number' &&
persisted.pageSize > 0
) {
pagination.value = {
...pagination.value,
pageSize: persisted.pageSize
};
}
const state = {};
const handlers = {};
const rowModels = {};
@@ -481,6 +494,17 @@ export function useVrcxVueTable(options) {
);
}
if (storageKey && persistPageSize) {
watch(
() => pagination.value.pageSize,
(val) => {
if (typeof val === 'number' && val > 0) {
persistWrite({ pageSize: val });
}
}
);
}
return {
table,
sorting,

View File

@@ -120,6 +120,9 @@
const hasDateFilter = computed(() => !!(feedTable.value.dateFrom || feedTable.value.dateTo));
const activeFilterCount = computed(() => (hasDateFilter.value ? 1 : 0));
/**
*
*/
function applyDateFilter() {
if (dateRange.value?.start) {
const s = dateRange.value.start;
@@ -137,6 +140,9 @@
feedTableLookup();
}
/**
*
*/
function clearDateFilter() {
dateRange.value = undefined;
feedTable.value.dateFrom = '';
@@ -155,10 +161,11 @@
});
const pageSizes = computed(() => appearanceSettingsStore.tablePageSizes);
const pageSize = computed(() =>
feedTable.value.pageSizeLinked ? appearanceSettingsStore.tablePageSize : feedTable.value.pageSize
);
/**
*
* @param row
*/
function getFeedRowId(row) {
if (row?.id != null) return `id:${row.id}`;
if (row?.rowId != null) return `row:${row.rowId}`;
@@ -185,7 +192,7 @@
initialExpanded: {},
initialPagination: {
pageIndex: 0,
pageSize: pageSize.value
pageSize: appearanceSettingsStore.tablePageSize
},
tableOptions: {
autoResetExpanded: false,
@@ -200,11 +207,11 @@
});
const handlePageSizeChange = (size) => {
if (feedTable.value.pageSizeLinked) {
appearanceSettingsStore.setTablePageSize(size);
} else {
feedTable.value.pageSize = size;
}
pagination.value = {
...pagination.value,
pageIndex: 0,
pageSize: size
};
};
const activeFilterSelection = computed(() => {
@@ -215,6 +222,10 @@
return filter;
});
/**
*
* @param value
*/
function handleFeedFilterChange(value) {
const selected = Array.isArray(value) ? value : [];
const wasAll = activeFilterSelection.value.includes('All');
@@ -230,16 +241,4 @@
}
feedTableLookup();
}
watch(pageSize, (size) => {
if (pagination.value.pageSize === size) {
return;
}
pagination.value = {
...pagination.value,
pageIndex: 0,
pageSize: size
};
table.setPageSize(size);
});
</script>

View File

@@ -171,7 +171,6 @@
const selectedFriends = ref(new Set());
const friendsListDisplayData = ref([]);
const pageSizes = computed(() => appearanceSettingsStore.tablePageSizes);
const pageSize = computed(() => appearanceSettingsStore.tablePageSize);
const defaultSorting = [{ id: 'friendNumber', desc: true }];
// const initialColumnPinning = {
@@ -212,7 +211,7 @@
initialSorting: defaultSorting,
initialPagination: {
pageIndex: 0,
pageSize: pageSize.value
pageSize: appearanceSettingsStore.tablePageSize
}
});
@@ -221,7 +220,11 @@
});
const handlePageSizeChange = (size) => {
appearanceSettingsStore.setTablePageSize(size);
pagination.value = {
...pagination.value,
pageIndex: 0,
pageSize: size
};
};
const handleRowClick = (row) => {
@@ -251,18 +254,6 @@
{ immediate: true }
);
watch(pageSize, (size) => {
if (pagination.value.pageSize === size) {
return;
}
pagination.value = {
...pagination.value,
pageIndex: 0,
pageSize: size
};
table.setPageSize(size);
});
const route = useRoute();
watch(
@@ -280,6 +271,9 @@
}
);
/**
*
*/
function friendsListSearchChange() {
friendsListLoading.value = true;
let query = '';
@@ -333,6 +327,10 @@
});
}
/**
*
* @param id
*/
function toggleFriendSelection(id) {
if (selectedFriends.value.has(id)) {
selectedFriends.value.delete(id);
@@ -341,12 +339,18 @@
}
}
/**
*
*/
function toggleFriendsListBulkUnfriendMode() {
if (!friendsListBulkUnfriendMode.value) {
selectedFriends.value.clear();
}
}
/**
*
*/
function showBulkUnfriendSelectionConfirm() {
const pending = friendsListDisplayData.value
.filter((item) => selectedFriends.value.has(item.id))
@@ -367,6 +371,9 @@
.catch(() => {});
}
/**
*
*/
async function bulkUnfriendSelection() {
if (!selectedFriends.value.size) return;
const selectedFriendsCount = selectedFriends.value.size;
@@ -384,6 +391,9 @@
selectedFriends.value.clear();
}
/**
*
*/
async function friendsListLoadUsers() {
const toFetch = Array.from(friends.value.values())
.filter((ctx) => ctx.ref && !ctx.ref.date_joined)
@@ -419,21 +429,35 @@
}
}
/**
*
*/
function cancelFriendsListLoad() {
friendsListLoading.value = false;
friendsListLoadDialogVisible.value = false;
}
/**
*
* @param val
*/
function selectFriendsListRow(val) {
if (!val) return;
if (!val.id) emit('lookup-user', val);
else showUserDialog(val.id);
}
/**
*
*/
function openChartsTab() {
router.push({ name: 'charts' });
}
/**
*
* @param value
*/
function handleFriendListFilterChange(value) {
friendsListSearchFilters.value = Array.isArray(value) ? value : [];
friendsListSearchChange();

View File

@@ -169,9 +169,6 @@
});
const pageSizes = computed(() => appearanceSettingsStore.tablePageSizes);
const pageSize = computed(() =>
friendLogTable.value.pageSizeLinked ? appearanceSettingsStore.tablePageSize : friendLogTable.value.pageSize
);
const { table, pagination } = useVrcxVueTable({
persistKey: 'friendLog',
@@ -183,7 +180,7 @@
initialSorting: [],
initialPagination: {
pageIndex: 0,
pageSize: pageSize.value
pageSize: appearanceSettingsStore.tablePageSize
},
tableOptions: {
autoResetPageIndex: false
@@ -195,22 +192,10 @@
});
const handlePageSizeChange = (size) => {
if (friendLogTable.value.pageSizeLinked) {
appearanceSettingsStore.setTablePageSize(size);
} else {
friendLogTable.value.pageSize = size;
}
};
watch(pageSize, (size) => {
if (pagination.value.pageSize === size) {
return;
}
pagination.value = {
...pagination.value,
pageIndex: 0,
pageSize: size
};
table.setPageSize(size);
});
};
</script>

View File

@@ -139,9 +139,6 @@
}
const pageSizes = computed(() => appearanceSettingsStore.tablePageSizes);
const pageSize = computed(() =>
gameLogTable.value.pageSizeLinked ? appearanceSettingsStore.tablePageSize : gameLogTable.value.pageSize
);
function getGameLogRowId(row) {
if (row?.rowId != null) return `row:${row.rowId}`;
@@ -165,7 +162,7 @@
initialSorting: [],
initialPagination: {
pageIndex: 0,
pageSize: pageSize.value
pageSize: appearanceSettingsStore.tablePageSize
},
tableOptions: {
autoResetPageIndex: false
@@ -179,22 +176,10 @@
});
const handlePageSizeChange = (size) => {
if (gameLogTable.value.pageSizeLinked) {
appearanceSettingsStore.setTablePageSize(size);
} else {
gameLogTable.value.pageSize = size;
}
};
watch(pageSize, (size) => {
if (pagination.value.pageSize === size) {
return;
}
pagination.value = {
...pagination.value,
pageIndex: 0,
pageSize: size
};
table.setPageSize(size);
});
};
</script>

View File

@@ -152,11 +152,6 @@
});
const pageSizes = computed(() => appearanceSettingsStore.tablePageSizes);
const pageSize = computed(() =>
playerModerationTable.value.pageSizeLinked
? appearanceSettingsStore.tablePageSize
: playerModerationTable.value.pageSize
);
const { table, pagination } = useVrcxVueTable({
persistKey: 'moderation',
@@ -168,7 +163,7 @@
initialSorting: [{ id: 'created', desc: true }],
initialPagination: {
pageIndex: 0,
pageSize: pageSize.value
pageSize: appearanceSettingsStore.tablePageSize
}
});
@@ -177,24 +172,12 @@
});
const handlePageSizeChange = (size) => {
if (playerModerationTable.value.pageSizeLinked) {
appearanceSettingsStore.setTablePageSize(size);
} else {
playerModerationTable.value.pageSize = size;
}
};
watch(pageSize, (size) => {
if (pagination.value.pageSize === size) {
return;
}
pagination.value = {
...pagination.value,
pageIndex: 0,
pageSize: size
};
table.setPageSize(size);
});
};
</script>
<style scoped>

View File

@@ -230,7 +230,6 @@
const { currentUser } = storeToRefs(useUserStore());
const pageSizes = computed(() => appearanceSettingsStore.tablePageSizes);
const pageSize = computed(() => appearanceSettingsStore.tablePageSize);
const containerRef = ref(null);
const searchText = ref('');
@@ -595,20 +594,18 @@
initialSorting: [{ id: 'updated_at', desc: true }],
initialPagination: {
pageIndex: 0,
pageSize: pageSize.value
pageSize: appearanceSettingsStore.tablePageSize
}
});
const handlePageSizeChange = (size) => {
appearanceSettingsStore.setTablePageSize(size);
pagination.value = {
...pagination.value,
pageIndex: 0,
pageSize: size
};
};
watch(pageSize, (size) => {
if (pagination.value.pageSize === size) return;
pagination.value = { ...pagination.value, pageIndex: 0, pageSize: size };
table.setPageSize(size);
});
/**
*
*/

View File

@@ -222,11 +222,6 @@
});
const pageSizes = computed(() => appearanceSettingsStore.tablePageSizes);
const pageSize = computed(() =>
notificationTable.value.pageSizeLinked
? appearanceSettingsStore.tablePageSize
: notificationTable.value.pageSize
);
const { table, pagination } = useVrcxVueTable({
persistKey: 'notifications',
@@ -238,7 +233,7 @@
initialSorting: [{ id: 'created_at', desc: true }],
initialPagination: {
pageIndex: 0,
pageSize: pageSize.value
pageSize: appearanceSettingsStore.tablePageSize
},
tableOptions: {
autoResetPageIndex: false
@@ -252,24 +247,12 @@
});
const handlePageSizeChange = (size) => {
if (notificationTable.value.pageSizeLinked) {
appearanceSettingsStore.setTablePageSize(size);
} else {
notificationTable.value.pageSize = size;
}
};
watch(pageSize, (size) => {
if (pagination.value.pageSize === size) {
return;
}
pagination.value = {
...pagination.value,
pageIndex: 0,
pageSize: size
};
table.setPageSize(size);
});
};
const sendInviteResponseDialog = ref({
messageSlot: {},