Add basic event search page

This commit is contained in:
ssmucny 2023-04-23 13:37:42 -04:00
parent 4df0407a28
commit a967c0268e
5 changed files with 60 additions and 7 deletions

View File

@ -113,6 +113,7 @@ import { ApMentionService } from './activitypub/models/ApMentionService.js';
import { ApNoteService } from './activitypub/models/ApNoteService.js'; import { ApNoteService } from './activitypub/models/ApNoteService.js';
import { ApPersonService } from './activitypub/models/ApPersonService.js'; import { ApPersonService } from './activitypub/models/ApPersonService.js';
import { ApQuestionService } from './activitypub/models/ApQuestionService.js'; import { ApQuestionService } from './activitypub/models/ApQuestionService.js';
import { ApEventService } from './activitypub/models/ApEventService.js';
import { QueueModule } from './QueueModule.js'; import { QueueModule } from './QueueModule.js';
import { QueueService } from './QueueService.js'; import { QueueService } from './QueueService.js';
import { LoggerService } from './LoggerService.js'; import { LoggerService } from './LoggerService.js';
@ -236,6 +237,7 @@ const $ApMentionService: Provider = { provide: 'ApMentionService', useExisting:
const $ApNoteService: Provider = { provide: 'ApNoteService', useExisting: ApNoteService }; const $ApNoteService: Provider = { provide: 'ApNoteService', useExisting: ApNoteService };
const $ApPersonService: Provider = { provide: 'ApPersonService', useExisting: ApPersonService }; const $ApPersonService: Provider = { provide: 'ApPersonService', useExisting: ApPersonService };
const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting: ApQuestionService }; const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting: ApQuestionService };
const $ApEventService: Provider = { provide: 'ApEventService', useExisting: ApEventService };
//#endregion //#endregion
@Module({ @Module({
@ -358,6 +360,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
ApNoteService, ApNoteService,
ApPersonService, ApPersonService,
ApQuestionService, ApQuestionService,
ApEventService,
QueueService, QueueService,
//#region 文字列ベースでのinjection用(循環参照対応のため) //#region 文字列ベースでのinjection用(循環参照対応のため)
@ -476,6 +479,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$ApNoteService, $ApNoteService,
$ApPersonService, $ApPersonService,
$ApQuestionService, $ApQuestionService,
$ApEventService,
//#endregion //#endregion
], ],
exports: [ exports: [
@ -594,6 +598,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
ApNoteService, ApNoteService,
ApPersonService, ApPersonService,
ApQuestionService, ApQuestionService,
ApEventService,
QueueService, QueueService,
//#region 文字列ベースでのinjection用(循環参照対応のため) //#region 文字列ベースでのinjection用(循環参照対応のため)
@ -711,6 +716,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$ApNoteService, $ApNoteService,
$ApPersonService, $ApPersonService,
$ApQuestionService, $ApQuestionService,
$ApEventService,
//#endregion //#endregion
], ],
}) })

View File

