mirror of
https://github.com/laurent22/joplin.git
synced 2026-03-13 08:09:59 +08:00
Signed-off-by: justin212407 <charlesjustin2124@gmail.com>
This commit is contained in:
@@ -284,9 +284,11 @@ interface ConnectProps {
|
||||
const mapStateToProps = (state: AppState, ownProps: ConnectProps) => {
|
||||
const whenClauseContext = stateToWhenClauseContext(state, { windowId: ownProps.windowId });
|
||||
const windowState = stateUtils.windowStateById(state, ownProps.windowId);
|
||||
const hasFolderForNewNotes = whenClauseContext.selectedFolderIsValid
|
||||
&& windowState.selectedFolderId !== getTrashFolderId();
|
||||
|
||||
return {
|
||||
showNewNoteButtons: windowState.selectedFolderId !== getTrashFolderId(),
|
||||
showNewNoteButtons: hasFolderForNewNotes,
|
||||
newNoteButtonEnabled: CommandService.instance().isEnabled('newNote', whenClauseContext),
|
||||
newTodoButtonEnabled: CommandService.instance().isEnabled('newTodo', whenClauseContext),
|
||||
sortOrderButtonsVisible: state.settings['notes.sortOrder.buttonsVisible'],
|
||||
|
||||
@@ -60,7 +60,7 @@ const useNoteListControlsBreakpoints = (width: number, newNoteButtonElement: Ele
|
||||
const [dynamicBreakpoints, setDynamicBreakpoints] = useState<Breakpoints>({ Sm: BaseBreakpoint.Sm, Md: BaseBreakpoint.Md, Lg: BaseBreakpoint.Lg, Xl: BaseBreakpoint.Xl });
|
||||
const previousWidth = usePrevious(width);
|
||||
const widthHasChanged = width !== previousWidth;
|
||||
const showNewNoteButton = selectedFolderId !== getTrashFolderId();
|
||||
const showNewNoteButton = !!selectedFolderId && selectedFolderId !== getTrashFolderId();
|
||||
|
||||
// Initialize language-specific breakpoints
|
||||
useEffect(() => {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { _ } from '@joplin/lib/locale';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
import Folder from '@joplin/lib/models/Folder';
|
||||
|
||||
export const newNoteEnabledConditions = 'oneFolderSelected && !inConflictFolder && !folderIsReadOnly && !folderIsTrash';
|
||||
export const newNoteEnabledConditions = 'oneFolderSelected && selectedFolderIsValid && !inConflictFolder && !folderIsReadOnly && !folderIsTrash';
|
||||
|
||||
export const declaration: CommandDeclaration = {
|
||||
name: 'newNote',
|
||||
|
||||
@@ -34,13 +34,14 @@ export default class MainScreen {
|
||||
}
|
||||
|
||||
public async waitFor() {
|
||||
await this.newNoteButton.waitFor();
|
||||
await this.noteList.waitFor();
|
||||
}
|
||||
|
||||
// Follows the steps a user would use to create a new note.
|
||||
public async createNewNote(title: string) {
|
||||
await this.waitFor();
|
||||
// The new note button is only visible when a folder is selected -- wait for it explicitly.
|
||||
await this.newNoteButton.waitFor();
|
||||
|
||||
// Create the new note. Retry this -- creating new notes can sometimes fail if done just after
|
||||
// application startup.
|
||||
|
||||
@@ -149,4 +149,47 @@ describe('stateToWhenClauseContext', () => {
|
||||
stateToWhenClauseContext(applicationState, { commandFolderIds }),
|
||||
).toHaveProperty('foldersAreDeleted', expectedDeletedState);
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
label: 'should be false when no folders exist (new profile)',
|
||||
selectedFolderId: 'non-existent-folder',
|
||||
folders: [],
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
label: 'should be false when selectedFolderId is null',
|
||||
selectedFolderId: null,
|
||||
folders: [{ id: '1', deleted_time: 0, share_id: '', parent_id: '' }],
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
label: 'should be false when selected folder has been deleted',
|
||||
selectedFolderId: '1',
|
||||
folders: [{ id: '1', deleted_time: 1000, share_id: '', parent_id: '' }],
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
label: 'should be true when selected folder exists and is not deleted',
|
||||
selectedFolderId: '1',
|
||||
folders: [{ id: '1', deleted_time: 0, share_id: '', parent_id: '' }],
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
label: 'should be false when selectedFolderId does not match any folder',
|
||||
selectedFolderId: 'stale-id',
|
||||
folders: [{ id: '1', deleted_time: 0, share_id: '', parent_id: '' }],
|
||||
expected: false,
|
||||
},
|
||||
])('should set selectedFolderIsValid correctly: $label', ({ selectedFolderId, folders, expected }) => {
|
||||
const applicationState = buildState({
|
||||
selectedFolderId,
|
||||
folders,
|
||||
notes: [],
|
||||
});
|
||||
|
||||
expect(
|
||||
stateToWhenClauseContext(applicationState),
|
||||
).toHaveProperty('selectedFolderIsValid', expected);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -47,6 +47,7 @@ export interface WhenClauseContext {
|
||||
noteTodoCompleted: boolean;
|
||||
oneFolderSelected: boolean;
|
||||
oneNoteSelected: boolean;
|
||||
selectedFolderIsValid: boolean;
|
||||
someNotesSelected: boolean;
|
||||
syncStarted: boolean;
|
||||
hasActivePluginEditor: boolean;
|
||||
@@ -73,6 +74,14 @@ export default function stateToWhenClauseContext(state: State, options: WhenClau
|
||||
|
||||
const settings = state.settings || {};
|
||||
|
||||
// Check whether the window's selected folder actually exists and is not
|
||||
// deleted. This resolves the case where selectedFolderId is stale (e.g.
|
||||
// new profile with no notebooks) or points to a deleted folder.
|
||||
const selectedFolder = windowState.selectedFolderId
|
||||
? BaseModel.byId(state.folders, windowState.selectedFolderId)
|
||||
: null;
|
||||
const selectedFolderIsValid = !!selectedFolder && !selectedFolder.deleted_time;
|
||||
|
||||
return {
|
||||
// Application state
|
||||
notesAreBeingSaved: stateUtils.hasNotesBeingSaved(state),
|
||||
@@ -98,6 +107,7 @@ export default function stateToWhenClauseContext(state: State, options: WhenClau
|
||||
|
||||
// Folder selection
|
||||
oneFolderSelected: selectedFolderIds.length === 1,
|
||||
selectedFolderIsValid,
|
||||
|
||||
// Current note properties
|
||||
noteIsTodo: selectedNote ? !!selectedNote.is_todo : false,
|
||||
|
||||
Reference in New Issue
Block a user