Compare commits

...

5 Commits

Author SHA1 Message Date
おさむのひと dba2e9c36f Merge branch 'develop' into feat/16035-serach-range-time 2025-05-31 10:21:08 +09:00
samunohito 4deae4f745 fix CHANGELOG.md 2025-05-31 10:03:20 +09:00
samunohito 128203b28d fix ui 2025-05-31 10:00:35 +09:00
samunohito d33b7b7d6e simplify 2025-05-30 07:51:11 +09:00
samunohito 4131be525b feat: 投稿日時の範囲を条件に加えてノート検索出来るようにする 2025-05-29 21:20:58 +09:00
7 changed files with 65 additions and 2 deletions
+1
View File
@@ -17,6 +17,7 @@
- 場合によってはファイル種別を正しく検出できないことがあります(特にテキストフォーマット)。その場合、ファイル種別は application/octet-stream と見做されます。
- したがって、それらの種別不明ファイルを許可したい場合は application/octet-stream を指定に追加してください。
- Feat: プレビュー先がリダイレクトを伴う場合、リダイレクト先のコンテンツを取得しに行くか否かを設定できるように(#16043)
- Feat: ノート検索で投稿日時の期間を条件に加えられるように(#16035)
- Enhance: UIのアイコンデータの読み込みを軽量化
### Client
+8
View File
@@ -11783,6 +11783,14 @@ export interface Locale extends ILocale {
* : misskey.example.com
*/
"serverHostPlaceholder": string;
/**
* 稿from
*/
"postFrom": string;
/**
* 稿to
*/
"postTo": string;
};
"_serverSetupWizard": {
/**
+2
View File
@@ -3150,6 +3150,8 @@ _search:
pleaseEnterServerHost: "サーバーのホストを入力してください"
pleaseSelectUser: "ユーザーを選択してください"
serverHostPlaceholder: "例: misskey.example.com"
postFrom: "投稿日時from"
postTo: "投稿日時to"
_serverSetupWizard:
installCompleted: "Misskeyのインストールが完了しました!"
@@ -38,6 +38,8 @@ export type SearchOpts = {
userId?: MiNote['userId'] | null;
channelId?: MiNote['channelId'] | null;
host?: string | null;
rangeStartAt?: number | null;
rangeEndAt?: number | null;
};
export type SearchPagination = {
@@ -233,6 +235,16 @@ export class SearchService {
}
}
if (opts.rangeStartAt) {
const date = this.idService.gen(opts.rangeStartAt);
query.andWhere('note.id >= :rangeStartAt', { rangeStartAt: date });
}
if (opts.rangeEndAt) {
const date = this.idService.gen(opts.rangeEndAt);
query.andWhere('note.id <= :rangeEndAt', { rangeEndAt: date });
}
this.queryService.generateVisibilityQuery(query, me);
this.queryService.generateBaseNoteFilteringQuery(query, me);
@@ -259,11 +271,21 @@ export class SearchService {
k: 'createdAt',
v: this.idService.parse(pagination.untilId).date.getTime(),
});
if (opts.rangeEndAt) filter.qs.push({
op: '<=',
k: 'createdAt',
v: opts.rangeEndAt,
});
if (pagination.sinceId) filter.qs.push({
op: '>',
k: 'createdAt',
v: this.idService.parse(pagination.sinceId).date.getTime(),
});
if (opts.rangeStartAt) filter.qs.push({
op: '>=',
k: 'createdAt',
v: opts.rangeStartAt,
});
if (opts.userId) filter.qs.push({ op: '=', k: 'userId', v: opts.userId });
if (opts.channelId) filter.qs.push({ op: '=', k: 'channelId', v: opts.channelId });
if (opts.host) {
@@ -38,6 +38,8 @@ export const paramDef = {
type: 'object',
properties: {
query: { type: 'string' },
rangeStartAt: { type: 'integer', nullable: true },
rangeEndAt: { type: 'integer', nullable: true },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
@@ -71,6 +73,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
userId: ps.userId,
channelId: ps.channelId,
host: ps.host,
rangeStartAt: ps.rangeStartAt,
rangeEndAt: ps.rangeEndAt,
}, {
untilId: ps.untilId,
sinceId: ps.sinceId,
+26 -2
View File
@@ -19,6 +19,15 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #header>{{ i18n.ts.options }}</template>
<div class="_gaps_m">
<div style="display: flex; gap: 8px;">
<MkInput v-model="rangeStartAt" type="datetime-local">
<template #label>{{ i18n.ts._search.postFrom }}</template>
</MkInput>
<MkInput v-model="rangeEndAt" type="datetime-local">
<template #label>{{ i18n.ts._search.postTo }}</template>
</MkInput>
</div>
<MkRadios v-model="searchScope">
<option v-if="instance.federation !== 'none' && noteSearchableScope === 'global'" value="all">{{ i18n.ts._search.searchScopeAll }}</option>
<option value="local">{{ instance.federation === 'none' ? i18n.ts._search.searchScopeAll : i18n.ts._search.searchScopeLocal }}</option>
@@ -112,10 +121,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed, ref, shallowRef, toRef } from 'vue';
import { host as localHost } from '@@/js/config.js';
import type * as Misskey from 'misskey-js';
import type { PagingCtx } from '@/composables/use-pagination.js';
import { $i } from '@/i.js';
import { host as localHost } from '@@/js/config.js';
import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js';
import * as os from '@/os.js';
@@ -148,6 +157,8 @@ const notePagination = ref<PagingCtx<'notes/search'>>();
const searchQuery = ref(toRef(props, 'query').value);
const hostInput = ref(toRef(props, 'host').value);
const rangeStartAt = ref<string | null>(null);
const rangeEndAt = ref<string | null>(null);
const user = shallowRef<Misskey.entities.UserDetailed | null>(null);
@@ -188,6 +199,8 @@ type SearchParams = {
readonly query: string;
readonly host?: string;
readonly userId?: string;
readonly rangeStartAt?: number | null;
readonly rangeEndAt?: number | null;
};
const fixHostIfLocal = (target: string | null | undefined) => {
@@ -195,6 +208,13 @@ const fixHostIfLocal = (target: string | null | undefined) => {
return target;
};
const searchRange = () => {
return {
rangeStartAt: rangeStartAt.value ? new Date(rangeStartAt.value).getTime() : null,
rangeEndAt: rangeEndAt.value ? new Date(rangeEndAt.value).getTime() : null,
};
};
const searchParams = computed<SearchParams | null>(() => {
const trimmedQuery = searchQuery.value.trim();
if (!trimmedQuery) return null;
@@ -205,6 +225,7 @@ const searchParams = computed<SearchParams | null>(() => {
query: trimmedQuery,
host: fixHostIfLocal(user.value.host),
userId: user.value.id,
...searchRange(),
};
}
@@ -219,6 +240,7 @@ const searchParams = computed<SearchParams | null>(() => {
return {
query: trimmedQuery,
host: fixHostIfLocal(trimmedHost),
...searchRange(),
};
}
@@ -226,11 +248,13 @@ const searchParams = computed<SearchParams | null>(() => {
return {
query: trimmedQuery,
host: '.',
...searchRange(),
};
}
return {
query: trimmedQuery,
...searchRange(),
};
});
@@ -265,7 +289,7 @@ async function search() {
if (res.type === 'User') {
router.push(`/@${res.object.username}@${res.object.host}`);
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
} else if (res.type === 'Note') {
router.push(`/notes/${res.object.id}`);
}
+2
View File
@@ -25720,6 +25720,8 @@ export type operations = {
content: {
'application/json': {
query: string;
rangeStartAt?: number | null;
rangeEndAt?: number | null;
/** Format: misskey:id */
sinceId?: string;
/** Format: misskey:id */