mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-24 01:03:50 +02:00
feat: add feed range date search
This commit is contained in:
@@ -5,7 +5,9 @@
|
|||||||
"no_data": "No data",
|
"no_data": "No data",
|
||||||
"no_matching_records": "No matching records",
|
"no_matching_records": "No matching records",
|
||||||
"actions": {
|
"actions": {
|
||||||
"open": "Open"
|
"open": "Open",
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"clear": "Clear"
|
||||||
},
|
},
|
||||||
"time_units": {
|
"time_units": {
|
||||||
"y": "y",
|
"y": "y",
|
||||||
|
|||||||
@@ -87,7 +87,9 @@ const feed = {
|
|||||||
search,
|
search,
|
||||||
filters,
|
filters,
|
||||||
vipList,
|
vipList,
|
||||||
maxEntries = dbVars.searchTableSize
|
maxEntries = dbVars.searchTableSize,
|
||||||
|
dateFrom = '',
|
||||||
|
dateTo = ''
|
||||||
) {
|
) {
|
||||||
if (search.startsWith('wrld_') || search.startsWith('grp_')) {
|
if (search.startsWith('wrld_') || search.startsWith('grp_')) {
|
||||||
return this.getFeedByInstanceId(search, filters, vipList);
|
return this.getFeedByInstanceId(search, filters, vipList);
|
||||||
@@ -103,6 +105,13 @@ const feed = {
|
|||||||
});
|
});
|
||||||
vipQuery = `AND user_id IN (${vipPlaceholders.join(', ')})`;
|
vipQuery = `AND user_id IN (${vipPlaceholders.join(', ')})`;
|
||||||
}
|
}
|
||||||
|
let dateQuery = '';
|
||||||
|
if (dateFrom) {
|
||||||
|
dateQuery += 'AND created_at >= @dateFrom ';
|
||||||
|
}
|
||||||
|
if (dateTo) {
|
||||||
|
dateQuery += 'AND created_at <= @dateTo ';
|
||||||
|
}
|
||||||
let gps = true;
|
let gps = true;
|
||||||
let status = true;
|
let status = true;
|
||||||
let bio = true;
|
let bio = true;
|
||||||
@@ -169,17 +178,17 @@ const feed = {
|
|||||||
].join(', ');
|
].join(', ');
|
||||||
if (gps) {
|
if (gps) {
|
||||||
selects.push(
|
selects.push(
|
||||||
`SELECT * FROM (SELECT id, created_at, user_id, display_name, 'GPS' AS type, location, world_name, previous_location, time, group_name, NULL AS status, NULL AS status_description, NULL AS previous_status, NULL AS previous_status_description, NULL AS bio, NULL AS previous_bio, NULL AS owner_id, NULL AS avatar_name, NULL AS current_avatar_image_url, NULL AS current_avatar_thumbnail_image_url, NULL AS previous_current_avatar_image_url, NULL AS previous_current_avatar_thumbnail_image_url FROM ${dbVars.userPrefix}_feed_gps WHERE (display_name LIKE @searchLike OR world_name LIKE @searchLike OR group_name LIKE @searchLike) ${vipQuery} ORDER BY created_at DESC, id DESC LIMIT @perTable)`
|
`SELECT * FROM (SELECT id, created_at, user_id, display_name, 'GPS' AS type, location, world_name, previous_location, time, group_name, NULL AS status, NULL AS status_description, NULL AS previous_status, NULL AS previous_status_description, NULL AS bio, NULL AS previous_bio, NULL AS owner_id, NULL AS avatar_name, NULL AS current_avatar_image_url, NULL AS current_avatar_thumbnail_image_url, NULL AS previous_current_avatar_image_url, NULL AS previous_current_avatar_thumbnail_image_url FROM ${dbVars.userPrefix}_feed_gps WHERE (display_name LIKE @searchLike OR world_name LIKE @searchLike OR group_name LIKE @searchLike) ${dateQuery} ${vipQuery} ORDER BY created_at DESC, id DESC LIMIT @perTable)`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (status) {
|
if (status) {
|
||||||
selects.push(
|
selects.push(
|
||||||
`SELECT * FROM (SELECT id, created_at, user_id, display_name, 'Status' AS type, NULL AS location, NULL AS world_name, NULL AS previous_location, NULL AS time, NULL AS group_name, status, status_description, previous_status, previous_status_description, NULL AS bio, NULL AS previous_bio, NULL AS owner_id, NULL AS avatar_name, NULL AS current_avatar_image_url, NULL AS current_avatar_thumbnail_image_url, NULL AS previous_current_avatar_image_url, NULL AS previous_current_avatar_thumbnail_image_url FROM ${dbVars.userPrefix}_feed_status WHERE (display_name LIKE @searchLike OR status LIKE @searchLike OR status_description LIKE @searchLike) ${vipQuery} ORDER BY created_at DESC, id DESC LIMIT @perTable)`
|
`SELECT * FROM (SELECT id, created_at, user_id, display_name, 'Status' AS type, NULL AS location, NULL AS world_name, NULL AS previous_location, NULL AS time, NULL AS group_name, status, status_description, previous_status, previous_status_description, NULL AS bio, NULL AS previous_bio, NULL AS owner_id, NULL AS avatar_name, NULL AS current_avatar_image_url, NULL AS current_avatar_thumbnail_image_url, NULL AS previous_current_avatar_image_url, NULL AS previous_current_avatar_thumbnail_image_url FROM ${dbVars.userPrefix}_feed_status WHERE (display_name LIKE @searchLike OR status LIKE @searchLike OR status_description LIKE @searchLike) ${dateQuery} ${vipQuery} ORDER BY created_at DESC, id DESC LIMIT @perTable)`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (bio) {
|
if (bio) {
|
||||||
selects.push(
|
selects.push(
|
||||||
`SELECT * FROM (SELECT id, created_at, user_id, display_name, 'Bio' AS type, NULL AS location, NULL AS world_name, NULL AS previous_location, NULL AS time, NULL AS group_name, NULL AS status, NULL AS status_description, NULL AS previous_status, NULL AS previous_status_description, bio, previous_bio, NULL AS owner_id, NULL AS avatar_name, NULL AS current_avatar_image_url, NULL AS current_avatar_thumbnail_image_url, NULL AS previous_current_avatar_image_url, NULL AS previous_current_avatar_thumbnail_image_url FROM ${dbVars.userPrefix}_feed_bio WHERE (display_name LIKE @searchLike OR bio LIKE @searchLike) ${vipQuery} ORDER BY created_at DESC, id DESC LIMIT @perTable)`
|
`SELECT * FROM (SELECT id, created_at, user_id, display_name, 'Bio' AS type, NULL AS location, NULL AS world_name, NULL AS previous_location, NULL AS time, NULL AS group_name, NULL AS status, NULL AS status_description, NULL AS previous_status, NULL AS previous_status_description, bio, previous_bio, NULL AS owner_id, NULL AS avatar_name, NULL AS current_avatar_image_url, NULL AS current_avatar_thumbnail_image_url, NULL AS previous_current_avatar_image_url, NULL AS previous_current_avatar_thumbnail_image_url FROM ${dbVars.userPrefix}_feed_bio WHERE (display_name LIKE @searchLike OR bio LIKE @searchLike) ${dateQuery} ${vipQuery} ORDER BY created_at DESC, id DESC LIMIT @perTable)`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (avatar) {
|
if (avatar) {
|
||||||
@@ -190,7 +199,7 @@ const feed = {
|
|||||||
avatarQuery = 'AND user_id != owner_id';
|
avatarQuery = 'AND user_id != owner_id';
|
||||||
}
|
}
|
||||||
selects.push(
|
selects.push(
|
||||||
`SELECT * FROM (SELECT id, created_at, user_id, display_name, 'Avatar' AS type, NULL AS location, NULL AS world_name, NULL AS previous_location, NULL AS time, NULL AS group_name, NULL AS status, NULL AS status_description, NULL AS previous_status, NULL AS previous_status_description, NULL AS bio, NULL AS previous_bio, owner_id, avatar_name, current_avatar_image_url, current_avatar_thumbnail_image_url, previous_current_avatar_image_url, previous_current_avatar_thumbnail_image_url FROM ${dbVars.userPrefix}_feed_avatar WHERE (display_name LIKE @searchLike OR avatar_name LIKE @searchLike) ${avatarQuery} ${vipQuery} ORDER BY created_at DESC, id DESC LIMIT @perTable)`
|
`SELECT * FROM (SELECT id, created_at, user_id, display_name, 'Avatar' AS type, NULL AS location, NULL AS world_name, NULL AS previous_location, NULL AS time, NULL AS group_name, NULL AS status, NULL AS status_description, NULL AS previous_status, NULL AS previous_status_description, NULL AS bio, NULL AS previous_bio, owner_id, avatar_name, current_avatar_image_url, current_avatar_thumbnail_image_url, previous_current_avatar_image_url, previous_current_avatar_thumbnail_image_url FROM ${dbVars.userPrefix}_feed_avatar WHERE (display_name LIKE @searchLike OR avatar_name LIKE @searchLike) ${avatarQuery} ${dateQuery} ${vipQuery} ORDER BY created_at DESC, id DESC LIMIT @perTable)`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (online || offline) {
|
if (online || offline) {
|
||||||
@@ -203,7 +212,7 @@ const feed = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
selects.push(
|
selects.push(
|
||||||
`SELECT * FROM (SELECT id, created_at, user_id, display_name, type, location, world_name, NULL AS previous_location, time, group_name, NULL AS status, NULL AS status_description, NULL AS previous_status, NULL AS previous_status_description, NULL AS bio, NULL AS previous_bio, NULL AS owner_id, NULL AS avatar_name, NULL AS current_avatar_image_url, NULL AS current_avatar_thumbnail_image_url, NULL AS previous_current_avatar_image_url, NULL AS previous_current_avatar_thumbnail_image_url FROM ${dbVars.userPrefix}_feed_online_offline WHERE (display_name LIKE @searchLike OR world_name LIKE @searchLike OR group_name LIKE @searchLike) ${query} ${vipQuery} ORDER BY created_at DESC, id DESC LIMIT @perTable)`
|
`SELECT * FROM (SELECT id, created_at, user_id, display_name, type, location, world_name, NULL AS previous_location, time, group_name, NULL AS status, NULL AS status_description, NULL AS previous_status, NULL AS previous_status_description, NULL AS bio, NULL AS previous_bio, NULL AS owner_id, NULL AS avatar_name, NULL AS current_avatar_image_url, NULL AS current_avatar_thumbnail_image_url, NULL AS previous_current_avatar_image_url, NULL AS previous_current_avatar_thumbnail_image_url FROM ${dbVars.userPrefix}_feed_online_offline WHERE (display_name LIKE @searchLike OR world_name LIKE @searchLike OR group_name LIKE @searchLike) ${query} ${dateQuery} ${vipQuery} ORDER BY created_at DESC, id DESC LIMIT @perTable)`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (selects.length === 0) {
|
if (selects.length === 0) {
|
||||||
@@ -216,6 +225,12 @@ const feed = {
|
|||||||
'@perTable': maxEntries,
|
'@perTable': maxEntries,
|
||||||
...vipArgs
|
...vipArgs
|
||||||
};
|
};
|
||||||
|
if (dateFrom) {
|
||||||
|
args['@dateFrom'] = dateFrom;
|
||||||
|
}
|
||||||
|
if (dateTo) {
|
||||||
|
args['@dateTo'] = dateTo;
|
||||||
|
}
|
||||||
await sqliteService.execute(
|
await sqliteService.execute(
|
||||||
(dbRow) => {
|
(dbRow) => {
|
||||||
const type = dbRow[4];
|
const type = dbRow[4];
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ export const useFeedStore = defineStore('Feed', () => {
|
|||||||
const feedTableData = shallowRef([]);
|
const feedTableData = shallowRef([]);
|
||||||
const feedTable = ref({
|
const feedTable = ref({
|
||||||
search: '',
|
search: '',
|
||||||
|
dateFrom: '',
|
||||||
|
dateTo: '',
|
||||||
vip: false,
|
vip: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
filter: [],
|
filter: [],
|
||||||
@@ -146,17 +148,21 @@ export const useFeedStore = defineStore('Feed', () => {
|
|||||||
vipList = Array.from(friendStore.localFavoriteFriends.values());
|
vipList = Array.from(friendStore.localFavoriteFriends.values());
|
||||||
}
|
}
|
||||||
const search = feedTable.value.search.trim();
|
const search = feedTable.value.search.trim();
|
||||||
const rows = search
|
const { dateFrom, dateTo } = feedTable.value;
|
||||||
? await database.searchFeedDatabase(
|
const rows =
|
||||||
search,
|
search || dateFrom || dateTo
|
||||||
feedTable.value.filter,
|
? await database.searchFeedDatabase(
|
||||||
vipList,
|
search,
|
||||||
vrcxStore.searchLimit
|
feedTable.value.filter,
|
||||||
)
|
vipList,
|
||||||
: await database.lookupFeedDatabase(
|
vrcxStore.searchLimit,
|
||||||
feedTable.value.filter,
|
dateFrom,
|
||||||
vipList
|
dateTo
|
||||||
);
|
)
|
||||||
|
: await database.lookupFeedDatabase(
|
||||||
|
feedTable.value.filter,
|
||||||
|
vipList
|
||||||
|
);
|
||||||
feedTableData.value = [];
|
feedTableData.value = [];
|
||||||
feedTableData.value = [...feedTableData.value, ...rows];
|
feedTableData.value = [...feedTableData.value, ...rows];
|
||||||
} finally {
|
} finally {
|
||||||
@@ -182,6 +188,18 @@ export const useFeedStore = defineStore('Feed', () => {
|
|||||||
if (!feedSearch(feed)) {
|
if (!feedSearch(feed)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
feedTable.value.dateFrom &&
|
||||||
|
feed.created_at < feedTable.value.dateFrom
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
feedTable.value.dateTo &&
|
||||||
|
feed.created_at > feedTable.value.dateTo
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
feedTableData.value = [feed, ...feedTableData.value];
|
feedTableData.value = [feed, ...feedTableData.value];
|
||||||
sweepFeed();
|
sweepFeed();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,32 @@
|
|||||||
style="flex: 0.4; margin-left: 10px"
|
style="flex: 0.4; margin-left: 10px"
|
||||||
@keyup.enter="feedTableLookup"
|
@keyup.enter="feedTableLookup"
|
||||||
@change="feedTableLookup" />
|
@change="feedTableLookup" />
|
||||||
|
<Popover v-model:open="popoverOpen">
|
||||||
|
<PopoverTrigger as-child>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon-sm"
|
||||||
|
class="ml-2 text-muted-foreground"
|
||||||
|
:class="{ 'text-accent-foreground': hasDateFilter }">
|
||||||
|
<Funnel />
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent class="w-auto" side="bottom" align="end">
|
||||||
|
<RangeCalendar
|
||||||
|
v-model="dateRange"
|
||||||
|
:locale="locale"
|
||||||
|
:max-value="todayDate"
|
||||||
|
:number-of-months="2" />
|
||||||
|
<div class="flex justify-end gap-2 mt-3">
|
||||||
|
<Button variant="outline" size="sm" @click="clearDateFilter">
|
||||||
|
{{ t('common.actions.clear') }}
|
||||||
|
</Button>
|
||||||
|
<Button size="sm" @click="applyDateFilter">
|
||||||
|
{{ t('common.actions.confirm') }}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</DataTableLayout>
|
</DataTableLayout>
|
||||||
@@ -43,13 +69,20 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
|
import { getLocalTimeZone, today } from '@internationalized/date';
|
||||||
|
import { Funnel } from 'lucide-vue-next';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
|
import { Popover, PopoverContent, PopoverTrigger } from '../../components/ui/popover';
|
||||||
import { useAppearanceSettingsStore, useFeedStore, useVrcxStore } from '../../stores';
|
import { useAppearanceSettingsStore, useFeedStore, useVrcxStore } from '../../stores';
|
||||||
import { ToggleGroup, ToggleGroupItem } from '../../components/ui/toggle-group';
|
import { ToggleGroup, ToggleGroupItem } from '../../components/ui/toggle-group';
|
||||||
|
import { Button } from '../../components/ui/button';
|
||||||
import { DataTableLayout } from '../../components/ui/data-table';
|
import { DataTableLayout } from '../../components/ui/data-table';
|
||||||
import { InputGroupField } from '../../components/ui/input-group';
|
import { InputGroupField } from '../../components/ui/input-group';
|
||||||
|
import { RangeCalendar } from '../../components/ui/range-calendar';
|
||||||
import { Switch } from '../../components/ui/switch';
|
import { Switch } from '../../components/ui/switch';
|
||||||
import { columns as baseColumns } from './columns.jsx';
|
import { columns as baseColumns } from './columns.jsx';
|
||||||
import { useDataTableScrollHeight } from '../../composables/useDataTableScrollHeight';
|
import { useDataTableScrollHeight } from '../../composables/useDataTableScrollHeight';
|
||||||
@@ -60,9 +93,39 @@
|
|||||||
const appearanceSettingsStore = useAppearanceSettingsStore();
|
const appearanceSettingsStore = useAppearanceSettingsStore();
|
||||||
const vrcxStore = useVrcxStore();
|
const vrcxStore = useVrcxStore();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t, locale } = useI18n();
|
||||||
const feedFilterTypes = ['GPS', 'Online', 'Offline', 'Status', 'Avatar', 'Bio'];
|
const feedFilterTypes = ['GPS', 'Online', 'Offline', 'Status', 'Avatar', 'Bio'];
|
||||||
|
|
||||||
|
const popoverOpen = ref(false);
|
||||||
|
const todayDate = today(getLocalTimeZone());
|
||||||
|
const dateRange = ref(undefined);
|
||||||
|
const hasDateFilter = computed(() => !!(feedTable.value.dateFrom || feedTable.value.dateTo));
|
||||||
|
|
||||||
|
function applyDateFilter() {
|
||||||
|
if (dateRange.value?.start) {
|
||||||
|
const s = dateRange.value.start;
|
||||||
|
feedTable.value.dateFrom = dayjs(`${s.year}-${s.month}-${s.day}`).startOf('day').toISOString();
|
||||||
|
} else {
|
||||||
|
feedTable.value.dateFrom = '';
|
||||||
|
}
|
||||||
|
if (dateRange.value?.end) {
|
||||||
|
const e = dateRange.value.end;
|
||||||
|
feedTable.value.dateTo = dayjs(`${e.year}-${e.month}-${e.day}`).endOf('day').toISOString();
|
||||||
|
} else {
|
||||||
|
feedTable.value.dateTo = '';
|
||||||
|
}
|
||||||
|
popoverOpen.value = false;
|
||||||
|
feedTableLookup();
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearDateFilter() {
|
||||||
|
dateRange.value = undefined;
|
||||||
|
feedTable.value.dateFrom = '';
|
||||||
|
feedTable.value.dateTo = '';
|
||||||
|
popoverOpen.value = false;
|
||||||
|
feedTableLookup();
|
||||||
|
}
|
||||||
|
|
||||||
const feedRef = ref(null);
|
const feedRef = ref(null);
|
||||||
|
|
||||||
// TODO: simplify
|
// TODO: simplify
|
||||||
|
|||||||
Reference in New Issue
Block a user