feat: add shared page filter to all pages (#5540)

Co-authored-by: EYHN <cneyhn@gmail.com>
This commit is contained in:
Whitewater
2024-02-23 16:07:13 +08:00
committed by GitHub
parent 745110c799
commit 228b0d789d
17 changed files with 134 additions and 38 deletions

View File

@@ -34,6 +34,7 @@ const mockVariableMap = (vars: Partial<VariableMap>): VariableMap => {
Created: 0, Created: 0,
Updated: 0, Updated: 0,
'Is Favourited': false, 'Is Favourited': false,
'Is Public': false,
Tags: [], Tags: [],
...vars, ...vars,
}; };

View File

@@ -104,7 +104,7 @@ export const VirtualizedPageList = ({
const filteredPageMetas = useFilteredPageMetas( const filteredPageMetas = useFilteredPageMetas(
'all', 'all',
pageMetas, pageMetas,
currentWorkspace.blockSuiteWorkspace currentWorkspace
); );
const pageMetasToRender = useMemo(() => { const pageMetasToRender = useMemo(() => {
if (listItem) { if (listItem) {

View File

@@ -15,6 +15,8 @@ const useFilterTag = ({ name }: FilterTagProps) => {
return t['Tags'](); return t['Tags']();
case 'Is Favourited': case 'Is Favourited':
return t['com.affine.filter.is-favourited'](); return t['com.affine.filter.is-favourited']();
case 'Is Public':
return t['com.affine.filter.is-public']();
case 'after': case 'after':
return t['com.affine.filter.after'](); return t['com.affine.filter.after']();
case 'before': case 'before':

View File

@@ -5,6 +5,7 @@ import type {
VariableMap, VariableMap,
} from '@affine/env/filter'; } from '@affine/env/filter';
import { import {
CloudWorkspaceIcon,
CreatedIcon, CreatedIcon,
FavoriteIcon, FavoriteIcon,
TagsIcon, TagsIcon,
@@ -44,6 +45,10 @@ export const variableDefineMap = {
type: meta => tArray(tTag.create({ tags: meta.tags?.options ?? [] })), type: meta => tArray(tTag.create({ tags: meta.tags?.options ?? [] })),
icon: <TagsIcon />, icon: <TagsIcon />,
}, },
'Is Public': {
type: () => tBoolean.create(),
icon: <CloudWorkspaceIcon />,
},
// Imported: { // Imported: {
// type: tBoolean.create(), // type: tBoolean.create(),
// }, // },

View File

@@ -97,24 +97,30 @@ export const useCollectionManager = (collectionService: CollectionService) => {
export const filterByFilterList = (filterList: Filter[], varMap: VariableMap) => export const filterByFilterList = (filterList: Filter[], varMap: VariableMap) =>
evalFilterList(filterList, varMap); evalFilterList(filterList, varMap);
export const filterPage = (collection: Collection, page: PageMeta) => { export type PageDataForFilter = {
meta: PageMeta;
publicMode: undefined | 'page' | 'edgeless';
};
export const filterPage = (collection: Collection, page: PageDataForFilter) => {
if (collection.filterList.length === 0) { if (collection.filterList.length === 0) {
return collection.allowList.includes(page.id); return collection.allowList.includes(page.meta.id);
} }
return filterPageByRules(collection.filterList, collection.allowList, page); return filterPageByRules(collection.filterList, collection.allowList, page);
}; };
export const filterPageByRules = ( export const filterPageByRules = (
rules: Filter[], rules: Filter[],
allowList: string[], allowList: string[],
page: PageMeta { meta, publicMode }: PageDataForFilter
) => { ) => {
if (allowList?.includes(page.id)) { if (allowList?.includes(meta.id)) {
return true; return true;
} }
return filterByFilterList(rules, { return filterByFilterList(rules, {
'Is Favourited': !!page.favorite, 'Is Favourited': !!meta.favorite,
Created: page.createDate, 'Is Public': !!publicMode,
Updated: page.updatedDate ?? page.createDate, Created: meta.createDate,
Tags: page.tags, Updated: meta.updatedDate ?? meta.createDate,
Tags: meta.tags,
}); });
}; };

View File

@@ -1,8 +1,9 @@
import { allPageModeSelectAtom } from '@affine/core/atoms'; import { allPageModeSelectAtom } from '@affine/core/atoms';
import { usePageHelper } from '@affine/core/components/blocksuite/block-suite-page-list/utils'; import { usePageHelper } from '@affine/core/components/blocksuite/block-suite-page-list/utils';
import { usePublicPages } from '@affine/core/hooks/affine/use-is-shared-page';
import { CollectionService } from '@affine/core/modules/collection'; import { CollectionService } from '@affine/core/modules/collection';
import type { BlockSuiteWorkspace } from '@affine/core/shared';
import type { PageMeta } from '@blocksuite/store'; import type { PageMeta } from '@blocksuite/store';
import type { Workspace } from '@toeverything/infra';
import { useService } from '@toeverything/infra/di'; import { useService } from '@toeverything/infra/di';
import { useAtomValue } from 'jotai'; import { useAtomValue } from 'jotai';
import { useMemo } from 'react'; import { useMemo } from 'react';
@@ -16,13 +17,14 @@ import {
export const useFilteredPageMetas = ( export const useFilteredPageMetas = (
route: 'all' | 'trash', route: 'all' | 'trash',
pageMetas: PageMeta[], pageMetas: PageMeta[],
workspace: BlockSuiteWorkspace workspace: Workspace
) => { ) => {
const { isPreferredEdgeless } = usePageHelper(workspace); const { isPreferredEdgeless } = usePageHelper(workspace.blockSuiteWorkspace);
const pageMode = useAtomValue(allPageModeSelectAtom); const pageMode = useAtomValue(allPageModeSelectAtom);
const { currentCollection, isDefault } = useCollectionManager( const { currentCollection, isDefault } = useCollectionManager(
useService(CollectionService) useService(CollectionService)
); );
const { getPublicMode } = usePublicPages(workspace);
const filteredPageMetas = useMemo( const filteredPageMetas = useMemo(
() => () =>
@@ -50,18 +52,23 @@ export const useFilteredPageMetas = (
if (!currentCollection) { if (!currentCollection) {
return true; return true;
} }
const pageData = {
meta: pageMeta,
publicMode: getPublicMode(pageMeta.id),
};
return isDefault return isDefault
? filterPageByRules( ? filterPageByRules(
currentCollection.filterList, currentCollection.filterList,
currentCollection.allowList, currentCollection.allowList,
pageMeta pageData
) )
: filterPage(currentCollection, pageMeta); : filterPage(currentCollection, pageData);
}), }),
[ [
currentCollection, currentCollection,
isDefault, isDefault,
isPreferredEdgeless, isPreferredEdgeless,
getPublicMode,
pageMetas, pageMetas,
pageMode, pageMode,
route, route,

View File

@@ -201,6 +201,10 @@ export type AllPageListConfig = {
allPages: PageMeta[]; allPages: PageMeta[];
workspace: Workspace; workspace: Workspace;
isEdgeless: (id: string) => boolean; isEdgeless: (id: string) => boolean;
/**
* Return `undefined` if the page is not public
*/
getPublicMode: (id: string) => undefined | 'page' | 'edgeless';
getPage: (id: string) => PageMeta | undefined; getPage: (id: string) => PageMeta | undefined;
favoriteRender: (page: PageMeta) => ReactNode; favoriteRender: (page: PageMeta) => ReactNode;
}; };

View File

@@ -40,7 +40,12 @@ export const PagesMode = ({
clickFilter, clickFilter,
createFilter, createFilter,
filteredList, filteredList,
} = useFilter(allPageListConfig.allPages); } = useFilter(
allPageListConfig.allPages.map(meta => ({
meta,
publicMode: allPageListConfig.getPublicMode(meta.id),
}))
);
const { searchText, updateSearchText, searchedList } = const { searchText, updateSearchText, searchedList } =
useSearch(filteredList); useSearch(filteredList);
const clearSelected = useCallback(() => { const clearSelected = useCallback(() => {

View File

@@ -48,18 +48,22 @@ export const RulesMode = ({
setShowTips(false); setShowTips(false);
localStorage.setItem('hide-rules-mode-include-page-tips', 'true'); localStorage.setItem('hide-rules-mode-include-page-tips', 'true');
}, []); }, []);
allPageListConfig.allPages.forEach(v => { allPageListConfig.allPages.forEach(meta => {
if (v.trash) { if (meta.trash) {
return; return;
} }
const pageData = {
meta,
publicMode: allPageListConfig.getPublicMode(meta.id),
};
if ( if (
collection.filterList.length && collection.filterList.length &&
filterPageByRules(collection.filterList, [], v) filterPageByRules(collection.filterList, [], pageData)
) { ) {
rulesPages.push(v); rulesPages.push(meta);
} }
if (collection.allowList.includes(v.id)) { if (collection.allowList.includes(meta.id)) {
allowListPages.push(v); allowListPages.push(meta);
} }
}); });
const { node: selectPageNode, open } = useSelectPage({ allPageListConfig }); const { node: selectPageNode, open } = useSelectPage({ allPageListConfig });

View File

@@ -42,7 +42,12 @@ export const SelectPage = ({
showFilter, showFilter,
updateFilters, updateFilters,
filteredList, filteredList,
} = useFilter(allPageListConfig.allPages); } = useFilter(
allPageListConfig.allPages.map(meta => ({
meta,
publicMode: allPageListConfig.getPublicMode(meta.id),
}))
);
const { searchText, updateSearchText, searchedList } = const { searchText, updateSearchText, searchedList } =
useSearch(filteredList); useSearch(filteredList);

View File

@@ -1,10 +1,12 @@
import type { Filter } from '@affine/env/filter'; import type { Filter } from '@affine/env/filter';
import type { PageMeta } from '@blocksuite/store';
import { type MouseEvent, useCallback, useState } from 'react'; import { type MouseEvent, useCallback, useState } from 'react';
import { filterPageByRules } from '../../use-collection-manager'; import {
filterPageByRules,
type PageDataForFilter,
} from '../../use-collection-manager';
export const useFilter = (list: PageMeta[]) => { export const useFilter = (list: PageDataForFilter[]) => {
const [filters, changeFilters] = useState<Filter[]>([]); const [filters, changeFilters] = useState<Filter[]>([]);
const [showFilter, setShowFilter] = useState(false); const [showFilter, setShowFilter] = useState(false);
const clickFilter = useCallback( const clickFilter = useCallback(
@@ -30,11 +32,13 @@ export const useFilter = (list: PageMeta[]) => {
updateFilters: changeFilters, updateFilters: changeFilters,
clickFilter, clickFilter,
createFilter: onCreateFilter, createFilter: onCreateFilter,
filteredList: list.filter(v => { filteredList: list
if (v.trash) { .filter(pageData => {
return false; if (pageData.meta.trash) {
} return false;
return filterPageByRules(filters, [], v); }
}), return filterPageByRules(filters, [], pageData);
})
.map(pageData => pageData.meta),
}; };
}; };

View File

@@ -81,9 +81,14 @@ const CollectionRenderer = ({
[collection.allowList] [collection.allowList]
); );
const pagesToRender = pages.filter( const pagesToRender = pages.filter(meta => {
page => filterPage(collection, page) && !page.trash if (meta.trash) return false;
); const pageData = {
meta,
publicMode: config.getPublicMode(meta.id),
};
return filterPage(collection, pageData);
});
const location = useLocation(); const location = useLocation();
const currentPath = location.pathname.split('?')[0]; const currentPath = location.pathname.split('?')[0];
const path = `/workspace/${workspace.id}/collection/${collection.id}`; const path = `/workspace/${workspace.id}/collection/${collection.id}`;

View File

@@ -12,9 +12,11 @@ import { useCallback, useMemo } from 'react';
import { usePageHelper } from '../../components/blocksuite/block-suite-page-list/utils'; import { usePageHelper } from '../../components/blocksuite/block-suite-page-list/utils';
import { useBlockSuiteMetaHelper } from './use-block-suite-meta-helper'; import { useBlockSuiteMetaHelper } from './use-block-suite-meta-helper';
import { usePublicPages } from './use-is-shared-page';
export const useAllPageListConfig = () => { export const useAllPageListConfig = () => {
const currentWorkspace = useService(Workspace); const currentWorkspace = useService(Workspace);
const { getPublicMode } = usePublicPages(currentWorkspace);
const workspace = currentWorkspace.blockSuiteWorkspace; const workspace = currentWorkspace.blockSuiteWorkspace;
const pageMetas = useBlockSuitePageMeta(workspace); const pageMetas = useBlockSuitePageMeta(workspace);
const { isPreferredEdgeless } = usePageHelper(workspace); const { isPreferredEdgeless } = usePageHelper(workspace);
@@ -42,6 +44,7 @@ export const useAllPageListConfig = () => {
return { return {
allPages: pageMetas, allPages: pageMetas,
isEdgeless: isPreferredEdgeless, isEdgeless: isPreferredEdgeless,
getPublicMode,
workspace: currentWorkspace.blockSuiteWorkspace, workspace: currentWorkspace.blockSuiteWorkspace,
getPage: id => pageMap[id], getPage: id => pageMap[id],
favoriteRender: page => { favoriteRender: page => {
@@ -55,9 +58,10 @@ export const useAllPageListConfig = () => {
}, },
}; };
}, [ }, [
currentWorkspace.blockSuiteWorkspace,
isPreferredEdgeless,
pageMetas, pageMetas,
isPreferredEdgeless,
getPublicMode,
currentWorkspace.blockSuiteWorkspace,
pageMap, pageMap,
onToggleFavoritePage, onToggleFavoritePage,
]); ]);

View File

@@ -1,4 +1,5 @@
import { pushNotificationAtom } from '@affine/component/notification-center'; import { pushNotificationAtom } from '@affine/component/notification-center';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { import {
getWorkspacePublicPagesQuery, getWorkspacePublicPagesQuery,
PublicPageMode, PublicPageMode,
@@ -6,6 +7,7 @@ import {
revokePublicPageMutation, revokePublicPageMutation,
} from '@affine/graphql'; } from '@affine/graphql';
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import type { Workspace } from '@toeverything/infra/workspace';
import { useSetAtom } from 'jotai'; import { useSetAtom } from 'jotai';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
@@ -192,3 +194,44 @@ export function useIsSharedPage(
[isSharedPage, currentShareMode, enableShare, disableShare, changeShare] [isSharedPage, currentShareMode, enableShare, disableShare, changeShare]
); );
} }
export function usePublicPages(workspace: Workspace) {
const isLocalWorkspace = workspace.flavour === WorkspaceFlavour.LOCAL;
const { data } = useQuery(
isLocalWorkspace
? undefined
: {
query: getWorkspacePublicPagesQuery,
variables: {
workspaceId: workspace.id,
},
}
);
const maybeData = data as typeof data | undefined;
const publicPages: {
id: string;
mode: PageMode;
}[] = useMemo(
() =>
maybeData?.workspace.publicPages.map(i => ({
id: i.id,
mode: i.mode === PublicPageMode.Edgeless ? 'edgeless' : 'page',
})) ?? [],
[maybeData?.workspace.publicPages]
);
/**
* Return `undefined` if the page is not public.
*/
const getPublicMode = useCallback(
(pageId: string) => {
return publicPages.find(i => i.id === pageId)?.mode;
},
[publicPages]
);
return {
publicPages,
getPublicMode,
};
}

View File

@@ -63,7 +63,7 @@ export const AllPage = ({
const filteredPageMetas = useFilteredPageMetas( const filteredPageMetas = useFilteredPageMetas(
'all', 'all',
pageMetas, pageMetas,
currentWorkspace.blockSuiteWorkspace currentWorkspace
); );
const tagPageMetas = useMemo(() => { const tagPageMetas = useMemo(() => {
if (params.tagId) { if (params.tagId) {

View File

@@ -69,7 +69,7 @@ export const TrashPage = () => {
const filteredPageMetas = useFilteredPageMetas( const filteredPageMetas = useFilteredPageMetas(
'trash', 'trash',
pageMetas, pageMetas,
blockSuiteWorkspace currentWorkspace
); );
const { restoreFromTrash, permanentlyDeletePage } = const { restoreFromTrash, permanentlyDeletePage } =

View File

@@ -627,6 +627,7 @@
"com.affine.filter.is empty": "is empty", "com.affine.filter.is empty": "is empty",
"com.affine.filter.is not empty": "is not empty", "com.affine.filter.is not empty": "is not empty",
"com.affine.filter.is-favourited": "Favourited", "com.affine.filter.is-favourited": "Favourited",
"com.affine.filter.is-public": "Shared",
"com.affine.filter.save-view": "Save View", "com.affine.filter.save-view": "Save View",
"com.affine.filter.true": "true", "com.affine.filter.true": "true",
"com.affine.filterList.button.add": "Add Filter", "com.affine.filterList.button.add": "Add Filter",