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