Merge branch 'feat/support-get-encoded-collab-event' of https://github.com/AppFlowy-IO/AppFlowy into feat/support-get-encoded-collab-event

This commit is contained in:
Lucas.Xu 2024-07-03 10:21:20 +08:00
commit 38f49d617f
11 changed files with 102 additions and 24 deletions

View File

@ -62,26 +62,28 @@ const createServer = async (req) => {
const reqUrl = new URL(req.url);
logger.info(`Request URL: ${reqUrl.pathname}`);
const [
namespace,
publishName,
] = reqUrl.pathname.slice(1).split('/');
logger.info(`Namespace: ${namespace}, Puganblish Name: ${publishName}`);
if (namespace === '' || !publishName) {
timer();
return new Response(null, {
status: 302,
headers: {
'Location': 'https://appflowy.io',
},
});
}
logger.info(`Namespace: ${namespace}, Publish Name: ${publishName}`);
if (req.method === 'GET') {
if (namespace === '' || !publishName) {
timer();
return new Response(null, {
status: 302,
headers: {
'Location': 'https://appflowy.io',
},
});
}
let metaData;
try {
metaData = await fetchMetaData(`${BASE_URL}/api/workspace/published/${namespace}/${publishName}`);
} catch (error) {

View File

@ -42,3 +42,17 @@ export async function openCollabDB(docName: string): Promise<YDoc> {
return doc as YDoc;
}
export async function closeCollabDB(docName: string) {
const name = `${databasePrefix}_${docName}`;
if (openedSet.has(name)) {
openedSet.delete(name);
}
const doc = new Y.Doc();
const provider = new IndexeddbPersistence(name, doc);
await provider.destroy();
}

View File

@ -7,7 +7,7 @@ import {
YSharedRoot,
} from '@/application/collab.type';
import { applyYDoc } from '@/application/ydoc/apply';
import { db, openCollabDB } from '@/application/db';
import { closeCollabDB, db, openCollabDB } from '@/application/db';
import { Fetcher, StrategyType } from '@/application/services/js-services/cache/types';
export function collabTypeToDBType(type: CollabType) {
@ -226,3 +226,13 @@ export async function getBatchCollabs(names: string[]) {
return collabs;
}
export async function deleteViewMeta(name: string) {
await db.view_metas.delete(name);
}
export async function deleteView(name: string) {
console.log('deleteView', name);
await deleteViewMeta(name);
await closeCollabDB(name);
}

View File

@ -1,5 +1,11 @@
import { YDoc } from '@/application/collab.type';
import { getBatchCollabs, getPublishView, getPublishViewMeta } from '@/application/services/js-services/cache';
import {
deleteView,
getBatchCollabs,
getPublishView,
getPublishViewMeta,
hasViewMetaCache,
} from '@/application/services/js-services/cache';
import { StrategyType } from '@/application/services/js-services/cache/types';
import { fetchPublishView, fetchPublishViewMeta, fetchViewInfo } from '@/application/services/js-services/fetch';
import { AFService, AFServiceConfig } from '@/application/services/services.type';
@ -56,8 +62,20 @@ export class AFClientService implements AFService {
const isLoaded = this.publishViewLoaded.has(name);
const doc = await getPublishView(
() => {
return fetchPublishView(namespace, publishName);
async () => {
try {
return await fetchPublishView(namespace, publishName);
} catch (e) {
void (async () => {
if (await hasViewMetaCache(name)) {
this.publishViewLoaded.delete(name);
void deleteView(name);
window.location.reload();
}
})();
return Promise.reject(e);
}
},
{
namespace,

View File

@ -8,6 +8,7 @@ const AppMain = withAppWrapper(() => {
return (
<Routes>
<Route path={'/:namespace/:publishName'} element={<PublishPage />} />
<Route path='/404' element={<NotFound />} />
<Route path='*' element={<NotFound />} />
</Routes>
);

View File

@ -41,7 +41,7 @@ export const LinkPreview = memo(
{data ? (
<div
className={
'container-bg flex w-full cursor-pointer select-none items-center gap-4 rounded border border-line-divider bg-fill-list-active p-3'
'container-bg flex w-full cursor-pointer select-none items-center gap-4 overflow-hidden rounded border border-line-divider bg-fill-list-active p-3'
}
>
<img
@ -49,10 +49,22 @@ export const LinkPreview = memo(
alt={data.title}
className={'container h-full w-[25%] rounded bg-cover bg-center'}
/>
<div className={'flex flex-col justify-center gap-2'}>
<div className={'text-base font-bold text-text-title'}>{data.title}</div>
<div className={'text-sm text-text-title'}>{data.description}</div>
<div className={'text-xs text-text-caption'}>{url}</div>
<div className={'flex flex-col justify-center gap-2 overflow-hidden'}>
<div
className={
'max-h-[48px] overflow-hidden whitespace-pre-wrap break-words text-base font-bold text-text-title'
}
>
{data.title}
</div>
<div
className={
'max-h-[64px] overflow-hidden truncate whitespace-pre-wrap break-words text-sm text-text-title'
}
>
{data.description}
</div>
<div className={'truncate whitespace-nowrap text-xs text-text-caption'}>{url}</div>
</div>
</div>
) : (

View File

@ -1,4 +1,9 @@
.table-block {
::-webkit-scrollbar {
width: 8px !important;
height: 8px !important;
}
[id^=table-] {
width: fit-content;
@apply border-t border-l border-line-border;

View File

@ -19,6 +19,7 @@ const drawerWidth = 268;
export function PublishView({ namespace, publishName }: PublishViewProps) {
const [doc, setDoc] = useState<YDoc | undefined>();
const [notFound, setNotFound] = useState<boolean>(false);
const service = useContext(AFConfigContext)?.service;
const openPublishView = useCallback(async () => {
let doc;
@ -58,6 +59,7 @@ export function PublishView({ namespace, publishName }: PublishViewProps) {
window.removeEventListener('keydown', onKeyDown);
};
}, [onKeyDown]);
if (notFound && !doc) {
return <NotFound />;
}

View File

@ -57,7 +57,9 @@ function BreadcrumbItem({ crumb, disableClick = false }: { crumb: Crumb; disable
<SpaceIcon value={extraObj.space_icon || ''} />
</span>
) : (
<span className={'icon'}>{icon || <ViewIcon layout={layout} size={'small'} />}</span>
<span className={'icon flex h-5 w-5 items-center justify-center'}>
{icon || <ViewIcon layout={layout} size={'small'} />}
</span>
)}
<span

View File

@ -8,6 +8,8 @@ import { ReactComponent as MoonIcon } from '@/assets/moon.svg';
import { ReactComponent as SunIcon } from '@/assets/sun.svg';
import { ReactComponent as ReportIcon } from '@/assets/report.svg';
import { useTranslation } from 'react-i18next';
import { ReactComponent as Logo } from '@/assets/logo.svg';
import { ReactComponent as AppflowyLogo } from '@/assets/appflowy.svg';
function MoreActions() {
const { isDark, setDark } = useContext(ThemeModeContext) || {};
@ -45,7 +47,7 @@ function MoreActions() {
Icon: ReportIcon,
label: t('publish.reportPage'),
onClick: () => {
void openUrl('', '_blank');
void openUrl('https://report.appflowy.io/', '_blank');
},
},
];
@ -85,6 +87,16 @@ function MoreActions() {
<span>{action.label}</span>
</button>
))}
<div
onClick={() => {
window.open('https://appflowy.io', '_blank');
}}
className={'flex w-full cursor-pointer items-center justify-center py-2 text-sm text-text-title opacity-50'}
>
Powered by
<Logo className={'ml-3 h-4 w-4'} />
<AppflowyLogo className={'w-20'} />
</div>
</div>
</Popover>
</>

View File

@ -21,7 +21,7 @@ export function useViewMeta() {
lineHeightLayout: extra?.lineHeightLayout,
};
}, [extra]);
const layout = viewMeta?.layout;
const style = useMemo(() => {
const fontSizeMap = {