Add importCompleted notification. Send importCompleted when antenna/customEmoji/muting/userList is imported
The only userImportableEntities that don't notify are blocking and following because they fork off a batch of single Closes #891
This commit is contained in:
parent
69f3c8a58e
commit
a00a3c6841
14 changed files with 104 additions and 7 deletions
8
locales/index.d.ts
vendored
8
locales/index.d.ts
vendored
|
|
@ -10378,6 +10378,10 @@ export interface Locale extends ILocale {
|
||||||
* Scheduled Note was posted
|
* Scheduled Note was posted
|
||||||
*/
|
*/
|
||||||
"scheduledNotePosted": string;
|
"scheduledNotePosted": string;
|
||||||
|
/**
|
||||||
|
* Import of {x} has been completed
|
||||||
|
*/
|
||||||
|
"importOfXCompleted": ParameterizedString<"x">;
|
||||||
};
|
};
|
||||||
"_deck": {
|
"_deck": {
|
||||||
/**
|
/**
|
||||||
|
|
@ -13346,6 +13350,10 @@ export interface Locale extends ILocale {
|
||||||
* Don't delete files used as avatars&c
|
* Don't delete files used as avatars&c
|
||||||
*/
|
*/
|
||||||
"keepFilesInUse": string;
|
"keepFilesInUse": string;
|
||||||
|
/**
|
||||||
|
* this option requires more complicated database queries, you may need to increase the value of db.extra.statement_timeout in the configuration file
|
||||||
|
*/
|
||||||
|
"keepFilesInUseDescription": string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
declare const locales: {
|
declare const locales: {
|
||||||
|
|
|
||||||
|
|
@ -187,6 +187,10 @@ export class NotificationEntityService implements OnModuleInit {
|
||||||
exportedEntity: notification.exportedEntity,
|
exportedEntity: notification.exportedEntity,
|
||||||
fileId: notification.fileId,
|
fileId: notification.fileId,
|
||||||
} : {}),
|
} : {}),
|
||||||
|
...(notification.type === 'importCompleted' ? {
|
||||||
|
importedEntity: notification.importedEntity,
|
||||||
|
fileId: notification.fileId,
|
||||||
|
} : {}),
|
||||||
...(notification.type === 'scheduledNoteFailed' ? {
|
...(notification.type === 'scheduledNoteFailed' ? {
|
||||||
reason: notification.reason,
|
reason: notification.reason,
|
||||||
} : {}),
|
} : {}),
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { userExportableEntities } from '@/types.js';
|
import { userExportableEntities, userImportableEntities } from '@/types.js';
|
||||||
import { MiUser } from './User.js';
|
import { MiUser } from './User.js';
|
||||||
import { MiNote } from './Note.js';
|
import { MiNote } from './Note.js';
|
||||||
import { MiAccessToken } from './AccessToken.js';
|
import { MiAccessToken } from './AccessToken.js';
|
||||||
|
|
@ -92,6 +92,12 @@ export type MiNotification = {
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
exportedEntity: typeof userExportableEntities[number];
|
exportedEntity: typeof userExportableEntities[number];
|
||||||
fileId: MiDriveFile['id'];
|
fileId: MiDriveFile['id'];
|
||||||
|
} | {
|
||||||
|
type: 'importCompleted';
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
importedEntity: typeof userImportableEntities[number];
|
||||||
|
fileId?: MiDriveFile['id'];
|
||||||
} | {
|
} | {
|
||||||
type: 'login';
|
type: 'login';
|
||||||
id: string;
|
id: string;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { notificationTypes, userExportableEntities } from '@/types.js';
|
import { notificationTypes, userExportableEntities, userImportableEntities } from '@/types.js';
|
||||||
|
|
||||||
const baseSchema = {
|
const baseSchema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
|
|
@ -334,6 +334,26 @@ export const packedNotificationSchema = {
|
||||||
format: 'id',
|
format: 'id',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
...baseSchema.properties,
|
||||||
|
type: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
enum: ['importCompleted'],
|
||||||
|
},
|
||||||
|
importedEntity: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
enum: userImportableEntities,
|
||||||
|
},
|
||||||
|
fileId: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
format: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import type { AntennasRepository, UsersRepository } from '@/models/_.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
import { QueueLoggerService } from '../QueueLoggerService.js';
|
||||||
|
import { NotificationService } from '@/core/NotificationService.js';
|
||||||
import { DBAntennaImportJobData } from '../types.js';
|
import { DBAntennaImportJobData } from '../types.js';
|
||||||
import type * as Bull from 'bullmq';
|
import type * as Bull from 'bullmq';
|
||||||
|
|
||||||
|
|
@ -65,6 +66,7 @@ export class ImportAntennasProcessorService {
|
||||||
private queueLoggerService: QueueLoggerService,
|
private queueLoggerService: QueueLoggerService,
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
private globalEventService: GlobalEventService,
|
private globalEventService: GlobalEventService,
|
||||||
|
private notificationService: NotificationService,
|
||||||
) {
|
) {
|
||||||
this.logger = this.queueLoggerService.logger.createSubLogger('import-antennas');
|
this.logger = this.queueLoggerService.logger.createSubLogger('import-antennas');
|
||||||
}
|
}
|
||||||
|
|
@ -106,6 +108,10 @@ export class ImportAntennasProcessorService {
|
||||||
this.logger.debug('Antenna created: ' + result.id);
|
this.logger.debug('Antenna created: ' + result.id);
|
||||||
this.globalEventService.publishInternalEvent('antennaCreated', result);
|
this.globalEventService.publishInternalEvent('antennaCreated', result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.notificationService.createNotification(job.data.user.id, 'importCompleted', {
|
||||||
|
importedEntity: 'antenna',
|
||||||
|
});
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this.logger.error('Error importing antennas:', err);
|
this.logger.error('Error importing antennas:', err);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import { bindThis } from '@/decorators.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { renderInlineError } from '@/misc/render-inline-error.js';
|
import { renderInlineError } from '@/misc/render-inline-error.js';
|
||||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
import { QueueLoggerService } from '../QueueLoggerService.js';
|
||||||
|
import { NotificationService } from '@/core/NotificationService.js';
|
||||||
import type * as Bull from 'bullmq';
|
import type * as Bull from 'bullmq';
|
||||||
import type { DbUserImportJobData } from '../types.js';
|
import type { DbUserImportJobData } from '../types.js';
|
||||||
|
|
||||||
|
|
@ -40,6 +41,7 @@ export class ImportCustomEmojisProcessorService {
|
||||||
private driveService: DriveService,
|
private driveService: DriveService,
|
||||||
private downloadService: DownloadService,
|
private downloadService: DownloadService,
|
||||||
private queueLoggerService: QueueLoggerService,
|
private queueLoggerService: QueueLoggerService,
|
||||||
|
private notificationService: NotificationService,
|
||||||
) {
|
) {
|
||||||
this.logger = this.queueLoggerService.logger.createSubLogger('import-custom-emojis');
|
this.logger = this.queueLoggerService.logger.createSubLogger('import-custom-emojis');
|
||||||
}
|
}
|
||||||
|
|
@ -127,7 +129,12 @@ export class ImportCustomEmojisProcessorService {
|
||||||
|
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|
||||||
this.logger.debug('Imported');
|
this.notificationService.createNotification(job.data.user.id, 'importCompleted', {
|
||||||
|
importedEntity: 'customEmoji',
|
||||||
|
fileId: file.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.logger.debug('Imported', file.name);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.error('Error importing custom emojis:', e as Error);
|
this.logger.error('Error importing custom emojis:', e as Error);
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { renderInlineError } from '@/misc/render-inline-error.js';
|
import { renderInlineError } from '@/misc/render-inline-error.js';
|
||||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
import { QueueLoggerService } from '../QueueLoggerService.js';
|
||||||
|
import { NotificationService } from '@/core/NotificationService.js';
|
||||||
import type * as Bull from 'bullmq';
|
import type * as Bull from 'bullmq';
|
||||||
import type { DbUserImportJobData } from '../types.js';
|
import type { DbUserImportJobData } from '../types.js';
|
||||||
|
|
||||||
|
|
@ -35,6 +36,7 @@ export class ImportMutingProcessorService {
|
||||||
private remoteUserResolveService: RemoteUserResolveService,
|
private remoteUserResolveService: RemoteUserResolveService,
|
||||||
private downloadService: DownloadService,
|
private downloadService: DownloadService,
|
||||||
private queueLoggerService: QueueLoggerService,
|
private queueLoggerService: QueueLoggerService,
|
||||||
|
private notificationService: NotificationService,
|
||||||
) {
|
) {
|
||||||
this.logger = this.queueLoggerService.logger.createSubLogger('import-muting');
|
this.logger = this.queueLoggerService.logger.createSubLogger('import-muting');
|
||||||
}
|
}
|
||||||
|
|
@ -99,6 +101,11 @@ export class ImportMutingProcessorService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.notificationService.createNotification(job.data.user.id, 'importCompleted', {
|
||||||
|
importedEntity: 'muting',
|
||||||
|
fileId: file.id,
|
||||||
|
});
|
||||||
|
|
||||||
this.logger.debug('Imported');
|
this.logger.debug('Imported');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { renderInlineError } from '@/misc/render-inline-error.js';
|
import { renderInlineError } from '@/misc/render-inline-error.js';
|
||||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
import { QueueLoggerService } from '../QueueLoggerService.js';
|
||||||
|
import { NotificationService } from '@/core/NotificationService.js';
|
||||||
import type * as Bull from 'bullmq';
|
import type * as Bull from 'bullmq';
|
||||||
import type { DbUserImportJobData } from '../types.js';
|
import type { DbUserImportJobData } from '../types.js';
|
||||||
|
|
||||||
|
|
@ -43,6 +44,7 @@ export class ImportUserListsProcessorService {
|
||||||
private remoteUserResolveService: RemoteUserResolveService,
|
private remoteUserResolveService: RemoteUserResolveService,
|
||||||
private downloadService: DownloadService,
|
private downloadService: DownloadService,
|
||||||
private queueLoggerService: QueueLoggerService,
|
private queueLoggerService: QueueLoggerService,
|
||||||
|
private notificationService: NotificationService,
|
||||||
) {
|
) {
|
||||||
this.logger = this.queueLoggerService.logger.createSubLogger('import-user-lists');
|
this.logger = this.queueLoggerService.logger.createSubLogger('import-user-lists');
|
||||||
}
|
}
|
||||||
|
|
@ -109,6 +111,11 @@ export class ImportUserListsProcessorService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.notificationService.createNotification(job.data.user.id, 'importCompleted', {
|
||||||
|
importedEntity: 'userList',
|
||||||
|
fileId: file.id,
|
||||||
|
});
|
||||||
|
|
||||||
this.logger.debug('Imported');
|
this.logger.debug('Imported');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ export const notificationTypes = [
|
||||||
'chatRoomInvitationReceived',
|
'chatRoomInvitationReceived',
|
||||||
'achievementEarned',
|
'achievementEarned',
|
||||||
'exportCompleted',
|
'exportCompleted',
|
||||||
|
'importCompleted',
|
||||||
'login',
|
'login',
|
||||||
'createToken',
|
'createToken',
|
||||||
'scheduledNoteFailed',
|
'scheduledNoteFailed',
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,7 @@ export const notificationTypes = [
|
||||||
'chatRoomInvitationReceived',
|
'chatRoomInvitationReceived',
|
||||||
'achievementEarned',
|
'achievementEarned',
|
||||||
'exportCompleted',
|
'exportCompleted',
|
||||||
|
'importCompleted',
|
||||||
'login',
|
'login',
|
||||||
'createToken',
|
'createToken',
|
||||||
'test',
|
'test',
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<div :class="$style.head">
|
<div :class="$style.head">
|
||||||
<MkAvatar v-if="['pollEnded', 'note', 'edited', 'scheduledNotePosted'].includes(notification.type) && 'note' in notification" :class="$style.icon" :user="notification.note.user" link preview/>
|
<MkAvatar v-if="['pollEnded', 'note', 'edited', 'scheduledNotePosted'].includes(notification.type) && 'note' in notification" :class="$style.icon" :user="notification.note.user" link preview/>
|
||||||
<MkAvatar v-else-if="['roleAssigned', 'achievementEarned', 'exportCompleted', 'login', 'createToken', 'scheduledNoteFailed'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/>
|
<MkAvatar v-else-if="['roleAssigned', 'achievementEarned', 'exportCompleted', 'importCompleted', 'login', 'createToken', 'scheduledNoteFailed'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/>
|
||||||
<div v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'" :class="[$style.icon, $style.icon_reactionGroupHeart]"><i class="ph-smiley ph-bold ph-lg" style="line-height: 1;"></i></div>
|
<div v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'" :class="[$style.icon, $style.icon_reactionGroupHeart]"><i class="ph-smiley ph-bold ph-lg" style="line-height: 1;"></i></div>
|
||||||
<div v-else-if="notification.type === 'reaction:grouped'" :class="[$style.icon, $style.icon_reactionGroup]"><i class="ph-smiley ph-bold ph-lg" style="line-height: 1;"></i></div>
|
<div v-else-if="notification.type === 'reaction:grouped'" :class="[$style.icon, $style.icon_reactionGroup]"><i class="ph-smiley ph-bold ph-lg" style="line-height: 1;"></i></div>
|
||||||
<div v-else-if="notification.type === 'renote:grouped'" :class="[$style.icon, $style.icon_renoteGroup]"><i class="ti ti-repeat" style="line-height: 1;"></i></div>
|
<div v-else-if="notification.type === 'renote:grouped'" :class="[$style.icon, $style.icon_renoteGroup]"><i class="ti ti-repeat" style="line-height: 1;"></i></div>
|
||||||
|
|
@ -25,6 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
[$style.t_pollEnded]: notification.type === 'pollEnded',
|
[$style.t_pollEnded]: notification.type === 'pollEnded',
|
||||||
[$style.t_achievementEarned]: notification.type === 'achievementEarned',
|
[$style.t_achievementEarned]: notification.type === 'achievementEarned',
|
||||||
[$style.t_exportCompleted]: notification.type === 'exportCompleted',
|
[$style.t_exportCompleted]: notification.type === 'exportCompleted',
|
||||||
|
[$style.t_importCompleted]: notification.type === 'importCompleted',
|
||||||
[$style.t_login]: notification.type === 'login',
|
[$style.t_login]: notification.type === 'login',
|
||||||
[$style.t_createToken]: notification.type === 'createToken',
|
[$style.t_createToken]: notification.type === 'createToken',
|
||||||
[$style.t_chatRoomInvitationReceived]: notification.type === 'chatRoomInvitationReceived',
|
[$style.t_chatRoomInvitationReceived]: notification.type === 'chatRoomInvitationReceived',
|
||||||
|
|
@ -44,6 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<i v-else-if="notification.type === 'pollEnded'" class="ti ti-chart-arrows"></i>
|
<i v-else-if="notification.type === 'pollEnded'" class="ti ti-chart-arrows"></i>
|
||||||
<i v-else-if="notification.type === 'achievementEarned'" class="ti ti-medal"></i>
|
<i v-else-if="notification.type === 'achievementEarned'" class="ti ti-medal"></i>
|
||||||
<i v-else-if="notification.type === 'exportCompleted'" class="ti ti-archive"></i>
|
<i v-else-if="notification.type === 'exportCompleted'" class="ti ti-archive"></i>
|
||||||
|
<i v-else-if="notification.type === 'importCompleted'" class="ti ti-archive"></i>
|
||||||
<i v-else-if="notification.type === 'login'" class="ti ti-login-2"></i>
|
<i v-else-if="notification.type === 'login'" class="ti ti-login-2"></i>
|
||||||
<i v-else-if="notification.type === 'createToken'" class="ti ti-key"></i>
|
<i v-else-if="notification.type === 'createToken'" class="ti ti-key"></i>
|
||||||
<i v-else-if="notification.type === 'chatRoomInvitationReceived'" class="ti ti-messages"></i>
|
<i v-else-if="notification.type === 'chatRoomInvitationReceived'" class="ti ti-messages"></i>
|
||||||
|
|
@ -75,6 +77,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<span v-else-if="notification.type === 'createToken'">{{ i18n.ts._notification.createToken }}</span>
|
<span v-else-if="notification.type === 'createToken'">{{ i18n.ts._notification.createToken }}</span>
|
||||||
<span v-else-if="notification.type === 'test'">{{ i18n.ts._notification.testNotification }}</span>
|
<span v-else-if="notification.type === 'test'">{{ i18n.ts._notification.testNotification }}</span>
|
||||||
<span v-else-if="notification.type === 'exportCompleted'">{{ i18n.tsx._notification.exportOfXCompleted({ x: exportEntityName[notification.exportedEntity] }) }}</span>
|
<span v-else-if="notification.type === 'exportCompleted'">{{ i18n.tsx._notification.exportOfXCompleted({ x: exportEntityName[notification.exportedEntity] }) }}</span>
|
||||||
|
<span v-else-if="notification.type === 'importCompleted'">{{ i18n.tsx._notification.importOfXCompleted({ x: importEntityName[notification.importedEntity] }) }}</span>
|
||||||
<MkA v-else-if="notification.type === 'follow' || notification.type === 'mention' || notification.type === 'reply' || notification.type === 'renote' || notification.type === 'quote' || notification.type === 'reaction' || notification.type === 'receiveFollowRequest' || notification.type === 'followRequestAccepted'" v-user-preview="notification.user.id" :class="$style.headerName" :to="userPage(notification.user)"><MkUserName :user="notification.user"/></MkA>
|
<MkA v-else-if="notification.type === 'follow' || notification.type === 'mention' || notification.type === 'reply' || notification.type === 'renote' || notification.type === 'quote' || notification.type === 'reaction' || notification.type === 'receiveFollowRequest' || notification.type === 'followRequestAccepted'" v-user-preview="notification.user.id" :class="$style.headerName" :to="userPage(notification.user)"><MkUserName :user="notification.user"/></MkA>
|
||||||
<span v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'">{{ i18n.tsx._notification.likedBySomeUsers({ n: getActualReactedUsersCount(notification) }) }}</span>
|
<span v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'">{{ i18n.tsx._notification.likedBySomeUsers({ n: getActualReactedUsersCount(notification) }) }}</span>
|
||||||
<span v-else-if="notification.type === 'reaction:grouped'">{{ i18n.tsx._notification.reactedBySomeUsers({ n: getActualReactedUsersCount(notification) }) }}</span>
|
<span v-else-if="notification.type === 'reaction:grouped'">{{ i18n.tsx._notification.reactedBySomeUsers({ n: getActualReactedUsersCount(notification) }) }}</span>
|
||||||
|
|
@ -122,7 +125,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkA v-else-if="notification.type === 'achievementEarned'" :class="$style.text" to="/my/achievements">
|
<MkA v-else-if="notification.type === 'achievementEarned'" :class="$style.text" to="/my/achievements">
|
||||||
{{ i18n.ts._achievements._types['_' + notification.achievement].title }}
|
{{ i18n.ts._achievements._types['_' + notification.achievement].title }}
|
||||||
</MkA>
|
</MkA>
|
||||||
<MkA v-else-if="notification.type === 'exportCompleted'" :class="$style.text" :to="`/my/drive/file/${notification.fileId}`">
|
<MkA v-else-if="notification.type === 'exportCompleted' || (notification.type === 'importCompleted' && notification.fileId)" :class="$style.text" :to="`/my/drive/file/${notification.fileId}`">
|
||||||
{{ i18n.ts.showFile }}
|
{{ i18n.ts.showFile }}
|
||||||
</MkA>
|
</MkA>
|
||||||
<MkA v-else-if="notification.type === 'createToken'" :class="$style.text" to="/settings/apps">
|
<MkA v-else-if="notification.type === 'createToken'" :class="$style.text" to="/settings/apps">
|
||||||
|
|
@ -219,6 +222,7 @@ const props = withDefaults(defineProps<{
|
||||||
});
|
});
|
||||||
|
|
||||||
type ExportCompletedNotification = Misskey.entities.Notification & { type: 'exportCompleted' };
|
type ExportCompletedNotification = Misskey.entities.Notification & { type: 'exportCompleted' };
|
||||||
|
type ImportCompletedNotification = Misskey.entities.Notification & { type: 'importCompleted' };
|
||||||
|
|
||||||
const exportEntityName = {
|
const exportEntityName = {
|
||||||
antenna: i18n.ts.antennas,
|
antenna: i18n.ts.antennas,
|
||||||
|
|
@ -232,6 +236,15 @@ const exportEntityName = {
|
||||||
userList: i18n.ts.lists,
|
userList: i18n.ts.lists,
|
||||||
} as const satisfies Record<ExportCompletedNotification['exportedEntity'], string>;
|
} as const satisfies Record<ExportCompletedNotification['exportedEntity'], string>;
|
||||||
|
|
||||||
|
const importEntityName = {
|
||||||
|
antenna: i18n.ts.antennas,
|
||||||
|
blocking: i18n.ts.blockedUsers,
|
||||||
|
customEmoji: i18n.ts.customEmojis,
|
||||||
|
following: i18n.ts.following,
|
||||||
|
muting: i18n.ts.mutedUsers,
|
||||||
|
userList: i18n.ts.lists,
|
||||||
|
} as const satisfies Record<ImportCompletedNotification['importedEntity'], string>;
|
||||||
|
|
||||||
const followRequestDone = ref(true);
|
const followRequestDone = ref(true);
|
||||||
const userDetailed: Ref<Misskey.entities.UserDetailed | null> = ref(null);
|
const userDetailed: Ref<Misskey.entities.UserDetailed | null> = ref(null);
|
||||||
|
|
||||||
|
|
@ -398,7 +411,7 @@ function getActualReactedUsersCount(notification: Misskey.entities.Notification)
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.t_exportCompleted {
|
.t_exportCompleted, .t_importCompleted {
|
||||||
background: var(--eventOther);
|
background: var(--eventOther);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ import MkFeatureBanner from '@/components/MkFeatureBanner.vue';
|
||||||
|
|
||||||
const $i = ensureSignin();
|
const $i = ensureSignin();
|
||||||
|
|
||||||
const nonConfigurableNotificationTypes = ['note', 'roleAssigned', 'followRequestAccepted', 'test', 'exportCompleted'] satisfies (typeof notificationTypes[number])[] as string[];
|
const nonConfigurableNotificationTypes = ['note', 'roleAssigned', 'followRequestAccepted', 'test', 'exportCompleted', 'importCompleted'] satisfies (typeof notificationTypes[number])[] as string[];
|
||||||
|
|
||||||
const onlyOnOrOffNotificationTypes = ['app', 'achievementEarned', 'login', 'createToken', 'scheduledNoteFailed', 'scheduledNotePosted'] satisfies (typeof notificationTypes[number])[] as string[];
|
const onlyOnOrOffNotificationTypes = ['app', 'achievementEarned', 'login', 'createToken', 'scheduledNoteFailed', 'scheduledNotePosted'] satisfies (typeof notificationTypes[number])[] as string[];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -235,6 +235,22 @@ async function composeNotification(data: PushNotificationDataMap[keyof PushNotif
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'importCompleted': {
|
||||||
|
const entityName = {
|
||||||
|
antenna: i18n.ts.antennas,
|
||||||
|
blocking: i18n.ts.blockedUsers,
|
||||||
|
customEmoji: i18n.ts.customEmojis,
|
||||||
|
following: i18n.ts.following,
|
||||||
|
muting: i18n.ts.mutedUsers,
|
||||||
|
userList: i18n.ts.lists,
|
||||||
|
} as const satisfies Record<typeof data.body.importedEntity, string>;
|
||||||
|
|
||||||
|
return [i18n.tsx._notification.importOfXCompleted({ x: entityName[data.body.importedEntity] }), {
|
||||||
|
badge: iconUrl('circle-check'),
|
||||||
|
data,
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
case 'pollEnded':
|
case 'pollEnded':
|
||||||
return [i18n.ts._notification.pollEnded, {
|
return [i18n.ts._notification.pollEnded, {
|
||||||
body: data.body.note.text ?? '',
|
body: data.body.note.text ?? '',
|
||||||
|
|
|
||||||
|
|
@ -314,6 +314,7 @@ _notification:
|
||||||
edited: "Note got edited"
|
edited: "Note got edited"
|
||||||
scheduledNoteFailed: "Posting scheduled note failed"
|
scheduledNoteFailed: "Posting scheduled note failed"
|
||||||
scheduledNotePosted: "Scheduled Note was posted"
|
scheduledNotePosted: "Scheduled Note was posted"
|
||||||
|
importOfXCompleted: "Import of {x} has been completed"
|
||||||
_types:
|
_types:
|
||||||
renote: "Boosts"
|
renote: "Boosts"
|
||||||
edited: "Edits"
|
edited: "Edits"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue