show account migration info / controls in admin-user

This commit is contained in:
Hazelnoot 2025-09-14 20:56:01 -04:00
parent 800b780267
commit 42470f099a
3 changed files with 117 additions and 12 deletions

40
locales/index.d.ts vendored
View file

@ -13633,6 +13633,46 @@ export interface Locale extends ILocale {
* Enable all write/edit permissions * Enable all write/edit permissions
*/ */
"enableAllWrite": string; "enableAllWrite": string;
/**
* New account
*/
"newAccount": string;
/**
* Previous accounts
*/
"previousAccounts": string;
/**
* Previous account IDs:
*/
"previousAccountIds": string;
/**
* Previous account URIs:
*/
"previousAccountUris": string;
/**
* Note: this list is provided by the user and is not verified.
*/
"previousAccountsNotVerified": string;
/**
* Migrated at
*/
"accountMovedAt": string;
/**
* Migrated to
*/
"accountMovedTo": string;
/**
* Restart account migration
*/
"restartMigration": string;
/**
* Account migration was last attempted on {date}. If the migration failed or was incomplete, then you may click this button to restart the process.
*/
"restartMigrationDescription": ParameterizedString<"date">;
/**
* Are you sure you want to restart this account migration?
*/
"restartMigrationConfirm": string;
} }
declare const locales: { declare const locales: {
[lang: string]: Locale; [lang: string]: Locale;

View file

@ -8,6 +8,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<FormSuspense v-if="init" :p="init"> <FormSuspense v-if="init" :p="init">
<div v-if="user && info"> <div v-if="user && info">
<div v-if="tab === 'overview'" class="_gaps"> <div v-if="tab === 'overview'" class="_gaps">
<MkAccountMoved v-if="user.movedToUri" :movedTo="user.movedTo" :movedToUri="user.movedToUri"/>
<div class="aeakzknw"> <div class="aeakzknw">
<MkAvatar class="avatar" :user="user" indicator link preview/> <MkAvatar class="avatar" :user="user" indicator link preview/>
<div class="body"> <div class="body">
@ -104,6 +106,44 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</MkFolder> </MkFolder>
<MkFolder v-if="info.movedTo || info.alsoKnownAs" :sticky="false">
<template #icon><i class="ph-airplane ph-bold ph-lg"></i></template>
<template #label>{{ i18n.ts.accountMigration }}</template>
<FormSection v-if="info.movedTo" first>
<template #label>{{ i18n.ts.newAccount }}</template>
<div style="display: flex; flex-direction: column; gap: 1em;">
<MkKeyValue v-if="info.movedAt" oneline>
<template #key>{{ i18n.ts.accountMigratedOn }}</template>
<template #value><MkTime :time="info.movedAt" :mode="'detail'"/></template>
</MkKeyValue>
<MkKeyValue oneline>
<template #key>{{ i18n.ts.accountMigratedTo }}</template>
<template #value>
<MkMention v-if="info.movedTo.user" :username="info.movedTo.user.username" :host="info.movedTo.user.host ?? localHost"/>
<MkLink v-else :url="info.movedTo.uri"/>
</template>
</MkKeyValue>
<div v-if="iAmAdmin" class="_gaps_s">
<MkInfo>{{ i18n.ts.restartMigrationDescription }}</MkInfo>
<MkButton inline @click="restartMigration"><i class="ph-airplane-takeoff ph-bold ph-lg"></i> {{ i18n.ts.restartMigration }}</MkButton>
</div>
</div>
</FormSection>
<FormSection v-if="info.alsoKnownAs.length > 0">
<template #label>{{ i18n.ts.previousAccounts }}</template>
<ul style="display: flex; flex-direction: column; gap: 1em;">
<li v-for="aka of info.alsoKnownAs">
<MkMention v-if="aka.user" :username="aka.user.username" :host="aka.user.host ?? localHost"/>
<MkLink v-else :url="aka.uri"/>
</li>
</ul>
</FormSection>
</MkFolder>
<MkFolder v-if="iAmModerator" :defaultOpen="moderationNote.length > 0" :sticky="false"> <MkFolder v-if="iAmModerator" :defaultOpen="moderationNote.length > 0" :sticky="false">
<template #icon><i class="ph-stamp ph-bold ph-lg"></i></template> <template #icon><i class="ph-stamp ph-bold ph-lg"></i></template>
<template #label>{{ i18n.ts.moderationNote }}</template> <template #label>{{ i18n.ts.moderationNote }}</template>
@ -116,17 +156,15 @@ SPDX-License-Identifier: AGPL-3.0-only
<FormSection v-if="user?.host"> <FormSection v-if="user?.host">
<template #label>{{ i18n.ts.activityPub }}</template> <template #label>{{ i18n.ts.activityPub }}</template>
<div class="_gaps_m"> <div style="display: flex; flex-direction: column; gap: 1em;">
<div style="display: flex; flex-direction: column; gap: 1em;"> <MkKeyValue oneline>
<MkKeyValue oneline> <template #key>{{ i18n.ts.instanceInfo }}</template>
<template #key>{{ i18n.ts.instanceInfo }}</template> <template #value><MkA :to="`/instance-info/${user.host}`" class="_link">{{ user.host }} <i class="ti ti-chevron-right"></i></MkA></template>
<template #value><MkA :to="`/instance-info/${user.host}`" class="_link">{{ user.host }} <i class="ti ti-chevron-right"></i></MkA></template> </MkKeyValue>
</MkKeyValue> <MkKeyValue oneline>
<MkKeyValue oneline> <template #key>{{ i18n.ts.updatedAt }}</template>
<template #key>{{ i18n.ts.updatedAt }}</template> <template #value><MkTime mode="detail" :time="user.lastFetchedAt"/></template>
<template #value><MkTime mode="detail" :time="user.lastFetchedAt"/></template> </MkKeyValue>
</MkKeyValue>
</div>
</div> </div>
</FormSection> </FormSection>
@ -279,7 +317,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { computed, defineAsyncComponent, watch, ref } from 'vue'; import { computed, defineAsyncComponent, watch, ref } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { url } from '@@/js/config.js'; import { host as localHost, url } from '@@/js/config.js';
import type { Badge } from '@/components/SkBadgeStrip.vue'; import type { Badge } from '@/components/SkBadgeStrip.vue';
import type { ChartSrc } from '@/components/MkChart.vue'; import type { ChartSrc } from '@/components/MkChart.vue';
import MkChart from '@/components/MkChart.vue'; import MkChart from '@/components/MkChart.vue';
@ -307,6 +345,9 @@ import MkInput from '@/components/MkInput.vue';
import MkNumber from '@/components/MkNumber.vue'; import MkNumber from '@/components/MkNumber.vue';
import { copyToClipboard } from '@/utility/copy-to-clipboard'; import { copyToClipboard } from '@/utility/copy-to-clipboard';
import SkBadgeStrip from '@/components/SkBadgeStrip.vue'; import SkBadgeStrip from '@/components/SkBadgeStrip.vue';
import MkAccountMoved from '@/components/MkAccountMoved.vue';
import MkLink from '@/components/MkLink.vue';
import MkMention from '@/components/MkMention.vue';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
userId: string; userId: string;
@ -730,6 +771,19 @@ function editAnnouncement(announcement) {
}); });
} }
async function restartMigration() {
const confirm = await os.confirm({
type: 'question',
title: i18n.ts.restartMigration,
text: i18n.ts.restartMigrationConfirm,
});
if (confirm.canceled) return;
await os.promiseDialog(async () => {
await misskeyApi('admin/restart-migration', { userId: props.userId });
await refreshUser();
});
}
watch(() => props.userId, () => { watch(() => props.userId, () => {
init.value = createFetcher(); init.value = createFetcher();
}, { }, {

View file

@ -721,3 +721,14 @@ grantSharedAccessSuccess2: "Shared access has been granted to {num} users."
tokenHasNoPermissionsConfirm: "Are you sure you want to create a token with no permissions?" tokenHasNoPermissionsConfirm: "Are you sure you want to create a token with no permissions?"
enableAllRead: "Enable all read-only permissions" enableAllRead: "Enable all read-only permissions"
enableAllWrite: "Enable all write/edit permissions" enableAllWrite: "Enable all write/edit permissions"
newAccount: "New account"
previousAccounts: "Previous accounts"
previousAccountIds: "Previous account IDs:"
previousAccountUris: "Previous account URIs:"
previousAccountsNotVerified: "Note: this list is provided by the user and is not verified."
accountMovedAt: "Migrated at"
accountMovedTo: "Migrated to"
restartMigration: "Restart account migration"
restartMigrationDescription: "Account migration was last attempted on {date}. If the migration failed or was incomplete, then you may click this button to restart the process."
restartMigrationConfirm: "Are you sure you want to restart this account migration?"