mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-23 08:43:50 +02:00
305 lines
10 KiB
Vue
305 lines
10 KiB
Vue
<template>
|
|
<div>
|
|
<DialogHeader>
|
|
<DialogTitle>{{ t('dialog.previous_instances.header') }}</DialogTitle>
|
|
</DialogHeader>
|
|
|
|
<DataTableLayout
|
|
class="min-w-0 w-full"
|
|
:table="table"
|
|
:loading="loading"
|
|
:table-style="tableStyle"
|
|
:page-sizes="pageSizes"
|
|
:total-items="totalItems"
|
|
:on-page-size-change="handlePageSizeChange"
|
|
:on-page-change="handlePageChange"
|
|
:on-sort-change="handleSortChange">
|
|
<template #toolbar>
|
|
<div style="display: flex; align-items: center; justify-content: space-between">
|
|
<span style="font-size: 14px" v-text="headerText"></span>
|
|
<InputGroupField
|
|
v-model="search"
|
|
:placeholder="t('dialog.previous_instances.search_placeholder')"
|
|
clearable
|
|
class="w-1/3"
|
|
style="display: block" />
|
|
</div>
|
|
</template>
|
|
</DataTableLayout>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
defineOptions({ name: 'PreviousInstancesListDialog' });
|
|
|
|
import { computed, ref, watch } from 'vue';
|
|
import { DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
|
import { InputGroupField } from '@/components/ui/input-group';
|
|
import { storeToRefs } from 'pinia';
|
|
import { useI18n } from 'vue-i18n';
|
|
|
|
import {
|
|
useInstanceStore,
|
|
useLaunchStore,
|
|
useModalStore,
|
|
useSearchStore,
|
|
useUiStore,
|
|
useUserStore,
|
|
useVrcxStore
|
|
} from '../../../stores';
|
|
import {
|
|
compareByCreatedAt,
|
|
localeIncludes,
|
|
parseLocation,
|
|
removeFromArray,
|
|
timeToText
|
|
} from '../../../shared/utils';
|
|
import { DataTableLayout } from '../../ui/data-table';
|
|
import { createPreviousInstancesColumns } from './previousInstancesColumns.jsx';
|
|
import { database } from '../../../service/database';
|
|
import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
|
|
|
|
const props = defineProps({
|
|
variant: {
|
|
type: String,
|
|
required: true,
|
|
validator: (value) => ['user', 'world', 'group'].includes(value)
|
|
}
|
|
});
|
|
|
|
const instanceStore = useInstanceStore();
|
|
const { showPreviousInstancesInfoDialog } = instanceStore;
|
|
const { previousInstancesListState, previousInstancesListDialog } = storeToRefs(instanceStore);
|
|
const { shiftHeld } = storeToRefs(useUiStore());
|
|
const { stringComparer } = storeToRefs(useSearchStore());
|
|
const { currentUser } = storeToRefs(useUserStore());
|
|
const { showLaunchDialog } = useLaunchStore();
|
|
const modalStore = useModalStore();
|
|
const vrcxStore = useVrcxStore();
|
|
const { t } = useI18n();
|
|
|
|
const dialogState = computed(() => {
|
|
return previousInstancesListDialog.value;
|
|
});
|
|
|
|
const getListState = () => {
|
|
const state = previousInstancesListState.value[props.variant];
|
|
if (state) {
|
|
return state;
|
|
}
|
|
previousInstancesListState.value[props.variant] = {
|
|
sortBy: [{ id: 'created_at', desc: true }],
|
|
search: '',
|
|
pageSize: 10,
|
|
pageIndex: 0
|
|
};
|
|
return previousInstancesListState.value[props.variant];
|
|
};
|
|
|
|
const loading = ref(false);
|
|
const rawRows = ref([]);
|
|
const pageSizes = [10, 25, 50, 100];
|
|
const pageSize = computed({
|
|
get: () => getListState().pageSize,
|
|
set: (value) => {
|
|
getListState().pageSize = value;
|
|
}
|
|
});
|
|
const tableStyle = { maxHeight: '100%' };
|
|
const search = computed({
|
|
get: () => getListState().search,
|
|
set: (value) => {
|
|
getListState().search = value;
|
|
}
|
|
});
|
|
const sortBy = computed({
|
|
get: () => getListState().sortBy,
|
|
set: (value) => {
|
|
getListState().sortBy = value;
|
|
}
|
|
});
|
|
|
|
const headerText = computed(() => {
|
|
const state = dialogState.value;
|
|
if (props.variant === 'user') return state?.userRef?.displayName ?? '';
|
|
if (props.variant === 'world') return state?.worldRef?.name ?? '';
|
|
return state?.groupRef?.name ?? '';
|
|
});
|
|
|
|
const currentId = computed(() => {
|
|
if (props.variant === 'user') return dialogState.value?.userRef?.id ?? '';
|
|
if (props.variant === 'world') return dialogState.value?.worldRef?.id ?? '';
|
|
return dialogState.value?.groupRef?.id ?? '';
|
|
});
|
|
|
|
const persistKey = computed(() => {
|
|
if (props.variant === 'user') return 'previousInstancesUserDialog';
|
|
if (props.variant === 'world') return 'previousInstancesWorldDialog';
|
|
return 'previousInstancesGroupDialog';
|
|
});
|
|
|
|
const pageIndex = computed({
|
|
get: () => getListState().pageIndex,
|
|
set: (value) => {
|
|
getListState().pageIndex = value;
|
|
}
|
|
});
|
|
|
|
const displayRows = computed(() => {
|
|
const q = String(search.value ?? '')
|
|
.trim()
|
|
.toLowerCase();
|
|
const rows = Array.isArray(rawRows.value) ? rawRows.value : [];
|
|
if (!q) return rows;
|
|
return rows.filter((row) => {
|
|
return (
|
|
localeIncludes(row?.worldName ?? '', q, stringComparer.value) ||
|
|
localeIncludes(row?.groupName ?? '', q, stringComparer.value) ||
|
|
localeIncludes(row?.location ?? '', q, stringComparer.value)
|
|
);
|
|
});
|
|
});
|
|
|
|
function deleteGameLogInstance(row) {
|
|
if (props.variant === 'user') {
|
|
database.deleteGameLogInstance({
|
|
id: previousInstancesListDialog.value.userRef.id,
|
|
displayName: previousInstancesListDialog.value.userRef.displayName,
|
|
location: row.location,
|
|
events: row.events
|
|
});
|
|
} else {
|
|
database.deleteGameLogInstanceByInstanceId({ location: row.location });
|
|
}
|
|
removeFromArray(rawRows.value, row);
|
|
}
|
|
|
|
function deleteGameLogInstancePrompt(row) {
|
|
const description =
|
|
props.variant === 'user'
|
|
? 'Continue? Delete User From GameLog Instance'
|
|
: 'Continue? Delete GameLog Instance';
|
|
modalStore
|
|
.confirm({
|
|
description,
|
|
title: 'Confirm'
|
|
})
|
|
.then(({ ok }) => {
|
|
if (!ok) return;
|
|
deleteGameLogInstance(row);
|
|
})
|
|
.catch(() => {});
|
|
}
|
|
|
|
const handleShowInfo = (location) => {
|
|
const instanceId = location ?? '';
|
|
showPreviousInstancesInfoDialog(instanceId);
|
|
};
|
|
|
|
const columns = computed(() =>
|
|
createPreviousInstancesColumns(props.variant, {
|
|
shiftHeld,
|
|
currentUserId: currentUser.value?.id,
|
|
forceUpdateKey: previousInstancesListDialog.value?.forceUpdate,
|
|
onLaunch: showLaunchDialog,
|
|
onShowInfo: handleShowInfo,
|
|
onDelete: deleteGameLogInstance,
|
|
onDeletePrompt: deleteGameLogInstancePrompt
|
|
})
|
|
);
|
|
|
|
const { table } = useVrcxVueTable({
|
|
persistKey: persistKey.value,
|
|
get data() {
|
|
return displayRows.value;
|
|
},
|
|
columns: columns.value,
|
|
getRowId: (row) => `${row?.location ?? ''}:${row?.created_at ?? ''}`,
|
|
initialSorting: sortBy.value,
|
|
initialPagination: {
|
|
pageIndex: pageIndex.value,
|
|
pageSize: pageSize.value
|
|
},
|
|
tableOptions: {
|
|
autoResetPageIndex: false
|
|
}
|
|
});
|
|
|
|
watch(
|
|
columns,
|
|
(next) => {
|
|
table.setOptions((prev) => ({
|
|
...prev,
|
|
columns: /** @type {any} */ (next)
|
|
}));
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
|
|
const totalItems = computed(() => {
|
|
const length = table.getFilteredRowModel().rows.length;
|
|
const max = vrcxStore.maxTableSize;
|
|
return length > max ? max : length;
|
|
});
|
|
|
|
const handlePageSizeChange = (size) => {
|
|
pageSize.value = size;
|
|
};
|
|
|
|
const handlePageChange = (page) => {
|
|
pageIndex.value = Math.max(0, page - 1);
|
|
};
|
|
|
|
const handleSortChange = (sorting) => {
|
|
sortBy.value = sorting;
|
|
};
|
|
|
|
const refreshTable = async () => {
|
|
loading.value = true;
|
|
const array = [];
|
|
try {
|
|
const D = previousInstancesListDialog.value;
|
|
if (currentId.value !== D.lastId) {
|
|
table.setPageIndex(0);
|
|
D.lastId = currentId.value;
|
|
}
|
|
if (props.variant === 'user') {
|
|
const data = await database.getPreviousInstancesByUserId(D.userRef);
|
|
for (const item of data.values()) {
|
|
item.$location = parseLocation(item.location);
|
|
item.timer = item.time > 0 ? timeToText(item.time) : '';
|
|
array.push(item);
|
|
}
|
|
} else if (props.variant === 'world') {
|
|
const data = await database.getPreviousInstancesByWorldId(D.worldRef);
|
|
for (const ref of data.values()) {
|
|
ref.$location = parseLocation(ref.location);
|
|
ref.timer = ref.time > 0 ? timeToText(ref.time) : '';
|
|
array.push(ref);
|
|
}
|
|
} else {
|
|
const data = await database.getPreviousInstancesByGroupId(D.groupRef.id);
|
|
for (const ref of data.values()) {
|
|
ref.$location = parseLocation(ref.location);
|
|
ref.timer = ref.time > 0 ? timeToText(ref.time) : '';
|
|
array.push(ref);
|
|
}
|
|
}
|
|
array.sort(compareByCreatedAt);
|
|
rawRows.value = array;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
|
|
watch(
|
|
() => dialogState.value?.visible,
|
|
(visible) => {
|
|
if (visible) {
|
|
refreshTable();
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
</script>
|