diff options
| author | おさむのひと <46447427+samunohito@users.noreply.github.com> | 2025-02-26 16:28:35 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-02-26 07:28:35 +0000 |
| commit | 15b0345335397ae6df8c85871793adab49343ec7 (patch) | |
| tree | 4bdc9f99fb9be1b4d44022f379b358aa8de7f40a | |
| parent | fix(frontend): リノート経由でノートの詳細情報を見るとき... (diff) | |
| download | misskey-15b0345335397ae6df8c85871793adab49343ec7.tar.gz misskey-15b0345335397ae6df8c85871793adab49343ec7.tar.bz2 misskey-15b0345335397ae6df8c85871793adab49343ec7.zip | |
enhance(frontend): コントロールパネルのユーザ検索で入力された情報をページ遷移で損なわないように (#15438)
* enhance(frontend): コントロールパネルのユーザ検索で入力された情報をページ遷移で損なわないように
* sessionStorageよりも更に短命な方法で持つように変更
* add comment
---------
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
Diffstat (limited to '')
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | packages/frontend/src/account.ts | 5 | ||||
| -rw-r--r-- | packages/frontend/src/memory-storage.ts | 57 | ||||
| -rw-r--r-- | packages/frontend/src/pages/admin/users.vue | 44 |
4 files changed, 100 insertions, 7 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index d51369f4bb..940a4309bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - Enhance: 開発者モードでメニューからファイルIDをコピー出来るように `#15441' - Enhance: ノートに埋め込まれたメディアのコンテキストメニューから管理者用のファイル管理画面を開けるように ( #15440 ) - Enhance: リアクションする際に確認ダイアログを表示できるように +- Enhance: コントロールパネルのユーザ検索で入力された情報をページ遷移で損なわないように `#15437` - Enhance: CWの注釈で入力済みの文字数を表示 - Fix: ノートページで、クリップ一覧が表示されないことがある問題を修正 - Fix: コンディショナルロールを手動で割り当てできる導線を削除 `#13529` diff --git a/packages/frontend/src/account.ts b/packages/frontend/src/account.ts index 9006150bc8..17d690cd3a 100644 --- a/packages/frontend/src/account.ts +++ b/packages/frontend/src/account.ts @@ -7,6 +7,7 @@ import { defineAsyncComponent, reactive, ref } from 'vue'; import * as Misskey from 'misskey-js'; import { apiUrl } from '@@/js/config.js'; import type { MenuItem, MenuButton } from '@/types/menu.js'; +import { defaultMemoryStorage } from '@/memory-storage'; import { showSuspendedDialog } from '@/scripts/show-suspended-dialog.js'; import { i18n } from '@/i18n.js'; import { miLocalStorage } from '@/local-storage.js'; @@ -40,6 +41,8 @@ export function incNotesCount() { export async function signout() { if (!$i) return; + defaultMemoryStorage.clear(); + waiting(); document.cookie.split(';').forEach((cookie) => { const cookieName = cookie.split('=')[0].trim(); @@ -107,7 +110,7 @@ export async function removeAccount(idOrToken: Account['id']) { } function fetchAccount(token: string, id?: string, forceShowDialog?: boolean): Promise<Account> { - document.cookie = "token=; path=/; max-age=0"; + document.cookie = 'token=; path=/; max-age=0'; document.cookie = `token=${token}; path=/queue; max-age=86400; SameSite=Strict; Secure`; // bull dashboardの認証とかで使う return new Promise((done, fail) => { diff --git a/packages/frontend/src/memory-storage.ts b/packages/frontend/src/memory-storage.ts new file mode 100644 index 0000000000..df0dc1308f --- /dev/null +++ b/packages/frontend/src/memory-storage.ts @@ -0,0 +1,57 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export type MemoryStorage = { + has: (key: string) => boolean; + getItem: <T>(key: string) => T | null; + setItem: (key: string, value: unknown) => void; + removeItem: (key: string) => void; + clear: () => void; + size: number; +}; + +class MemoryStorageImpl implements MemoryStorage { + private readonly storage: Map<string, unknown>; + + constructor() { + this.storage = new Map(); + } + + has(key: string): boolean { + return this.storage.has(key); + } + + getItem<T>(key: string): T | null { + return this.storage.has(key) ? this.storage.get(key) as T : null; + } + + setItem(key: string, value: unknown): void { + this.storage.set(key, value); + } + + removeItem(key: string): void { + this.storage.delete(key); + } + + clear(): void { + this.storage.clear(); + } + + get size(): number { + return this.storage.size; + } +} + +export function createMemoryStorage(): MemoryStorage { + return new MemoryStorageImpl(); +} + +/** + * SessionStorageよりも更に短い期間でクリアされるストレージです + * - ブラウザの再読み込みやタブの閉じると内容が揮発します + * - このストレージは他のタブと共有されません + * - アカウント切り替えやログアウトを行うと内容が揮発します + */ +export const defaultMemoryStorage: MemoryStorage = createMemoryStorage(); diff --git a/packages/frontend/src/pages/admin/users.vue b/packages/frontend/src/pages/admin/users.vue index 870c3ce88b..91104b676d 100644 --- a/packages/frontend/src/pages/admin/users.vue +++ b/packages/frontend/src/pages/admin/users.vue @@ -10,6 +10,9 @@ SPDX-License-Identifier: AGPL-3.0-only <MkSpacer :contentMax="900"> <div class="_gaps"> <div :class="$style.inputs"> + <MkButton style="margin-left: auto" @click="resetQuery">{{ i18n.ts.reset }}</MkButton> + </div> + <div :class="$style.inputs"> <MkSelect v-model="sort" style="flex: 1;"> <template #label>{{ i18n.ts.sort }}</template> <option value="-createdAt">{{ i18n.ts.registeredDate }} ({{ i18n.ts.ascendingOrder }})</option> @@ -57,8 +60,10 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, shallowRef, ref } from 'vue'; +import { computed, shallowRef, ref, watchEffect } from 'vue'; import XHeader from './_header_.vue'; +import { defaultMemoryStorage } from '@/memory-storage'; +import MkButton from '@/components/MkButton.vue'; import MkInput from '@/components/MkInput.vue'; import MkSelect from '@/components/MkSelect.vue'; import MkPagination from '@/components/MkPagination.vue'; @@ -69,13 +74,22 @@ import { definePageMetadata } from '@/scripts/page-metadata.js'; import MkUserCardMini from '@/components/MkUserCardMini.vue'; import { dateString } from '@/filters/date.js'; +type SearchQuery = { + sort?: string; + state?: string; + origin?: string; + username?: string; + hostname?: string; +}; + const paginationComponent = shallowRef<InstanceType<typeof MkPagination>>(); +const storedQuery = JSON.parse(defaultMemoryStorage.getItem('admin-users-query') ?? '{}') as SearchQuery; -const sort = ref('+createdAt'); -const state = ref('all'); -const origin = ref('local'); -const searchUsername = ref(''); -const searchHost = ref(''); +const sort = ref(storedQuery.sort ?? '+createdAt'); +const state = ref(storedQuery.state ?? 'all'); +const origin = ref(storedQuery.origin ?? 'local'); +const searchUsername = ref(storedQuery.username ?? ''); +const searchHost = ref(storedQuery.hostname ?? ''); const pagination = { endpoint: 'admin/show-users' as const, limit: 10, @@ -119,6 +133,14 @@ function show(user) { os.pageWindow(`/admin/user/${user.id}`); } +function resetQuery() { + sort.value = '+createdAt'; + state.value = 'all'; + origin.value = 'local'; + searchUsername.value = ''; + searchHost.value = ''; +} + const headerActions = computed(() => [{ icon: 'ti ti-search', text: i18n.ts.search, @@ -137,6 +159,16 @@ const headerActions = computed(() => [{ const headerTabs = computed(() => []); +watchEffect(() => { + defaultMemoryStorage.setItem('admin-users-query', JSON.stringify({ + sort: sort.value, + state: state.value, + origin: origin.value, + username: searchUsername.value, + hostname: searchHost.value, + })); +}); + definePageMetadata(() => ({ title: i18n.ts.users, icon: 'ti ti-users', |