From 50f19663d45e1d02f75e4579dfdad8ea0a2b01c6 Mon Sep 17 00:00:00 2001 From: himself65 Date: Mon, 2 Jan 2023 00:57:08 +0800 Subject: [PATCH 01/14] build: enhance debugging with blocksuite --- packages/app/next.config.js | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/app/next.config.js b/packages/app/next.config.js index 20f12e5770..6d7225864c 100644 --- a/packages/app/next.config.js +++ b/packages/app/next.config.js @@ -4,6 +4,11 @@ const { dependencies } = require('./package.json'); const path = require('node:path'); const printer = require('./scripts/printer').printer; +const enableDebugLocal = path.isAbsolute(process.env.LOCAL_BLOCK_SUITE ?? ''); +const EDITOR_VERSION = enableDebugLocal + ? 'local-version' + : dependencies['@blocksuite/editor']; + /** @type {import('next').NextConfig} */ const nextConfig = { productionBrowserSourceMaps: true, @@ -16,7 +21,7 @@ const nextConfig = { CI: process.env.CI || null, VERSION: getGitVersion(), COMMIT_HASH: getCommitHash(), - EDITOR_VERSION: dependencies['@blocksuite/editor'], + EDITOR_VERSION, }, webpack: config => { config.experiments = { ...config.experiments, topLevelAwait: true }; @@ -63,11 +68,25 @@ const baseDir = process.env.LOCAL_BLOCK_SUITE ?? '/'; const withDebugLocal = require('next-debug-local')( { '@blocksuite/editor': path.resolve(baseDir, 'packages', 'editor'), + '@blocksuite/blocks/models': path.resolve( + baseDir, + 'packages', + 'blocks', + 'src', + 'models' + ), + '@blocksuite/blocks/std': path.resolve( + baseDir, + 'packages', + 'blocks', + 'src', + 'std' + ), '@blocksuite/blocks': path.resolve(baseDir, 'packages', 'blocks'), '@blocksuite/store': path.resolve(baseDir, 'packages', 'store'), }, { - enable: path.isAbsolute(process.env.LOCAL_BLOCK_SUITE ?? ''), + enable: enableDebugLocal, } ); From ae94c901b3b9547706f1db98bc89e9e69668d825 Mon Sep 17 00:00:00 2001 From: DarkSky Date: Wed, 4 Jan 2023 16:49:40 +0800 Subject: [PATCH 02/14] feat: auth implement --- packages/data-center/src/apis/token.ts | 27 ++++++++++++++++--- packages/data-center/src/datacenter.ts | 15 +++++++++++ packages/data-center/src/index.ts | 4 +++ .../data-center/src/provider/affine/index.ts | 26 ++++++++++++++++-- packages/data-center/src/provider/base.ts | 4 +++ .../data-center/src/provider/local/index.ts | 16 ++++++++--- 6 files changed, 82 insertions(+), 10 deletions(-) diff --git a/packages/data-center/src/apis/token.ts b/packages/data-center/src/apis/token.ts index b0acf68ee3..c509da0f33 100644 --- a/packages/data-center/src/apis/token.ts +++ b/packages/data-center/src/apis/token.ts @@ -60,7 +60,9 @@ class Token { } async initToken(token: string) { - this._setToken(await login({ token, type: 'Google' })); + const tokens = await login({ token, type: 'Google' }); + this._setToken(tokens); + return this._user; } async refreshToken(token?: string) { @@ -153,10 +155,27 @@ export const getAuthorizer = () => { const googleAuthProvider = new GoogleAuthProvider(); + const getToken = async () => { + const currentUser = firebaseAuth.currentUser; + if (currentUser) { + await currentUser.getIdTokenResult(true); + if (!currentUser.isAnonymous) { + return currentUser.getIdToken(); + } + } + return; + }; + const signInWithGoogle = async () => { - const user = await signInWithPopup(firebaseAuth, googleAuthProvider); - const idToken = await user.user.getIdToken(); - await token.initToken(idToken); + const idToken = await getToken(); + if (idToken) { + await token.initToken(idToken); + } else { + const user = await signInWithPopup(firebaseAuth, googleAuthProvider); + const idToken = await user.user.getIdToken(); + await token.initToken(idToken); + } + return firebaseAuth.currentUser; }; const onAuthStateChanged = (callback: (user: User | null) => void) => { diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 62edea334d..a094b9def6 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -97,6 +97,21 @@ export class DataCenter { return provider; } + async auth(providerId: string, globalConfig?: Record) { + const Provider = this._providers.get(providerId); + if (Provider) { + // initial configurator + const config = getKVConfigure(`provider:${providerId}`); + // set workspace configs + const values = Object.entries(globalConfig || {}); + if (values.length) await config.setMany(values); + + const logger = this._logger.extend(`auth:${providerId}`); + logger.enabled = this._logger.enabled; + await Provider.auth(config, logger); + } + } + /** * load workspace data to memory * @param workspaceId workspace id diff --git a/packages/data-center/src/index.ts b/packages/data-center/src/index.ts index 68aa74b916..72aa6015e1 100644 --- a/packages/data-center/src/index.ts +++ b/packages/data-center/src/index.ts @@ -7,6 +7,10 @@ const _initializeDataCenter = () => { return (debug = true) => { if (!_dataCenterInstance) { _dataCenterInstance = DataCenter.init(debug); + _dataCenterInstance.then(dc => { + (window as any).dc = dc; + return dc; + }); } return _dataCenterInstance; diff --git a/packages/data-center/src/provider/affine/index.ts b/packages/data-center/src/provider/affine/index.ts index fef7a4d0a9..6f1824a152 100644 --- a/packages/data-center/src/provider/affine/index.ts +++ b/packages/data-center/src/provider/affine/index.ts @@ -1,8 +1,8 @@ import assert from 'assert'; import { applyUpdate } from 'yjs'; -import type { InitialParams } from '../index.js'; -import { token, Callback } from '../../apis/index.js'; +import type { ConfigStore, InitialParams, Logger } from '../index.js'; +import { token, Callback, getApis } from '../../apis/index.js'; import { LocalProvider } from '../local/index.js'; import { WebsocketProvider } from './sync.js'; @@ -91,4 +91,26 @@ export class AffineProvider extends LocalProvider { // just a workaround for yjs doc.getMap('space:meta'); } + + static async auth(config: Readonly>, logger: Logger) { + const refreshToken = await config.get('token'); + if (refreshToken) { + await token.refreshToken(refreshToken); + if (token.isLogin && !token.isExpired) { + logger('check login success'); + // login success + return; + } + } + + logger('start login'); + // login with google + const apis = getApis(); + assert(apis.signInWithGoogle); + const user = await apis.signInWithGoogle(); + assert(user); + logger(`login success: ${user.displayName}`); + + // TODO: refresh local workspace data + } } diff --git a/packages/data-center/src/provider/base.ts b/packages/data-center/src/provider/base.ts index 95bd309a1c..8ed184b6eb 100644 --- a/packages/data-center/src/provider/base.ts +++ b/packages/data-center/src/provider/base.ts @@ -55,6 +55,10 @@ export class BaseProvider { return this._workspace; } + static async auth(_config: Readonly, _logger: Logger) { + throw Error('Not implemented: auth'); + } + // get workspace list,return a map of workspace id and boolean // if value is true, it exists locally, otherwise it does not exist locally static async list( diff --git a/packages/data-center/src/provider/local/index.ts b/packages/data-center/src/provider/local/index.ts index d2ced1b9ee..89ec6ce192 100644 --- a/packages/data-center/src/provider/local/index.ts +++ b/packages/data-center/src/provider/local/index.ts @@ -1,7 +1,7 @@ import type { BlobStorage } from '@blocksuite/store'; import assert from 'assert'; -import type { ConfigStore, InitialParams } from '../index.js'; +import type { ConfigStore, InitialParams, Logger } from '../index.js'; import { BaseProvider } from '../base.js'; import { IndexedDBProvider } from './indexeddb.js'; @@ -32,14 +32,14 @@ export class LocalProvider extends BaseProvider { await this._idb.whenSynced; this._logger('Local data loaded'); - await this._globalConfig.set(this._workspace.room, true); + await this._globalConfig.set(`list:${this._workspace.room}`, true); } async clear() { await super.clear(); await this._blobs.clear(); await this._idb?.clearData(); - await this._globalConfig.delete(this._workspace.room!); + await this._globalConfig.delete(`list:${this._workspace.room}`); } async destroy(): Promise { @@ -55,10 +55,18 @@ export class LocalProvider extends BaseProvider { return this._blobs.set(blob); } + static async auth(_config: Readonly, logger: Logger) { + logger("Local provider doesn't require authentication"); + } + static async list( config: Readonly> ): Promise | undefined> { const entries = await config.entries(); - return new Map(entries); + return new Map( + entries + .filter(([key]) => key.startsWith('list:')) + .map(([key, value]) => [key.slice(5), value]) + ); } } From 1bc2dcd6610eec24d60517c2ccadb0d2b86223ae Mon Sep 17 00:00:00 2001 From: JimmFly Date: Wed, 4 Jan 2023 16:57:21 +0800 Subject: [PATCH 03/14] feat: init i18n --- packages/app/src/libs/i18n/resources/en.json | 87 ++++++++++++++------ packages/app/src/pages/_app.tsx | 1 + 2 files changed, 63 insertions(+), 25 deletions(-) diff --git a/packages/app/src/libs/i18n/resources/en.json b/packages/app/src/libs/i18n/resources/en.json index c2716448f7..45822ea009 100644 --- a/packages/app/src/libs/i18n/resources/en.json +++ b/packages/app/src/libs/i18n/resources/en.json @@ -1,28 +1,65 @@ { - "Sync to Disk": "Sync to Disk", - "Share": "Share", - "WarningTips": { - "IsNotfsApiSupported": "Welcome to the AFFiNE demo. To begin saving changes you can SYNC DATA TO DISK with the latest version of Chromium based browser like Chrome/Edge", - "IsNotLocalWorkspace": "Welcome to the AFFiNE demo. To begin saving changes you can SYNC TO DISK.", - "DoNotStore": "AFFiNE is under active development and the current version is UNSTABLE. Please DO NOT store information or data" - }, - "Layout": "Layout", - "Comment": "Comment", - "Settings": "Settings", - "ComingSoon": "Layout Settings Coming Soon...", - "Duplicate Page": "Duplicate Page", - "Copy Page Link": "Copy Page Link", - "Language": "Language", - "Clear Workspace": "Clear Workspace", - "Export As Markdown": "Export As Markdown", - "Export As HTML": "Export As HTML", - "Export As PDF (Unsupported)": "Export As PDF (Unsupported)", - "Import Workspace": "Import Workspace", - "Export Workspace": "Export Workspace", - "Last edited by": "Last edited by {{name}}", - "Logout": "Logout", + "Quick search": "Quick search", + "All pages": "All pages", + "Favourites": "Favourites", + "No item": "No item", + "Import": "Import", + "Trash": "Trash", + "New Page": "New Page", + "New Keyword Page": "New '{{query}}' page", + "Find 0 result": "Find 0 result", + "Find results": "Find {{number}} results", + "Collapse sidebar": "Collapse sidebar", + "Expand sidebar": "Expand sidebar", + "Removed to Favourites": "Removed to Favourites", + "Remove to favourites": "Remove to favourites", + "Added to Favourites": "Added to Favourites", + "Add to favourites": "Add to favourites", + "Paper": "Paper", + "Edgeless": "Edgeless", + "Switch to": "Switch to", + "Convert to ": "Convert to ", + "Page": "Page", + "Export": "Export", + "Export to HTML": "Export to HTML", + "Export to Markdown": "Export to Markdown", "Delete": "Delete", - "Turn into": "Turn into", - "Add A Below Block": "Add A Below Block", - "Divide Here As A New Group": "Divide Here As A New Group" + "Title": "Title", + "Untitled": "Untitled", + "Created": "Created", + "Updated": "Updated", + "Open in new tab": "Open in new tab", + "Favourite": "Favourite", + "Favourited": "Favourited", + "Delete page?": "Delete page?", + "Delete permanently?": "Delete permanently?", + "will be moved to Trash": "{{title}} will be moved to Trash", + "Once deleted, you can't undo this action.": "Once deleted,you can't undo this action.", + "Moved to Trash": "Moved to Trash", + "Permanently deleted": "Permanently deleted", + "restored": "{{title}} restored", + "Cancel": "Cancel", + "Keyboard Shortcuts": "Keyboard Shortcuts", + "Contact Us": "Contact Us", + "Official Website": "Official Website", + "Get in touch!": "Get in touch!", + "AFFiNE Community": "AFFiNE Community", + "How is AFFiNE Alpha different?": "How is AFFiNE Alpha different?", + "Shortcuts": "Shortcuts", + "Undo": "Undo", + "Redo": "Redo", + "Bold": "Bold", + "Italic": "Italic", + "Underline": "Underline", + "Strikethrough": "Strikethrough", + "Inline code": "Inline code", + "Code block": "Code block", + "Link": "Link", + "Body text": "Body text", + "Heading": "Heading {{number}}", + "Increase indent": "Increase indent", + "Reduce indent": "Reduce indent", + "Markdown Syntax": "Markdown Syntax", + "Divider": "Divider", + "404 - Page Not Found": "404 - Page Not Found" } diff --git a/packages/app/src/pages/_app.tsx b/packages/app/src/pages/_app.tsx index bb56e9acef..c7cbd78d4b 100644 --- a/packages/app/src/pages/_app.tsx +++ b/packages/app/src/pages/_app.tsx @@ -18,6 +18,7 @@ import { useEffect } from 'react'; import { useAppState } from '@/providers/app-state-provider'; import { PageLoading } from '@/components/loading'; import Head from 'next/head'; +import '@/libs/i18n'; const ThemeProvider = dynamic(() => import('@/providers/themeProvider'), { ssr: false, From 0b61f4a2a04a83d3dd3616aaf87d649330ae51ba Mon Sep 17 00:00:00 2001 From: JimmFly Date: Wed, 4 Jan 2023 17:10:47 +0800 Subject: [PATCH 04/14] feat: add translation --- packages/app/src/components/404/index.tsx | 5 +-- .../src/components/contact-modal/index.tsx | 35 +++++++++--------- .../components/editor-mode-switch/index.tsx | 8 ++--- .../header-right-items/editor-option-menu.tsx | 30 +++++++++------- .../components/header/quick-search-button.tsx | 6 ++-- .../app/src/components/help-island/index.tsx | 7 ++-- packages/app/src/components/import/index.tsx | 4 ++- .../components/page-list/operation-cell.tsx | 36 ++++++++++--------- .../src/components/quick-search/footer.tsx | 7 ++-- .../src/components/quick-search/results.tsx | 10 ++++-- .../src/components/shortcuts-modal/index.tsx | 16 +++++---- .../components/workspace-slider-bar/index.tsx | 22 ++++++------ .../src/pages/workspace/[workspaceId]/all.tsx | 6 ++-- .../workspace/[workspaceId]/favorite.tsx | 7 ++-- .../pages/workspace/[workspaceId]/trash.tsx | 5 +-- packages/app/src/ui/confirm/Confirm.tsx | 4 ++- 16 files changed, 118 insertions(+), 90 deletions(-) diff --git a/packages/app/src/components/404/index.tsx b/packages/app/src/components/404/index.tsx index e2f828ad9f..7df644bbfe 100644 --- a/packages/app/src/components/404/index.tsx +++ b/packages/app/src/components/404/index.tsx @@ -1,9 +1,10 @@ import { NotFoundTitle, PageContainer } from './styles'; - +import { useTranslation } from 'react-i18next'; export const NotfoundPage = () => { + const { t } = useTranslation(); return ( - 404 - Page Not Found + {t('404 - Page Not Found')} ); }; diff --git a/packages/app/src/components/contact-modal/index.tsx b/packages/app/src/components/contact-modal/index.tsx index a182f3e047..50c1e1b530 100644 --- a/packages/app/src/components/contact-modal/index.tsx +++ b/packages/app/src/components/contact-modal/index.tsx @@ -23,7 +23,7 @@ import { StyledModalFooter, } from './style'; import bg from '@/components/contact-modal/bg.png'; - +import { useTranslation } from 'react-i18next'; const linkList = [ { icon: , @@ -51,20 +51,6 @@ const linkList = [ link: 'https://discord.gg/Arn7TqJBvG', }, ]; -const rightLinkList = [ - { - icon: , - title: 'Official Website ', - subTitle: 'AFFiNE.pro', - link: 'https://affine.pro', - }, - { - icon: , - title: 'AFFiNE Community', - subTitle: 'community.affine.pro', - link: 'https://community.affine.pro', - }, -]; type TransitionsModalProps = { open: boolean; @@ -72,6 +58,21 @@ type TransitionsModalProps = { }; export const ContactModal = ({ open, onClose }: TransitionsModalProps) => { + const { t } = useTranslation(); + const rightLinkList = [ + { + icon: , + title: t('Official Website'), + subTitle: 'AFFiNE.pro', + link: 'https://affine.pro', + }, + { + icon: , + title: t('AFFiNE Community'), + subTitle: 'community.affine.pro', + link: 'https://community.affine.pro', + }, + ]; return ( { })} - Get in touch! + {t('Get in touch!')} {linkList.map(({ icon, title, link }) => { return ( @@ -128,7 +129,7 @@ export const ContactModal = ({ open, onClose }: TransitionsModalProps) => { target="_blank" rel="noreferrer" > - How is AFFiNE Alpha different? + {t('How is AFFiNE Alpha different?')}

Copyright © 2022 Toeverything

diff --git a/packages/app/src/components/editor-mode-switch/index.tsx b/packages/app/src/components/editor-mode-switch/index.tsx index 8a219e4757..86a54d8606 100644 --- a/packages/app/src/components/editor-mode-switch/index.tsx +++ b/packages/app/src/components/editor-mode-switch/index.tsx @@ -15,7 +15,7 @@ import { useTheme } from '@/providers/themeProvider'; import { EdgelessIcon, PaperIcon } from './icons'; import useCurrentPageMeta from '@/hooks/use-current-page-meta'; import { usePageHelper } from '@/hooks/use-page-helper'; - +import { useTranslation } from 'react-i18next'; const PaperItem = ({ active }: { active?: boolean }) => { const { theme: { @@ -96,7 +96,7 @@ export const EditorModeSwitch = ({ setRadioItemStatus(modifyRadioItemStatus()); // eslint-disable-next-line react-hooks/exhaustive-deps }, [isHover, mode]); - + const { t } = useTranslation(); return ( } active={mode === 'page'} status={radioItemStatus.left} @@ -126,7 +126,7 @@ export const EditorModeSwitch = ({