diff --git a/locales/index.d.ts b/locales/index.d.ts index 728b112e02..5cab76136a 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1098,6 +1098,8 @@ export interface Locale { "doYouAgree": string; "beSureToReadThisAsItIsImportant": string; "iHaveReadXCarefullyAndAgree": string; + "dialog": string; + "icon": string; "_announcement": { "forExistingUsers": string; "forExistingUsersDescription": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index f344ebedd7..2db6dcf283 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1096,6 +1096,7 @@ doYouAgree: "同意しますか?" beSureToReadThisAsItIsImportant: "重要ですので必ずお読みください。" iHaveReadXCarefullyAndAgree: "「{x}」の内容をよく読み、同意します。" dialog: "ダイアログ" +icon: "アイコン" _announcement: forExistingUsers: "既存ユーザーのみ" diff --git a/packages/backend/migration/1691657412740-refine-announcement-2.js b/packages/backend/migration/1691657412740-refine-announcement-2.js new file mode 100644 index 0000000000..8791f99f44 --- /dev/null +++ b/packages/backend/migration/1691657412740-refine-announcement-2.js @@ -0,0 +1,11 @@ +export class RefineAnnouncement21691657412740 { + name = 'RefineAnnouncement21691657412740' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "announcement" ADD "icon" character varying(256) NOT NULL DEFAULT 'info'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "announcement" DROP COLUMN "icon"`); + } +} diff --git a/packages/backend/src/core/AnnouncementService.ts b/packages/backend/src/core/AnnouncementService.ts index f8e1433d8f..bf7ab49b88 100644 --- a/packages/backend/src/core/AnnouncementService.ts +++ b/packages/backend/src/core/AnnouncementService.ts @@ -66,6 +66,7 @@ export class AnnouncementService { title: values.title, text: values.text, imageUrl: values.imageUrl, + icon: values.icon, display: values.display, forExistingUsers: values.forExistingUsers, needConfirmationToRead: values.needConfirmationToRead, @@ -118,6 +119,7 @@ export class AnnouncementService { text: announcement.text, title: announcement.title, imageUrl: announcement.imageUrl, + icon: announcement.icon, display: announcement.display, needConfirmationToRead: announcement.needConfirmationToRead, forYou: announcement.userId === me?.id, diff --git a/packages/backend/src/models/entities/Announcement.ts b/packages/backend/src/models/entities/Announcement.ts index ee5d1da7ea..18c26faab0 100644 --- a/packages/backend/src/models/entities/Announcement.ts +++ b/packages/backend/src/models/entities/Announcement.ts @@ -39,6 +39,13 @@ export class Announcement { }) public imageUrl: string | null; + // info, warning, error, success + @Column('varchar', { + length: 256, nullable: false, + default: 'info', + }) + public icon: string; + // normal ... お知らせページ掲載 // banner ... お知らせページ掲載 + バナー表示 // dialog ... お知らせページ掲載 + ダイアログ表示 diff --git a/packages/backend/src/models/json-schema/announcement.ts b/packages/backend/src/models/json-schema/announcement.ts index 12dec96f3c..c7e24c7f29 100644 --- a/packages/backend/src/models/json-schema/announcement.ts +++ b/packages/backend/src/models/json-schema/announcement.ts @@ -34,6 +34,10 @@ export const packedAnnouncementSchema = { type: 'string', optional: false, nullable: true, }, + icon: { + type: 'string', + optional: false, nullable: false, + }, display: { type: 'string', optional: false, nullable: false, diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts index 454379cbe6..6c5520c2ef 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts @@ -55,6 +55,7 @@ export const paramDef = { title: { type: 'string', minLength: 1 }, text: { type: 'string', minLength: 1 }, imageUrl: { type: 'string', nullable: true, minLength: 1 }, + icon: { type: 'string', enum: ['info', 'warning', 'error', 'success'], default: 'info' }, display: { type: 'string', enum: ['normal', 'banner', 'dialog'], default: 'normal' }, forExistingUsers: { type: 'boolean', default: false }, needConfirmationToRead: { type: 'boolean', default: false }, @@ -76,6 +77,7 @@ export default class extends Endpoint { title: ps.title, text: ps.text, imageUrl: ps.imageUrl, + icon: ps.icon, display: ps.display, forExistingUsers: ps.forExistingUsers, needConfirmationToRead: ps.needConfirmationToRead, diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts index 24709843b6..b776b1cdcc 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts @@ -108,6 +108,7 @@ export default class extends Endpoint { title: announcement.title, text: announcement.text, imageUrl: announcement.imageUrl, + icon: announcement.icon, display: announcement.display, isActive: announcement.isActive, forExistingUsers: announcement.forExistingUsers, diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts index e97004c343..e007769101 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts @@ -31,12 +31,13 @@ export const paramDef = { title: { type: 'string', minLength: 1 }, text: { type: 'string', minLength: 1 }, imageUrl: { type: 'string', nullable: true, minLength: 0 }, + icon: { type: 'string', enum: ['info', 'warning', 'error', 'success'] }, display: { type: 'string', enum: ['normal', 'banner', 'dialog'] }, forExistingUsers: { type: 'boolean' }, needConfirmationToRead: { type: 'boolean' }, isActive: { type: 'boolean' }, }, - required: ['id', 'title', 'text', 'imageUrl', 'display', 'forExistingUsers', 'needConfirmationToRead', 'isActive'], + required: ['id', 'title', 'text', 'imageUrl', 'icon', 'display', 'forExistingUsers', 'needConfirmationToRead', 'isActive'], } as const; // eslint-disable-next-line import/no-default-export @@ -58,6 +59,7 @@ export default class extends Endpoint { /* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- 空の文字列の場合、nullを渡すようにするため */ imageUrl: ps.imageUrl || null, display: ps.display, + icon: ps.icon, forExistingUsers: ps.forExistingUsers, needConfirmationToRead: ps.needConfirmationToRead, isActive: ps.isActive, diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts index 058cb4144d..9ab1f6e14c 100644 --- a/packages/frontend/src/boot/main-boot.ts +++ b/packages/frontend/src/boot/main-boot.ts @@ -89,7 +89,14 @@ export async function mainBoot() { }, {}, 'closed'); } - // TODO: announcementCreatedイベント監視 + stream.on('announcementCreated', (ev) => { + const announcement = ev.announcement; + if (announcement.display === 'dialog') { + popup(defineAsyncComponent(() => import('@/components/MkAnnouncementDialog.vue')), { + announcement, + }, {}, 'closed'); + } + }); if ($i.isDeleted) { alert({ diff --git a/packages/frontend/src/components/MkAnnouncementDialog.vue b/packages/frontend/src/components/MkAnnouncementDialog.vue index 5c4a6adffb..29134ecef1 100644 --- a/packages/frontend/src/components/MkAnnouncementDialog.vue +++ b/packages/frontend/src/components/MkAnnouncementDialog.vue @@ -16,6 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only