mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
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:
commit
38f49d617f
@ -68,20 +68,22 @@ const createServer = async (req) => {
|
|||||||
publishName,
|
publishName,
|
||||||
] = reqUrl.pathname.slice(1).split('/');
|
] = reqUrl.pathname.slice(1).split('/');
|
||||||
|
|
||||||
logger.info(`Namespace: ${namespace}, Puganblish Name: ${publishName}`);
|
logger.info(`Namespace: ${namespace}, Publish Name: ${publishName}`);
|
||||||
|
|
||||||
if (namespace === '' || !publishName) {
|
|
||||||
timer();
|
|
||||||
return new Response(null, {
|
|
||||||
status: 302,
|
|
||||||
headers: {
|
|
||||||
'Location': 'https://appflowy.io',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.method === 'GET') {
|
if (req.method === 'GET') {
|
||||||
|
|
||||||
|
if (namespace === '' || !publishName) {
|
||||||
|
timer();
|
||||||
|
return new Response(null, {
|
||||||
|
status: 302,
|
||||||
|
headers: {
|
||||||
|
'Location': 'https://appflowy.io',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let metaData;
|
let metaData;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
metaData = await fetchMetaData(`${BASE_URL}/api/workspace/published/${namespace}/${publishName}`);
|
metaData = await fetchMetaData(`${BASE_URL}/api/workspace/published/${namespace}/${publishName}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -42,3 +42,17 @@ export async function openCollabDB(docName: string): Promise<YDoc> {
|
|||||||
|
|
||||||
return doc as 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();
|
||||||
|
}
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
YSharedRoot,
|
YSharedRoot,
|
||||||
} from '@/application/collab.type';
|
} from '@/application/collab.type';
|
||||||
import { applyYDoc } from '@/application/ydoc/apply';
|
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';
|
import { Fetcher, StrategyType } from '@/application/services/js-services/cache/types';
|
||||||
|
|
||||||
export function collabTypeToDBType(type: CollabType) {
|
export function collabTypeToDBType(type: CollabType) {
|
||||||
@ -226,3 +226,13 @@ export async function getBatchCollabs(names: string[]) {
|
|||||||
|
|
||||||
return collabs;
|
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);
|
||||||
|
}
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
import { YDoc } from '@/application/collab.type';
|
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 { StrategyType } from '@/application/services/js-services/cache/types';
|
||||||
import { fetchPublishView, fetchPublishViewMeta, fetchViewInfo } from '@/application/services/js-services/fetch';
|
import { fetchPublishView, fetchPublishViewMeta, fetchViewInfo } from '@/application/services/js-services/fetch';
|
||||||
import { AFService, AFServiceConfig } from '@/application/services/services.type';
|
import { AFService, AFServiceConfig } from '@/application/services/services.type';
|
||||||
@ -56,8 +62,20 @@ export class AFClientService implements AFService {
|
|||||||
|
|
||||||
const isLoaded = this.publishViewLoaded.has(name);
|
const isLoaded = this.publishViewLoaded.has(name);
|
||||||
const doc = await getPublishView(
|
const doc = await getPublishView(
|
||||||
() => {
|
async () => {
|
||||||
return fetchPublishView(namespace, publishName);
|
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,
|
namespace,
|
||||||
|
@ -8,6 +8,7 @@ const AppMain = withAppWrapper(() => {
|
|||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path={'/:namespace/:publishName'} element={<PublishPage />} />
|
<Route path={'/:namespace/:publishName'} element={<PublishPage />} />
|
||||||
|
<Route path='/404' element={<NotFound />} />
|
||||||
<Route path='*' element={<NotFound />} />
|
<Route path='*' element={<NotFound />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
);
|
);
|
||||||
|
@ -41,7 +41,7 @@ export const LinkPreview = memo(
|
|||||||
{data ? (
|
{data ? (
|
||||||
<div
|
<div
|
||||||
className={
|
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
|
<img
|
||||||
@ -49,10 +49,22 @@ export const LinkPreview = memo(
|
|||||||
alt={data.title}
|
alt={data.title}
|
||||||
className={'container h-full w-[25%] rounded bg-cover bg-center'}
|
className={'container h-full w-[25%] rounded bg-cover bg-center'}
|
||||||
/>
|
/>
|
||||||
<div className={'flex flex-col justify-center gap-2'}>
|
<div className={'flex flex-col justify-center gap-2 overflow-hidden'}>
|
||||||
<div className={'text-base font-bold text-text-title'}>{data.title}</div>
|
<div
|
||||||
<div className={'text-sm text-text-title'}>{data.description}</div>
|
className={
|
||||||
<div className={'text-xs text-text-caption'}>{url}</div>
|
'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>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
.table-block {
|
.table-block {
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 8px !important;
|
||||||
|
height: 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
[id^=table-] {
|
[id^=table-] {
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
@apply border-t border-l border-line-border;
|
@apply border-t border-l border-line-border;
|
||||||
|
@ -19,6 +19,7 @@ const drawerWidth = 268;
|
|||||||
export function PublishView({ namespace, publishName }: PublishViewProps) {
|
export function PublishView({ namespace, publishName }: PublishViewProps) {
|
||||||
const [doc, setDoc] = useState<YDoc | undefined>();
|
const [doc, setDoc] = useState<YDoc | undefined>();
|
||||||
const [notFound, setNotFound] = useState<boolean>(false);
|
const [notFound, setNotFound] = useState<boolean>(false);
|
||||||
|
|
||||||
const service = useContext(AFConfigContext)?.service;
|
const service = useContext(AFConfigContext)?.service;
|
||||||
const openPublishView = useCallback(async () => {
|
const openPublishView = useCallback(async () => {
|
||||||
let doc;
|
let doc;
|
||||||
@ -58,6 +59,7 @@ export function PublishView({ namespace, publishName }: PublishViewProps) {
|
|||||||
window.removeEventListener('keydown', onKeyDown);
|
window.removeEventListener('keydown', onKeyDown);
|
||||||
};
|
};
|
||||||
}, [onKeyDown]);
|
}, [onKeyDown]);
|
||||||
|
|
||||||
if (notFound && !doc) {
|
if (notFound && !doc) {
|
||||||
return <NotFound />;
|
return <NotFound />;
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,9 @@ function BreadcrumbItem({ crumb, disableClick = false }: { crumb: Crumb; disable
|
|||||||
<SpaceIcon value={extraObj.space_icon || ''} />
|
<SpaceIcon value={extraObj.space_icon || ''} />
|
||||||
</span>
|
</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
|
<span
|
||||||
|
@ -8,6 +8,8 @@ import { ReactComponent as MoonIcon } from '@/assets/moon.svg';
|
|||||||
import { ReactComponent as SunIcon } from '@/assets/sun.svg';
|
import { ReactComponent as SunIcon } from '@/assets/sun.svg';
|
||||||
import { ReactComponent as ReportIcon } from '@/assets/report.svg';
|
import { ReactComponent as ReportIcon } from '@/assets/report.svg';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { ReactComponent as Logo } from '@/assets/logo.svg';
|
||||||
|
import { ReactComponent as AppflowyLogo } from '@/assets/appflowy.svg';
|
||||||
|
|
||||||
function MoreActions() {
|
function MoreActions() {
|
||||||
const { isDark, setDark } = useContext(ThemeModeContext) || {};
|
const { isDark, setDark } = useContext(ThemeModeContext) || {};
|
||||||
@ -45,7 +47,7 @@ function MoreActions() {
|
|||||||
Icon: ReportIcon,
|
Icon: ReportIcon,
|
||||||
label: t('publish.reportPage'),
|
label: t('publish.reportPage'),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
void openUrl('', '_blank');
|
void openUrl('https://report.appflowy.io/', '_blank');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -85,6 +87,16 @@ function MoreActions() {
|
|||||||
<span>{action.label}</span>
|
<span>{action.label}</span>
|
||||||
</button>
|
</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>
|
</div>
|
||||||
</Popover>
|
</Popover>
|
||||||
</>
|
</>
|
||||||
|
Loading…
Reference in New Issue
Block a user