@ -33,6 +33,11 @@ export default defineComponent({
required: false, required: false,
default: false, default: false,
}, },
getDate: {
type: Function, // Note => date string
required: false,
default: undefined,
}
}, },
setup(props, { slots, expose }) { setup(props, { slots, expose }) {
@ -58,7 +63,7 @@ export default defineComponent({
if ( if (
i !== props.items.length - 1 && i !== props.items.length - 1 &&
new Date(item.createdAt).getDate() !== new Date(props.items[i + 1].createdAt).getDate() new Date(getDateKey(item)).getDate() !== new Date(getDateKey(props.items[i + 1])).getDate()
) { ) {
const separator = h('div', { const separator = h('div', {
class: $style['separator'], class: $style['separator'],
@ -72,12 +77,12 @@ export default defineComponent({
h('i', { h('i', {
class: `ti ti-chevron-up ${$style['date-1-icon']}`, class: `ti ti-chevron-up ${$style['date-1-icon']}`,
}), }),
getDateText(item.createdAt), getDateText(getDateKey(item)),
]), ]),
h('span', { h('span', {
class: $style['date-2'], class: $style['date-2'],
}, [ }, [
getDateText(props.items[i + 1].createdAt), getDateText(getDateKey(props.items[i + 1])),
h('i', { h('i', {
class: `ti ti-chevron-down ${$style['date-2-icon']}`, class: `ti ti-chevron-down ${$style['date-2-icon']}`,
}), }),
@ -97,6 +102,8 @@ export default defineComponent({
} }
}); });
const getDateKey = (item: MisskeyEntity): string => props.getDate ? props.getDate(item) : item.createdAt;
const renderChildren = () => { const renderChildren = () => {
const children = renderChildrenImpl(); const children = renderChildrenImpl();
if (isDebuggerEnabled(6864)) { if (isDebuggerEnabled(6864)) {

View File

@ -13,6 +13,7 @@
ref="notes" ref="notes"
v-slot="{ item: note }" v-slot="{ item: note }"
:items="notes" :items="notes"
:get-date="getDate"
:direction="pagination.reversed ? 'up' : 'down'" :direction="pagination.reversed ? 'up' : 'down'"
:reversed="pagination.reversed" :reversed="pagination.reversed"
:no-gap="noGap" :no-gap="noGap"
@ -36,6 +37,7 @@ import { i18n } from '@/i18n';
const props = defineProps<{ const props = defineProps<{
pagination: Paging; pagination: Paging;
noGap?: boolean; noGap?: boolean;
getDate?: (any) => string; // custom function to separate notes on something that isn't createdAt
}>(); }>();
const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>(); const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>();

View File

@ -39,6 +39,23 @@
</MkFoldableSection> </MkFoldableSection>
</div> </div>
</MkSpacer> </MkSpacer>
<MkSpacer v-else-if="tab === 'event'" :content-max="800">
<div class="_gaps">
<div class="_gaps">
<MkSelect v-model="eventSort" small>
<template #label>{{ 'Sort By' }}</template>
<option value="startDate">{{ 'Event Date' }}</option>
<option value="createdAt">{{ 'New' }}</option>
</MkSelect>
<MkButton large primary gradate rounded @click="search">{{ i18n.ts.search }}</MkButton>
</div>
<MkFoldableSection v-if="eventPagination">
<template #header>{{ i18n.ts.searchResult }}</template>
<MkNotes :key="key" :pagination="eventPagination" :get-date="eventSort === 'startDate' ? note => note.event.start : undefined"/>
</MkFoldableSection>
</div>
</MkSpacer>
</MkStickyContainer> </MkStickyContainer>
</template> </template>
@ -49,6 +66,7 @@ import MkUserList from '@/components/MkUserList.vue';
import MkInput from '@/components/MkInput.vue'; import MkInput from '@/components/MkInput.vue';
import MkRadios from '@/components/MkRadios.vue'; import MkRadios from '@/components/MkRadios.vue';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
import MkSelect from '@/components/MkSelect.vue';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata'; import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os'; import * as os from '@/os';
@ -71,8 +89,10 @@ let key = $ref('');
let tab = $ref('note'); let tab = $ref('note');
let searchQuery = $ref(''); let searchQuery = $ref('');
let searchOrigin = $ref('combined'); let searchOrigin = $ref('combined');
let eventSort = $ref('startDate');
let notePagination = $ref(); let notePagination = $ref();
let userPagination = $ref(); let userPagination = $ref();
let eventPagination = $ref();
const notesSearchAvailable = (($i == null && instance.policies.canSearchNotes) || ($i != null && $i.policies.canSearchNotes)); const notesSearchAvailable = (($i == null && instance.policies.canSearchNotes) || ($i != null && $i.policies.canSearchNotes));
@ -85,7 +105,8 @@ onMounted(() => {
async function search() { async function search() {
const query = searchQuery.toString().trim(); const query = searchQuery.toString().trim();
if (query == null || query === '') return; // only notes/users search use the query string. event does not use it
if ((query == null || query === '') && tab !== 'event') return;
if (query.startsWith('https://')) { if (query.startsWith('https://')) {
const promise = os.api('ap/show', { const promise = os.api('ap/show', {
@ -123,6 +144,19 @@ async function search() {
origin: searchOrigin, origin: searchOrigin,
}, },
}; };
} else if (tab === 'event') {
eventPagination = {
endpoint: 'notes/events/search',
limit: 10,
params: {
sortBy: eventSort,
},
};
// only refresh search on query/key change
key = JSON.stringify(eventPagination);
return;
} }
key = query; key = query;
@ -138,6 +172,10 @@ const headerTabs = $computed(() => [{
key: 'user', key: 'user',
title: i18n.ts.users, title: i18n.ts.users,
icon: 'ti ti-users', icon: 'ti ti-users',
}, {
key: 'event',
title: 'Events',
icon: 'ti ti-calendar',
}]); }]);
definePageMetadata(computed(() => ({ definePageMetadata(computed(() => ({

View File

@ -3,11 +3,11 @@
<MkStickyContainer> <MkStickyContainer>
<template #header> <template #header>
<MkTab v-model="include" :class="$style.tab"> <MkTab v-model="include" :class="$style.tab">
<option :value="null">{{ i18n.ts.events || 'Events' }}</option>
<option value="upcoming">{{ i18n.ts.upcomingEvents || 'Upcoming' }}</option> <option value="upcoming">{{ i18n.ts.upcomingEvents || 'Upcoming' }}</option>
<option :value="null">{{ i18n.ts.events || 'Events' }}</option>
</MkTab> </MkTab>
</template> </template>
<MkNotes :no-gap="true" :pagination="pagination" :class="$style.tl"/> <MkNotes :no-gap="true" :pagination="pagination" :class="$style.tl" :get-date="include === 'upcoming' ? note => note.event.start : undefined "/>
</MkStickyContainer> </MkStickyContainer>
</MkSpacer> </MkSpacer>
</template> </template>
@ -23,7 +23,7 @@ const props = defineProps<{
user: misskey.entities.UserDetailed; user: misskey.entities.UserDetailed;
}>(); }>();
const include = ref<string | null>(null); const include = ref<string | null>('upcoming');
const pagination = { const pagination = {
endpoint: 'notes/events/search' as const, endpoint: 'notes/events/search' as const,