mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-25 02:13:00 +08:00
feat: improve test & bundler (#14434)
#### PR Dependency Tree * **PR #14434** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Introduced rspack bundler as an alternative to webpack for optimized builds. * **Tests & Quality** * Added comprehensive editor semantic tests covering markdown, hotkeys, and slash-menu operations. * Expanded CI cross-browser testing to Chromium, Firefox, and WebKit; improved shape-rendering tests to account for zoom. * **Bug Fixes** * Corrected CSS overlay styling for development servers. * Fixed TypeScript typings for build tooling. * **Other** * Document duplication now produces consistent "(n)" suffixes. * French i18n completeness increased to 100%. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -6,7 +6,8 @@ textarea
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
#webpack-dev-server-client-overlay {
|
||||
#webpack-dev-server-client-overlay,
|
||||
#rspack-dev-server-client-overlay {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
|
||||
8
packages/frontend/core/src/desktop/route-paths.ts
Normal file
8
packages/frontend/core/src/desktop/route-paths.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export const WORKSPACE_ROUTE_PATH = '/workspace/:workspaceId/*';
|
||||
export const SHARE_ROUTE_PATH = '/share/:workspaceId/:pageId';
|
||||
export const NOT_FOUND_ROUTE_PATH = '/404';
|
||||
export const CATCH_ALL_ROUTE_PATH = '*';
|
||||
|
||||
export function getWorkspaceDocPath(workspaceId: string, docId: string) {
|
||||
return `/workspace/${workspaceId}/${docId}`;
|
||||
}
|
||||
@@ -10,6 +10,13 @@ import {
|
||||
import { AffineErrorComponent } from '../components/affine/affine-error-boundary/affine-error-fallback';
|
||||
import { NavigateContext } from '../components/hooks/use-navigate-helper';
|
||||
import { RootWrapper } from './pages/root';
|
||||
import {
|
||||
CATCH_ALL_ROUTE_PATH,
|
||||
getWorkspaceDocPath,
|
||||
NOT_FOUND_ROUTE_PATH,
|
||||
SHARE_ROUTE_PATH,
|
||||
WORKSPACE_ROUTE_PATH,
|
||||
} from './route-paths';
|
||||
|
||||
export function RootRouter() {
|
||||
const navigate = useNavigate();
|
||||
@@ -38,17 +45,19 @@ export const topLevelRoutes = [
|
||||
lazy: () => import('./pages/index'),
|
||||
},
|
||||
{
|
||||
path: '/workspace/:workspaceId/*',
|
||||
path: WORKSPACE_ROUTE_PATH,
|
||||
lazy: () => import('./pages/workspace/index'),
|
||||
},
|
||||
{
|
||||
path: '/share/:workspaceId/:pageId',
|
||||
path: SHARE_ROUTE_PATH,
|
||||
loader: ({ params }) => {
|
||||
return redirect(`/workspace/${params.workspaceId}/${params.pageId}`);
|
||||
return redirect(
|
||||
getWorkspaceDocPath(params.workspaceId ?? '', params.pageId ?? '')
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/404',
|
||||
path: NOT_FOUND_ROUTE_PATH,
|
||||
lazy: () => import('./pages/404'),
|
||||
},
|
||||
{
|
||||
@@ -175,7 +184,7 @@ export const topLevelRoutes = [
|
||||
lazy: () => import('./pages/open-app'),
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
path: CATCH_ALL_ROUTE_PATH,
|
||||
lazy: () => import('./pages/404'),
|
||||
},
|
||||
],
|
||||
|
||||
@@ -18,6 +18,7 @@ import type { DocPropertiesStore } from '../stores/doc-properties';
|
||||
import type { DocsStore } from '../stores/docs';
|
||||
import type { DocCreateOptions } from '../types';
|
||||
import { DocService } from './doc';
|
||||
import { getDuplicatedDocTitle } from './duplicate-title';
|
||||
|
||||
const logger = new DebugLogger('DocsService');
|
||||
|
||||
@@ -286,13 +287,7 @@ export class DocsService extends Service {
|
||||
});
|
||||
|
||||
// duplicate doc title
|
||||
const originalTitle = sourceDoc.title$.value;
|
||||
const lastDigitRegex = /\((\d+)\)$/;
|
||||
const match = originalTitle.match(lastDigitRegex);
|
||||
const newNumber = match ? parseInt(match[1], 10) + 1 : 1;
|
||||
const newPageTitle =
|
||||
originalTitle.replace(lastDigitRegex, '') + `(${newNumber})`;
|
||||
targetDoc.changeDocTitle(newPageTitle);
|
||||
targetDoc.changeDocTitle(getDuplicatedDocTitle(sourceDoc.title$.value));
|
||||
|
||||
// duplicate doc properties
|
||||
const properties = sourceDoc.getProperties();
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
const DUPLICATED_DOC_TITLE_SUFFIX = /\((\d+)\)$/;
|
||||
|
||||
export function getDuplicatedDocTitle(originalTitle: string) {
|
||||
const match = originalTitle.match(DUPLICATED_DOC_TITLE_SUFFIX);
|
||||
const nextSequence = match ? parseInt(match[1], 10) + 1 : 1;
|
||||
return (
|
||||
originalTitle.replace(DUPLICATED_DOC_TITLE_SUFFIX, '') + `(${nextSequence})`
|
||||
);
|
||||
}
|
||||
@@ -46,6 +46,10 @@ import type {
|
||||
} from '../../workspace';
|
||||
import { WorkspaceImpl } from '../../workspace/impls/workspace';
|
||||
import { getWorkspaceProfileWorker } from './out-worker';
|
||||
import {
|
||||
dedupeWorkspaceIds,
|
||||
normalizeWorkspaceIds,
|
||||
} from './workspace-id-utils';
|
||||
|
||||
export const LOCAL_WORKSPACE_LOCAL_STORAGE_KEY = 'affine-local-workspace';
|
||||
export const LOCAL_WORKSPACE_GLOBAL_STATE_KEY =
|
||||
@@ -61,13 +65,6 @@ type GlobalStateStorageLike = {
|
||||
set<T>(key: string, value: T): void;
|
||||
};
|
||||
|
||||
function normalizeWorkspaceIds(ids: unknown): string[] {
|
||||
if (!Array.isArray(ids)) {
|
||||
return [];
|
||||
}
|
||||
return ids.filter((id): id is string => typeof id === 'string');
|
||||
}
|
||||
|
||||
function getElectronGlobalStateStorage(): GlobalStateStorageLike | null {
|
||||
if (!BUILD_CONFIG.isElectron) {
|
||||
return null;
|
||||
@@ -113,7 +110,7 @@ export function setLocalWorkspaceIds(
|
||||
? idsOrUpdater(getLocalWorkspaceIds())
|
||||
: idsOrUpdater
|
||||
);
|
||||
const deduplicated = [...new Set(next)];
|
||||
const deduplicated = dedupeWorkspaceIds(next);
|
||||
|
||||
const globalState = getElectronGlobalStateStorage();
|
||||
if (globalState) {
|
||||
@@ -168,14 +165,12 @@ class LocalWorkspaceFlavourProvider implements WorkspaceFlavourProvider {
|
||||
}
|
||||
|
||||
setLocalWorkspaceIds(currentIds => {
|
||||
return [
|
||||
...new Set([
|
||||
...currentIds,
|
||||
...persistedIds,
|
||||
...legacyIds,
|
||||
...scannedIds,
|
||||
]),
|
||||
];
|
||||
return dedupeWorkspaceIds([
|
||||
...currentIds,
|
||||
...persistedIds,
|
||||
...legacyIds,
|
||||
...scannedIds,
|
||||
]);
|
||||
});
|
||||
})()
|
||||
.catch(e => {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
export function normalizeWorkspaceIds(ids: unknown): string[] {
|
||||
if (!Array.isArray(ids)) return [];
|
||||
return ids.filter((id): id is string => typeof id === 'string');
|
||||
}
|
||||
|
||||
export function dedupeWorkspaceIds(ids: string[]): string[] {
|
||||
return [...new Set(ids)];
|
||||
}
|
||||
3
packages/frontend/core/src/types/types.d.ts
vendored
3
packages/frontend/core/src/types/types.d.ts
vendored
@@ -1,4 +1,5 @@
|
||||
/// <reference types="@webpack/env"" />
|
||||
/// <reference types="@webpack/env" />
|
||||
/// <reference types="@rspack/core/module" />
|
||||
|
||||
declare module '*.md' {
|
||||
const text: string;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"es-CL": 98,
|
||||
"es": 96,
|
||||
"fa": 96,
|
||||
"fr": 98,
|
||||
"fr": 100,
|
||||
"hi": 1,
|
||||
"it-IT": 98,
|
||||
"it": 1,
|
||||
|
||||
@@ -2311,4 +2311,3 @@
|
||||
"error.RESPONSE_TOO_LARGE_ERROR": "Réponse trop volumineuse ({{receivedBytes}} octets), la limite est de {{limitBytes}} octets",
|
||||
"error.SSRF_BLOCKED_ERROR": "URL invalide"
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user