diff --git a/packages/web/src/javascripts/Components/ApplicationView/ApplicationView.tsx b/packages/web/src/javascripts/Components/ApplicationView/ApplicationView.tsx index 78db68a34..7e46b3261 100644 --- a/packages/web/src/javascripts/Components/ApplicationView/ApplicationView.tsx +++ b/packages/web/src/javascripts/Components/ApplicationView/ApplicationView.tsx @@ -216,6 +216,8 @@ const ApplicationView: FunctionComponent = ({ application, mainApplicatio ( filesController={filesController} featuresController={featuresController} linkingController={linkingController} + navigationController={navigationController} /> ) : ( = observer(({ filesController, selectionController }) => { - const { showFileContextMenu, setShowFileContextMenu, fileContextMenuLocation } = filesController - const { selectedFiles } = selectionController +const FileContextMenu: FunctionComponent = observer( + ({ filesController, selectionController, linkingController, navigationController }) => { + const { showFileContextMenu, setShowFileContextMenu, fileContextMenuLocation } = filesController + const { selectedFiles } = selectionController - return ( - setShowFileContextMenu(!showFileContextMenu)} - align="start" - className="py-2" - > - - setShowFileContextMenu(false)} - shouldShowRenameOption={false} - shouldShowAttachOption={false} - /> - - - ) -}) + return ( + setShowFileContextMenu(!showFileContextMenu)} + align="start" + className="py-2" + > + + setShowFileContextMenu(false)} + shouldShowRenameOption={false} + shouldShowAttachOption={false} + /> + + + ) + }, +) FileContextMenu.displayName = 'FileContextMenu' -const FileContextMenuWrapper: FunctionComponent = ({ filesController, selectionController }) => { +const FileContextMenuWrapper: FunctionComponent = ({ + filesController, + linkingController, + navigationController, + selectionController, +}) => { const { showFileContextMenu } = filesController const { selectedFiles } = selectionController @@ -48,7 +61,14 @@ const FileContextMenuWrapper: FunctionComponent = ({ filesController, sel return null } - return + return ( + + ) } export default observer(FileContextMenuWrapper) diff --git a/packages/web/src/javascripts/Components/FileContextMenu/FileMenuOptions.tsx b/packages/web/src/javascripts/Components/FileContextMenu/FileMenuOptions.tsx index 0b0e9e959..10ae996fa 100644 --- a/packages/web/src/javascripts/Components/FileContextMenu/FileMenuOptions.tsx +++ b/packages/web/src/javascripts/Components/FileContextMenu/FileMenuOptions.tsx @@ -11,10 +11,16 @@ import MenuItem from '../Menu/MenuItem' import { FileContextMenuBackupOption } from './FileContextMenuBackupOption' import MenuSwitchButtonItem from '../Menu/MenuSwitchButtonItem' import { FileItem } from '@standardnotes/snjs' +import AddTagOption from '../NotesOptions/AddTagOption' +import { MenuItemIconSize } from '@/Constants/TailwindClassNames' +import { LinkingController } from '@/Controllers/LinkingController' +import { NavigationController } from '@/Controllers/Navigation/NavigationController' type Props = { closeMenu: () => void filesController: FilesController + linkingController: LinkingController + navigationController: NavigationController isFileAttachedToNote?: boolean renameToggleCallback?: (isRenamingFile: boolean) => void shouldShowRenameOption: boolean @@ -25,6 +31,8 @@ type Props = { const FileMenuOptions: FunctionComponent = ({ closeMenu, filesController, + linkingController, + navigationController, isFileAttachedToNote, renameToggleCallback, shouldShowRenameOption, @@ -82,6 +90,12 @@ const FileMenuOptions: FunctionComponent = ({ ) : null} )} + { diff --git a/packages/web/src/javascripts/Components/FileContextMenu/FileOptionsPanel.tsx b/packages/web/src/javascripts/Components/FileContextMenu/FileOptionsPanel.tsx index dec830ca1..7148a7c3c 100644 --- a/packages/web/src/javascripts/Components/FileContextMenu/FileOptionsPanel.tsx +++ b/packages/web/src/javascripts/Components/FileContextMenu/FileOptionsPanel.tsx @@ -6,13 +6,22 @@ import { SelectedItemsController } from '@/Controllers/SelectedItemsController' import Popover from '../Popover/Popover' import RoundIconButton from '../Button/RoundIconButton' import Menu from '../Menu/Menu' +import { LinkingController } from '@/Controllers/LinkingController' +import { NavigationController } from '@/Controllers/Navigation/NavigationController' type Props = { filesController: FilesController selectionController: SelectedItemsController + linkingController: LinkingController + navigationController: NavigationController } -const FilesOptionsPanel = ({ filesController, selectionController }: Props) => { +const FilesOptionsPanel = ({ + filesController, + linkingController, + navigationController, + selectionController, +}: Props) => { const [isOpen, setIsOpen] = useState(false) const buttonRef = useRef(null) @@ -25,6 +34,8 @@ const FilesOptionsPanel = ({ filesController, selectionController }: Props) => { { setIsOpen(false) diff --git a/packages/web/src/javascripts/Components/FileView/FileViewWithoutProtection.tsx b/packages/web/src/javascripts/Components/FileView/FileViewWithoutProtection.tsx index 523d5278c..8a468a1ed 100644 --- a/packages/web/src/javascripts/Components/FileView/FileViewWithoutProtection.tsx +++ b/packages/web/src/javascripts/Components/FileView/FileViewWithoutProtection.tsx @@ -112,6 +112,8 @@ const FileViewWithoutProtection = ({ application, viewControllerManager, file }: diff --git a/packages/web/src/javascripts/Components/FilesTableView/FilesTableView.tsx b/packages/web/src/javascripts/Components/FilesTableView/FilesTableView.tsx index 0a01e65f8..e167be5bf 100644 --- a/packages/web/src/javascripts/Components/FilesTableView/FilesTableView.tsx +++ b/packages/web/src/javascripts/Components/FilesTableView/FilesTableView.tsx @@ -31,8 +31,19 @@ import { LinkingController } from '@/Controllers/LinkingController' import { FeaturesController } from '@/Controllers/FeaturesController' import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery' import { useApplication } from '../ApplicationProvider' +import { NavigationController } from '@/Controllers/Navigation/NavigationController' -const ContextMenuCell = ({ files, filesController }: { files: FileItem[]; filesController: FilesController }) => { +const ContextMenuCell = ({ + files, + filesController, + navigationController, + linkingController, +}: { + files: FileItem[] + filesController: FilesController + navigationController: NavigationController + linkingController: LinkingController +}) => { const [contextMenuVisible, setContextMenuVisible] = useState(false) const anchorElementRef = useRef(null) @@ -61,6 +72,8 @@ const ContextMenuCell = ({ files, filesController }: { files: FileItem[]; filesC > { setContextMenuVisible(false) }} @@ -160,9 +173,16 @@ type Props = { filesController: FilesController featuresController: FeaturesController linkingController: LinkingController + navigationController: NavigationController } -const FilesTableView = ({ application, filesController, featuresController, linkingController }: Props) => { +const FilesTableView = ({ + application, + filesController, + featuresController, + linkingController, + navigationController, +}: Props) => { const files = application.items .getDisplayableNotesAndFiles() .filter((item) => item.content_type === ContentType.File) as FileItem[] @@ -312,12 +332,22 @@ const FilesTableView = ({ application, filesController, featuresController, link featuresController={featuresController} linkingController={linkingController} /> - + ) }, selectionActions: (fileIds) => ( - fileIds.includes(file.uuid))} filesController={filesController} /> + fileIds.includes(file.uuid))} + filesController={filesController} + linkingController={linkingController} + navigationController={navigationController} + /> ), showSelectionActions: true, }) @@ -347,6 +377,8 @@ const FilesTableView = ({ application, filesController, featuresController, link shouldShowRenameOption={false} shouldShowAttachOption={false} selectedFiles={[contextMenuFile]} + linkingController={linkingController} + navigationController={navigationController} /> diff --git a/packages/web/src/javascripts/Components/MultipleSelectedFiles/MultipleSelectedFiles.tsx b/packages/web/src/javascripts/Components/MultipleSelectedFiles/MultipleSelectedFiles.tsx index 4394a141f..2e8ccc393 100644 --- a/packages/web/src/javascripts/Components/MultipleSelectedFiles/MultipleSelectedFiles.tsx +++ b/packages/web/src/javascripts/Components/MultipleSelectedFiles/MultipleSelectedFiles.tsx @@ -5,13 +5,22 @@ import { useCallback } from 'react' import FileOptionsPanel from '../FileContextMenu/FileOptionsPanel' import { FilesController } from '@/Controllers/FilesController' import { SelectedItemsController } from '@/Controllers/SelectedItemsController' +import { NavigationController } from '@/Controllers/Navigation/NavigationController' +import { LinkingController } from '@/Controllers/LinkingController' type Props = { filesController: FilesController selectionController: SelectedItemsController + linkingController: LinkingController + navigationController: NavigationController } -const MultipleSelectedFiles = ({ filesController, selectionController }: Props) => { +const MultipleSelectedFiles = ({ + filesController, + selectionController, + linkingController, + navigationController, +}: Props) => { const count = selectionController.selectedFilesCount const cancelMultipleSelection = useCallback(() => { @@ -23,7 +32,12 @@ const MultipleSelectedFiles = ({ filesController, selectionController }: Props)

{count} selected files

- +
diff --git a/packages/web/src/javascripts/Components/NoteGroupView/NoteGroupView.tsx b/packages/web/src/javascripts/Components/NoteGroupView/NoteGroupView.tsx index 983b3cb8c..3a5ead97c 100644 --- a/packages/web/src/javascripts/Components/NoteGroupView/NoteGroupView.tsx +++ b/packages/web/src/javascripts/Components/NoteGroupView/NoteGroupView.tsx @@ -118,6 +118,8 @@ class NoteGroupView extends AbstractComponent { )} {shouldNotShowMultipleSelectedItems && hasControllers && ( diff --git a/packages/web/src/javascripts/Components/NotesOptions/AddTagOption.tsx b/packages/web/src/javascripts/Components/NotesOptions/AddTagOption.tsx index ac395c268..1996131fa 100644 --- a/packages/web/src/javascripts/Components/NotesOptions/AddTagOption.tsx +++ b/packages/web/src/javascripts/Components/NotesOptions/AddTagOption.tsx @@ -2,22 +2,28 @@ import { observer } from 'mobx-react-lite' import { FunctionComponent, useCallback, useRef, useState } from 'react' import Icon from '@/Components/Icon/Icon' import { NavigationController } from '@/Controllers/Navigation/NavigationController' -import { NotesController } from '@/Controllers/NotesController/NotesController' import { KeyboardKey } from '@standardnotes/ui-services' import Popover from '../Popover/Popover' -import { IconType } from '@standardnotes/snjs' +import { classNames, DecryptedItemInterface, IconType, SNTag } from '@standardnotes/snjs' import { getTitleForLinkedTag } from '@/Utils/Items/Display/getTitleForLinkedTag' import { useApplication } from '../ApplicationProvider' import MenuItem from '../Menu/MenuItem' import Menu from '../Menu/Menu' +import { LinkingController } from '@/Controllers/LinkingController' type Props = { navigationController: NavigationController - notesController: NotesController + linkingController: LinkingController + selectedItems: DecryptedItemInterface[] iconClassName: string } -const AddTagOption: FunctionComponent = ({ navigationController, notesController, iconClassName }) => { +const AddTagOption: FunctionComponent = ({ + navigationController, + linkingController, + selectedItems, + iconClassName, +}) => { const application = useApplication() const menuContainerRef = useRef(null) const buttonRef = useRef(null) @@ -28,6 +34,18 @@ const AddTagOption: FunctionComponent = ({ navigationController, notesCon setIsOpen((isOpen) => !isOpen) }, []) + const isTagLinkedToSelectedItems = (tag: SNTag) => { + return selectedItems.every((item) => application.getItemTags(item).find((itemTag) => itemTag.uuid === tag.uuid)) + } + + const linkTagToSelectedItems = (tag: SNTag) => { + selectedItems.forEach((item) => linkingController.linkItems(item, tag)) + } + + const unlinkTagFromSelectedItems = (tag: SNTag) => { + selectedItems.forEach((item) => linkingController.unlinkItems(item, tag)) + } + return (
= ({ navigationController, notesCon { - notesController.isTagInSelectedNotes(tag) - ? notesController.removeTagFromSelectedNotes(tag).catch(console.error) - : notesController.addTagToSelectedNotes(tag).catch(console.error) + isTagLinkedToSelectedItems(tag) ? unlinkTagFromSelectedItems(tag) : linkTagToSelectedItems(tag) }} > {tag.iconString && ( @@ -72,8 +88,10 @@ const AddTagOption: FunctionComponent = ({ navigationController, notesCon /> )} {getTitleForLinkedTag(tag, application)?.longTitle} diff --git a/packages/web/src/javascripts/Components/NotesOptions/NotesOptions.tsx b/packages/web/src/javascripts/Components/NotesOptions/NotesOptions.tsx index 83f92e465..1ced1c5bb 100644 --- a/packages/web/src/javascripts/Components/NotesOptions/NotesOptions.tsx +++ b/packages/web/src/javascripts/Components/NotesOptions/NotesOptions.tsx @@ -42,6 +42,7 @@ const NotesOptions = ({ application, navigationController, notesController, + linkingController, historyModalController, closeMenu, }: NotesOptionsProps) => { @@ -214,7 +215,8 @@ const NotesOptions = ({ )}