summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorおさむのひと <46447427+samunohito@users.noreply.github.com>2025-02-26 16:28:35 +0900
committerGitHub <noreply@github.com>2025-02-26 07:28:35 +0000
commit15b0345335397ae6df8c85871793adab49343ec7 (patch)
tree4bdc9f99fb9be1b4d44022f379b358aa8de7f40a
parentfix(frontend): リノート経由でノートの詳細情報を見るとき... (diff)
downloadmisskey-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.md1
-rw-r--r--packages/frontend/src/account.ts5
-rw-r--r--packages/frontend/src/memory-storage.ts57
-rw-r--r--packages/frontend/src/pages/admin/users.vue44
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',