From e649e2ea6c01f69a78c60bc5ee66da72f98752f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=AC=B4=EB=9D=BC=EC=BF=A0=EB=AA=A8?= Date: Thu, 25 Jul 2024 17:56:38 +0900 Subject: [PATCH] feat!: brand-new onboarding page --- cypress/e2e/basic.cy.ts | 59 +-- cypress/e2e/router.cy.ts | 6 - locales/ja-JP.yml | 29 ++ locales/ko-KR.yml | 29 ++ .../1708933788259-canSkipInitialTutorial.js | 16 + .../src/core/entities/MetaEntityService.ts | 1 + packages/backend/src/models/Meta.ts | 5 + .../backend/src/models/json-schema/meta.ts | 4 + .../src/server/api/endpoints/admin/meta.ts | 5 + .../server/api/endpoints/admin/update-meta.ts | 5 + packages/frontend/.storybook/generate.tsx | 2 - .../frontend/assets/tutorial/reaction.png | Bin 0 -> 42113 bytes packages/frontend/package.json | 1 + packages/frontend/src/_boot_.ts | 2 +- packages/frontend/src/boot/common.ts | 11 +- packages/frontend/src/boot/main-boot.ts | 6 - .../frontend/src/components/MkPostForm.vue | 4 + .../src/components/MkSignupDialog.form.vue | 2 +- ...ue => MkTutorial.FollowUsers.UserCard.vue} | 0 ....Follow.vue => MkTutorial.FollowUsers.vue} | 17 +- ...ialDialog.Note.vue => MkTutorial.Note.vue} | 21 +- ...g.PostNote.vue => MkTutorial.PostNote.vue} | 2 +- .../components/MkTutorial.PrivacySettings.vue | 55 +++ ...log.Profile.vue => MkTutorial.Profile.vue} | 0 ...Sensitive.vue => MkTutorial.Sensitive.vue} | 2 +- ...g.Timeline.vue => MkTutorial.Timeline.vue} | 3 +- .../frontend/src/components/MkTutorial.vue | 327 +++++++++++++++ .../src/components/MkTutorialDialog.vue | 162 +------ .../MkUserSetupDialog.Follow.stories.impl.ts | 56 --- .../MkUserSetupDialog.Privacy.stories.impl.ts | 36 -- .../components/MkUserSetupDialog.Privacy.vue | 71 ---- .../MkUserSetupDialog.Profile.stories.impl.ts | 36 -- .../MkUserSetupDialog.User.stories.impl.ts | 37 -- .../MkUserSetupDialog.stories.impl.ts | 56 --- .../src/components/MkUserSetupDialog.vue | 258 ------------ .../frontend/src/components/form/link.vue | 44 +- .../frontend/src/pages/admin/moderation.vue | 8 + packages/frontend/src/pages/onboarding.vue | 394 ++++++++++++++++++ .../frontend/src/pages/signup-complete.vue | 2 +- packages/frontend/src/router/definition.ts | 4 + .../frontend/src/scripts/reaction-picker.ts | 4 + packages/misskey-js/src/autogen/types.ts | 3 + 42 files changed, 982 insertions(+), 803 deletions(-) create mode 100644 packages/backend/migration/1708933788259-canSkipInitialTutorial.js create mode 100644 packages/frontend/assets/tutorial/reaction.png rename packages/frontend/src/components/{MkUserSetupDialog.User.vue => MkTutorial.FollowUsers.UserCard.vue} (100%) rename packages/frontend/src/components/{MkUserSetupDialog.Follow.vue => MkTutorial.FollowUsers.vue} (76%) rename packages/frontend/src/components/{MkTutorialDialog.Note.vue => MkTutorial.Note.vue} (82%) rename packages/frontend/src/components/{MkTutorialDialog.PostNote.vue => MkTutorial.PostNote.vue} (96%) create mode 100644 packages/frontend/src/components/MkTutorial.PrivacySettings.vue rename packages/frontend/src/components/{MkUserSetupDialog.Profile.vue => MkTutorial.Profile.vue} (100%) rename packages/frontend/src/components/{MkTutorialDialog.Sensitive.vue => MkTutorial.Sensitive.vue} (95%) rename packages/frontend/src/components/{MkTutorialDialog.Timeline.vue => MkTutorial.Timeline.vue} (93%) create mode 100644 packages/frontend/src/components/MkTutorial.vue delete mode 100644 packages/frontend/src/components/MkUserSetupDialog.Follow.stories.impl.ts delete mode 100644 packages/frontend/src/components/MkUserSetupDialog.Privacy.stories.impl.ts delete mode 100644 packages/frontend/src/components/MkUserSetupDialog.Privacy.vue delete mode 100644 packages/frontend/src/components/MkUserSetupDialog.Profile.stories.impl.ts delete mode 100644 packages/frontend/src/components/MkUserSetupDialog.User.stories.impl.ts delete mode 100644 packages/frontend/src/components/MkUserSetupDialog.stories.impl.ts delete mode 100644 packages/frontend/src/components/MkUserSetupDialog.vue create mode 100644 packages/frontend/src/pages/onboarding.vue diff --git a/cypress/e2e/basic.cy.ts b/cypress/e2e/basic.cy.ts index d2525e0a7..5f781fc91 100644 --- a/cypress/e2e/basic.cy.ts +++ b/cypress/e2e/basic.cy.ts @@ -127,9 +127,9 @@ describe('After user signup', () => { cy.get('[data-cy-signin-password] input').type('alice1234{enter}'); cy.wait('@signin'); - }); + }); - it('suspend', function() { + it('suspend', function () { cy.request('POST', '/api/admin/suspend-user', { i: this.admin.token, userId: this.alice.id, @@ -146,56 +146,6 @@ describe('After user signup', () => { }); }); -describe('After user signed in', () => { - beforeEach(() => { - cy.resetState(); - - // インスタンス初期セットアップ - cy.registerUser('admin', 'pass', true); - - // ユーザー作成 - cy.registerUser('alice', 'alice1234'); - - cy.login('alice', 'alice1234'); - }); - - afterEach(() => { - // テスト終了直前にページ遷移するようなテストケース(例えばアカウント作成)だと、たぶんCypressのバグでブラウザの内容が次のテストケースに引き継がれてしまう(例えばアカウントが作成し終わった段階からテストが始まる)。 - // waitを入れることでそれを防止できる - cy.wait(1000); - }); - - it('successfully loads', () => { - // 表示に時間がかかるのでデフォルト秒数だとタイムアウトする - cy.get('[data-cy-user-setup-continue]', { timeout: 30000 }).should('be.visible'); - }); - - it('account setup wizard', () => { - // 表示に時間がかかるのでデフォルト秒数だとタイムアウトする - cy.get('[data-cy-user-setup-continue]', { timeout: 30000 }).click(); - - cy.get('[data-cy-user-setup-user-name] input').type('ありす'); - cy.get('[data-cy-user-setup-user-description] textarea').type('ほげ'); - // TODO: アイコン設定テスト - - cy.get('[data-cy-user-setup-continue]').click(); - - // プライバシー設定 - - cy.get('[data-cy-user-setup-continue]').click(); - - // フォローはスキップ - - cy.get('[data-cy-user-setup-continue]').click(); - - // プッシュ通知設定はスキップ - - cy.get('[data-cy-user-setup-continue]').click(); - - cy.get('[data-cy-user-setup-continue]').click(); - }); -}); - describe('After user setup', () => { beforeEach(() => { cy.resetState(); @@ -207,11 +157,6 @@ describe('After user setup', () => { cy.registerUser('alice', 'alice1234'); cy.login('alice', 'alice1234'); - - // アカウント初期設定ウィザード - // 表示に時間がかかるのでデフォルト秒数だとタイムアウトする - cy.get('[data-cy-user-setup] [data-cy-modal-window-close]', { timeout: 30000 }).click(); - cy.get('[data-cy-modal-dialog-ok]').click(); }); afterEach(() => { diff --git a/cypress/e2e/router.cy.ts b/cypress/e2e/router.cy.ts index 8d8fb3af3..7cc5d55ad 100644 --- a/cypress/e2e/router.cy.ts +++ b/cypress/e2e/router.cy.ts @@ -16,12 +16,6 @@ describe('Router transition', () => { cy.registerUser('alice', 'alice1234'); cy.login('alice', 'alice1234'); - - // アカウント初期設定ウィザード - // 表示に時間がかかるのでデフォルト秒数だとタイムアウトする - cy.get('[data-cy-user-setup] [data-cy-modal-window-close]', { timeout: 30000 }).click(); - cy.wait(500); - cy.get('[data-cy-modal-dialog-ok]').click(); }); it('redirect to user profile', () => { diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 92dd79110..1fff58af9 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1276,6 +1276,8 @@ youAreHidingSensitiveInformation: "「プライベートモード」で非表示 temporarilySeeThis: "無視して表示する" sensitiveDoubleClickRequired: "敏感な内容のメディアをダブルクリックして表示" mutualLink: "相互リンク" +prohibitSkippingInitialTutorial: "チュートリアルをスキップできないようにする" +prohibitSkippingInitialTutorialDescription: "新規登録したユーザーに表示されるチュートリアルをスキップできないようにします。チュートリアルを完了しなかったりチュートリアルページを回避したりした場合でも、強制的にリダイレクトされます。" _bubbleGame: howToPlay: "遊び方" @@ -1382,6 +1384,9 @@ _initialTutorial: global: "接続している他のすべてのサーバーからの投稿を見られます。" description2: "それぞれのタイムラインは、画面上部でいつでも切り替えられます。" description3: "その他にも、リストタイムラインやチャンネルタイムラインなどがあります。詳しくは{link}をご覧ください。" + _followUsers: + description1: "誰もフォローしていない状態だと、ホームタイムラインには何も表示されません。" + description2: "タイムラインを構築するため、気になるユーザーをフォローしてみましょう。" _postNote: title: "ノートの投稿設定" description1: "Misskeyにノートを投稿する際には、様々なオプションの設定が可能です。投稿フォームはこのようになっています。" @@ -1410,9 +1415,33 @@ _initialTutorial: method: "添付ファイルをセンシティブにする際は、そのファイルをクリックしてメニューを開き、「センシティブとして設定」をクリックします。" sensitiveSucceeded: "ファイルを添付する際は、サーバーのガイドラインに従ってセンシティブを適切に設定してください。" doItToContinue: "画像をセンシティブに設定すると先に進めるようになります。" + _pushNotification: + description: "プッシュ通知を有効にすると{name}の通知をお使いのデバイスで受け取ることができます。" + _privacySettings: + title: "プライバシー設定" + description1: "多くのユーザーが利用しているプライバシー関連の設定項目をリストアップしました。必要に応じて変更してください。" + theseSettingsCanEditLater: "これらの設定は後から変更できます。" + youCanEditMoreSettingsInSettingsPageLater: "この他にも様々な設定を「設定」ページから行えます。ぜひ後で確認してみてください。" _done: title: "チュートリアルは終了です🎉" description: "ここで紹介した機能はほんの一部にすぎません。Misskeyの使い方をより詳しく知るには、{link}をご覧ください。" + haveFun: "{name}をお楽しみください!" + youCanReferTutorialBy: "このチュートリアルは、「もっと!」→「情報」→「チュートリアルを見る」からいつでも見返すことができます。" + _onboardingLanding: + accountCreated: "アカウントの作成が完了しました!" + welcomeToX: "ようこそ、{name}へ!" + description: "「{name}に登録したは良いものの、どう使えばいいか分からない…💦」といったことを防ぐために、まずはMisskeyの基本的な使い方を学びましょう。" + takesAbout: "このチュートリアルの所要時間は{min}分程度です。\nチュートリアルを完了すると実績が解除されます。" + adminForcesToTakeTutorial: "このサーバーの管理者は新規ユーザーにチュートリアルを完了することを義務付けています。\nチュートリアルを完了するまでMisskeyを使い始めることはできません。" + _onboardingDone: + description: "お疲れ様でした!次のステップに進んで、{name}をもっと楽しめるようにしましょう。" + backToOriginalPath: "元のページに戻る" + backToOriginalPathDescription: "あなたがアクセスしようとしていたページに戻ります。" + profile: "プロフィール設定" + profileDescription: "他のユーザーが親しみやすいように、プロフィールをつくりましょう。" + exploreDescription: "人気のノートやユーザーを見つけて交流をはじめましょう。" + goToTimeline: "ホーム画面に進む" + goToTimelineDescription: "設定等を行わず、通常のホーム画面(タイムライン)に進みます。" _timelineDescription: home: "ホームタイムラインでは、あなたがフォローしているアカウントの投稿を見られます。" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 8299ccbd1..7cd6b9d71 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -1261,6 +1261,8 @@ youAreHidingSensitiveInformation: "'프라이빗 모드'에 의해 숨겨졌습 temporarilySeeThis: "무시하고 표시하기" sensitiveDoubleClickRequired: "민감한 내용의 미디어를 더블 클릭해서 표시" mutualLink: "서로링크" +prohibitSkippingInitialTutorial: "チュートリアルをスキップできないようにする" +prohibitSkippingInitialTutorialDescription: "新規登録したユーザーに表示されるチュートリアルをスキップできないようにします。チュートリアルを完了しなかったりチュートリアルページを回避したりした場合でも、強制的にリダイレクトされます。" _bubbleGame: howToPlay: "설명" hold: "홀드" @@ -1367,6 +1369,9 @@ _initialTutorial: global: "연결되어 있는 모든 서버의 게시물을 볼 수 있습니다." description2: "각각의 타임라인은 화면 상단에서 언제든지 변경할 수 있습니다." description3: "이 외에도, '리스트 타임라인'이나 '채널 타임라인' 등이 있습니다. 자세한 사항은 {link}에서 확인하실 수 있습니다." + _followUsers: + description1: "誰もフォローしていない状態だと、ホームタイムラインには何も表示されません。" + description2: "タイムラインを構築するため、気になるユーザーをフォローしてみましょう。" _postNote: title: "노트 게시 설정" description1: "Misskey에 노트를 쓸 때에는 다양한 옵션을 설정할 수 있습니다. 노트를 작성하는 화면은 이렇게 생겼습니다." @@ -1395,9 +1400,33 @@ _initialTutorial: method: "첨부 파일을 열람 주의로 설정하려면, 해당 파일을 클릭하여 메뉴를 열고, '열람주의로 설정'을 클릭합니다." sensitiveSucceeded: "파일을 첨부할 때에는 서버의 가이드라인에 따라 적절히 열람주의를 설정해 주시기 바랍니다." doItToContinue: "이미지를 열람 주의로 설정하면 다음으로 넘어갈 수 있게 됩니다." + _pushNotification: + description: "プッシュ通知を有効にすると{name}の通知をお使いのデバイスで受け取ることができます。" + _privacySettings: + title: "プライバシー設定" + description1: "多くのユーザーが利用しているプライバシー関連の設定項目をリストアップしました。必要に応じて変更してください。" + theseSettingsCanEditLater: "これらの設定は後から変更できます。" + youCanEditMoreSettingsInSettingsPageLater: "この他にも様々な設定を「設定」ページから行えます。ぜひ後で確認してみてください。" _done: title: "튜토리얼이 끝났습니다! 🎉" description: "여기에서 소개한 기능은 극히 일부에 지나지 않습니다. Misskey의 사용 방법을 더 자세히 알아보려면 {link}를 확인해 주세요!" + haveFun: "{name}をお楽しみください!" + youCanReferTutorialBy: "このチュートリアルは、「もっと!」→「情報」→「チュートリアルを見る」からいつでも見返すことができます。" + _onboardingLanding: + accountCreated: "アカウントの作成が完了しました!" + welcomeToX: "ようこそ、{name}へ!" + description: "「{name}に登録したは良いものの、どう使えばいいか分からない…💦」といったことを防ぐために、まずはMisskeyの基本的な使い方を学びましょう。" + takesAbout: "このチュートリアルの所要時間は{min}分程度です。\nチュートリアルを完了すると実績が解除されます。" + adminForcesToTakeTutorial: "このサーバーの管理者は新規ユーザーにチュートリアルを完了することを義務付けています。\nチュートリアルを完了するまでMisskeyを使い始めることはできません。" + _onboardingDone: + description: "お疲れ様でした!次のステップに進んで、{name}をもっと楽しめるようにしましょう。" + backToOriginalPath: "元のページに戻る" + backToOriginalPathDescription: "あなたがアクセスしようとしていたページに戻ります。" + profile: "プロフィール設定" + profileDescription: "他のユーザーが親しみやすいように、プロフィールをつくりましょう。" + exploreDescription: "人気のノートやユーザーを見つけて交流をはじめましょう。" + goToTimeline: "ホーム画面に進む" + goToTimelineDescription: "設定等を行わず、通常のホーム画面(タイムライン)に進みます。" _timelineDescription: home: "홈 타임라인에서는, 내가 팔로우한 계정의 게시물을 볼 수 있습니다." local: "로컬 타임라인에서는, 이 서버의 모든 유저의 게시물을 볼 수 있습니다." diff --git a/packages/backend/migration/1708933788259-canSkipInitialTutorial.js b/packages/backend/migration/1708933788259-canSkipInitialTutorial.js new file mode 100644 index 000000000..eaf7a5f84 --- /dev/null +++ b/packages/backend/migration/1708933788259-canSkipInitialTutorial.js @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class CanSkipInitialTutorial1708933788259 { + name = 'CanSkipInitialTutorial1708933788259' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "canSkipInitialTutorial" boolean NOT NULL DEFAULT true`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "canSkipInitialTutorial"`); + } +} diff --git a/packages/backend/src/core/entities/MetaEntityService.ts b/packages/backend/src/core/entities/MetaEntityService.ts index 7fbde9008..01f7089e5 100644 --- a/packages/backend/src/core/entities/MetaEntityService.ts +++ b/packages/backend/src/core/entities/MetaEntityService.ts @@ -68,6 +68,7 @@ export class MetaEntityService { privacyPolicyUrl: instance.privacyPolicyUrl, disableRegistration: instance.disableRegistration, emailRequiredForSignup: instance.emailRequiredForSignup, + canSkipInitialTutorial: instance.canSkipInitialTutorial, enableHcaptcha: instance.enableHcaptcha, hcaptchaSiteKey: instance.hcaptchaSiteKey, enableMcaptcha: instance.enableMcaptcha, diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts index d346b7afb..22df6faad 100644 --- a/packages/backend/src/models/Meta.ts +++ b/packages/backend/src/models/Meta.ts @@ -184,6 +184,11 @@ export class MiMeta { }) public emailRequiredForSignup: boolean; + @Column('boolean', { + default: true, + }) + public canSkipInitialTutorial: boolean; + @Column('boolean', { default: false, }) diff --git a/packages/backend/src/models/json-schema/meta.ts b/packages/backend/src/models/json-schema/meta.ts index bff146114..1cfe9e77b 100644 --- a/packages/backend/src/models/json-schema/meta.ts +++ b/packages/backend/src/models/json-schema/meta.ts @@ -75,6 +75,10 @@ export const packedMetaLiteSchema = { type: 'boolean', optional: false, nullable: false, }, + canSkipInitialTutorial: { + type: 'boolean', + optional: false, nullable: false, + }, enableHcaptcha: { type: 'boolean', optional: false, nullable: false, diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 3081faccc..923c2add4 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -33,6 +33,10 @@ export const meta = { type: 'boolean', optional: false, nullable: false, }, + canSkipInitialTutorial: { + type: 'boolean', + optional: false, nullable: false, + }, enableHcaptcha: { type: 'boolean', optional: false, nullable: false, @@ -548,6 +552,7 @@ export default class extends Endpoint { // eslint- privacyPolicyUrl: instance.privacyPolicyUrl, disableRegistration: instance.disableRegistration, emailRequiredForSignup: instance.emailRequiredForSignup, + canSkipInitialTutorial: instance.canSkipInitialTutorial, enableHcaptcha: instance.enableHcaptcha, hcaptchaSiteKey: instance.hcaptchaSiteKey, enableMcaptcha: instance.enableMcaptcha, diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index 9948e06f8..53e1b71be 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -65,6 +65,7 @@ export const paramDef = { cacheRemoteFiles: { type: 'boolean' }, cacheRemoteSensitiveFiles: { type: 'boolean' }, emailRequiredForSignup: { type: 'boolean' }, + canSkipInitialTutorial: { type: 'boolean' }, enableHcaptcha: { type: 'boolean' }, hcaptchaSiteKey: { type: 'string', nullable: true }, hcaptchaSecretKey: { type: 'string', nullable: true }, @@ -322,6 +323,10 @@ export default class extends Endpoint { // eslint- set.emailRequiredForSignup = ps.emailRequiredForSignup; } + if (ps.canSkipInitialTutorial !== undefined) { + set.canSkipInitialTutorial = ps.canSkipInitialTutorial; + } + if (ps.enableHcaptcha !== undefined) { set.enableHcaptcha = ps.enableHcaptcha; } diff --git a/packages/frontend/.storybook/generate.tsx b/packages/frontend/.storybook/generate.tsx index d74c83a50..1965fee34 100644 --- a/packages/frontend/.storybook/generate.tsx +++ b/packages/frontend/.storybook/generate.tsx @@ -401,8 +401,6 @@ function toStories(component: string): Promise { glob('src/components/MkDigitalClock.vue'), glob('src/components/MkGalleryPostPreview.vue'), glob('src/components/MkSignupServerRules.vue'), - glob('src/components/MkUserSetupDialog.vue'), - glob('src/components/MkUserSetupDialog.*.vue'), glob('src/components/MkInviteCode.vue'), glob('src/pages/user/home.vue'), ]); diff --git a/packages/frontend/assets/tutorial/reaction.png b/packages/frontend/assets/tutorial/reaction.png new file mode 100644 index 0000000000000000000000000000000000000000..c09fda34445b7fe1d484d4614379a3f140ff1d9f GIT binary patch literal 42113 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 location.pathname === i || location.pathname.startsWith(i + '/'))) { subBoot(); diff --git a/packages/frontend/src/boot/common.ts b/packages/frontend/src/boot/common.ts index 1f459bb86..fb34ea633 100644 --- a/packages/frontend/src/boot/common.ts +++ b/packages/frontend/src/boot/common.ts @@ -12,7 +12,7 @@ import { version, lang, updateLocale, locale } from '@/config.js'; import { applyTheme } from '@/scripts/theme.js'; import { isDeviceDarkmode } from '@/scripts/is-device-darkmode.js'; import { updateI18n } from '@/i18n.js'; -import { $i, refreshAccount, login } from '@/account.js'; +import { $i, iAmModerator, refreshAccount, login } from '@/account.js'; import { defaultStore, ColdDeviceStorage } from '@/store.js'; import { fetchInstance, instance } from '@/instance.js'; import { deviceKind } from '@/scripts/device-kind.js'; @@ -21,6 +21,7 @@ import { getUrlWithoutLoginId } from '@/scripts/login-id.js'; import { getAccountFromId } from '@/scripts/get-account-from-id.js'; import { deckStore } from '@/ui/deck/deck-store.js'; import { miLocalStorage } from '@/local-storage.js'; +import { claimedAchievements } from '@/scripts/achievements.js'; import { fetchCustomEmojis } from '@/custom-emojis.js'; import { setupRouter } from '@/router/definition.js'; @@ -118,6 +119,14 @@ export async function common(createVue: () => App) { await defaultStore.ready; await deckStore.ready; + // 2024年4月1日JST以降に作成されたアカウントで、チュートリアルを完了していない通常ユーザーの場合、チュートリアルにリダイレクト + if (!instance.canSkipInitialTutorial && $i && !iAmModerator && defaultStore.state.accountSetupWizard !== -1 && !location.pathname.startsWith('/onboarding') && !location.pathname.startsWith('/signup-complete')) { + const param = new URLSearchParams(); + param.set('redirected_from', location.pathname + location.search + location.hash); + location.replace('/onboarding?' + param.toString()); + return; + } + const fetchInstanceMetaPromise = fetchInstance(); fetchInstanceMetaPromise.then(() => { diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts index cab20b0cf..c85119728 100644 --- a/packages/frontend/src/boot/main-boot.ts +++ b/packages/frontend/src/boot/main-boot.ts @@ -107,12 +107,6 @@ export async function mainBoot() { // only add post shortcuts if logged in hotkeys['p|n'] = post; - defaultStore.loaded.then(() => { - if (defaultStore.state.accountSetupWizard !== -1) { - popup(defineAsyncComponent(() => import('@/components/MkUserSetupDialog.vue')), {}, {}, 'closed'); - } - }); - for (const announcement of ($i.unreadAnnouncements ?? []).filter(x => x.display === 'dialog')) { popup(defineAsyncComponent(() => import('@/components/MkAnnouncementDialog.vue')), { announcement, diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index 5a3a35a68..88dc14684 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -555,6 +555,8 @@ function pushVisibleUser(user: Misskey.entities.UserDetailed) { } function addVisibleUser() { + if (props.mock) return; + os.selectUser().then(user => { pushVisibleUser(user); @@ -884,6 +886,8 @@ function cancel() { } function insertMention() { + if (props.mock) return; + os.selectUser({ localOnly: localOnly.value, includeSelf: true }).then(user => { insertTextAtCursor(textareaEl.value, '@' + Misskey.acct.toString(user) + ' '); }); diff --git a/packages/frontend/src/components/MkSignupDialog.form.vue b/packages/frontend/src/components/MkSignupDialog.form.vue index 52d910afc..9f5c9c58b 100644 --- a/packages/frontend/src/components/MkSignupDialog.form.vue +++ b/packages/frontend/src/components/MkSignupDialog.form.vue @@ -214,7 +214,7 @@ async function onSubmit(): Promise { emit('signup', res); if (props.autoSet) { - return login(res.i); + return login(res.i, '/onboarding'); } } } catch { diff --git a/packages/frontend/src/components/MkUserSetupDialog.User.vue b/packages/frontend/src/components/MkTutorial.FollowUsers.UserCard.vue similarity index 100% rename from packages/frontend/src/components/MkUserSetupDialog.User.vue rename to packages/frontend/src/components/MkTutorial.FollowUsers.UserCard.vue diff --git a/packages/frontend/src/components/MkUserSetupDialog.Follow.vue b/packages/frontend/src/components/MkTutorial.FollowUsers.vue similarity index 76% rename from packages/frontend/src/components/MkUserSetupDialog.Follow.vue rename to packages/frontend/src/components/MkTutorial.FollowUsers.vue index 3e451519e..985a4697f 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.Follow.vue +++ b/packages/frontend/src/components/MkTutorial.FollowUsers.vue @@ -5,14 +5,14 @@ SPDX-License-Identifier: AGPL-3.0-only