Compare commits

..

135 Commits

Author SHA1 Message Date
Alex Yang
c45149b664 v0.8.0-canary.1 2023-07-29 08:23:38 -07:00
Alex Yang
ce0c1c39e2 feat: improve copilot plugin (#3459) 2023-07-29 07:37:01 +00:00
Alex Yang
52809a2783 refactor: image preview plugin (#3457) 2023-07-29 00:18:28 -07:00
Alex Yang
be3909370e refactor(plugin-infra): split functions (#3451) 2023-07-28 22:28:10 -07:00
Alex Yang
f79733e5df feat(plugin-infra): add package.json schema (#3456) 2023-07-29 05:07:25 +00:00
Alex Yang
2d95de06d6 docs: update rustc version 2023-07-28 21:36:43 -07:00
Alex Yang
97502231a3 v0.8.0-canary.0 2023-07-28 20:18:00 -07:00
Alex Yang
d20a6d2677 chore: bump version (#3449) 2023-07-29 02:53:29 +00:00
Alex Yang
9f43c0ddc8 refactor: plugin loading logic (#3448) 2023-07-29 02:43:52 +00:00
Peng Xiao
4cb1bf6a9f test: add test for sub doc (#3444) 2023-07-28 15:15:32 +00:00
JimmFly
d96263fde9 feat: add read only mode for page in trash (#3440) 2023-07-28 15:01:10 +00:00
JimmFly
ed8b2d9927 chore: update change log link (#3435) 2023-07-28 15:00:03 +00:00
Alex Yang
7b3be389d4 v0.7.0-canary.59 2023-07-27 22:03:23 -07:00
JimmFly
68755f4303 fix: bring back the lost WorkspaceDeleteModal style (#3434) 2023-07-27 21:32:46 -07:00
Alex Yang
0e1f712dcc v0.7.0-canary.58 2023-07-27 20:33:14 -07:00
Alex Yang
0ab1cfdeb6 chore: split vitest (#3426) 2023-07-28 03:06:50 +00:00
Alex Yang
8185ee991b fix: serial build plugins (#3431) 2023-07-28 03:06:37 +00:00
Alex Yang
1001d7462a v0.7.0-canary.57 2023-07-27 17:58:21 -07:00
Alex Yang
f9929ebd61 fix: copilot not working (#3425) 2023-07-28 00:28:21 +00:00
Alex Yang
aa69a7cad2 v0.7.0-canary.56 2023-07-27 14:42:44 -07:00
JimmFly
4de063de98 style: adjust collection modal style (#3407) 2023-07-27 20:37:34 +00:00
Alex Yang
d765d0350d ci: add timeout (#3423) 2023-07-27 20:08:47 +00:00
Alex Yang
d2459a5837 fix(electron): plugin cannot found (#3418) 2023-07-27 19:55:19 +00:00
JimmFly
e1f604d857 refactor: create collection (#3406) 2023-07-27 19:55:04 +00:00
xiaodong zuo
af4e860176 fix: the exported pdf has part white background in dark mode (#3408) 2023-07-27 19:50:20 +00:00
Alex Yang
a3d665503f fix(core): delete page (#3419) 2023-07-27 18:12:11 +00:00
Alex Yang
b47fbde479 fix: improve navigate (#3420) 2023-07-27 18:06:30 +00:00
Pratik Kumar
115f46a4fa test: improve e2e coverage on page deletion (#3416) 2023-07-27 17:42:16 +00:00
Alex Yang
b0f8486ef2 docs: update plugin description 2023-07-27 10:48:45 -07:00
fourdim
57c27e6a4b fix: undefined allDb in firefox (#3417) 2023-07-27 16:30:09 +00:00
Subhadip Sarkar
f591939a6a docs: fix the Linux download button on the readme page (#3413) 2023-07-27 10:08:04 -07:00
Peng Xiao
2d41cce90f fix: sqlite db apply (#3409) 2023-07-27 07:06:06 -07:00
Alex Yang
3b1aff1db1 v0.7.0-canary.55 2023-07-27 07:03:07 -07:00
Alex Yang
3a64b43032 fix(cli): create empty plugin directory 2023-07-27 07:02:06 -07:00
Alex Yang
59f53760d1 v0.7.0-canary.54 2023-07-27 05:58:20 -07:00
Alex Yang
2980c1afac fix: plugin not found (#3415) 2023-07-27 05:56:59 -07:00
Alex Yang
39054a7c3d v0.7.0-canary.53 2023-07-27 05:19:20 -07:00
Alex Yang
4b7e47e265 chore: bump blocksuite (#3404)
Co-authored-by: LongYinan <lynweklm@gmail.com>
2023-07-27 05:37:38 +00:00
Peng Xiao
4e7824583d build: add AppImage build (#3401) 2023-07-26 22:38:01 -07:00
JimmFly
ba53c74130 fix: unable to add a second collection (#3405) 2023-07-26 22:37:42 -07:00
Qi
bc263e7afb feat: modify current workspace label to a dot (#3399) 2023-07-26 22:37:31 -07:00
JimmFly
bc27412425 feat: support gif toast (#3389) 2023-07-26 22:37:18 -07:00
Qi
fa8086d525 fix: button style error (#3396) 2023-07-26 22:37:00 -07:00
JimmFly
04534c2008 chore: adjust sidebar padding (#3397) 2023-07-26 22:36:45 -07:00
Alex Yang
780fffb88f fix: plugin infra (#3398) 2023-07-26 22:36:29 -07:00
Alex Yang
1e72d3c270 chore: bump version (#3394) 2023-07-27 04:02:18 +00:00
xiaodong zuo
1e38d36161 fix: inconsistent database content in exported PDF (#3385) 2023-07-26 21:26:53 +00:00
JimmFly
bb9908e1fa fix: filter button conflicts with electron header drag event (#3380) 2023-07-26 09:58:40 +00:00
liuyi
6bafa83cef fix(workspace): should avoid sending providers' update back (#3384) 2023-07-26 09:47:24 +00:00
JimmFly
2c249781a2 feat: add new collection button to slider bar (#3369) 2023-07-26 04:32:55 +00:00
Alex Yang
8334ac031b Revert "chore(cli): build infra (#3375)"
This reverts commit 635ca081e4.
2023-07-25 22:04:58 -07:00
Alex Yang
635ca081e4 chore(cli): build infra (#3375) 2023-07-25 23:33:25 +00:00
Alex Yang
10f879f29a refactor(electron): server side plugin (#3360) 2023-07-25 21:32:34 +00:00
Alex Yang
521e505a01 build: update cli (#3374) 2023-07-25 21:32:18 +00:00
Alex Yang
f968587f6f v0.7.0-canary.52 2023-07-25 12:36:30 -07:00
Whitewater
e70f8e74ec chore: allow custom editor spec presets (#3362)
Co-authored-by: Alex Yang <himself65@outlook.com>
2023-07-25 18:57:42 +00:00
Alex Yang
32fd01ed33 build: fix ci (#3373) 2023-07-25 18:41:32 +00:00
TinsFox
00718f8c9a chore: update version label (#3368) 2023-07-25 11:18:02 -07:00
Peng Xiao
20ee9d485d perf: use lazy load provider for IDB and SQLITE (#3351) 2023-07-25 16:56:48 +00:00
JimmFly
e3f66d7e22 style: move trash button group to page bottom (#3352) 2023-07-25 05:21:16 +00:00
JimmFly
be81e63eed chore: update icon size (#3350) 2023-07-24 23:35:10 +00:00
Alex Yang
2cf4e8ebce fix(y-indexeddb): un-track doc when destroy (#3358) 2023-07-24 15:23:16 +00:00
Alex Yang
e6e98975ed fix(core): avoid page full refresh (#3341)
Co-authored-by: Peng Xiao <pengxiao@outlook.com>
2023-07-24 09:02:35 +00:00
Peng Xiao
ccb0df10e4 fix: temp workaround for missing blobs in export (#3347) 2023-07-23 10:45:01 +00:00
Alex Yang
dd31d1e8c6 feat(plugin-infra): add plugin cli (#3344) 2023-07-22 17:17:40 +00:00
Alex Yang
a494bad543 chore: bump version (#3346) 2023-07-22 13:10:20 +00:00
danielchim
363699a175 feat: title editing on workspace title (#3139)
Co-authored-by: Alex Yang <himself65@outlook.com>
2023-07-22 13:03:18 +00:00
Qi
439ef1ba90 feat: refactor button with new design (#3343) 2023-07-21 11:07:28 +00:00
Alex Yang
a4f60f22cf v0.7.0-canary.51 2023-07-21 18:46:08 +08:00
Alex Yang
f05cd66368 fix(core): use Link from react-router-dom (#3342) 2023-07-21 10:29:36 +00:00
Peng Xiao
869d98d019 perf: lazy doc provider factory (#3330)
Co-authored-by: Alex Yang <himself65@outlook.com>
2023-07-21 05:23:18 +00:00
JimmFly
cff741e9ba style: add text overflow style for collections (#3292)
Co-authored-by: Alex Yang <himself65@outlook.com>
2023-07-21 03:48:22 +00:00
Alex Yang
9f105b5806 v0.7.0-canary.50 2023-07-21 11:52:50 +08:00
Alex Yang
cac609d36f fix(core): migration (#3322) 2023-07-20 20:16:15 +00:00
Alex Yang
c319e7e707 fix: type check in plugins (#3337) 2023-07-20 19:28:55 +00:00
Alex Yang
c2f6bb152c v0.7.0-canary.49 2023-07-21 01:21:25 +08:00
Alex Yang
f4b3c70fd4 build: move file 2023-07-21 01:20:29 +08:00
Alex Yang
a9db82ea21 v0.7.0-canary.48 2023-07-21 00:56:46 +08:00
Alex Yang
ecf6f98858 chore: bump version (#3333) 2023-07-20 16:39:16 +00:00
Alex Yang
e3a6204f2d fix: lockdown (#3336) 2023-07-20 16:04:26 +00:00
Alex Yang
19055baa49 feat: init new plugin system (#3323) 2023-07-20 10:52:29 +00:00
Alex Yang
604b53d9a4 feat: init doc monitor (#3320) 2023-07-20 02:44:50 +00:00
Alex Yang
27edd7cd93 fix: enable strict mode (#3321) 2023-07-20 01:59:58 +00:00
Alex Yang
fbd5b36170 feat: use string on origin (#3319) 2023-07-19 16:15:48 +00:00
Alex Yang
19925038ba fix(core): css.ts hmr (#3317) 2023-07-19 15:52:21 +00:00
Alex Yang
ae182bfd78 chore: update runtime (#3312) 2023-07-19 09:58:51 +00:00
Alex Yang
710b34a13a chore(core): update webpack hash logic (#3308) 2023-07-19 07:19:27 +00:00
Alex Yang
8e9535dd27 fix(core): plugin (#3307) 2023-07-19 07:00:42 +00:00
JimmFly
f4aa249138 fix: banner blocking new page button issue (#3301) 2023-07-19 04:51:15 +00:00
Alex Yang
57bac5d36b chore: bump version (#3298) 2023-07-19 04:31:57 +00:00
Alex Yang
b6e5618a2e chore(core): fix missing stuff (#3302) 2023-07-19 04:30:04 +00:00
Alex Yang
e475aa4c99 feat: add bootstrap (#3299) 2023-07-19 03:58:23 +00:00
Alex Yang
4ced66c236 chore: remove next.js dependency (#3297) 2023-07-19 03:13:14 +00:00
Alex Yang
1abcdee2f0 fix(cli): update dev-core (#3296) 2023-07-19 02:55:56 +00:00
Alex Yang
47f12f77f2 refactor!: remove next.js (#3267) 2023-07-18 16:53:10 +00:00
Whitewater
79227a1e7c chore: update block card styles (#3290) 2023-07-18 11:45:03 +00:00
Whitewater
bf41b25988 feat: new import page component (#3277) 2023-07-18 05:36:14 +00:00
Alex Yang
41edacfc81 build: fix nx inputs 2023-07-18 12:59:25 +08:00
JimmFly
9b32db9f62 chore: increase the frequency of the banner (#3264) 2023-07-17 09:45:02 +00:00
JimmFly
f21eb5f272 feat: move plugins config to setting (#3259) 2023-07-17 09:25:00 +00:00
JimmFly
d4cd0e763d fix: temporarily handle all page scroll bar styles (#3269) 2023-07-17 08:04:12 +00:00
Camol
8f06854130 feat(i18n): support i18n in app version (#3263) 2023-07-17 08:03:50 +00:00
Peng Xiao
81bad608bc fix: disable updater button when app updating (#3268) 2023-07-17 07:49:03 +00:00
Alex Yang
eeed398155 fix(plugin-infra): react as peer dependency (#3260) 2023-07-17 15:48:32 +08:00
xiaodong zuo
f173c8b183 chore: update blocksuite version (#3261) 2023-07-17 06:44:53 +00:00
Alex Yang
071d582250 fix: first workspace not found (#3258) 2023-07-17 05:00:30 +00:00
JimmFly
e8f8bd21cf chore: upadete onboarding video and changlog link (#3255) 2023-07-17 04:31:07 +00:00
Alex Yang
c0749fbb9f refactor: use useCallback (#3254) 2023-07-17 03:31:06 +00:00
Si Yang
b317a3e506 docs: update building-desktop-client-app.md (#3248) 2023-07-17 03:11:31 +00:00
Alex Yang
06184a765c fix(plugin-infra): dependencies (#3252) 2023-07-17 03:11:02 +00:00
Alex Yang
a2dae0d592 v0.7.0-canary.47 2023-07-16 23:27:39 +08:00
Alex Yang
202e9b8fe3 chore: bump version (#3250)
Co-authored-by: Alex Yang <himself65@Alexs-MacBook-Pro.local>
2023-07-16 15:13:00 +00:00
angle
ce23817c11 fix: pwa icon (#3246) 2023-07-15 23:20:29 +08:00
Alex Yang
c49cf1c53c fix: create first workspace logic (#3241) 2023-07-14 09:54:11 +00:00
Alex Yang
1bc427e7a6 fix: migration logic (#3238) 2023-07-14 09:28:15 +00:00
Alex Yang
ea592eb150 fix: remove hello-world page (#3234) 2023-07-14 07:49:34 +00:00
Alex Yang
5864f8cb9a refactor: simplify code (#3231) 2023-07-14 07:47:51 +00:00
Alex Yang
2be0ae8906 revert: use stable react (#3228) 2023-07-14 05:33:43 +00:00
Peng Xiao
9a85a14970 fix: internal build updater (#3229) 2023-07-14 05:21:43 +00:00
Alex Yang
6b0d048156 v0.7.0-canary.46 2023-07-14 11:30:06 +08:00
Alex Yang
3421c2803a fix(plugin-infra): dependencies (#3226) 2023-07-14 03:18:08 +00:00
Alex Yang
af6807826b v0.7.0-canary.45 2023-07-14 01:01:58 +08:00
Alex Yang
1336ec562e chore: bump version (#3223) 2023-07-13 16:40:44 +00:00
Alex Yang
1f5995ffc7 refactor(plugin-infra): workspace loading (#3222) 2023-07-13 15:52:06 +00:00
3720
23ac82f845 fix: can't go back to all pages by click All Pages button (#3219) 2023-07-13 15:26:12 +00:00
Alex Yang
492852ba0c refactor: mode atom (#3221) 2023-07-13 15:11:00 +00:00
Alex Yang
d18df12951 test: add workspace ref in e2e (#3217) 2023-07-13 12:41:46 +00:00
Alex Yang
64cf297399 refactor(web): move current atoms into plugin infra (#3220) 2023-07-13 12:14:30 +00:00
Alex Yang
0230cea16e refactor: move test utils to package (#3206) 2023-07-13 09:05:01 +00:00
Alex Yang
4f5ed30298 v0.7.0-canary.44 2023-07-13 17:07:14 +08:00
3720
9c5d91a1d9 fix: collections should be unique for workspaces (#3213) 2023-07-13 08:42:20 +00:00
Alex Yang
24a5b54b67 fix: fullscreen settting not working (#3215)
Co-authored-by: QiShaoXuan <qishaoxuan777@gmail.com>
2023-07-13 16:31:17 +08:00
xiaodong zuo
8be6676ddb chore: update blocksuite version (#3209)
Co-authored-by: Alex Yang <himself65@outlook.com>
2023-07-13 07:31:13 +00:00
Alex Yang
6a2dbc0105 fix: page id could be invalid (#3204) 2023-07-13 04:18:18 +00:00
Alex Yang
5dda7d83da fix: block hub might not work (#3199) 2023-07-12 18:02:00 +00:00
583 changed files with 13393 additions and 12692 deletions

View File

@@ -10,7 +10,7 @@
"tasks": {
"start-web": {
"name": "Start Web",
"command": "yarn nx dev @affine/web --port 8080",
"command": "yarn dev-core",
"runAtStart": true,
"preview": {
"port": 8080

View File

@@ -7,7 +7,7 @@
[
"electron",
"server",
"web",
"core",
"docs",
"storybook",
"component",
@@ -22,7 +22,9 @@
"templates",
"y-indexeddb",
"debug",
"storage"
"storage",
"infra",
"plugin-infra"
]
]
}

11
.env.template Normal file
View File

@@ -0,0 +1,11 @@
ENABLE_PLUGIN=
ENABLE_TEST_PROPERTIES=
ENABLE_BC_PROVIDER=
CHANGELOG_URL=
ENABLE_PRELOADING=
ENABLE_NEW_SETTING_MODAL=
ENABLE_SQLITE_PROVIDER=
ENABLE_NEW_SETTING_UNSTABLE_API=
ENABLE_NOTIFICATION_CENTER=
ENABLE_CLOUD=
ENABLE_MOVE_DATABASE=

View File

@@ -22,10 +22,15 @@ const createPattern = packageName => [
allowTypeImports: false,
},
{
group: ['@blocksuite/store'],
group: ['@blocksuite /store'],
message: "Import from '@blocksuite/global/utils'",
importNames: ['assertExists', 'assertEquals'],
},
{
group: ['react-router-dom'],
message: 'Use `useNavigateHelper` instead',
importNames: ['useNavigate'],
},
];
const allPackages = [
@@ -144,6 +149,11 @@ const config = {
message: "Import from '@blocksuite/global/utils'",
importNames: ['assertExists', 'assertEquals'],
},
{
group: ['react-router-dom'],
message: 'Use `useNavigateHelper` instead',
importNames: ['useNavigate'],
},
],
},
],

View File

@@ -21,8 +21,8 @@ body:
label: Distribution version
description: What version of AFFiNE are you using?
options:
- macOS x64
- macOS ARM 64
- macOS x64 (Intel)
- macOS ARM 64 (Apple Silicon)
- Windows x64
- Linux
- Web (app.affine.pro)

View File

@@ -1,6 +1,6 @@
FROM openresty/openresty:1.21.4.1-0-buster
WORKDIR /app
COPY ./apps/web/out ./dist
COPY ./apps/core/dist ./dist
COPY ./.github/deployment/front/nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
COPY ./.github/deployment/front/affine.nginx.conf /etc/nginx/conf.d/affine.nginx.conf

2
.github/labeler.yml vendored
View File

@@ -53,7 +53,7 @@ rust:
package:y-indexeddb: 'packages/y-indexeddb/**/*'
app:web: 'apps/web/**/*'
app:core: 'apps/core/**/*'
app:electron: 'apps/electron/**/*'

View File

@@ -101,8 +101,8 @@ jobs:
path: ./apps/storybook/storybook-static
if-no-files-found: error
build-web:
name: Build @affine/web
build-core:
name: Build @affine/core
runs-on: ubuntu-latest
environment: development
@@ -110,13 +110,15 @@ jobs:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: ./.github/actions/setup-node
- name: Build Web
run: yarn nx build @affine/web
- name: Upload artifact
- name: Build Plugins
run: yarn run build:plugins
- name: Build Core
run: yarn nx build @affine/core
- name: Upload core artifact
uses: actions/upload-artifact@v3
with:
name: next-js-static
path: ./apps/web/out
name: core
path: ./apps/core/dist
if-no-files-found: error
server-test:
@@ -207,6 +209,48 @@ jobs:
run: |
yarn exec concurrently -k -s first -n "SB,TEST" -c "magenta,blue" "yarn exec serve ./storybook-static -l 6006" "yarn exec wait-on tcp:6006 && yarn test"
e2e-plugin-test:
name: E2E Plugin Test
runs-on: ubuntu-latest
environment: development
needs: build-core
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: ./.github/actions/setup-node
with:
playwright-install: true
electron-install: false
- name: Download core artifact
uses: actions/download-artifact@v3
with:
name: core
path: ./apps/core/dist
- name: Run playwright tests
run: yarn e2e --forbid-only
working-directory: tests/affine-plugin
env:
COVERAGE: true
- name: Collect code coverage report
run: yarn exec nyc report -t .nyc_output --report-dir .coverage --reporter=lcov
- name: Upload e2e test coverage results
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./.coverage/lcov.info
flags: e2e-plugin-test
name: affine
fail_ci_if_error: false
- name: Upload test results
if: ${{ failure() }}
uses: actions/upload-artifact@v3
with:
name: test-results-e2e-plugin
path: ./test-results
if-no-files-found: ignore
e2e-test:
name: E2E Test
runs-on: ubuntu-latest
@@ -215,7 +259,7 @@ jobs:
matrix:
shard: [1, 2, 3, 4, 5]
environment: development
needs: build-web
needs: build-core
steps:
- uses: actions/checkout@v3
@@ -224,14 +268,15 @@ jobs:
with:
playwright-install: true
electron-install: false
- name: Download artifact
- name: Download core artifact
uses: actions/download-artifact@v3
with:
name: next-js-static
path: ./apps/web/out
name: core
path: ./apps/core/dist
- name: Run playwright tests
run: yarn e2e --forbid-only --shard=${{ matrix.shard }}/${{ strategy.job-total }}
working-directory: tests/affine-local
env:
COVERAGE: true
@@ -259,7 +304,7 @@ jobs:
name: E2E Migration Test
runs-on: ubuntu-latest
environment: development
needs: [build-web]
needs: build-core
steps:
- uses: actions/checkout@v3
@@ -269,11 +314,11 @@ jobs:
playwright-install: true
electron-install: false
- name: Download next static
- name: Download core artifact
uses: actions/download-artifact@v3
with:
name: next-js-static
path: ./apps/web/out
name: core
path: ./apps/core/dist
- name: Unzip
run: yarn unzip
@@ -332,11 +377,12 @@ jobs:
target: x86_64-pc-windows-msvc,
test: true,
}
needs: [build-web]
needs: build-core
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: ./.github/actions/setup-node
timeout-minutes: 10
with:
playwright-install: true
hard-link-nm: false
@@ -348,14 +394,13 @@ jobs:
- name: Run unit tests
if: ${{ matrix.spec.test }}
shell: bash
run: yarn nx test @affine/monorepo
env:
NATIVE_TEST: 'true'
run: yarn vitest
working-directory: ./apps/electron
- name: Download static resource artifact
- name: Download core artifact
uses: actions/download-artifact@v3
with:
name: next-js-static
name: core
path: apps/electron/resources/web-static
- name: Build Plugins
@@ -442,11 +487,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Download next static
- name: Download core artifact
uses: actions/download-artifact@v3
with:
name: next-js-static
path: ./apps/web/out
name: core
path: ./apps/core/dist
- name: Download server dist
uses: actions/download-artifact@v3
with:

View File

@@ -34,7 +34,7 @@ jobs:
runs-on: ubuntu-latest
environment: production
outputs:
version: 0.0.0-${{ steps.version.outputs.version }}
version: 0.0.0-internal.${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@v3
- uses: toeverything/set-build-version@latest
@@ -62,10 +62,10 @@ jobs:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
RELEASE_VERSION: ${{ needs.set-build-version.outputs.version }}
- name: Upload Artifact (web-static)
- name: Upload core artifact
uses: actions/upload-artifact@v3
with:
name: before-make-web-static
name: core
path: apps/electron/resources/web-static
make-distribution:
@@ -120,7 +120,7 @@ jobs:
run: ./scripts/set-version.sh ${{ needs.set-build-version.outputs.version }}
- uses: actions/download-artifact@v3
with:
name: before-make-web-static
name: core
path: apps/electron/resources/web-static
- name: Build Plugins
@@ -159,6 +159,7 @@ jobs:
run: |
mkdir -p builds
mv apps/electron/out/*/make/zip/linux/x64/*.zip ./builds/affine-${{ env.BUILD_TYPE }}-linux-x64.zip
mv apps/electron/out/*/make/AppImage/x64/*.AppImage ./builds/affine-${{ env.BUILD_TYPE }}-linux-x64.AppImage
- name: Upload Artifact
uses: actions/upload-artifact@v3

View File

@@ -66,10 +66,10 @@ jobs:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
RELEASE_VERSION: ${{ github.event.inputs.version || steps.get-canary-version.outputs.RELEASE_VERSION }}
- name: Upload Artifact (web-static)
- name: Upload core artifact
uses: actions/upload-artifact@v3
with:
name: before-make-web-static
name: core
path: apps/electron/resources/web-static
make-distribution:
@@ -120,7 +120,7 @@ jobs:
nx_token: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
- uses: actions/download-artifact@v3
with:
name: before-make-web-static
name: core
path: apps/electron/resources/web-static
- name: Build Plugins
@@ -159,6 +159,7 @@ jobs:
run: |
mkdir -p builds
mv apps/electron/out/*/make/zip/linux/x64/*.zip ./builds/affine-${{ env.BUILD_TYPE }}-linux-x64.zip
mv apps/electron/out/*/make/AppImage/x64/*.AppImage ./builds/affine-${{ env.BUILD_TYPE }}-linux-x64.AppImage
- name: Upload Artifact
uses: actions/upload-artifact@v3

8
.gitignore vendored
View File

@@ -13,6 +13,7 @@
/out-tsc
.nyc_output
.coverage
.swc
# dependencies
node_modules
@@ -60,9 +61,10 @@ out/
storybook-static
i18n-generated.ts
/test-results/
/playwright-report/
/playwright/.cache/
test-results
playwright-report
playwright/.cache
download
# Cache
.eslintcache

View File

@@ -12,3 +12,5 @@ tests/affine-legacy/0.7.0-canary.18/static
.github/helm
_next
storybook-static
web-static
public

View File

@@ -126,10 +126,10 @@ If you have questions, you are welcome to contact us. One of the best places to
>
> (Currently, plugins are under heavy development, and the SDK is not yet available.)
| Name | |
| ------------------------------------------------ | ----------------------------------------- |
| [@affine/bookmark-block](plugins/bookmark-block) | A block for bookmarking a website |
| [@affine/copilot](plugins/copilot) | AI Copilot that help you document writing |
| Name | |
| ------------------------------------ | ----------------------------------------- |
| [@affine/bookmark](plugins/bookmark) | A block for bookmarking a website |
| [@affine/copilot](plugins/copilot) | AI Copilot that help you document writing |
## Thanks
@@ -197,10 +197,10 @@ See [LICENSE] for details.
[jobs available]: ./docs/jobs.md
[latest packages]: https://github.com/toeverything/AFFiNE/pkgs/container/affine-self-hosted
[contributor license agreement]: https://github.com/toeverything/affine/edit/master/.github/CLA.md
[rust-version-icon]: https://img.shields.io/badge/Rust-1.70.0-dea584
[rust-version-icon]: https://img.shields.io/badge/Rust-1.71.0-dea584
[stars-icon]: https://img.shields.io/github/stars/toeverything/AFFiNE.svg?style=flat&logo=github&colorB=red&label=stars
[codecov]: https://codecov.io/gh/toeverything/affine/branch/master/graphs/badge.svg?branch=master
[node-version-icon]: https://img.shields.io/badge/node-%3E=18.16.1-success
[typescript-version-icon]: https://img.shields.io/github/package-json/dependency-version/toeverything/affine/dev/typescript
[react-version-icon]: https://img.shields.io/github/package-json/dependency-version/toeverything/AFFiNE/react?filename=apps%2Fweb%2Fpackage.json&color=rgb(97%2C228%2C251)
[blocksuite-icon]: https://img.shields.io/github/package-json/dependency-version/toeverything/AFFiNE/@blocksuite/store?color=6880ff&filename=apps%2Fweb%2Fpackage.json&label=blocksuite
[react-version-icon]: https://img.shields.io/github/package-json/dependency-version/toeverything/AFFiNE/react?filename=apps%2Fcore%2Fpackage.json&color=rgb(97%2C228%2C251)
[blocksuite-icon]: https://img.shields.io/github/package-json/dependency-version/toeverything/AFFiNE/@blocksuite/store?color=6880ff&filename=apps%2Fcore%2Fpackage.json&label=blocksuite

View File

@@ -20,6 +20,6 @@ Server using [Nest.js](https://nestjs.com/).
Storybook using [Storybook](https://storybook.js.org/).
## web
## Core
AFFiNE Core Application using [React.js](https://reactjs.org/).

View File

@@ -0,0 +1,82 @@
function testPackageName(regexp: RegExp): (module: any) => boolean {
return (module: any) =>
module.nameForCondition && regexp.test(module.nameForCondition());
}
export const productionCacheGroups = {
asyncVendor: {
test: /[\\/]node_modules[\\/]/,
name(module: any) {
// https://hackernoon.com/the-100-correct-way-to-split-your-chunks-with-webpack-f8a9df5b7758
const name =
module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)?.[1] ??
'unknown';
return `npm-async-${name}`;
},
priority: Number.MAX_SAFE_INTEGER,
chunks: 'async' as const,
},
mui: {
name: `npm-mui`,
test: testPackageName(/[\\/]node_modules[\\/](mui|@mui)[\\/]/),
priority: 200,
enforce: true,
},
blocksuite: {
name: `npm-blocksuite`,
test: testPackageName(/[\\/]node_modules[\\/](@blocksuite)[\\/]/),
priority: 200,
enforce: true,
},
react: {
name: `npm-react`,
test: testPackageName(
/[\\/]node_modules[\\/](react|react-dom|scheduler)[\\/]/
),
priority: 200,
enforce: true,
},
jotai: {
name: `npm-jotai`,
test: testPackageName(/[\\/]node_modules[\\/](jotai)[\\/]/),
priority: 200,
enforce: true,
},
rxjs: {
name: `npm-rxjs`,
test: testPackageName(/[\\/]node_modules[\\/]rxjs[\\/]/),
priority: 200,
enforce: true,
},
lodash: {
name: `npm-lodash`,
test: testPackageName(/[\\/]node_modules[\\/]lodash[\\/]/),
priority: 200,
enforce: true,
},
emotion: {
name: `npm-emotion`,
test: testPackageName(/[\\/]node_modules[\\/](@emotion)[\\/]/),
priority: 200,
enforce: true,
},
vendor: {
name: 'vendor',
test: /[\\/]node_modules[\\/]/,
priority: 190,
enforce: true,
},
styles: {
name: 'styles',
test: (module: any) =>
module.nameForCondition &&
/\.css$/.test(module.nameForCondition()) &&
!/^javascript/.test(module.type),
chunks: 'all' as const,
minSize: 1,
minChunks: 1,
reuseExistingChunk: true,
priority: 1000,
enforce: true,
},
};

View File

@@ -0,0 +1,346 @@
import { join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { createRequire } from 'node:module';
import HTMLPlugin from 'html-webpack-plugin';
import type { Configuration as DevServerConfiguration } from 'webpack-dev-server';
import { PerfseePlugin } from '@perfsee/webpack';
import { sentryWebpackPlugin } from '@sentry/webpack-plugin';
import CopyPlugin from 'copy-webpack-plugin';
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
import TerserPlugin from 'terser-webpack-plugin';
import webpack from 'webpack';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import { productionCacheGroups } from './cache-group.js';
import type { BuildFlags } from '@affine/cli/config';
import { projectRoot } from '@affine/cli/config';
import { VanillaExtractPlugin } from '@vanilla-extract/webpack-plugin';
import { computeCacheKey } from './utils.js';
import type { RuntimeConfig } from '@affine/env/global';
const IN_CI = !!process.env.CI;
export const rootPath = fileURLToPath(new URL('..', import.meta.url));
const require = createRequire(rootPath);
const OptimizeOptionOptions: (
buildFlags: BuildFlags
) => webpack.Configuration['optimization'] = buildFlags => ({
minimize: buildFlags.mode === 'production',
minimizer: [
new TerserPlugin({
minify: TerserPlugin.swcMinify,
parallel: true,
extractComments: true,
terserOptions: {
ecma: 2020,
compress: {
unused: true,
},
mangle: true,
},
}),
],
removeEmptyChunks: true,
providedExports: true,
usedExports: true,
sideEffects: true,
removeAvailableModules: true,
runtimeChunk: {
name: 'runtime',
},
splitChunks: {
chunks: 'all',
minSize: 1,
minChunks: 1,
maxInitialRequests: Number.MAX_SAFE_INTEGER,
maxAsyncRequests: Number.MAX_SAFE_INTEGER,
cacheGroups:
buildFlags.mode === 'production'
? productionCacheGroups
: {
default: false,
vendors: false,
},
},
});
export const createConfiguration: (
buildFlags: BuildFlags,
runtimeConfig: RuntimeConfig
) => webpack.Configuration = (buildFlags, runtimeConfig) => {
let publicPath = process.env.PUBLIC_PATH ?? '/';
const cacheKey = computeCacheKey(buildFlags);
const config = {
name: 'affine',
// to set a correct base path for the source map
context: projectRoot,
output: {
environment: {
module: true,
dynamicImport: true,
},
filename:
buildFlags.mode === 'production'
? 'js/[name]-[contenthash:8].js'
: 'js/[name].js',
// In some cases webpack will emit files starts with "_" which is reserved in web extension.
chunkFilename: 'js/chunk.[name].js',
assetModuleFilename: 'assets/[contenthash:8][ext][query]',
devtoolModuleFilenameTemplate: 'webpack://[namespace]/[resource-path]',
hotUpdateChunkFilename: 'hot/[id].[fullhash].js',
hotUpdateMainFilename: 'hot/[runtime].[fullhash].json',
path: join(rootPath, 'dist'),
clean: buildFlags.mode === 'production',
globalObject: 'globalThis',
publicPath,
},
target: ['web', 'es2022'],
mode: buildFlags.mode,
devtool:
buildFlags.mode === 'production'
? buildFlags.distribution === 'desktop'
? 'nosources-source-map'
: 'source-map'
: 'eval-cheap-module-source-map',
resolve: {
symlinks: true,
extensionAlias: {
'.js': ['.js', '.tsx', '.ts'],
'.mjs': ['.mjs', '.mts'],
},
extensions: ['.js', '.ts', '.tsx'],
},
cache: {
type: 'filesystem',
buildDependencies: {
config: [fileURLToPath(import.meta.url)],
},
version: cacheKey,
},
module: {
parser: {
javascript: {
// Treat as missing export as error
strictExportPresence: true,
},
},
rules: [
{
test: /\.m?js?$/,
resolve: {
fullySpecified: false,
},
},
{
oneOf: [
{
test: /\.tsx?$/,
// Compile all ts files in the workspace
include: resolve(rootPath, '..', '..'),
loader: require.resolve('swc-loader'),
options: {
// https://swc.rs/docs/configuring-swc/
jsc: {
preserveAllComments: true,
parser: {
syntax: 'typescript',
dynamicImport: true,
topLevelAwait: false,
tsx: true,
},
target: 'es2022',
externalHelpers: true,
transform: {
react: {
runtime: 'automatic',
refresh: buildFlags.mode === 'development' && {
refreshReg: '$RefreshReg$',
refreshSig: '$RefreshSig$',
emitFullSignatures: true,
},
},
},
experimental: {
keepImportAssertions: true,
plugins: [
buildFlags.coverage && [
'swc-plugin-coverage-instrument',
{},
],
].filter(Boolean),
},
},
},
},
{
test: /\.svg$/,
use: [
'thread-loader',
{
loader: '@svgr/webpack',
options: {
icon: true,
},
},
],
exclude: [/node_modules/],
},
{
test: /\.(png|jpg|gif|svg|webp)$/,
type: 'asset/resource',
},
{
test: /\.(ttf|eot|woff|woff2)$/,
type: 'asset/resource',
},
{
test: /\.txt$/,
loader: 'raw-loader',
},
{
test: /\.css$/,
use: [
buildFlags.mode === 'development'
? 'style-loader'
: MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
url: false,
sourceMap: false,
modules: false,
import: true,
importLoaders: 1,
},
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
config: resolve(
rootPath,
'.webpack',
'postcss.config.cjs'
),
},
},
},
],
},
],
},
],
},
plugins: [
...(IN_CI ? [] : [new webpack.ProgressPlugin({ percentBy: 'entries' })]),
...(buildFlags.mode === 'development'
? [new ReactRefreshWebpackPlugin({ overlay: false, esModule: true })]
: [
new MiniCssExtractPlugin({
filename: `[name].[contenthash:8].css`,
ignoreOrder: true,
}),
]),
new HTMLPlugin({
template: join(rootPath, '.webpack', 'template.html'),
inject: 'body',
scriptLoading: 'defer',
minify: false,
chunks: ['index', 'plugin'],
filename: 'index.html',
}),
new VanillaExtractPlugin(),
new webpack.DefinePlugin({
'process.env': JSON.stringify({}),
'process.env.COVERAGE': JSON.stringify(!!buildFlags.coverage),
'process.env.NODE_ENV': JSON.stringify(buildFlags.mode),
runtimeConfig: JSON.stringify(runtimeConfig),
}),
new CopyPlugin({
patterns: [
{ from: resolve(rootPath, 'public'), to: resolve(rootPath, 'dist') },
],
}),
],
optimization: OptimizeOptionOptions(buildFlags),
devServer: {
hot: 'only',
liveReload: true,
client: undefined,
historyApiFallback: true,
static: {
directory: resolve(rootPath, 'public'),
publicPath: '/',
watch: true,
},
} as DevServerConfiguration,
} satisfies webpack.Configuration;
if (buildFlags.mode === 'production' && process.env.PERFSEE_TOKEN) {
config.devtool = 'hidden-nosources-source-map';
config.plugins.push(
new PerfseePlugin({
project: 'affine-toeverything',
})
);
}
if (buildFlags.mode === 'development') {
config.optimization = {
...config.optimization,
minimize: false,
runtimeChunk: false,
splitChunks: {
maxInitialRequests: Infinity,
chunks: 'all',
cacheGroups: {
defaultVendors: {
test: `[\\/]node_modules[\\/](?!.*vanilla-extract)`,
priority: -10,
reuseExistingChunk: true,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
styles: {
name: 'styles',
type: 'css/mini-extract',
chunks: 'all',
enforce: true,
},
},
},
};
}
if (
process.env.SENTRY_AUTH_TOKEN &&
process.env.SENTRY_ORG &&
process.env.SENTRY_PROJECT
) {
config.plugins.push(
sentryWebpackPlugin({
org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT,
authToken: process.env.SENTRY_AUTH_TOKEN,
})
);
}
return config;
};

View File

@@ -0,0 +1,20 @@
const cssnano = require('cssnano');
module.exports = function (context) {
const plugins = [
cssnano({
preset: [
'default',
{
convertValues: false,
},
],
}),
];
return {
from: context.from,
plugins,
to: context.to,
};
};

View File

@@ -0,0 +1,115 @@
import type { BlockSuiteFeatureFlags, RuntimeConfig } from '@affine/env/global';
import type { BuildFlags } from '@affine/cli/config';
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
const packageJson = require('../package.json');
const editorFlags: BlockSuiteFeatureFlags = {
enable_database: true,
enable_slash_menu: true,
enable_edgeless_toolbar: true,
enable_block_hub: true,
enable_drag_handle: true,
enable_surface: true,
enable_linked_page: true,
enable_bookmark_operation: false,
};
export function getRuntimeConfig(buildFlags: BuildFlags): RuntimeConfig {
const buildPreset: Record<string, RuntimeConfig> = {
stable: {
enablePlugin: false,
enableTestProperties: false,
enableBroadcastChannelProvider: true,
enableDebugPage: true,
changelogUrl: 'https://affine.pro/blog/what-is-new-affine-0728',
imageProxyUrl: 'https://workers.toeverything.workers.dev/proxy/image',
enablePreloading: true,
enableNewSettingModal: true,
enableNewSettingUnstableApi: false,
enableSQLiteProvider: true,
enableMoveDatabase: false,
enableNotificationCenter: false,
enableCloud: false,
serverAPI: 'https://localhost:3010',
editorFlags,
appVersion: packageJson.version,
editorVersion: packageJson.dependencies['@blocksuite/editor'],
},
// canary will be aggressive and enable all features
canary: {
enablePlugin: true,
enableTestProperties: true,
enableBroadcastChannelProvider: true,
enableDebugPage: true,
changelogUrl: 'https://github.com/toeverything/AFFiNE/releases',
imageProxyUrl: 'https://workers.toeverything.workers.dev/proxy/image',
enablePreloading: true,
enableNewSettingModal: true,
enableNewSettingUnstableApi: false,
enableSQLiteProvider: true,
enableMoveDatabase: false,
enableNotificationCenter: true,
enableCloud: false,
serverAPI: 'https://localhost:3010',
editorFlags,
appVersion: packageJson.version,
editorVersion: packageJson.dependencies['@blocksuite/editor'],
},
};
// beta and internal versions are the same as stable
buildPreset.beta = buildPreset.stable;
buildPreset.internal = buildPreset.stable;
const currentBuild = buildFlags.channel;
if (!(currentBuild in buildPreset)) {
throw new Error(`BUILD_TYPE ${currentBuild} is not supported`);
}
const currentBuildPreset = buildPreset[currentBuild];
const environmentPreset = {
enablePlugin: process.env.ENABLE_PLUGIN
? process.env.ENABLE_PLUGIN === 'true'
: currentBuildPreset.enablePlugin,
enableTestProperties: process.env.ENABLE_TEST_PROPERTIES
? process.env.ENABLE_TEST_PROPERTIES === 'true'
: currentBuildPreset.enableTestProperties,
enableBroadcastChannelProvider: process.env.ENABLE_BC_PROVIDER
? process.env.ENABLE_BC_PROVIDER !== 'false'
: currentBuildPreset.enableBroadcastChannelProvider,
changelogUrl: process.env.CHANGELOG_URL ?? currentBuildPreset.changelogUrl,
enablePreloading: process.env.ENABLE_PRELOADING
? process.env.ENABLE_PRELOADING === 'true'
: currentBuildPreset.enablePreloading,
enableNewSettingModal: process.env.ENABLE_NEW_SETTING_MODAL
? process.env.ENABLE_NEW_SETTING_MODAL === 'true'
: currentBuildPreset.enableNewSettingModal,
enableSQLiteProvider: process.env.ENABLE_SQLITE_PROVIDER
? process.env.ENABLE_SQLITE_PROVIDER === 'true'
: currentBuildPreset.enableSQLiteProvider,
enableNewSettingUnstableApi: process.env.ENABLE_NEW_SETTING_UNSTABLE_API
? process.env.ENABLE_NEW_SETTING_UNSTABLE_API === 'true'
: currentBuildPreset.enableNewSettingUnstableApi,
enableNotificationCenter: process.env.ENABLE_NOTIFICATION_CENTER
? process.env.ENABLE_NOTIFICATION_CENTER === 'true'
: currentBuildPreset.enableNotificationCenter,
enableCloud: process.env.ENABLE_CLOUD
? process.env.ENABLE_CLOUD === 'true'
: currentBuildPreset.enableCloud,
enableMoveDatabase: process.env.ENABLE_MOVE_DATABASE
? process.env.ENABLE_MOVE_DATABASE === 'true'
: currentBuildPreset.enableMoveDatabase,
};
return {
...currentBuildPreset,
// environment preset will overwrite current build preset
// this environment variable is for debug proposes only
// do not put them into CI
...(process.env.CI ? {} : environmentPreset),
};
}

View File

@@ -0,0 +1,45 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1"
/>
<title>AFFiNE</title>
<meta name="theme-color" content="#fafafa" />
<link rel="manifest" href="/manifest.json" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<link rel="icon" sizes="192x192" href="/chrome-192x192.png" />
<meta name="emotion-insertion-point" content="" />
<meta property="description" content="{description}" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:url" content="https://app.affine.pro/" />
<meta
name="twitter:title"
content="AFFiNEThere can be more than Notion and Miro."
/>
<meta name="twitter:description" content="{description}" />
<meta name="twitter:site" content="@AffineOfficial" />
<meta name="twitter:image" content="https://affine.pro/og.jpeg" />
<meta
property="og:title"
content="AFFiNEThere can be more than Notion and Miro."
/>
<meta property="og:type" content="website" />
<meta
property="og:description"
content="There can be more than Notion and Miro. AFFiNE is a next-gen knowledge base that brings planning, sorting and creating all together."
/>
<meta property="og:url" content="https://app.affine.pro/" />
<meta property="og:image" content="https://affine.pro/og.jpeg" />
<link
data-react-helmet="true"
rel="shortcut icon"
href="https://affine.pro/favicon.ico"
/>
</head>
<body>
<div id="app"></div>
</body>
</html>

View File

@@ -0,0 +1,11 @@
import type { BuildFlags } from '@affine/cli/config';
export function computeCacheKey(buildFlags: BuildFlags) {
return [
'1',
'node' + process.version,
buildFlags.mode,
buildFlags.distribution,
buildFlags.channel,
].join('-');
}

View File

@@ -0,0 +1,28 @@
import { createConfiguration, rootPath } from './config.js';
import { merge } from 'webpack-merge';
import { resolve } from 'node:path';
import type { BuildFlags } from '@affine/cli/config';
import { getRuntimeConfig } from './runtime-config.js';
export default async function (cli_env: any, _: any) {
const flags: BuildFlags = JSON.parse(
Buffer.from(cli_env.flags, 'hex').toString('utf-8')
);
console.log('build flags', flags);
const runtimeConfig = getRuntimeConfig(flags);
console.log('runtime config', runtimeConfig);
const config = createConfiguration(flags, runtimeConfig);
return merge(config, {
entry: {
index: {
asyncChunks: false,
import: resolve(rootPath, 'src/index.tsx'),
},
plugin: {
dependOn: ['index'],
asyncChunks: true,
import: resolve(rootPath, 'src/bootstrap/register-plugins.ts'),
},
},
});
}

82
apps/core/package.json Normal file
View File

@@ -0,0 +1,82 @@
{
"name": "@affine/core",
"type": "module",
"private": true,
"version": "0.8.0-canary.1",
"scripts": {
"build": "yarn -T run build-core",
"dev": "yarn -T run dev-core",
"static-server": "ts-node-esm ./server.mts"
},
"dependencies": {
"@affine-test/fixtures": "workspace:*",
"@affine/component": "workspace:*",
"@affine/debug": "workspace:*",
"@affine/env": "workspace:*",
"@affine/graphql": "workspace:*",
"@affine/i18n": "workspace:*",
"@affine/jotai": "workspace:*",
"@affine/templates": "workspace:*",
"@affine/workspace": "workspace:*",
"@blocksuite/block-std": "0.0.0-20230729011742-613f3782-nightly",
"@blocksuite/blocks": "0.0.0-20230729011742-613f3782-nightly",
"@blocksuite/editor": "0.0.0-20230729011742-613f3782-nightly",
"@blocksuite/global": "0.0.0-20230729011742-613f3782-nightly",
"@blocksuite/icons": "^2.1.27",
"@blocksuite/lit": "0.0.0-20230729011742-613f3782-nightly",
"@blocksuite/store": "0.0.0-20230729011742-613f3782-nightly",
"@dnd-kit/core": "^6.0.8",
"@dnd-kit/sortable": "^7.0.2",
"@emotion/cache": "^11.11.0",
"@emotion/react": "^11.11.1",
"@emotion/server": "^11.11.0",
"@emotion/styled": "^11.11.0",
"@mui/material": "^5.14.2",
"@react-hookz/web": "^23.1.0",
"async-call-rpc": "^6.3.1",
"cmdk": "^0.2.0",
"css-spring": "^4.1.0",
"cssnano": "^6.0.1",
"graphql": "^16.7.1",
"jotai": "^2.2.2",
"jotai-devtools": "^0.6.0",
"lit": "^2.7.6",
"lottie-web": "^5.12.2",
"mini-css-extract-plugin": "^2.7.6",
"next-themes": "^0.2.1",
"postcss-loader": "^7.3.3",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-is": "18.2.0",
"react-resizable-panels": "^0.0.54",
"react-router-dom": "^6.14.2",
"rxjs": "^7.8.1",
"ses": "^0.18.5",
"swr": "2.1.5",
"y-protocols": "^1.0.5",
"yjs": "^13.6.7",
"zod": "^3.21.4"
},
"devDependencies": {
"@perfsee/webpack": "^1.8.2",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
"@sentry/webpack-plugin": "^2.5.0",
"@svgr/webpack": "^8.0.1",
"@swc/core": "^1.3.71",
"@types/webpack-env": "^1.18.1",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.8.1",
"express": "^4.18.2",
"html-webpack-plugin": "^5.5.3",
"raw-loader": "^4.0.2",
"style-loader": "^3.3.3",
"swc-loader": "^0.2.3",
"swc-plugin-coverage-instrument": "^0.0.19",
"thread-loader": "^4.0.2",
"ts-node": "^10.9.1",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1",
"webpack-merge": "^5.9.0"
}
}

51
apps/core/project.json Normal file
View File

@@ -0,0 +1,51 @@
{
"name": "@affine/core",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"root": "apps/core",
"sourceRoot": "apps/core/src",
"targets": {
"build": {
"executor": "nx:run-script",
"dependsOn": ["^build"],
"inputs": [
"{projectRoot}/**/*",
"{workspaceRoot}/packages/component/src/**/*",
"{workspaceRoot}/packages/debug/src/**/*",
"{workspaceRoot}/packages/graphql/src/**/*",
"{workspaceRoot}/packages/hooks/src/**/*",
"{workspaceRoot}/packages/jotai/src/**/*",
"{workspaceRoot}/packages/templates/src/**/*",
"{workspaceRoot}/packages/workspace/src/**/*",
{
"env": "BUILD_TYPE"
},
{
"env": "PERFSEE_TOKEN"
},
{
"env": "SENTRY_ORG"
},
{
"env": "SENTRY_PROJECT"
},
{
"env": "SENTRY_AUTH_TOKEN"
},
{
"env": "NEXT_PUBLIC_SENTRY_DSN"
},
{
"env": "DISTRIBUTION"
},
{
"env": "COVERAGE"
}
],
"options": {
"script": "build"
},
"outputs": ["{projectRoot}/dist", "{projectRoot}/public/plugins"]
}
}
}

4
apps/core/public/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
*.js
*.map
plugins

View File

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

15
apps/core/server.mts Normal file
View File

@@ -0,0 +1,15 @@
// static server for web app
import express from 'express';
const app = express();
const PORT = process.env.PORT || 8080;
app.use('/', express.static('dist'));
app.get('/*', (req, res) => {
res.sendFile('index.html', { root: 'dist' });
});
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});

View File

@@ -16,10 +16,10 @@ import {
CRUD,
saveWorkspaceToLocalStorage,
} from '@affine/workspace/local/crud';
import { getOrCreateWorkspace } from '@affine/workspace/manager';
import { createIndexedDBDownloadProvider } from '@affine/workspace/providers';
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
import { nanoid } from '@blocksuite/store';
import { useStaticBlockSuiteWorkspace } from '@toeverything/hooks/use-block-suite-workspace';
import { useStaticBlockSuiteWorkspace } from '@toeverything/plugin-infra/__internal__/react';
import {
BlockSuitePageList,
@@ -36,7 +36,7 @@ export const LocalAdapter: WorkspaceAdapter<WorkspaceFlavour.LOCAL> = {
loadPriority: LoadPriority.LOW,
Events: {
'app:init': () => {
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(
const blockSuiteWorkspace = getOrCreateWorkspace(
nanoid(),
WorkspaceFlavour.LOCAL
);

56
apps/core/src/app.tsx Normal file
View File

@@ -0,0 +1,56 @@
import '@affine/component/theme/global.css';
import '@affine/component/theme/theme.css';
import { AffineContext } from '@affine/component/context';
import { WorkspaceFallback } from '@affine/component/workspace';
import { createI18n, setUpLanguage } from '@affine/i18n';
import { CacheProvider } from '@emotion/react';
import type { PropsWithChildren, ReactElement } from 'react';
import { lazy, memo, Suspense, useEffect } from 'react';
import { RouterProvider } from 'react-router-dom';
import { router } from './router';
import createEmotionCache from './utils/create-emotion-cache';
const i18n = createI18n();
const cache = createEmotionCache();
const DevTools = lazy(() =>
import('jotai-devtools').then(m => ({ default: m.DevTools }))
);
const DebugProvider = ({ children }: PropsWithChildren): ReactElement => {
return (
<>
<Suspense>{process.env.DEBUG_JOTAI === 'true' && <DevTools />}</Suspense>
{children}
</>
);
};
const future = {
v7_startTransition: true,
} as const;
export const App = memo(function App() {
useEffect(() => {
document.documentElement.lang = i18n.language;
// todo(himself65): this is a hack, we should use a better way to set the language
setUpLanguage(i18n)?.catch(error => {
console.error(error);
});
}, []);
return (
<CacheProvider value={cache}>
<AffineContext>
<DebugProvider>
<RouterProvider
fallbackElement={<WorkspaceFallback key="RouterFallback" />}
router={router}
future={future}
/>
</DebugProvider>
</AffineContext>
</CacheProvider>
);
});

View File

@@ -0,0 +1,106 @@
import { useAtom } from 'jotai';
import { atomWithStorage, createJSONStorage } from 'jotai/utils';
import { useCallback } from 'react';
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
import { useNavigate } from 'react-router-dom';
import { router } from '../router';
export type History = {
stack: string[];
current: number;
skip: boolean;
};
export const MAX_HISTORY = 50;
const historyBaseAtom = atomWithStorage<History>(
'router-history',
{
stack: [],
current: 0,
skip: false,
},
createJSONStorage(() => sessionStorage)
);
historyBaseAtom.onMount = set => {
const unsubscribe = router.subscribe(state => {
set(prev => {
const url = state.location.pathname;
// if stack top is the same as current, skip
if (prev.stack[prev.current] === url) {
return prev;
}
if (prev.skip) {
return {
stack: [...prev.stack],
current: prev.current,
skip: false,
};
} else {
if (prev.current < prev.stack.length - 1) {
const newStack = prev.stack.slice(0, prev.current);
newStack.push(url);
if (newStack.length > MAX_HISTORY) {
newStack.shift();
}
return {
stack: newStack,
current: newStack.length - 1,
skip: false,
};
} else {
const newStack = [...prev.stack, url];
if (newStack.length > MAX_HISTORY) {
newStack.shift();
}
return {
stack: newStack,
current: newStack.length - 1,
skip: false,
};
}
}
});
});
return () => {
unsubscribe();
};
};
export function useHistoryAtom() {
const navigate = useNavigate();
const [base, setBase] = useAtom(historyBaseAtom);
return [
base,
useCallback(
(forward: boolean) => {
setBase(prev => {
if (forward) {
const target = Math.min(prev.stack.length - 1, prev.current + 1);
const url = prev.stack[target];
navigate(url);
return {
...prev,
current: target,
skip: true,
};
} else {
const target = Math.max(0, prev.current - 1);
const url = prev.stack[target];
navigate(url);
return {
...prev,
current: target,
skip: true,
};
}
});
},
[setBase, navigate]
),
] as const;
}

View File

@@ -0,0 +1,12 @@
import { currentPageIdAtom } from '@toeverything/plugin-infra/atom';
import { atom } from 'jotai/vanilla';
import { pageSettingFamily } from './index';
export const currentModeAtom = atom<'page' | 'edgeless'>(get => {
const pageId = get(currentPageIdAtom);
if (!pageId) {
return 'page';
}
return get(pageSettingFamily(pageId)).mode;
});

View File

@@ -0,0 +1,133 @@
import { migrateToSubdoc } from '@affine/env/blocksuite';
import { setupGlobal } from '@affine/env/global';
import type {
LocalIndexedDBDownloadProvider,
WorkspaceAdapter,
} from '@affine/env/workspace';
import { WorkspaceFlavour, WorkspaceVersion } from '@affine/env/workspace';
import type { RootWorkspaceMetadata } from '@affine/workspace/atom';
import {
type RootWorkspaceMetadataV2,
rootWorkspacesMetadataAtom,
workspaceAdaptersAtom,
} from '@affine/workspace/atom';
import {
migrateLocalBlobStorage,
upgradeV1ToV2,
} from '@affine/workspace/migration';
import { createIndexedDBDownloadProvider } from '@affine/workspace/providers';
import { assertExists } from '@blocksuite/global/utils';
import { rootStore } from '@toeverything/plugin-infra/atom';
import { WorkspaceAdapters } from '../adapters/workspace';
console.log('setup global');
setupGlobal();
rootStore.set(
workspaceAdaptersAtom,
WorkspaceAdapters as Record<
WorkspaceFlavour,
WorkspaceAdapter<WorkspaceFlavour>
>
);
const value = localStorage.getItem('jotai-workspaces');
if (value) {
try {
const metadata = JSON.parse(value) as RootWorkspaceMetadata[];
const promises: Promise<void>[] = [];
const newMetadata = [...metadata];
metadata.forEach(oldMeta => {
if (!('version' in oldMeta)) {
const adapter = WorkspaceAdapters[oldMeta.flavour];
assertExists(adapter);
const upgrade = async () => {
const workspace = await adapter.CRUD.get(oldMeta.id);
if (!workspace) {
console.warn('cannot find workspace', oldMeta.id);
return;
}
if (workspace.flavour !== WorkspaceFlavour.LOCAL) {
console.warn('not supported');
return;
}
const doc = workspace.blockSuiteWorkspace.doc;
const provider = createIndexedDBDownloadProvider(workspace.id, doc, {
awareness: workspace.blockSuiteWorkspace.awarenessStore.awareness,
}) as LocalIndexedDBDownloadProvider;
provider.sync();
await provider.whenReady;
const newDoc = migrateToSubdoc(doc);
if (doc === newDoc) {
console.log('doc not changed');
return;
}
const newWorkspace = upgradeV1ToV2(workspace);
const newId = await adapter.CRUD.create(
newWorkspace.blockSuiteWorkspace
);
await adapter.CRUD.delete(workspace as any);
console.log('migrated', oldMeta.id, newId);
const index = newMetadata.findIndex(meta => meta.id === oldMeta.id);
newMetadata[index] = {
...oldMeta,
id: newId,
version: WorkspaceVersion.SubDoc,
};
await migrateLocalBlobStorage(workspace.id, newId);
};
// create a new workspace and push it to metadata
promises.push(upgrade());
}
});
await Promise.all(promises)
.then(() => {
console.log('migration done');
})
.catch(() => {
console.error('migration failed');
})
.finally(() => {
localStorage.setItem('jotai-workspaces', JSON.stringify(newMetadata));
window.dispatchEvent(new CustomEvent('migration-done'));
window.$migrationDone = true;
});
} catch (e) {
console.error('error when migrating data', e);
}
}
const createFirst = (): RootWorkspaceMetadataV2[] => {
const Plugins = Object.values(WorkspaceAdapters).sort(
(a, b) => a.loadPriority - b.loadPriority
);
return Plugins.flatMap(Plugin => {
return Plugin.Events['app:init']?.().map(
id =>
({
id,
flavour: Plugin.flavour,
// new workspace should all support sub-doc feature
version: WorkspaceVersion.SubDoc,
}) satisfies RootWorkspaceMetadataV2
);
}).filter((ids): ids is RootWorkspaceMetadataV2 => !!ids);
};
await rootStore
.get(rootWorkspacesMetadataAtom)
.then(meta => {
if (meta.length === 0 && localStorage.getItem('is-first-open') === null) {
const result = createFirst();
console.info('create first workspace', result);
localStorage.setItem('is-first-open', 'false');
rootStore.set(rootWorkspacesMetadataAtom, result).catch(console.error);
}
})
.catch(console.error);

View File

@@ -0,0 +1,106 @@
import * as AFFiNEComponent from '@affine/component';
import * as BlockSuiteBlocksStd from '@blocksuite/blocks/std';
import * as BlockSuiteGlobalUtils from '@blocksuite/global/utils';
import * as Icons from '@blocksuite/icons';
import * as Atom from '@toeverything/plugin-infra/atom';
import * as Jotai from 'jotai/index';
import * as JotaiUtils from 'jotai/utils';
import * as React from 'react';
import * as ReactJSXRuntime from 'react/jsx-runtime';
import * as ReactDom from 'react-dom';
import * as ReactDomClient from 'react-dom/client';
const customRequire = (id: string) => {
if (id === '@toeverything/plugin-infra/atom') {
return Atom;
}
if (id === 'react') {
return React;
}
if (id === 'react/jsx-runtime') {
return ReactJSXRuntime;
}
if (id === 'react-dom') {
return ReactDom;
}
if (id === 'react-dom/client') {
return ReactDomClient;
}
if (id === '@blocksuite/icons') {
return Icons;
}
if (id === '@affine/component') {
return AFFiNEComponent;
}
if (id === '@blocksuite/blocks/std') {
return BlockSuiteBlocksStd;
}
if (id === '@blocksuite/global/utils') {
return BlockSuiteGlobalUtils;
}
if (id === 'jotai') {
return Jotai;
}
if (id === 'jotai/utils') {
return JotaiUtils;
}
throw new Error(`Cannot find module '${id}'`);
};
export const createGlobalThis = () => {
return {
process: Object.freeze({
env: {
NODE_ENV: process.env.NODE_ENV,
},
}),
// UNSAFE: React will read `window` and `document`
window,
document,
navigator,
userAgent: navigator.userAgent,
// todo(himself65): permission control
fetch: function (input: RequestInfo, init?: RequestInit) {
return globalThis.fetch(input, init);
},
setTimeout: function (callback: () => void, timeout: number) {
return globalThis.setTimeout(callback, timeout);
},
clearTimeout: function (id: number) {
return globalThis.clearTimeout(id);
},
// copilot uses these
crypto: globalThis.crypto,
CustomEvent: globalThis.CustomEvent,
Date: globalThis.Date,
Math: globalThis.Math,
URL: globalThis.URL,
URLSearchParams: globalThis.URLSearchParams,
Headers: globalThis.Headers,
TextEncoder: globalThis.TextEncoder,
TextDecoder: globalThis.TextDecoder,
Request: globalThis.Request,
Error: globalThis.Error,
// bookmark uses these
Blob: globalThis.Blob,
ClipboardItem: globalThis.ClipboardItem,
// fixme: use our own db api
indexedDB: globalThis.indexedDB,
IDBRequest: globalThis.IDBRequest,
IDBDatabase: globalThis.IDBDatabase,
IDBCursorWithValue: globalThis.IDBCursorWithValue,
IDBFactory: globalThis.IDBFactory,
IDBKeyRange: globalThis.IDBKeyRange,
IDBOpenDBRequest: globalThis.IDBOpenDBRequest,
IDBTransaction: globalThis.IDBTransaction,
IDBObjectStore: globalThis.IDBObjectStore,
IDBIndex: globalThis.IDBIndex,
IDBCursor: globalThis.IDBCursor,
IDBVersionChangeEvent: globalThis.IDBVersionChangeEvent,
exports: {},
console: globalThis.console,
require: customRequire,
};
};

View File

@@ -0,0 +1,170 @@
/// <reference types="@types/webpack-env" />
import 'ses';
import { DebugLogger } from '@affine/debug';
import { FormatQuickBar } from '@blocksuite/blocks';
import { DisposableGroup } from '@blocksuite/global/utils';
import {
editorItemsAtom,
headerItemsAtom,
registeredPluginAtom,
rootStore,
settingItemsAtom,
windowItemsAtom,
} from '@toeverything/plugin-infra/atom';
import type {
CallbackMap,
PluginContext,
} from '@toeverything/plugin-infra/entry';
import { Provider } from 'jotai/react';
import type { PropsWithChildren } from 'react';
import { createElement } from 'react';
import { createGlobalThis } from './plugins/setup';
if (!process.env.COVERAGE) {
lockdown({
evalTaming: 'unsafeEval',
overrideTaming: 'severe',
consoleTaming: 'unsafe',
errorTaming: 'unsafe',
errorTrapping: 'platform',
unhandledRejectionTrapping: 'report',
});
}
const builtinPluginUrl = new Set([
'/plugins/bookmark',
'/plugins/copilot',
'/plugins/hello-world',
'/plugins/image-preview',
]);
const logger = new DebugLogger('register-plugins');
const PluginProvider = ({ children }: PropsWithChildren) =>
createElement(
Provider,
{
store: rootStore,
},
children
);
const group = new DisposableGroup();
declare global {
// eslint-disable-next-line no-var
var __pluginPackageJson__: unknown[];
}
globalThis.__pluginPackageJson__ = [];
await Promise.all(
[...builtinPluginUrl].map(url => {
return fetch(`${url}/package.json`)
.then(async res => {
const packageJson = await res.json();
const {
name: pluginName,
affinePlugin: {
release,
entry: { core },
assets,
},
} = packageJson;
globalThis.__pluginPackageJson__.push(packageJson);
logger.debug(`registering plugin ${pluginName}`);
logger.debug(`package.json: ${packageJson}`);
if (!release && process.env.NODE_ENV === 'production') {
return Promise.resolve();
}
const pluginCompartment = new Compartment(createGlobalThis(), {});
const pluginGlobalThis = pluginCompartment.globalThis;
const baseURL = url;
const entryURL = `${baseURL}/${core}`;
rootStore.set(registeredPluginAtom, prev => [...prev, pluginName]);
await fetch(entryURL).then(async res => {
if (assets.length > 0) {
await Promise.all(
assets.map(async (asset: string) => {
if (asset.endsWith('.css')) {
const res = await fetch(`${baseURL}/${asset}`);
if (res.ok) {
// todo: how to put css file into sandbox?
return res.text().then(text => {
const style = document.createElement('style');
style.setAttribute('plugin-id', pluginName);
style.textContent = text;
document.head.appendChild(style);
});
}
return null;
} else {
return Promise.resolve();
}
})
);
}
const codeText = await res.text();
pluginCompartment.evaluate(codeText, {
__evadeHtmlCommentTest__: true,
});
pluginGlobalThis.__INTERNAL__ENTRY = {
register: (part, callback) => {
logger.info(`Registering ${pluginName} to ${part}`);
if (part === 'headerItem') {
rootStore.set(headerItemsAtom, items => ({
...items,
[pluginName]: callback as CallbackMap['headerItem'],
}));
} else if (part === 'editor') {
rootStore.set(editorItemsAtom, items => ({
...items,
[pluginName]: callback as CallbackMap['editor'],
}));
} else if (part === 'window') {
rootStore.set(windowItemsAtom, items => ({
...items,
[pluginName]: callback as CallbackMap['window'],
}));
} else if (part === 'setting') {
rootStore.set(settingItemsAtom, items => ({
...items,
[pluginName]: callback as CallbackMap['setting'],
}));
} else if (part === 'formatBar') {
FormatQuickBar.customElements.push((page, getBlockRange) => {
const div = document.createElement('div');
(callback as CallbackMap['formatBar'])(
div,
page,
getBlockRange
);
return div;
});
} else {
throw new Error(`Unknown part: ${part}`);
}
},
utils: {
PluginProvider,
},
} satisfies PluginContext;
const dispose = pluginCompartment.evaluate(
'exports.entry(__INTERNAL__ENTRY)'
);
if (typeof dispose !== 'function') {
throw new Error('Plugin entry must return a function');
}
pluginGlobalThis.__INTERNAL__ENTRY = undefined;
group.add(dispose);
});
})
.catch(e => {
console.error(`error when fetch plugin from ${url}`, e);
});
})
).then(() => {
console.info('All plugins loaded');
});

View File

@@ -1,6 +1,6 @@
import { initEmptyPage } from '@affine/env/blocksuite';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
import { getOrCreateWorkspace } from '@affine/workspace/manager';
import type { EditorContainer } from '@blocksuite/editor';
import type { Page } from '@blocksuite/store';
import type React from 'react';
@@ -8,7 +8,7 @@ import { useCallback } from 'react';
import { BlockSuiteEditor } from '../../blocksuite/block-suite-editor';
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(
const blockSuiteWorkspace = getOrCreateWorkspace(
'test',
WorkspaceFlavour.LOCAL
);

View File

@@ -4,22 +4,19 @@ import type {
WorkspaceNotFoundError,
} from '@affine/env/constant';
import { PageNotFoundError } from '@affine/env/constant';
import { rootWorkspacesMetadataAtom } from '@affine/workspace/atom';
import {
rootCurrentPageIdAtom,
rootCurrentWorkspaceIdAtom,
rootWorkspacesMetadataAtom,
} from '@affine/workspace/atom';
import { rootStore } from '@toeverything/plugin-infra/manager';
currentPageIdAtom,
currentWorkspaceIdAtom,
rootStore,
} from '@toeverything/plugin-infra/atom';
import { useAtomValue } from 'jotai/react';
import { Provider } from 'jotai/react';
import type { NextRouter } from 'next/router';
import type { ErrorInfo, ReactElement, ReactNode } from 'react';
import type React from 'react';
import { Component } from 'react';
export type AffineErrorBoundaryProps = React.PropsWithChildren<{
router: NextRouter;
}>;
import { useLocation, useParams } from 'react-router-dom';
export type AffineErrorBoundaryProps = React.PropsWithChildren;
type AffineError =
| QueryParamError
@@ -32,13 +29,13 @@ interface AffineErrorBoundaryState {
error: AffineError | null;
}
export const DumpInfo = (props: Pick<AffineErrorBoundaryProps, 'router'>) => {
const router = props.router;
export const DumpInfo = () => {
const location = useLocation();
const metadata = useAtomValue(rootWorkspacesMetadataAtom);
const currentWorkspaceId = useAtomValue(rootCurrentWorkspaceIdAtom);
const currentPageId = useAtomValue(rootCurrentPageIdAtom);
const path = router.asPath;
const query = router.query;
const currentWorkspaceId = useAtomValue(currentWorkspaceIdAtom);
const currentPageId = useAtomValue(currentPageIdAtom);
const path = location.pathname;
const query = useParams();
return (
<>
<div>
@@ -91,24 +88,6 @@ export class AffineErrorBoundary extends Component<
Cannot find page {error.pageId} in workspace{' '}
{error.workspace.id}
</span>
<button
onClick={() => {
this.props.router
.replace({
pathname: '/workspace/[workspaceId]/[pageId]',
query: {
workspaceId: error.workspace.id,
pageId: error.workspace.meta.pageMetas[0].id,
},
})
.finally(() => {
this.setState({ error: null });
});
}}
>
{' '}
refresh{' '}
</button>
</>
</>
);
@@ -124,7 +103,7 @@ export class AffineErrorBoundary extends Component<
<>
{errorDetail}
<Provider key="JotaiProvider" store={rootStore}>
<DumpInfo router={this.props.router} />
<DumpInfo />
</Provider>
</>
);

View File

@@ -79,7 +79,7 @@ const NameWorkspaceContent = ({
<div className={style.buttonGroup}>
<Button
data-testid="create-workspace-close-button"
type="light"
type="primary"
onClick={onClose}
>
{t.Cancel()}
@@ -155,7 +155,7 @@ const SetDBLocationContent = ({
<Button
disabled={opening}
data-testid="create-workspace-customize-button"
type="light"
type="primary"
onClick={handleSelectDBFileLocation}
>
{t['Customize']()}

View File

@@ -47,7 +47,7 @@ const LanguageMenuContent: FC<{
</>
);
};
export const LanguageMenu: FC<{ triggerProps: ButtonProps }> = ({
export const LanguageMenu: FC<{ triggerProps?: ButtonProps }> = ({
triggerProps,
}) => {
const i18n = useI18N();

View File

@@ -92,15 +92,15 @@ export const WorkspaceDeleteModal = ({
/>
</StyledInputContent>
<StyledButtonContent>
<Button shape="circle" onClick={onClose}>
<Button onClick={onClose} size="large">
{t['Cancel']()}
</Button>
<Button
data-testid="delete-workspace-confirm-button"
disabled={!allowDelete}
onClick={handleDelete}
type="danger"
shape="circle"
size="large"
type="error"
style={{ marginLeft: '24px' }}
>
{t['Delete']()}

View File

@@ -5,7 +5,7 @@ export const StyledModalWrapper = styled('div')(() => {
position: 'relative',
padding: '0px',
width: '560px',
background: 'var(--affine-white)',
background: 'var(--affine-background-overlay-panel-color)',
borderRadius: '12px',
// height: '312px',
};

Some files were not shown because too many files have changed in this diff Show More