feat(core): add flag for two-step journal conformation (#13246)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Introduced a feature flag to control a two-step journal confirmation
process.
* Users may now experience either an immediate journal opening or a
confirmation step before journal creation, depending on the feature flag
status.

* **Chores**
* Added a new feature flag for two-step journal confirmation,
configurable in canary builds.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Cats Juice
2025-07-17 15:03:32 +08:00
committed by GitHub
parent 21360591a9
commit ea21de8311
4 changed files with 78 additions and 12 deletions

View File

@@ -1,5 +1,6 @@
import type { WeekDatePickerHandle } from '@affine/component'; import type { WeekDatePickerHandle } from '@affine/component';
import { WeekDatePicker } from '@affine/component'; import { WeekDatePicker } from '@affine/component';
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
import { import {
JOURNAL_DATE_FORMAT, JOURNAL_DATE_FORMAT,
JournalService, JournalService,
@@ -25,6 +26,11 @@ export const JournalWeekDatePicker = ({ page }: JournalWeekDatePickerProps) => {
); );
const workbench = useService(WorkbenchService).workbench; const workbench = useService(WorkbenchService).workbench;
const featureFlagService = useService(FeatureFlagService);
const isTwoStepJournalConfirmationEnabled = useLiveData(
featureFlagService.flags.enable_two_step_journal_confirmation.$
);
useEffect(() => { useEffect(() => {
if (!journalDate) return; if (!journalDate) return;
setDate(journalDate.format(JOURNAL_DATE_FORMAT)); setDate(journalDate.format(JOURNAL_DATE_FORMAT));
@@ -33,14 +39,19 @@ export const JournalWeekDatePicker = ({ page }: JournalWeekDatePickerProps) => {
const openJournal = useCallback( const openJournal = useCallback(
(date: string) => { (date: string) => {
const docs = journalService.journalsByDate$(date).value; if (isTwoStepJournalConfirmationEnabled) {
if (docs.length > 0) { const docs = journalService.journalsByDate$(date).value;
workbench.openDoc(docs[0].id, { at: 'active' }); if (docs.length > 0) {
workbench.openDoc(docs[0].id, { at: 'active' });
} else {
workbench.open(`/journals?date=${date}`, { at: 'active' });
}
} else { } else {
workbench.open(`/journals?date=${date}`, { at: 'active' }); const doc = journalService.ensureJournalByDate(date);
workbench.openDoc(doc.id, { at: 'active' });
} }
}, },
[journalService, workbench] [isTwoStepJournalConfirmationEnabled, journalService, workbench]
); );
return ( return (

View File

@@ -16,6 +16,7 @@ import {
DocsService, DocsService,
} from '@affine/core/modules/doc'; } from '@affine/core/modules/doc';
import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta'; import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta';
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
import { JournalService } from '@affine/core/modules/journal'; import { JournalService } from '@affine/core/modules/journal';
import { import {
WorkbenchLink, WorkbenchLink,
@@ -113,16 +114,26 @@ export const EditorJournalPanel = () => {
const journalDate = journalDateStr ? dayjs(journalDateStr) : null; const journalDate = journalDateStr ? dayjs(journalDateStr) : null;
const isJournal = !!journalDate; const isJournal = !!journalDate;
const featureFlagService = useService(FeatureFlagService);
const isTwoStepJournalConfirmationEnabled = useLiveData(
featureFlagService.flags.enable_two_step_journal_confirmation.$
);
const openJournal = useCallback( const openJournal = useCallback(
(date: string) => { (date: string) => {
const docs = journalService.journalsByDate$(date).value; if (isTwoStepJournalConfirmationEnabled) {
if (docs.length > 0) { const docs = journalService.journalsByDate$(date).value;
workbench.openDoc(docs[0].id, { at: 'active' }); if (docs.length > 0) {
workbench.openDoc(docs[0].id, { at: 'active' });
} else {
workbench.open(`/journals?date=${date}`, { at: 'active' });
}
} else { } else {
workbench.open(`/journals?date=${date}`, { at: 'active' }); const doc = journalService.ensureJournalByDate(date);
workbench.openDoc(doc.id, { at: 'active' });
} }
}, },
[journalService, workbench] [isTwoStepJournalConfirmationEnabled, journalService, workbench]
); );
const onDateSelect = useCallback( const onDateSelect = useCallback(

View File

@@ -4,6 +4,7 @@ import {
type WeekDatePickerHandle, type WeekDatePickerHandle,
} from '@affine/component'; } from '@affine/component';
import { BlocksuiteEditorJournalDocTitleUI } from '@affine/core/blocksuite/block-suite-editor/journal-doc-title'; import { BlocksuiteEditorJournalDocTitleUI } from '@affine/core/blocksuite/block-suite-editor/journal-doc-title';
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
import { import {
JOURNAL_DATE_FORMAT, JOURNAL_DATE_FORMAT,
JournalService, JournalService,
@@ -21,7 +22,13 @@ import { TodayIcon } from '@blocksuite/icons/rc';
import { useLiveData, useService } from '@toeverything/infra'; import { useLiveData, useService } from '@toeverything/infra';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import type { Location } from 'history'; import type { Location } from 'history';
import { useCallback, useLayoutEffect, useRef, useState } from 'react'; import {
useCallback,
useEffect,
useLayoutEffect,
useRef,
useState,
} from 'react';
import { AllDocSidebarTabs } from '../layouts/all-doc-sidebar-tabs'; import { AllDocSidebarTabs } from '../layouts/all-doc-sidebar-tabs';
import * as styles from './index.css'; import * as styles from './index.css';
@@ -36,7 +43,7 @@ function getDateFromUrl(location: Location) {
const weekStyle = { maxWidth: 800, width: '100%' }; const weekStyle = { maxWidth: 800, width: '100%' };
// this route page acts as a redirector to today's journal // this route page acts as a redirector to today's journal
export const Component = () => { export const JournalsPageWithConfirmation = () => {
const handleRef = useRef<WeekDatePickerHandle>(null); const handleRef = useRef<WeekDatePickerHandle>(null);
const t = useI18n(); const t = useI18n();
@@ -139,3 +146,32 @@ export const Component = () => {
</> </>
); );
}; };
export const JournalsPageWithoutConfirmation = () => {
const journalService = useService(JournalService);
const workbench = useService(WorkbenchService).workbench;
useEffect(() => {
const today = dayjs().format(JOURNAL_DATE_FORMAT);
const doc = journalService.ensureJournalByDate(today);
workbench.openDoc(doc.id, {
replaceHistory: true,
at: 'active',
});
}, [journalService, workbench]);
return null;
};
export const Component = () => {
const featureFlagService = useService(FeatureFlagService);
const isTwoStepJournalConfirmationEnabled = useLiveData(
featureFlagService.flags.enable_two_step_journal_confirmation.$
);
if (isTwoStepJournalConfirmationEnabled) {
return <JournalsPageWithConfirmation />;
}
return <JournalsPageWithoutConfirmation />;
};

View File

@@ -264,6 +264,14 @@ export const AFFINE_FLAGS = {
configurable: isCanaryBuild, configurable: isCanaryBuild,
defaultState: false, defaultState: false,
}, },
enable_two_step_journal_confirmation: {
category: 'affine',
displayName: 'Enable Two Step Journal Confirmation',
description:
'When enabled, you must confirm the journal before you can create a new journal.',
configurable: isCanaryBuild,
defaultState: isCanaryBuild,
},
} satisfies { [key in string]: FlagInfo }; } satisfies { [key in string]: FlagInfo };
// oxlint-disable-next-line no-redeclare // oxlint-disable-next-line no-redeclare