mirror of
https://codeberg.org/yeentown/barkey
synced 2024-11-22 16:05:12 +00:00
merge: Drive searching by alt text and title (!564)
View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/564 Approved-by: dakkar <dakkar@thenautilus.net> Approved-by: Marie <marie@kaifa.ch>
This commit is contained in:
commit
3d5fd4a12d
6 changed files with 38 additions and 2 deletions
|
@ -321,6 +321,7 @@ lightThemes: "Light themes"
|
||||||
darkThemes: "Dark themes"
|
darkThemes: "Dark themes"
|
||||||
syncDeviceDarkMode: "Sync Dark Mode with your device settings"
|
syncDeviceDarkMode: "Sync Dark Mode with your device settings"
|
||||||
drive: "Drive"
|
drive: "Drive"
|
||||||
|
driveSearchbarPlaceholder: "Search drive"
|
||||||
fileName: "Filename"
|
fileName: "Filename"
|
||||||
selectFile: "Select a file"
|
selectFile: "Select a file"
|
||||||
selectFiles: "Select files"
|
selectFiles: "Select files"
|
||||||
|
|
4
locales/index.d.ts
vendored
4
locales/index.d.ts
vendored
|
@ -1300,6 +1300,10 @@ export interface Locale extends ILocale {
|
||||||
* ドライブ
|
* ドライブ
|
||||||
*/
|
*/
|
||||||
"drive": string;
|
"drive": string;
|
||||||
|
/**
|
||||||
|
* 検索ドライブ
|
||||||
|
*/
|
||||||
|
"driveSearchbarPlaceholder": string;
|
||||||
/**
|
/**
|
||||||
* ファイル名
|
* ファイル名
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -321,6 +321,7 @@ lightThemes: "明るいテーマ"
|
||||||
darkThemes: "暗いテーマ"
|
darkThemes: "暗いテーマ"
|
||||||
syncDeviceDarkMode: "デバイスのダークモードと同期する"
|
syncDeviceDarkMode: "デバイスのダークモードと同期する"
|
||||||
drive: "ドライブ"
|
drive: "ドライブ"
|
||||||
|
driveSearchbarPlaceholder: "検索ドライブ"
|
||||||
fileName: "ファイル名"
|
fileName: "ファイル名"
|
||||||
selectFile: "ファイルを選択"
|
selectFile: "ファイルを選択"
|
||||||
selectFiles: "ファイルを選択"
|
selectFiles: "ファイルを選択"
|
||||||
|
|
|
@ -9,6 +9,7 @@ import type { DriveFilesRepository } from '@/models/_.js';
|
||||||
import { QueryService } from '@/core/QueryService.js';
|
import { QueryService } from '@/core/QueryService.js';
|
||||||
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
|
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { sqlLikeEscape } from '@/misc/sql-like-escape.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['drive'],
|
tags: ['drive'],
|
||||||
|
@ -37,6 +38,7 @@ export const paramDef = {
|
||||||
folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null },
|
folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null },
|
||||||
type: { type: 'string', nullable: true, pattern: /^[a-zA-Z\/\-*]+$/.toString().slice(1, -1) },
|
type: { type: 'string', nullable: true, pattern: /^[a-zA-Z\/\-*]+$/.toString().slice(1, -1) },
|
||||||
sort: { type: 'string', nullable: true, enum: ['+createdAt', '-createdAt', '+name', '-name', '+size', '-size', null] },
|
sort: { type: 'string', nullable: true, enum: ['+createdAt', '-createdAt', '+name', '-name', '+size', '-size', null] },
|
||||||
|
searchQuery: { type: 'string', default: '' }
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -60,6 +62,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
query.andWhere('file.folderId IS NULL');
|
query.andWhere('file.folderId IS NULL');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ps.searchQuery.length > 0) {
|
||||||
|
query.andWhere('file.name ILIKE :searchQuery OR file.comment ILIKE :searchQuery', { searchQuery: `%${sqlLikeEscape(ps.searchQuery)}%` });
|
||||||
|
}
|
||||||
|
|
||||||
if (ps.type) {
|
if (ps.type) {
|
||||||
if (ps.type.endsWith('/*')) {
|
if (ps.type.endsWith('/*')) {
|
||||||
query.andWhere('file.type like :type', { type: ps.type.replace('/*', '/') + '%' });
|
query.andWhere('file.type like :type', { type: ps.type.replace('/*', '/') + '%' });
|
||||||
|
|
|
@ -9,6 +9,7 @@ import type { DriveFoldersRepository } from '@/models/_.js';
|
||||||
import { QueryService } from '@/core/QueryService.js';
|
import { QueryService } from '@/core/QueryService.js';
|
||||||
import { DriveFolderEntityService } from '@/core/entities/DriveFolderEntityService.js';
|
import { DriveFolderEntityService } from '@/core/entities/DriveFolderEntityService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { sqlLikeEscape } from '@/misc/sql-like-escape.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['drive'],
|
tags: ['drive'],
|
||||||
|
@ -35,6 +36,7 @@ export const paramDef = {
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null },
|
folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null },
|
||||||
|
searchQuery: { type: 'string', default: '' }
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -58,6 +60,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
query.andWhere('folder.parentId IS NULL');
|
query.andWhere('folder.parentId IS NULL');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ps.searchQuery.length > 0) {
|
||||||
|
query.andWhere('folder.name ILIKE :searchQuery', { searchQuery: `%${sqlLikeEscape(ps.searchQuery)}%` });
|
||||||
|
}
|
||||||
const folders = await query.limit(ps.limit).getMany();
|
const folders = await query.limit(ps.limit).getMany();
|
||||||
|
|
||||||
return await Promise.all(folders.map(folder => this.driveFolderEntityService.pack(folder)));
|
return await Promise.all(folders.map(folder => this.driveFolderEntityService.pack(folder)));
|
||||||
|
|
|
@ -30,7 +30,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<span v-if="folder != null" :class="[$style.navPathItem, $style.navSeparator]"><i class="ti ti-chevron-right"></i></span>
|
<span v-if="folder != null" :class="[$style.navPathItem, $style.navSeparator]"><i class="ti ti-chevron-right"></i></span>
|
||||||
<span v-if="folder != null" :class="[$style.navPathItem, $style.navCurrent]">{{ folder.name }}</span>
|
<span v-if="folder != null" :class="[$style.navPathItem, $style.navCurrent]">{{ folder.name }}</span>
|
||||||
</div>
|
</div>
|
||||||
<button class="_button" :class="$style.navMenu" @click="showMenu"><i class="ti ti-dots"></i></button>
|
<div :class="$style.navMenu">
|
||||||
|
<!-- "Search drive via alt text or file names" -->
|
||||||
|
<MkInput v-model="searchQuery" :large="true" :autofocus="true" type="search" :placeholder="i18n.ts.driveSearchbarPlaceholder" @enter="fetch">
|
||||||
|
<template #prefix><i class="ph-magnifying-glass ph-bold ph-lg"></i></template>
|
||||||
|
</MkInput>
|
||||||
|
|
||||||
|
<button class="_button" :class="$style.navMenu" @click="showMenu"><i class="ti ti-dots"></i></button>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div
|
<div
|
||||||
ref="main"
|
ref="main"
|
||||||
|
@ -102,6 +109,7 @@ import type { MenuItem } from '@/types/menu.js';
|
||||||
import XNavFolder from '@/components/MkDrive.navFolder.vue';
|
import XNavFolder from '@/components/MkDrive.navFolder.vue';
|
||||||
import XFolder from '@/components/MkDrive.folder.vue';
|
import XFolder from '@/components/MkDrive.folder.vue';
|
||||||
import XFile from '@/components/MkDrive.file.vue';
|
import XFile from '@/components/MkDrive.file.vue';
|
||||||
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { useStream } from '@/stream.js';
|
import { useStream } from '@/stream.js';
|
||||||
|
@ -110,6 +118,8 @@ import { i18n } from '@/i18n.js';
|
||||||
import { uploadFile, uploads } from '@/scripts/upload.js';
|
import { uploadFile, uploads } from '@/scripts/upload.js';
|
||||||
import { claimAchievement } from '@/scripts/achievements.js';
|
import { claimAchievement } from '@/scripts/achievements.js';
|
||||||
|
|
||||||
|
const searchQuery = ref('');
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
initialFolder?: Misskey.entities.DriveFolder;
|
initialFolder?: Misskey.entities.DriveFolder;
|
||||||
type?: string;
|
type?: string;
|
||||||
|
@ -540,6 +550,7 @@ async function fetch() {
|
||||||
const foldersPromise = misskeyApi('drive/folders', {
|
const foldersPromise = misskeyApi('drive/folders', {
|
||||||
folderId: folder.value ? folder.value.id : null,
|
folderId: folder.value ? folder.value.id : null,
|
||||||
limit: foldersMax + 1,
|
limit: foldersMax + 1,
|
||||||
|
searchQuery: searchQuery.value.toString().trim(),
|
||||||
}).then(fetchedFolders => {
|
}).then(fetchedFolders => {
|
||||||
if (fetchedFolders.length === foldersMax + 1) {
|
if (fetchedFolders.length === foldersMax + 1) {
|
||||||
moreFolders.value = true;
|
moreFolders.value = true;
|
||||||
|
@ -552,6 +563,7 @@ async function fetch() {
|
||||||
folderId: folder.value ? folder.value.id : null,
|
folderId: folder.value ? folder.value.id : null,
|
||||||
type: props.type,
|
type: props.type,
|
||||||
limit: filesMax + 1,
|
limit: filesMax + 1,
|
||||||
|
searchQuery: searchQuery.value.toString().trim(),
|
||||||
}).then(fetchedFiles => {
|
}).then(fetchedFiles => {
|
||||||
if (fetchedFiles.length === filesMax + 1) {
|
if (fetchedFiles.length === filesMax + 1) {
|
||||||
moreFiles.value = true;
|
moreFiles.value = true;
|
||||||
|
@ -578,6 +590,7 @@ function fetchMoreFolders() {
|
||||||
type: props.type,
|
type: props.type,
|
||||||
untilId: folders.value.at(-1)?.id,
|
untilId: folders.value.at(-1)?.id,
|
||||||
limit: max + 1,
|
limit: max + 1,
|
||||||
|
searchQuery: searchQuery.value.toString().trim(),
|
||||||
}).then(folders => {
|
}).then(folders => {
|
||||||
if (folders.length === max + 1) {
|
if (folders.length === max + 1) {
|
||||||
moreFolders.value = true;
|
moreFolders.value = true;
|
||||||
|
@ -601,6 +614,7 @@ function fetchMoreFiles() {
|
||||||
type: props.type,
|
type: props.type,
|
||||||
untilId: files.value.at(-1)?.id,
|
untilId: files.value.at(-1)?.id,
|
||||||
limit: max + 1,
|
limit: max + 1,
|
||||||
|
searchQuery: searchQuery.value.toString().trim(),
|
||||||
}).then(files => {
|
}).then(files => {
|
||||||
if (files.length === max + 1) {
|
if (files.length === max + 1) {
|
||||||
moreFiles.value = true;
|
moreFiles.value = true;
|
||||||
|
@ -747,8 +761,13 @@ onBeforeUnmount(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.navMenu {
|
.navMenu {
|
||||||
|
display: flex;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
padding: 0 12px;
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navMenu > *:not(:last-child) {
|
||||||
|
padding-right: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
|
|
Loading…
Reference in a new issue