feat: Added per-tag preference to use table layout and removed "Files Table View" from Labs

This commit is contained in:
Aman Harwara
2023-01-06 17:00:19 +05:30
parent eea97362f8
commit dd8ccdeadc
16 changed files with 98 additions and 76 deletions

View File

@@ -38,8 +38,6 @@ export enum FeatureIdentifier {
TaskEditor = 'org.standardnotes.simple-task-editor', TaskEditor = 'org.standardnotes.simple-task-editor',
TokenVaultEditor = 'org.standardnotes.token-vault', TokenVaultEditor = 'org.standardnotes.token-vault',
FilesTableView = 'org.standardnotes.files-table-view',
DeprecatedBoldEditor = 'org.standardnotes.bold-editor', DeprecatedBoldEditor = 'org.standardnotes.bold-editor',
DeprecatedMarkdownBasicEditor = 'org.standardnotes.simple-markdown-editor', DeprecatedMarkdownBasicEditor = 'org.standardnotes.simple-markdown-editor',
DeprecatedMarkdownMathEditor = 'org.standardnotes.fancy-markdown-editor', DeprecatedMarkdownMathEditor = 'org.standardnotes.fancy-markdown-editor',
@@ -53,4 +51,4 @@ export enum FeatureIdentifier {
*/ */
export const LegacyFileSafeIdentifier = 'org.standardnotes.legacy.file-safe' export const LegacyFileSafeIdentifier = 'org.standardnotes.legacy.file-safe'
export const ExperimentalFeatures = [FeatureIdentifier.FilesTableView] export const ExperimentalFeatures = []

View File

@@ -1,18 +1,5 @@
import { RoleName, SubscriptionName } from '@standardnotes/common'
import { FeatureDescription } from '../Feature/FeatureDescription' import { FeatureDescription } from '../Feature/FeatureDescription'
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
import { PermissionName } from '../Permission/PermissionName'
export function experimentalFeatures(): FeatureDescription[] { export function experimentalFeatures(): FeatureDescription[] {
const filesTableView: FeatureDescription = { return []
identifier: FeatureIdentifier.FilesTableView,
name: 'Files Table View',
description:
'Replaces the current Files view with a table view, with name, size, and date sort options. Requires reload to take effect.',
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
availableInRoles: [RoleName.PlusUser, RoleName.ProUser],
permission_name: PermissionName.FilesTableView,
}
return [filesTableView]
} }

View File

@@ -40,5 +40,4 @@ export enum PermissionName {
TwoFactorAuth = 'server:two-factor-auth', TwoFactorAuth = 'server:two-factor-auth',
SubscriptionSharing = 'server:subscription-sharing', SubscriptionSharing = 'server:subscription-sharing',
SuperEditor = 'editor:super-editor', SuperEditor = 'editor:super-editor',
FilesTableView = 'app:files-table-view',
} }

View File

@@ -18,4 +18,5 @@ export interface TagPreferences {
editorIdentifier?: EditorIdentifier editorIdentifier?: EditorIdentifier
entryMode?: 'normal' | 'daily' entryMode?: 'normal' | 'daily'
panelWidth?: number panelWidth?: number
useTableView?: boolean
} }

View File

@@ -12,7 +12,7 @@ import { NavigationController } from '@/Controllers/Navigation/NavigationControl
import { NotesController } from '@/Controllers/NotesController/NotesController' import { NotesController } from '@/Controllers/NotesController/NotesController'
import { ElementIds } from '@/Constants/ElementIDs' import { ElementIds } from '@/Constants/ElementIDs'
import { classNames } from '@standardnotes/utils' import { classNames } from '@standardnotes/utils'
import { ContentType, FeatureIdentifier, SNTag } from '@standardnotes/snjs' import { ContentType, SNTag } from '@standardnotes/snjs'
type Props = { type Props = {
application: WebApplication application: WebApplication
@@ -97,8 +97,6 @@ const ContentList: FunctionComponent<Props> = ({
const hasNotes = items.some((item) => item.content_type === ContentType.Note) const hasNotes = items.some((item) => item.content_type === ContentType.Note)
const isFilesTableViewEnabled = application.features.isExperimentalFeatureEnabled(FeatureIdentifier.FilesTableView)
return ( return (
<div <div
className={classNames( className={classNames(
@@ -112,13 +110,7 @@ const ContentList: FunctionComponent<Props> = ({
onKeyDown={onKeyDown} onKeyDown={onKeyDown}
tabIndex={FOCUSABLE_BUT_NOT_TABBABLE} tabIndex={FOCUSABLE_BUT_NOT_TABBABLE}
> >
{items.map((item, index) => { {items.map((item) => {
const previousIndex = index - 1
const previousItem = previousIndex >= 0 ? items[previousIndex] : undefined
const nextIndex = index + 1
const nextItem = nextIndex < items.length ? items[nextIndex] : undefined
return ( return (
<ContentListItem <ContentListItem
key={item.uuid} key={item.uuid}
@@ -134,8 +126,6 @@ const ContentList: FunctionComponent<Props> = ({
onSelect={selectItem} onSelect={selectItem}
tags={getTagsForItem(item)} tags={getTagsForItem(item)}
notesController={notesController} notesController={notesController}
isPreviousItemTiled={previousItem?.content_type === ContentType.File && !isFilesTableViewEnabled}
isNextItemTiled={nextItem?.content_type === ContentType.File && !isFilesTableViewEnabled}
/> />
) )
})} })}

View File

@@ -1,25 +1,16 @@
import { ContentType, FeatureIdentifier, FileItem, SNNote } from '@standardnotes/snjs' import { ContentType, FileItem, SNNote } from '@standardnotes/snjs'
import React, { FunctionComponent } from 'react' import React, { FunctionComponent } from 'react'
import FileListItem from './FileListItem' import FileListItem from './FileListItem'
import FileListItemCard from './FileListItemCard'
import NoteListItem from './NoteListItem' import NoteListItem from './NoteListItem'
import { AbstractListItemProps, doListItemPropsMeritRerender } from './Types/AbstractListItemProps' import { AbstractListItemProps, doListItemPropsMeritRerender } from './Types/AbstractListItemProps'
import { ListableContentItem } from './Types/ListableContentItem' import { ListableContentItem } from './Types/ListableContentItem'
const ContentListItem: FunctionComponent<AbstractListItemProps<ListableContentItem>> = (props) => { const ContentListItem: FunctionComponent<AbstractListItemProps<ListableContentItem>> = (props) => {
const isFilesTableViewEnabled = props.application.features.isExperimentalFeatureEnabled(
FeatureIdentifier.FilesTableView,
)
switch (props.item.content_type) { switch (props.item.content_type) {
case ContentType.Note: case ContentType.Note:
return <NoteListItem {...props} item={props.item as SNNote} /> return <NoteListItem {...props} item={props.item as SNNote} />
case ContentType.File: { case ContentType.File: {
if (isFilesTableViewEnabled) { return <FileListItem {...props} item={props.item as FileItem} />
return <FileListItem {...props} item={props.item as FileItem} />
}
return <FileListItemCard {...props} item={props.item as FileItem} />
} }
default: default:
return null return null

View File

@@ -9,7 +9,7 @@ import {
} from '@standardnotes/ui-services' } from '@standardnotes/ui-services'
import { WebApplication } from '@/Application/Application' import { WebApplication } from '@/Application/Application'
import { PANEL_NAME_NOTES } from '@/Constants/Constants' import { PANEL_NAME_NOTES } from '@/Constants/Constants'
import { FeatureIdentifier, FileItem, PrefKey, SystemViewId, WebAppEvent } from '@standardnotes/snjs' import { FileItem, PrefKey, WebAppEvent } from '@standardnotes/snjs'
import { observer } from 'mobx-react-lite' import { observer } from 'mobx-react-lite'
import { forwardRef, useCallback, useEffect, useMemo } from 'react' import { forwardRef, useCallback, useEffect, useMemo } from 'react'
import ContentList from '@/Components/ContentListView/ContentList' import ContentList from '@/Components/ContentListView/ContentList'
@@ -40,6 +40,7 @@ import ContentTableView from '../ContentTableView/ContentTableView'
import { FeaturesController } from '@/Controllers/FeaturesController' import { FeaturesController } from '@/Controllers/FeaturesController'
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery' import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
import { HistoryModalController } from '@/Controllers/NoteHistory/HistoryModalController' import { HistoryModalController } from '@/Controllers/NoteHistory/HistoryModalController'
import { PaneController } from '@/Controllers/PaneController/PaneController'
type Props = { type Props = {
accountMenuController: AccountMenuController accountMenuController: AccountMenuController
@@ -54,6 +55,7 @@ type Props = {
linkingController: LinkingController linkingController: LinkingController
featuresController: FeaturesController featuresController: FeaturesController
historyModalController: HistoryModalController historyModalController: HistoryModalController
paneController: PaneController
className?: string className?: string
id: string id: string
children?: React.ReactNode children?: React.ReactNode
@@ -75,6 +77,7 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
linkingController, linkingController,
featuresController, featuresController,
historyModalController, historyModalController,
paneController,
className, className,
id, id,
children, children,
@@ -94,6 +97,7 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
renderedItems, renderedItems,
items, items,
isCurrentNoteTemplate, isCurrentNoteTemplate,
isTableViewEnabled,
} = itemListController } = itemListController
const innerRef = useForwardedRef(ref) const innerRef = useForwardedRef(ref)
@@ -185,9 +189,7 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
}, [isFilesSmartView, filesController, createNewNote, toggleAppPane, application]) }, [isFilesSmartView, filesController, createNewNote, toggleAppPane, application])
const isMobileScreen = useMediaQuery(MutuallyExclusiveMediaQueryBreakpoints.sm) const isMobileScreen = useMediaQuery(MutuallyExclusiveMediaQueryBreakpoints.sm)
const isFilesTableViewEnabled = application.features.isExperimentalFeatureEnabled(FeatureIdentifier.FilesTableView) const shouldUseTableView = (isFilesSmartView || isTableViewEnabled) && !isMobileScreen
const shouldShowFilesTableView =
isFilesTableViewEnabled && !isMobileScreen && selectedTag?.uuid === SystemViewId.Files
useEffect(() => { useEffect(() => {
const searchBarElement = document.getElementById(ElementIds.SearchBar) const searchBarElement = document.getElementById(ElementIds.SearchBar)
@@ -211,7 +213,7 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
if (searchBarElement === document.activeElement) { if (searchBarElement === document.activeElement) {
searchBarElement?.blur() searchBarElement?.blur()
} }
if (shouldShowFilesTableView) { if (shouldUseTableView) {
return return
} }
selectNextItem() selectNextItem()
@@ -221,7 +223,7 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
command: PREVIOUS_LIST_ITEM_KEYBOARD_COMMAND, command: PREVIOUS_LIST_ITEM_KEYBOARD_COMMAND,
element: document.body, element: document.body,
onKeyDown: () => { onKeyDown: () => {
if (shouldShowFilesTableView) { if (shouldUseTableView) {
return return
} }
selectPreviousItem() selectPreviousItem()
@@ -265,7 +267,7 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
selectNextItem, selectNextItem,
selectPreviousItem, selectPreviousItem,
selectionController, selectionController,
shouldShowFilesTableView, shouldUseTableView,
]) ])
const shortcutForCreate = useMemo( const shortcutForCreate = useMemo(
@@ -319,18 +321,19 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
addButtonLabel={addButtonLabel} addButtonLabel={addButtonLabel}
addNewItem={addNewItem} addNewItem={addNewItem}
isFilesSmartView={isFilesSmartView} isFilesSmartView={isFilesSmartView}
isFilesTableViewEnabled={isFilesTableViewEnabled} isTableViewEnabled={isTableViewEnabled}
optionsSubtitle={optionsSubtitle} optionsSubtitle={optionsSubtitle}
selectedTag={selectedTag} selectedTag={selectedTag}
filesController={filesController} filesController={filesController}
itemListController={itemListController} itemListController={itemListController}
paneController={paneController}
/> />
)} )}
{(!shouldShowFilesTableView || isMobileScreen) && ( {(!shouldUseTableView || isMobileScreen) && (
<SearchBar <SearchBar
itemListController={itemListController} itemListController={itemListController}
searchOptionsController={searchOptionsController} searchOptionsController={searchOptionsController}
hideOptions={shouldShowFilesTableView} hideOptions={shouldUseTableView}
/> />
)} )}
<NoAccountWarning <NoAccountWarning
@@ -355,7 +358,7 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
<p className="empty-items-list opacity-50">Loading...</p> <p className="empty-items-list opacity-50">Loading...</p>
) : null} ) : null}
{!dailyMode && renderedItems.length ? ( {!dailyMode && renderedItems.length ? (
shouldShowFilesTableView ? ( shouldUseTableView ? (
<ContentTableView <ContentTableView
items={items} items={items}
application={application} application={application}

View File

@@ -13,6 +13,7 @@ import AddItemMenuButton from './AddItemMenuButton'
import { FilesController } from '@/Controllers/FilesController' import { FilesController } from '@/Controllers/FilesController'
import SearchButton from './SearchButton' import SearchButton from './SearchButton'
import { ItemListController } from '@/Controllers/ItemList/ItemListController' import { ItemListController } from '@/Controllers/ItemList/ItemListController'
import { PaneController } from '@/Controllers/PaneController/PaneController'
type Props = { type Props = {
application: WebApplication application: WebApplication
@@ -21,11 +22,12 @@ type Props = {
addButtonLabel: string addButtonLabel: string
addNewItem: () => void addNewItem: () => void
isFilesSmartView: boolean isFilesSmartView: boolean
isFilesTableViewEnabled: boolean isTableViewEnabled: boolean
optionsSubtitle?: string optionsSubtitle?: string
selectedTag: AnyTag selectedTag: AnyTag
filesController: FilesController filesController: FilesController
itemListController: ItemListController itemListController: ItemListController
paneController: PaneController
} }
const ContentListHeader = ({ const ContentListHeader = ({
@@ -35,11 +37,12 @@ const ContentListHeader = ({
addButtonLabel, addButtonLabel,
addNewItem, addNewItem,
isFilesSmartView, isFilesSmartView,
isFilesTableViewEnabled, isTableViewEnabled,
optionsSubtitle, optionsSubtitle,
selectedTag, selectedTag,
filesController, filesController,
itemListController, itemListController,
paneController,
}: Props) => { }: Props) => {
const displayOptionsContainerRef = useRef<HTMLDivElement>(null) const displayOptionsContainerRef = useRef<HTMLDivElement>(null)
const displayOptionsButtonRef = useRef<HTMLButtonElement>(null) const displayOptionsButtonRef = useRef<HTMLButtonElement>(null)
@@ -79,19 +82,13 @@ const ContentListHeader = ({
isFilesSmartView={isFilesSmartView} isFilesSmartView={isFilesSmartView}
isOpen={showDisplayOptionsMenu} isOpen={showDisplayOptionsMenu}
selectedTag={selectedTag} selectedTag={selectedTag}
paneController={paneController}
/> />
</Popover> </Popover>
</div> </div>
</div> </div>
) )
}, [ }, [showDisplayOptionsMenu, toggleDisplayOptionsMenu, application, isFilesSmartView, selectedTag, paneController])
showDisplayOptionsMenu,
toggleDisplayOptionsMenu,
displayOptionsButtonRef,
application,
isFilesSmartView,
selectedTag,
])
const AddButton = useMemo(() => { const AddButton = useMemo(() => {
return ( return (
@@ -106,12 +103,12 @@ const ContentListHeader = ({
}, [addButtonLabel, addNewItem, filesController, isDailyEntry, isFilesSmartView]) }, [addButtonLabel, addNewItem, filesController, isDailyEntry, isFilesSmartView])
const SearchBarButton = useMemo(() => { const SearchBarButton = useMemo(() => {
if (!isFilesSmartView || !isFilesTableViewEnabled || isMobileScreen) { if (!isTableViewEnabled || isMobileScreen) {
return null return null
} }
return <SearchButton itemListController={itemListController} /> return <SearchButton itemListController={itemListController} />
}, [isFilesSmartView, isFilesTableViewEnabled, isMobileScreen, itemListController]) }, [isTableViewEnabled, isMobileScreen, itemListController])
const FolderName = useMemo(() => { const FolderName = useMemo(() => {
return ( return (

View File

@@ -1,7 +1,6 @@
import { import {
CollectionSort, CollectionSort,
CollectionSortProperty, CollectionSortProperty,
FeatureIdentifier,
IconType, IconType,
isSmartView, isSmartView,
isSystemView, isSystemView,
@@ -25,6 +24,8 @@ import NoSubscriptionBanner from '@/Components/NoSubscriptionBanner/NoSubscripti
import MenuRadioButtonItem from '@/Components/Menu/MenuRadioButtonItem' import MenuRadioButtonItem from '@/Components/Menu/MenuRadioButtonItem'
import MenuSwitchButtonItem from '@/Components/Menu/MenuSwitchButtonItem' import MenuSwitchButtonItem from '@/Components/Menu/MenuSwitchButtonItem'
import { Pill } from '@/Components/Preferences/PreferencesComponents/Content' import { Pill } from '@/Components/Preferences/PreferencesComponents/Content'
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
import { PaneLayout } from '@/Controllers/PaneController/PaneLayout'
const DailyEntryModeEnabled = true const DailyEntryModeEnabled = true
@@ -33,6 +34,7 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
isOpen, isOpen,
isFilesSmartView, isFilesSmartView,
selectedTag, selectedTag,
paneController,
}) => { }) => {
const isSystemTag = isSmartView(selectedTag) && isSystemView(selectedTag) const isSystemTag = isSmartView(selectedTag) && isSystemView(selectedTag)
const selectedTagPreferences = isSystemTag const selectedTagPreferences = isSystemTag
@@ -217,6 +219,14 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
void changePreferences({ entryMode: isDailyEntry ? 'normal' : 'daily' }) void changePreferences({ entryMode: isDailyEntry ? 'normal' : 'daily' })
}, [isDailyEntry, changePreferences]) }, [isDailyEntry, changePreferences])
const toggleTableView = useCallback(() => {
const useTableView = !preferences.useTableView
void changePreferences({ useTableView })
if (useTableView) {
paneController.setPaneLayout(PaneLayout.TableView)
}
}, [preferences.useTableView, changePreferences, paneController])
const TabButton: FunctionComponent<{ const TabButton: FunctionComponent<{
label: string label: string
mode: PreferenceMode mode: PreferenceMode
@@ -250,8 +260,9 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
) )
} }
const isFilesTableViewEnabled = application.features.isExperimentalFeatureEnabled(FeatureIdentifier.FilesTableView) const isMobileScreen = useMediaQuery(MutuallyExclusiveMediaQueryBreakpoints.sm)
const shouldHideNonApplicableOptions = isFilesTableViewEnabled && selectedTag?.uuid === SystemViewId.Files const isTableViewEnabled = Boolean(isFilesSmartView || preferences.useTableView)
const shouldHideNonApplicableOptions = isTableViewEnabled && !isMobileScreen
return ( return (
<Menu className="text-sm" a11yLabel="Notes list options menu" isOpen={isOpen}> <Menu className="text-sm" a11yLabel="Notes list options menu" isOpen={isOpen}>
@@ -410,7 +421,7 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
</> </>
)} )}
{currentMode === 'tag' && !isSystemTag && DailyEntryModeEnabled && ( {currentMode === 'tag' && !isSystemTag && DailyEntryModeEnabled && !isTableViewEnabled && (
<> <>
<MenuItemSeparator /> <MenuItemSeparator />
<MenuSwitchButtonItem <MenuSwitchButtonItem
@@ -432,6 +443,28 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
</> </>
)} )}
{currentMode === 'tag' && !isSystemTag && !isDailyEntry && (
<>
<MenuItemSeparator />
<MenuSwitchButtonItem
disabled={controlsDisabled}
className="py-1 hover:bg-contrast focus:bg-info-backdrop"
checked={isTableViewEnabled}
onChange={toggleTableView}
>
<div className="flex flex-col pr-5">
<div className="flex flex-row items-center">
<div className="text-base font-semibold uppercase text-text lg:text-xs">Table view</div>
<Pill className="py-0 px-1.5" style="success">
Labs
</Pill>
</div>
<div className="mt-1">Display the notes & files in the current tag in a table layout</div>
</div>
</MenuSwitchButtonItem>
</>
)}
{!shouldHideNonApplicableOptions && (!isSystemTag || currentMode === 'global') && ( {!shouldHideNonApplicableOptions && (!isSystemTag || currentMode === 'global') && (
<> <>
<MenuItemSeparator /> <MenuItemSeparator />

View File

@@ -1,5 +1,6 @@
import { WebApplication } from '@/Application/Application' import { WebApplication } from '@/Application/Application'
import { AnyTag } from '@/Controllers/Navigation/AnyTagType' import { AnyTag } from '@/Controllers/Navigation/AnyTagType'
import { PaneController } from '@/Controllers/PaneController/PaneController'
export type DisplayOptionsMenuPositionProps = { export type DisplayOptionsMenuPositionProps = {
top: number top: number
@@ -11,4 +12,5 @@ export type DisplayOptionsMenuProps = {
selectedTag: AnyTag selectedTag: AnyTag
isOpen: boolean isOpen: boolean
isFilesSmartView: boolean isFilesSmartView: boolean
paneController: PaneController
} }

View File

@@ -305,6 +305,7 @@ const PanesSystemComponent = () => {
linkingController={viewControllerManager.linkingController} linkingController={viewControllerManager.linkingController}
featuresController={viewControllerManager.featuresController} featuresController={viewControllerManager.featuresController}
historyModalController={viewControllerManager.historyModalController} historyModalController={viewControllerManager.historyModalController}
paneController={viewControllerManager.paneController}
> >
{showPanelResizers && listRef && ( {showPanelResizers && listRef && (
<PanelResizer <PanelResizer

View File

@@ -186,7 +186,7 @@ function Table<Data>({ table }: { table: Table<Data> }) {
break break
case KeyboardKey.Down: case KeyboardKey.Down:
event.preventDefault() event.preventDefault()
if (focusedRowIndex.current < rowCount) { if (focusedRowIndex.current <= rowCount) {
const nextRow = focusedRowIndex.current + 1 const nextRow = focusedRowIndex.current + 1
focusCell(nextRow, focusedCellIndex.current) focusCell(nextRow, focusedCellIndex.current)
} }

View File

@@ -1,5 +1,5 @@
import { ListableContentItem } from '@/Components/ContentListView/Types/ListableContentItem' import { ListableContentItem } from '@/Components/ContentListView/Types/ListableContentItem'
import { destroyAllObjectProperties } from '@/Utils' import { destroyAllObjectProperties, isMobileScreen } from '@/Utils'
import { import {
ApplicationEvent, ApplicationEvent,
CollectionSort, CollectionSort,
@@ -71,6 +71,7 @@ export class ItemListController extends AbstractViewController implements Intern
hideNotePreview: false, hideNotePreview: false,
hideEditorIcon: false, hideEditorIcon: false,
} }
isTableViewEnabled = false
private reloadItemsPromise?: Promise<unknown> private reloadItemsPromise?: Promise<unknown>
override deinit() { override deinit() {
@@ -451,6 +452,10 @@ export class ItemListController extends AbstractViewController implements Intern
this.selectionController.deselectItem(activeItem) this.selectionController.deselectItem(activeItem)
if (this.shouldSelectFirstItem(itemsReloadSource)) { if (this.shouldSelectFirstItem(itemsReloadSource)) {
if (this.isTableViewEnabled && !isMobileScreen()) {
return
}
log(LoggingDomain.Selection, 'Selecting next item after closing active one') log(LoggingDomain.Selection, 'Selecting next item after closing active one')
this.selectionController.selectNextItem({ userTriggered: false }) this.selectionController.selectNextItem({ userTriggered: false })
} }
@@ -513,6 +518,8 @@ export class ItemListController extends AbstractViewController implements Intern
? this.application.getPreference(PrefKey.SystemViewPreferences)?.[selectedTag.uuid as SystemViewId] ? this.application.getPreference(PrefKey.SystemViewPreferences)?.[selectedTag.uuid as SystemViewId]
: selectedTag?.preferences : selectedTag?.preferences
this.isTableViewEnabled = Boolean(selectedTagPreferences?.useTableView)
const currentSortBy = this.displayOptions.sortBy const currentSortBy = this.displayOptions.sortBy
let sortBy = let sortBy =
selectedTagPreferences?.sortBy || selectedTagPreferences?.sortBy ||
@@ -729,6 +736,10 @@ export class ItemListController extends AbstractViewController implements Intern
selectFirstItem = async () => { selectFirstItem = async () => {
const item = this.getFirstNonProtectedItem() const item = this.getFirstNonProtectedItem()
if (this.isTableViewEnabled && !isMobileScreen()) {
return
}
if (item) { if (item) {
log(LoggingDomain.Selection, 'Selecting first item', item.uuid) log(LoggingDomain.Selection, 'Selecting first item', item.uuid)

View File

@@ -14,6 +14,7 @@ import {
InternalEventPublishStrategy, InternalEventPublishStrategy,
VectorIconNameOrEmoji, VectorIconNameOrEmoji,
isTag, isTag,
PrefKey,
} from '@standardnotes/snjs' } from '@standardnotes/snjs'
import { action, computed, makeAutoObservable, makeObservable, observable, reaction, runInAction } from 'mobx' import { action, computed, makeAutoObservable, makeObservable, observable, reaction, runInAction } from 'mobx'
import { WebApplication } from '../../Application/Application' import { WebApplication } from '../../Application/Application'
@@ -268,6 +269,14 @@ export class NavigationController
return tag.uuid === SystemViewId.Files return tag.uuid === SystemViewId.Files
} }
tagUsesTableView(tag: AnyTag): boolean {
const isSystemView = tag instanceof SmartView && Object.values(SystemViewId).includes(tag.uuid as SystemViewId)
const useTableView = isSystemView
? this.application.getPreference(PrefKey.SystemViewPreferences)?.[tag.uuid as SystemViewId]
: tag?.preferences
return Boolean(useTableView)
}
public isInAnySystemView(): boolean { public isInAnySystemView(): boolean {
return ( return (
this.selected instanceof SmartView && Object.values(SystemViewId).includes(this.selected.uuid as SystemViewId) this.selected instanceof SmartView && Object.values(SystemViewId).includes(this.selected.uuid as SystemViewId)
@@ -466,8 +475,8 @@ export class NavigationController
.catch(console.error) .catch(console.error)
} }
if (tag && this.isTagFilesView(tag)) { if (tag && (this.isTagFilesView(tag) || this.tagUsesTableView(tag))) {
this.application.paneController.setPaneLayout(PaneLayout.FilesView) this.application.paneController.setPaneLayout(PaneLayout.TableView)
} else if (userTriggered) { } else if (userTriggered) {
this.application.paneController.setPaneLayout(PaneLayout.ItemSelection) this.application.paneController.setPaneLayout(PaneLayout.ItemSelection)
} }

View File

@@ -1,6 +1,6 @@
export enum PaneLayout { export enum PaneLayout {
TagSelection = 'tag-selection', TagSelection = 'tag-selection',
ItemSelection = 'item-selection', ItemSelection = 'item-selection',
FilesView = 'files-view', TableView = 'files-view',
Editing = 'editing', Editing = 'editing',
} }

View File

@@ -11,20 +11,20 @@ export function panesForLayout(layout: PaneLayout, application: WebApplication):
} else if ( } else if (
layout === PaneLayout.ItemSelection || layout === PaneLayout.ItemSelection ||
layout === PaneLayout.Editing || layout === PaneLayout.Editing ||
layout === PaneLayout.FilesView layout === PaneLayout.TableView
) { ) {
return [AppPaneId.Items, AppPaneId.Editor] return [AppPaneId.Items, AppPaneId.Editor]
} }
} else if (screen.isMobile) { } else if (screen.isMobile) {
if (layout === PaneLayout.TagSelection) { if (layout === PaneLayout.TagSelection) {
return [AppPaneId.Navigation] return [AppPaneId.Navigation]
} else if (layout === PaneLayout.ItemSelection || layout === PaneLayout.FilesView) { } else if (layout === PaneLayout.ItemSelection || layout === PaneLayout.TableView) {
return [AppPaneId.Navigation, AppPaneId.Items] return [AppPaneId.Navigation, AppPaneId.Items]
} else if (layout === PaneLayout.Editing) { } else if (layout === PaneLayout.Editing) {
return [AppPaneId.Navigation, AppPaneId.Items, AppPaneId.Editor] return [AppPaneId.Navigation, AppPaneId.Items, AppPaneId.Editor]
} }
} else { } else {
if (layout === PaneLayout.FilesView) { if (layout === PaneLayout.TableView) {
return [AppPaneId.Navigation, AppPaneId.Items] return [AppPaneId.Navigation, AppPaneId.Items]
} else { } else {
return [AppPaneId.Navigation, AppPaneId.Items, AppPaneId.Editor] return [AppPaneId.Navigation, AppPaneId.Items, AppPaneId.Editor]