From dd8ccdeadc6c2fd7f7ccd66f2dc4b0081616fb2b Mon Sep 17 00:00:00 2001 From: Aman Harwara Date: Fri, 6 Jan 2023 17:00:19 +0530 Subject: [PATCH] feat: Added per-tag preference to use table layout and removed "Files Table View" from Labs --- .../src/Domain/Feature/FeatureIdentifier.ts | 4 +- .../src/Domain/Lists/ExperimentalFeatures.ts | 15 +------ .../src/Domain/Permission/PermissionName.ts | 1 - .../src/Domain/Syncable/Tag/TagPreferences.ts | 1 + .../ContentListView/ContentList.tsx | 14 +------ .../ContentListView/ContentListItem.tsx | 13 +----- .../ContentListView/ContentListView.tsx | 25 ++++++----- .../Header/ContentListHeader.tsx | 21 ++++------ .../Header/DisplayOptionsMenu.tsx | 41 +++++++++++++++++-- .../Header/DisplayOptionsMenuProps.tsx | 2 + .../Components/Panes/PanesSystemComponent.tsx | 1 + .../javascripts/Components/Table/Table.tsx | 2 +- .../ItemList/ItemListController.ts | 13 +++++- .../Navigation/NavigationController.ts | 13 +++++- .../Controllers/PaneController/PaneLayout.ts | 2 +- .../PaneController/panesForLayout.ts | 6 +-- 16 files changed, 98 insertions(+), 76 deletions(-) diff --git a/packages/features/src/Domain/Feature/FeatureIdentifier.ts b/packages/features/src/Domain/Feature/FeatureIdentifier.ts index 430e7cd6b..990fee0b5 100644 --- a/packages/features/src/Domain/Feature/FeatureIdentifier.ts +++ b/packages/features/src/Domain/Feature/FeatureIdentifier.ts @@ -38,8 +38,6 @@ export enum FeatureIdentifier { TaskEditor = 'org.standardnotes.simple-task-editor', TokenVaultEditor = 'org.standardnotes.token-vault', - FilesTableView = 'org.standardnotes.files-table-view', - DeprecatedBoldEditor = 'org.standardnotes.bold-editor', DeprecatedMarkdownBasicEditor = 'org.standardnotes.simple-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 ExperimentalFeatures = [FeatureIdentifier.FilesTableView] +export const ExperimentalFeatures = [] diff --git a/packages/features/src/Domain/Lists/ExperimentalFeatures.ts b/packages/features/src/Domain/Lists/ExperimentalFeatures.ts index a5b1fce49..30c3ebf5a 100644 --- a/packages/features/src/Domain/Lists/ExperimentalFeatures.ts +++ b/packages/features/src/Domain/Lists/ExperimentalFeatures.ts @@ -1,18 +1,5 @@ -import { RoleName, SubscriptionName } from '@standardnotes/common' import { FeatureDescription } from '../Feature/FeatureDescription' -import { FeatureIdentifier } from '../Feature/FeatureIdentifier' -import { PermissionName } from '../Permission/PermissionName' export function experimentalFeatures(): FeatureDescription[] { - const filesTableView: FeatureDescription = { - 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] + return [] } diff --git a/packages/features/src/Domain/Permission/PermissionName.ts b/packages/features/src/Domain/Permission/PermissionName.ts index 9d30ff8b3..17fab4c39 100644 --- a/packages/features/src/Domain/Permission/PermissionName.ts +++ b/packages/features/src/Domain/Permission/PermissionName.ts @@ -40,5 +40,4 @@ export enum PermissionName { TwoFactorAuth = 'server:two-factor-auth', SubscriptionSharing = 'server:subscription-sharing', SuperEditor = 'editor:super-editor', - FilesTableView = 'app:files-table-view', } diff --git a/packages/models/src/Domain/Syncable/Tag/TagPreferences.ts b/packages/models/src/Domain/Syncable/Tag/TagPreferences.ts index e61d01b7c..2fc70d269 100644 --- a/packages/models/src/Domain/Syncable/Tag/TagPreferences.ts +++ b/packages/models/src/Domain/Syncable/Tag/TagPreferences.ts @@ -18,4 +18,5 @@ export interface TagPreferences { editorIdentifier?: EditorIdentifier entryMode?: 'normal' | 'daily' panelWidth?: number + useTableView?: boolean } diff --git a/packages/web/src/javascripts/Components/ContentListView/ContentList.tsx b/packages/web/src/javascripts/Components/ContentListView/ContentList.tsx index 15a0eaf16..1d6065adf 100644 --- a/packages/web/src/javascripts/Components/ContentListView/ContentList.tsx +++ b/packages/web/src/javascripts/Components/ContentListView/ContentList.tsx @@ -12,7 +12,7 @@ import { NavigationController } from '@/Controllers/Navigation/NavigationControl import { NotesController } from '@/Controllers/NotesController/NotesController' import { ElementIds } from '@/Constants/ElementIDs' import { classNames } from '@standardnotes/utils' -import { ContentType, FeatureIdentifier, SNTag } from '@standardnotes/snjs' +import { ContentType, SNTag } from '@standardnotes/snjs' type Props = { application: WebApplication @@ -97,8 +97,6 @@ const ContentList: FunctionComponent = ({ const hasNotes = items.some((item) => item.content_type === ContentType.Note) - const isFilesTableViewEnabled = application.features.isExperimentalFeatureEnabled(FeatureIdentifier.FilesTableView) - return (
= ({ onKeyDown={onKeyDown} tabIndex={FOCUSABLE_BUT_NOT_TABBABLE} > - {items.map((item, index) => { - const previousIndex = index - 1 - const previousItem = previousIndex >= 0 ? items[previousIndex] : undefined - - const nextIndex = index + 1 - const nextItem = nextIndex < items.length ? items[nextIndex] : undefined - + {items.map((item) => { return ( = ({ onSelect={selectItem} tags={getTagsForItem(item)} notesController={notesController} - isPreviousItemTiled={previousItem?.content_type === ContentType.File && !isFilesTableViewEnabled} - isNextItemTiled={nextItem?.content_type === ContentType.File && !isFilesTableViewEnabled} /> ) })} diff --git a/packages/web/src/javascripts/Components/ContentListView/ContentListItem.tsx b/packages/web/src/javascripts/Components/ContentListView/ContentListItem.tsx index 344fde822..6550f8fc9 100644 --- a/packages/web/src/javascripts/Components/ContentListView/ContentListItem.tsx +++ b/packages/web/src/javascripts/Components/ContentListView/ContentListItem.tsx @@ -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 FileListItem from './FileListItem' -import FileListItemCard from './FileListItemCard' import NoteListItem from './NoteListItem' import { AbstractListItemProps, doListItemPropsMeritRerender } from './Types/AbstractListItemProps' import { ListableContentItem } from './Types/ListableContentItem' const ContentListItem: FunctionComponent> = (props) => { - const isFilesTableViewEnabled = props.application.features.isExperimentalFeatureEnabled( - FeatureIdentifier.FilesTableView, - ) - switch (props.item.content_type) { case ContentType.Note: return case ContentType.File: { - if (isFilesTableViewEnabled) { - return - } - - return + return } default: return null diff --git a/packages/web/src/javascripts/Components/ContentListView/ContentListView.tsx b/packages/web/src/javascripts/Components/ContentListView/ContentListView.tsx index ce7c9390c..00d64e052 100644 --- a/packages/web/src/javascripts/Components/ContentListView/ContentListView.tsx +++ b/packages/web/src/javascripts/Components/ContentListView/ContentListView.tsx @@ -9,7 +9,7 @@ import { } from '@standardnotes/ui-services' import { WebApplication } from '@/Application/Application' 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 { forwardRef, useCallback, useEffect, useMemo } from 'react' import ContentList from '@/Components/ContentListView/ContentList' @@ -40,6 +40,7 @@ import ContentTableView from '../ContentTableView/ContentTableView' import { FeaturesController } from '@/Controllers/FeaturesController' import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery' import { HistoryModalController } from '@/Controllers/NoteHistory/HistoryModalController' +import { PaneController } from '@/Controllers/PaneController/PaneController' type Props = { accountMenuController: AccountMenuController @@ -54,6 +55,7 @@ type Props = { linkingController: LinkingController featuresController: FeaturesController historyModalController: HistoryModalController + paneController: PaneController className?: string id: string children?: React.ReactNode @@ -75,6 +77,7 @@ const ContentListView = forwardRef( linkingController, featuresController, historyModalController, + paneController, className, id, children, @@ -94,6 +97,7 @@ const ContentListView = forwardRef( renderedItems, items, isCurrentNoteTemplate, + isTableViewEnabled, } = itemListController const innerRef = useForwardedRef(ref) @@ -185,9 +189,7 @@ const ContentListView = forwardRef( }, [isFilesSmartView, filesController, createNewNote, toggleAppPane, application]) const isMobileScreen = useMediaQuery(MutuallyExclusiveMediaQueryBreakpoints.sm) - const isFilesTableViewEnabled = application.features.isExperimentalFeatureEnabled(FeatureIdentifier.FilesTableView) - const shouldShowFilesTableView = - isFilesTableViewEnabled && !isMobileScreen && selectedTag?.uuid === SystemViewId.Files + const shouldUseTableView = (isFilesSmartView || isTableViewEnabled) && !isMobileScreen useEffect(() => { const searchBarElement = document.getElementById(ElementIds.SearchBar) @@ -211,7 +213,7 @@ const ContentListView = forwardRef( if (searchBarElement === document.activeElement) { searchBarElement?.blur() } - if (shouldShowFilesTableView) { + if (shouldUseTableView) { return } selectNextItem() @@ -221,7 +223,7 @@ const ContentListView = forwardRef( command: PREVIOUS_LIST_ITEM_KEYBOARD_COMMAND, element: document.body, onKeyDown: () => { - if (shouldShowFilesTableView) { + if (shouldUseTableView) { return } selectPreviousItem() @@ -265,7 +267,7 @@ const ContentListView = forwardRef( selectNextItem, selectPreviousItem, selectionController, - shouldShowFilesTableView, + shouldUseTableView, ]) const shortcutForCreate = useMemo( @@ -319,18 +321,19 @@ const ContentListView = forwardRef( addButtonLabel={addButtonLabel} addNewItem={addNewItem} isFilesSmartView={isFilesSmartView} - isFilesTableViewEnabled={isFilesTableViewEnabled} + isTableViewEnabled={isTableViewEnabled} optionsSubtitle={optionsSubtitle} selectedTag={selectedTag} filesController={filesController} itemListController={itemListController} + paneController={paneController} /> )} - {(!shouldShowFilesTableView || isMobileScreen) && ( + {(!shouldUseTableView || isMobileScreen) && ( )} (

Loading...

) : null} {!dailyMode && renderedItems.length ? ( - shouldShowFilesTableView ? ( + shouldUseTableView ? ( void isFilesSmartView: boolean - isFilesTableViewEnabled: boolean + isTableViewEnabled: boolean optionsSubtitle?: string selectedTag: AnyTag filesController: FilesController itemListController: ItemListController + paneController: PaneController } const ContentListHeader = ({ @@ -35,11 +37,12 @@ const ContentListHeader = ({ addButtonLabel, addNewItem, isFilesSmartView, - isFilesTableViewEnabled, + isTableViewEnabled, optionsSubtitle, selectedTag, filesController, itemListController, + paneController, }: Props) => { const displayOptionsContainerRef = useRef(null) const displayOptionsButtonRef = useRef(null) @@ -79,19 +82,13 @@ const ContentListHeader = ({ isFilesSmartView={isFilesSmartView} isOpen={showDisplayOptionsMenu} selectedTag={selectedTag} + paneController={paneController} />
) - }, [ - showDisplayOptionsMenu, - toggleDisplayOptionsMenu, - displayOptionsButtonRef, - application, - isFilesSmartView, - selectedTag, - ]) + }, [showDisplayOptionsMenu, toggleDisplayOptionsMenu, application, isFilesSmartView, selectedTag, paneController]) const AddButton = useMemo(() => { return ( @@ -106,12 +103,12 @@ const ContentListHeader = ({ }, [addButtonLabel, addNewItem, filesController, isDailyEntry, isFilesSmartView]) const SearchBarButton = useMemo(() => { - if (!isFilesSmartView || !isFilesTableViewEnabled || isMobileScreen) { + if (!isTableViewEnabled || isMobileScreen) { return null } return - }, [isFilesSmartView, isFilesTableViewEnabled, isMobileScreen, itemListController]) + }, [isTableViewEnabled, isMobileScreen, itemListController]) const FolderName = useMemo(() => { return ( diff --git a/packages/web/src/javascripts/Components/ContentListView/Header/DisplayOptionsMenu.tsx b/packages/web/src/javascripts/Components/ContentListView/Header/DisplayOptionsMenu.tsx index f537b4043..fb4a59c4d 100644 --- a/packages/web/src/javascripts/Components/ContentListView/Header/DisplayOptionsMenu.tsx +++ b/packages/web/src/javascripts/Components/ContentListView/Header/DisplayOptionsMenu.tsx @@ -1,7 +1,6 @@ import { CollectionSort, CollectionSortProperty, - FeatureIdentifier, IconType, isSmartView, isSystemView, @@ -25,6 +24,8 @@ import NoSubscriptionBanner from '@/Components/NoSubscriptionBanner/NoSubscripti import MenuRadioButtonItem from '@/Components/Menu/MenuRadioButtonItem' import MenuSwitchButtonItem from '@/Components/Menu/MenuSwitchButtonItem' import { Pill } from '@/Components/Preferences/PreferencesComponents/Content' +import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery' +import { PaneLayout } from '@/Controllers/PaneController/PaneLayout' const DailyEntryModeEnabled = true @@ -33,6 +34,7 @@ const DisplayOptionsMenu: FunctionComponent = ({ isOpen, isFilesSmartView, selectedTag, + paneController, }) => { const isSystemTag = isSmartView(selectedTag) && isSystemView(selectedTag) const selectedTagPreferences = isSystemTag @@ -217,6 +219,14 @@ const DisplayOptionsMenu: FunctionComponent = ({ void changePreferences({ entryMode: isDailyEntry ? 'normal' : 'daily' }) }, [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<{ label: string mode: PreferenceMode @@ -250,8 +260,9 @@ const DisplayOptionsMenu: FunctionComponent = ({ ) } - const isFilesTableViewEnabled = application.features.isExperimentalFeatureEnabled(FeatureIdentifier.FilesTableView) - const shouldHideNonApplicableOptions = isFilesTableViewEnabled && selectedTag?.uuid === SystemViewId.Files + const isMobileScreen = useMediaQuery(MutuallyExclusiveMediaQueryBreakpoints.sm) + const isTableViewEnabled = Boolean(isFilesSmartView || preferences.useTableView) + const shouldHideNonApplicableOptions = isTableViewEnabled && !isMobileScreen return ( @@ -410,7 +421,7 @@ const DisplayOptionsMenu: FunctionComponent = ({ )} - {currentMode === 'tag' && !isSystemTag && DailyEntryModeEnabled && ( + {currentMode === 'tag' && !isSystemTag && DailyEntryModeEnabled && !isTableViewEnabled && ( <> = ({ )} + {currentMode === 'tag' && !isSystemTag && !isDailyEntry && ( + <> + + +
+
+
Table view
+ + Labs + +
+
Display the notes & files in the current tag in a table layout
+
+
+ + )} + {!shouldHideNonApplicableOptions && (!isSystemTag || currentMode === 'global') && ( <> diff --git a/packages/web/src/javascripts/Components/ContentListView/Header/DisplayOptionsMenuProps.tsx b/packages/web/src/javascripts/Components/ContentListView/Header/DisplayOptionsMenuProps.tsx index 9dcac55ba..3047fd665 100644 --- a/packages/web/src/javascripts/Components/ContentListView/Header/DisplayOptionsMenuProps.tsx +++ b/packages/web/src/javascripts/Components/ContentListView/Header/DisplayOptionsMenuProps.tsx @@ -1,5 +1,6 @@ import { WebApplication } from '@/Application/Application' import { AnyTag } from '@/Controllers/Navigation/AnyTagType' +import { PaneController } from '@/Controllers/PaneController/PaneController' export type DisplayOptionsMenuPositionProps = { top: number @@ -11,4 +12,5 @@ export type DisplayOptionsMenuProps = { selectedTag: AnyTag isOpen: boolean isFilesSmartView: boolean + paneController: PaneController } diff --git a/packages/web/src/javascripts/Components/Panes/PanesSystemComponent.tsx b/packages/web/src/javascripts/Components/Panes/PanesSystemComponent.tsx index 0a3e09533..4b58f8930 100644 --- a/packages/web/src/javascripts/Components/Panes/PanesSystemComponent.tsx +++ b/packages/web/src/javascripts/Components/Panes/PanesSystemComponent.tsx @@ -305,6 +305,7 @@ const PanesSystemComponent = () => { linkingController={viewControllerManager.linkingController} featuresController={viewControllerManager.featuresController} historyModalController={viewControllerManager.historyModalController} + paneController={viewControllerManager.paneController} > {showPanelResizers && listRef && ( ({ table }: { table: Table }) { break case KeyboardKey.Down: event.preventDefault() - if (focusedRowIndex.current < rowCount) { + if (focusedRowIndex.current <= rowCount) { const nextRow = focusedRowIndex.current + 1 focusCell(nextRow, focusedCellIndex.current) } diff --git a/packages/web/src/javascripts/Controllers/ItemList/ItemListController.ts b/packages/web/src/javascripts/Controllers/ItemList/ItemListController.ts index ac38d1e60..5aaaf2858 100644 --- a/packages/web/src/javascripts/Controllers/ItemList/ItemListController.ts +++ b/packages/web/src/javascripts/Controllers/ItemList/ItemListController.ts @@ -1,5 +1,5 @@ import { ListableContentItem } from '@/Components/ContentListView/Types/ListableContentItem' -import { destroyAllObjectProperties } from '@/Utils' +import { destroyAllObjectProperties, isMobileScreen } from '@/Utils' import { ApplicationEvent, CollectionSort, @@ -71,6 +71,7 @@ export class ItemListController extends AbstractViewController implements Intern hideNotePreview: false, hideEditorIcon: false, } + isTableViewEnabled = false private reloadItemsPromise?: Promise override deinit() { @@ -451,6 +452,10 @@ export class ItemListController extends AbstractViewController implements Intern this.selectionController.deselectItem(activeItem) if (this.shouldSelectFirstItem(itemsReloadSource)) { + if (this.isTableViewEnabled && !isMobileScreen()) { + return + } + log(LoggingDomain.Selection, 'Selecting next item after closing active one') 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] : selectedTag?.preferences + this.isTableViewEnabled = Boolean(selectedTagPreferences?.useTableView) + const currentSortBy = this.displayOptions.sortBy let sortBy = selectedTagPreferences?.sortBy || @@ -729,6 +736,10 @@ export class ItemListController extends AbstractViewController implements Intern selectFirstItem = async () => { const item = this.getFirstNonProtectedItem() + if (this.isTableViewEnabled && !isMobileScreen()) { + return + } + if (item) { log(LoggingDomain.Selection, 'Selecting first item', item.uuid) diff --git a/packages/web/src/javascripts/Controllers/Navigation/NavigationController.ts b/packages/web/src/javascripts/Controllers/Navigation/NavigationController.ts index 9726fd697..df418f412 100644 --- a/packages/web/src/javascripts/Controllers/Navigation/NavigationController.ts +++ b/packages/web/src/javascripts/Controllers/Navigation/NavigationController.ts @@ -14,6 +14,7 @@ import { InternalEventPublishStrategy, VectorIconNameOrEmoji, isTag, + PrefKey, } from '@standardnotes/snjs' import { action, computed, makeAutoObservable, makeObservable, observable, reaction, runInAction } from 'mobx' import { WebApplication } from '../../Application/Application' @@ -268,6 +269,14 @@ export class NavigationController 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 { return ( this.selected instanceof SmartView && Object.values(SystemViewId).includes(this.selected.uuid as SystemViewId) @@ -466,8 +475,8 @@ export class NavigationController .catch(console.error) } - if (tag && this.isTagFilesView(tag)) { - this.application.paneController.setPaneLayout(PaneLayout.FilesView) + if (tag && (this.isTagFilesView(tag) || this.tagUsesTableView(tag))) { + this.application.paneController.setPaneLayout(PaneLayout.TableView) } else if (userTriggered) { this.application.paneController.setPaneLayout(PaneLayout.ItemSelection) } diff --git a/packages/web/src/javascripts/Controllers/PaneController/PaneLayout.ts b/packages/web/src/javascripts/Controllers/PaneController/PaneLayout.ts index d9bba698d..926e5e7c7 100644 --- a/packages/web/src/javascripts/Controllers/PaneController/PaneLayout.ts +++ b/packages/web/src/javascripts/Controllers/PaneController/PaneLayout.ts @@ -1,6 +1,6 @@ export enum PaneLayout { TagSelection = 'tag-selection', ItemSelection = 'item-selection', - FilesView = 'files-view', + TableView = 'files-view', Editing = 'editing', } diff --git a/packages/web/src/javascripts/Controllers/PaneController/panesForLayout.ts b/packages/web/src/javascripts/Controllers/PaneController/panesForLayout.ts index 33c1e314a..d2ba01225 100644 --- a/packages/web/src/javascripts/Controllers/PaneController/panesForLayout.ts +++ b/packages/web/src/javascripts/Controllers/PaneController/panesForLayout.ts @@ -11,20 +11,20 @@ export function panesForLayout(layout: PaneLayout, application: WebApplication): } else if ( layout === PaneLayout.ItemSelection || layout === PaneLayout.Editing || - layout === PaneLayout.FilesView + layout === PaneLayout.TableView ) { return [AppPaneId.Items, AppPaneId.Editor] } } else if (screen.isMobile) { if (layout === PaneLayout.TagSelection) { return [AppPaneId.Navigation] - } else if (layout === PaneLayout.ItemSelection || layout === PaneLayout.FilesView) { + } else if (layout === PaneLayout.ItemSelection || layout === PaneLayout.TableView) { return [AppPaneId.Navigation, AppPaneId.Items] } else if (layout === PaneLayout.Editing) { return [AppPaneId.Navigation, AppPaneId.Items, AppPaneId.Editor] } } else { - if (layout === PaneLayout.FilesView) { + if (layout === PaneLayout.TableView) { return [AppPaneId.Navigation, AppPaneId.Items] } else { return [AppPaneId.Navigation, AppPaneId.Items, AppPaneId.Editor]