Compare commits
	
		
			2 Commits
		
	
	
		
			5096be06ac
			...
			bdf390eb7e
		
	
	| Author | SHA1 | Date | 
|---|---|---|
|  | bdf390eb7e | |
|  | a52f63ec6a | 
|  | @ -18,7 +18,8 @@ | ||||||
| - OAuth 2.0のサポート | - OAuth 2.0のサポート | ||||||
| 
 | 
 | ||||||
| ### Client | ### Client | ||||||
| - | - Fix: サーバー情報画面(`/instance-info/{domain}`)でブロックができないのを修正 | ||||||
|  | - Fix: 未読のお知らせの「わかった」をクリック・タップしてもその場で「わかった」が消えない問題を修正 | ||||||
| 
 | 
 | ||||||
| ### Server | ### Server | ||||||
| - | - | ||||||
|  |  | ||||||
|  | @ -7,15 +7,15 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||||
| <MkStickyContainer> | <MkStickyContainer> | ||||||
| 	<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> | 	<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> | ||||||
| 	<MkSpacer :contentMax="800"> | 	<MkSpacer :contentMax="800"> | ||||||
| 		<MkPagination v-slot="{items}" :pagination="pagination" class="ruryvtyk _gaps_m"> | 		<MkPagination ref="paginationEl" v-slot="{items}" :pagination="pagination" class="ruryvtyk _gaps_m"> | ||||||
| 			<section v-for="(announcement, i) in items" :key="announcement.id" class="announcement _panel"> | 			<section v-for="announcement in items" :key="announcement.id" class="announcement _panel"> | ||||||
| 				<div class="header"><span v-if="$i && !announcement.isRead">🆕 </span>{{ announcement.title }}</div> | 				<div class="header"><span v-if="$i && !announcement.isRead">🆕 </span>{{ announcement.title }}</div> | ||||||
| 				<div class="content"> | 				<div class="content"> | ||||||
| 					<Mfm :text="announcement.text"/> | 					<Mfm :text="announcement.text"/> | ||||||
| 					<img v-if="announcement.imageUrl" :src="announcement.imageUrl"/> | 					<img v-if="announcement.imageUrl" :src="announcement.imageUrl"/> | ||||||
| 				</div> | 				</div> | ||||||
| 				<div v-if="$i && !announcement.isRead" class="footer"> | 				<div v-if="$i && !announcement.isRead" class="footer"> | ||||||
| 					<MkButton primary @click="read(items, announcement, i)"><i class="ti ti-check"></i> {{ i18n.ts.gotIt }}</MkButton> | 					<MkButton primary @click="read(announcement.id)"><i class="ti ti-check"></i> {{ i18n.ts.gotIt }}</MkButton> | ||||||
| 				</div> | 				</div> | ||||||
| 			</section> | 			</section> | ||||||
| 		</MkPagination> | 		</MkPagination> | ||||||
|  | @ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script lang="ts" setup> | <script lang="ts" setup> | ||||||
| import { } from 'vue'; | import { ref } from 'vue'; | ||||||
| import MkPagination from '@/components/MkPagination.vue'; | import MkPagination from '@/components/MkPagination.vue'; | ||||||
| import MkButton from '@/components/MkButton.vue'; | import MkButton from '@/components/MkButton.vue'; | ||||||
| import * as os from '@/os'; | import * as os from '@/os'; | ||||||
|  | @ -37,13 +37,15 @@ const pagination = { | ||||||
| 	limit: 10, | 	limit: 10, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // TODO: これは実質的に親コンポーネントから子コンポーネントのプロパティを変更してるのでなんとかしたい | const paginationEl = ref<InstanceType<typeof MkPagination>>(); | ||||||
| function read(items, announcement, i) { | 
 | ||||||
| 	items[i] = { | function read(id: string) { | ||||||
| 		...announcement, | 	if (!paginationEl.value) return; | ||||||
| 		isRead: true, | 	paginationEl.value.updateItem(id, announcement => { | ||||||
| 	}; | 		announcement.isRead = true; | ||||||
| 	os.api('i/read-announcement', { announcementId: announcement.id }); | 		return announcement; | ||||||
|  | 	}); | ||||||
|  | 	os.api('i/read-announcement', { announcementId: id }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const headerActions = $computed(() => []); | const headerActions = $computed(() => []); | ||||||
|  |  | ||||||
|  | @ -34,8 +34,8 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||||
| 			<FormSection v-if="iAmModerator"> | 			<FormSection v-if="iAmModerator"> | ||||||
| 				<template #label>Moderation</template> | 				<template #label>Moderation</template> | ||||||
| 				<div class="_gaps_s"> | 				<div class="_gaps_s"> | ||||||
| 					<MkSwitch v-model="suspended" @update:modelValue="toggleSuspend">{{ i18n.ts.stopActivityDelivery }}</MkSwitch> | 					<MkSwitch v-model="suspended" :disabled="!instance" @update:modelValue="toggleSuspend">{{ i18n.ts.stopActivityDelivery }}</MkSwitch> | ||||||
| 					<MkSwitch v-model="isBlocked" @update:modelValue="toggleBlock">{{ i18n.ts.blockThisInstance }}</MkSwitch> | 					<MkSwitch v-model="isBlocked" :disabled="!meta || !instance" @update:modelValue="toggleBlock">{{ i18n.ts.blockThisInstance }}</MkSwitch> | ||||||
| 					<MkButton @click="refreshMetadata"><i class="ti ti-refresh"></i> Refresh metadata</MkButton> | 					<MkButton @click="refreshMetadata"><i class="ti ti-refresh"></i> Refresh metadata</MkButton> | ||||||
| 				</div> | 				</div> | ||||||
| 			</FormSection> | 			</FormSection> | ||||||
|  | @ -129,7 +129,7 @@ import MkSelect from '@/components/MkSelect.vue'; | ||||||
| import MkSwitch from '@/components/MkSwitch.vue'; | import MkSwitch from '@/components/MkSwitch.vue'; | ||||||
| import * as os from '@/os'; | import * as os from '@/os'; | ||||||
| import number from '@/filters/number'; | import number from '@/filters/number'; | ||||||
| import { iAmModerator } from '@/account'; | import { iAmModerator, iAmAdmin } from '@/account'; | ||||||
| import { definePageMetadata } from '@/scripts/page-metadata'; | import { definePageMetadata } from '@/scripts/page-metadata'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
| import MkUserCardMini from '@/components/MkUserCardMini.vue'; | import MkUserCardMini from '@/components/MkUserCardMini.vue'; | ||||||
|  | @ -143,11 +143,11 @@ const props = defineProps<{ | ||||||
| 
 | 
 | ||||||
| let tab = $ref('overview'); | let tab = $ref('overview'); | ||||||
| let chartSrc = $ref('instance-requests'); | let chartSrc = $ref('instance-requests'); | ||||||
| let meta = $ref<misskey.entities.DetailedInstanceMetadata | null>(null); | let meta = $ref<misskey.entities.AdminInstanceMetadata | null>(null); | ||||||
| let instance = $ref<misskey.entities.Instance | null>(null); | let instance = $ref<misskey.entities.Instance | null>(null); | ||||||
| let suspended = $ref(false); | let suspended = $ref(false); | ||||||
| let isBlocked = $ref(false); | let isBlocked = $ref(false); | ||||||
| let faviconUrl = $ref(null); | let faviconUrl = $ref<string | null>(null); | ||||||
| 
 | 
 | ||||||
| const usersPagination = { | const usersPagination = { | ||||||
| 	endpoint: iAmModerator ? 'admin/show-users' : 'users' as const, | 	endpoint: iAmModerator ? 'admin/show-users' : 'users' as const, | ||||||
|  | @ -160,7 +160,10 @@ const usersPagination = { | ||||||
| 	offsetMode: true, | 	offsetMode: true, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| async function fetch() { | async function fetch(): Promise<void> { | ||||||
|  | 	if (iAmAdmin) { | ||||||
|  | 		meta = await os.api('admin/meta'); | ||||||
|  | 	} | ||||||
| 	instance = await os.api('federation/show-instance', { | 	instance = await os.api('federation/show-instance', { | ||||||
| 		host: props.host, | 		host: props.host, | ||||||
| 	}); | 	}); | ||||||
|  | @ -169,21 +172,25 @@ async function fetch() { | ||||||
| 	faviconUrl = getProxiedImageUrlNullable(instance.faviconUrl, 'preview') ?? getProxiedImageUrlNullable(instance.iconUrl, 'preview'); | 	faviconUrl = getProxiedImageUrlNullable(instance.faviconUrl, 'preview') ?? getProxiedImageUrlNullable(instance.iconUrl, 'preview'); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function toggleBlock(ev) { | async function toggleBlock(): Promise<void> { | ||||||
| 	if (meta == null) return; | 	if (!meta) throw new Error('No meta?'); | ||||||
|  | 	if (!instance) throw new Error('No instance?'); | ||||||
|  | 	const { host } = instance; | ||||||
| 	await os.api('admin/update-meta', { | 	await os.api('admin/update-meta', { | ||||||
| 		blockedHosts: isBlocked ? meta.blockedHosts.concat([instance.host]) : meta.blockedHosts.filter(x => x !== instance.host), | 		blockedHosts: isBlocked ? meta.blockedHosts.concat([host]) : meta.blockedHosts.filter(x => x !== host), | ||||||
| 	}); | 	}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function toggleSuspend(v) { | async function toggleSuspend(): Promise<void> { | ||||||
|  | 	if (!instance) throw new Error('No instance?'); | ||||||
| 	await os.api('admin/federation/update-instance', { | 	await os.api('admin/federation/update-instance', { | ||||||
| 		host: instance.host, | 		host: instance.host, | ||||||
| 		isSuspended: suspended, | 		isSuspended: suspended, | ||||||
| 	}); | 	}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function refreshMetadata() { | function refreshMetadata(): void { | ||||||
|  | 	if (!instance) throw new Error('No instance?'); | ||||||
| 	os.api('admin/federation/refresh-remote-instance-metadata', { | 	os.api('admin/federation/refresh-remote-instance-metadata', { | ||||||
| 		host: instance.host, | 		host: instance.host, | ||||||
| 	}); | 	}); | ||||||
|  |  | ||||||
|  | @ -17,6 +17,11 @@ export type Acct = { | ||||||
| // @public (undocumented) | // @public (undocumented) | ||||||
| type Ad = TODO_2; | type Ad = TODO_2; | ||||||
| 
 | 
 | ||||||
|  | // @public (undocumented) | ||||||
|  | type AdminInstanceMetadata = DetailedInstanceMetadata & { | ||||||
|  |     blockedHosts: string[]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| // @public (undocumented) | // @public (undocumented) | ||||||
| type Announcement = { | type Announcement = { | ||||||
|     id: ID; |     id: ID; | ||||||
|  | @ -329,8 +334,8 @@ export type Endpoints = { | ||||||
|         res: TODO; |         res: TODO; | ||||||
|     }; |     }; | ||||||
|     'admin/meta': { |     'admin/meta': { | ||||||
|         req: TODO; |         req: NoParams; | ||||||
|         res: TODO; |         res: AdminInstanceMetadata; | ||||||
|     }; |     }; | ||||||
|     'admin/reset-password': { |     'admin/reset-password': { | ||||||
|         req: TODO; |         req: TODO; | ||||||
|  | @ -2226,6 +2231,7 @@ declare namespace entities { | ||||||
|         LiteInstanceMetadata, |         LiteInstanceMetadata, | ||||||
|         DetailedInstanceMetadata, |         DetailedInstanceMetadata, | ||||||
|         InstanceMetadata, |         InstanceMetadata, | ||||||
|  |         AdminInstanceMetadata, | ||||||
|         ServerInfo, |         ServerInfo, | ||||||
|         Stats, |         Stats, | ||||||
|         Page, |         Page, | ||||||
|  | @ -2317,7 +2323,7 @@ type ID = string; | ||||||
| // @public (undocumented) | // @public (undocumented) | ||||||
| type Instance = { | type Instance = { | ||||||
|     id: ID; |     id: ID; | ||||||
|     caughtAt: DateString; |     firstRetrievedAt: DateString; | ||||||
|     host: string; |     host: string; | ||||||
|     usersCount: number; |     usersCount: number; | ||||||
|     notesCount: number; |     notesCount: number; | ||||||
|  | @ -2331,6 +2337,7 @@ type Instance = { | ||||||
|     lastCommunicatedAt: DateString; |     lastCommunicatedAt: DateString; | ||||||
|     isNotResponding: boolean; |     isNotResponding: boolean; | ||||||
|     isSuspended: boolean; |     isSuspended: boolean; | ||||||
|  |     isBlocked: boolean; | ||||||
|     softwareName: string | null; |     softwareName: string | null; | ||||||
|     softwareVersion: string | null; |     softwareVersion: string | null; | ||||||
|     openRegistrations: boolean | null; |     openRegistrations: boolean | null; | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ import type { | ||||||
| 	Ad, Announcement, Antenna, App, AuthSession, Blocking, Channel, Clip, DateString, DetailedInstanceMetadata, DriveFile, DriveFolder, Following, FollowingFolloweePopulated, FollowingFollowerPopulated, FollowRequest, GalleryPost, Instance, | 	Ad, Announcement, Antenna, App, AuthSession, Blocking, Channel, Clip, DateString, DetailedInstanceMetadata, DriveFile, DriveFolder, Following, FollowingFolloweePopulated, FollowingFollowerPopulated, FollowRequest, GalleryPost, Instance, | ||||||
| 	LiteInstanceMetadata, | 	LiteInstanceMetadata, | ||||||
| 	MeDetailed, | 	MeDetailed, | ||||||
| 	Note, NoteFavorite, OriginType, Page, ServerInfo, Stats, User, UserDetailed, MeSignup, UserGroup, UserList, UserSorting, Notification, NoteReaction, Signin, MessagingMessage, Invite, InviteLimit, | 	Note, NoteFavorite, OriginType, Page, ServerInfo, Stats, User, UserDetailed, MeSignup, UserGroup, UserList, UserSorting, Notification, NoteReaction, Signin, MessagingMessage, Invite, InviteLimit, AdminInstanceMetadata, | ||||||
| } from './entities.js'; | } from './entities.js'; | ||||||
| 
 | 
 | ||||||
| type TODO = Record<string, any> | null; | type TODO = Record<string, any> | null; | ||||||
|  | @ -20,7 +20,7 @@ export type Endpoints = { | ||||||
| 	'admin/get-table-stats': { req: TODO; res: TODO; }; | 	'admin/get-table-stats': { req: TODO; res: TODO; }; | ||||||
| 	'admin/invite': { req: TODO; res: TODO; }; | 	'admin/invite': { req: TODO; res: TODO; }; | ||||||
| 	'admin/logs': { req: TODO; res: TODO; }; | 	'admin/logs': { req: TODO; res: TODO; }; | ||||||
| 	'admin/meta': { req: TODO; res: TODO; }; | 	'admin/meta': { req: NoParams; res: AdminInstanceMetadata; }; | ||||||
| 	'admin/reset-password': { req: TODO; res: TODO; }; | 	'admin/reset-password': { req: TODO; res: TODO; }; | ||||||
| 	'admin/resolve-abuse-user-report': { req: TODO; res: TODO; }; | 	'admin/resolve-abuse-user-report': { req: TODO; res: TODO; }; | ||||||
| 	'admin/resync-chart': { req: TODO; res: TODO; }; | 	'admin/resync-chart': { req: TODO; res: TODO; }; | ||||||
|  |  | ||||||
|  | @ -346,6 +346,11 @@ export type DetailedInstanceMetadata = LiteInstanceMetadata & { | ||||||
| 
 | 
 | ||||||
| export type InstanceMetadata = LiteInstanceMetadata | DetailedInstanceMetadata; | export type InstanceMetadata = LiteInstanceMetadata | DetailedInstanceMetadata; | ||||||
| 
 | 
 | ||||||
|  | export type AdminInstanceMetadata = DetailedInstanceMetadata & { | ||||||
|  | 	// TODO: There are more fields.
 | ||||||
|  | 	blockedHosts: string[]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| export type ServerInfo = { | export type ServerInfo = { | ||||||
| 	machine: string; | 	machine: string; | ||||||
| 	cpu: { | 	cpu: { | ||||||
|  | @ -482,7 +487,7 @@ export type Blocking = { | ||||||
| 
 | 
 | ||||||
| export type Instance = { | export type Instance = { | ||||||
| 	id: ID; | 	id: ID; | ||||||
| 	caughtAt: DateString; | 	firstRetrievedAt: DateString; | ||||||
| 	host: string; | 	host: string; | ||||||
| 	usersCount: number; | 	usersCount: number; | ||||||
| 	notesCount: number; | 	notesCount: number; | ||||||
|  | @ -496,6 +501,7 @@ export type Instance = { | ||||||
| 	lastCommunicatedAt: DateString; | 	lastCommunicatedAt: DateString; | ||||||
| 	isNotResponding: boolean; | 	isNotResponding: boolean; | ||||||
| 	isSuspended: boolean; | 	isSuspended: boolean; | ||||||
|  | 	isBlocked: boolean; | ||||||
| 	softwareName: string | null; | 	softwareName: string | null; | ||||||
| 	softwareVersion: string | null; | 	softwareVersion: string | null; | ||||||
| 	openRegistrations: boolean | null; | 	openRegistrations: boolean | null; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue