Compare commits

..
636 Commits
Author SHA1 Message Date
Zack Fu Zi Xiang f78b5b4561 chore: update dep 2024-11-05 20:30:12 +08:00
Kilu.He f6e002edbd feat: support toggle heading (#6712)
* feat: support toggle heading

* fix: support others markdown
2024-11-05 14:06:38 +08:00
Lucas 82effbf8e4 fix: toggle heading issues (#6714)
* fix: pages overflow when selecting homepage

* fix: toggle heading issues

* Revert "fix: pages overflow when selecting homepage"

This reverts commit 156882a9a7.

* chore: optimize code logic

* fix: assertion in toggle list

* fix: make the turn into menu and color menu exclusive

* test: add toggle heading test
2024-11-05 10:52:22 +08:00
Lucas 54096b391f fix: settings site issues (#6701)
* fix: pages overflow when selecting homepage

* fix: settings site issues

* chore: try to fix windows ci

* test: add tests

* fix: shareblock state update

* fix: pages overflow when selecting homepage

* fix: view name doesn't update after publishing

* chore: add translations

* feat: close popup menu after unpublishing page

* feat: align the published page name with header
2024-11-05 09:23:38 +08:00
Mathias Mogensen 39eee12f53 fix: launch review 0.7.3 (#6718) 2024-11-05 00:39:00 +01:00
Mathias Mogensen bae19b9c3a feat: files media improvements (#6632)
* feat: files & media uiux improvements

* feat: desktop grid media cell changes

* test: amend tests

* feat: media mobile improvements

* feat: more refinement

* fix: dart linter

* chore: update collab

* fix: icon and test

* test: refactor upload hint

* test: forgot to use helper method
2024-11-05 00:13:19 +01:00
Richard Shiue f00e1ebf20 chore: remove focus when starting to create a card from the bottom (#6709) 2024-11-04 14:30:32 +08:00
Kilu.He 939e28d2e1 feat: support tab and shift+tab on range (#6703)
* feat: support tab and shift+tab on range

* feat: add login to no found page
2024-11-04 14:14:16 +08:00
Nathan.fooo 3fbdcab7b0 chore: try to fix when load data from cloud cause windows delay rendering (#6708) 2024-11-04 13:53:02 +08:00
Nathan.fooo a1d0dba0a5 chore: remove local ai watch on windows and linux (#6704)
* chore: remove local ai watch on windows and linux

* chore: clippy
2024-11-04 11:26:05 +08:00
Mathias Mogensen 5e41849f69 fix: remove listeners (#6686) 2024-11-04 10:26:48 +08:00
Richard Shiue cf56e20be9 chore: launch review 0.7.3 (#6698)
* refactor: date picker

* chore: provide guidance to users while using date picker

* fix: row card icon alignment

* fix: untitled database views

* chore: hide hint text while choosing date range

* test: fix widget test

* chore: use current time when toggling include time

* chore: move autofill date logic to date picker

* test: add tests

* chore: also apply to mention date block

* test: fix integration tests

* chore: fix a date picker edge case

* fix: unmatching border radii
2024-11-04 10:11:56 +08:00
Nathan.fooo 1b9b2a5f8d chore: fix database view event (#6697) 2024-11-01 21:48:25 +08:00
Nathan.fooo 690b46a59a chore: fix remove view desc test (#6696)
* chore: fix remove view desc test

* chore: fix remove view desc test

* chore: clippy
2024-11-01 15:57:58 +08:00
Richard Shiue 4d33c87b33 test: fix date picker tests (#6695) 2024-11-01 08:40:43 +01:00
Mathias Mogensen 7cf0c4b16b fix: do not rely on getIt in turnIntoBlock (#6693) 2024-11-01 08:04:02 +01:00
Lucas 910b643db0 chore: bump version 0.7.3 (#6692)
* chore: bump version 0.7.3

* fix: windows ci
2024-11-01 14:23:09 +08:00
Nathan.fooo 0e5ff844b6 chore: remove view desc (#6691)
* chore: remove desc in view

* chore: remove desc in view
2024-11-01 14:18:35 +08:00
Ahad PatelandLucas a9a784f0f0 fix: owner can delete spaces created by other users (#6672)
* fix: owner can delete spaces created by other users

* fix: Update frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/space/space_more_popup.dart

Co-authored-by: Lucas <lucas.xu@appflowy.io>

* fix: add import statement and remove conficting code

---------

Co-authored-by: Lucas <lucas.xu@appflowy.io>
2024-11-01 12:56:52 +08:00
Mathias Mogensen af390f584e feat: turn into page (sub page block) (#6685)
* feat: turn into page (sub page block)

* fix: bugs and node copyWith

* test: add base test
2024-11-01 05:14:51 +01:00
Lucas eff37d74dc fix: date reminder test (#6681) 2024-11-01 09:33:12 +08:00
Mathias Mogensen 0ea2da424f fix: reminder improvements (#6680) 2024-11-01 00:36:14 +01:00
Lucas 07e34609e7 feat: custom namespace/domain (#6614) 2024-10-31 14:38:32 +08:00
Lucas 74c757d0c8 feat: enable link to database in slash menu (#6673)
* feat: enable link to database in slash menu

* test: add link to page test

* test: remove improper test
2024-10-31 14:12:19 +08:00
Nathan.fooo e6357a9d6c chore: optimize import appflowy data (#6671)
* chore: only import user workspace

* chore: apply migration if need

* chore remove unused code

* chore: store first time installed version

* chore: clippy
2024-10-31 13:02:54 +08:00
Mathias Mogensen 5a047b9d2d fix: add referenced page hint (#6679) 2024-10-31 04:25:26 +01:00
Lucas 873ab6cdc7 feat: scroll to block after selecting notification item (#6667)
* fix: scrollbar's ScrollController has no ScrollPosition attached

* feat: support scrolling to block after selecting notification item

* chore: remove debug print

* fix: unable to cancel block selection
2024-10-31 10:29:34 +08:00
Mathias Mogensen af6736d352 fix: enable sub page block (#6595)
* fix: enable sub page block

* fix: open newly inserted page

* fix: created view should have empty name

* test: use secondary to rename page

* fix: make popover secondary interaction better

* test: amend test

* fix: icon color of sub page block

* test: fix tests

* test: fix hover issue

* feat: clean API for show at cursor on popover
2024-10-30 22:29:01 +01:00
Richard Shiue d5c1955ea3 chore: capitalization for field editor insert left/right (#6676) 2024-10-31 00:12:19 +08:00
Richard Shiue 8bb8131dd4 feat(flutter_desktop): press enter to confirm a dialog (#6675)
* feat: enter to confirm in popup dialog

* test: add test
2024-10-30 23:20:12 +08:00
Richard Shiue 7f4abb5866 chore(flutter_desktop): drop down menu conforms to design (#6674) 2024-10-30 23:19:05 +08:00
Richard Shiue fbe87cc536 fix(flutter_desktop): add forgotten call to update text cell (#6668) 2024-10-30 19:31:10 +08:00
Kilu.He 74165ace0f fix: optimize bundle (#6666)
* feat: open editing

* fix: use cdn to replace build react and react-dom

* fix: replace mention page icon

* fix: replace optimize web bundle
2024-10-30 14:13:52 +08:00
proxycon b576287ac6 chore: update translations with Fink 🐦 (#6656) 2024-10-30 09:29:05 +08:00
Richard Shiue 68d7211735 fix(flutter_desktop): glitchy kanban card editing (#6661)
* test: add test

* fix(flutter_desktop): editing kanban card is glitchy
2024-10-29 22:46:22 +08:00
Richard Shiue dd0dcace87 chore(flutter_desktop): set VisualDensity.standard for entire desktop app (#6648)
* chore: set standard visual density for entire app

* fix: pixel overflow

* fix: pixel overflow

* fix: pixel overflow

* fix: pixel overflow

* fix: text button padding

* chore: slash menu fixes

* chore: slash menu fixes

* ditto
2024-10-29 21:26:04 +08:00
Richard Shiue 8f58c39448 chore(flutter_desktop): improve title and heading appearance (#6658) 2024-10-29 21:25:13 +08:00
Nathan.fooo cee0e2ed42 test: fix ci (#6657) 2024-10-29 20:55:37 +08:00
Lucas 557ce7e006 chore: update appflowy_editor version (#6655)
* fix: foramt link starting at 0 index will lose href attr

* fix: pillcrow icon resize

* fix: integration test

* fix: emoji may not align on Linux
2024-10-29 19:39:56 +08:00
Nathan.fooo d50521d9b6 chore: ignore invalid database when import appflowy data (#6654) 2024-10-29 16:20:05 +08:00
Lucas 28aa2329fb feat: run integration tests on multiple runners (#6637)
* feat: split the integration tests into multiple runners

* feat: use 6 runners

* fix: name

* fix: integration tests

* fix: macos arm64 build

* Revert "fix: macos arm64 build"

This reverts commit 80b961361f.

* chore: use 7 runners

* chore: use 8 runners
2024-10-29 14:55:20 +08:00
Nathan.fooo 9707148b86 chore: bump appflowy collab (#6649)
* chore: fix test

* chore: fix duplicated view name

* chore: fix windows build

* chore: clippy
2024-10-29 11:21:49 +08:00
Lucas 4e739c857b fix: macos arm64 build (#6650) 2024-10-29 10:20:48 +08:00
Nathan.fooo 363fecc7d6 chore: bump client api that includes upload large zip file (#6634)
* chore: bump client api

* chore: update cloud version on CI

* chore: bump client api

* chore: update ci
2024-10-28 21:51:07 +08:00
Kilu.He 6bbaad59a4 fix: redirect to default page (#6638)
* feat: open editing

* fix: add logs

* fix: add logs
2024-10-28 17:55:11 +08:00
Kilu.He 497fcf3bbb fix: support redirect to default page (#6593) 2024-10-28 14:15:59 +08:00
Kilu.He b9ec9f863d fix: import interfaces and error message (#6630) 2024-10-28 11:34:56 +08:00
rensawamo eafd0b3353 fix: crash on delete button press caused by GoRouter (#6629)
* fix: crash on delete button press caused by GoRouter

* fix: gorouter pop
2024-10-28 09:09:11 +08:00
Nathan.fooo a42b6e02ab chore: revamp error for FolderCloudService service (#6623)
* chore: revamp error for FolderCloudService service

* chore: bump cloud

* ci: update configuration

* chore: clippy

* chore: bump client api
2024-10-26 11:20:16 +08:00
Mathias Mogensen 79116e7c7f fix: use drop path rather than node (#6611) 2024-10-25 14:05:19 +02:00
Richard Shiue 128ff594be fix: date picker code improvements and regressions (#6619)
* chore: improve handling result's error variant

* chore: dont call setState in didUpdateWidget

* fix: don't make assumptions on provided data
2024-10-24 20:46:45 +08:00
Lucas c821454df8 Revert "feat: custom domain (#6518)" (#6613)
This reverts commit 73e8b476fb.
2024-10-24 11:10:59 +08:00
ZackandLucas.Xu 73e8b476fb feat: custom domain (#6518)
* feat: api for namespace setting

* feat: add publish timestamp

* feat: update api

* chore: update proto

* feat: add link impl for appflowy cloud

* feat: impl set and get default view for workspace

* chore: merge with main and update to latest cloud client api

* fix: ci build

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-10-23 19:41:46 +08:00
Lucas faa95ffb9c feat: support toggle heading (#6598)
* feat: support toggle heading

* feat: add numbered list shortcut and heading shortcut

* feat: update format greater to toggle list shortcut

* feat: add removeToggleHeadingStyle shortcut

* feat: add toggle list and toggle headings in turn into menu

* feat: turn into toggle heading block

* feat: highlight selected toggle heading

* fix: collapsed button animation

* test: turn heading block to toggle heading block

* test: turn toggle heading block to heading block

* test: convert '# + >' or '> + #' to toggle heading block

* test: turn heading 2 block with following heading 1 block to toggle heading 2 block

* test: integration tests

* fix: unable to move children after heading 1 to toggle heading block

* test: unable to move children after heading 1 to toggle heading block

* fix: flutter analyze

* fix: toggle heading block test: insert toggle heading 1 - 3 block by shortcuts

* fix: inline database in document tests

* fix: integration test
2024-10-23 19:41:12 +08:00
Richard Shiue 6a5c4c95b7 feat(flutter): date picker improvements (#6582)
* feat(flutter): improve date picker

* test: add widget tests

* test: add bloc test

* test: adjust rust-lib tests

* fix: fix failing tests

* chore: fix rustfmt

* test: remove redundant await

* fix: fix failing tests

* feat: use cupertino date picker on mobile

* fix: flutter analyzer
2024-10-23 08:51:37 +08:00
Richard Shiue 7141e9d8cf fix(flutter-moile): edit primary field from database controls (#6591) 2024-10-22 20:22:15 +08:00
Richard Shiue d7bbb4261c chore: remove legacy CreateRowParams (#6592) 2024-10-22 20:22:03 +08:00
Lucas 251b16cb62 chore: update changelog (#6596) 2024-10-22 10:22:25 +08:00
Mathias Mogensen da80c599bf fix: show default view name (#6571) 2024-10-22 09:31:14 +08:00
Lucas ca6a900874 fix: display paragraph mark only if the block content is empty (#6594) 2024-10-21 20:25:55 +08:00
Lucas 5e09e96f7b fix: callout emoji size should follow the document font size (#6590) 2024-10-21 18:00:32 +08:00
Mathias MogensenandLucas.Xu 068500df84 feat: inline sub page mention (#6567)
* feat: inline sub page mention

* fix: disable editing documents in trash

* fix: duplicate block behavior

* refactor: clean up code

* feat: use formatText function instead of modify delta manually

* fix: paste behavior format mention

* fix: default icon for mentioned pages

* fix: view new parent turn into page reference

* test: add base test

* chore: add feature flag

* chore: default flag to on

* fix: minor fixes to behavior

* fix: review and code cleanup

* fix: dart linter

* fix: content is required

* test: use doc title to rename page

* test: add test coverage

* test: fix wrong expect

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-10-21 16:34:30 +08:00
Murat Sarıbaş 15949a7e21 chore: update translations with Fink 🐦 (#6565) 2024-10-21 09:45:52 +08:00
Mathias Mogensen e635fe3378 fix: trash breadcrumb line height (#6588) 2024-10-21 09:42:48 +08:00
Mathias Mogensen 8276c5db57 fix: drag and drop row document full page (#6589) 2024-10-21 09:42:15 +08:00
Mathias Mogensen 1d9876a6eb fix: notifier disposed but in use (#6586) 2024-10-21 00:21:25 +02:00
Lucas 6340174927 fix: share link and publish issues on mobile (#6579)
* fix: cache publish info to avoid repeated requests

* chore: 'Copy Link' to 'Copy link'

* chore: enable ios ci

* fix: ios ci

* chore: replace mention block icon

* fix: ios ci tests

* fix: ios ci tests

* fix: ai wirte replace assertion

* fix: windows ci
2024-10-20 10:13:06 +08:00
Lucas 7b031b228e fix: turn into issues (#6576)
* fix: cover title issues

* fix: the selection should be cleared if selecting child node

* fix: exclude the blocks that are not supported in the 'turn into' types

* fix: add logs

* fix: floating toolbar ai status

* test: selecting the parent should deselect all the child nodes as well

* chore: 'Copy Link' to 'Copy link'

* fix: select all and turn into block doesn't work on Windows

* test: calculate turn into selection test

* fix: option button tests
2024-10-18 17:13:38 +08:00
Richard Shiue ec408940e4 fix(flutter_desktop): bring back the board scrollbar (#6580) 2024-10-18 15:52:32 +08:00
Richard Shiue bd46fc11f4 fix(flutter-desktop): launch review issues for 0.7.2 (#6577)
* test: add test case for calendar filter

* fix: select option filter logic

* fix: calendar filters not applying if switched repeatedly

* fix: checklist cell editor improvements

* fix: nested scrolling in checklist

* fix: make filter logic match notion

* test: fix checklist cell test

* test: single select filter tests

* test: fix flutter test

* test: fix rust tests

* chore: fix clippy
2024-10-18 13:48:50 +08:00
nathan 42e55fe248 chore: update import string 2024-10-17 16:03:22 +08:00
nathan 3a9011b3cb chore: remove timezone for self-hosted runner 2024-10-17 15:42:01 +08:00
Lucas e3bf0442e8 fix: space icon color assertion (#6570)
* fix: space icon color assertion

* chore: bump version 0.7.2
2024-10-17 13:43:14 +08:00
Lucas 0413100e2b feat: observe mention block change and support block navigation (#6568)
* feat: observe mentioned block changes and navigate to block

* test: add delete mentioned block test

* chore: update editor version

* feat: navigate block in same page

* fix: sometimes turn into menu doesn't work

* test: add test

* fix: integration test
2024-10-17 13:29:34 +08:00
nathan 7cad04bbf4 chore: bump collab which include fixing windows build 2024-10-17 13:27:05 +08:00
Mathias Mogensen c9f0bbf26a feat: right click to open view more actions (#6529)
* feat: right click to open view more actions

* test: fix tests

* test: fix failing test

* fix: hide in move to page menu

* test: add simple test

* test: add negative case in cloud test

* chore: check code related to sidebar spaces

* fix: view item

* fix: clean up
2024-10-17 06:58:01 +02:00
Nathan.fooo d91639172a chore: show import error (#6569) 2024-10-17 10:32:51 +08:00
Nathan.fooo 5f0cc1becd chore: bump client api and collab (#6563)
* chore: bump client api and collab

* chore: fix windows build
2024-10-17 09:45:45 +08:00
Lucas a8bcab7770 feat: turn into multiple lines (#6558)
* feat: select multiple lines with block selection style

* feat: multiple nodes conversion

* fix: exclude children for the block can't contain children

* chore: update editor version

* fix: unit test

* test: convert nested list to heading/quote/callout

* test: transform nodes at the same level into another block type

* test: add undo redo for turn into

* test: add multi lines integration test

* chore: remove debug logs

* fix: integration test
2024-10-16 22:19:18 +08:00
Kilu.He b1682e4f54 fix: modified import function (#6562) 2024-10-16 21:40:32 +08:00
Richard Shiue 2447b34107 fix: text button's text style (#6559) 2024-10-16 17:06:14 +08:00
Richard Shiue 8126d19682 fix(flutter): wrong time zone when filtering by date field (#6543)
* fix: wrong time zone when filtering by date field

* test: set time zone
2024-10-16 16:44:06 +08:00
Richard Shiue 6cc8c81e3d chore: adjust Toggle widget's onChanged callback (#6556) 2024-10-16 14:39:46 +08:00
Nathan.fooo e86d812ee6 chore: add tooltip when import notion file (#6557) 2024-10-16 13:55:21 +08:00
Nathan.fooo c6f042830f fix: import document that contains refs (#6551)
* fix: import document that contains refs

* chore: clippy
2024-10-15 23:55:27 +08:00
Nathan.fooo 2378c0c441 chore: add calculation rust test (#6547)
* chore: add test

* chore: clippy
2024-10-15 17:20:53 +08:00
Lucas 7bc53d7bc6 feat: support 'share link' and 'publish' on mobile (#6548)
* feat: support publish on mobile

* chore: replace icons

* feat: support publish and copy link on mobile

* feat: support copy link

* feat: support copy share link

* chore: update icons

* fix: flutter analyze

* fix: ignore opening same page on mobile

* test: add copy link test on mobile
2024-10-15 15:12:59 +08:00
Nathan.fooo 7918d6c0d1 chore: update logs (#6550) 2024-10-15 15:05:22 +08:00
Kilu.He 073e8b897b feat: support import notion (#6549)
* feat: support import notion

* feat: support import page
2024-10-15 11:49:38 +08:00
Nathan.fooo 46a3006f4d refactor: database test (#6544)
* chore: remove script

* chore: remove script

* chore: refactor test

* chore: clippy

* chore: fix test

* chore: fix test

* chore: fmt
2024-10-15 09:32:06 +08:00
Deep Isane 5d578ab9e6 chore: update README.md fixed a typo (#6546)
Corrected "Acknowledgements" to "Acknowledgments" in [README.md].

This pull request addresses a minor typo found in the repository. The typo has been corrected to improve clarity and maintain the quality of the documentation.

This change is purely cosmetic and does not affect functionality.
2024-10-14 22:11:34 +02:00
Lucas f3fe729900 fix: potentially missing field in todo list (#6540)
* fix: potentially missing field in todo list

* chore: upgrade appflowy_editor_plugins

* fix: potentially missing field in todo list
2024-10-14 20:54:13 +08:00
Ahad PatelandLucas.Xu a04c157770 fix: date issue when enbling time feild (#6447)
* fix: date issue when enbling time field

* chore: add integration test for date or reminder field

* chore: add test file to document_test_runner.dart

* fix: flutter analyze

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-10-14 20:54:03 +08:00
Nathan.fooo 320ffcb434 Import notion zip (#6528)
* chore: upgrade client api

* chore: import notion zip

* chore: bump client api

* chore: bump collab

* chore: upgrade cloud version

* chore: fix test

* chore: fix test
2024-10-14 20:38:04 +08:00
Lucas 37a2fb17b5 feat: copy link to block (#6523)
* feat: copy link to block

* chore: add comment

* feat: using mention bloc to manage the mention bloc status

* feat: use mention page bloc to manage mentioned page status

* feat: observe mention block content changes

* feat: sync the block content

* fix: integration test

* fix: mentioned block display name contains unnessary -

* fix: handle block was deleted case

* chore: move the get doc block and get mentioned page status to service

* feat: support copy link to page

* test: add copy link to block tests

* test: add copy link to block(same pge) tests

* test: open the mentioned page

* fix: integration test

* Revert "fix: integration test"

This reverts commit f4466b22d8.

* fix: integration test
2024-10-14 14:04:42 +08:00
Kilu.He b5936cec54 fix: supported incremental updates (#6531) 2024-10-11 11:29:29 +08:00
Richard Shiue ea61c81cce feat(flutter_desktop): open created filtered rows (#6522)
* fix: revert previous implementation

* feat: open created but hidden rows as page

* fix: cargo clippy

* test: add integration tests

* fix: typo

* fix: flutter analyzer

* chore: clean up code

* chore: code cleanup

* chore: code cleanup
2024-10-11 11:04:03 +08:00
Kilu.He 64d71d0d20 fix: add sync manager (#6517)
* fix: add sync manager

* fix: add toolbar actions

* fix: add import entry

* fix: modified approve page
2024-10-10 19:48:30 +08:00
Mathias Mogensen af08b4c004 fix: hide breadcrumbs for deleted pages and show trash (#6512)
* fix: hide breadcrumbs for deleted pages and show trash

* fix: copy for banner and trash deletion

* test: add base test

* test: expand on test

* test: fix test

* test: fix failing test
2024-10-10 11:57:42 +02:00
ea670b6ae6 fix: grid new row getting cut (#6475)
* fix: Grid new row getting cut

* chore: add test case for testing text in veiwport

* refac: clean up code

---------

Co-authored-by: Mathias Mogensen <mathiasrieckm@gmail.com>
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-10-10 11:02:05 +02:00
Lucas f19e354418 feat: support 'turn into' in doc (#6516)
* feat: customize animation for popover

* chore: code refactor

* feat: using popover direction calculate the popover animation translate direction

* feat: integrate the animated popover in appflowy_popover and popover_action

* fix: close popover assertion

* chore: format code

* chore: code refactor

* feat: optimize the popover listener

* feat: clear popover when hot-reloading

* chore: refactor code

* feat: integrate animated popover in block action button

* fix: integration test

* feat: add turn into entry

* fix: popover asBarrier issue

* feat: move biz logic from widget to cubit

* feat: add turn into menu

* chore: remove unused code

* feat: support h1-h3

* feat: add block conversions

* fix: integration test

* feat: implement block conversions

* fix: outline test

* test: add turn into tests

* test: add turn into nested list test

* test: add turn into nested list test

* fix: flutter analyze

* chore: replace turninto icon

* feat: integrate animated popover in color option button

* chore: split the block option action into separate files

* test: add integration test

* fix: outline block test

* fix: integration test

* fix: shortcut test
2024-10-10 14:40:38 +08:00
Richard Shiue b54e3dd243 feat: checklist cell improvements (#6515)
* feat: reorder checklist tasks

* feat: quickly create checklist tasks

* feat: reorder checklist on mobile

* test: add integration test

* test: add bloc test

* fix: flutter analyzer

* fix: cargo clippy
2024-10-10 11:38:17 +08:00
Richard Shiue 9798e39e49 feat: calendar filters (#6519)
* feat: calendar filters

* test: add integration tests
2024-10-10 11:00:23 +08:00
Richard Shiue 66fd0c19da test: fix flaky sort editor bloc test (#6520) 2024-10-10 11:00:09 +08:00
Mathias Mogensen 8d6c67206c feat: enable drag and drop in row document (#6513)
* feat: enable drag and drop in row document

* refactor: cleanup drop handling to one widget

* fix: clean up code
2024-10-09 15:23:42 +02:00
Lucas 8cf683eb50 feat: customize animation for popover (#6507)
* feat: customize animation for popover

* chore: code refactor

* feat: using popover direction calculate the popover animation translate direction

* feat: integrate the animated popover in appflowy_popover and popover_action

* fix: close popover assertion

* chore: format code

* chore: code refactor

* feat: optimize the popover listener

* feat: clear popover when hot-reloading

* chore: refactor code

* fix: integration test

* fix: icon test
2024-10-09 15:10:05 +08:00
Kilu.He 580a23f3f5 feat: support pasted on web (#6510)
* fix: add some test cases

* fix: with pasted plugin
2024-10-09 11:50:33 +08:00
Richard Shiue 29dc46a993 fix: dont edit every view while handling database view row change (#6506)
* fix: don't process on every view while only handling one view

* test: add test
2024-10-09 11:01:09 +08:00
Richard Shiue 93885bad7b fix: get all calendar events not fetching empty ones (#6508) 2024-10-09 11:00:33 +08:00
Richard Shiue 6e0619c21e chore: bump validator crate version (#6494) 2024-10-08 21:38:58 +08:00
Lucas 8c956afabd fix: show AI limit error toast if exceeding the AI response (#6505)
* fix: show AI limit error toast if exceeding the AI response

* test: add ai limit test
2024-10-08 18:28:07 +08:00
Richard Shiue f9fbf62283 test: fix flaky sort editor bloc test (#6504)
* test: fix flaky sort test

* test: experiment

* test: remove loops
2024-10-08 16:33:48 +08:00
Lucas 5f1f536181 feat: support editing name when creating a new page on mobile (#6501)
* feat: support editing name when creating a new page on mobile

* chore: add defaultName in layout extension

* test: add cover title test on mobile

* fix: cover title test on mobile

* feat: add integration runner 4

* chore: update translations

* chore: disable subpage feature
2024-10-08 14:29:07 +08:00
Lucas ba59514464 fix: ignore same workspace icon update (#6496)
* fix: ignore same workspace icon update

* feat: pressing esc to exit editing mode in cover title

* fix: integration test

* fix: unable to use redo/undo in cover title

* chore: update collab version b56d051

* feat: show add emoji & add cover button when hovering on the title

* test: add hover on title test

* fix: unable to use arrow right in cover title

* fix: unable to select title sometimes

* fix: integration test

* fix: cloud integration test

* fix: cloud integration test

* fix: integration test
2024-10-08 11:46:15 +08:00
Annie 6bb6750be7 chore: update CHANGELOG.md (#6502)
change log for v0.7.1
2024-10-08 09:22:34 +08:00
Kilu.He 19a3df6d47 feat: support shortcuts on web (#6474)
* fix: add tab and shift+tab test cases on web

* fix: support BIUS on web

* fix: add BIUS test cases

* fix: add markdown to block test cases

* fix: add markdown to block test cases
2024-10-07 18:30:39 +08:00
Mathias Mogensen 87408fd2a9 fix: sub page block review fixes (#6491)
* fix: sub page block review fixes

* test: fix tests
2024-10-07 12:08:44 +02:00
Richard Shiue 9ee39f45c9 test: rewrite bloc tests (#6492) 2024-10-07 16:41:20 +08:00
Lucas a763304386 fix: fix potential text empty when editing doc (#6495) 2024-10-07 16:40:36 +08:00
Nathan.fooo f8ce501b53 chore: fix anon user integration test (#6493)
* chore: fix anon user integration test

* chore: fix env

* chore: appflowy cloud version

* chore: appflowy cloud version
2024-10-07 13:31:47 +08:00
nathan 54d449647c fix: clippy and test 2024-10-07 11:20:59 +08:00
Lucas 552fd39d74 fix: share button doesn't response under macOS 15 (#6487)
* fix: share button doesn't response under macos 15

* chore: enable macos integration test

* Revert "chore: enable macos integration test"

This reverts commit 32c49c9f36.

* chore: update comment
2024-10-07 10:18:11 +08:00
nathan 01d73f2753 chore: clippy 2024-10-07 09:44:00 +08:00
Nathan.fooo 75da496128 fix: calculation bug (#6489)
* chore: upgrade collab

* fix: calculate value

* chore: optimize calculate

* chore: cal when open database

* chore: update calculation when filter change

* chore: use same runtime
2024-10-07 08:57:42 +08:00
Nathan.fooo fd9b01ca27 fix: import data (#6483)
* chore: import into space

* chore: par insert

* fix: migrate from anon

* chore: fix test

* chore: update test

* chore: add test

* chore: update test

* chore: update test

* chore: update docs

* fix: space collab

* chore: update test
2024-10-06 20:08:17 +08:00
Lucas 1a82f3fff1 fix: title flash when resizing (#6481) 2024-10-05 21:11:45 +08:00
Richard Shiue 8e6f051dec fix: launch review issues (#6479)
* fix(flutter_desktop): field icon picker popover constraints

* fix(mobile): immediately select field when editing filter

* fix: filter through select options not working

* fix(mobile): scroll to bottom after filter creation

* fix: primary field tooltip
2024-10-05 10:57:52 +08:00
Lucas 8ceff03f3e feat: add more bottom padding in workspace menu (#6469)
* chore: add more bottom padding in create workspace menu on mobile

* feat: add more bottom padding in workspace menu

* feat: enable scrollable in workspace menu on desktop

* feat: enable to customize filiter rules

* fix: workspace menu icon dark mode issue

* Revert "feat: enable to customize filiter rules"

This reverts commit 3e6d522112.
2024-10-04 15:50:36 +08:00
Lucas e1bbcc415f chore: disable copy link to block feature (#6472) 2024-10-04 14:57:46 +08:00
Kilu.He 567ba7d962 fix: not found page issues (#6471) 2024-10-04 14:00:51 +08:00
Lucas 153416604d fix: ingore keyup event in cover title (#6468)
* fix: ingore keyup event in cover title

* feat: add text field with line metric

* chore: refactor test strcuture

* test: add arrow down key test
2024-10-04 14:00:10 +08:00
Kilu.He caa882dc37 fix: add some placeholder for deleted and not found (#6470) 2024-10-04 13:52:01 +08:00
Kilu.He 9c05788834 fix: share link issues (#6465) 2024-10-04 12:51:17 +08:00
Mathias Mogensen 6b585ef9a7 fix: do not bring back purposeful null selection (#6464)
* fix: do not bring back purposeful null selection

* test: add more tests

* fix: redundant import
2024-10-03 23:05:30 +02:00
Nathan.fooo 469ddacfcc chore: bump collab (#6450)
* chore: upgrade collab

* chore: bump client api
2024-10-03 23:45:29 +08:00
Kilu.He 4d4e3bfb8a fix: add backspace behavior test cases (#6463) 2024-10-03 22:37:40 +08:00
Richard Shiue 257a7530a0 chore: bump version 0.7.1 (#6460) 2024-10-03 14:41:31 +08:00
Lucas 02126a1e24 chore: update client api (#6459) 2024-10-03 14:31:19 +08:00
Lucas 97913c390b feat: support share page and block (#6431)
* feat: support share page

* feat: support copy share link

* chore: replace share icon

* chore: update translations

* chore: optimize code

* test: add share link test

* feat: support copy block link

* test: add copy link to block test

* chore: refactor share code

* fix: doc bloc not found issue
2024-10-03 14:31:04 +08:00
Kilu.He c1cf58b99e feat: support withYHistory and editing document on web (#6438)
* feat: support withYHistory

* fix: inline elements

* fix: insert break in single line

* fix: add enter key behavior tests

* fix: add test cases

* fix: add test cases
2024-10-03 13:54:42 +08:00
Lucas 574b0ce84b fix: windows CI failed (#6457)
* chore: update flutter & rust version

* chore: try to fix windows ci

* chore: downgrade windows version to 2019
2024-10-03 13:28:02 +08:00
Mathias Mogensen 26ac896bac test: amend tests after automatic merge (#6458) 2024-10-03 05:48:32 +02:00
Mathias Mogensen b36babf754 feat: resume selection on window focus (#6455) 2024-10-03 05:44:44 +02:00
Mathias Mogensen 0d69b895aa feat: sub page block (#6427)
* feat: base subpage block and behavior

* fix: do not record undo

* refactor: add BlockTransactionHandler

* test: start adding coverage

* test: delete w/ backspace

* test: add to runner

* fix: rebuild issue on create

* test: copy+paste base test

* fix: conflict behavior and test coverage

* fix: after merge

* test: add wait duration

* test: more tests

* fix: cut behavior + tests

* fix: refactor copy+paste and more test cov

* fix: localization + test coverage + cleanup

* test: add drag subpageblock node test

* test: remove backspace test
2024-10-03 04:58:08 +02:00
Mathias Mogensen 3b48ca0f4b fix: new dialog style in trash actions (#6456)
* fix: new dialog style in trash actions

* fix: restore dialog
2024-10-03 04:38:50 +02:00
ja49619 2e6ce16b11 chore: update ru-RU translations 🐦 (#6384) 2024-10-03 10:19:02 +08:00
Richard Shiue edeec49121 fix: hide editing rows from groups when filters are applied (#6409)
* fix: editing a row while in active filters

* fix: dont allow filtering by group field
2024-10-03 10:17:51 +08:00
Lucas 5de716b19d feat: update workspace icon style on desktop (#6452)
* feat: update workspace icon style on desktop

* fix: unable to insert two referenced link at the same doc
2024-10-03 09:39:52 +08:00
Mathias Mogensen cb2b933a90 feat: show file popover automatically (#6453) 2024-10-03 03:25:09 +02:00
Mathias Mogensen 37f99988eb fix: hide border on icon in callout (#6454) 2024-10-03 03:12:33 +02:00
Richard Shiue 99962dc3c6 fix: field type option transform (#6451)
* test: add field transform tests

* fix: type option transform messing up type option data

* test: add date time transform integration test

* fix: update view editor
2024-10-03 08:11:11 +08:00
DongHyeon 063d54dfae chore(i18n): update ko-KR translations (#6378)
* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦
2024-10-02 20:54:22 +08:00
Sean SidersandLucas.Xu 59f79be290 feat(flutter_desktop): clickable url links in row detail (#5916)
* feat: Url row detail openable via `ctrl | meta + click`

* feat: Optimize `LinkTextField` state management

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-10-02 20:52:52 +08:00
Lucas 813c8e6b86 feat: support workspace ops on mobile (#6449)
* feat: support workspace ops on mobile

* chore: move the member bloc to workspace menu item widget

* feat: support creating workspace on mobile

* chore: add popToHome extension

* fix: flutter analyze

* feat: support renaming a workspace

* feat: support deleting a workspace

* feat: support leaving a workspace

* feat: workspace icon ui revamp

* feat: support updating workspace icon on mobile

* feat: show a confirm dialog before deleting a workspace

* fix: workspace name overflow

* feat: support leaving a workspace

* chore: update translations

* feat: show a toast after renaming workspace

* feat: update translations

* feat: add workspace operation integration tests on mobile

* test: add create workspace test on mobile
2024-10-02 20:13:19 +08:00
Richard Shiue 23e3650570 test(flutter_desktop): add edit row test (#6442) 2024-10-02 09:17:28 +08:00
Richard Shiue 092aefdd71 fix(flutter_desktop): fix calendar event bugs (#6446)
* fix: row controller being disposed too early in calendar

* fix: empty accessories in calendar event card
2024-10-02 09:17:02 +08:00
Lucas 19361e2c68 feat: optimize selection gesture in editor (#6445) 2024-10-01 20:14:53 +08:00
Lucas 6e48f02d25 fix: insert the pasted nodes after current selection if they start with a non-delta node (#6441)
* fix: pasting in-app json on a line with text can cause corrupt blocks

* chore: update editor

* fix: paste multiple nodes test
2024-10-01 17:58:10 +08:00
Lucas 46e45c3715 feat: keep link format when converting preview block to text (#6435)
* feat: keep link format when converting preview block to text

* test: add test

* fix: flutter analyze

* feat: ctrl/cmd+z to revert the link prevew op

* test: add test

* chore: update toast style
2024-10-01 12:53:44 +08:00
Lucas eca495ce63 fix: double cursor show in title and doc sometimes (#6437) 2024-10-01 11:57:51 +08:00
Richard Shiue 70e72d843e feat: custom database field icons (#6415) 2024-09-30 22:14:15 +08:00
Richard Shiue 7ac3b72a4f feat(flutter_desktop): use regular rather than medium font weight by default (#6432)
* feat(flutter_desktop): use regular rather than medium by default

* fix: setting button regression

* fix: bring more text styles up to date with design
2024-09-30 21:37:11 +08:00
Mathias Mogensen cc9072e9cc chore: remove supabase dependency (#6396) 2024-09-30 12:17:23 +02:00
Lucas a0ee47b809 feat: support copy/cut command when the selection is collapsed (#6429)
* feat: add delete line command

* test: add delete line test

* test: add delete line command test

* feat: support copy command when selection is collasped
2024-09-30 16:34:41 +08:00
Richard Shiue af40ff8eb1 chore: grid ui improvements (#6428)
* fix: dont use medium font weight

* fix: widget padding adjustments

* fix: new divider color

* chore: use horizontal padding from databsepluginwidgetbuildersize

* chore: use existing color token

* chore: restore old add icon
2024-09-30 16:09:57 +08:00
Richard Shiue b0211be03c fix(flutter_desktop): field info not updating in sort info (#6430) 2024-09-30 16:08:49 +08:00
Kilu.He 3174ffed5c fix: support approve (#6413) 2024-09-30 13:41:47 +08:00
Richard Shiue 99c7252a15 fix(flutter_desktop): board card rebuild issue (#6424) 2024-09-29 11:34:45 +08:00
Lucas 99c81fed56 fix: paste doesn't work sometimes in the first try (#6412)
* fix: paste doesn't work sometimes in the first try

* test: paste the url that doesn't contain a protocol

* feat: skip parsing as a preview block if the url is image
2024-09-27 17:45:49 +08:00
Lucas a01fc5b572 feat: support window tiling on macos (#6410) 2024-09-27 15:22:18 +08:00
Lucas 1b0bb1d5ff fix: backtick issue in French IME (#6408)
* fix: backtick doesn't format the text to code in french ime

* test: add backtick test

* fix: three backticks doesn't convert to code block in french ime

* chore: remove cache for docker ci
2024-09-26 20:16:49 +08:00
Lucas 1ffd653515 fix: grid cell date time test (#6406)
* fix: grid cell date time test

* chore: delete test
2024-09-26 20:16:33 +08:00
Richard Shiue e1c60084d3 feat: allow filtering by last modified and created at field types (#6407)
* feat: last modified and created on filters

* chore: improve select option filter

* test: add test
2024-09-26 18:57:15 +08:00
LucasandMathias Mogensen 4c6b6ffdac feat: support cover title (#6353)
* feat: support cover title

* feat: support arrow down and arrow right key on cover title

* feat: support arrow up and arrow left key on editor

* test: add integration test

* chore: update frontend/appflowy_flutter/integration_test/desktop/document/document_title_test.dart

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>

* feat: use shared document context to save title focus node

* fix: the backspace key doesn't work after pressing Enter in the title

* feat: support pressing arrow left key to focus on title

* fix: integration test

* test: edit title and insert new line

* test: arrow key in title test

* test: check if the title is saved

* fix: flutter analyze

* test: add cover title command tests

* fix: integration tests

* test: change the title via sidebar, check the title is updated

* test: set default name when pasting content

* fix: field visibility test

* fix: 'create a new workspace, open it and then delete it' test

* fix: create a new document and move it to Getting started test

* test: fix integration tests

* fix: 'create a new document and edit title' failed on linux

* fix: shortcut and create a new page test

---------

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
2024-09-25 22:44:59 +08:00
Richard Shiue 783d458100 feat(mobile): database filters (#6401) 2024-09-25 22:22:36 +08:00
Richard Shiue 9b7d38bca7 feat(flutter_desktop): allow filtering by date end (#6399) 2024-09-25 15:28:47 +08:00
Lucas a8a8502577 chore: install deps using pacman (#6397)
* chore: install deps using pacman

* chore: use rust 1.80.1

* chore: add docker ci

* fix: docker ci

* chore: optimize docker-ci speed
2024-09-25 15:25:44 +08:00
Nathan.fooo 6a1619d300 chore: detect field type when import csv (#6400) 2024-09-25 15:09:00 +08:00
Richard Shiue 9b811f0166 refactor(flutter_desktop): filter blocs (#6356)
* refactor: database filter bloc

* refactor: filter choice chips

* fix: update field info in filters

* refactor: simplify select option filter panel

* test: fix tests

* refactor: filter choice chips

* test: add bloc tests

* refactor: date time filter bloc and choice chip
2024-09-25 12:04:00 +08:00
Nathan.fooo 7e1b77f872 chore: Migrate type option (#6395)
* chore: migrate number type option

* chore: migrate single select

* chore: migrate multi select

* chore: migrate date type option

* chore: migrate timestamp type option

* chore: support friendly full

* chore: migrate media type option

* chore: update collab

* chore: update zip

* chore: remove file

* chore: fix build

* chore: fix test
2024-09-25 11:44:19 +08:00
Mohammad Zolfaghari b7c598ea56 feat(flutter_desktop): date filter (#6288)
* feat: wip enabling date filter

* fix: update date picker selected range on change

* fix: save in utc, load in local date time

* test: added date filter test

* fix: don't include time in date picker

including time makes filtering complex without much gain.
when the condition is "is" we should also note the exact time
which most of the cases the time is not intended by user only the day.

* fix: flutter analyze
2024-09-24 22:03:07 +08:00
Richard Shiue da7c993fd6 chore(flutter_desktop): enable selecting icons without backgrounds (#6379)
* chore: enable selecting icons without backgrounds

* chore: remove debugprint

* chore: rename flag
2024-09-24 22:01:21 +08:00
Richard Shiue c6dd5db6da fix: edge case for text filters (#6387) 2024-09-24 22:01:05 +08:00
Mathias Mogensen e125e9493a fix: offset row actions by cover height (#6390) 2024-09-24 14:33:23 +02:00
Lucas 5fbd07e96a fix: potential ai_repository not init (#6388)
* fix: potential ai_repository not init

* fix: assertion when deleting block

* chore: remove the rule

* test: add smart edit bloc test

* test: add delete block test

* chore: remove unused_import

* fix: paste image integration test
2024-09-24 20:24:28 +08:00
Mathias Mogensen 0a6bee6232 fix: hover bug in row banner (#6389) 2024-09-24 13:57:26 +02:00
Mathias Mogensen 552f2a73de fix: row cover improvements (#6381)
* fix: row cover improvements

* feat: set image from media cell as cover

* fix: duplicate row meta when duplicating row

* fix: use serialize repr and deserialize repr

* chore: update collab revision

* fix: failing test and bug w/ document icon

* fix: show empty cover on load failure

* fix: tauri collab revision
2024-09-23 16:28:47 +02:00
Richard Shiue eeb6b69f58 fix: semi-transparent colors being forced to full opacity in FlowySvg (#6376)
* fix: semi-transparent colors being forced to full opacity

* chore: code style

* chore: update comment
2024-09-23 20:44:23 +08:00
Richard Shiue 99889b9950 fix(flutter_desktop): select option kanban groups not updating #6369 2024-09-23 20:44:10 +08:00
Lucas c51b495544 feat: support appflowy cloud in sign-in settings page (#6386)
* feat: support appflowy cloud in sign-in settings page

* test: add cloud server test

* test: wait until the tooltip disappear
2024-09-23 20:19:29 +08:00
Lucas 0d2841227a feat: add numpadSubtract as zoom out keycode (#6380)
* feat: add numpadSubtract as zoom out keycode

* test: add zoom in/out and reset zoom refacotr test

* fix: zoom in test assertion

* fix: zoom in/out test

* test: exclude LogicalKeyboardKey.add & LogicalKeyboardKey.numpadSubtract in linux test
2024-09-23 12:25:45 +08:00
Lucas 2dc7dc1a26 fix: sidebar move page test (#6377) 2024-09-22 14:13:44 +08:00
Lucas f0a494b41d fix: 0.7.0 launch review issues (#6365)
* fix: cannot use 'move to' from sidebar

* feat: disable moving the page to a database

* fix: check if the move to path is same as current path

* fix: document width doesn't refresh after resetting

* fix: disable tooltip when dragging blocks

* fix: reminder not render when dragging

* chore: optimize code

* fix: after changing the language in the settings page, some of the text doesn't change

* feat: support moving a block to another block's child

* fix: tooltip assertion

* fix: disable table cell block

* chore: optimize moving logic

* test: collaborative workspace test

* test: move to page test

* test: drag block test

* test: check if the tooltip is hidden when dragging block

* test: move a block to another block's child

* test: change document width test
2024-09-22 09:35:11 +08:00
Richard Shiue 806fc75a8a fix: launch review issues 0.7.0 (#6367)
* fix: leave away the property edit action -> the menu doesnt close

* fix: tooltip showing when hovering over empty space

* fix: text not centered

* fix: board card sizing issue
2024-09-22 09:34:21 +08:00
Nathan.fooo d3362bf96a chore: fix anon test (#6375)
* chore: fix anon test

* chore: fix test
2024-09-21 16:04:18 +08:00
Mathias Mogensen 7bef698f03 fix: hide line numbers in code block (#6352) 2024-09-21 16:00:23 +08:00
Kilu.He bea4b60a7a fix: fix jump error issue (#6374) 2024-09-21 15:08:02 +08:00
Kilu.He 1100c8b7e1 fix: modified row page cover (#6373) 2024-09-21 14:47:33 +08:00
Kilu.He 728c75ff87 fix: adjust row page skeleton (#6372) 2024-09-21 14:42:45 +08:00
Kilu.He e01a59c772 fix: adjust editor's margin bottom (#6371) 2024-09-21 14:39:58 +08:00
Kilu.He 164933325c fix: adjust margin bottom (#6370) 2024-09-21 14:31:10 +08:00
Kilu.He 88df232139 feat: support app router (#6366)
* fix: modified the folder name

* feat: open document and database

* feat: support editing

* fix: lint

* fix: add share actions

* fix: support interfaces
2024-09-21 10:39:09 +08:00
Nathan.fooo 7d3159c8da fix: delete duplicate test in board (#6364)
* chore: fix delete duplicate test in board

* chore: update log
2024-09-21 09:57:17 +08:00
Nathan.fooo e36f9aee4e chore: bump collab version (#6363) 2024-09-20 16:19:04 +08:00
Jessie.H 0a5f98014c chore: update zh-TW translations (#6357) 2024-09-20 10:01:19 +08:00
Mathias Mogensen e5cb16f5b3 chore: add changelog for 0.7.0 (#6355) 2024-09-19 08:15:34 +02:00
Lucas aa06c78b68 fix: settings page minor issues (#6354) 2024-09-19 13:40:08 +08:00
Lucas da03f40d29 fix: icon doesn't align with the editor when the editor is not initialized (#6345) 2024-09-19 10:57:06 +08:00
Mathias Mogensen 6ddbb418eb fix: image upload loading (#6351) 2024-09-19 00:33:13 +02:00
Nathan.fooo f9f5ae04d0 chore: fix potential when open a workspace with retry will cause lock… (#6344)
* chore: fix potential when open a workspace with retry will cause lock issue

* chore: disable verbose log
2024-09-18 21:00:01 +08:00
Richard Shiue 71e7f54367 fix(flutter_desktop): alignment on filter and sort menu (#6337) 2024-09-18 20:28:13 +08:00
Lucas c5afbb97a0 feat: support settings on sign in page (#6342)
* feat: support settings on sign in page

* feat: add settings entry in sign in page

* feat: support exporting log files on desktop

* chore: remove openfile dependency
2024-09-18 18:03:03 +08:00
Chikage0o0 d189c1ca4e chore: update zh-CN translations (#6281)
fix chinese translation
2024-09-18 14:45:58 +08:00
Lucas 630fdb8995 feat: support moveTo feature in more action menu (#6338)
* feat: support moveTo feature in more action menu

* fix: unable to switch to another workspace

* fix: integration test

* chore: update editor version

* fix: integration test
2024-09-18 14:45:25 +08:00
Lucas 522143cfd8 feat: support adjusting document width (#6327)
* feat: support adjusting document width

* chore: refactor padding calculation function

* fix: remove reset confim dialog

* chore: remove unused code

* feat: update sider position

* feat: use max width instead of padding

* fix: remove unused code

* fix: padding is negative error

* fix: set maxDocumentWidth to 480 * 4 and minDocumentWidth to 480

* fix: integration test
2024-09-18 10:43:23 +08:00
Richard Shiue 1dedb909e5 fix(flutter_desktop): incorrect row meta in row detail page (#6329) 2024-09-17 21:49:52 +08:00
LucasandMathias Mogensen 605a079927 fix: inputting backtick will crash when using French IME (#6321)
* fix: inputting backtick will crash when using French IME

* feat: convert backtick to codeblock

* chore: update frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/base/backtick_character_command.dart

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>

---------

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
2024-09-17 14:12:17 +08:00
Lucas 938abb396e fix: dismiss settings dialog after signing in (#6324)
* fix: dismiss settings dialog after signing in

* fix: tests

* fix: use boardcast stream to allow multiple listener
2024-09-17 13:19:15 +08:00
Richard Shiue a406dfbc43 fix(flutter_desktop): make icon of primary cells align to top (#6328)
* fix: make icon of primary cells align to top

* chore: use FlowyText.emoji
2024-09-17 11:24:34 +08:00
Kilu.He f303674737 fix: fixed image size for media cell (#6325) 2024-09-16 23:24:09 +08:00
Mathias Mogensen 2bc9753f60 fix: show count of files on card per column (#6323)
* fix: show count of files on card per column

* fix: analyzer
2024-09-16 15:18:14 +02:00
Richard Shiue 56cc7bb972 test(flutter_desktop): add grid integration tests (#6298)
* test: run board integration tests

* test: add grid integration tests

* test: fix delete group test

* chore: fix rust-lib tests

* chore: comment out failing test fix tests and remove tOdOS
2024-09-16 21:01:08 +08:00
Richard Shiue 710e894446 fix: grid filters (#6317) 2024-09-16 17:34:02 +08:00
Lucas d67d77f442 feat: support dragging the block to reorder (#6285)
* feat: support dragging the block to reorder

* feat: render feedback widget

* feat: add drag to move translation

* fix: the feedback widget doesn't update after node changed

* feat: render table placeholder

* feat: implement auto scroll when dragging to edge

* chore: add back the drop images/files feature

* chore: code refactor

* feat: exclude image and file block

* feat: exclude image gallery and database block
2024-09-16 17:01:02 +08:00
nathan 129db6925c chore: clippy 2024-09-16 16:53:47 +08:00
nathan 924df56d28 chore: clippy 2024-09-16 16:07:29 +08:00
Nathan.fooo c2b194b1d2 chore: remove cancel get rows (#6320)
* chore: config flutter logs

* chore: remove cancellation when get rows

* chore: clippy
2024-09-16 15:46:18 +08:00
Kilu.He 68986bd170 fix: modified primary cell (#6319) 2024-09-16 15:13:22 +08:00
Kilu.He e4029d05dc feat: support file media on web (#6318) 2024-09-16 14:24:25 +08:00
Nathan.foooandRichard Shiue f1bc9f860c fix: untitled override the true value in row details page (#6315)
* fix: untitled override the true value in row details page

* chore: use on complete edit callback

* chore: fix test

* chore: fix test

---------

Co-authored-by: Richard Shiue <71320345+richardshiue@users.noreply.github.com>
2024-09-16 13:19:36 +08:00
Lucas b865037728 chore: downgrade appimage builder (#6291) 2024-09-16 09:32:43 +08:00
Lucas 7e0de1f69c fix: view title doesn't update after renaming from 'more' button (#6309) 2024-09-16 09:32:32 +08:00
Mathias Mogensen 12c575dbbe feat: cover in database row (#6238)
* feat: cover in database

* chore: clean debugPrint

* chore: update collab rev

* feat: add cover functionality

* fix: provider issue for calendarbloc in popover

* feat: mobile row cover

* fix: imports after merge

* test: add media test to runner

* fix: mobile cover

* test: add row cover tests

* fix: add isClosed check
2024-09-15 22:33:18 +02:00
Mathias Mogensen f44fb02e4a fix: provider issue in row document (#6289)
* fix: provider issue in row document

* fix: use bloc consumer
2024-09-15 22:33:00 +02:00
Richard Shiue 4df59ca421 fix(flutter_desktop): reordering or creating a row while sorts are active (#6306)
* fix: reordering or creating a row while sorts are active

* test: fix integration test
2024-09-15 23:46:41 +08:00
Richard Shiue 7fee00ab72 chore(flutter_desktop): show full name of groups on hover (#6307)
* chore: show full name of groups on hover

* fix: elide text on overflow
2024-09-15 23:46:22 +08:00
Nathan.fooo 7271e0a108 chore: update ai model name (#6316) 2024-09-15 23:36:29 +08:00
Nathan.fooo 877236baf9 fix: sort with original row orders (#6314)
* fix: sort with original row orders

* chore: bump collab
2024-09-15 19:14:16 +08:00
Kilu.He 2c66634c89 feat: support invitation page (#6300) 2024-09-15 13:45:13 +08:00
Nathan.fooo 609ea27c42 fix: write/load database/document collab (#6308)
* chore: post document collab after create

* chore: write database rows

* chore: fix test

* chore: fix test

* chore: bump collab

* chore: fix get related row

* chore: try to fix open database error

* chore: update client api
2024-09-15 00:02:17 +08:00
Nathan.fooo aafdb80455 chore: bump collab that removes timeout when loading row (#6296) 2024-09-13 14:08:39 +08:00
Mathias Mogensen 4888d5d528 fix: media option improvements (#6260)
* feat: hide file names option

* chore: copywriting fixes

* fix: mobile cell

* feat: browse all images in a cell in viewer

* chore: unused variable

* fix: dialogs on download file

* feat: upload multiple files at once

* test: improve test coverage

* fix: missing format of rust files from merge
2024-09-13 00:12:13 +02:00
Nathan.fooo 21cc130e4e chore: unfinalized rows (#6283)
* chore: unfinalized rows

* chore: blocking read

* chore: fix test

* chore: clippy
2024-09-12 22:27:11 +08:00
AnnieandLucas.Xu a02de1a435 chore: update README.md (#6286)
* chore: Update README.md

added links to App Store and Play Store

* Update README.md

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-09-12 21:23:41 +08:00
Mathias Mogensen 477683d454 fix: card rebuild issue (#6277) 2024-09-12 15:27:32 +08:00
Lucas.Xu 340f37e00d chore: update appflowy_editor version (#6282)
* chore: update connectivity_plus

* chore: update appflowy_editor

* chore: enable editor log when enableDocumentInternalLog is true

* chore: update podfile.lock

* Revert "chore: update podfile.lock"

This reverts commit 41dbcad8c1.

* fix: compile

* chore: revert hotkey changes

* chore: revert network_monitor change
2024-09-12 14:40:19 +08:00
Richard Shiue eea3004a97 feat(flutter_desktop): colored column names in kanban board (#6270)
* feat: colored column names in kanban board

* fix: rename group event

* chore: add comment for rough design

* chore: revert unintentional changes

* fix: use new colors and use new delete confirmation dialog
2024-09-12 09:32:23 +08:00
Nathan.fooo f59772756a chore: adjust num of preload rows (#6280)
* chore: concurrent load rows

* chore: update client api

* chore: fix build
2024-09-12 08:47:49 +08:00
Lucas.Xu 1cf4f493db feat: ai writer on multi-lines of text (#6267)
* feat: ai writer on multi-lines of text

* feat: use flutter_bloc to manage ai response

* feat: integrate smart_edit_bloc

* fix: bloc not found

* feat: support 'fix spelling and grammer'

* fix: add log to address ai generate issue
2024-09-11 20:15:27 +08:00
Kilu.He c5a9dea721 feat: update iOS download link (#6276) 2024-09-11 11:24:01 +08:00
Nathan.fooo 7d2719dd71 fix: filter rows sometime not working (#6272) 2024-09-10 23:41:06 +08:00
Lucas.Xu 2ef896fb4a feat: support moving cursor using keyboard gesture on mobile (#6239)
* fix: invalid value when inserting image

* feat: support moving cursor using keyboard gesture on mobile

* fix: invalid value when inserting image
2024-09-10 16:33:16 +08:00
Lucas.Xu a0c6fb2fe8 fix: the last block of a doc is randomly moved to the first position of the doc (#6264) 2024-09-10 16:32:51 +08:00
Mathias Mogensen ee3054b355 fix: more default image extensions (#6250)
* fix: more default image extensions

* fix: add and comment default image extensions
2024-09-10 16:32:36 +08:00
Lucas.Xu bfe6d25322 chore: update version to 0.7.0 (#6266) 2024-09-10 16:32:14 +08:00
Nathan.fooo 055af03320 chore: check collab before saving collab to disk (#6261)
* chore: check collab before saving collab to disk
2024-09-10 07:56:13 +08:00
Annie 879d73a27a chore: update CHANGELOG.md incl v0.6.9 (#6256) 2024-09-09 21:55:52 +08:00
Annie 6721caf2fa chore: Update README.md (#6243)
change mobile screenshots layout
2024-09-09 21:02:25 +08:00
Mathias Mogensen 7bd876bf85 feat: file block on mobile (#6245)
* feat: file block on mobile

* chore: analyzer issues

* chore: cleanup after review
2024-09-09 19:47:33 +08:00
Lucas.Xu 2f3c9c11b1 feat: collect row page collabs (#6215)
* fix: invalid value when inserting image

* feat: collect row document collabs

* fix: code review

* fix: invalid value when inserting image

* chore: remove database_row_metas
2024-09-09 19:40:52 +08:00
Nathan.fooo 5d42d03e15 chore: bump collab (#6246)
* chore: bump collab

* chore: bump client api
2024-09-09 18:56:20 +08:00
Lucas.Xu 38d69c0b58 fix: android file permission issue (#6244)
* fix: invalid value when inserting image

* fix: upgrade share_plus version and use temp dir as android export log path

* fix: only noto emoji on Linux

* chore: upgrade android minSdkVersion to 29
2024-09-09 17:09:54 +08:00
Richard Shiue 7a0c6a829b fix: hover color in different color schemes (#6240) 2024-09-09 13:44:56 +08:00
Richard Shiue d1d485ee94 fix: incorrect colors for switch workspace button (#6228)
* fix: incorrect colors for switch workspace button

* chore: apply code style suggestions
2024-09-09 13:44:41 +08:00
Annie 1b15b8fa64 chore: update CHANGELOG.md (#6184) 2024-09-09 13:42:54 +08:00
Mathias MogensenandRichard Shiue 614f3ce81b feat: media launch review (#6198)
* fix: unexpected thrown exceptions~

* fix: wrap toggle rebuild

* fix: copywriting + checkbox group

* fix: only show item menu on hover

* feat: click to open image in viewer

* feat: improve row detail ux

* fix: add delete confirmation dialog

---------

Co-authored-by: Richard Shiue <71320345+richardshiue@users.noreply.github.com>
2024-09-09 13:42:23 +08:00
Nathan.fooo 006ea02bfe chore: fix database rows filter and sort (#6241)
* chore: fix database rows filter and sort

* chore: fix ios build

* chore: fix task id

* chore: fmt

* chore: ios build
2024-09-09 12:54:44 +08:00
Kilu.He 3caf84b8a0 fix: modified some behavior of template (#6242) 2024-09-09 12:06:22 +08:00
zkkvandLucas.Xu a002cb7428 chore: update ru-RU translations (#6141)
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-09-09 09:49:45 +08:00
rensawamo 96e39d0257 chore: update jp-JP translations (#6224)
* feat: pull upstream

* fix: revision

* chore: update jp-JP translations
2024-09-09 09:30:01 +08:00
Lucas.Xu 944da858a8 fix: redirect to login page after deleting account on Android (#6206) 2024-09-09 09:28:29 +08:00
CanonNi 53a2b7cb6e chore: update zh-CN translations (#6201)
* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦
2024-09-09 09:27:05 +08:00
Richard Shiue ec799afb7d fix: more checklist multiline issues (#6229)
* fix: more checklist multiline issues

* chore: add comment

* chore: apply code style improvments
2024-09-09 09:22:08 +08:00
Mathias Mogensen 06c356c7a1 fix: space button rebuild issue (#6235) 2024-09-08 21:58:00 +02:00
nathan dbe17aa4e8 chore: update logs 2024-09-08 23:38:24 +08:00
Nathan.fooo 187c5892ea fix: move group row (#6233)
* chore: fix group notification

* chore: clippy

* Revert "fix: newly-created group rows appear out of order (#6212)"

This reverts commit decc438b8a.

* chore: revamp function

* chore: update test

* chore: workaround to fix filter or sort don't show result after opening database

* chore: fix test
2024-09-08 22:21:34 +08:00
Annie c8be43134c chore: Update README.md (#6231)
two mobile images per row
2024-09-08 16:48:41 +08:00
Richard Shiue e615e7a304 fix: unhiding group throws exception (#6217) 2024-09-08 16:48:17 +08:00
Annie e3cd9a09f3 chore: Update README.md (#6230)
Part I: update product screenshots
2024-09-08 16:39:10 +08:00
Richard Shiue decc438b8a fix: newly-created group rows appear out of order (#6212)
* fix: newly-created group rows appear out of order

* test: fix tests

* fix: dont re-insert nor insert into no-status

* fix: clippy
2024-09-08 14:48:55 +08:00
Kilu.He a1793b53dd fix: open duplicate entrance and fixed some issues (#6216) 2024-09-07 13:35:51 +08:00
Mathias Mogensen 2b9b8c19a9 fix: flowy hover isselected check (#6223) 2024-09-07 01:39:49 +02:00
Richard Shiue 91173f707e fix: cannot drag newly-created board cards (#6207) 2024-09-07 00:20:13 +08:00
Kilu.He a1bc9246b1 fix: apple login on web (#6213) 2024-09-06 14:46:05 +08:00
Kilu.He 3e91be4960 fix: hide toast (#6210) 2024-09-06 12:28:49 +08:00
Kilu.He 9930efdc84 fix: toast issues (#6209) 2024-09-06 12:27:08 +08:00
Kilu.He 93ca6ac906 feat: support gallery block (#6205) 2024-09-06 11:49:50 +08:00
Lucas.Xu c400fdc01d fix: launch review 0.6.9 issues (#6203)
* chore: replace teamspaces with workspaces

* fix: set delete account button height to 32

* feat: use 'deletemyaccount' as confirmation text

* fix: remove input text after closing account deletion dialog

* feat: replace the existing error page with the new style

* fix: update photo library usage description

* chore: remove beta

* feat: add more acceptable confirm texts

* feat: optimize account deletion UX
2024-09-06 10:39:10 +08:00
Mathias Mogensen 4f592e80b6 fix: edit group title + rebuild improvement (#6156)
* fix: edit group title + rebuild improvement

* chore: fix clippy

* chore: fix clippy

* fix: stop widget replacement causing perf issues

* fix: after merge main

* chore: minor cleanup in view_editor

* fix: attempt to fix hover issue in tests
2024-09-05 12:48:44 +02:00
Nathan.fooo 7ea71fc6ae fix: open duplicated database (#6197)
* fix: open duplicated database

* chore: update logs
2024-09-05 17:35:24 +08:00
Lucas.Xu 8688183dae chore: update translation (#6196) 2024-09-05 15:28:34 +08:00
onxzyandLucas.Xu b5a17ee0bd chore: update fr-FR translations (#6148)
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-09-05 14:07:51 +08:00
CanonNi 1ecb864db0 chore: update zh-CN translations (#6178) 2024-09-05 13:57:24 +08:00
SimonandLucas.Xu 7b8af686e0 chore: updat the Ukrainian translation (#5904)
* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-09-05 13:55:54 +08:00
Richard Shiue 1c6e709c82 fix: board ui bugs (#6194)
* fix: date reminder indicator on board/calendar cards

* fix: stop restricting max lines of card title to two lines

* fix: don't allow multiline row titles

* fix: oops
2024-09-05 13:55:37 +08:00
Richard ShiueandMathias Mogensen 0fd0483302 fix: various grid ui issues (#6182)
* fix: delete field confirmation dialog only closes top most popover

* fix: prioritize single-line checklist items

* chore: wrap text toggle persist

* test: update integration tests

* chore: delete conflicting outputs on freezed

* chore: slightly make field editor faster

* chore: use standard dialog componet

* chore: enable multiline checklist tasks on mobile

* chore: Update frontend/appflowy_flutter/lib/plugins/database/application/field/field_editor_bloc.dart

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>

* chore: code cleanup

* fix: create field from row detail and add test

* chore: allow opening related database from editor

* test: integration test flake

---------

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
2024-09-05 13:54:50 +08:00
Kilu.He aa621289e9 feat: support publish outline (#6173) 2024-09-05 12:27:32 +08:00
Mathias Mogensen 009c2ed402 feat: media type option (#6090)
* feat: media type option

* feat: rename files + more media types

* feat: add basic style for cards on desktop

* test: add media

* chore: clippy

* feat: row detail ux improvement

* feat: show all media attachments as one count on card

* chore: localization

* fix: overlay issue + disable filter for option

* test: add base integration test

* test: add pumpAndSettle

* chore: update collab revision

* feat: mobile grid & board styling

* fix: clippy

* fix: grid reorder rows bug

* fix: style discrepancy

* chore: clippy

* chore: code cleanup
2024-09-05 06:03:58 +02:00
Lucas.Xu 08e2be367c feat: optimize error page in database row page and remove unused code (#6193) 2024-09-05 11:57:54 +08:00
Nathan.fooo 31567d451f chore: Observe database row event (#6190)
* chore: observe row

* chore: fix test
2024-09-04 23:21:05 +08:00
Lucas.Xu 8e34951477 feat: auto-fix table block data when duplicating it (#6185)
* fix: remove camera permission and update photo usage description

* feat: optimize the error block style in document

* feat: auto-fix table block when duplicating it
2024-09-04 17:11:50 +08:00
Lucas.Xu 589f5c1298 feat: exclude ARMv7 architecture for Android builds (#6187) 2024-09-04 16:55:49 +08:00
Lucas.Xu d1127a9bfa chore: update translations on iOS (#6186)
* chore: update mobile translations

* fix: folder context not found assertion

* fix: attempted to change a read-only map field

* feat: only replace the translation on iOS
2024-09-04 16:03:54 +08:00
Lucas.Xu 71bb182803 fix: remove camera permission and update photo usage description (#6181) 2024-09-04 14:26:32 +08:00
Richard Shiue 3161dddb25 chore(mobile): dismiss the keyboard when tap outside on login (#6183) 2024-09-04 14:04:39 +08:00
Lucas.Xu d9dc132e5b feat: enable apple sign in on desktop version (#6119) 2024-09-04 10:27:31 +08:00
Lucas.Xu 49ba1fd246 chore: podfile.lock should not be ignored (#6180) 2024-09-04 10:07:02 +08:00
Nathan.foooandLucas.Xu e9b2cbb317 chore: observe file upload state (#6172)
* chore: observe file upload state

* chore: observe file upload state

* chore: upgrade client api

* Update frontend/appflowy_flutter/lib/startup/tasks/file_storage_task.dart

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>

* chore: fix tauri build

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-09-04 07:56:08 +08:00
Lucas.Xu 2bb33e1d2a fix: incorrect right-click menu position on Desktop (#6177) 2024-09-04 00:58:02 +02:00
Lucas.Xu b7db1e7dda fix: build error in release mode (#6175) 2024-09-03 18:10:02 +08:00
Lucas.Xu 9da71c3186 feat: support account deletion (#6103)
* feat: support account deletion

* chore: update translation

* feat: support account deletion on mobile

* fix: only display account deletion button in appflowy cloud mode

* chore: remove unused code

* chore: update checkbox style

* fix: integration test

* chore: update translations

* chore: update sentry version in podfile.lock

* chore: update version
2024-09-03 16:58:38 +08:00
Zack a6cce62b06 feat: added delete account functionality (#6167)
* feat: added delete account functionality

* chore: update client api
2024-09-03 15:19:28 +08:00
Richard Shiue f7c6b8792f chore(flutter): bump sentry version to fix compilation (#6170) 2024-09-03 15:17:41 +08:00
Lucas.Xu 735cddd64b chore: downgrade macOS version in iOS CI to avoid "no space left" error (#6168)
* chore: dump mobile ci disk space usage

* chore: downgrade macos ci version to avoid no space left error
2024-09-03 15:08:09 +08:00
Kilu.He 94c033bba8 fix: some duplicate issues (#6171) 2024-09-03 12:49:56 +08:00
Kilu.He 4b0368d552 fix: display duplicate entry (#5853)
* fix: some issue

* fix: add colors

* fix: do not allow people who are not appflowy
2024-09-03 11:50:28 +08:00
Lucas.Xu dda798752f chore: bump version 0.6.8 (#6164)
* chore: bump version 0.6.8

* chore: update translations
2024-09-02 16:42:25 +08:00
Ufal SalmanandLucas.Xu e561778526 chore: update ID-id translations (#6150)
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-09-02 15:35:44 +08:00
FreezingKasandLucas.Xu ed2f2360fe chore: update FR-fr translations (#6155)
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-09-02 15:35:08 +08:00
Nathan.fooo 08bf5db2de chore: auto update field title when creating a new field (#6159)
* chore: auto update field title when creating a new field

* chore: fix test
2024-09-02 13:54:21 +08:00
Lucas.Xu 080b7db605 chore: remove unused translation (#6158) 2024-09-02 10:46:51 +08:00
Nathan.fooo 1cc41c10c4 fix: local ai enable/disable (#6151)
* chore: local ai state

* chore: fix local ai state when switch workspace

* chore: fix test
2024-09-01 17:48:07 +08:00
Mohammad Zolfaghari 6ce77aea3e fix: wrap checklist item text (#6145) 2024-09-01 16:06:58 +08:00
Nathan.fooo 01d7d6e900 chore: show document icon or emoji (#6144)
* chore: show icon

* chore: rename

* chore: adjust UI

* chore: remove unused property

* chore: update test

* chore: fix test

* chore: fix test
2024-08-31 23:54:37 +08:00
Lucas.Xu d264f3dbde fix: android toast style (#6128) 2024-08-31 09:33:44 +08:00
Nathan.fooo 8139065113 fix: init database row init (#6127) 2024-08-30 22:12:20 +08:00
Aymane BoumaazaandLucas.Xu 3324e7837b chore: update ar-SA and fr-FR translations with Fink 🐦 (#6084)
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-08-30 21:22:01 +08:00
vavenCVandLucas.Xu f20f8bcfbf chore: update Fr-fr translations (#6106)
* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-08-30 21:17:42 +08:00
MIckaelandLucas.Xu c20ed8c019 chore: update Pt-br translations (#6107)
* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-08-30 20:14:04 +08:00
YurminandLucas.Xu 0b658bff0b chore: update it-IT translations (#6058)
* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-08-30 20:13:33 +08:00
8319606cc0 chore: updated Arabic translation (#6111)
Co-authored-by: Nathan.fooo <86001920+appflowy@users.noreply.github.com>
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-08-30 20:13:17 +08:00
Antonio Albert eefdf96b00 fix: typo in german translation (#6126) 2024-08-30 19:31:15 +08:00
KD-MM2 e85e092db8 chore: update translations for Vietnamese(vi-VN) (#6122)
* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦
2024-08-30 19:24:43 +08:00
Lucas.XuandMathias Mogensen 928da2a223 chore: update translations (#6124)
* chore: update translations

* fix: close popup menu when tapping navigation bar item

* chore: update toolbar divider color and popup menu background color

* chore: update translations and icon

* chore: update frontend/appflowy_flutter/lib/shared/popup_menu/appflowy_popup_menu.dart

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>

---------

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
2024-08-30 19:19:41 +08:00
Mathias Mogensen 78c2e756d6 fix: lose focus when changing tabs (#6118) 2024-08-30 10:12:36 +02:00
Mathias Mogensen 47c2ae23ed fix: move title bar on top of tabs on Windows (#6116) 2024-08-30 10:12:26 +02:00
Mathias Mogensen 0fd0900b41 fix: add leading zeros to day & month in date format (#6114) 2024-08-30 10:12:16 +02:00
Lucas.Xu 61ad75502f feat: upgrade template button style (#6121) 2024-08-30 16:10:17 +08:00
Nathan.fooo 29858dda7a chore: update plan desc (#6120) 2024-08-30 15:35:57 +08:00
koukemo 34c441f3ad fix: add libnotify and rocksdb as docker dependencies (#6065) 2024-08-30 15:28:09 +08:00
Nathan.fooo c3114e5a39 chore: bump client api (#6113)
* chore: bump client api and collab
2024-08-30 14:31:05 +08:00
Nathan.fooo d89804f3e4 chore: bump client api (#6098) 2024-08-28 21:31:04 +08:00
Lucas.Xu 9209562648 fix: reset first page when switching space (#6097)
* fix: reset first page when switching space

* fix: primary field icon align issue in grid page
2024-08-28 21:25:57 +08:00
Lucas.Xu 9ee8cc6a7b feat: optimize sync error page (#6082) 2024-08-28 18:53:16 +08:00
Nathan.fooo 9a295daf99 chore: fix database filter (#6094)
* chore: fix database filter

* chore: fix test
2024-08-28 16:15:40 +08:00
Lucas.Xu 956d62fe82 fix: expand the icon to be the same size as the text in the heading block (#6093)
* fix: hidden board group padding

* fix: expand icon in heading style
2024-08-28 13:22:07 +08:00
Kilu.He 7541dff00e fix: some file block issues (#6085) 2024-08-28 10:30:08 +08:00
Nathan.fooo c4cdcbff73 chore: disable old import type (#6089) 2024-08-28 09:15:42 +08:00
Bartosz Sypytkowskiandnathan b77fdb8424 chore: update yrs dependencies (#6086)
* chore: update dependencies

* chore: catch results from apply update

---------

Co-authored-by: nathan <nathan@appflowy.io>
2024-08-27 20:53:00 +08:00
Nathan.fooo 083c0d0f0b chore: upgrade client api that fix initfine sync (#6083) 2024-08-27 19:59:52 +08:00
Kilu.He d25efba292 feat: support file block preview on web (#6081) 2024-08-27 15:01:23 +08:00
Nathan.fooo 40e627c303 chore: enable upload when switching workspace (#6080)
* chore: enable upload when switching workspace

* chore: update client api
2024-08-27 14:22:57 +08:00
Kilu.He e3a68d3ecb fix: change icons (#6076) 2024-08-27 10:59:31 +08:00
Lucas.Xu 1b185ba3cd feat: support sign in with Apple (#6049)
* feat: support sign in with Apple

* feat: support sign in with Apple

* feat: optimize sign in on desktop

* feat: expand third party sign in buttons on android

* fix: revert text color and font size in button
2024-08-27 10:49:31 +08:00
Lucas.Xu e5ad0f6d1d fix: table render error (#6074)
* fix: table render error

* fix: sidebar doesn't refresh if the pages are same

* chore: optimize empty placeholder align

* fix: debounce open workspace toast

* fix: editor color decoration error
2024-08-27 09:23:25 +08:00
Nathan.fooo 93bf1f79f6 chore: fix database row meta (#6078)
* chore: fix database row meta

* chore: update

* chore: update client api

* chore: clippy

* chore: update client api

* chore: update collab

* chore: update client api
2024-08-26 23:42:18 +08:00
Lucas.Xu f342f5ec7e feat: customize transition animation for popup menu (#6071)
* feat: customize transition animation for popup menu

* chore: add hint text for duplicate and favorite action

* fix: flutter analyze
2024-08-26 15:15:59 +08:00
Nathan.fooo 12cb9bde39 chore: replace cell content when import from csv (#6073) 2024-08-26 14:19:30 +08:00
Kilu.He b649950d62 fix: table issues (#6072) 2024-08-26 13:52:02 +08:00
Lucas.Xu 2ef74c229c fix: update settings menu color (#6039)
* chore: replace settings popup menu backgroundcolor

* fix: invite toast blocked by keyboard
2024-08-26 09:51:57 +08:00
Nathan.fooo 62f0307289 feat: async load database row, async filter, async sort (#6068)
* chore: display date when convert text to date

* chore: filter & sort

* chore: fix filter and sort

* chore: fix test

* chore: clippy

* chore: fix test
2024-08-26 09:46:16 +08:00
Kilu.He 242faee2f5 fix: document issues (#6069) 2024-08-25 22:06:34 +08:00
Kilu.He 7626cfd546 fix: database tabs (#6067) 2024-08-25 21:45:01 +08:00
Kilu.He 5b2df9e482 fix: calendar style issues (#6066) 2024-08-25 20:56:41 +08:00
Kilu.He 2a2dc903c1 fix: table cells order on publish (#6064) 2024-08-25 17:27:44 +08:00
Nathan.fooo d1ed45c312 fix: upload all imported csv rows (#6063)
* chore: upload imported csv rows

* chore: format number
2024-08-25 15:14:54 +08:00
Nathan.fooo a487aa74fd feat: support edit imported database (#6061)
* chore: change field type of imported csv

* fix: support load 10000 rows

* fix: clippy
2024-08-25 14:28:51 +08:00
Nathan.fooo d3b7c5fea5 chore: async load database row (#6051)
* chore: update

* chore: fix test

* chore: clippy

* chore: clippy
2024-08-24 00:40:57 +08:00
Kilu.He 3fa72106e9 fix: upload template (#6021)
* fix: upload template

* fix: scale thumb
2024-08-23 16:28:46 +08:00
Nathan.fooo 8ae67c5098 chore: upgrade collab verison (#6047) 2024-08-23 15:40:48 +08:00
Nathan.fooo a206d9aa8c chore: fix board row (#6046)
* chore: fix board row init

* chore: update client api version
2024-08-23 13:55:40 +08:00
Nathan.fooo 9e93483113 chore: Enable document undo redo (#6044)
* chore: update logs

* chore: enable document undo redo

* chore: clippy
2024-08-22 22:31:43 +08:00
Lucas.Xu 00690a1bb8 chore: add images from readme (#6041) 2024-08-22 17:51:44 +08:00
Nathan.fooo 86be92ba1b chore: upgrade collab version (#6038) 2024-08-22 16:28:29 +08:00
Khor Shu Heng 6305ab8c5d chore: bump version to 0.6.8 (#6037) 2024-08-22 12:33:13 +08:00
Lucas.Xu c371c6cd63 fix: ai writer generate button color (#6035)
* fix: ai writer generate button color

* fix: replace ai writer button with outlined rounded button
2024-08-22 11:38:50 +08:00
Lucas.Xu 190e3bedda chore: update member exceeded hint text (#6034)
* chore: update member exceeded hint text

* fix: disable ai writer widget on mobile
2024-08-22 11:14:01 +08:00
Francisco Di Marzo Borghi a78752d427 fix: removed Wayland Header (#5991)
* fix: sync AppImage recipe linux version with release

* fix: don't draw custom header on Wayland sessions

* chore(AppImage): reset `app_info.version`
2024-08-22 09:36:26 +08:00
Evililim b2b72d2130 chore: update French translations (#5973)
* chore: update translations with Fink 🐦

* Corrections demandée par Ninja i18n

* Chore: Correction for Ninja i18n
2024-08-22 09:34:06 +08:00
Lucas.Xu 104bf12ac7 feat: optimize settings on mobile (#6031)
* feat: optimize settings on mobile

* feat: open discord link when clicking help button

* fix: flutter analyze
2024-08-22 09:32:29 +08:00
Bartosz Sypytkowskiandnathan 0e844678fc chore: Remove last sync at (#6029)
* chore: update dependencies to stop using last sync at field

* chore: apply cargo fmt

* chore: fix dependencies

* chore: upgrade client api

---------

Co-authored-by: nathan <nathan@appflowy.io>
2024-08-22 08:42:32 +08:00
Nathan.fooo 23968d89fc chore: Upgrade collab version (#6028)
* chore: write collab to disk if it's not exist

* chore: write collab if it's not exit

* chore: fix test

* chore: upgrade appflowy collab

* chore: upgrade appflowy collab

* chore: update collab version

* chore: fix test
2024-08-22 07:45:51 +08:00
Nathan.fooo 0ce43ca5fa chore: write collab to disk if it's not exist (#6023)
* chore: write collab to disk if it's not exist

* chore: write collab if it's not exit

* chore: fix test
2024-08-21 14:04:53 +08:00
nathan b9a34f6fc2 chore: turn off verbose log 2024-08-20 21:45:14 +08:00
Nathan.fooo 93a110d37d chore: explicit using any int64 (#6020)
* chore: explicit using any int64

* chore: update commit id of appflowy collab
2024-08-20 21:38:29 +08:00
Nathan.fooo 70d6351a6c chore: calm clippy wanring when using non send with Arc (#6018) 2024-08-20 17:07:54 +08:00
Lucas.Xu 70e96c01b3 fix: ignore case sensitive of image name when dragging image to document (#6017) 2024-08-20 16:55:53 +08:00
Nathan.fooo 6a0650e6d5 chore: fix file upload test (#6016)
* chore: fix file upload test
2024-08-20 15:18:57 +08:00
Nathan.fooo 6d09c33782 chore: spawn task on local set (#6012)
* chore: spawn local

* chore: using multiple thread runtime

* chore: fix test
2024-08-20 14:16:24 +08:00
nathan faf1e98d15 chore: update appflowy collab 2024-08-19 22:09:31 +08:00
Nathan.fooo 58b17a939c chore: fix lib dispatch (#6008)
* chore: replace rc with arc

* chore: fix dispatch

* chore: fix test

* chore: fix dispatch

* chore: fix test

* chore: remove afconcurrent

* chore: fix runtime block_on runtime
2024-08-19 22:08:10 +08:00
Lucas.Xu 7113269802 chore: optimize row card page UI (#5995)
* chore: adjust buttons padding in row record page

* fix: disable more button in row page

* fix: upload image button ui on mobile

* fix: embed link button ui on mobile

* fix: add missing border for ai text field and ai translate field

* fix: delete AI can make mistakes on mobile

* chore: disable sentry

* fix: invite error toast

* fix: add member limit hint text in invite member screen

* feat: show toast after opening workspace on mobile

* chore: remove sentry

* chore: filter row page in recent views

* feat: support display field name as row page title

* chore: remove scroll bar on home page

* chore: remove legacy code

* chore: optimize mobile speed

* Revert "chore: remove sentry"

This reverts commit 73b45e2590.

* fix: reduce document page rebuild time

* chore: improve tooltip style
2024-08-19 11:06:34 +08:00
Lucas.Xu e460120a1c feat: add ai bubble button on mobile home page (#5992)
* chore: skip check list test if the task is not found

* feat: add ai bubble button in home page

* feat: only show the ai bubble button for the cloud user

* chore: add border color to ai bubble button

* Revert "chore: skip check list test if the task is not found"

This reverts commit 961f594a31.

* fix: only display ai bubble button on home page
2024-08-19 09:50:42 +08:00
Nathan.fooo d0ce65f711 chore: fix database filter (#6005)
* chore: fix filter
2024-08-19 09:47:37 +08:00
Nathan.fooo 5878379b2e chore: lazy load database row (#6001)
* chore: fix potential load database rows fail

* chore: fix layout padding
2024-08-18 18:44:32 +08:00
Bartosz Sypytkowskiandnathan fd5299a13d move to latest appflowy collab version (#5894)
* chore: move to latest appflowy collab version

* chore: filter mapping

* chore: remove mutex folder

* chore: cleanup borrow checker issues

* chore: fixed flowy user crate compilation errors

* chore: removed parking lot crate

* chore: adjusting non locking approach

* chore: remove with folder method

* chore: fix folder manager

* chore: fixed workspace database compilation errors

* chore: initialize database plugins

* chore: fix locks in flowy core

* chore: remove supabase

* chore: async traits

* chore: add mutexes in dart ffi

* chore: post rebase fixes

* chore: remove supabase dart code

* chore: fix deadlock

* chore: fix page_id is empty

* chore: use data source to init collab

* chore: fix user awareness test

* chore: fix database deadlock

* fix: initialize user awareness

* chore: fix open workspace test

* chore: fix import csv

* chore: fix update row meta deadlock

* chore: fix document size test

* fix: timestamp set/get type convert

* fix: calculation

* chore: revert Arc to Rc

* chore: attach plugin to database and database row

* chore: async get row

* chore: clippy

* chore: fix tauri build

* chore: clippy

* fix: duplicate view deadlock

* chore: fmt

* chore: tauri build

---------

Co-authored-by: nathan <nathan@appflowy.io>
2024-08-18 11:16:42 +08:00
Nathan.fooo c2d7c5360d chore: remove file size limit (#5974)
* chore: remove file size limit

* chore: flutter analyze
2024-08-17 21:51:36 +08:00
Lucas.Xu 9853fbfc10 chore: support monochrome icon on Android (#5989) 2024-08-17 11:05:06 +08:00
Lucas.Xu 44fb610269 fix: support pasting web image on mobile (#5987)
* fix: support pasting web image on mobile

* fix: permission check will deactive editor focus
2024-08-17 11:04:56 +08:00
Lucas.Xu e6bf6a5c7d feat: support inviting members on mobile (#5986)
* feat: support inviting members on mobile

* feat: support workspace member list on mobile

* feat: support leave workspace on mobile

* chore: adjust member list ui

* fix: flutter analyze
2024-08-17 11:04:43 +08:00
Lucas.Xu d3d929b68e fix: unable to insert todo list via slash menu (#5980)
* fix: unable to insert todo list via slash menu

* fix: unable to insert divider via slash menu

* chore: update editor version

* chore: update translations

* chore: decrease sentry sample rate to 0.1

* fix: integration test
2024-08-16 11:58:48 +08:00
Lucas.Xu f7a2d9e581 chore: add loading indicator when generating freezed file (#5978) 2024-08-15 20:12:25 +08:00
Lucas.Xu 6283649a6b feat: open the row page on mobile (#5975)
* chore: add dart dependency validator

* feat: open the row page on mobile

* Revert "chore: add dart dependency validator"

This reverts commit c81e5ef0ed.

* chore: update translations

* feat: preload row page to reduce open time

* chore: don't add orphan doc into recent records

* fix: bloc error

* fix: migrate the row page title to latest design

* chore: optimize database mobile UI
2024-08-15 20:12:09 +08:00
Lucas.Xu 88cc0caab7 feat: integrate Sentry Flutter and enable it if SENTRY_DSN is not empty (#5959)
* chore: add dart dependency validator

* feat: integrate sentry flutter

* chore: remove user info collection

* fix: flutter analyze

* fix: ios compile

* chore: add log
2024-08-15 10:00:27 +08:00
Nathan.fooo 7eb8ea347d fix: local ai toggle (#5968)
* chore: fix disable local ai

* chore: do not index file
2024-08-15 07:44:32 +08:00
Nathan.fooo 8935b7158c chore: remove workspac id in user profile (#5962)
* chore: remove workspac id in user profile

* chore: fix test

* chore: clippy

* chore: clippy

* chore: fix cloud test

* chore: fix checklist test
2024-08-14 19:44:15 +08:00
Nathan.fooo fa230907ca fix: refresh local ai state when opening workspace (#5961)
* chore: fix local ai state when open other workspace

* chore: fix duplicate message
2024-08-14 16:58:56 +08:00
Nathan.fooo 6d496b2088 chore: remove future result (#5960)
* chore: remove future result

* chore: fix test
2024-08-14 15:50:21 +08:00
Nathan.fooo 4b24b41dd4 chore: rm fut (#5958)
* chore: rm fut

* chore: clippy
2024-08-14 10:33:23 +08:00
Lucas.Xu b3a0119c18 feat: optimize date picker & mention block (#5954)
* chore: optimize rename button on mobile

* fix: mention block id empty error

* chore: optimize mention block style

* feat: add confirm button in date picker
2024-08-14 09:31:30 +08:00
Nathan.fooo 463c8c7ee4 feat: enable local set (#5955)
* chore: enable local set

* chore: fix test

* chore: clippy

* chore: fix tauri build

* chore: fix tauri build
2024-08-13 23:36:44 +08:00
Lucas.Xu e2359cf047 fix: row property align issue (#5950)
* fix: row property align issue

* fix: generate_freezed.sh path warning

* Revert "fix: generate_freezed.sh path warning"

This reverts commit 7c0a4a3177.

* fix: generate_freezed.sh path warning

* chore: improve chat page mobile UI
2024-08-13 20:01:32 +08:00
Lucas.Xu d23977ebb0 chore: optimize generation speed (#5930)
* chore: optimize language generation speed

* chore: optimize code generation speed

* chore: optimize freezed generation speed

* chore: optimzie appflowy_backend generation speed

* chore: optimize appflowy_result

* chore: optimzie flowy_infra generation speed

* chore: optimzie flowy_infra_ui generation speed

* chore: optimzie appflowy_flutter generation speed

* chore: optimize generate.sh

* chore: optimize the execution order

* chore: use exclude_packages instead of include_packages
2024-08-13 16:13:33 +08:00
Lucas.Xu f1ad03eaa9 chore: bump version 0.6.7 (#5949)
* chore: update collab version

* chore: update changelog

* chore: update notification reddot style

* fix: unable to fetch reminders

* chore: optimize notification red dot size
2024-08-13 15:03:57 +08:00
Lucas.Xu 17c9c9b556 chore: optimize recent section performance (#5948)
* fix: duplicated call for setting recent view

* chore: reduce recent update
2024-08-13 13:52:02 +08:00
Lucas.Xu 93f9a2cab1 feat: display no access page (#5941)
* feat: display no access page

* fix: optimize the primary rounded button
2024-08-13 09:32:22 +08:00
Annie 4b710527c9 chore: remove file upload limitation & add tooltip for search (#5944) 2024-08-12 22:24:24 +08:00
Nathan.fooo 6e26dc128c chore: fix message id (#5943) 2024-08-12 22:24:06 +08:00
Annie d3d9ab2fb0 chore: reset line height to null as default value (#5942) 2024-08-12 18:08:54 +08:00
Nathan.fooo 1db8480b75 chore: using write lock to fix acquire lock error (#5938) 2024-08-12 16:28:34 +08:00
AnnieandNathan.fooo 7e53b34484 chore: center confirm or cancel (#5936)
Co-authored-by: Nathan.fooo <86001920+appflowy@users.noreply.github.com>
2024-08-12 16:19:16 +08:00
Lucas.Xu 34465efc24 chore: replace all the buttons on settings page with the primary button style (#5937) 2024-08-12 16:03:52 +08:00
AnnieandLucas.Xu a29b170b13 chore: remove stability ai (#5927)
* chore: remove stability ai

* chore: remove stabilityAI widgets

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-08-12 15:46:56 +08:00
Mohammad ZolfaghariandLucas.Xu 14b60fb9b0 fix: list paste bug #5846 (#5917)
* fix: list paste bug #5846

selecting a single word on a bullet or number list and pasting it
from the clipboard would clear the whole text of that node and
replace it with clipboard text.

resolves #5846

* chore: update editor version

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-08-12 15:46:45 +08:00
Nathan.fooo 1c638dd930 chore: show reference sources on local ai response (#5933)
* chore: show reference sources on local ai response

* chore: clippy

* chore: clippy

* chore: update i18n

* chore: update client api
2024-08-12 15:43:17 +08:00
Sota 55a4810d60 chore: update translations with Fink 🐦 (#5932) 2024-08-12 15:12:52 +08:00
AnnieandLucas.Xu 2bc7875bdd chore: polish upload image menu (#5928)
* chore: polish upload image menu

* fix: text align issue

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-08-12 13:52:53 +08:00
Nathan.fooo f7adcae8ff chore: show attachment on local ai (#5929)
* chore: show attachment on local ai

* chore: fix compile
2024-08-12 09:21:44 +08:00
Nathan.fooo 23997e977c refactor: revamp file upload and fix partitial upload bugs (#5924)
* chore: upload chat file to local ai

* chore: async func

* chore: individual file progress

* chore: fix test

* chore: fix file upload
2024-08-11 20:39:25 +08:00
Lucas.Xu 3ff47b7e1e fix: link to two calendars in same doc may failed randomly (#5926)
* chore: udpate translation

* fix: editor loses focus randomly when interacting with certain databases

* fix: text align issues on Windows

* chore: update editor version
2024-08-11 20:18:35 +08:00
AnnieandLucas.Xu d33af70a5c chore: revamp editor icon (#5925)
* chore: revamp file block icon

* chore: revamp other blocks icon

* fix: flutter analyze

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-08-11 20:18:23 +08:00
nathan 510752868d chore: fix flutter wanrings 2024-08-11 15:16:02 +08:00
nathan 42d1bb84c5 chore: fix compile 2024-08-11 15:10:30 +08:00
Annie 2debd0283c chore: revamp question bubble (#5923) 2024-08-11 15:02:29 +08:00
Nathan.fooo e87ade6b3f chore: update tabbar icon (#5921) 2024-08-10 21:06:54 +08:00
e2a923a796 chore: update editor version (#5918)
* chore: update editor version

* fix: new property field width on Mobile

* feat: support enter to insert a new line on mobile

* feat: optimzie callout style

* feat: add hover effect on share button

* chore: fix

---------

Co-authored-by: Nathan.fooo <86001920+appflowy@users.noreply.github.com>
Co-authored-by: nathan <nathan@appflowy.io>
2024-08-10 20:49:06 +08:00
Annieandnathan cd0f8d80e9 chore: replace icons (#5914)
Co-authored-by: nathan <nathan@appflowy.io>
2024-08-10 18:05:53 +08:00
Nathan.fooo 7abe9f4661 feat: show indicator when send chat message with attachment/mention etc (#5919)
* chore: adjust line height

* chore: send stream message

* chore: index file

* chore: clippy
2024-08-10 17:23:37 +08:00
Nathan.fooo 758c304a74 feat: support mention a document as context on local ai (#5913)
* feat: support mention a document as context on local ai

* chore: rename

* chore: fix test

* chore: fix test
2024-08-09 21:55:20 +08:00
f84473c857 chore: update German translations to state of v0.6.7 (#5848)
* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* fix: add empty itemSeven removed by Inlang

* fix: add empty itemSeven removed by Inlang

fix for turkish translation

* fix: empty translation for itemSeven

quickfix for the empty translation of itemSeven. This has been done the same way to resolve previous issues with InLang and empty translation strings.

* fix: empty translation for itemSeven in TR

quickfix for the empty translation of itemSeven. This has been done the same way to resolve previous issues with InLang and empty translation strings.

* fix: remove itemSeven completely

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* fix: resolve conflicts after merging main

* chore: update translations with Fink 🐦

---------

Co-authored-by: Mathias Mogensen <mathiasrieckm@gmail.com>
Co-authored-by: Mathias Mogensen <mathias@appflowy.io>
2024-08-09 21:51:23 +08:00
Lucas.Xu a26b2a356c feat: optimize the slash menu item name & icon (#5908)
* feat: optimize the slash menu item name & icon

* feat: optimize the toolbar item name & icon

* fix: integration test

* fix: replace unaligned icons
2024-08-09 21:50:47 +08:00
Annie 57bbb6cc41 chore: replace property icons in database (#5910) 2024-08-09 21:08:13 +08:00
Nathan.fooo e82edc0419 chore: polish UI and display attachment when using local ai (#5906)
* chore: polish UI

* chore: fix compile
2024-08-09 07:40:24 +08:00
Lucas.Xu f57297e76d fix: known issues in 0.6.7 (#5903)
* feat: add capitalize extension for string and apply it in emoji picker header and icon picker

* fix: adjust tooltip height calculation

* feat: add Streamline open source icons notice and link

* feat: enhance heading toolbar item to toggle heading level and cancel on same level selection

* feat: use home-3 as default space icon

* feat: use the first character of space name as icon if icon was removed

* chore: update hover effect for delete workspace button

* chore: optimize space icon on mobile

* fix: adjust chat ui on mobile

* fix: adjust default space icon on mobile
2024-08-08 19:31:10 +08:00
Lucas.Xu 7769034467 chore: add more logs in reminder bloc (#5860)
* chore: add more logs in reminder bloc

* Revert "chore: add more logs in reminder bloc"

This reverts commit 9d0bb8fb29.

* chore: add more logs in reminder bloc

* fix: unable to view reminders on Desktop

* fix: force refresh reminders

* chore: fix flutter analyze

* feat: support database reminder on Mobile

* chore: remove referenced database padding
2024-08-08 13:35:22 +08:00
Nathan.fooo a523b8ff90 chore: chat ui polish (#5902)
* chore: chat ui polish

* chore: fmt

* chore: clippy
2024-08-08 12:07:00 +08:00
Kilu.HeandLucas.Xu 7b7b907017 feat: support custom icon (#5869)
* feat: support custom icon

* fix: quote

* chore: join lines for icons.json

* fix: manual add .svg for icon

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-08-08 09:49:34 +08:00
Lucas.Xu 29b262a1c6 chore: optimize mobile ai chat page (#5897)
* feat: improve chat page UI on mobile

* feat: integrate add page menu into chat page on mobile

* fix: only display document view in @ menu
2024-08-08 09:49:08 +08:00
Nathan.fooo e28a251e72 chore: chat UI poblish (#5895)
* chore: update ui

* chore: update send state

* chore: workspace owner prompt

* chore: show other user

* chore: fix ui
2024-08-07 16:48:09 +08:00
Lucas.Xu 98b7882d43 feat: move all the heading toolbar items into a popup menu (#5890)
* chore: udpate translations

* feat: move all the heading items into a popup menu

* chore: add arrow down icon after heading toolbar items

* fix: compile

* chore: adjust heading toolbar style
2024-08-07 12:42:52 +08:00
Lucas.Xu e279ad1cc7 feat: optimize editor toolbar tooltip (#5889)
* chore: improve icon picker dark mode color

* feat: optimize editor toolbar tooltip style

* feat: customize markdown item tooltip message

* chore: find the tooltip by rich message

* feat: add hover effect in toolbar item

* feat: add hover effect in toolbar item

* chore: optimize hover color in light mode

* chore: fix integration test

* chore: optimize align & font toolbar item

* chore: fix integration test
2024-08-07 11:37:30 +08:00
Mathias Mogensen a798b037db fix: add back invitation success toast (#5875) 2024-08-06 10:10:06 +02:00
Nathan.fooo 5fbaf664ba chore: update translation (#5887) 2024-08-06 16:01:32 +08:00
Lucas.Xu 41a346c7ed chore: adjust legacy space icon (#5886) 2024-08-06 15:10:44 +08:00
Lucas.Xu aab942d163 fix: remove unused expanded widget (#5885)
* fix: remove unused expanded widget

* Revert "fix: remove unused expanded widget"

This reverts commit dcdc318ea2.

* fix: remove unused expanded widget
2024-08-06 14:19:44 +08:00
Nathan.fooo 5757cc9a1d chore: polish ui (#5883)
* chore: polish ui

* chore: clippy

* chore: fmt
2024-08-06 13:17:56 +08:00
Lucas.Xu 453e6309d5 feat: refactor space icon picker (#5878)
* feat: refactor space icon picker

* chore: optimize the _loadIconGroups function

* feat: refactor emoji picker

* feat: integrate icon picker into flowy_icon_emoji_picker

* feat: support searching icon

* feat: support displaying new icons

* fix: flutter analyze

* chore: join lines

* feat: support space icon in view title

* feat: support customzing icon when creating space or managing space

* feat: customize the emoji picker and icon picker padding

* feat: shuffle icon

* fix: expand popup menu font size

* fix: flutter integration test
2024-08-06 11:47:38 +08:00
Lucas.Xu 4041724980 fix: prevent shaking in nested lists deeper in AI message (#5877) 2024-08-06 11:22:40 +08:00
Nathan.fooo d378c456d4 feat: Implement menu on chat (#5879)
* chore: implement menu

* chore: gather metadata

* chore: update client api

* chore: stream metadata

* chore: save metadata

* chore: update client api

* chore: adjust UI

* chore: fmt
2024-08-06 07:56:13 +08:00
Lucas.Xu 0abf916796 feat: support pasting image from Slack (#5864) 2024-08-02 22:00:40 +08:00
Lucas.Xu 393850ae4b chore: expand inline menu width (#5867) 2024-08-02 22:00:28 +08:00
Lucas.Xu 46bad4e7e8 chore: optimize the workspace menu hover status (#5865) 2024-08-02 16:10:49 +08:00
Lucas.Xu e9fc003e10 fix: + button in the navigation bar doesn't work when the space is not initialized (#5862) 2024-08-02 13:11:52 +08:00
Kilu.He cb60488bbe fix: replace wasm with axios (#5856)
* fix: replace wasm with axios

* fix: login redirect

* fix: flag emoji on windows
2024-08-02 12:19:32 +08:00
Lucas.Xu 04556252e1 chore: optimzie emoji align on desktop (#5857) 2024-08-02 10:20:31 +08:00
Mathias Mogensen c2e8a12427 fix: select option chip size (#5859) 2024-08-01 23:28:05 +02:00
Nathan.fooo 73421e0d58 feat: suppport translate and summary using local ai (#5858)
* chore: fix ui

* chore: fix ui

* chore: rename

* chore: rename

* chore: rename

* chore: refactor database ai interface

* chore: support local ai for database

* chore: clippy
2024-08-01 23:13:35 +08:00
Lucas.Xu b9fd3701cd feat: improve reminder color in notification page (#5855)
* feat: improve reminder color

* fix: notification page doesn't update when switching workspace
2024-08-01 20:21:25 +08:00
Lucas.Xu 9fbba5fb60 feat: notification multiple select (#5847)
* chore: update editor version

* feat: support multi select notification items

* fix: flutter analyze

* feat: add navgation bar button

* feat: add multi select item

* feat: add multi choice in notification page

* feat: support multi choice

* chore: update icon

* feat: support open page from notification page

* chore: update version
2024-08-01 16:30:15 +08:00
Lucas.Xu 7261d1e8da chore: update rocksdb version 0.22.0 (#5826)
* chore: update rocksdb version 0.22.0

* chore: update collab

* chore: revert rust toolchain to 1.77.2
2024-08-01 15:36:59 +08:00
Lucas.Xu 27aac2b911 chore: optimize emoji align on mobile (#5852) 2024-08-01 15:36:21 +08:00
Kilu.He 0cd5af5ffa fix: add comment tip (#5854) 2024-08-01 14:15:38 +08:00
Kilu.He 87e950733f fix: react action bugs (#5851) 2024-08-01 13:07:12 +08:00
Kilu.He 2402b4c6f1 feat: support global comment on publish (#5834)
* feat: support duplicate UI on web

* fix: replace google svg

* fix: modified some copy

* fix: adjust modal position

* fix: upgrade wasm package

* fix: text overflow

* fix: global comments

* fix: replace appflowy icon

* fix: demond load outline

* fix: lazy load

* fix: close duplicate entry

* fix: ci error

* fix: modified comment styles

* fix: adjust space

* fix: easy find reply comment

* fix: calendar scroll bugs

* fix: image render

* fix: replace loading

* fix: issues of test session

* fix: fixed adding comment

* fix: database view name
2024-08-01 12:59:04 +08:00
Mathias Mogensen ed81a0aff2 feat: upload file in document (#5843)
* feat: upload file in document

* feat: add uploaded at & improvements

* fix: popover onOpen not triggered by manual show

* test: add basic file test

* test: fix and add rename test
2024-07-31 15:49:35 +02:00
Lucas.Xu dce9231118 fix: try to reopen the first workspace if the workspace deletion failed (#5844) 2024-07-31 17:52:36 +08:00
Lucas.Xu d1c1449cf6 feat: support notification on mobile (#5831)
* feat: add inbox/unread/archived tabs

* feat: dump notification info

* chore: add reminder bloc

* feat: support unread / archive notification tab

* feat: support archive all & mark all as read

* feat: add empty page

* chore: optimize gesture

* feat: add red dot above notification icon

* chore: optimize code logic

* feat: optimize tabbar animation

* fix: notification align issue

* fix: todo list icon align issue

* feat: disable emoji button inside callout in read-only mode

* feat: optimize icon size in editor

* chore: improve text color in dark mode
2024-07-31 15:15:15 +08:00
Nathan.fooo 7c3dd5375d chore: switch to appflowy ai if local ai is not enable (#5839)
* chore: switch to appflowy ai if local ai is not enable

* chore: clippy

* chore: fix enable bug

* chore: fix compile

* chore: clippy
2024-07-31 11:47:09 +08:00
Lucas.Xu 81532d014e chore: use light haptic feedback (#5838)
* chore: use light haptic feedback

* chore: optimize tabbar & side action animation
2024-07-30 19:53:11 +08:00
Nathan.fooo 735a09b333 chore: remove local ai (#5837)
* chore: remove local ai

* chore: flutter analyze
2024-07-30 19:44:08 +08:00
nathan d52a04a9e3 chore: update chat input hint 2024-07-30 17:40:58 +08:00
Lucas.Xu a14ced458c chore: bump version 0.6.6 (#5833) 2024-07-30 17:37:28 +08:00
Nathan.fooo 5250a151c8 feat: Chat app download (#5835)
* chore: downlaod chat app

* chore: download app

* chore: disable local ai in billing

* chore: remove watcher

* chore: flutter analyzer
2024-07-30 17:32:30 +08:00
Mathias Mogensen d5a5a64fcf fix: photo gallery improvements + launch review fixes (#5830)
* fix: photo gallery improvements

* fix: improve when to show billing/plan pages

* feat: add grid photo gallery layout

* fix: close inline actions menu
2024-07-30 15:28:40 +08:00
Lucas.Xu 175c90e379 chore: update collab 93ec9a38722d5ed0628e6d03a161e2de172967f3 (#5832) 2024-07-30 15:28:21 +08:00
Lucas.Xu 115ae27ab1 fix: missing system font display (#5825)
* fix: missing system font display

* fix: integration test

* fix: cloud integration test
2024-07-29 14:30:11 +08:00
Chen ☁️☁️ e908892b4a chore: update simplified Chinese translate (#5798) 2024-07-29 10:00:05 +08:00
hasanbeder 948d61a9e0 chore: update tr-TR.json (#5822)
chore: Update Turkish translations
2024-07-29 09:59:25 +08:00
Lucas.Xu b5c4786896 fix: 0.6.6 launch review issues (#5824)
* fix: only rebuild the sidebar header when needed

* fix: skip the null or empty awareness data

* fix: ai writer setState error

* chore: add arrow down icon when hovering on workspace button

* chore: update workspace button tooltip sytle

* chore: only show collapse all subpages button when then page is expanded

* chore: update pin color

* chore: fix integration test

* Revert "chore: fix integration test"

This reverts commit e02b237423.
2024-07-29 09:57:58 +08:00
Nathan.fooo d24f1c566a fix: chat bugs (#5823)
* chore: implement slash menu

* chore: show popup

* chore: single column

* chore: update appflowy editor

* chore: fix warns
2024-07-27 23:47:08 +08:00
Lucas.Xu ddf68b010d chore: improve UI design on mobile (#5816) 2024-07-27 21:05:51 +08:00
Nathan.fooo 22b108df70 chore: enable billing (#5818) 2024-07-26 12:03:29 +08:00
Nathan.fooo aff9a61919 chore: notify in release build (#5817) 2024-07-26 10:28:18 +08:00
Lucas.Xu 043cd3f3bb fix: chat messaage color doesn't update when switching theme (#5815) 2024-07-26 10:08:00 +08:00
Lucas.Xu 29fb4af40a chore: improve UI design on Desktop (#5792)
* fix: only show collapse page button when the children of the page is not emtpy

* chore: set minimum sidebar width to 268

* chore: replace space lock icon and pin & unpin icon

* chore: change divider color

* chore: update divider color

* chore: improve create space color

* feat: highlight delete button when hovering

* chore: update translations

* fix: icon align issue

* feat: highlight sidebar resizer when hovering

* feat: add border to popover

* feat: optimize scroll bar

* feat: improve scrollbar hover color

* feat: support creating a new page via cmd+n

* chore: improve scrollbar color

* feat: improve tooltip style

* chore: fix unit test

* chore: bump version 0.6.6
2024-07-26 09:49:13 +08:00
Nathan.fooo a2e211555e chore: chat with pdf ui (#5811)
* chore: chat with pdf ui

* chore: only enable local ai on macos

* chore: add todo

* chore: adjust UI

* chore: clippy
2024-07-26 07:58:54 +08:00
Mathias Mogensen d1af172fb7 feat: drop images into editor (#5813) 2024-07-26 00:08:55 +02:00
Mathias Mogensenandnathan 23b6f94e82 feat: photo gallery block + image improvements (#5803)
* feat: support multiple images in image block

* feat: support drop files on image placeholder

* fix: overflow in image placeholder

* chore: clean code

* feat: refactor to multi image block

* feat: drop image on gallery to add

* feat: add delete image inside interactive viewer

* fix: some mobile improvements

* fix: web ci

* test: fix tests after dialog changes

* test: add basic multi image block test

* test: add to test runner

* test: open interactive viewer

* fix: add delete index to callback

* test: add navigation next/previous

* ci: fix

* ci: fix

* ci: fix

* test: add network image + deletion tests

* fix: remove duplicates after merge

* test: add multi image insertion test

* ci: try

* ci: try

---------

Co-authored-by: nathan <nathan@appflowy.io>
2024-07-25 14:47:08 +02:00
Nathan.fooo 82fffba45a chore: document local ai (#5810)
* chore: document local ai

* chore: update ui

* chore: clippy
2024-07-25 19:41:16 +08:00
charles 0373088fb8 fix: defaultWindowSize is out of scope (#5795) (#5796) 2024-07-25 13:53:46 +08:00
Lucas.Xu 0da0f320b7 fix: the action menu is blocked by the navigation bar on Android (#5806) 2024-07-25 13:52:20 +08:00
Lucas.Xu 4abdcd9478 fix: integration test (reset to default location) (#5804)
* fix: integration test (reset to default location)

* fix: unit test (appflowy cloud anon user and then sign in)

* Revert "fix: unit test (appflowy cloud anon user and then sign in)"

This reverts commit 2635aa42f0.

* fix: unit test (appflowy cloud anon user and then sign in)
2024-07-25 12:02:18 +08:00
Nathan.fooo 1e54c2dc7c chore: only run appflowy cloud if it's not exist (#5799)
* chore: only run appflowy cloud if it's not exist

* chore: update

* chore: log error

* chore: fix sign out test

* chore: update test
2024-07-25 07:59:03 +08:00
Lucas.Xu 01747f13e8 chore: bump version 0.6.5 (#5800) 2024-07-24 14:53:56 +08:00
Nathan.foooandMathias Mogensen 4a5eda6eeb chore: enable billing (#5779)
* chore: enable billing

* chore: adjust bright mode UI

* chore: show corresponding error in sidebar

* chore: dismiss dialog in ai writter when hit ai response

* fix: improvements from test session

* chore: ai error message for database

* chore: different prompt for workspace owner

* feat: cancel plan survey

* chore: show ai repsonse limit on chat

* fix: sidebar toast after merge

* chore: remove unused debug print

* fix: popover close on action

* fix: minor copy changes

* chore: disable billing

* chore: disbale billing

---------

Co-authored-by: Mathias Mogensen <mathiasrieckm@gmail.com>
2024-07-24 14:23:09 +08:00
Lucas.Xu b5d799655a fix: delete reference databases in toggle list (#5782) 2024-07-24 11:24:33 +08:00
Nathan.fooo 43b250ec28 CI: use self-hosted runner if developer can create a branch in the up-stream repo (#5791)
* chore: use self hosted macos runner
2024-07-24 10:55:58 +08:00
Khor Shu Heng 20e82880ff chore: remove unused step in rust CI, allow cache on failure, show container logs (#5770) 2024-07-24 10:03:46 +08:00
Khor Shu Heng 661a0879c6 fix: Remove empty edit from read me json (#5769)
* fix: Remove empty edit from read me json

* fix: remove delta field entirely
2024-07-24 09:45:41 +08:00
Kilu.He 2fb18dd051 fix: to 16px (#5790)
* fix: to 16px

* fix: to 16px

* fix: to 14px
2024-07-23 17:48:51 +08:00
Kilu.He 6334255e15 fix: some style issues (#5783) 2024-07-23 10:21:50 +08:00
Lucas.Xu f66821715f fix: integration test failed (grid row detail page: hide and show hidden fields) (#5781) 2024-07-22 16:51:58 +08:00
620e027c3e feat: ai billing (#5741)
* feat: start on AI plan+billing UI

* chore: enable plan and billing

* feat: cache workspace subscription + minor fixes (#5705)

* feat: update api from billing

* feat: add api for workspace subscription info (#5717)

* feat: refactor and start integrating AI plans

* feat: refine UI and add business logic for AI

* feat: complete UIUX for AI and limits

* chore: remove resolved todo

* chore: localize remove addon dialog

* chore: fix spacing issue for usage

* fix: interpret subscription + usage on action

* chore: update api for billing (#5735)

* chore: update revisions

* fix: remove subscription cache

* fix: copy improvements + use consistent dialog

* chore: update to the latest client api

* feat: support updating billing period

* Feat/ai billing cancel reason (#5752)

* chore: add cancellation reason field

* fix: ci add one retry for concurrent sign up

* chore: merge with main

* chore: half merge

* chore: fix conflict

* chore: observer error

* chore: remove unneeded protobuf and remove unwrap

* feat: added subscription plan details

* chore: check error code and update sidebar toast

* chore: periodically check billing state

* chore: editor ai error

* chore: return file upload error

* chore: fmt

* chore: clippy

* chore: disable upload image when exceed storage limitation

* chore: remove todo

* chore: remove openai i18n

* chore: update log

* chore: update client-api to fix stream error

* chore: clippy

* chore: fix language file

* chore: disable billing UI

---------

Co-authored-by: Zack Fu Zi Xiang <speed2exe@live.com.sg>
Co-authored-by: nathan <nathan@appflowy.io>
2024-07-22 15:43:48 +08:00
Kilu.He 864768b3ba fix: can not display rows when rows overthan 1000 (#5777) 2024-07-22 15:38:13 +08:00
Kilu.HeandLucas.Xu a8b4f22703 feat: support publish database on web (#5748)
* fix: view name

* fix: hidden login on web

* fix: database update bugs

* feat: support render database on web

* fix: loading

* fix: calendar width on mobile

* fix: calendar boder color

* fix: replace some icons

* fix: deal with visible view ids

* fix: filter error child

* fix: hide filters and sorts

* fix: the style of relation

* fix: throw error when apply fail

* fix: upgrade yjs

* fix: eslint errors

* fix: support group by checkbox

* fix: add shortcut to clear data

* fix: relation

* fix: relation

* fix: relation

* fix: relation

* fix: view meta

* fix: view meta

* fix: view meta

* fix: empty database block

* fix: 0716 bugs

* fix: add button to url cell

* fix: jest test

* fix: unit tests

* fix: lint

* fix: reduce database space

* fix: add after payment page

* fix: add spacing

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-07-22 13:37:27 +08:00
Lucas.Xu 432db0f6d5 feat: publish databse to Web (#5709)
* chore: refactor the publish code

* feat: integrate publish into database page

* feat: add publish database structure

* feat: add database row collab

* feat: publish the database row collabs

* chore: update collab

* chore: improve question bubble

* feat: publish the database relations

* fix: rust ci

* feat: select grid view to publish

* feat: unable to deselect the primary database

* feat: optimize the read recent views speed (#5726)

* feat: optimize the read recent views speed

* fix: order of recent views should be from the latest to the oldest

* chore: update translations

* fix: replace the unable to be selected icon

* feat: remove left padding of inline database

* fix: code review

* chore: remove publish api err log

* chore: read the database collab and document collab from disk instead of memory

* chore: code cleanup

* chore: revert beta.appflowy.com

* chore: code cleanup

* test: add database encode test

* test: add publish database test

* chore: refresh sidebar layout

* chore: update comments
2024-07-22 13:35:42 +08:00
Abhijeet SinghandLucas.Xu e8e4162a5c chore: update Spanish translations (#5742)
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-07-22 10:15:50 +08:00
sayishiandLucas.Xu 241234726f chore: update Chinese translations (#5727)
* chore: update translations with Fink 🐦

* chore: revert cargo.lock changes

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-07-22 10:07:50 +08:00
Khor Shu Heng e426970eed fix: Add retry for admin client sign in for test (#5767) 2024-07-22 10:02:01 +08:00
Yaron ShahrabaniandLucas.Xu d5544af6c5 chore: update Hebrew translation (#5738)
* Added Hebrew initial infra.

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* Hebrew translation.

* Hebrew update.

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-07-22 10:00:24 +08:00
Stefan Weiberg 9361afd573 chore: update German translations (#5722) 2024-07-19 16:40:03 +08:00
Artjom Jemeljanov dc93a336d6 chore: update Russian translations (#5730)
* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦

* Update en.json

* Update ru-RU.json

* Update ru-RU.json

* chore: update translations with Fink 🐦

* Update settings.json

* Update settings.json
2024-07-19 16:26:00 +08:00
Nathan.fooo 4e5482488f chore: update build config (#5759)
* chore: update build config

* chore: fix ci

* chore: update client-api

* chore: fix compile
2024-07-19 12:23:51 +08:00
Nathan.fooo 5bbf174ffd chore: enable local ai and local ai chat (#5755)
* chore: enable local ai and local ai chat

* chore: config for chat with file

* chore: flutter anaylzer
2024-07-18 20:54:35 +08:00
Lucas.Xu f36e3ae378 chore: bump version 0.6.4 (#5744) 2024-07-16 14:51:00 +08:00
Mathias MogensenandLucas.Xu dc6349b4b1 fix: improve color selector (#5743)
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-07-16 14:50:50 +08:00
Lucas.Xu 44d8def3ce fix: reset space relationship when clearing cache (#5737)
* fix: space's child views didn't update when moving a page into it

* chore: remove check logic

* feat: integrate fix space into clear cache

* fix: translation missing value

* chore: update logger version
2024-07-16 13:23:07 +08:00
Nathan.fooo c6ad57f11d chore: show plugin state (#5740)
* chore: show plugin state

* chore: flutter analyzer

* chore: update
2024-07-15 22:45:53 +08:00
Nathan.fooo ff23165d3e chore: download llm files (#5723)
* chore: download file

* chore: config download ui

* chore: update zip

* chore: config download ui

* chore: unzip file

* chore: unzip file

* chore: rename

* chore: disable local ai

* chore: fmt

* chore: fix warning

* chore: update

* chore: fix clippy
2024-07-15 15:23:23 +08:00
Lucas.Xu 253e7597c4 feat: optimize the read recent views speed (#5726)
* feat: optimize the read recent views speed

* fix: order of recent views should be from the latest to the oldest
2024-07-15 14:23:20 +08:00
Zack d2e3fdfefd chore: fix compile (#5733) 2024-07-15 09:01:34 +08:00
Lucas.Xu a2336f5bf7 chore: improve popup menu color (#5725)
* chore: improve popup menu color

* fix: 100% text wrap into a new line in checklist cell
2024-07-12 15:23:22 +08:00
Lucas.Xu 8833df1740 fix: ai chat result contains html escape text (#5721)
* fix: ai chat result contains html escape text

* feat: support copy the code block from ai chat page

* feat: support copy code block from ai chat page

* fix: add hover effect to color picker button

* chore: increase minimum window size
2024-07-11 21:42:02 +08:00
Lucas.Xu 1524b10a8a chore: bump version 0.6.4 (#5719)
* chore: upgrade android target sdk to 34

* chore: downgrade macos builder version to support x86_64

* chore: bump version 0.6.4
2024-07-11 13:46:28 +08:00
Kilu.He fe0fa9b530 feat: support sign-in and sign-up on Web (#5712) 2024-07-11 12:55:22 +08:00
Lucas.Xu 80afcf44c0 fix: syntax error when generating translation files (#5718) 2024-07-11 11:56:00 +08:00
e500c89978 feat: choose cursor/selection color from palette or color picker #5041 (#5677)
* chore: show ai service error (#5675)

* feat: Implement color picker dialog for user color selection (#5041)

- Added `flex_color_picker` dependency.
- Implemented a new color picker dialog with the following features:
  - Display Material predefined colors.
  - Include primary, accent, and shade colors, as well as a color wheel for selection.
  - Add a graphical opacity selector.
  - Enhanced the previous dialog to include an icon in a text field for opening the palette.
- Added `suffixIcon` parameter to the `_ColorSettingTextField` class, making it reactive to tap gestures.
- Utilized `ColorExtension` on the `Color` class to avoid namespace conflicts when converting colors to hexadecimal strings.
- Added translation strings to english

This commit addresses issue #5041

* feat: Implement color picker dialog for user color selection (#5041)

- Added `flex_color_picker` dependency.
- Implemented a new color picker dialog with the following features:
      - Display Material predefined colors.
      - Include primary, accent, and shade colors, as well as a color wheel for selection.
      - Add a graphical opacity selector.
      - Enhanced the previous dialog to include an icon in a text field for opening the palette.
- Added `suffixIcon` parameter to the `_ColorSettingTextField` class, making it reactive to tap gestures.
- Utilized `ColorExtension` on the `Color` class to avoid namespace conflicts when converting colors to hexadecimal strings.
- Added translation strings to english

This commit addresses issue #5041

* chore: refactor code

---------

Co-authored-by: Nathan.fooo <86001920+appflowy@users.noreply.github.com>
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-07-10 17:49:59 +08:00
Lucas.Xu 079b9888a8 feat: render ai text message with appflowy_editor (#5682)
* feat: render ai text message with appflowy_editor

* chore: update appflowy_editor

* fix: integration test

* feat: support paste inAppJson format

* chore: update appflowy_editor
2024-07-10 17:17:07 +08:00
Lucas.Xu 0fe383e538 feat: enable debug logs in internal build (#5713) 2024-07-10 13:55:40 +08:00
Bartosz Sypytkowski c006e29afc chore: update yrs and appflowy collab dependencies (#5707)
* chore: update yrs and appflowy collab dependencies

* chore: fix clippy errors

* chore: update yrs and collab dependencies in appflowy tauri

* chore: update yrs and collab dependencies in appflowy web app
2024-07-10 10:10:21 +08:00
Lucas.Xu 655a2b7093 chore: bump version 0.6.3 (#5701) 2024-07-08 13:46:27 +08:00
23c67bcdba feat: support publish document (#5576)
* feat: support a event for getting encoded collab of document

* feat: support publish view and unpublish views

* feat: publish page to the web

* chore: refacotor share bloc

* feat: call the publish event

* feat: support publish view and unpublish views

* feat: integrate publish api

* feat: integrate unpublish api

* feat: fetch the publish info to show the publish status

* feat: support publish interfaces

* fix: lint error

* fix: modified web server

* fix: some style

* fix: some style

* fix: some style

* fix: some style

* fix: some style

* fix: some style

* fix: some style

* fix: some style

* fix: some style

* fix: update codes

* fix: update codes

* fix: update codes

* fix: update codes

* fix: update codes

* chore: refactor publish bloc

* fix: some style

* fix: some style

* fix: some style

* fix: some style

* fix: some style

* fix: some style

* fix: the name is too long to publish

* chore: change color

* fix: some style

* fix: some style

* feat: refacotor share menu UI

* fix: some style

* fix: lint

* fix: some style

* feat: refacotor export-as

* fix: some style

* chore: refactor share menu colors

* fix: rust ci

* fix: some style

* fix: some style

* fix: deploy

* fix: deploy

* fix: deploy

* fix: deploy

* fix: deploy

* fix: deploy

* fix: deploy

* fix: deploy

* fix: deploy

* fix: deploy

* fix: deploy

* fix: deploy

* fix: bugs

* fix: bugs

* fix: bugs

* fix: bugs

* fix: bugs

* fix: bugs

* fix: bugs

* fix: bugs

* fix: bugs

* fix: bugs

* fix: bugs

* fix: bugs

* fix: bugs

* fix: bugs

* fix: bugs

* fix: bugs

* fix: rerelease

* fix: deploy

* fix: deploy

* fix: deploy

* fix: deploy

* fix: deploy

* fix: deploy

* fix: deploy

* fix: og image

* fix: support copy button

* fix: support copy button

* fix: support copy button

* chore: add a params

* feat: use default publish name

* chore: update copy

* feat: show a confirm deletion dialog if the deleted page contains published page

* feat: add copy toast in publish tab

* fix: to 404

fix: to 404

fix: to 404

fix: the error to 404

* feat: unpublish the page auto when moving it to another space

* feat: improve confirm deletion dialog

* feat: show unpublish error

* chore: use beta.appflowy.com

* feat: disable publish in non-apppflowy-cloud user mode

* fix: modified bullted icon style

* fix: the dark mode color

* fix: save the dark mode in local storage

* fix: text color

* chore: make bash script more portable (#5679)

* fix: title longer

* chore: move the files and modified the en

* chore: update deploy.sh

* chore: modified Dockerfile

* chore: modified server.cjs to server.js

* chore: modifed server.js to server.ts

* chore: replace publish url

* chore: remove todo list hover

* chore: show confirm dialog before deleting page

* fix: unpublish the pages before deleting

* fix: table cell bg color

* fix: callout icon

* fix: list number

* fix: emoji

* fix: number icon

* fix: callout icon position

* fix: add margin bottom

* fix: code block

* fix: support scroll for breadcrumbs

* fix: the breadcrumb doesn't update after moving page

* fix: 0705 issues

* fix: update publish status afer deleting page

* chore: add hover effect for visit site button

* fix: remove puiblish url text field enable border color

* chore: update delete page copy

* chore: enable debug category

* fix: only render sidebar if the spaces are ready

* fix: the breadcrumb doesn't update after moving page

* fix: auto code

* fix: add emoji

* fix: add emoji

* fix: favicon

* fix: cypress test

* fix: remove deploy ci

* fix: default url

* chore: revert launch.json

* fix: docker ci

* fix: change favicon

* fix: flutter integration test

* feat: add hover effect to share menu

* chore: add a checkmark if the page has been published

* chore: revert space deletion

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
Co-authored-by: Zack <speed2exe@live.com.sg>
2024-07-08 13:45:57 +08:00
Nathan.fooo 521fffd97c refactor: extract chat plugin to new repo (#5699)
* chore: update ui

* chore: update

* chore: update

* chore: separate to new crate

* chore: update commit id

* chore: fix compile

* chore: bump version
2024-07-08 13:19:13 +08:00
Lucas.Xu 2ecc2a67a9 fix: take the max value of the keyboard height and the view insets bottom to make the toolbar visible (#5700)
* fix: android toolbar will be blocked if the scroll bar is hidden

* fix: last opened view is synced in same workspace

* fix: fallback to space if the section sidebar contains space

* chore: revert last opened view code

* fix: integration tests
2024-07-08 13:15:42 +08:00
Lucas.Xu 2d11215bb2 chore: use latest macos runner to build the release package (#5686) 2024-07-08 09:43:23 +08:00
Lucas.Xu 6d0c9f766b fix: filter chat page when duplicating (#5676)
* fix: filter chat page when duplicating

* fix: don't clear selection if it has been disposed
2024-07-02 14:35:29 +08:00
Nathan.fooo 7a3f013a87 chore: show ai service error (#5675) 2024-07-02 13:26:53 +08:00
Lucas.Xu 8c1520b273 feat: sync the created view after duplicating (#5674)
* feat: sync the created view after duplicating

* chore: revert launch.json

* chore: refacotor code
2024-07-02 13:02:15 +08:00
Mathias MogensenandLucas.Xu a7b850e752 chore: disable cloud search (#5663)
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-07-02 13:02:01 +08:00
Lucas.Xu 42dc6017c6 feat: support moving page to a space (#5665)
* feat: support moving page to a space

* chore: update collab repo
2024-07-02 10:29:46 +08:00
Stefan Weiberg f9fba6b561 chore: update German translations (#5640) 2024-07-02 09:44:16 +08:00
Nathan.fooo 46896b5a2b chore: remove appflowy_web project (#5671)
* chore: remove appflowy_web project

* chore: remove ci
2024-07-01 22:49:24 +08:00
Lucas.Xu 2b8dca209e feat: sync the documents and databases after batch importing documents and databases (#5644)
* feat: support batch import

* feat: support batch import database

* chore: revert launch.json

* chore: fix rust ci

* fix: rust ci
2024-07-01 14:44:08 +08:00
Lucas.Xu c78f23e1c0 fix: v0.6.2 issues (#5654)
* fix: remove create button in move to menu

* fix: add loading indicator when duplicating space

* fix: sidebar header expand icon status

* fix: text within select tag overflow

* fix: callout block icon align issue

* feat: sync the space icon when creating a space

* fix: duplicated hover views

* fix: cover image doesn't update
2024-07-01 14:43:57 +08:00
Lucas.Xu 50f5be3e75 chore: fix rustfmt ci test (#5664) 2024-07-01 13:26:43 +08:00
Nathan.fooo e1c68c1b72 feat: Run Local AI model in AppFlowy (#5655)
* chore: load plugin

* chore: sidecar

* chore: fix test

* chore: clippy

* chore: save chat config

* chore: arc plugin

* chore: add plugins

* chore: clippy

* chore: test streaming

* chore: config chat

* chore: stream message

* chore: response with local ai

* chore: fix compile

* chore: config ui

* chore: fix load plugin

* chore: add docs

* chore: update docs

* chore: disable local ai

* chore: fix compile

* chore: clippy
2024-06-30 17:38:39 +08:00
Mathias Mogensen 3bcadff152 fix: settings changes + ai layout improvements (#5656)
* fix: settings changes

* fix: improve chat layout
2024-06-28 22:54:54 +08:00
Mathias Mogensen b09ff040f1 fix: postpone fetching member (#5648) 2024-06-28 09:03:30 +08:00
Nathan.fooo bf087bba5d fix: score filter (#5645)
* fix: score filter

* chore: update score limit
2024-06-28 07:57:12 +08:00
Lucas.Xu 605a53f2ae feat: open the duplicated space by default (#5638) 2024-06-27 14:12:52 +08:00
Stefan Weiberg ecc5555a4e chore: update German translations (#5630) 2024-06-27 13:34:51 +08:00
Lucas.Xu d2a5bab6d9 chore: bump version 0.6.2 (#5637) 2024-06-27 12:02:15 +08:00
Lucas.Xu a1dec0f269 feat: add check workspace health button in settings page (#5631) 2024-06-27 09:57:06 +08:00
Mohammad Zolfaghari b24fbc6b60 fix: fill field_settings on creating linked view (#5598) 2024-06-27 03:07:08 +02:00
Mathias Mogensen bbb3f95a13 fix: billing+cleanup (#5634)
* fix: billing fixes

* chore: best practice and cleaning

* chore: dispose of unused resources

* chore: upgrade editor version
2024-06-27 02:00:21 +02:00
Mathias Mogensen 7859fc7922 fix: macos fullscreen window position (#5632) 2024-06-27 00:36:59 +02:00
Lucas.Xu f812040f04 feat: support creating database at the first level (#5627)
* feat: support creating database at the first level

* chore: add loading indicator when importing file
2024-06-26 13:27:33 +08:00
Lucas.Xu 7d96c2dfd4 feat: add key + as zoom-in key (#5628) 2024-06-26 13:27:13 +08:00
Mathias Mogensen e4132ed217 chore: enable cloud search (#5624)
* chore: enable cloud search

* fix: filter received msgs by query
2024-06-25 21:56:58 +02:00
Mathias Mogensen a7f40b2adc fix: paste in list (#5621)
* fix: support pasting in list

* test: add simple test

* chore: remove debugPrint
2024-06-25 20:08:01 +02:00
Mathias Mogensen c996c9c28e fix: maximized window optimization (#5622) 2024-06-25 20:07:43 +02:00
MarcinandLucas.Xu f59b8a2e5c chore: update Polish translations (#5593)
* chore: update translations with Fink 🐦

* Revert "chore: update translations with Fink 🐦"

This reverts commit e3b7ca9e22.

* chore: update pl-PL translations

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-06-25 21:16:35 +08:00
JakobandLucas.Xu f7480cba16 chore: update de-DE translations (#5588)
* chore: update translations with Fink 🐦

* Revert "chore: update translations with Fink 🐦"

This reverts commit f24a479b63.

* chore: update de-DE translations

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-06-25 21:09:02 +08:00
Mathias Mogensen 271b250eac fix: make theme uploads more tolerant (#5617) 2024-06-25 13:52:59 +02:00
Nathan.foooandLucas.Xu 6b1e7b6ac8 chore: set document id (#5585)
* chore: set document id

* feat: set document id to upload image api

* chore: fmt

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-06-25 17:36:41 +08:00
Lucas.Xu bf2a00b133 fix: prevent overfow of space name and view name (#5619)
* fix: space name overflow

* fix: space name overflow in space menu

* fix: view name overflow in favorite menu
2024-06-25 17:36:00 +08:00
Lucas.Xu a8ed93054c feat: support moving page across spaces (#5618)
* feat: support moving page across spaces

* feat: refacotor move api

* feat: filter the database views

* feat: support searching in move page menu
2024-06-25 16:43:58 +08:00
Lucas.Xu b9ad2768cf feat: duplicate space (#5612) 2024-06-25 10:03:02 +08:00
54c9d12171 feat: support switch model (#5575)
* feat: ai settings page

* chore: intergate client api

* chore: replace open ai calls

* chore: disable gen image from ai

* chore: clippy

* chore: remove learn about ai

* chore: fix wanrings

* chore: fix restart button title

* chore: remove await

* chore: remove loading indicator

---------

Co-authored-by: nathan <nathan@appflowy.io>
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-06-25 07:59:38 +08:00
Lucas.Xu 40312f4260 fix: infinite loading (#5613) 2024-06-24 20:14:22 +08:00
Zack d2ca41c8f5 Remove deprecated add member (#5611)
* chore: remove deprecated add member directly

* chore: cargo clippy

* chore: cargo clippy

* chore: cargo clippy
2024-06-24 14:19:36 +08:00
Mathias Mogensen 7586a0ed48 fix: settings ui improvements (#5590)
* fix: settings ui improvements

* fix: replace placeholder + fix open folder

* fix: collapse sidebar button on windows

* test: fix tests after changes

* test: missed type cast
2024-06-20 21:01:20 +02:00
Mathias MogensenandLucas.Xu d8b32168a9 feat: hide application to dock macos (#5592)
* feat: hide application to tray macos

* chore: enable reopen the app after closing it

* fix: remove tray

* fix: remove asset

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-06-20 21:00:56 +02:00
Mathias Mogensen 8ca541bfa1 fix: reminder race condition (#5587) 2024-06-20 10:13:59 +02:00
Nathan.fooo b64da2c02f refactor: File upload (#5542)
* chore: rename service

* refactor: upload

* chore: save upload meta data

* chore: add sql test

* chore: uploader

* chore: fix upload

* chore: cache file and remove after finish

* chore: retry upload

* chore: pause when netowork unreachable

* chore: add event test

* chore: add test

* chore: clippy

* chore: update client-api commit id

* chore: fix flutter test
2024-06-20 07:44:57 +08:00
Lucas.Xu fdaca36b87 fix: automatically open page after switching space (#5580) 2024-06-19 21:28:49 +08:00
Lucas.Xu 8557383a89 fix: cursor height is inconsistent after upgrading to Flutter 3.22 (#5574)
* fix: cursor height is inconsistent after upgrading to Flutter 3.22

* fix: cursor height is inconsistent after upgrading to Flutter 3.22

* fix: android toolbar height issue
2024-06-19 19:34:47 +08:00
Mathias Mogensen fa86480458 feat: shortcuts page remake (#5567)
* feat: settings shortcuts page remake

* test: add shortcut test

* fix: physics on listview

* fix: menu icon
2024-06-19 10:24:34 +02:00
Nathan.fooo d75eb05707 chore: fix flutter test (#5572) 2024-06-19 13:26:18 +08:00
Lucas.Xu a2b32585a1 chore: bump version 0.6.0 (#5571) 2024-06-19 12:10:05 +08:00
Lucas.Xu 75cea400d2 fix: cursor jump randomly in check list item (#5565)
* chore: remove debug logs

* fix: cursor jump ramdomly in checklist item
2024-06-19 09:33:27 +08:00
Lucas.XuandMathias Mogensen ed82ec8eef chore: remove gl_es env (#5564)
* fix: try without media kit

* chore: remove gl_es env

* Revert "fix: try without media kit"

This reverts commit e331dbfabf.

---------

Co-authored-by: Mathias Mogensen <mathiasrieckm@gmail.com>
2024-06-18 16:16:31 +08:00
Lucas.XuandMathias Mogensen b6debd6c71 fix: remove media_kit (#5563)
Co-authored-by: Mathias Mogensen <mathiasrieckm@gmail.com>
2024-06-18 15:47:52 +08:00
Nathan.fooo a05ed63a3e chore: fix can't delete characters in card (#5562)
* chore: fix can't delete characters in card

* chore: i18n
2024-06-18 13:12:57 +08:00
Nathan.fooo 3e75f1f24a chore: fix checklist potential panic (#5561)
* chore: fix checklist

* chore: fix checklist
2024-06-18 10:16:39 +08:00
Lucas.Xu e607694729 chore: change slash menu hover color (#5555)
* feat: add a pinned icon after page name

* chore: change slack menu hover color

* Revert "feat: add a pinned icon after page name"

This reverts commit a668e0bd09.
2024-06-18 09:55:43 +08:00
ansizheshi 91d870415e chore: update zh-CN translations (#5545)
* chore: update translations with Fink 🐦

* Delete frontend/resources/translations/de-DE.json

* Add files via upload

* Restore en.json

* Restore en.json
2024-06-18 09:52:44 +08:00
Nathan.fooo 21a497924c chore: adjust height (#5558) 2024-06-17 21:38:05 +08:00
Mathias Mogensen 4a126e17ce fix: settings improvements (#5547)
* fix: user workspace bloc changed

* fix: use translate card cell style

* fix: add getworkspacemember

* fix: billing launch review

* fix: disable time field

* fix: member tooltip

* fix: remove my account description

* fix: punctuation

* fix: filter workspace font

* fix: cloud toggle

* fix: minor adjustments

* chore: disable cloud document search

* fix: improve workspace name textfield

* test: move billing test to cloud

* fix: use cache over remote

* fix: clippy and tests

* chore: amend flowy tooltip

* test: add pump and settle

* test: integration test for local auth
2024-06-17 14:30:19 +02:00
Lucas.Xu 8bf97ad5c6 feat: add a pinned icon after page name (#5553) 2024-06-17 19:18:06 +08:00
Lucas.Xu a85d11fb6d feat: collapse space and switch space by shortcuts (#5554)
* chore: improve delete popup style

* feat: support collapsing space and switching space by shortcuts
2024-06-17 18:59:08 +08:00
Lucas.Xu 1fd34bc58a chore: turn off the billing feature (#5551) 2024-06-17 17:33:40 +08:00
Lucas.Xu 70a7b856a2 feat: improve space UX (#5549)
* fix: scroll bar hover color

* chore: replace board icon

* chore: remove close button in upgrade menu

* chore: add translation

* feat: switch to the next space by shortcut

* chore: replace space lock icon

* chore: remove arrow icon in change icon button

* feat: only show other favorites header if the other two is empty

* fix: create new page in current space

* feat: create a new page in a newly created space by default

* chore: update translations

* feat: open the first page after switching space by default

* chore: replace board icon

* fix: open the first page(non-space) after switching workspace

* chore: revert more icon

* chore: revert editor version
2024-06-17 16:23:17 +08:00
Lucas.Xu 49683e6079 fix: migrate the private views only if they are not empty (#5544) 2024-06-17 10:29:15 +08:00
Lucas.Xu 13107b63e9 feat: improve upgrade space toast (#5543)
* fix: divider color

* feat: improve upgrade space toast
2024-06-15 09:03:09 +08:00
Nathan.fooo ce1a6e4fca chore: highlight code block (#5540) 2024-06-14 14:53:53 +08:00
Lucas.Xu 1d23e28eaf chore: enable billing system (#5539) 2024-06-14 08:42:20 +02:00
Lucas.Xu 2a4d78b688 feat: improve hover color in dark mode (#5538) 2024-06-14 14:31:55 +08:00
Lucas.Xu cbe452a73d feat: improve page thumbnail on mobile (#5535)
* feat: improve view thumbnail

* chore: blur the bottom navigation bar

* feat: improve date format

* feat: support url avatar

* fix: remove duplicated divider
2024-06-14 13:15:41 +08:00
Nathan.fooo 27899ee993 chore: save workspace member info to disk (#5536)
* chore: save workspace member info to disk

* chore: fix clippy
2024-06-14 11:34:23 +08:00
Lucas.Xu 785597f53e fix: space issues (#5531)
* fix: display the space icon in breadcrumb and disable the space entry

* fix: the icon and the title are not aligned center in more menu

* fix: incorrect space icon corner radius

* fix: missed tooltip for add new page button

* fix: disable space migration for local user

* chore: use general as default space name

* fix: space name overflow

* fix: only show arrow button when hovering on page

* fix: sidebar tooltip font size

* fix: use space name as hint text

* feat: support adding a new space from space menu

* fix: filter the space view
2024-06-14 09:32:02 +08:00
Nathan.fooo e2ce274718 chore: polish chat UI (#5533)
* chore: adjust chat ui

* chore: clippy
2024-06-14 09:02:06 +08:00
Zack 6be9c00127 chore: update to latest client api (#5529) 2024-06-13 15:14:20 +08:00
Mohammad ZolfaghariandMathias Mogensen aa621a8d84 feat: timer field (#5349)
* feat: wip timer field

* feat: timer field fixing errors

* feat: wip timer field frontend

* fix: parsing TimerCellDataPB

* feat: parse time string to minutes

* fix: don't allow none number input

* fix: timer filter

* style: cargo fmt

* fix: clippy errors

* refactor: rename field type timer to time

* refactor: missed some variable and files to rename

* style: cargo fmt fix

* feat: format time field type data in frontend

* style: fix cargo fmt

* fix: fixes after merge

---------

Co-authored-by: Mathias Mogensen <mathiasrieckm@gmail.com>
2024-06-13 08:52:13 +02:00
Mathias Mogensen 2d4300e931 chore: update version to 0.6.0 (#5528) 2024-06-13 08:25:11 +02:00
Lucas.Xu dc12938ab6 feat: support switching space on mobile (#5527) 2024-06-13 14:14:18 +08:00
Lucas.Xu 2d674060c6 feat: introduce space to manage the pages (#5517)
* fix: resizing icon on mobile

* feat: add space feature

* feat: support creating space

* feat: support creating new space

* feat: support space expand status

* feat: support creating page in space

* feat: support customizing space icon

* feat: display the space icon on space menu

* feat: add space more action button

* fix: flutter analyze

* feat: support editing space icon on more menu

* chore: update translations

* feat: manage space

* feat: delete workspace

* feat: disable delete button if needed

* feat: add private lock

* chore: adjust the old version

* feat: display upgrade button

* feat: support migrating space

* feat: support migrating space

* feat: allow user to upgrade space maunally

* fix: dark mode issue

* fix: create space delay

* chore: translations

* chore: disable workspace test
2024-06-13 13:43:29 +08:00
Nathan.fooo ecca81f3b8 chore: exclude ai columns (#5526) 2024-06-13 11:15:59 +08:00
Lucas.Xu 15329b39d0 chore: update editor version (#5513) 2024-06-13 07:58:05 +08:00
Mathias Mogensen bd5f5f8b9e feat: integrate cloud document search (#5523) 2024-06-13 01:37:19 +02:00
4f4be7eac7 feat: enable group condition (#5248)
* feat: enable group condition

* style: added i18n for date field group conditions

* fix: flutter analyze

* fix: test use i18n

* fix: more localization

---------

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
Co-authored-by: Mathias Mogensen <mathias@appflowy.io>
2024-06-13 00:02:16 +02:00
Nathan.fooo f1a4deb459 chore: support more language (#5522)
* chore: support more language

* chore: adjust ui
2024-06-12 23:17:57 +08:00
Mathias MogensenandZack Fu Zi Xiang 4708c0f779 feat: plan+billing (#5518)
* feat: billing client

* feat: subscribe workspace default impl

* feat: added create subscription

* feat: add get workspace subs

* feat: added subscription cancellation

* feat: add workspace limits api

* fix: update client api

* feat: user billing portal

* feat: billing UI (#5455)

* feat: plan ui

* feat: billing ui

* feat: settings plan comparison dialog

* feat: complete plan+billing ui

* feat: backend integration

* chore: cleaning

* chore: fixes after merge

* fix: dependency issue

* feat: added subscription plan cancellation information

* feat: subscription callback + canceled date

* feat: put behind feature flag

* feat: downgrade/upgrade dialogs

* feat: update limit error codes

* fix: billing refresh + downgrade dialog

* fix: some minor improvements to settings

* chore: use patch for client-api in tauri

* fix: add shared-entity to patch

* fix: compile

* ci: try to add back maximize build space step

* test: increase timeout in failing test

---------

Co-authored-by: Zack Fu Zi Xiang <speed2exe@live.com.sg>
2024-06-12 17:08:55 +02:00
Nathan.fooo 3d7a500550 feat: AI translation in Database (#5515)
* chore: add tranlate field type

* chore: integrate ai translate

* chore: integrate client api

* chore: implement UI
2024-06-12 16:32:28 +08:00
Mathias Mogensen 815c99710e feat: magic link sign-in as anonymous user (#5520)
* feat: magic link sign-in as anonymous user

* chore: remove commented code

* fix: custom sign-in dialog

* fix: bring back sign-out dialog

* fix: add minor space for sync indicator
2024-06-11 22:17:29 +02:00
Murat Mirgün ERCAN c9fe93920f chore: update tr_TR translations (#5499) 2024-06-11 10:17:28 +08:00
Lucas.Xu 5012b99c9b fix: remove member request on launch (#5505) 2024-06-11 10:16:32 +08:00
Mathias Mogensen 6b46372aa0 fix: custom font dropdown (#5502)
* fix: custom font dropdown

* fix: dart analyzer
2024-06-10 15:23:26 +02:00
Mathias Mogensen b6d873db1b chore: remove build bot (#5500) 2024-06-10 09:04:28 +08:00
Lucas.Xu 38d2bd7ee8 fix: board shortcuts conflict with textfield (#5487)
* fix: board shortcuts conflict with text field

* fix: typo

* fix: favorite icon issue in dark mode
2024-06-10 09:04:01 +08:00
Nathan.fooo bb3e9d5bd8 feat: Stream chat message (#5498)
* chore: stream message

* chore: stream message

* chore: fix streaming

* chore: fix clippy
2024-06-09 14:02:32 +08:00
Kilu.He 94060a0a99 fix: generate default document data from document id (#5430)
* fix: generate default document data from document id

* fix: update version
2024-06-09 13:42:09 +08:00
Kilu.He 86696b271e chore: improvements to caching strategies (#5488) 2024-06-07 16:37:07 +08:00
Tianyu Yuan 76fde00cc4 chore: update zh-CN translations (#5484)
* chore: update translations with Fink 🐦

* chore: update translations with Fink 🐦
2024-06-07 11:48:23 +08:00
Kilu.He b794f3894e chore: improve coverage of cypress (#5483) 2024-06-06 19:47:14 +08:00
Kilu.He 3b72f90ca5 feat: improve test coverage (#5481) 2024-06-06 17:48:58 +08:00
3753 changed files with 183598 additions and 62291 deletions

No files matched your search

+18 -13
View File
@@ -58,19 +58,24 @@ runs:
- name: Install prerequisites
working-directory: frontend
run: |
if [ "$RUNNER_OS" == "Linux" ]; then
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
sudo wget -qO /etc/apt/sources.list.d/dart_stable.list https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list
sudo apt-get update
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev libmpv-dev mpv
elif [ "$RUNNER_OS" == "Windows" ]; then
vcpkg integrate install
elif [ "$RUNNER_OS" == "macOS" ]; then
echo 'do nothing'
fi
cargo make appflowy-flutter-deps-tools
shell: bash
run: |
case $RUNNER_OS in
Linux)
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
sudo wget -qO /etc/apt/sources.list.d/dart_stable.list https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list
sudo apt-get update
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev
;;
Windows)
vcpkg integrate install
vcpkg update
;;
macOS)
# No additional prerequisites needed for macOS
;;
esac
cargo make appflowy-flutter-deps-tools
- name: Build AppFlowy
working-directory: frontend
@@ -94,4 +99,4 @@ runs:
- uses: actions/upload-artifact@v4
with:
name: ${{ github.run_id }}-${{ matrix.os }}
path: appflowy_flutter.tar.gz
path: appflowy_flutter.tar.gz
@@ -52,7 +52,7 @@ runs:
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
sudo wget -qO /etc/apt/sources.list.d/dart_stable.list https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list
sudo apt-get update
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev network-manager libmpv-dev mpv
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev network-manager
shell: bash
- name: Enable Flutter Desktop
@@ -75,4 +75,4 @@ runs:
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
sudo apt-get install network-manager
flutter test ${{ inputs.test_path }} -d Linux --coverage
shell: bash
shell: bash
-28
View File
@@ -1,28 +0,0 @@
name: Build Bot
on:
issue_comment:
types: [created]
jobs:
dispatch_slash_command:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
# get build name from pubspec.yaml
- name: Get build version
working-directory: frontend/appflowy_flutter
id: get_build_name
run: |
echo "fetching version from pubspec.yaml..."
echo "build_name=$(grep 'version: ' pubspec.yaml | awk '{print $2}')" >> $GITHUB_OUTPUT
- uses: peter-evans/slash-command-dispatch@v4
with:
token: ${{ secrets.PAT }}
commands: build
static-args: |
ref=refs/pull/${{ github.event.issue.number }}/head
build_name=${{ steps.get_build_name.outputs.build_name }}
-72
View File
@@ -1,72 +0,0 @@
name: Deploy Web (Test)
on:
push:
branches:
- build/test
env:
NODE_VERSION: "18.16.0"
PNPM_VERSION: "8.5.0"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
deploy:
runs-on: ubuntu-latest
env:
SSH_PRIVATE_KEY: ${{ secrets.WEB_TEST_SSH_PRIVATE_KEY }}
REMOTE_HOST: ${{ secrets.WEB_TEST_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.WEB_TEST_REMOTE_USER }}
SSL_CERTIFICATE: ${{ secrets.WEB_TEST_SSL_CERTIFICATE }}
SSL_CERTIFICATE_KEY: ${{ secrets.WEB_TEST_SSL_CERTIFICATE_KEY }}
ENV_FILE: test.env
steps:
- uses: actions/checkout@v4
- name: setup node
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
- name: setup pnpm
uses: pnpm/action-setup@v2
with:
version: ${{ env.PNPM_VERSION }}
- name: Node_modules cache
uses: actions/cache@v2
with:
path: frontend/appflowy_web_app/node_modules
key: node-modules-${{ runner.os }}
- name: install frontend dependencies
working-directory: frontend/appflowy_web_app
run: |
pnpm install
- name: copy env file
working-directory: frontend/appflowy_web_app
run: |
cp ${{ env.ENV_FILE }} .env
- name: test and lint
working-directory: frontend/appflowy_web_app
run: |
pnpm run lint
- name: build
working-directory: frontend/appflowy_web_app
run: |
pnpm run build
- name: generate SSL certificate
run: |
echo "${{ env.SSL_CERTIFICATE }}" > nginx-signed.crt
echo "${{ env.SSL_CERTIFICATE_KEY }}" > nginx-signed.key
- name: Deploy to EC2
uses: easingthemes/ssh-deploy@main
with:
SSH_PRIVATE_KEY: ${{ env.SSH_PRIVATE_KEY }}
ARGS: "-rlgoDzvc -i"
SOURCE: "frontend/appflowy_web_app/dist frontend/appflowy_web_app/server.cjs frontend/appflowy_web_app/start.sh frontend/appflowy_web_app/Dockerfile frontend/appflowy_web_app/nginx.conf frontend/appflowy_web_app/.env nginx-signed.crt nginx-signed.key"
REMOTE_HOST: ${{ env.REMOTE_HOST }}
REMOTE_USER: ${{ env.REMOTE_USER }}
EXCLUDE: "frontend/appflowy_web_app/dist/, frontend/appflowy_web_app/node_modules/"
SCRIPT_AFTER: |
docker build -t appflowy-web-app .
docker rm -f appflowy-web-app || true
docker run -d -p 80:80 -p 443:443 --name appflowy-web-app appflowy-web-app
+27 -31
View File
@@ -2,18 +2,10 @@ name: Docker-CI
on:
push:
branches:
- main
- release/*
paths:
- frontend/**
branches: ["main", "release/*"]
pull_request:
branches:
- main
- release/*
paths:
- frontend/**
types: [opened, synchronize, reopened, unlocked, ready_for_review]
branches: ["main", "release/*"]
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@@ -27,25 +19,29 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
- name: Set up Docker Compose
run: |
docker-compose --version || {
echo "Docker Compose not found, installing..."
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# cache the docker layers
# don't cache anything temporarly, because it always triggers "no space left on device" error
# - name: Cache Docker layers
# uses: actions/cache@v3
# with:
# path: /tmp/.buildx-cache
# key: ${{ runner.os }}-buildx-${{ github.sha }}
# restore-keys: |
# ${{ runner.os }}-buildx-
- name: Build the app
shell: bash
run: |
set -eu -o pipefail
cd frontend/scripts/docker-buildfiles
docker-compose build --no-cache --progress=plain \
| while read line; do \
if [[ "$line" =~ ^Step[[:space:]] ]]; then \
echo "$(date -u '+%H:%M:%S') | $line"; \
else \
echo "$line"; \
fi; \
done
uses: docker/build-push-action@v5
with:
context: .
file: ./frontend/scripts/docker-buildfiles/Dockerfile
push: false
# cache-from: type=local,src=/tmp/.buildx-cache
# cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
# - name: Move cache
# run: |
# rm -rf /tmp/.buildx-cache
# mv /tmp/.buildx-cache-new /tmp/.buildx-cache
+59 -91
View File
@@ -25,9 +25,10 @@ on:
env:
CARGO_TERM_COLOR: always
FLUTTER_VERSION: "3.22.0"
RUST_TOOLCHAIN: "1.77.2"
CARGO_MAKE_VERSION: "0.36.6"
FLUTTER_VERSION: "3.22.2"
RUST_TOOLCHAIN: "1.80.1"
CARGO_MAKE_VERSION: "0.37.18"
CLOUD_VERSION: 0.6.54-amd64
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@@ -39,7 +40,7 @@ jobs:
strategy:
fail-fast: true
matrix:
os: [ ubuntu-latest ]
os: [ubuntu-latest]
include:
- os: ubuntu-latest
flutter_profile: development-linux-x86_64
@@ -73,7 +74,7 @@ jobs:
strategy:
fail-fast: true
matrix:
os: [ windows-latest ]
os: [windows-latest]
include:
- os: windows-latest
flutter_profile: development-windows-x86
@@ -100,7 +101,7 @@ jobs:
strategy:
fail-fast: true
matrix:
os: [ macos-latest ]
os: [macos-latest]
include:
- os: macos-latest
flutter_profile: development-mac-x86_64
@@ -122,12 +123,12 @@ jobs:
flutter_profile: ${{ matrix.flutter_profile }}
unit_test:
needs: [ prepare-linux ]
needs: [prepare-linux]
if: github.event.pull_request.draft != true
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest ]
os: [ubuntu-latest]
include:
- os: ubuntu-latest
flutter_profile: development-linux-x86_64
@@ -173,7 +174,7 @@ jobs:
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
sudo wget -qO /etc/apt/sources.list.d/dart_stable.list https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list
sudo apt-get update
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev libmpv-dev mpv
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev
fi
shell: bash
@@ -216,11 +217,11 @@ jobs:
shell: bash
cloud_integration_test:
needs: [ prepare-linux ]
needs: [prepare-linux]
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest ]
os: [ubuntu-latest]
include:
- os: ubuntu-latest
flutter_profile: development-linux-x86_64
@@ -241,17 +242,50 @@ jobs:
cp deploy.env .env
sed -i 's|RUST_LOG=.*|RUST_LOG=trace|' .env
sed -i 's/GOTRUE_EXTERNAL_GOOGLE_ENABLED=.*/GOTRUE_EXTERNAL_GOOGLE_ENABLED=true/' .env
sed -i 's|GOTRUE_MAILER_AUTOCONFIRM=.*|GOTRUE_MAILER_AUTOCONFIRM=true|' .env
sed -i 's|API_EXTERNAL_URL=.*|API_EXTERNAL_URL=http://localhost|' .env
- name: Run Docker-Compose
working-directory: AppFlowy-Cloud
env:
BACKEND_VERSION: 0.3.24-amd64
APPFLOWY_CLOUD_VERSION: ${{ env.CLOUD_VERSION }}
APPFLOWY_HISTORY_VERSION: ${{ env.CLOUD_VERSION }}
APPFLOWY_WORKER_VERSION: ${{ env.CLOUD_VERSION }}
run: |
docker compose down -v --remove-orphans
docker compose pull
docker compose up -d
sleep 10
container_id=$(docker ps --filter name=appflowy-cloud-appflowy_cloud-1 -q)
if [ -z "$container_id" ]; then
echo "AppFlowy-Cloud container is not running. Pulling and starting the container..."
docker compose pull
docker compose up -d
echo "Waiting for the container to be ready..."
sleep 10
else
running_image=$(docker inspect --format='{{index .Config.Image}}' "$container_id")
if [ "$running_image" != "appflowy-cloud:$APPFLOWY_CLOUD_VERSION" ]; then
echo "AppFlowy-Cloud is running with an incorrect version. Restarting with the correct version..."
# Remove all containers if any exist
if [ "$(docker ps -aq)" ]; then
docker rm -f $(docker ps -aq)
else
echo "No containers to remove."
fi
# Remove all volumes if any exist
if [ "$(docker volume ls -q)" ]; then
docker volume rm $(docker volume ls -q)
else
echo "No volumes to remove."
fi
docker compose pull
docker compose up -d
echo "Waiting for the container to be ready..."
sleep 10
docker ps -a
docker compose logs
else
echo "AppFlowy-Cloud is running with the correct version."
fi
fi
- name: Checkout source code
uses: actions/checkout@v4
@@ -274,7 +308,7 @@ jobs:
sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub
sudo wget -qO /etc/apt/sources.list.d/dart_stable.list https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list
sudo apt-get update
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev libmpv-dev mpv
sudo apt-get install -y dart curl build-essential libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev
shell: bash
- name: Enable Flutter Desktop
@@ -302,96 +336,30 @@ jobs:
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
sudo apt-get install network-manager
docker ps -a
flutter test integration_test/cloud/cloud_runner.dart -d Linux --coverage
flutter test integration_test/desktop/cloud/cloud_runner.dart -d Linux --coverage
shell: bash
# split the integration tests into different machines to minimize the time
integration_test_1:
needs: [ prepare-linux ]
integration_test:
needs: [prepare-linux]
if: github.event.pull_request.draft != true
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest ]
os: [ubuntu-latest]
test_number: [1, 2, 3, 4, 5, 6, 7, 8]
include:
- os: ubuntu-latest
target: 'x86_64-unknown-linux-gnu'
target: "x86_64-unknown-linux-gnu"
runs-on: ${{ matrix.os }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Install video dependency
run: |
sudo apt-get update
sudo apt-get -y install libmpv-dev mpv
shell: bash
- name: Flutter Integration Test 1
- name: Flutter Integration Test ${{ matrix.test_number }}
uses: ./.github/actions/flutter_integration_test
with:
test_path: integration_test/desktop_runner_1.dart
test_path: integration_test/desktop_runner_${{ matrix.test_number }}.dart
flutter_version: ${{ env.FLUTTER_VERSION }}
rust_toolchain: ${{ env.RUST_TOOLCHAIN }}
cargo_make_version: ${{ env.CARGO_MAKE_VERSION }}
rust_target: ${{ matrix.target }}
integration_test_2:
needs: [ prepare-linux ]
if: github.event.pull_request.draft != true
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest ]
include:
- os: ubuntu-latest
target: 'x86_64-unknown-linux-gnu'
runs-on: ${{ matrix.os }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Install video dependency
run: |
sudo apt-get update
sudo apt-get -y install libmpv-dev mpv
shell: bash
- name: Flutter Integration Test 2
uses: ./.github/actions/flutter_integration_test
with:
test_path: integration_test/desktop_runner_2.dart
flutter_version: ${{ env.FLUTTER_VERSION }}
rust_toolchain: ${{ env.RUST_TOOLCHAIN }}
cargo_make_version: ${{ env.CARGO_MAKE_VERSION }}
rust_target: ${{ matrix.target }}
integration_test_3:
needs: [ prepare-linux ]
if: github.event.pull_request.draft != true
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest ]
include:
- os: ubuntu-latest
target: 'x86_64-unknown-linux-gnu'
runs-on: ${{ matrix.os }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Install video dependency
run: |
sudo apt-get update
sudo apt-get -y install libmpv-dev mpv
shell: bash
- name: Flutter Integration Test 3
uses: ./.github/actions/flutter_integration_test
with:
test_path: integration_test/desktop_runner_3.dart
flutter_version: ${{ env.FLUTTER_VERSION }}
rust_toolchain: ${{ env.RUST_TOOLCHAIN }}
cargo_make_version: ${{ env.CARGO_MAKE_VERSION }}
rust_target: ${{ matrix.target }}
+33 -19
View File
@@ -21,27 +21,43 @@ on:
env:
FLUTTER_VERSION: "3.22.0"
RUST_TOOLCHAIN: "1.77.2"
RUST_TOOLCHAIN: "1.80.1"
CLOUD_VERSION: 0.6.51
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build:
if: github.event.pull_request.draft != true
strategy:
fail-fast: true
matrix:
os: [ macos-14 ]
runs-on: ${{ matrix.os }}
build-self-hosted:
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: self-hosted
steps:
- name: Checkout source code
uses: actions/checkout@v2
- name: Build AppFlowy
working-directory: frontend
run: |
cargo make --profile development-ios-arm64-sim appflowy-core-dev-ios
cargo make --profile development-ios-arm64-sim code_generation
- uses: futureware-tech/simulator-action@v3
id: simulator-action
with:
model: "iPhone 15"
shutdown_after_job: false
integration-tests:
if: github.event.pull_request.head.repo.full_name != github.repository
runs-on: macos-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Install Rust toolchain
id: rust_toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
@@ -49,8 +65,7 @@ jobs:
override: true
profile: minimal
- name: Install flutter
id: flutter
- name: Install Flutter
uses: subosito/flutter-action@v2
with:
channel: "stable"
@@ -59,13 +74,13 @@ jobs:
- uses: Swatinem/rust-cache@v2
with:
prefix-key: ${{ matrix.os }}
prefix-key: macos-latest
workspaces: |
frontend/rust-lib
- uses: davidB/rust-cargo-make@v1
with:
version: "0.36.6"
version: "0.37.15"
- name: Install prerequisites
working-directory: frontend
@@ -82,11 +97,11 @@ jobs:
cargo make --profile development-ios-arm64-sim appflowy-core-dev-ios
cargo make --profile development-ios-arm64-sim code_generation
- uses: futureware-tech/simulator-action@v3
id: simulator-action
with:
model: 'iPhone 15'
shutdown_after_job: false
# - uses: futureware-tech/simulator-action@v3
# id: simulator-action
# with:
# model: "iPhone 15"
# shutdown_after_job: false
# - name: Run AppFlowy on simulator
# working-directory: frontend/appflowy_flutter
@@ -97,7 +112,6 @@ jobs:
# kill $pid
# continue-on-error: true
# enable it again if the 12 mins timeout is fixed
# - name: Run integration tests
# working-directory: frontend/appflowy_flutter
# run: flutter test integration_test/runner.dart -d ${{ steps.simulator-action.outputs.udid }}
+30 -12
View File
@@ -135,7 +135,7 @@ jobs:
fail-fast: false
matrix:
job:
- { target: x86_64-apple-darwin, os: macos-11, extra-build-args: "" }
- { target: x86_64-apple-darwin, os: macos-12, extra-build-args: "" }
steps:
- name: Checkout source code
uses: actions/checkout@v4
@@ -232,10 +232,10 @@ jobs:
matrix:
job:
- {
targets: "aarch64-apple-darwin,x86_64-apple-darwin",
os: macos-11,
extra-build-args: "",
}
targets: "aarch64-apple-darwin,x86_64-apple-darwin",
os: macos-latest,
extra-build-args: "",
}
steps:
- name: Checkout source code
uses: actions/checkout@v4
@@ -336,12 +336,12 @@ jobs:
matrix:
job:
- {
arch: x86_64,
target: x86_64-unknown-linux-gnu,
os: ubuntu-20.04,
extra-build-args: "",
flutter_profile: production-linux-x86_64,
}
arch: x86_64,
target: x86_64-unknown-linux-gnu,
os: ubuntu-20.04,
extra-build-args: "",
flutter_profile: production-linux-x86_64,
}
steps:
- name: Checkout source code
uses: actions/checkout@v4
@@ -368,7 +368,7 @@ jobs:
sudo apt-get update
sudo apt-get install -y build-essential libsqlite3-dev libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev
sudo apt-get install keybinder-3.0
sudo apt-get install -y alien libnotify-dev libmpv-dev mpv
sudo apt-get install -y alien libnotify-dev
source $HOME/.cargo/env
cargo install --force cargo-make
cargo install --force duckscript_cli
@@ -479,6 +479,24 @@ jobs:
cache-from: type=registry,ref=${{ secrets.DOCKER_HUB_USERNAME }}/af_build_cache:buildcache
cache-to: type=registry,ref=${{ secrets.DOCKER_HUB_USERNAME }}/af_build_cache:buildcache,mode=max
notify-failure:
runs-on: ubuntu-latest
needs:
- build-for-macOS-x86_64
- build-for-windows
- build-for-linux
if: failure()
steps:
- uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
text: |
🔴🔴🔴Workflow ${{ github.workflow }} in repository ${{ github.repository }} was failed 🔴🔴🔴.
fields: repo,message,author,eventName,ref,workflow
env:
SLACK_WEBHOOK_URL: ${{ secrets.RELEASE_SLACK_WEBHOOK }}
if: always()
notify-discord:
runs-on: ubuntu-latest
needs:
+135 -48
View File
@@ -8,6 +8,7 @@ on:
- "release/*"
paths:
- "frontend/rust-lib/**"
- ".github/workflows/rust_ci.yaml"
pull_request:
branches:
@@ -19,73 +20,58 @@ on:
env:
CARGO_TERM_COLOR: always
CLOUD_VERSION: 0.6.51-amd64
RUST_TOOLCHAIN: "1.77.2"
jobs:
test-on-ubuntu:
runs-on: ubuntu-latest
self-hosted-job:
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: self-hosted
steps:
# - name: Maximize build space
# uses: easimon/maximize-build-space@master
# with:
# root-reserve-mb: 2048
# swap-size-mb: 1024
# remove-dotnet: 'true'
# # the following step is required to avoid running out of space
# - name: Maximize build space
# run: |
# sudo rm -rf /usr/share/dotnet
# sudo rm -rf /opt/ghc
# sudo rm -rf "/usr/local/share/boost"
# sudo rm -rf "$AGENT_TOOLSDIRECTORY"
# sudo docker image prune --all --force
- name: Checkout source code
uses: actions/checkout@v4
- name: Install Rust toolchain
id: rust_toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
override: true
components: rustfmt, clippy
profile: minimal
- name: Install prerequisites
working-directory: frontend
run: |
cargo install --force cargo-make
cargo install --force duckscript_cli
- uses: Swatinem/rust-cache@v2
with:
prefix-key: "ubuntu-latest"
workspaces: |
frontend/rust-lib
- name: Checkout appflowy cloud code
- name: Checkout Appflowy Cloud
uses: actions/checkout@v4
with:
repository: AppFlowy-IO/AppFlowy-Cloud
path: AppFlowy-Cloud
- name: Prepare appflowy cloud env
- name: Prepare Appflowy Cloud env
working-directory: AppFlowy-Cloud
run: |
# log level
cp deploy.env .env
sed -i 's|RUST_LOG=.*|RUST_LOG=trace|' .env
sed -i 's|API_EXTERNAL_URL=.*|API_EXTERNAL_URL=http://localhost|' .env
sed -i '' 's|RUST_LOG=.*|RUST_LOG=trace|' .env
sed -i '' 's|API_EXTERNAL_URL=.*|API_EXTERNAL_URL=http://localhost|' .env
- name: Run Docker-Compose
- name: Ensure AppFlowy-Cloud is Running with Correct Version
working-directory: AppFlowy-Cloud
env:
BACKEND_VERSION: 0.3.24-amd64
APPFLOWY_CLOUD_VERSION: ${{ env.CLOUD_VERSION }}
APPFLOWY_HISTORY_VERSION: ${{ env.CLOUD_VERSION }}
APPFLOWY_WORKER_VERSION: ${{ env.CLOUD_VERSION }}
run: |
docker pull appflowyinc/appflowy_cloud:latest
docker compose up -d
container_id=$(docker ps --filter name=appflowy-cloud-appflowy_cloud-1 -q)
if [ -z "$container_id" ]; then
echo "AppFlowy-Cloud container is not running. Pulling and starting the container..."
docker compose pull
docker compose up -d
echo "Waiting for the container to be ready..."
sleep 10
else
running_image=$(docker inspect --format='{{index .Config.Image}}' "$container_id")
if [ "$running_image" != "appflowy-cloud:$APPFLOWY_CLOUD_VERSION" ]; then
echo "AppFlowy-Cloud is running with an incorrect version. Pulling the correct version..."
docker compose pull
docker compose up -d
echo "Waiting for the container to be ready..."
sleep 10
docker ps -a
docker compose logs
else
echo "AppFlowy-Cloud is running with the correct version."
fi
fi
- name: Run rust-lib tests
working-directory: frontend/rust-lib
@@ -106,6 +92,107 @@ jobs:
run: cargo clippy --all-targets -- -D warnings
working-directory: frontend/rust-lib
ubuntu-job:
if: github.event.pull_request.head.repo.full_name != github.repository
runs-on: ubuntu-latest
steps:
- name: Set timezone for action
uses: szenius/set-timezone@v2.0
with:
timezoneLinux: "US/Pacific"
- name: Maximize build space
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /opt/ghc
sudo rm -rf "/usr/local/share/boost"
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
sudo docker image prune --all --force
- name: Checkout source code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
override: true
components: rustfmt, clippy
profile: minimal
- uses: Swatinem/rust-cache@v2
with:
prefix-key: ${{ runner.os }}
cache-on-failure: true
workspaces: |
frontend/rust-lib
- name: Checkout appflowy cloud code
uses: actions/checkout@v4
with:
repository: AppFlowy-IO/AppFlowy-Cloud
path: AppFlowy-Cloud
- name: Prepare appflowy cloud env
working-directory: AppFlowy-Cloud
run: |
cp deploy.env .env
sed -i 's|RUST_LOG=.*|RUST_LOG=trace|' .env
sed -i 's|GOTRUE_MAILER_AUTOCONFIRM=.*|GOTRUE_MAILER_AUTOCONFIRM=true|' .env
sed -i 's|API_EXTERNAL_URL=.*|API_EXTERNAL_URL=http://localhost|' .env
- name: Ensure AppFlowy-Cloud is Running with Correct Version
working-directory: AppFlowy-Cloud
env:
APPFLOWY_CLOUD_VERSION: ${{ env.CLOUD_VERSION }}
APPFLOWY_HISTORY_VERSION: ${{ env.CLOUD_VERSION }}
APPFLOWY_WORKER_VERSION: ${{ env.CLOUD_VERSION }}
run: |
# Remove all containers if any exist
if [ "$(docker ps -aq)" ]; then
docker rm -f $(docker ps -aq)
else
echo "No containers to remove."
fi
# Remove all volumes if any exist
if [ "$(docker volume ls -q)" ]; then
docker volume rm $(docker volume ls -q)
else
echo "No volumes to remove."
fi
docker compose pull
docker compose up -d
echo "Waiting for the container to be ready..."
sleep 10
docker ps -a
docker compose logs
- name: Run rust-lib tests
working-directory: frontend/rust-lib
env:
RUST_LOG: info
RUST_BACKTRACE: 1
af_cloud_test_base_url: http://localhost
af_cloud_test_ws_url: ws://localhost/ws/v1
af_cloud_test_gotrue_url: http://localhost/gotrue
run: |
DISABLE_CI_TEST_LOG="true" cargo test --no-default-features --features="dart"
- name: rustfmt rust-lib
run: cargo fmt --all -- --check
working-directory: frontend/rust-lib/
- name: clippy rust-lib
run: cargo clippy --all-targets -- -D warnings
working-directory: frontend/rust-lib
- name: "Debug: show Appflowy-Cloud container logs"
if: failure()
working-directory: AppFlowy-Cloud
run: |
docker compose logs appflowy_cloud
- name: Clean up Docker images
run: |
docker image prune -af
+39 -28
View File
@@ -1,4 +1,5 @@
name: Tauri-CI
on:
pull_request:
paths:
@@ -11,28 +12,47 @@ env:
NODE_VERSION: "18.16.0"
PNPM_VERSION: "8.5.0"
RUST_TOOLCHAIN: "1.77.2"
CARGO_MAKE_VERSION: "0.36.6"
CI: true
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
tauri-build:
if: github.event.pull_request.draft != true
strategy:
fail-fast: false
matrix:
platform: [ ubuntu-20.04 ]
# tauri-build-self-hosted:
# if: github.event.pull_request.head.repo.full_name == github.repository
# runs-on: self-hosted
#
# steps:
# - uses: actions/checkout@v4
# - name: install frontend dependencies
# working-directory: frontend/appflowy_web_app
# run: |
# mkdir dist
# pnpm install
# cd src-tauri && cargo build
#
# - name: test and lint
# working-directory: frontend/appflowy_web_app
# run: |
# pnpm run lint:tauri
#
# - uses: tauri-apps/tauri-action@v0
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# with:
# tauriScript: pnpm tauri
# projectPath: frontend/appflowy_web_app
# args: "--debug"
runs-on: ${{ matrix.platform }}
tauri-build-ubuntu:
#if: github.event.pull_request.head.repo.full_name != github.repository
runs-on: ubuntu-20.04
env:
CI: true
steps:
- uses: actions/checkout@v4
- name: Maximize build space (ubuntu only)
if: matrix.platform == 'ubuntu-20.04'
- name: Maximize build space
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /opt/ghc
@@ -61,36 +81,27 @@ jobs:
override: true
profile: minimal
- name: Rust cache
uses: swatinem/rust-cache@v2
with:
workspaces: "./frontend/appflowy_web_app/src-tauri -> target"
- name: Node_modules cache
uses: actions/cache@v2
with:
path: frontend/appflowy_web_app/node_modules
key: node-modules-${{ runner.os }}
- name: install dependencies (windows only)
if: matrix.platform == 'windows-latest'
working-directory: frontend
run: |
cargo install --force duckscript_cli
vcpkg integrate install
- name: install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-20.04'
- name: install dependencies
working-directory: frontend
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
- name: install cargo-make
- uses: taiki-e/install-action@v2
with:
tool: cargo-make@${{ env.CARGO_MAKE_VERSION }}
- name: install tauri deps tools
working-directory: frontend
run: |
cargo install --force cargo-make
cargo make appflowy-tauri-deps-tools
shell: bash
- name: install frontend dependencies
working-directory: frontend/appflowy_web_app
-83
View File
@@ -1,83 +0,0 @@
name: WEB-CI
on:
workflow_dispatch:
inputs:
build:
description: 'Build the web app'
required: true
default: 'true'
env:
CARGO_TERM_COLOR: always
NODE_VERSION: "18.16.0"
PNPM_VERSION: "8.5.0"
RUST_TOOLCHAIN: "1.77.2"
CARGO_MAKE_VERSION: "0.36.6"
jobs:
web-build:
if: github.event.pull_request.draft != true
strategy:
fail-fast: false
matrix:
platform: [ ubuntu-latest ]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
- name: setup node
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Cache Rust Dependencies
uses: Swatinem/rust-cache@v2
with:
key: rust-dependencies-${{ runner.os }}
workspaces: |
frontend/rust-lib
frontend/appflowy_web/appflowy_wasm
# TODO: Can combine caching deps and node_modules in one
# See Glob patterns: https://github.com/actions/toolkit/tree/main/packages/glob
- name: Cache Node.js dependencies
uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ runner.os }}
- name: Cache node_modules
uses: actions/cache@v4
with:
path: frontend/appflowy_web/node_modules
key: node-modules-${{ runner.os }}
- name: Install Rust toolchain
id: rust_toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
override: true
profile: minimal
- name: Install wasm-pack
run: cargo install wasm-pack
- uses: taiki-e/install-action@v2
with:
tool: cargo-make@${{ env.CARGO_MAKE_VERSION }}
- name: install dependencies
if: matrix.platform == 'ubuntu-latest'
working-directory: frontend
run: |
sudo apt-get update
npm install -g pnpm@${{ env.PNPM_VERSION }}
cargo make install_web_protobuf
- name: Build
working-directory: frontend/appflowy_web
run: |
pnpm install
pnpm run build_release_wasm
+11 -5
View File
@@ -6,6 +6,7 @@ on:
- ".github/workflows/web2_ci.yaml"
- "frontend/appflowy_web_app/**"
- "frontend/resources/**"
env:
NODE_VERSION: "18.16.0"
PNPM_VERSION: "8.5.0"
@@ -52,8 +53,13 @@ jobs:
run: |
pnpm run test:unit
- name: Generate and post coverage summary
working-directory: frontend/appflowy_web_app
run: |
pnpm run merge-coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v2
with:
token: cf9245e0-e136-4e21-b0ee-35755fa0c493
files: frontend/appflowy_web_app/coverage/jest/lcov.info,frontend/appflowy_web_app/coverage/cypress/lcov.info
flags: appflowy_web_app
name: frontend/appflowy_web_app
fail_ci_if_error: true
verbose: true
+162
View File
@@ -1,4 +1,166 @@
# Release Notes
## Version 0.7.2 - 22/10/2024
### New Features
- Copy link to block
- Support turn into in document
- Enable sharing links and publishing pages on mobile
- Enable drag and drop in row documents
- Right-click on page in sidebar to open more actions
- Create new subpage in document using `+` character
- Allow reordering checklist item
### Bug Fixes
- Fixed issue with inability to cancel inline code format in French IME
- Fixed delete with Shift or Ctrl shortcuts not working in documents
- Fixed the issues with incorrect time zone being used in filters.
## Version 0.7.1 - 07/10/2024
### New Features
- Copy link to share and open it in a browser
- Enable the ability to edit the page title within the body of the document
- Filter by last modified, created at, or a date range
- Allow customization of database property icons
- Support CTRL/CMD+X to delete the current line when the selection is collapsed in the document
- Support window tiling on macOS
- Add filters to grid views on mobile
- Create and manage workspaces on mobile
- Automatically convert property types for imported CSV files
### Bug Fixes
- Fixed calculations with filters applied
- Fixed issues with importing data folders into a cloud account
- Fixed French IME backtick issues
- Fixed selection gesture bugs on mobile
## Version 0.7.0 - 19/09/2024
### New Features
- Support reordering blocks in document with drag and drop
- Support for adding a cover to a row/card in databases
- Added support for accessing settings on the sign-in page
- Added "Move to" option to the document menu in top right corner
- Support for adjusting the document width from settings
- Show full name of a group on hover
- Colored group names in kanban boards
- Support "Ask AI" on multiple lines of text
- Support for keyboard gestures to move cursor on Mobile
- Added markdown support for quickly inserting a code block using three backticks
### Bug Fixes
- Fixed a critical bug where the backtick character would crash the application
- Fixed an issue with signing-in from the settings dialog where the dialog would persist
- Fixed a visual bug with icon alignment in primary cell of database rows
- Fixed a bug with filters applied where new rows were inserted in wrong position
- Fixed a bug where "Untitled" would override the name of the row
- Fixed page title not updating after renaming from "More"-menu
- Fixed File block breaking row detail document
- Fixed issues with reordering rows with sorting rules applied
- Improvements to the File & Media type in Database
- Performance improvement in Grid view
- Fixed filters sometimes not applying properly in databases
## Version 0.6.9 - 09/09/2024
### New Features
- Added a new property type, 'Files & media'
- Supported Apple Sign-in
- Displayed the page icon next to the row name when the row page contains nested notes
- Enabled Delete Account in Settings
- Included a collapsible navigation menu in your published site
### Bug Fixes
- Fixed the space name color issue in the community themes
- Fixed database filters and sorting issues
- Fixed the issue of not being able to fully display the title on Kanban cards
- Fixed the inability to see the entire text of a checklist item when it's more than one line long
- Fixed hide/unhide buttons in the No Status group
- Fixed the inability to edit group names on Kanban boards
- Made error codes more user-friendly
- Added leading zeros to day and month in date format
## Version 0.6.8 - 22/08/2024
### New Features
- Enabled viewing data inside a database record on mobile.
- Added the ability to invite members to a workspace on mobile.
- Introduced Ask AI in the Home tab on mobile.
- Import CSV files with up to 1,000 rows.
- Convert properties from one type to another while preserving the data.
- Optimized the speed of opening documents and databases.
- Improved syncing performance across devices.
- Added support for a monochrome app icon on Android.
### Bug Fixes
- Removed the Wayland header from the AppImage build.
- Fixed the issue where pasting a web image on mobile failed.
- Corrected the Local AI state when switching between different workspaces.
- Fixed high CPU usage when opening large databases.
## Version 0.6.7 - 13/08/2024
### New Features
- Redesigned the icon picker design on Desktop.
- Redesigned the notification page on Mobile.
### Bug Fixes
- Enhance the toolbar tooltip functionality on Desktop.
- Enhance the slash menu user experience on Desktop.
- Fixed the issue where list style overrides occurred during text pasting.
- Fixed the issue where linking multiple databases in the same document could cause random loss of focus.
## Version 0.6.6 - 30/07/2024
### New Features
- Upgrade your workspace to a premium plan to unlock more features and storage.
- Image galleries and drag-and-drop image support in documents.
### Bug Fixes
- Fix minor UI issues on Desktop and Mobile.
## Version 0.6.5 - 24/07/2024
### New Features
- Publish a Database to the Web
## Version 0.6.4 - 16/07/2024
### New Features
- Enhanced the message style on the AI chat page.
- Added the ability to choose cursor color and selection color from a palette in settings page.
### Bug Fixes
- Optimized the performance for loading recent pages.
- Fixed an issue where the cursor would jump randomly when typing in the document title on mobile.
## Version 0.6.3 - 08/07/2024
### New Features
- Publish a Document to the Web
## Version 0.6.2 - 01/07/2024
### New Features
- Added support for duplicating spaces.
- Added support for moving pages across spaces.
- Undo markdown formatting with `Ctrl + Z` or `Cmd + Z`.
- Improved shortcuts settings UI.
### Bug Fixes
- Fixed unable to zoom in with `Ctrl` and `+` or `Cmd` and `+` on some keyboards.
- Fixed unable to paste nested lists in existing lists.
## Version 0.6.1 - 22/06/2024
### New Features
- Introduced the "Space" feature to help you organize your pages more efficiently.
### Bug Fixes
- Resolved shortcut conflicts on the board page.
- Resolved an issue where underscores could cause the editor to freeze.
## Version 0.6.0 - 19/06/2024
### New Features
- Introduced the "Space" feature to help you organize your pages more efficiently.
### Bug Fixes
- Resolved shortcut conflicts on the board page.
- Resolved an issue where underscores could cause the editor to freeze.
## Version 0.5.9 - 06/06/2024
### New Features
- Revamped the sidebar for both Desktop and Mobile.
- Added support for embedding videos in documents.
- Introduced a hotkey (Cmd/Ctrl + 0) to reset the app scale.
- Supported searching the workspace by page title.
### Bug Fixes
- Fixed the issue preventing the use of Backspace to delete words in Kanban boards.
## Version 0.5.8 - 05/20/2024
### New Features
- Improvement to the Callout block to insert new lines
+23 -9
View File
@@ -6,7 +6,7 @@
</h1>
<p align="center">
You are in charge of your data and customizations.
AppFlowy is the AI workspace where you achieve more without losing control of your data
</p>
<p align="center">
@@ -19,20 +19,34 @@ You are in charge of your data and customizations.
<p align="center">
<a href="https://www.appflowy.io"><b>Website</b></a> •
<a href="https://forum.appflowy.io/"><b>Forum</b></a> •
<a href="https://discord.gg/9Q2xaN37tV"><b>Discord</b></a> •
<a href="https://www.reddit.com/r/AppFlowy"><b>Reddit</b></a> •
<a href="https://twitter.com/appflowy"><b>Twitter</b></a>
</p>
<p align="center"><img src="https://user-images.githubusercontent.com/12026239/236664610-fc209a97-815e-4716-af07-d94a859d1907.png" alt="AppFlowy Docs & Notes & Wikis" width="1000px" /></p>
<p align="center"><img src="https://user-images.githubusercontent.com/12026239/236664628-5def2450-914a-4b2d-b907-92b7476b9863.png" alt="AppFlowy Databases for Tasks and Projects" width="1000px" /></p>
<p align="center"><img src="https://user-images.githubusercontent.com/12026239/236664642-22e26c1b-5eae-4635-9aa6-b12ecf1c3c46.png" alt="AppFlowy Kanban Board for To-Dos" width="1000px" /></p>
<p align="center"><img src="https://github.com/AppFlowy-IO/AppFlowy/assets/12026239/6be93d2b-a5c5-48a9-b7cf-c599d5f5140c" alt="AppFlowy Calendars for Plan and Manage Content" width="1000px" /></p>
<p align="center"><img src="https://user-images.githubusercontent.com/12026239/236664657-dc5291f3-67b0-4a43-a818-640e92735deb.png" alt="AppFlowy OpenAI GPT Writers" width="1000px" /></p>
<p align="center"><img src="https://appflowy.io/_next/static/media/tasks.796c753e.png" alt="AppFlowy Kanban Board for To-dos" /></p>
<p align="center"><img src="https://appflowy.io/_next/static/media/Grid.9e30484b.png" alt="AppFlowy Databases for Tasks and Projects" /></p>
<p align="center"><img src="https://appflowy.io/_next/static/media/sites.a8d5b2b9.png" alt="AppFlowy Sites for Beautiful documentation" /></p>
<p align="center"><img src="https://appflowy.io/_next/static/media/ai.e1460982.png" alt="AppFlowy AI" /></p>
<p align="center"><img src="https://appflowy.io/_next/static/media/template.9ea13c3b.png" alt="AppFlowy Templates" /></p>
<br></br>
<p align="center" >
<img src="https://github.com/user-attachments/assets/5841c491-b564-4a26-b9b6-191def430911" alt="Work across devices" width="1040px" /></p>
<p align="center" >
<img src="https://github.com/user-attachments/assets/c2ba6bb8-746c-4743-9393-d008a669be95" alt="Work across devices" width="1040px" /></p>
<p align="center" >
<img src="https://github.com/user-attachments/assets/e83dd1a3-4975-4d0e-91a1-9eb6e0d248cd" alt="Work across devices" width="1040px" /></p>
## User Installation
- [Windows/Mac/Linux](https://docs.appflowy.io/docs/appflowy/install-appflowy/installation-methods/mac-windows-linux-packages)
- [Docker](https://docs.appflowy.io/docs/appflowy/install-appflowy/installation-methods/installing-with-docker)
- [Download AppFlowy Desktop (macOS, Windows, and Linux)](https://github.com/AppFlowy-IO/AppFlowy/releases)
- Other channels: [FlatHub](https://flathub.org/apps/io.appflowy.AppFlowy), [Snapcraft](https://snapcraft.io/appflowy), [Sourceforge](https://sourceforge.net/projects/appflowy/)
- Available on
- [App Store](https://apps.apple.com/app/appflowy/id6457261352): iPhone
- [Play Store](https://play.google.com/store/apps/details?id=io.appflowy.appflowy): Android 10 or above; ARMv7 is not supported
- [Self-hosting AppFlowy](https://docs.appflowy.io/docs/guides/appflowy/self-hosting-appflowy)
- [Source](https://docs.appflowy.io/docs/documentation/appflowy/from-source)
## Built With
@@ -105,7 +119,7 @@ We do not claim to outperform Notion in terms of functionality and design, at le
Distributed under the AGPLv3 License. See [`LICENSE.md`](https://github.com/AppFlowy-IO/AppFlowy/blob/main/LICENSE) for more information.
## Acknowledgements
## Acknowledgments
Special thanks to these amazing projects which help power AppFlowy.IO:
Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

+1 -2
View File
@@ -13,7 +13,6 @@
"type": "dart",
"env": {
"RUST_LOG": "debug",
"RUST_BACKTRACE": "1"
},
// uncomment the following line to testing performance.
// "flutterMode": "profile",
@@ -138,4 +137,4 @@
"cwd": "${workspaceRoot}/appflowy_tauri/"
},
]
}
}
+1 -2
View File
@@ -26,7 +26,7 @@ CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
CARGO_MAKE_CRATE_FS_NAME = "dart_ffi"
CARGO_MAKE_CRATE_NAME = "dart-ffi"
LIB_NAME = "dart_ffi"
APPFLOWY_VERSION = "0.5.9"
APPFLOWY_VERSION = "0.7.3"
FLUTTER_DESKTOP_FEATURES = "dart"
PRODUCT_NAME = "AppFlowy"
MACOSX_DEPLOYMENT_TARGET = "11.0"
@@ -50,7 +50,6 @@ APP_ENVIRONMENT = "local"
FLUTTER_FLOWY_SDK_PATH = "appflowy_flutter/packages/appflowy_backend"
TAURI_BACKEND_SERVICE_PATH = "appflowy_tauri/src/services/backend"
WEB_BACKEND_SERVICE_PATH = "appflowy_web/src/services/backend"
WEB_LIB_PATH = "appflowy_web/wasm-libs/af-wasm"
TAURI_APP_BACKEND_SERVICE_PATH = "appflowy_web_app/src/application/services/tauri-services/backend"
# Test default config
TEST_CRATE_TYPE = "cdylib"
@@ -1,13 +1,3 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
analyzer:
@@ -16,17 +6,6 @@ analyzer:
- "**/*.freezed.dart"
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
- require_trailing_commas
@@ -51,8 +30,5 @@ linter:
- sort_constructors_first
- unawaited_futures
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
errors:
invalid_annotation_target: ignore
@@ -52,8 +52,8 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "io.appflowy.appflowy"
minSdkVersion 23
targetSdkVersion 33
minSdkVersion 29
targetSdkVersion 34
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
multiDexEnabled true
@@ -87,6 +87,13 @@ android {
path "src/main/CMakeLists.txt"
}
}
// only support arm64-v8a
defaultConfig {
ndk {
abiFilters "arm64-v8a"
}
}
}
flutter {
Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/black" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background" />
<foreground
android:drawable="@mipmap/ic_launcher_foreground" />
<monochrome
android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FFFFFF</color>
</resources>
@@ -0,0 +1 @@
{ "artificial_intelligence": [ { "name": "ai-chip-spark", "keywords": [ "chip", "processor", "artificial", "intelligence", "ai" ], "content": "<svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<g clip-path=\"url(#clip0_1068_189544)\">\n<path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M8.71468 0.0400391C9.1289 0.0400391 9.46468 0.375825 9.46468 0.790039V1.97754H10.4999C11.3283 1.97754 11.9999 2.64911 11.9999 3.47754V4.51367H13.2186C13.6328 4.51367 13.9686 4.84946 13.9686 5.26367C13.9686 5.67789 13.6328 6.01367 13.2186 6.01367H11.9999V7.94324H13.2186C13.6328 7.94324 13.9686 8.27902 13.9686 8.69324C13.9686 9.10745 13.6328 9.44324 13.2186 9.44324H11.9999V10.4775C11.9999 11.306 11.3283 11.9775 10.4999 11.9775H9.46468V13.2099C9.46468 13.6241 9.1289 13.9599 8.71468 13.9599C8.30047 13.9599 7.96468 13.6241 7.96468 13.2099V11.9775H6.03524V13.2099C6.03524 13.6241 5.69945 13.9599 5.28524 13.9599C4.87103 13.9599 4.53524 13.6241 4.53524 13.2099V11.9775H3.49984C2.67141 11.9775 1.99984 11.306 1.99984 10.4775V9.44324H0.783203C0.368989 9.44324 0.0332031 9.10745 0.0332031 8.69324C0.0332031 8.27902 0.368989 7.94324 0.783203 7.94324H1.99984V6.01367H0.783203C0.368989 6.01367 0.0332031 5.67789 0.0332031 5.26367C0.0332031 4.84946 0.368989 4.51367 0.783203 4.51367H1.99984V3.47754C1.99984 2.64911 2.67141 1.97754 3.49984 1.97754H4.53524V0.790039C4.53524 0.375825 4.87103 0.0400391 5.28524 0.0400391C5.69945 0.0400391 6.03524 0.375825 6.03524 0.790039V1.97754H7.96468V0.790039C7.96468 0.375825 8.30047 0.0400391 8.71468 0.0400391ZM6.24357 4.5682C6.41951 3.76446 7.56392 3.75946 7.74688 4.56163L7.75499 4.59732C7.76038 4.62113 7.76543 4.64342 7.7708 4.66628C7.96264 5.48335 8.62389 6.10768 9.45164 6.25169C10.2908 6.39768 10.2908 7.60232 9.45164 7.74831C8.61948 7.89308 7.95559 8.52332 7.76776 9.34682L7.74688 9.43837C7.56392 10.2405 6.41951 10.2355 6.24357 9.4318L6.22638 9.35325C6.04547 8.52684 5.38257 7.89201 4.54911 7.74701C3.71142 7.60128 3.71141 6.39872 4.54911 6.25299C5.37967 6.10849 6.04086 5.47757 6.22447 4.65539L6.23707 4.598L6.24357 4.5682Z\" fill=\"black\"/>\n</g>\n<defs>\n<clipPath id=\"clip0_1068_189544\">\n<rect width=\"14\" height=\"14\" fill=\"white\"/>\n</clipPath>\n</defs>\n</svg>\n" }, { "name": "ai-cloud-spark", "keywords": [ "cloud", "internet", "server", "network", "artificial", "intelligence", "ai" ], "content": "<svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <g clip-path=\"url(#clip0_1068_189529)\">\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M7.88381 0.165291C6.89196 0.0450664 5.88886 0.268505 5.04181 0.798345C4.25349 1.29145 3.64467 2.02219 3.30135 2.88247C2.87262 2.92977 2.45508 3.05187 2.06781 3.24362C1.63324 3.45878 1.24531 3.75744 0.92616 4.12253C0.281611 4.85986 -0.0436335 5.82304 0.0219743 6.80017C0.087582 7.77731 0.538668 8.68836 1.276 9.33291C1.52925 9.55429 1.80913 9.738 2.10708 9.88114C2.23853 9.09496 2.79956 8.38069 3.79016 8.20836C4.35848 8.10949 4.81104 7.67811 4.93736 7.11585L4.96023 7.01146C5.43591 4.83845 8.53 4.82492 9.02466 6.9937L9.03475 7.03814C9.04166 7.06865 9.047 7.09221 9.05244 7.11538C9.18449 7.6778 9.63973 8.10763 10.2096 8.20676C11.2609 8.38966 11.8287 9.18251 11.9131 10.0243C12.2792 9.884 12.6197 9.67707 12.9162 9.41068C13.5042 8.88231 13.878 8.15668 13.9669 7.37119C14.0558 6.58569 13.8536 5.79486 13.3985 5.14845C12.9811 4.55545 12.3775 4.12175 11.6866 3.91417C11.5613 2.99088 11.1436 2.12994 10.4923 1.45901C9.79633 0.742138 8.87567 0.285516 7.88381 0.165291ZM6.18132 7.27876C6.37146 6.41016 7.60823 6.40476 7.80595 7.27166L7.81577 7.3149C7.8225 7.34462 7.82879 7.37239 7.83553 7.4011C8.08204 8.451 8.93171 9.25323 9.99531 9.43826C10.9004 9.59573 10.9004 10.8951 9.99531 11.0525C8.92604 11.2386 8.07299 12.0484 7.83164 13.1065L7.80595 13.2191C7.60823 14.086 6.37146 14.0806 6.18132 13.212L6.16017 13.1154C5.92765 12.0532 5.07564 11.2373 4.0044 11.0509C3.10108 10.8938 3.10107 9.59701 4.0044 9.43986C5.07191 9.25414 5.92172 8.44323 6.15771 7.38648L6.17343 7.31494L6.18132 7.27876Z\"\n fill=\"black\"/>\n </g>\n <defs>\n <clipPath id=\"clip0_1068_189529\">\n <rect width=\"14\" height=\"14\" fill=\"white\"/>\n </clipPath>\n </defs>\n</svg>\n" }, { "name": "ai-edit-spark", "keywords": [ "change", "edit", "modify", "pencil", "write", "writing", "artificial", "intelligence", "ai" ], "content": "<svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<g clip-path=\"url(#clip0_1068_189535)\">\n<path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M2.85637 0.654372C3.04651 -0.214226 4.28328 -0.219632 4.481 0.647271L4.49082 0.690505C4.49756 0.720231 4.50384 0.747995 4.51058 0.776709C4.75709 1.82661 5.60676 2.62884 6.67036 2.81387C7.57548 2.97134 7.57548 4.27068 6.67036 4.42815C5.60109 4.61417 4.74804 5.42398 4.50669 6.48214L4.481 6.59475C4.28328 7.46166 3.04651Line truncated
@@ -0,0 +1,14 @@
"{""id"":""RGmzka"",""name"":""Name"",""field_type"":0,""type_options"":{""0"":{""data"":""""}},""is_primary"":true}","{""id"":""oYoH-q"",""name"":""Time Slot"",""field_type"":2,""type_options"":{""0"":{""date_format"":3,""data"":"""",""time_format"":1,""timezone_id"":""""},""2"":{""date_format"":3,""time_format"":1,""timezone_id"":""""}},""is_primary"":false}","{""id"":""zVrp17"",""name"":""Amount"",""field_type"":1,""type_options"":{""1"":{""scale"":0,""format"":4,""name"":""Number"",""symbol"":""RUB""},""0"":{""data"":"""",""symbol"":""RUB"",""name"":""Number"",""format"":0,""scale"":0}},""is_primary"":false}","{""id"":""_p4EGt"",""name"":""Delta"",""field_type"":1,""type_options"":{""1"":{""name"":""Number"",""format"":36,""symbol"":""RUB"",""scale"":0},""0"":{""data"":"""",""symbol"":""RUB"",""name"":""Number"",""format"":0,""scale"":0}},""is_primary"":false}","{""id"":""Z909lc"",""name"":""Email"",""field_type"":6,""type_options"":{""6"":{""url"":"""",""content"":""""},""0"":{""data"":"""",""content"":"""",""url"":""""}},""is_primary"":false}","{""id"":""dBrSc7"",""name"":""Registration Complete"",""field_type"":5,""type_options"":{""5"":{}},""is_primary"":false}","{""id"":""VoigvK"",""name"":""Progress"",""field_type"":7,""type_options"":{""0"":{""data"":""""},""7"":{}},""is_primary"":false}","{""id"":""gbbQwh"",""name"":""Attachments"",""field_type"":14,""type_options"":{""0"":{""data"":"""",""content"":""{\""files\"":[]}""},""14"":{""content"":""{\""files\"":[]}""}},""is_primary"":false}","{""id"":""id3L0G"",""name"":""Priority"",""field_type"":3,""type_options"":{""3"":{""content"":""{\""options\"":[{\""id\"":\""cplL\"",\""name\"":\""VIP\"",\""color\"":\""Purple\""},{\""id\"":\""GSf_\"",\""name\"":\""High\"",\""color\"":\""Blue\""},{\""id\"":\""qnja\"",\""name\"":\""Medium\"",\""color\"":\""Green\""}],\""disable_color\"":false}""}},""is_primary"":false}","{""id"":""541SFC"",""name"":""Tags"",""field_type"":4,""type_options"":{""0"":{""data"":"""",""content"":""{\""options\"":[],\""disable_color\"":false}""},""4"":{""content"":""{\""options\"":[{\""id\"":\""1i4f\"",\""name\"":\""Education\"",\""color\"":\""Yellow\""},{\""id\"":\""yORP\"",\""name\"":\""Health\"",\""color\"":\""Orange\""},{\""id\"":\""SEUo\"",\""name\"":\""Hobby\"",\""color\"":\""LightPink\""},{\""id\"":\""uRAO\"",\""name\"":\""Family\"",\""color\"":\""Pink\""},{\""id\"":\""R9I7\"",\""name\"":\""Work\"",\""color\"":\""Purple\""}],\""disable_color\"":false}""}},""is_primary"":false}","{""id"":""lg0B7O"",""name"":""Last modified"",""field_type"":8,""type_options"":{""0"":{""time_format"":1,""field_type"":8,""date_format"":3,""data"":"""",""include_time"":true},""8"":{""date_format"":3,""field_type"":8,""time_format"":1,""include_time"":true}},""is_primary"":false}","{""id"":""5riGR7"",""name"":""Created at"",""field_type"":9,""type_options"":{""0"":{""field_type"":9,""include_time"":true,""date_format"":3,""time_format"":1,""data"":""""},""9"":{""include_time"":true,""field_type"":9,""date_format"":3,""time_format"":1}},""is_primary"":false}"
"{""data"":""Olaf"",""created_at"":1726063289,""last_modified"":1726063289,""field_type"":0}","{""last_modified"":1726122374,""created_at"":1726110045,""reminder_id"":"""",""is_range"":true,""include_time"":true,""end_timestamp"":""1725415200"",""field_type"":2,""data"":""1725256800""}","{""field_type"":1,""data"":""55200"",""last_modified"":1726063592,""created_at"":1726063592}","{""last_modified"":1726062441,""created_at"":1726062441,""data"":""0.5"",""field_type"":1}","{""created_at"":1726063719,""last_modified"":1726063732,""data"":""doyouwannabuildasnowman@arendelle.gov"",""field_type"":6}",,"{""field_type"":7,""last_modified"":1726064207,""data"":""{\""options\"":[{\""id\"":\""oqXQ\"",\""name\"":\""find elsa\"",\""color\"":\""Purple\""},{\""id\"":\""eQwp\"",\""name\"":\""find anna\"",\""color\"":\""Purple\""},{\""id\"":\""5-B3\"",\""name\"":\""play in the summertime\"",\""color\"":\""Purple\""},{\""id\"":\""UBFn\"",\""name\"":\""get a personal flurry\"",\""color\"":\""Purple\""}],\""selected_option_ids\"":[\""oqXQ\"",\""eQwp\"",\""UBFn\""]}"",""created_at"":1726064129}",,"{""created_at"":1726065208,""data"":""cplL"",""last_modified"":1726065282,""field_type"":3}","{""field_type"":4,""data"":""1i4f"",""last_modified"":1726105102,""created_at"":1726105102}","{""field_type"":8,""data"":""1726122374""}","{""data"":""1726060476"",""field_type"":9}"
"{""field_type"":0,""last_modified"":1726063323,""data"":""Beatrice"",""created_at"":1726063323}",,"{""last_modified"":1726063638,""data"":""828600"",""created_at"":1726063607,""field_type"":1}","{""field_type"":1,""created_at"":1726062488,""data"":""-2.25"",""last_modified"":1726062488}","{""last_modified"":1726063790,""data"":""btreee17@gmail.com"",""field_type"":6,""created_at"":1726063790}","{""created_at"":1726062718,""data"":""Yes"",""field_type"":5,""last_modified"":1726062724}","{""created_at"":1726064277,""data"":""{\""options\"":[{\""id\"":\""BDuH\"",\""name\"":\""get the leaf node\"",\""color\"":\""Purple\""},{\""id\"":\""GXAr\"",\""name\"":\""upgrade to b+\"",\""color\"":\""Purple\""}],\""selected_option_ids\"":[]}"",""field_type"":7,""last_modified"":1726064293}",,"{""data"":""GSf_"",""created_at"":1726065288,""last_modified"":1726065288,""field_type"":3}","{""created_at"":1726105110,""data"":""yORP,uRAO"",""last_modified"":1726105111,""field_type"":4}","{""data"":""1726105111"",""field_type"":8}","{""field_type"":9,""data"":""1726060476""}"
"{""last_modified"":1726063355,""created_at"":1726063355,""field_type"":0,""data"":""Lancelot""}","{""data"":""1726468159"",""is_range"":true,""end_timestamp"":""1726727359"",""reminder_id"":"""",""include_time"":false,""field_type"":2,""created_at"":1726122403,""last_modified"":1726122559}","{""created_at"":1726063617,""last_modified"":1726063617,""data"":""22500"",""field_type"":1}","{""data"":""11.6"",""last_modified"":1726062504,""field_type"":1,""created_at"":1726062504}","{""field_type"":6,""data"":""sir.lancelot@gmail.com"",""last_modified"":1726063812,""created_at"":1726063812}","{""data"":""No"",""field_type"":5,""last_modified"":1726062724,""created_at"":1726062375}",,,"{""data"":""cplL"",""created_at"":1726065286,""last_modified"":1726065286,""field_type"":3}","{""last_modified"":1726105237,""data"":""SEUo"",""created_at"":1726105237,""field_type"":4}","{""field_type"":8,""data"":""1726122559""}","{""field_type"":9,""data"":""1726060476""}"
"{""data"":""Scotty"",""last_modified"":1726063399,""created_at"":1726063399,""field_type"":0}","{""reminder_id"":"""",""last_modified"":1726122418,""include_time"":true,""data"":""1725868800"",""end_timestamp"":""1726646400"",""created_at"":1726122381,""field_type"":2,""is_range"":true}","{""created_at"":1726063650,""last_modified"":1726063650,""data"":""10900"",""field_type"":1}","{""data"":""0"",""created_at"":1726062581,""last_modified"":1726062581,""field_type"":1}","{""last_modified"":1726063835,""created_at"":1726063835,""field_type"":6,""data"":""scottylikestosing@outlook.com""}","{""data"":""Yes"",""field_type"":5,""created_at"":1726062718,""last_modified"":1726062718}","{""created_at"":1726064309,""data"":""{\""options\"":[{\""id\"":\""Cw0K\"",\""name\"":\""vocal warmup\"",\""color\"":\""Purple\""},{\""id\"":\""nYMo\"",\""name\"":\""mixed voice training\"",\""color\"":\""Purple\""},{\""id\"":\""i-OX\"",\""name\"":\""belting training\"",\""color\"":\""Purple\""}],\""selected_option_ids\"":[\""Cw0K\"",\""nYMo\"",\""i-OX\""]}"",""field_type"":7,""last_modified"":1726064325}","{""last_modified"":1726122911,""created_at"":1726122835,""data"":[""{\""id\"":\""746a741d-98f8-4cc6-b807-a82d2e78c221\"",\""name\"":\""googlelogo_color_272x92dp.png\"",\""url\"":\""https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png\"",\""upload_type\"":\""NetworkMedia\"",\""file_type\"":\""Image\""}"",""{\""id\"":\""cbbab3ee-32ab-4438-a909-3f69f935a8bd\"",\""name\"":\""tL_v571NdZ0.svg\"",\""url\"":\""https://static.xx.fbcdn.net/rsrc.php/y9/r/tL_v571NdZ0.svg\"",\""upload_type\"":\""NetworkMedia\"",\""file_type\"":\""Link\""}""],""field_type"":14}",,"{""data"":""SEUo,yORP"",""field_type"":4,""last_modified"":1726105123,""created_at"":1726105115}","{""data"":""1726122911"",""field_type"":8}","{""data"":""1726060539"",""field_type"":9}"
"{""field_type"":0,""created_at"":1726063405,""last_modified"":1726063421,""data"":""""}",,,"{""last_modified"":1726062625,""field_type"":1,""data"":"""",""created_at"":1726062607}",,"{""data"":""No"",""last_modified"":1726062702,""created_at"":1726062393,""field_type"":5}",,,,,"{""data"":""1726063421"",""field_type"":8}","{""data"":""1726060539"",""field_type"":9}"
"{""field_type"":0,""data"":""Thomas"",""last_modified"":1726063421,""created_at"":1726063421}","{""reminder_id"":"""",""field_type"":2,""data"":""1725627600"",""is_range"":false,""created_at"":1726122583,""last_modified"":1726122593,""end_timestamp"":"""",""include_time"":true}","{""last_modified"":1726063666,""field_type"":1,""data"":""465800"",""created_at"":1726063666}","{""last_modified"":1726062516,""field_type"":1,""created_at"":1726062516,""data"":""-0.03""}","{""field_type"":6,""last_modified"":1726063848,""created_at"":1726063848,""data"":""tfp3827@gmail.com""}","{""field_type"":5,""last_modified"":1726062725,""data"":""Yes"",""created_at"":1726062376}","{""created_at"":1726064344,""data"":""{\""options\"":[{\""id\"":\""D6X8\"",\""name\"":\""brainstorm\"",\""color\"":\""Purple\""},{\""id\"":\""XVN9\"",\""name\"":\""schedule\"",\""color\"":\""Purple\""},{\""id\"":\""nJx8\"",\""name\"":\""shoot\"",\""color\"":\""Purple\""},{\""id\"":\""7Mrm\"",\""name\"":\""edit\"",\""color\"":\""Purple\""},{\""id\"":\""o6vg\"",\""name\"":\""publish\"",\""color\"":\""Purple\""}],\""selected_option_ids\"":[\""D6X8\""]}"",""last_modified"":1726064379,""field_type"":7}",,"{""last_modified"":1726065298,""created_at"":1726065298,""field_type"":3,""data"":""GSf_""}","{""data"":""yORP,SEUo"",""field_type"":4,""last_modified"":1726105229,""created_at"":1726105229}","{""data"":""1726122593"",""field_type"":8}","{""field_type"":9,""data"":""1726060540""}"
"{""data"":""Juan"",""last_modified"":1726063423,""created_at"":1726063423,""field_type"":0}","{""created_at"":1726122510,""reminder_id"":"""",""include_time"":false,""is_range"":true,""last_modified"":1726122515,""data"":""1725604115"",""end_timestamp"":""1725776915"",""field_type"":2}","{""field_type"":1,""created_at"":1726063677,""last_modified"":1726063677,""data"":""93100""}","{""field_type"":1,""data"":""4.86"",""created_at"":1726062597,""last_modified"":1726062597}",,"{""last_modified"":1726062377,""field_type"":5,""data"":""Yes"",""created_at"":1726062377}","{""last_modified"":1726064412,""field_type"":7,""data"":""{\""options\"":[{\""id\"":\""tTDq\"",\""name\"":\""complete onboarding\"",\""color\"":\""Purple\""},{\""id\"":\""E8Ds\"",\""name\"":\""contact support\"",\""color\"":\""Purple\""},{\""id\"":\""RoGN\"",\""name\"":\""get started\"",\""color\"":\""Purple\""}],\""selected_option_ids\"":[\""tTDq\"",\""E8Ds\""]}"",""created_at"":1726064396}",,"{""created_at"":1726065278,""field_type"":3,""data"":""qnja"",""last_modified"":1726065278}","{""data"":""R9I7,yORP,1i4f"",""field_type"":4,""created_at"":1726105126,""last_modified"":1726105127}","{""data"":""1726122515"",""field_type"":8}","{""data"":""1726060541"",""field_type"":9}"
"{""data"":""Alex"",""created_at"":1726063432,""last_modified"":1726063432,""field_type"":0}","{""reminder_id"":"""",""data"":""1725292800"",""include_time"":true,""last_modified"":1726122448,""created_at"":1726122422,""is_range"":true,""end_timestamp"":""1725551940"",""field_type"":2}","{""field_type"":1,""last_modified"":1726063683,""created_at"":1726063683,""data"":""3560""}","{""created_at"":1726062561,""data"":""1.96"",""last_modified"":1726062561,""field_type"":1}","{""last_modified"":1726063952,""created_at"":1726063931,""data"":""al3x1343@protonmail.com"",""field_type"":6}","{""last_modified"":1726062375,""field_type"":5,""created_at"":1726062375,""data"":""Yes""}","{""data"":""{\""options\"":[{\""id\"":\""qNyr\"",\""name\"":\""finish reading book\"",\""color\"":\""Purple\""}],\""selected_option_ids\"":[]}"",""created_at"":1726064616,""last_modified"":1726064616,""field_type"":7}",,"{""data"":""qnja"",""created_at"":1726065272,""last_modified"":1726065272,""field_type"":3}","{""created_at"":1726105180,""last_modified"":1726105180,""field_type"":4,""data"":""R9I7,1i4f""}","{""field_type"":8,""data"":""1726122448""}","{""field_type"":9,""data"":""1726060541""}"
"{""last_modified"":1726063478,""created_at"":1726063436,""field_type"":0,""data"":""Alexander""}",,"{""field_type"":1,""last_modified"":1726063691,""created_at"":1726063691,""data"":""2073""}","{""field_type"":1,""data"":""0.5"",""last_modified"":1726062577,""created_at"":1726062577}","{""last_modified"":1726063991,""field_type"":6,""created_at"":1726063991,""data"":""alexandernotthedra@gmail.com""}","{""field_type"":5,""last_modified"":1726062378,""created_at"":1726062377,""data"":""No""}",,,"{""created_at"":1726065291,""data"":""GSf_"",""last_modified"":1726065291,""field_type"":3}","{""last_modified"":1726105142,""created_at"":1726105133,""data"":""SEUo"",""field_type"":4}","{""field_type"":8,""data"":""1726105142""}","{""field_type"":9,""data"":""1726060542""}"
"{""field_type"":0,""created_at"":1726063454,""last_modified"":1726063454,""data"":""George""}","{""created_at"":1726122467,""end_timestamp"":""1726468070"",""include_time"":false,""is_range"":true,""reminder_id"":"""",""field_type"":2,""data"":""1726295270"",""last_modified"":1726122470}",,,"{""field_type"":6,""data"":""george.aq@appflowy.io"",""last_modified"":1726064104,""created_at"":1726064016}","{""last_modified"":1726062376,""created_at"":1726062376,""field_type"":5,""data"":""Yes""}","{""data"":""{\""options\"":[{\""id\"":\""s_dQ\"",\""name\"":\""bug triage\"",\""color\"":\""Purple\""},{\""id\"":\""-Zfo\"",\""name\"":\""fix bugs\"",\""color\"":\""Purple\""},{\""id\"":\""wsDN\"",\""name\"":\""attend meetings\"",\""color\"":\""Purple\""}],\""selected_option_ids\"":[\""s_dQ\"",\""-Zfo\""]}"",""last_modified"":1726064468,""created_at"":1726064424,""field_type"":7}","{""data"":[""{\""id\"":\""8a77f84d-64e9-4e67-b902-fa23980459ec\"",\""name\"":\""BQdTmxpRI6f.png\"",\""url\"":\""https://static.cdninstagram.com/rsrc.php/v3/ym/r/BQdTmxpRI6f.png\"",\""upload_type\"":\""NetworkMedia\"",\""file_type\"":\""Image\""}""],""field_type"":14,""created_at"":1726122956,""last_modified"":1726122956}","{""field_type"":3,""data"":""qnja"",""created_at"":1726065313,""last_modified"":1726065313}","{""data"":""R9I7,yORP"",""field_type"":4,""last_modified"":1726105198,""created_at"":1726105187}","{""data"":""1726122956"",""field_type"":8}","{""data"":""1726060543"",""field_type"":9}"
"{""field_type"":0,""last_modified"":1726063467,""data"":""Joanna"",""created_at"":1726063467}","{""include_time"":false,""end_timestamp"":""1727072893"",""is_range"":true,""last_modified"":1726122493,""created_at"":1726122483,""data"":""1726554493"",""field_type"":2,""reminder_id"":""""}","{""last_modified"":1726065463,""data"":""16470"",""field_type"":1,""created_at"":1726065463}","{""created_at"":1726062626,""field_type"":1,""last_modified"":1726062626,""data"":""-5.36""}","{""last_modified"":1726064069,""data"":""joannastrawberry29+hello@gmail.com"",""created_at"":1726064069,""field_type"":6}",,"{""field_type"":7,""created_at"":1726064444,""last_modified"":1726064460,""data"":""{\""options\"":[{\""id\"":\""ZxJz\"",\""name\"":\""post on Twitter\"",\""color\"":\""Purple\""},{\""id\"":\""upwi\"",\""name\"":\""watch Youtube videos\"",\""color\"":\""Purple\""}],\""selected_option_ids\"":[\""upwi\""]}""}",,"{""created_at"":1726065317,""last_modified"":1726065317,""field_type"":3,""data"":""qnja""}","{""field_type"":4,""last_modified"":1726105173,""data"":""uRAO,yORP"",""created_at"":1726105170}","{""data"":""1726122493"",""field_type"":8}","{""data"":""1726060545"",""field_type"":9}"
"{""last_modified"":1726063457,""created_at"":1726063457,""data"":""George"",""field_type"":0}","{""include_time"":true,""reminder_id"":"""",""field_type"":2,""is_range"":true,""created_at"":1726122521,""end_timestamp"":""1725829200"",""data"":""1725822900"",""last_modified"":1726122535}","{""last_modified"":1726065493,""field_type"":1,""data"":""9500"",""created_at"":1726065493}","{""last_modified"":1726062680,""created_at"":1726062680,""field_type"":1,""data"":""1.7""}","{""data"":""plgeorgebball@gmail.com"",""field_type"":6,""last_modified"":1726064087,""created_at"":1726064036}",,"{""last_modified"":1726064513,""data"":""{\""options\"":[{\""id\"":\""zy0x\"",\""name\"":\""game vs celtics\"",\""color\"":\""Purple\""},{\""id\"":\""WJsv\"",\""name\"":\""training\"",\""color\"":\""Purple\""},{\""id\"":\""w-f8\"",\""name\"":\""game vs spurs\"",\""color\"":\""Purple\""},{\""id\"":\""p1VQ\"",\""name\"":\""game vs knicks\"",\""color\"":\""Purple\""},{\""id\"":\""VjUA\"",\""name\"":\""recovery\"",\""color\"":\""Purple\""},{\""id\"":\""sQ8X\"",\""name\"":\""don't get injured\"",\""color\"":\""Purple\""}],\""selected_option_ids\"":[]}"",""created_at"":1726064486,""field_type"":7}",,"{""field_type"":3,""last_modified"":1726065310,""data"":""qnja"",""created_at"":1726065310}","{""created_at"":1726105205,""field_type"":4,""last_modified"":1726105249,""data"":""R9I7,1i4f,yORP,SEUo""}","{""data"":""1726122535"",""field_type"":8}","{""field_type"":9,""data"":""1726060546""}"
"{""data"":""Judy"",""created_at"":1726063475,""field_type"":0,""last_modified"":1726063487}","{""end_timestamp"":"""",""reminder_id"":"""",""data"":""1726640950"",""field_type"":2,""include_time"":false,""created_at"":1726122550,""last_modified"":1726122550,""is_range"":false}",,,"{""created_at"":1726063882,""field_type"":6,""last_modified"":1726064000,""data"":""judysmithjr@outlook.com""}","{""last_modified"":1726062712,""field_type"":5,""data"":""Yes"",""created_at"":1726062712}","{""created_at"":1726064549,""field_type"":7,""data"":""{\""options\"":[{\""id\"":\""j8cC\"",\""name\"":\""finish training\"",\""color\"":\""Purple\""},{\""id\"":\""SmSk\"",\""name\"":\""brainwash\"",\""color\"":\""Purple\""},{\""id\"":\""mnf5\"",\""name\"":\""welcome to ba sing se\"",\""color\"":\""Purple\""},{\""id\"":\""hcrj\"",\""name\"":\""don't mess up\"",\""color\"":\""Purple\""}],\""selected_option_ids\"":[\""j8cC\"",\""SmSk\"",\""mnf5\"",\""hcrj\""]}"",""last_modified"":1726064591}",,,"{""field_type"":4,""last_modified"":1726105152,""created_at"":1726105152,""data"":""R9I7""}","{""field_type"":8,""data"":""1726122550""}","{""field_type"":9,""data"":""1726060549""}"
Whitespace-only changes.
@@ -0,0 +1,12 @@
# dart_dependency_validator.yaml
allow_pins: true
include:
- "lib/**"
exclude:
- "packages/**"
ignore:
- analyzer
@@ -1,25 +0,0 @@
import 'anon_user_continue_test.dart' as anon_user_continue_test;
import 'appflowy_cloud_auth_test.dart' as appflowy_cloud_auth_test;
import 'empty_test.dart' as preset_af_cloud_env_test;
// import 'document_sync_test.dart' as document_sync_test;
import 'user_setting_sync_test.dart' as user_sync_test;
import 'workspace/change_name_and_icon_test.dart'
as change_workspace_name_and_icon_test;
import 'workspace/collaborative_workspace_test.dart'
as collaboration_workspace_test;
Future<void> main() async {
preset_af_cloud_env_test.main();
appflowy_cloud_auth_test.main();
// document_sync_test.main();
user_sync_test.main();
anon_user_continue_test.main();
// workspace
collaboration_workspace_test.main();
change_workspace_name_and_icon_test.main();
}
@@ -1,93 +0,0 @@
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/settings/pages/settings_account_view.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_supabase_cloud.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('supabase auth', () {
testWidgets('sign in with supabase', (tester) async {
await tester.initializeAppFlowy(cloudType: AuthenticatorType.supabase);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
});
testWidgets('sign out with supabase', (tester) async {
await tester.initializeAppFlowy(cloudType: AuthenticatorType.supabase);
await tester.tapGoogleLoginInButton();
// Open the setting page and sign out
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.account);
await tester.logout();
// Go to the sign in page again
await tester.pumpAndSettle(const Duration(seconds: 1));
tester.expectToSeeGoogleLoginButton();
});
testWidgets('sign in as anonymous', (tester) async {
await tester.initializeAppFlowy(cloudType: AuthenticatorType.supabase);
await tester.tapSignInAsGuest();
// should not see the sync setting page when sign in as anonymous
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.account);
// Scroll to sign-out
await tester.scrollUntilVisible(
find.byType(SignInOutButton),
100,
scrollable: find.findSettingsScrollable(),
);
await tester.tapButton(find.byType(SignInOutButton));
tester.expectToSeeGoogleLoginButton();
});
// testWidgets('enable encryption', (tester) async {
// await tester.initializeAppFlowy(cloudType: CloudType.supabase);
// await tester.tapGoogleLoginInButton();
// // Open the setting page and sign out
// await tester.openSettings();
// await tester.openSettingsPage(SettingsPage.cloud);
// // the switch should be off by default
// tester.assertEnableEncryptSwitchValue(false);
// await tester.toggleEnableEncrypt();
// // the switch should be on after toggling
// tester.assertEnableEncryptSwitchValue(true);
// // the switch can not be toggled back to off
// await tester.toggleEnableEncrypt();
// tester.assertEnableEncryptSwitchValue(true);
// });
testWidgets('enable sync', (tester) async {
await tester.initializeAppFlowy(cloudType: AuthenticatorType.supabase);
await tester.tapGoogleLoginInButton();
// Open the setting page and sign out
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.cloud);
// the switch should be on by default
tester.assertSupabaseEnableSyncSwitchValue(true);
await tester.toggleEnableSync(SupabaseEnableSync);
// the switch should be off
tester.assertSupabaseEnableSyncSwitchValue(false);
// the switch should be on after toggling
await tester.toggleEnableSync(SupabaseEnableSync);
tester.assertSupabaseEnableSyncSwitchValue(true);
});
});
}
@@ -22,9 +22,10 @@ void main() {
const fieldName = "test change field";
await tester.createField(
FieldType.RichText,
fieldName,
name: fieldName,
layout: ViewLayoutPB.Board,
);
await tester.dismissRowDetailPage();
await tester.tapButton(card1);
await tester.changeFieldTypeOfFieldWithName(
fieldName,
@@ -1,17 +1,21 @@
import 'package:appflowy/plugins/database/board/presentation/widgets/board_column_header.dart';
import 'package:appflowy/plugins/database/widgets/card/card.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/extension.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/select_option_cell_editor.dart';
import 'package:appflowy/plugins/database/widgets/field/type_option_editor/select/select_option_editor.dart';
import 'package:appflowy/plugins/database/widgets/row/row_property.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../../shared/database_test_op.dart';
import '../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('board group test', () {
group('board group test:', () {
testWidgets('move row to another group', (tester) async {
const card1Name = 'Card 1';
await tester.initializeAppFlowy();
@@ -46,5 +50,105 @@ void main() {
final card1StatusText = tester.widget<Text>(card1StatusFinder).data;
expect(card1StatusText, 'Doing');
});
testWidgets('rename group', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
final headers = find.byType(BoardColumnHeader);
expect(headers, findsNWidgets(4));
// try to tap no status
final noStatus = headers.first;
expect(
find.descendant(of: noStatus, matching: find.text("No Status")),
findsOneWidget,
);
await tester.tapButton(noStatus);
expect(
find.descendant(of: noStatus, matching: find.byType(TextField)),
findsNothing,
);
// tap on To Do and edit it
final todo = headers.at(1);
expect(
find.descendant(of: todo, matching: find.text("To Do")),
findsOneWidget,
);
await tester.tapButton(todo);
await tester.enterText(
find.descendant(of: todo, matching: find.byType(TextField)),
"tada",
);
await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pumpAndSettle();
final newHeaders = find.byType(BoardColumnHeader);
expect(newHeaders, findsNWidgets(4));
final tada = find.byType(BoardColumnHeader).at(1);
expect(
find.descendant(of: tada, matching: find.byType(TextField)),
findsNothing,
);
expect(
find.descendant(
of: tada,
matching: find.text("tada"),
),
findsOneWidget,
);
});
testWidgets('edit select option from row detail', (tester) async {
const card1Name = 'Card 1';
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
await tester.tapButton(
find.descendant(
of: find.byType(RowCard),
matching: find.text(card1Name),
),
);
await tester.tapGridFieldWithNameInRowDetailPage("Status");
await tester.tapButton(
find.byWidgetPredicate(
(widget) =>
widget is SelectOptionTagCell && widget.option.name == "To Do",
),
);
final editor = find.byType(SelectOptionEditor);
await tester.enterText(
find.descendant(of: editor, matching: find.byType(TextField)),
"tada",
);
await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pumpAndSettle();
await tester.dismissFieldEditor();
await tester.dismissRowDetailPage();
final newHeaders = find.byType(BoardColumnHeader);
expect(newHeaders, findsNWidgets(4));
final tada = find.byType(BoardColumnHeader).at(1);
expect(
find.descendant(of: tada, matching: find.byType(TextField)),
findsNothing,
);
expect(
find.descendant(
of: tada,
matching: find.text("tada"),
),
findsOneWidget,
);
});
});
}
@@ -1,13 +1,13 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/board/presentation/widgets/board_column_header.dart';
import 'package:appflowy/plugins/database/board/presentation/widgets/board_hidden_groups.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../../shared/database_test_op.dart';
import '../../shared/util.dart';
void main() {
@@ -77,65 +77,46 @@ void main() {
shownGroups = tester.widgetList(find.byType(BoardColumnHeader)).length;
expect(shownGroups, 4);
});
});
testWidgets('delete a group', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
testWidgets('delete a group', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
expect(tester.widgetList(find.byType(BoardColumnHeader)).length, 4);
expect(tester.widgetList(find.byType(BoardColumnHeader)).length, 4);
// tap group option button for the first group. Delete shouldn't show up
await tester.tapButton(
find
.descendant(
of: find.byType(BoardColumnHeader),
matching: find.byFlowySvg(FlowySvgs.details_horizontal_s),
)
.first,
);
expect(find.byFlowySvg(FlowySvgs.delete_s), findsNothing);
// tap group option button for the first group. Delete shouldn't show up
await tester.tapButton(
find
.descendant(
of: find.byType(BoardColumnHeader),
matching: find.byFlowySvg(FlowySvgs.details_horizontal_s),
)
.first,
);
expect(find.byFlowySvg(FlowySvgs.delete_s), findsNothing);
// dismiss the popup
await tester.sendKeyEvent(LogicalKeyboardKey.escape);
await tester.pumpAndSettle();
// dismiss the popup
await tester.sendKeyEvent(LogicalKeyboardKey.escape);
await tester.pumpAndSettle();
// tap group option button for the first group. Delete should show up
await tester.tapButton(
find
.descendant(
of: find.byType(BoardColumnHeader),
matching: find.byFlowySvg(FlowySvgs.details_horizontal_s),
)
.at(1),
);
expect(find.byFlowySvg(FlowySvgs.delete_s), findsOneWidget);
// tap group option button for the first group. Delete should show up
await tester.tapButton(
find
.descendant(
of: find.byType(BoardColumnHeader),
matching: find.byFlowySvg(FlowySvgs.details_horizontal_s),
)
.at(1),
);
expect(find.byFlowySvg(FlowySvgs.delete_s), findsOneWidget);
// Tap the delete button and confirm
await tester.tapButton(find.byFlowySvg(FlowySvgs.delete_s));
await tester.tapDialogOkButton();
// Tap the delete button and confirm
await tester.tapButton(find.byFlowySvg(FlowySvgs.delete_s));
await tester.tapButtonWithName(LocaleKeys.space_delete.tr());
// Expect number of groups to decrease by one
expect(tester.widgetList(find.byType(BoardColumnHeader)).length, 3);
// Expect number of groups to decrease by one
expect(tester.widgetList(find.byType(BoardColumnHeader)).length, 3);
});
});
}
extension FlowySvgFinder on CommonFinders {
Finder byFlowySvg(FlowySvgData svg) => _FlowySvgFinder(svg);
}
class _FlowySvgFinder extends MatchFinder {
_FlowySvgFinder(this.svg);
final FlowySvgData svg;
@override
String get description => 'flowy_svg "$svg"';
@override
bool matches(Element candidate) {
final Widget widget = candidate.widget;
return widget is FlowySvg && widget.svg == svg;
}
}
@@ -6,6 +6,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:time/time.dart';
import '../../shared/database_test_op.dart';
import '../../shared/util.dart';
@@ -14,6 +15,31 @@ void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('board row test', () {
testWidgets('edit item in ToDo card', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
const name = 'Card 1';
final card1 = find.ancestor(
matching: find.byType(RowCard),
of: find.text(name),
);
await tester.hoverOnWidget(
card1,
onHover: () async {
final editCard = find.byType(EditCardAccessory);
await tester.tapButton(editCard);
},
);
await tester.showKeyboard(card1);
tester.testTextInput.enterText("");
await tester.pump(300.milliseconds);
tester.testTextInput.enterText("a");
await tester.pump(300.milliseconds);
expect(find.text('a'), findsOneWidget);
});
testWidgets('delete item in ToDo card', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
@@ -29,6 +55,7 @@ void main() {
},
);
await tester.tapButtonWithName(LocaleKeys.button_delete.tr());
await tester.tapButtonWithName(LocaleKeys.button_delete.tr());
expect(find.text(name), findsNothing);
});
@@ -50,6 +77,37 @@ void main() {
expect(find.textContaining(name, findRichText: true), findsNWidgets(2));
});
testWidgets('duplicate item in ToDo card then delete', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
const name = 'Card 1';
final card1 = find.text(name);
await tester.hoverOnWidget(
card1,
onHover: () async {
final moreOption = find.byType(MoreCardOptionsAccessory);
await tester.tapButton(moreOption);
},
);
await tester.tapButtonWithName(LocaleKeys.button_duplicate.tr());
expect(find.textContaining(name, findRichText: true), findsNWidgets(2));
// get the last widget that contains the name
final duplicatedCard = find.textContaining(name, findRichText: true).last;
await tester.hoverOnWidget(
duplicatedCard,
onHover: () async {
final moreOption = find.byType(MoreCardOptionsAccessory);
await tester.tapButton(moreOption);
},
);
await tester.tapButtonWithName(LocaleKeys.button_delete.tr());
await tester.tapButtonWithName(LocaleKeys.button_delete.tr());
expect(find.textContaining(name, findRichText: true), findsNWidgets(1));
});
testWidgets('add new group', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
@@ -3,6 +3,8 @@ import 'package:integration_test/integration_test.dart';
import 'board_add_row_test.dart' as board_add_row_test;
import 'board_group_test.dart' as board_group_test;
import 'board_row_test.dart' as board_row_test;
import 'board_field_test.dart' as board_field_test;
import 'board_hide_groups_test.dart' as board_hide_groups_test;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@@ -11,4 +13,6 @@ void main() {
board_row_test.main();
board_add_row_test.main();
board_group_test.main();
board_field_test.main();
board_hide_groups_test.main();
}
@@ -0,0 +1,25 @@
import 'document/document_test_runner.dart' as document_test_runner;
import 'sidebar/sidebar_move_page_test.dart' as sidebar_move_page_test;
import 'uncategorized/uncategorized_test_runner.dart'
as uncategorized_test_runner;
import 'workspace/workspace_test_runner.dart' as workspace_test_runner;
import 'data_migration/data_migration_test_runner.dart'
as data_migration_test_runner;
import 'set_env.dart' as preset_af_cloud_env_test;
Future<void> main() async {
preset_af_cloud_env_test.main();
data_migration_test_runner.main();
// uncategorized
uncategorized_test_runner.main();
// workspace
workspace_test_runner.main();
// document
document_test_runner.main();
// sidebar
sidebar_move_page_test.main();
}
@@ -3,8 +3,6 @@
import 'dart:io';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
@@ -12,6 +10,7 @@ import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/settings/pages/account/account.dart';
import 'package:appflowy/workspace/presentation/settings/pages/settings_account_view.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_body.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
@@ -19,30 +18,35 @@ import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flowy_infra_ui/style_widget/text_field.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:intl/intl.dart';
import 'package:path/path.dart' as p;
import '../desktop/board/board_hide_groups_test.dart';
import '../shared/dir.dart';
import '../shared/mock/mock_file_picker.dart';
import '../shared/util.dart';
import '../../../shared/dir.dart';
import '../../../shared/mock/mock_file_picker.dart';
import '../../../shared/util.dart';
import '../../board/board_hide_groups_test.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('appflowy cloud', () {
testWidgets('anon user and then sign in', (tester) async {
testWidgets('anon user -> sign in -> open imported space', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
tester.expectToSeeText(LocaleKeys.signIn_loginStartWithAnonymous.tr());
await tester.tapContinousAnotherWay();
await tester.tapAnonymousSignInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
// reanme the name of the anon user
const pageName = 'Test Document';
await tester.createNewPageWithNameUnderParent(name: pageName);
tester.expectToSeePageName(pageName);
// rename the name of the anon user
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.account);
await tester.pumpAndSettle();
@@ -51,42 +55,26 @@ void main() {
// Scroll to sign-in
await tester.scrollUntilVisible(
find.byType(SignInOutButton),
find.byType(AccountSignInOutButton),
100,
scrollable: find.findSettingsScrollable(),
);
await tester.tapButton(find.byType(SignInOutButton));
await tester.tapButton(find.byType(AccountSignInOutButton));
// sign up with Google
await tester.tapGoogleLoginInButton();
// await tester.pumpAndSettle(const Duration(seconds: 16));
// sign out
// open the imported space
await tester.expectToSeeHomePage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.account);
await tester.clickSpaceHeader();
// Scroll to sign-out
await tester.scrollUntilVisible(
find.byType(SignInOutButton),
100,
scrollable: find.findSettingsScrollable(),
);
// After import the anon user data, we will create a new space for it
await tester.openSpace("Getting started");
await tester.openPage(pageName);
await tester.logout();
await tester.pumpAndSettle();
// tap the continue as anonymous button
await tester
.tapButton(find.text(LocaleKeys.signIn_loginStartWithAnonymous.tr()));
await tester.expectToSeeHomePage();
// New anon user name
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.account);
final userNameInput =
tester.widget(find.byType(UserProfileSetting)) as UserProfileSetting;
expect(userNameInput.name, 'Me');
});
});
}
@@ -0,0 +1,5 @@
import 'anon_user_data_migration_test.dart' as anon_user_test;
void main() async {
anon_user_test.main();
}
@@ -0,0 +1,275 @@
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/document_page.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_block.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_page_block.dart';
import 'package:appflowy/shared/patterns/common_patterns.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../../../shared/constants.dart';
import '../../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
// copy link to block
group('copy link to block:', () {
testWidgets('copy link to check if the clipboard has the correct content',
(tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
// open getting started page
await tester.openPage(Constants.gettingStartedPageName);
await tester.editor.copyLinkToBlock([0]);
await tester.pumpAndSettle(Durations.short1);
// check the clipboard
final content = await Clipboard.getData(Clipboard.kTextPlain);
expect(
content?.text,
matches(appflowySharePageLinkPattern),
);
});
testWidgets('copy link to block(another page) and paste it in doc',
(tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
// open getting started page
await tester.openPage(Constants.gettingStartedPageName);
await tester.editor.copyLinkToBlock([0]);
// create a new page and paste it
const pageName = 'copy link to block';
await tester.createNewPageInSpace(
spaceName: Constants.generalSpaceName,
layout: ViewLayoutPB.Document,
pageName: pageName,
);
// paste the link to the new page
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.paste();
await tester.pumpAndSettle();
// check the content of the block
final node = tester.editor.getNodeAtPath([0]);
final delta = node.delta!;
final insert = (delta.first as TextInsert).text;
final attributes = delta.first.attributes;
expect(insert, MentionBlockKeys.mentionChar);
final mention =
attributes?[MentionBlockKeys.mention] as Map<String, dynamic>;
expect(mention[MentionBlockKeys.type], MentionType.page.name);
expect(mention[MentionBlockKeys.blockId], isNotNull);
expect(mention[MentionBlockKeys.pageId], isNotNull);
expect(
find.descendant(
of: find.byType(AppFlowyEditor),
matching: find.textContaining(
Constants.gettingStartedPageName,
findRichText: true,
),
),
findsOneWidget,
);
expect(
find.descendant(
of: find.byType(AppFlowyEditor),
matching: find.textContaining(
// the pasted block content is 'Welcome to AppFlowy'
'Welcome to AppFlowy',
findRichText: true,
),
),
findsOneWidget,
);
// tap the mention block to jump to the page
await tester.tapButton(find.byType(MentionPageBlock));
await tester.pumpAndSettle();
// expect to go to the getting started page
final documentPage = find.byType(DocumentPage);
expect(documentPage, findsOneWidget);
expect(
tester.widget<DocumentPage>(documentPage).view.name,
Constants.gettingStartedPageName,
);
// and the block is selected
expect(
tester.widget<DocumentPage>(documentPage).initialBlockId,
mention[MentionBlockKeys.blockId],
);
expect(
tester.editor.getCurrentEditorState().selection,
Selection.collapsed(
Position(
path: [0],
),
),
);
});
testWidgets('copy link to block(same page) and paste it in doc',
(tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
// create a new page and paste it
const pageName = 'copy link to block';
await tester.createNewPageInSpace(
spaceName: Constants.generalSpaceName,
layout: ViewLayoutPB.Document,
pageName: pageName,
);
// copy the link to block from the first line
const inputText = 'Hello World';
await tester.editor.tapLineOfEditorAt(0);
await tester.ime.insertText(inputText);
await tester.ime.insertCharacter('\n');
await tester.pumpAndSettle();
await tester.editor.copyLinkToBlock([0]);
// paste the link to the second line
await tester.editor.tapLineOfEditorAt(1);
await tester.editor.paste();
await tester.pumpAndSettle();
// check the content of the block
final node = tester.editor.getNodeAtPath([1]);
final delta = node.delta!;
final insert = (delta.first as TextInsert).text;
final attributes = delta.first.attributes;
expect(insert, MentionBlockKeys.mentionChar);
final mention =
attributes?[MentionBlockKeys.mention] as Map<String, dynamic>;
expect(mention[MentionBlockKeys.type], MentionType.page.name);
expect(mention[MentionBlockKeys.blockId], isNotNull);
expect(mention[MentionBlockKeys.pageId], isNotNull);
expect(
find.descendant(
of: find.byType(AppFlowyEditor),
matching: find.textContaining(
inputText,
findRichText: true,
),
),
findsNWidgets(2),
);
// edit the pasted block
await tester.editor.tapLineOfEditorAt(0);
await tester.ime.insertText('!');
await tester.pumpAndSettle();
// check the content of the block
expect(
find.descendant(
of: find.byType(AppFlowyEditor),
matching: find.textContaining(
'$inputText!',
findRichText: true,
),
),
findsNWidgets(2),
);
// tap the mention block
await tester.tapButton(find.byType(MentionPageBlock));
expect(
tester.editor.getCurrentEditorState().selection,
Selection.collapsed(
Position(
path: [0],
),
),
);
});
testWidgets('''1. copy link to block from another page
2. paste the link to the new page
3. delete the original page
4. check the content of the block, it should be no access to the page
''', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
// open getting started page
await tester.openPage(Constants.gettingStartedPageName);
await tester.editor.copyLinkToBlock([0]);
// create a new page and paste it
const pageName = 'copy link to block';
await tester.createNewPageInSpace(
spaceName: Constants.generalSpaceName,
layout: ViewLayoutPB.Document,
pageName: pageName,
);
// paste the link to the new page
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.paste();
await tester.pumpAndSettle();
// tap the mention block to jump to the page
await tester.tapButton(find.byType(MentionPageBlock));
await tester.pumpAndSettle();
// expect to go to the getting started page
final documentPage = find.byType(DocumentPage);
expect(documentPage, findsOneWidget);
expect(
tester.widget<DocumentPage>(documentPage).view.name,
Constants.gettingStartedPageName,
);
// delete the getting started page
await tester.hoverOnPageName(
Constants.gettingStartedPageName,
onHover: () async => tester.tapDeletePageButton(),
);
tester.expectToSeeDocumentBanner();
tester.expectNotToSeePageName(gettingStarted);
// delete the page permanently
await tester.tapDeletePermanentlyButton();
// go back the page
await tester.openPage(pageName);
await tester.pumpAndSettle();
// check the content of the block
// it should be no access to the page
expect(
find.descendant(
of: find.byType(AppFlowyEditor),
matching: find.findTextInFlowyText(
LocaleKeys.document_mention_noAccess.tr(),
),
),
findsOneWidget,
);
});
});
}
@@ -0,0 +1,114 @@
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/drag_to_reorder/draggable_option_button.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../../../shared/constants.dart';
import '../../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('document option actions:', () {
testWidgets('drag block to the top', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
// open getting started page
await tester.openPage(Constants.gettingStartedPageName);
// before move
final beforeMoveBlock = tester.editor.getNodeAtPath([1]);
// move the desktop guide to the top, above the getting started
await tester.editor.dragBlock(
[1],
const Offset(20, -80),
);
// wait for the move animation to complete
await tester.pumpAndSettle(Durations.short1);
// check if the block is moved to the top
final afterMoveBlock = tester.editor.getNodeAtPath([0]);
expect(afterMoveBlock.delta, beforeMoveBlock.delta);
});
testWidgets('drag block to other block\'s child', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
// open getting started page
await tester.openPage(Constants.gettingStartedPageName);
// before move
final beforeMoveBlock = tester.editor.getNodeAtPath([10]);
// move the checkbox to the child of the block at path [9]
await tester.editor.dragBlock(
[10],
const Offset(80, -30),
);
// wait for the move animation to complete
await tester.pumpAndSettle(Durations.short1);
// check if the block is moved to the child of the block at path [9]
final afterMoveBlock = tester.editor.getNodeAtPath([9, 0]);
expect(afterMoveBlock.delta, beforeMoveBlock.delta);
});
testWidgets('hover on the block and delete it', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
// open getting started page
await tester.openPage(Constants.gettingStartedPageName);
// before delete
final path = [1];
final beforeDeletedBlock = tester.editor.getNodeAtPath(path);
// hover on the block and delete it
final optionButton = find.byWidgetPredicate(
(widget) =>
widget is DraggableOptionButton &&
widget.blockComponentContext.node.path.equals(path),
);
await tester.hoverOnWidget(
optionButton,
onHover: () async {
// click the delete button
await tester.tapButton(optionButton);
},
);
await tester.pumpAndSettle(Durations.short1);
// click the delete button
final deleteButton =
find.findTextInFlowyText(LocaleKeys.button_delete.tr());
await tester.tapButton(deleteButton);
// wait for the deletion
await tester.pumpAndSettle(Durations.short1);
// check if the block is deleted
final afterDeletedBlock = tester.editor.getNodeAtPath([1]);
expect(afterDeletedBlock.id, isNot(equals(beforeDeletedBlock.id)));
});
});
}
@@ -0,0 +1,157 @@
// ignore_for_file: unused_import
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_paste/clipboard_service.dart';
import 'package:appflowy/plugins/shared/share/constants.dart';
import 'package:appflowy/plugins/shared/share/publish_tab.dart';
import 'package:appflowy/plugins/shared/share/share_menu.dart';
import 'package:appflowy/shared/feature_flags.dart';
import 'package:appflowy/shared/patterns/common_patterns.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_icon.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
import '../../../shared/constants.dart';
import '../../../shared/mock/mock_file_picker.dart';
import '../../../shared/util.dart';
import '../../../shared/workspace.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('Publish:', () {
testWidgets('publish document', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
const pageName = 'Document';
await tester.createNewPageInSpace(
spaceName: Constants.generalSpaceName,
layout: ViewLayoutPB.Document,
pageName: pageName,
);
// open the publish menu
await tester.openPublishMenu();
// publish the document
final publishButton = find.byType(PublishButton);
final unpublishButton = find.byType(UnPublishButton);
await tester.tapButton(publishButton);
// expect to see unpublish, visit site and manage all sites button
expect(unpublishButton, findsOneWidget);
expect(find.text(LocaleKeys.shareAction_visitSite.tr()), findsOneWidget);
// unpublish the document
await tester.tapButton(unpublishButton);
// expect to see publish button
expect(publishButton, findsOneWidget);
});
testWidgets('rename path name', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
const pageName = 'Document';
await tester.createNewPageInSpace(
spaceName: Constants.generalSpaceName,
layout: ViewLayoutPB.Document,
pageName: pageName,
);
// open the publish menu
await tester.openPublishMenu();
// publish the document
final publishButton = find.byType(PublishButton);
await tester.tapButton(publishButton);
// rename the path name
final inputField = find.descendant(
of: find.byType(ShareMenu),
matching: find.byType(TextField),
);
// rename with invalid name
await tester.tap(inputField);
await tester.enterText(inputField, '&&&&????');
await tester.tapButton(find.text(LocaleKeys.button_save.tr()));
await tester.pumpAndSettle();
// expect to see the toast with error message
final errorToast1 = find.text(
LocaleKeys.settings_sites_error_publishNameContainsInvalidCharacters
.tr(),
);
await tester.pumpUntilFound(errorToast1);
await tester.pumpUntilNotFound(errorToast1);
// rename with long name
await tester.tap(inputField);
await tester.enterText(inputField, 'long-path-name' * 200);
await tester.tapButton(find.text(LocaleKeys.button_save.tr()));
await tester.pumpAndSettle();
// expect to see the toast with error message
final errorToast2 = find.text(
LocaleKeys.settings_sites_error_publishNameTooLong.tr(),
);
await tester.pumpUntilFound(errorToast2);
await tester.pumpUntilNotFound(errorToast2);
await tester.tap(inputField);
// input the new path name
await tester.enterText(inputField, 'new-path-name');
// click save button
await tester.tapButton(find.text(LocaleKeys.button_save.tr()));
await tester.pumpAndSettle();
// expect to see the toast with success message
final successToast = find.text(
LocaleKeys.settings_sites_success_updatePathNameSuccess.tr(),
);
await tester.pumpUntilFound(successToast);
await tester.pumpUntilNotFound(successToast);
// click the copy link button
await tester.tapButton(
find.byWidgetPredicate(
(widget) =>
widget is FlowySvg &&
widget.svg.path == FlowySvgs.m_toolbar_link_m.path,
),
);
await tester.pumpAndSettle();
// check the clipboard has the link
final content = await Clipboard.getData(Clipboard.kTextPlain);
expect(
content?.text?.contains('new-path-name'),
isTrue,
);
});
});
}
@@ -0,0 +1,14 @@
import 'package:integration_test/integration_test.dart';
import 'document_copy_link_to_block_test.dart'
as document_copy_link_to_block_test;
import 'document_option_actions_test.dart' as document_option_actions_test;
import 'document_publish_test.dart' as document_publish_test;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
document_option_actions_test.main();
document_copy_link_to_block_test.main();
document_publish_test.main();
}
@@ -2,7 +2,7 @@ import 'package:appflowy/env/cloud_env.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../shared/util.dart';
import '../../shared/util.dart';
// This test is meaningless, just for preventing the CI from failing.
void main() {
@@ -0,0 +1,130 @@
// ignore_for_file: unused_import
import 'dart:io';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/widgets/loading.dart';
import 'package:appflowy/shared/feature_flags.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_actions.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_menu.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/sidebar_workspace.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:appflowy/workspace/presentation/widgets/user_avatar.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
import 'package:universal_platform/universal_platform.dart';
import '../../../shared/constants.dart';
import '../../../shared/database_test_op.dart';
import '../../../shared/dir.dart';
import '../../../shared/emoji.dart';
import '../../../shared/mock/mock_file_picker.dart';
import '../../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('sidebar move page: ', () {
testWidgets('create a new document and move it to Getting started',
(tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
const pageName = 'Document';
await tester.createNewPageInSpace(
spaceName: Constants.generalSpaceName,
layout: ViewLayoutPB.Document,
pageName: pageName,
);
// click the ... button and move to Getting started
await tester.hoverOnPageName(
pageName,
onHover: () async {
await tester.tapPageOptionButton();
await tester.tapButtonWithName(
LocaleKeys.disclosureAction_moveTo.tr(),
);
},
);
// expect to see two pages
// one is in the sidebar, the other is in the move to page list
// 1. Getting started
// 2. To-dos
final gettingStarted = find.findTextInFlowyText(
Constants.gettingStartedPageName,
);
final toDos = find.findTextInFlowyText(Constants.toDosPageName);
await tester.pumpUntilFound(gettingStarted);
await tester.pumpUntilFound(toDos);
expect(gettingStarted, findsNWidgets(2));
// skip the length check on Linux temporarily,
// because it failed in expect check but the previous pumpUntilFound is successful
if (!UniversalPlatform.isLinux) {
expect(toDos, findsNWidgets(2));
// hover on the todos page, and will see a forbidden icon
await tester.hoverOnWidget(
toDos.last,
onHover: () async {
final tooltips = find.byTooltip(
LocaleKeys.space_cannotMovePageToDatabase.tr(),
);
expect(tooltips, findsOneWidget);
},
);
await tester.pumpAndSettle();
}
// Attempt right-click on the page name and expect not to see
await tester.tap(gettingStarted.last, buttons: kSecondaryButton);
await tester.pumpAndSettle();
expect(
find.text(LocaleKeys.disclosureAction_moveTo.tr()),
findsOneWidget,
);
// move the current page to Getting started
await tester.tapButton(
gettingStarted.last,
);
await tester.pumpAndSettle();
// after moving, expect to not see the page name in the sidebar
final page = tester.findPageName(pageName);
expect(page, findsNothing);
// click to expand the getting started page
await tester.expandOrCollapsePage(
pageName: Constants.gettingStartedPageName,
layout: ViewLayoutPB.Document,
);
await tester.pumpAndSettle();
// expect to see the page name in the getting started page
final pageInGettingStarted = tester.findPageName(
pageName,
parentName: Constants.gettingStartedPageName,
);
expect(pageInGettingStarted, findsOneWidget);
});
});
}
@@ -6,6 +6,7 @@ import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/settings/pages/account/account.dart';
import 'package:appflowy/workspace/presentation/settings/pages/settings_account_view.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:easy_localization/easy_localization.dart';
@@ -14,8 +15,8 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
import '../shared/mock/mock_file_picker.dart';
import '../shared/util.dart';
import '../../../shared/mock/mock_file_picker.dart';
import '../../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@@ -41,17 +42,17 @@ void main() {
// Scroll to sign-out
await tester.scrollUntilVisible(
find.byType(SignInOutButton),
find.byType(AccountSignInOutButton),
100,
scrollable: find.findSettingsScrollable(),
);
await tester.tapButton(find.byType(SignInOutButton));
await tester.tapButton(find.byType(AccountSignInOutButton));
tester.expectToSeeText(LocaleKeys.button_confirm.tr());
await tester.tapButtonWithName(LocaleKeys.button_confirm.tr());
tester.expectToSeeText(LocaleKeys.button_ok.tr());
await tester.tapButtonWithName(LocaleKeys.button_ok.tr());
// Go to the sign in page again
await tester.pumpAndSettle(const Duration(seconds: 1));
await tester.pumpAndSettle(const Duration(seconds: 5));
tester.expectToSeeGoogleLoginButton();
});
@@ -67,11 +68,11 @@ void main() {
// Scroll to sign-in
await tester.scrollUntilVisible(
find.byType(SignInOutButton),
find.byType(AccountSignInOutButton),
100,
scrollable: find.findSettingsScrollable(),
);
await tester.tapButton(find.byType(SignInOutButton));
await tester.tapButton(find.byType(AccountSignInOutButton));
tester.expectToSeeGoogleLoginButton();
});
@@ -85,10 +86,13 @@ void main() {
// Open the setting page and sign out
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.cloud);
await tester.pumpAndSettle();
// the switch should be on by default
tester.assertAppFlowyCloudEnableSyncSwitchValue(true);
await tester.toggleEnableSync(AppFlowyCloudEnableSync);
// wait for the switch animation
await tester.wait(250);
// the switch should be off
tester.assertAppFlowyCloudEnableSyncSwitchValue(false);
@@ -96,6 +100,7 @@ void main() {
// the switch should be on after toggling
await tester.toggleEnableSync(AppFlowyCloudEnableSync);
tester.assertAppFlowyCloudEnableSyncSwitchValue(true);
await tester.wait(250);
});
});
}
@@ -17,9 +17,9 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
import '../shared/dir.dart';
import '../shared/mock/mock_file_picker.dart';
import '../shared/util.dart';
import '../../../shared/dir.dart';
import '../../../shared/mock/mock_file_picker.dart';
import '../../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@@ -46,7 +46,6 @@ void main() {
await tester.ime.insertText(inputContent);
expect(find.text(inputContent, findRichText: true), findsOneWidget);
// TODO(nathan): remove the await
// 6 seconds for data sync
await tester.waitForSeconds(6);
@@ -0,0 +1,7 @@
import 'appflowy_cloud_auth_test.dart' as appflowy_cloud_auth_test;
import 'user_setting_sync_test.dart' as user_sync_test;
void main() async {
appflowy_cloud_auth_test.main();
user_sync_test.main();
}
@@ -2,8 +2,6 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
@@ -11,6 +9,7 @@ import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/settings/pages/account/account_user_profile.dart';
import 'package:appflowy/workspace/presentation/settings/pages/settings_account_view.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:appflowy/workspace/presentation/widgets/user_avatar.dart';
@@ -18,16 +17,17 @@ import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flowy_infra_ui/style_widget/text_field.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
import '../desktop/board/board_hide_groups_test.dart';
import '../shared/database_test_op.dart';
import '../shared/dir.dart';
import '../shared/emoji.dart';
import '../shared/mock/mock_file_picker.dart';
import '../shared/util.dart';
import '../../../shared/database_test_op.dart';
import '../../../shared/dir.dart';
import '../../../shared/emoji.dart';
import '../../../shared/mock/mock_file_picker.dart';
import '../../../shared/util.dart';
import '../../board/board_hide_groups_test.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@@ -47,13 +47,12 @@ void main() {
await tester.openSettingsPage(SettingsPage.account);
await tester.enterUserName(name);
await tester.tapEscButton();
await tester.pumpAndSettle(const Duration(seconds: 6));
await tester.logout();
// wait 2 seconds for the sync to finish
await tester.pumpAndSettle(const Duration(seconds: 2));
});
});
testWidgets('get user icon and name from server', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
@@ -68,7 +67,7 @@ void main() {
// Verify name
final profileSetting =
tester.widget(find.byType(UserProfileSetting)) as UserProfileSetting;
tester.widget(find.byType(AccountUserProfile)) as AccountUserProfile;
expect(profileSetting.name, name);
});
@@ -15,9 +15,9 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
import '../../shared/mock/mock_file_picker.dart';
import '../../shared/util.dart';
import '../../shared/workspace.dart';
import '../../../shared/mock/mock_file_picker.dart';
import '../../../shared/util.dart';
import '../../../shared/workspace.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@@ -23,18 +23,16 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
import '../../shared/database_test_op.dart';
import '../../shared/dir.dart';
import '../../shared/emoji.dart';
import '../../shared/mock/mock_file_picker.dart';
import '../../shared/util.dart';
import '../../../shared/database_test_op.dart';
import '../../../shared/dir.dart';
import '../../../shared/emoji.dart';
import '../../../shared/mock/mock_file_picker.dart';
import '../../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
final email = '${uuid()}@appflowy.io';
group('collaborative workspace', () {
group('collaborative workspace: ', () {
// combine the create and delete workspace test to reduce the time
testWidgets('create a new workspace, open it and then delete it',
(tester) async {
@@ -45,7 +43,6 @@ void main() {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
email: email,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
@@ -0,0 +1,77 @@
// ignore_for_file: unused_import
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_paste/clipboard_service.dart';
import 'package:appflowy/plugins/shared/share/constants.dart';
import 'package:appflowy/plugins/shared/share/share_menu.dart';
import 'package:appflowy/shared/feature_flags.dart';
import 'package:appflowy/shared/patterns/common_patterns.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_icon.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
import '../../../shared/constants.dart';
import '../../../shared/mock/mock_file_picker.dart';
import '../../../shared/util.dart';
import '../../../shared/workspace.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('Share menu:', () {
testWidgets('share tab', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
const pageName = 'Document';
await tester.createNewPageInSpace(
spaceName: Constants.generalSpaceName,
layout: ViewLayoutPB.Document,
pageName: pageName,
);
// click the share button
await tester.tapShareButton();
// expect the share menu is shown
final shareMenu = find.byType(ShareMenu);
expect(shareMenu, findsOneWidget);
// click the copy link button
final copyLinkButton = find.textContaining(
LocaleKeys.button_copyLink.tr(),
);
await tester.tapButton(copyLinkButton);
// read the clipboard content
final clipboardContent = await getIt<ClipboardService>().getData();
final plainText = clipboardContent.plainText;
expect(
plainText,
matches(appflowySharePageLinkPattern),
);
final shareValues = plainText!
.replaceAll('https://${ShareConstants.shareBaseUrl}/', '')
.split('/');
final workspaceId = shareValues[0];
expect(workspaceId, isNotEmpty);
final pageId = shareValues[1];
expect(pageId, isNotEmpty);
});
});
}
@@ -0,0 +1,68 @@
// ignore_for_file: unused_import
import 'dart:io';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/widgets/loading.dart';
import 'package:appflowy/shared/feature_flags.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_actions.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_icon.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_menu.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/sidebar_workspace.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:appflowy/workspace/presentation/widgets/user_avatar.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
import 'package:universal_platform/universal_platform.dart';
import '../../../shared/constants.dart';
import '../../../shared/database_test_op.dart';
import '../../../shared/dir.dart';
import '../../../shared/emoji.dart';
import '../../../shared/mock/mock_file_picker.dart';
import '../../../shared/util.dart';
import '../../../shared/workspace.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('workspace icon:', () {
testWidgets('remove icon from workspace', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openWorkspaceMenu();
// click the workspace icon
await tester.tapButton(
find.descendant(
of: find.byType(WorkspaceMenuItem),
matching: find.byType(WorkspaceIcon),
),
);
// click the remove icon button
await tester.tapButton(
find.text(LocaleKeys.button_remove.tr()),
);
// nothing should happen
expect(
find.text(LocaleKeys.workspace_updateIconSuccess.tr()),
findsNothing,
);
});
});
}
@@ -0,0 +1,368 @@
// ignore_for_file: unused_import
import 'dart:io';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_paste/clipboard_service.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/widgets/loading.dart';
import 'package:appflowy/plugins/document/presentation/editor_style.dart';
import 'package:appflowy/plugins/shared/share/publish_tab.dart';
import 'package:appflowy/shared/feature_flags.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_actions.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_menu.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/sidebar_workspace.dart';
import 'package:appflowy/workspace/presentation/settings/pages/settings_workspace_view.dart';
import 'package:appflowy/workspace/presentation/settings/pages/sites/domain/domain_item.dart';
import 'package:appflowy/workspace/presentation/settings/pages/sites/domain/domain_more_action.dart';
import 'package:appflowy/workspace/presentation/settings/pages/sites/domain/domain_settings_dialog.dart';
import 'package:appflowy/workspace/presentation/settings/pages/sites/domain/home_page_menu.dart';
import 'package:appflowy/workspace/presentation/settings/pages/sites/published_page/published_view_item.dart';
import 'package:appflowy/workspace/presentation/settings/pages/sites/published_page/published_view_more_action.dart';
import 'package:appflowy/workspace/presentation/settings/pages/sites/published_page/published_view_settings_dialog.dart';
import 'package:appflowy/workspace/presentation/settings/shared/setting_list_tile.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
import 'package:appflowy/workspace/presentation/widgets/user_avatar.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
import '../../../shared/constants.dart';
import '../../../shared/database_test_op.dart';
import '../../../shared/dir.dart';
import '../../../shared/emoji.dart';
import '../../../shared/mock/mock_file_picker.dart';
import '../../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('workspace settings: ', () {
testWidgets(
'change document width',
(tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.workspace);
final documentWidthSettings = find.findTextInFlowyText(
LocaleKeys.settings_appearance_documentSettings_width.tr(),
);
final scrollable = find.ancestor(
of: find.byType(SettingsWorkspaceView),
matching: find.descendant(
of: find.byType(SingleChildScrollView),
matching: find.byType(Scrollable),
),
);
await tester.scrollUntilVisible(
documentWidthSettings,
0,
scrollable: scrollable,
);
await tester.pumpAndSettle();
// change the document width
final slider = find.byType(Slider);
final oldValue = tester.widget<Slider>(slider).value;
await tester.drag(slider, const Offset(-100, 0));
await tester.pumpAndSettle();
// check the document width is changed
expect(tester.widget<Slider>(slider).value, lessThan(oldValue));
// click the reset button
final resetButton = find.descendant(
of: find.byType(DocumentPaddingSetting),
matching: find.byType(SettingsResetButton),
);
await tester.tap(resetButton);
await tester.pumpAndSettle();
// check the document width is reset
expect(
tester.widget<Slider>(slider).value,
EditorStyleCustomizer.maxDocumentWidth,
);
},
);
});
group('sites settings:', () {
testWidgets(
'manage published page, set it as homepage, remove the homepage',
(tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
const pageName = 'Document';
await tester.createNewPageInSpace(
spaceName: Constants.generalSpaceName,
layout: ViewLayoutPB.Document,
pageName: pageName,
);
// open the publish menu
await tester.openPublishMenu();
// publish the document
await tester.tapButton(find.byType(PublishButton));
// click empty area to close the publish menu
await tester.tapAt(Offset.zero);
await tester.pumpAndSettle();
// check if the page is published in sites page
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.sites);
// wait the backend return the sites data
await tester.wait(1000);
// check if the page is published in sites page
final pageItem = find.byWidgetPredicate(
(widget) =>
widget is PublishedViewItem &&
widget.publishInfoView.view.name == pageName,
);
expect(pageItem, findsOneWidget);
// comment it out because it's not allowed to update the namespace in free plan
// // set it to homepage
// await tester.tapButton(
// find.textContaining(
// LocaleKeys.settings_sites_selectHomePage.tr(),
// ),
// );
// await tester.tapButton(
// find.descendant(
// of: find.byType(SelectHomePageMenu),
// matching: find.text(pageName),
// ),
// );
// await tester.pumpAndSettle();
// // check if the page is set to homepage
// final homePageItem = find.descendant(
// of: find.byType(DomainItem),
// matching: find.text(pageName),
// );
// expect(homePageItem, findsOneWidget);
// // remove the homepage
// await tester.tapButton(find.byType(DomainMoreAction));
// await tester.tapButton(
// find.text(LocaleKeys.settings_sites_removeHomepage.tr()),
// );
// await tester.pumpAndSettle();
// // check if the page is removed from homepage
// expect(homePageItem, findsNothing);
});
testWidgets('update namespace', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
// check if the page is published in sites page
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.sites);
// wait the backend return the sites data
await tester.wait(1000);
// update the domain
final domainMoreAction = find.byType(DomainMoreAction);
await tester.tapButton(domainMoreAction);
final updateNamespaceButton = find.text(
LocaleKeys.settings_sites_updateNamespace.tr(),
);
await tester.pumpUntilFound(updateNamespaceButton);
// click the update namespace button
await tester.tapButton(updateNamespaceButton);
// comment it out because it's not allowed to update the namespace in free plan
// expect to see the dialog
// await tester.updateNamespace('&&&???');
// // need to upgrade to pro plan to update the namespace
// final errorToast = find.text(
// LocaleKeys.settings_sites_error_proPlanLimitation.tr(),
// );
// await tester.pumpUntilFound(errorToast);
// expect(errorToast, findsOneWidget);
// await tester.pumpUntilNotFound(errorToast);
// comment it out because it's not allowed to update the namespace in free plan
// // short namespace
// await tester.updateNamespace('a');
// // expect to see the toast with error message
// final errorToast2 = find.text(
// LocaleKeys.settings_sites_error_namespaceTooShort.tr(),
// );
// await tester.pumpUntilFound(errorToast2);
// expect(errorToast2, findsOneWidget);
// await tester.pumpUntilNotFound(errorToast2);
// // valid namespace
// await tester.updateNamespace('AppFlowy');
// // expect to see the toast with success message
// final successToast = find.text(
// LocaleKeys.settings_sites_success_namespaceUpdated.tr(),
// );
// await tester.pumpUntilFound(successToast);
// expect(successToast, findsOneWidget);
});
testWidgets('''
More actions for published page:
1. visit site
2. copy link
3. settings
4. unpublish
5. custom url
''', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
const pageName = 'Document';
await tester.createNewPageInSpace(
spaceName: Constants.generalSpaceName,
layout: ViewLayoutPB.Document,
pageName: pageName,
);
// open the publish menu
await tester.openPublishMenu();
// publish the document
await tester.tapButton(find.byType(PublishButton));
// click empty area to close the publish menu
await tester.tapAt(Offset.zero);
await tester.pumpAndSettle();
// check if the page is published in sites page
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.sites);
// wait the backend return the sites data
await tester.wait(1000);
// check if the page is published in sites page
final pageItem = find.byWidgetPredicate(
(widget) =>
widget is PublishedViewItem &&
widget.publishInfoView.view.name == pageName,
);
expect(pageItem, findsOneWidget);
final copyLinkItem = find.text(LocaleKeys.shareAction_copyLink.tr());
final customUrlItem = find.text(LocaleKeys.settings_sites_customUrl.tr());
final unpublishItem = find.text(LocaleKeys.shareAction_unPublish.tr());
// custom url
final publishMoreAction = find.byType(PublishedViewMoreAction);
// click the copy link button
{
await tester.tapButton(publishMoreAction);
await tester.pumpAndSettle();
await tester.pumpUntilFound(copyLinkItem);
await tester.tapButton(copyLinkItem);
await tester.pumpAndSettle();
await tester.pumpUntilNotFound(copyLinkItem);
final clipboardContent = await getIt<ClipboardService>().getData();
final plainText = clipboardContent.plainText;
expect(
plainText,
contains(pageName),
);
}
// custom url
{
await tester.tapButton(publishMoreAction);
await tester.pumpAndSettle();
await tester.pumpUntilFound(customUrlItem);
await tester.tapButton(customUrlItem);
await tester.pumpAndSettle();
await tester.pumpUntilNotFound(customUrlItem);
// see the custom url dialog
final customUrlDialog = find.byType(PublishedViewSettingsDialog);
expect(customUrlDialog, findsOneWidget);
// rename the custom url
final textField = find.descendant(
of: customUrlDialog,
matching: find.byType(TextField),
);
await tester.enterText(textField, 'hello-world');
await tester.pumpAndSettle();
// click the save button
final saveButton = find.descendant(
of: customUrlDialog,
matching: find.text(LocaleKeys.button_save.tr()),
);
await tester.tapButton(saveButton);
await tester.pumpAndSettle();
// expect to see the toast with success message
final successToast = find.text(
LocaleKeys.settings_sites_success_updatePathNameSuccess.tr(),
);
await tester.pumpUntilFound(successToast);
expect(successToast, findsOneWidget);
}
// unpublish
{
await tester.tapButton(publishMoreAction);
await tester.pumpAndSettle();
await tester.pumpUntilFound(unpublishItem);
await tester.tapButton(unpublishItem);
await tester.pumpAndSettle();
await tester.pumpUntilNotFound(unpublishItem);
// expect to see the toast with success message
final successToast = find.text(
LocaleKeys.publish_unpublishSuccessfully.tr(),
);
await tester.pumpUntilFound(successToast);
expect(successToast, findsOneWidget);
await tester.pumpUntilNotFound(successToast);
// check if the page is unpublished in sites page
expect(pageItem, findsNothing);
}
});
});
}
@@ -0,0 +1,17 @@
import 'package:integration_test/integration_test.dart';
import 'change_name_and_icon_test.dart' as change_name_and_icon_test;
import 'collaborative_workspace_test.dart' as collaborative_workspace_test;
import 'share_menu_test.dart' as share_menu_test;
import 'workspace_icon_test.dart' as workspace_icon_test;
import 'workspace_settings_test.dart' as workspace_settings_test;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
workspace_settings_test.main();
share_menu_test.main();
collaborative_workspace_test.main();
change_name_and_icon_test.main();
workspace_icon_test.main();
}
@@ -1,5 +1,5 @@
import 'package:appflowy/plugins/database/calendar/presentation/calendar_event_editor.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pbenum.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -277,5 +277,72 @@ void main() {
tester.assertRowDetailPageOpened();
});
testWidgets('filter calendar events', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
// Create the calendar view
await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Calendar,
);
// Create a new event on the first of this month
final today = DateTime.now();
final firstOfThisMonth = DateTime(today.year, today.month);
await tester.doubleClickCalendarCell(firstOfThisMonth);
await tester.dismissEventEditor();
tester.assertNumberOfEventsInCalendar(1);
await tester.openCalendarEvent(index: 0, date: firstOfThisMonth);
await tester.tapButton(finderForFieldType(FieldType.MultiSelect));
await tester.createOption(name: "asdf");
await tester.createOption(name: "qwer");
await tester.selectOption(name: "asdf");
await tester.dismissCellEditor();
await tester.tapDatabaseFilterButton();
await tester.tapCreateFilterByFieldType(FieldType.MultiSelect, "Tags");
await tester.tapFilterButtonInGrid('Tags');
await tester.tapOptionFilterWithName('asdf');
await tester.dismissCellEditor();
tester.assertNumberOfEventsInCalendar(0);
await tester.tapFilterButtonInGrid('Tags');
await tester.tapOptionFilterWithName('asdf');
await tester.dismissCellEditor();
tester.assertNumberOfEventsInCalendar(1);
await tester.tapFilterButtonInGrid('Tags');
await tester.tapOptionFilterWithName('asdf');
await tester.dismissCellEditor();
tester.assertNumberOfEventsInCalendar(0);
final secondOfThisMonth = DateTime(today.year, today.month, 2);
await tester.doubleClickCalendarCell(secondOfThisMonth);
await tester.dismissEventEditor();
tester.assertNumberOfEventsInCalendar(1);
await tester.openCalendarEvent(index: 0, date: secondOfThisMonth);
await tester.tapButton(finderForFieldType(FieldType.MultiSelect));
await tester.selectOption(name: "asdf");
await tester.dismissCellEditor();
tester.assertNumberOfEventsInCalendar(0);
await tester.tapFilterButtonInGrid('Tags');
await tester.changeSelectFilterCondition(
SelectOptionFilterConditionPB.OptionIsEmpty,
);
await tester.dismissCellEditor();
tester.assertNumberOfEventsInCalendar(1);
tester.assertNumberOfEventsOnSpecificDay(1, secondOfThisMonth);
});
});
}
@@ -1,3 +1,4 @@
import 'package:appflowy/util/field_type_extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -41,7 +42,7 @@ void main() {
name: 'my grid',
layout: ViewLayoutPB.Grid,
);
await tester.createField(FieldType.RichText, 'description');
await tester.createField(FieldType.RichText, name: 'description');
await tester.editCell(
rowIndex: 0,
@@ -81,7 +82,7 @@ void main() {
const fieldType = FieldType.Number;
// Create a number field
await tester.createField(fieldType, fieldType.name);
await tester.createField(fieldType);
await tester.editCell(
rowIndex: 0,
@@ -157,7 +158,7 @@ void main() {
const fieldType = FieldType.CreatedTime;
// Create a create time field
// The create time field is not editable
await tester.createField(fieldType, fieldType.name);
await tester.createField(fieldType);
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
@@ -175,7 +176,7 @@ void main() {
const fieldType = FieldType.LastEditedTime;
// Create a last time field
// The last time field is not editable
await tester.createField(fieldType, fieldType.name);
await tester.createField(fieldType);
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
@@ -191,7 +192,7 @@ void main() {
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.DateTime;
await tester.createField(fieldType, fieldType.name);
await tester.createField(fieldType);
// Tap the cell to invoke the field editor
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
@@ -210,21 +211,21 @@ void main() {
await tester.toggleIncludeTime();
// Select a date
final today = DateTime.now();
await tester.selectDay(content: today.day);
DateTime now = DateTime.now();
await tester.selectDay(content: now.day);
await tester.dismissCellEditor();
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.DateTime,
content: DateFormat('MMM dd, y').format(today),
content: DateFormat('MMM dd, y').format(now),
);
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
// Toggle include time
final now = DateTime.now();
now = DateTime.now();
await tester.toggleIncludeTime();
await tester.dismissCellEditor();
@@ -298,7 +299,7 @@ void main() {
await tester.dismissCellEditor();
// Make sure the option is created and displayed in the cell
await tester.findSelectOptionWithNameInGrid(
tester.findSelectOptionWithNameInGrid(
rowIndex: 0,
name: 'tag 1',
);
@@ -310,12 +311,12 @@ void main() {
await tester.createOption(name: 'tag 2');
await tester.dismissCellEditor();
await tester.findSelectOptionWithNameInGrid(
tester.findSelectOptionWithNameInGrid(
rowIndex: 0,
name: 'tag 2',
);
await tester.assertNumberOfSelectedOptionsInGrid(
tester.assertNumberOfSelectedOptionsInGrid(
rowIndex: 0,
matcher: findsOneWidget,
);
@@ -327,12 +328,12 @@ void main() {
await tester.selectOption(name: 'tag 1');
await tester.dismissCellEditor();
await tester.findSelectOptionWithNameInGrid(
tester.findSelectOptionWithNameInGrid(
rowIndex: 0,
name: 'tag 1',
);
await tester.assertNumberOfSelectedOptionsInGrid(
tester.assertNumberOfSelectedOptionsInGrid(
rowIndex: 0,
matcher: findsOneWidget,
);
@@ -344,7 +345,7 @@ void main() {
await tester.selectOption(name: 'tag 1');
await tester.dismissCellEditor();
await tester.assertNumberOfSelectedOptionsInGrid(
tester.assertNumberOfSelectedOptionsInGrid(
rowIndex: 0,
matcher: findsNothing,
);
@@ -366,7 +367,7 @@ void main() {
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.MultiSelect;
await tester.createField(fieldType, fieldType.name);
await tester.createField(fieldType, name: fieldType.i18n);
// Tap the cell to invoke the selection option editor
await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
@@ -377,7 +378,7 @@ void main() {
await tester.dismissCellEditor();
// Make sure the option is created and displayed in the cell
await tester.findSelectOptionWithNameInGrid(
tester.findSelectOptionWithNameInGrid(
rowIndex: 0,
name: tags.first,
);
@@ -392,13 +393,13 @@ void main() {
await tester.dismissCellEditor();
for (final tag in tags) {
await tester.findSelectOptionWithNameInGrid(
tester.findSelectOptionWithNameInGrid(
rowIndex: 0,
name: tag,
);
}
await tester.assertNumberOfSelectedOptionsInGrid(
tester.assertNumberOfSelectedOptionsInGrid(
rowIndex: 0,
matcher: findsNWidgets(4),
);
@@ -412,7 +413,7 @@ void main() {
}
await tester.dismissCellEditor();
await tester.assertNumberOfSelectedOptionsInGrid(
tester.assertNumberOfSelectedOptionsInGrid(
rowIndex: 0,
matcher: findsNothing,
);
@@ -425,16 +426,16 @@ void main() {
await tester.selectOption(name: tags[3]);
await tester.dismissCellEditor();
await tester.findSelectOptionWithNameInGrid(
tester.findSelectOptionWithNameInGrid(
rowIndex: 0,
name: tags[1],
);
await tester.findSelectOptionWithNameInGrid(
tester.findSelectOptionWithNameInGrid(
rowIndex: 0,
name: tags[3],
);
await tester.assertNumberOfSelectedOptionsInGrid(
tester.assertNumberOfSelectedOptionsInGrid(
rowIndex: 0,
matcher: findsNWidgets(2),
);
@@ -449,7 +450,7 @@ void main() {
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.Checklist;
await tester.createField(fieldType, fieldType.name);
await tester.createField(fieldType);
// assert that there is no progress bar in the grid
tester.assertChecklistCellInGrid(rowIndex: 0, percent: null);
@@ -461,22 +462,22 @@ void main() {
tester.assertChecklistEditorVisible(visible: true);
// create a new task with enter
await tester.createNewChecklistTask(name: "task 0", enter: true);
await tester.createNewChecklistTask(name: "task 1", enter: true);
// assert that the task is displayed
tester.assertChecklistTaskInEditor(
index: 0,
name: "task 0",
name: "task 1",
isChecked: false,
);
// update the task's name
await tester.renameChecklistTask(index: 0, name: "task 1");
await tester.renameChecklistTask(index: 0, name: "task 11");
// assert that the task's name is updated
tester.assertChecklistTaskInEditor(
index: 0,
name: "task 1",
name: "task 11",
isChecked: false,
);
@@ -1,5 +1,5 @@
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pbenum.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -10,7 +10,7 @@ import '../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('database field settings', () {
group('grid field settings test:', () {
testWidgets('field visibility', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
@@ -50,6 +50,15 @@ void main() {
await tester.tapHidePropertyButtonInFieldEditor();
await tester.dismissRowDetailPage();
tester.noFieldWithName('New field 1');
// the field should still be sort and filter-able
await tester.tapDatabaseFilterButton();
await tester.tapCreateFilterByFieldType(
FieldType.RichText,
"New field 1",
);
await tester.tapDatabaseSortButton();
await tester.tapCreateSortByFieldType(FieldType.RichText, "New field 1");
});
});
}
@@ -1,12 +1,14 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
import 'package:appflowy/plugins/database/widgets/field/type_option_editor/select/select_option.dart';
import 'package:appflowy/util/field_type_extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:intl/intl.dart';
import '../../shared/database_test_op.dart';
import '../../shared/util.dart';
@@ -14,7 +16,7 @@ import '../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('grid field editor:', () {
group('grid edit field test:', () {
testWidgets('rename existing field', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
@@ -23,7 +25,6 @@ void main() {
// Invoke the field editor
await tester.tapGridFieldWithName('Name');
await tester.tapEditFieldButton();
await tester.renameField('hello world');
await tester.dismissFieldEditor();
@@ -32,6 +33,32 @@ void main() {
await tester.pumpAndSettle();
});
testWidgets('edit field icon', (tester) async {
const icon = 'artificial_intelligence/ai-upscale-spark';
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
tester.assertFieldSvg('Name', FieldType.RichText);
// choose specific icon
await tester.tapGridFieldWithName('Name');
await tester.changeFieldIcon(icon);
await tester.dismissFieldEditor();
tester.assertFieldCustomSvg('Name', icon);
// remove icon
await tester.tapGridFieldWithName('Name');
await tester.changeFieldIcon('');
await tester.dismissFieldEditor();
tester.assertFieldSvg('Name', FieldType.RichText);
await tester.pumpAndSettle();
});
testWidgets('update field type of existing field', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
@@ -56,11 +83,22 @@ void main() {
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// create a field
await tester.createField(FieldType.Checklist, 'checklist');
await tester.createField(FieldType.Checklist);
tester.findFieldWithName(FieldType.Checklist.i18n);
// check the field is created successfully
tester.findFieldWithName('checklist');
await tester.pumpAndSettle();
// editing field type during field creation should change title
await tester.createField(FieldType.MultiSelect);
tester.findFieldWithName(FieldType.MultiSelect.i18n);
// not if the user changes the title manually though
const name = "New field";
await tester.createField(FieldType.DateTime);
await tester.tapGridFieldWithName(FieldType.DateTime.i18n);
await tester.renameField(name);
await tester.tapEditFieldButton();
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.URL);
tester.findFieldWithName(name);
});
testWidgets('delete field', (tester) async {
@@ -70,14 +108,14 @@ void main() {
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// create a field
await tester.createField(FieldType.Checkbox, 'New field 1');
await tester.createField(FieldType.Checkbox, name: 'New field 1');
// Delete the field
await tester.tapGridFieldWithName('New field 1');
await tester.tapDeletePropertyButton();
// confirm delete
await tester.tapDialogOkButton();
await tester.tapButtonWithName(LocaleKeys.space_delete.tr());
tester.noFieldWithName('New field 1');
await tester.pumpAndSettle();
@@ -90,10 +128,7 @@ void main() {
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// create a field
await tester.scrollToRight(find.byType(GridPage));
await tester.tapNewPropertyButton();
await tester.renameField('New field 1');
await tester.dismissFieldEditor();
await tester.createField(FieldType.RichText, name: 'New field 1');
// duplicate the field
await tester.tapGridFieldWithName('New field 1');
@@ -117,7 +152,7 @@ void main() {
await tester.dismissFieldEditor();
tester.findFieldWithName('Right');
// insert new field to the right
// insert new field to the left
await tester.tapGridFieldWithName('Type');
await tester.tapInsertFieldButton(left: true, name: "Left");
await tester.dismissFieldEditor();
@@ -126,26 +161,6 @@ void main() {
await tester.pumpAndSettle();
});
testWidgets('create checklist field', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.scrollToRight(find.byType(GridPage));
await tester.tapNewPropertyButton();
// Open the type option menu
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.Checklist);
// After update the field type, the cells should be updated
await tester.findCellByFieldType(FieldType.Checklist);
await tester.pumpAndSettle();
});
testWidgets('create list of fields', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
@@ -162,18 +177,10 @@ void main() {
FieldType.CreatedTime,
FieldType.Checkbox,
]) {
await tester.scrollToRight(find.byType(GridPage));
await tester.tapNewPropertyButton();
await tester.renameField(fieldType.name);
// Open the type option menu
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(fieldType);
await tester.dismissFieldEditor();
await tester.createField(fieldType);
// After update the field type, the cells should be updated
await tester.findCellByFieldType(fieldType);
tester.findCellByFieldType(fieldType);
await tester.pumpAndSettle();
}
});
@@ -190,15 +197,7 @@ void main() {
FieldType.Checklist,
FieldType.URL,
]) {
// create the field
await tester.scrollToRight(find.byType(GridPage));
await tester.tapNewPropertyButton();
await tester.renameField(fieldType.i18n);
// change field type
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(fieldType);
await tester.dismissFieldEditor();
await tester.createField(fieldType);
// open the field editor
await tester.tapGridFieldWithName(fieldType.i18n);
@@ -218,11 +217,7 @@ void main() {
await tester.scrollToRight(find.byType(GridPage));
// create a number field
await tester.tapNewPropertyButton();
await tester.renameField("Number");
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.Number);
await tester.dismissFieldEditor();
await tester.createField(FieldType.Number);
// enter some data into the first number cell
await tester.editCell(
@@ -243,7 +238,7 @@ void main() {
);
// open editor and change number format
await tester.tapGridFieldWithName('Number');
await tester.tapGridFieldWithName(FieldType.Number.i18n);
await tester.tapEditFieldButton();
await tester.changeNumberFieldFormat();
await tester.dismissFieldEditor();
@@ -276,7 +271,6 @@ void main() {
matching: find.byType(TextField),
);
await tester.enterText(inputField, text);
await tester.pumpAndSettle();
await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pumpAndSettle(const Duration(milliseconds: 500));
@@ -292,11 +286,7 @@ void main() {
await tester.scrollToRight(find.byType(GridPage));
// create a date field
await tester.tapNewPropertyButton();
await tester.renameField(FieldType.DateTime.i18n);
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.DateTime);
await tester.dismissFieldEditor();
await tester.createField(FieldType.DateTime);
// edit the first date cell
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.DateTime);
@@ -327,6 +317,30 @@ void main() {
);
});
testWidgets('text in viewport while typing', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.changeCalculateAtIndex(0, CalculationType.Count);
// add very large text with 200 lines
final largeText = List.generate(
200,
(index) => 'Line ${index + 1}',
).join('\n');
await tester.editCell(
rowIndex: 2,
fieldType: FieldType.RichText,
input: largeText,
);
// checks if last line is in view port
tester.expectToSeeText('Line 200');
});
// Disable this test because it fails on CI randomly
// testWidgets('last modified and created at field type options',
// (tester) async {
@@ -392,5 +406,188 @@ void main() {
// content: DateFormat('dd/MM/y hh:mm a').format(modified),
// );
// });
testWidgets('select option transform', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Grid,
);
// invoke the field editor of existing Single-Select field Type
await tester.tapGridFieldWithName('Type');
await tester.tapEditFieldButton();
// add some select options
await tester.tapAddSelectOptionButton();
for (final optionName in ['A', 'B', 'C']) {
final inputField = find.descendant(
of: find.byType(CreateOptionTextField),
matching: find.byType(TextField),
);
await tester.enterText(inputField, optionName);
await tester.testTextInput.receiveAction(TextInputAction.done);
}
await tester.dismissFieldEditor();
// select A in first row's cell under the Type field
await tester.tapCellInGrid(
rowIndex: 0,
fieldType: FieldType.SingleSelect,
);
await tester.selectOption(name: 'A');
await tester.dismissCellEditor();
tester.findSelectOptionWithNameInGrid(name: 'A', rowIndex: 0);
await tester.changeFieldTypeOfFieldWithName('Type', FieldType.RichText);
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.RichText,
content: "A",
cellIndex: 1,
);
// add some random text in the second row
await tester.editCell(
rowIndex: 1,
fieldType: FieldType.RichText,
input: "random",
cellIndex: 1,
);
tester.assertCellContent(
rowIndex: 1,
fieldType: FieldType.RichText,
content: "random",
cellIndex: 1,
);
await tester.changeFieldTypeOfFieldWithName(
'Type',
FieldType.SingleSelect,
);
tester.findSelectOptionWithNameInGrid(name: 'A', rowIndex: 0);
tester.assertNumberOfSelectedOptionsInGrid(
rowIndex: 1,
matcher: findsNothing,
);
// create a new field for testing
await tester.createField(FieldType.RichText, name: 'Test');
// edit the first 2 rows
await tester.editCell(
rowIndex: 0,
fieldType: FieldType.RichText,
input: "E,F",
cellIndex: 1,
);
await tester.editCell(
rowIndex: 1,
fieldType: FieldType.RichText,
input: "G",
cellIndex: 1,
);
await tester.changeFieldTypeOfFieldWithName(
'Test',
FieldType.MultiSelect,
);
tester.assertMultiSelectOption(contents: ['E', 'F'], rowIndex: 0);
tester.assertMultiSelectOption(contents: ['G'], rowIndex: 1);
await tester.tapCellInGrid(
rowIndex: 2,
fieldType: FieldType.MultiSelect,
);
await tester.selectOption(name: 'G');
await tester.createOption(name: 'H');
await tester.dismissCellEditor();
tester.findSelectOptionWithNameInGrid(name: 'A', rowIndex: 0);
tester.assertMultiSelectOption(contents: ['G', 'H'], rowIndex: 2);
await tester.changeFieldTypeOfFieldWithName(
'Test',
FieldType.RichText,
);
tester.assertCellContent(
rowIndex: 2,
fieldType: FieldType.RichText,
content: "G,H",
cellIndex: 1,
);
await tester.changeFieldTypeOfFieldWithName(
'Test',
FieldType.MultiSelect,
);
tester.assertMultiSelectOption(contents: ['E', 'F'], rowIndex: 0);
tester.assertMultiSelectOption(contents: ['G'], rowIndex: 1);
tester.assertMultiSelectOption(contents: ['G', 'H'], rowIndex: 2);
});
testWidgets('date time transform', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.scrollToRight(find.byType(GridPage));
// create a date field
await tester.createField(FieldType.DateTime);
// edit the first date cell
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.DateTime);
await tester.toggleIncludeTime();
final now = DateTime.now();
await tester.selectDay(content: now.day);
await tester.dismissCellEditor();
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.DateTime,
content: DateFormat('MMM dd, y HH:mm').format(now),
);
await tester.changeFieldTypeOfFieldWithName(
'Date',
FieldType.RichText,
);
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.RichText,
content: DateFormat('MMM dd, y HH:mm').format(now),
cellIndex: 1,
);
await tester.editCell(
rowIndex: 1,
fieldType: FieldType.RichText,
input: "Oct 5, 2024",
cellIndex: 1,
);
tester.assertCellContent(
rowIndex: 1,
fieldType: FieldType.RichText,
content: "Oct 5, 2024",
cellIndex: 1,
);
await tester.changeFieldTypeOfFieldWithName(
'Date',
FieldType.DateTime,
);
tester.assertCellContent(
rowIndex: 0,
fieldType: FieldType.DateTime,
content: DateFormat('MMM dd, y').format(now),
);
tester.assertCellContent(
rowIndex: 1,
fieldType: FieldType.DateTime,
content: "Oct 05, 2024",
);
});
});
}
@@ -1,17 +1,21 @@
import 'package:appflowy/plugins/database/application/field/filter_entities.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/choicechip/checkbox.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/choicechip/text.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy/plugins/database/widgets/row/row_detail.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../../shared/database_test_op.dart';
import '../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('grid filter:', () {
testWidgets('add text filter', (tester) async {
await tester.openV020database();
await tester.openTestDatabase(v020GridFileName);
// create a filter
await tester.tapDatabaseFilterButton();
@@ -19,68 +23,68 @@ void main() {
await tester.tapFilterButtonInGrid('Name');
// enter 'A' in the filter text field
await tester.assertNumberOfRowsInGridPage(10);
tester.assertNumberOfRowsInGridPage(10);
await tester.enterTextInTextFilter('A');
await tester.assertNumberOfRowsInGridPage(1);
tester.assertNumberOfRowsInGridPage(1);
// after remove the filter, the grid should show all rows
await tester.enterTextInTextFilter('');
await tester.assertNumberOfRowsInGridPage(10);
tester.assertNumberOfRowsInGridPage(10);
await tester.enterTextInTextFilter('B');
await tester.assertNumberOfRowsInGridPage(1);
tester.assertNumberOfRowsInGridPage(1);
// open the menu to delete the filter
await tester.tapDisclosureButtonInFinder(find.byType(TextFilterEditor));
await tester.tapDeleteFilterButtonInGrid();
await tester.assertNumberOfRowsInGridPage(10);
tester.assertNumberOfRowsInGridPage(10);
await tester.pumpAndSettle();
});
testWidgets('add checkbox filter', (tester) async {
await tester.openV020database();
await tester.openTestDatabase(v020GridFileName);
// create a filter
await tester.tapDatabaseFilterButton();
await tester.tapCreateFilterByFieldType(FieldType.Checkbox, 'Done');
await tester.assertNumberOfRowsInGridPage(5);
tester.assertNumberOfRowsInGridPage(5);
await tester.tapFilterButtonInGrid('Done');
await tester.tapCheckboxFilterButtonInGrid();
await tester.tapUnCheckedButtonOnCheckboxFilter();
await tester.assertNumberOfRowsInGridPage(5);
tester.assertNumberOfRowsInGridPage(5);
await tester
.tapDisclosureButtonInFinder(find.byType(CheckboxFilterEditor));
await tester.tapDeleteFilterButtonInGrid();
await tester.assertNumberOfRowsInGridPage(10);
tester.assertNumberOfRowsInGridPage(10);
await tester.pumpAndSettle();
});
testWidgets('add checklist filter', (tester) async {
await tester.openV020database();
await tester.openTestDatabase(v020GridFileName);
// create a filter
await tester.tapDatabaseFilterButton();
await tester.tapCreateFilterByFieldType(FieldType.Checklist, 'checklist');
// By default, the condition of checklist filter is 'uncompleted'
await tester.assertNumberOfRowsInGridPage(9);
tester.assertNumberOfRowsInGridPage(9);
await tester.tapFilterButtonInGrid('checklist');
await tester.tapChecklistFilterButtonInGrid();
await tester.tapCompletedButtonOnChecklistFilter();
await tester.assertNumberOfRowsInGridPage(1);
tester.assertNumberOfRowsInGridPage(1);
await tester.pumpAndSettle();
});
testWidgets('add single select filter', (tester) async {
await tester.openV020database();
await tester.openTestDatabase(v020GridFileName);
// create a filter
await tester.tapDatabaseFilterButton();
@@ -90,27 +94,27 @@ void main() {
// select the option 's6'
await tester.tapOptionFilterWithName('s6');
await tester.assertNumberOfRowsInGridPage(0);
tester.assertNumberOfRowsInGridPage(0);
// unselect the option 's6'
await tester.tapOptionFilterWithName('s6');
await tester.assertNumberOfRowsInGridPage(10);
tester.assertNumberOfRowsInGridPage(10);
// select the option 's5'
await tester.tapOptionFilterWithName('s5');
await tester.assertNumberOfRowsInGridPage(1);
tester.assertNumberOfRowsInGridPage(1);
// select the option 's4'
await tester.tapOptionFilterWithName('s4');
// The row with 's4' should be shown.
await tester.assertNumberOfRowsInGridPage(1);
tester.assertNumberOfRowsInGridPage(2);
await tester.pumpAndSettle();
});
testWidgets('add multi select filter', (tester) async {
await tester.openV020database();
await tester.openTestDatabase(v020GridFileName);
// create a filter
await tester.tapDatabaseFilterButton();
@@ -124,17 +128,95 @@ void main() {
// select the option 'm1'. Any option with 'm1' should be shown.
await tester.tapOptionFilterWithName('m1');
await tester.assertNumberOfRowsInGridPage(5);
tester.assertNumberOfRowsInGridPage(5);
await tester.tapOptionFilterWithName('m1');
// select the option 'm2'. Any option with 'm2' should be shown.
await tester.tapOptionFilterWithName('m2');
await tester.assertNumberOfRowsInGridPage(4);
tester.assertNumberOfRowsInGridPage(4);
await tester.tapOptionFilterWithName('m2');
// select the option 'm4'. Any option with 'm4' should be shown.
await tester.tapOptionFilterWithName('m4');
await tester.assertNumberOfRowsInGridPage(1);
tester.assertNumberOfRowsInGridPage(1);
await tester.pumpAndSettle();
});
testWidgets('add date filter', (tester) async {
await tester.openTestDatabase(v020GridFileName);
// create a filter
await tester.tapDatabaseFilterButton();
await tester.tapCreateFilterByFieldType(FieldType.DateTime, 'date');
// By default, the condition of date filter is current day and time
tester.assertNumberOfRowsInGridPage(0);
await tester.tapFilterButtonInGrid('date');
await tester.changeDateFilterCondition(DateTimeFilterCondition.before);
tester.assertNumberOfRowsInGridPage(7);
await tester.changeDateFilterCondition(DateTimeFilterCondition.isEmpty);
tester.assertNumberOfRowsInGridPage(3);
await tester.pumpAndSettle();
});
testWidgets('add timestamp filter', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.createField(
FieldType.CreatedTime,
name: 'Created at',
);
// create a filter
await tester.tapDatabaseFilterButton();
await tester.tapCreateFilterByFieldType(
FieldType.CreatedTime,
'Created at',
);
await tester.pumpAndSettle();
tester.assertNumberOfRowsInGridPage(3);
await tester.tapFilterButtonInGrid('Created at');
await tester.changeDateFilterCondition(DateTimeFilterCondition.before);
tester.assertNumberOfRowsInGridPage(0);
await tester.pumpAndSettle();
});
testWidgets('create new row when filters don\'t autofill', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// create a filter
await tester.tapDatabaseFilterButton();
await tester.tapCreateFilterByFieldType(
FieldType.RichText,
'Name',
);
tester.assertNumberOfRowsInGridPage(3);
await tester.tapCreateRowButtonInGrid();
tester.assertNumberOfRowsInGridPage(4);
await tester.tapFilterButtonInGrid('Name');
await tester
.changeTextFilterCondition(TextFilterConditionPB.TextIsNotEmpty);
await tester.dismissCellEditor();
tester.assertNumberOfRowsInGridPage(0);
await tester.tapCreateRowButtonInGrid();
tester.assertNumberOfRowsInGridPage(0);
expect(find.byType(RowDetailPage), findsOneWidget);
await tester.pumpAndSettle();
});
@@ -0,0 +1,297 @@
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:appflowy/core/config/kv.dart';
import 'package:appflowy/core/config/kv_keys.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/media_cell_editor.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/shared_widget.dart';
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import '../../shared/database_test_op.dart';
import '../../shared/mock/mock_file_picker.dart';
import '../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('media type option in database', () {
testWidgets('add media field and add files two times', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Invoke the field editor
await tester.tapGridFieldWithName('Type');
await tester.tapEditFieldButton();
// Change to media type
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.Media);
await tester.dismissFieldEditor();
// Open media cell editor
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.Media);
await tester.findMediaCellEditor(findsOneWidget);
// Prepare files for upload from local
final firstImage =
await rootBundle.load('assets/test/images/sample.jpeg');
final secondImage =
await rootBundle.load('assets/test/images/sample.gif');
final tempDirectory = await getTemporaryDirectory();
final firstImagePath = p.join(tempDirectory.path, 'sample.jpeg');
final firstFile = File(firstImagePath)
..writeAsBytesSync(firstImage.buffer.asUint8List());
final secondImagePath = p.join(tempDirectory.path, 'sample.gif');
final secondFile = File(secondImagePath)
..writeAsBytesSync(secondImage.buffer.asUint8List());
mockPickFilePaths(paths: [firstImagePath]);
await getIt<KeyValueStorage>().set(KVKeys.kCloudType, '0');
// Click on add file button in the Media Cell Editor
await tester.tap(find.text(LocaleKeys.grid_media_addFileOrImage.tr()));
await tester.pumpAndSettle();
// Tap on the upload interaction
await tester.tapFileUploadHint();
// Expect one file
expect(find.byType(RenderMedia), findsOneWidget);
// Mock second file
mockPickFilePaths(paths: [secondImagePath]);
// Click on add file button in the Media Cell Editor
await tester.tap(find.text(LocaleKeys.grid_media_addFileOrImage.tr()));
await tester.pumpAndSettle();
// Tap on the upload interaction
await tester.tapFileUploadHint();
await tester.pumpAndSettle();
// Expect two files
expect(find.byType(RenderMedia), findsNWidgets(2));
// Remove the temp files
await Future.wait([firstFile.delete(), secondFile.delete()]);
});
testWidgets('add two files at once', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Invoke the field editor
await tester.tapGridFieldWithName('Type');
await tester.tapEditFieldButton();
// Change to media type
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.Media);
await tester.dismissFieldEditor();
// Open media cell editor
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.Media);
await tester.findMediaCellEditor(findsOneWidget);
// Prepare files for upload from local
final firstImage =
await rootBundle.load('assets/test/images/sample.jpeg');
final secondImage =
await rootBundle.load('assets/test/images/sample.gif');
final tempDirectory = await getTemporaryDirectory();
final firstImagePath = p.join(tempDirectory.path, 'sample.jpeg');
final firstFile = File(firstImagePath)
..writeAsBytesSync(firstImage.buffer.asUint8List());
final secondImagePath = p.join(tempDirectory.path, 'sample.gif');
final secondFile = File(secondImagePath)
..writeAsBytesSync(secondImage.buffer.asUint8List());
mockPickFilePaths(paths: [firstImagePath, secondImagePath]);
await getIt<KeyValueStorage>().set(KVKeys.kCloudType, '0');
// Click on add file button in the Media Cell Editor
await tester.tap(find.text(LocaleKeys.grid_media_addFileOrImage.tr()));
await tester.pumpAndSettle();
// Tap on the upload interaction
await tester.tapFileUploadHint();
// Expect two files
expect(find.byType(RenderMedia), findsNWidgets(2));
// Remove the temp files
await Future.wait([firstFile.delete(), secondFile.delete()]);
});
testWidgets('delete files', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Invoke the field editor
await tester.tapGridFieldWithName('Type');
await tester.tapEditFieldButton();
// Change to media type
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.Media);
await tester.dismissFieldEditor();
// Open media cell editor
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.Media);
await tester.findMediaCellEditor(findsOneWidget);
// Prepare files for upload from local
final firstImage =
await rootBundle.load('assets/test/images/sample.jpeg');
final secondImage =
await rootBundle.load('assets/test/images/sample.gif');
final tempDirectory = await getTemporaryDirectory();
final firstImagePath = p.join(tempDirectory.path, 'sample.jpeg');
final firstFile = File(firstImagePath)
..writeAsBytesSync(firstImage.buffer.asUint8List());
final secondImagePath = p.join(tempDirectory.path, 'sample.gif');
final secondFile = File(secondImagePath)
..writeAsBytesSync(secondImage.buffer.asUint8List());
mockPickFilePaths(paths: [firstImagePath, secondImagePath]);
await getIt<KeyValueStorage>().set(KVKeys.kCloudType, '0');
// Click on add file button in the Media Cell Editor
await tester.tap(find.text(LocaleKeys.grid_media_addFileOrImage.tr()));
await tester.pumpAndSettle();
// Tap on the upload interaction
await tester.tapFileUploadHint();
// Expect two files
expect(find.byType(RenderMedia), findsNWidgets(2));
// Tap on the three dots menu for the first RenderMedia
final mediaMenuFinder = find.descendant(
of: find.byType(RenderMedia),
matching: find.byFlowySvg(FlowySvgs.three_dots_s),
);
await tester.tap(mediaMenuFinder.first);
await tester.pumpAndSettle();
// Tap on the delete button
await tester.tap(find.text(LocaleKeys.grid_media_delete.tr()));
await tester.pumpAndSettle();
// Tap on Delete button in the confirmation dialog
await tester.tap(
find.descendant(
of: find.byType(SpaceCancelOrConfirmButton),
matching: find.text(LocaleKeys.grid_media_delete.tr()),
),
);
await tester.pumpAndSettle(const Duration(seconds: 1));
// Expect one file
expect(find.byType(RenderMedia), findsOneWidget);
// Remove the temp files
await Future.wait([firstFile.delete(), secondFile.delete()]);
});
testWidgets('show file names', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Invoke the field editor
await tester.tapGridFieldWithName('Type');
await tester.tapEditFieldButton();
// Change to media type
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.Media);
await tester.dismissFieldEditor();
// Open media cell editor
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.Media);
await tester.findMediaCellEditor(findsOneWidget);
// Prepare files for upload from local
final firstImage =
await rootBundle.load('assets/test/images/sample.jpeg');
final secondImage =
await rootBundle.load('assets/test/images/sample.gif');
final tempDirectory = await getTemporaryDirectory();
final firstImagePath = p.join(tempDirectory.path, 'sample.jpeg');
final firstFile = File(firstImagePath)
..writeAsBytesSync(firstImage.buffer.asUint8List());
final secondImagePath = p.join(tempDirectory.path, 'sample.gif');
final secondFile = File(secondImagePath)
..writeAsBytesSync(secondImage.buffer.asUint8List());
mockPickFilePaths(paths: [firstImagePath, secondImagePath]);
await getIt<KeyValueStorage>().set(KVKeys.kCloudType, '0');
// Click on add file button in the Media Cell Editor
await tester.tap(find.text(LocaleKeys.grid_media_addFileOrImage.tr()));
await tester.pumpAndSettle();
// Tap on the upload interaction
await tester.tapFileUploadHint();
// Expect two files
expect(find.byType(RenderMedia), findsNWidgets(2));
await tester.dismissCellEditor();
await tester.pumpAndSettle();
// Open first row in row detail view then toggle show file names
await tester.openFirstRowDetailPage();
await tester.pumpAndSettle();
// Expect file names to not be shown (hidden)
expect(find.text('sample.jpeg'), findsNothing);
expect(find.text('sample.gif'), findsNothing);
await tester.tapGridFieldWithNameInRowDetailPage('Type');
await tester.pumpAndSettle();
// Toggle show file names
await tester.tap(find.byType(Toggle));
await tester.pumpAndSettle();
// Expect file names to be shown
expect(find.text('sample.jpeg'), findsOneWidget);
expect(find.text('sample.gif'), findsOneWidget);
await tester.dismissRowDetailPage();
await tester.pumpAndSettle();
// Remove the temp files
await Future.wait([firstFile.delete(), secondFile.delete()]);
});
});
}
@@ -0,0 +1,188 @@
import 'dart:io';
import 'package:appflowy/core/config/kv.dart';
import 'package:appflowy/core/config/kv_keys.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/widgets/card/card.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/media_cell_editor.dart';
import 'package:appflowy/plugins/database/widgets/row/row_banner.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy/shared/af_image.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pbenum.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import '../../shared/database_test_op.dart';
import '../../shared/mock/mock_file_picker.dart';
import '../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('database row cover', () {
testWidgets('add image to media field and check if cover is set (grid)',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Invoke the field editor
await tester.tapGridFieldWithName('Type');
await tester.tapEditFieldButton();
// Change to media type
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(FieldType.Media);
await tester.dismissFieldEditor();
// Prepare file for upload from local
final image = await rootBundle.load('assets/test/images/sample.jpeg');
final tempDirectory = await getTemporaryDirectory();
final imagePath = p.join(tempDirectory.path, 'sample.jpeg');
final file = File(imagePath)
..writeAsBytesSync(image.buffer.asUint8List());
mockPickFilePaths(paths: [imagePath]);
await getIt<KeyValueStorage>().set(KVKeys.kCloudType, '0');
// Open media cell editor
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.Media);
await tester.findMediaCellEditor(findsOneWidget);
// Click on add file button in the Media Cell Editor
await tester.tap(find.text(LocaleKeys.grid_media_addFileOrImage.tr()));
await tester.pumpAndSettle();
// Tap on the upload interaction
await tester.tapFileUploadHint();
// Expect one file
expect(find.byType(RenderMedia), findsOneWidget);
// Close cell editor
await tester.dismissCellEditor();
// Open first row in row detail view
await tester.openFirstRowDetailPage();
await tester.pumpAndSettle();
// Expect a cover to be shown
expect(find.byType(RowCover), findsOneWidget);
// Remove the temp file
await Future.wait([file.delete()]);
});
testWidgets('add and remove cover from Row Detail Card', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Open first row in row detail view
await tester.openFirstRowDetailPage();
await tester.pumpAndSettle();
// Expect no cover
expect(find.byType(RowCover), findsNothing);
// Hover on RowBanner to show Add Cover button
await tester.hoverRowBanner();
// Click on Add Cover button
await tester.tapAddCoverButton();
// Expect a cover to be shown - the default asset cover
expect(find.byType(RowCover), findsOneWidget);
// Tap on the delete cover button
await tester.tapButton(find.byType(DeleteCoverButton));
await tester.pumpAndSettle();
// Expect no cover to be shown
expect(find.byType(AFImage), findsNothing);
});
testWidgets('add and change cover and check in Board', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
await tester.pumpAndSettle();
// Open "Card 1"
await tester.tap(find.text('Card 1'), warnIfMissed: false);
await tester.pumpAndSettle();
// Expect no cover
expect(find.byType(RowCover), findsNothing);
// Hover on RowBanner to show Add Cover button
await tester.hoverRowBanner();
// Click on Add Cover button
await tester.tapAddCoverButton();
// Expect default cover to be shown
expect(find.byType(RowCover), findsOneWidget);
// Prepare image for upload from local
final image = await rootBundle.load('assets/test/images/sample.jpeg');
final tempDirectory = await getTemporaryDirectory();
final imagePath = p.join(tempDirectory.path, 'sample.jpeg');
final file = File(imagePath)
..writeAsBytesSync(image.buffer.asUint8List());
mockPickFilePaths(paths: [imagePath]);
await getIt<KeyValueStorage>().set(KVKeys.kCloudType, '0');
// Hover on RowBanner to show Change Cover button
await tester.hoverRowBanner();
// Tap on the change cover button
await tester.tapButtonWithName(
LocaleKeys.document_plugins_cover_changeCover.tr(),
);
await tester.pumpAndSettle();
// Change tab to Upload tab
await tester.tapButtonWithName(
LocaleKeys.document_imageBlock_upload_label.tr(),
);
// Tab on the upload button
await tester.tapButtonWithName(
LocaleKeys.document_imageBlock_upload_placeholder.tr(),
);
// Expect one cover
expect(find.byType(RowCover), findsOneWidget);
// Expect the cover to be shown both in RowCover and in CardCover
expect(find.byType(AFImage), findsNWidgets(2));
// Dismiss Row Detail Page
await tester.dismissRowDetailPage();
// Expect a cover to be shown in CardCover
expect(
find.descendant(
of: find.byType(CardCover),
matching: find.byType(AFImage),
),
findsOneWidget,
);
// Remove the temp file
await Future.wait([file.delete()]);
});
});
}
@@ -1,10 +1,18 @@
import 'package:appflowy/plugins/database/widgets/cell/desktop_row_detail/desktop_row_detail_checklist_cell.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/checklist_cell_editor.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:appflowy/plugins/database/widgets/row/row_banner.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/header/desktop_field_cell.dart';
import 'package:appflowy/plugins/database/widgets/row/row_detail.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emoji_icon_widget.dart';
import 'package:appflowy/util/field_type_extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -33,26 +41,7 @@ void main() {
await tester.assertDocumentExistInRowDetailPage();
});
testWidgets('add emoji', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
// Create a new grid
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
await tester.hoverRowBanner();
await tester.openEmojiPicker();
await tester.tapEmoji('😀');
// After select the emoji, the EmojiButton will show up
await tester.tapButton(find.byType(EmojiButton));
});
testWidgets('update emoji', (tester) async {
testWidgets('add and update emoji', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
@@ -65,8 +54,18 @@ void main() {
await tester.openEmojiPicker();
await tester.tapEmoji('😀');
// Update existing selected emoji
await tester.tapButton(find.byType(EmojiButton));
// expect to find the emoji selected
final firstEmojiFinder = find.byWidgetPredicate(
(w) => w is FlowyText && w.text == '😀',
);
// There are 2 eomjis - one in the row banner and another in the primary cell
expect(firstEmojiFinder, findsNWidgets(2));
// Update existing selected emoji - tap on it to update
await tester.tapButton(find.byType(EmojiIconWidget));
await tester.pumpAndSettle();
await tester.tapEmoji('😅');
// The emoji already displayed in the row banner
@@ -93,7 +92,9 @@ void main() {
await tester.tapEmoji('😀');
// Remove the emoji
await tester.tapButton(find.byType(RemoveEmojiButton));
await tester.tapButton(find.byType(EmojiIconWidget));
await tester.tapButton(find.text(LocaleKeys.button_remove.tr()));
final emojiText = find.byWidgetPredicate(
(widget) => widget is FlowyText && widget.text == '😀',
);
@@ -121,15 +122,24 @@ void main() {
FieldType.Checkbox,
]) {
await tester.tapRowDetailPageCreatePropertyButton();
await tester.renameField(fieldType.name);
// Open the type option menu
await tester.tapSwitchFieldTypeButton();
await tester.selectFieldType(fieldType);
final field = find.descendant(
of: find.byType(RowDetailPage),
matching: find.byWidgetPredicate(
(widget) =>
widget is FieldCellButton &&
widget.field.name == fieldType.i18n,
),
);
expect(field, findsOneWidget);
// After update the field type, the cells should be updated
await tester.findCellByFieldType(fieldType);
tester.findCellByFieldType(fieldType);
await tester.scrollRowDetailByOffset(const Offset(0, -50));
}
});
@@ -309,7 +319,7 @@ void main() {
await tester.tapRowDetailPageDeleteRowButton();
await tester.tapEscButton();
await tester.assertNumberOfRowsInGridPage(2);
tester.assertNumberOfRowsInGridPage(2);
});
testWidgets('duplicate row', (tester) async {
@@ -326,7 +336,141 @@ void main() {
await tester.tapRowDetailPageDuplicateRowButton();
await tester.tapEscButton();
await tester.assertNumberOfRowsInGridPage(4);
tester.assertNumberOfRowsInGridPage(4);
});
testWidgets('edit checklist cell', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.Checklist;
await tester.createField(fieldType);
await tester.openFirstRowDetailPage();
await tester.hoverOnWidget(
find.byType(ChecklistRowDetailCell),
onHover: () async {
await tester.tapButton(find.byType(ChecklistItemControl));
},
);
tester.assertPhantomChecklistItemAtIndex(index: 0);
await tester.enterText(find.byType(PhantomChecklistItem), 'task 1');
await tester.pumpAndSettle();
await tester.simulateKeyEvent(LogicalKeyboardKey.enter);
await tester.pumpAndSettle(const Duration(milliseconds: 500));
tester.assertChecklistTaskInEditor(
index: 0,
name: "task 1",
isChecked: false,
);
tester.assertPhantomChecklistItemAtIndex(index: 1);
await tester.enterText(find.byType(PhantomChecklistItem), 'task 2');
await tester.pumpAndSettle();
await tester.simulateKeyEvent(LogicalKeyboardKey.enter);
await tester.pumpAndSettle(const Duration(milliseconds: 500));
tester.assertChecklistTaskInEditor(
index: 1,
name: "task 2",
isChecked: false,
);
tester.assertPhantomChecklistItemAtIndex(index: 2);
await tester.simulateKeyEvent(LogicalKeyboardKey.escape);
await tester.pumpAndSettle();
expect(find.byType(PhantomChecklistItem), findsNothing);
await tester.renameChecklistTask(index: 0, name: "task -1", enter: false);
await tester.simulateKeyEvent(LogicalKeyboardKey.enter);
tester.assertChecklistTaskInEditor(
index: 0,
name: "task -1",
isChecked: false,
);
tester.assertPhantomChecklistItemAtIndex(index: 1);
await tester.enterText(find.byType(PhantomChecklistItem), 'task 0');
await tester.pumpAndSettle();
await tester.simulateKeyEvent(LogicalKeyboardKey.enter);
await tester.pumpAndSettle(const Duration(milliseconds: 500));
tester.assertPhantomChecklistItemAtIndex(index: 2);
await tester.checkChecklistTask(index: 1);
expect(find.byType(PhantomChecklistItem), findsNothing);
expect(find.byType(ChecklistItem), findsNWidgets(3));
tester.assertChecklistTaskInEditor(
index: 0,
name: "task -1",
isChecked: false,
);
tester.assertChecklistTaskInEditor(
index: 1,
name: "task 0",
isChecked: true,
);
tester.assertChecklistTaskInEditor(
index: 2,
name: "task 2",
isChecked: false,
);
await tester.tapButton(
find.descendant(
of: find.byType(ProgressAndHideCompleteButton),
matching: find.byType(FlowyIconButton),
),
);
expect(find.byType(ChecklistItem), findsNWidgets(2));
tester.assertChecklistTaskInEditor(
index: 0,
name: "task -1",
isChecked: false,
);
tester.assertChecklistTaskInEditor(
index: 1,
name: "task 2",
isChecked: false,
);
await tester.renameChecklistTask(index: 1, name: "task 3", enter: false);
await tester.simulateKeyEvent(LogicalKeyboardKey.enter);
await tester.renameChecklistTask(index: 0, name: "task 1", enter: false);
await tester.simulateKeyEvent(LogicalKeyboardKey.enter);
await tester.enterText(find.byType(PhantomChecklistItem), 'task 2');
await tester.pumpAndSettle();
await tester.simulateKeyEvent(LogicalKeyboardKey.enter);
await tester.pumpAndSettle(const Duration(milliseconds: 500));
tester.assertChecklistTaskInEditor(
index: 0,
name: "task 1",
isChecked: false,
);
tester.assertChecklistTaskInEditor(
index: 1,
name: "task 2",
isChecked: false,
);
tester.assertChecklistTaskInEditor(
index: 2,
name: "task 3",
isChecked: false,
);
tester.assertPhantomChecklistItemAtIndex(index: 2);
await tester.checkChecklistTask(index: 1);
expect(find.byType(ChecklistItem), findsNWidgets(2));
});
});
}
@@ -1,65 +0,0 @@
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../../shared/database_test_op.dart';
import '../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('grid', () {
testWidgets('create row of the grid', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.tapCreateRowButtonInGrid();
// 3 initial rows + 1 created
await tester.assertNumberOfRowsInGridPage(4);
await tester.pumpAndSettle();
});
testWidgets('create row from row menu of the grid', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.hoverOnFirstRowOfGrid();
await tester.tapCreateRowButtonInRowMenuOfGrid();
// 3 initial rows + 1 created
await tester.assertNumberOfRowsInGridPage(4);
await tester.pumpAndSettle();
});
testWidgets('delete row of the grid', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.hoverOnFirstRowOfGrid();
// Open the row menu and then click the delete
await tester.tapRowMenuButtonInGrid();
await tester.tapDeleteOnRowMenu();
// 3 initial rows - 1 deleted
await tester.assertNumberOfRowsInGridPage(2);
await tester.pumpAndSettle();
});
testWidgets('check number of row indicator in the initial grid',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.pumpAndSettle();
});
});
}
@@ -9,7 +9,7 @@ void main() {
group('database', () {
testWidgets('import v0.2.0 database data', (tester) async {
await tester.openV020database();
await tester.openTestDatabase(v020GridFileName);
// wait the database data is loaded
await tester.pumpAndSettle(const Duration(microseconds: 500));
@@ -115,7 +115,7 @@ void main() {
[],
];
for (final (index, contents) in multiSelectCells.indexed) {
await tester.assertMultiSelectOption(
tester.assertMultiSelectOption(
rowIndex: index,
contents: contents,
);
@@ -1,3 +1,4 @@
import 'package:appflowy/plugins/database/grid/presentation/widgets/sort/sort_editor.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -7,9 +8,9 @@ import '../../shared/database_test_op.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('grid', () {
testWidgets('add text sort', (tester) async {
await tester.openV020database();
group('grid sort:', () {
testWidgets('text sort', (tester) async {
await tester.openTestDatabase(v020GridFileName);
// create a sort
await tester.tapDatabaseSortButton();
await tester.tapCreateSortByFieldType(FieldType.RichText, 'Name');
@@ -37,7 +38,7 @@ void main() {
// open the sort menu and select order by descending
await tester.tapSortMenuInSettingBar();
await tester.tapSortButtonByName('Name');
await tester.tapEditSortConditionButtonByFieldName('Name');
await tester.tapSortByDescending();
for (final (index, content) in <String>[
'E',
@@ -60,7 +61,7 @@ void main() {
// delete all sorts
await tester.tapSortMenuInSettingBar();
await tester.tapAllSortButton();
await tester.tapDeleteAllSortsButton();
// check the text cell order
for (final (index, content) in <String>[
@@ -84,8 +85,8 @@ void main() {
await tester.pumpAndSettle();
});
testWidgets('add checkbox sort', (tester) async {
await tester.openV020database();
testWidgets('checkbox', (tester) async {
await tester.openTestDatabase(v020GridFileName);
// create a sort
await tester.tapDatabaseSortButton();
await tester.tapCreateSortByFieldType(FieldType.Checkbox, 'Done');
@@ -111,7 +112,7 @@ void main() {
// open the sort menu and select order by descending
await tester.tapSortMenuInSettingBar();
await tester.tapSortButtonByName('Done');
await tester.tapEditSortConditionButtonByFieldName('Done');
await tester.tapSortByDescending();
for (final (index, content) in <bool>[
true,
@@ -134,8 +135,8 @@ void main() {
await tester.pumpAndSettle();
});
testWidgets('add number sort', (tester) async {
await tester.openV020database();
testWidgets('number', (tester) async {
await tester.openTestDatabase(v020GridFileName);
// create a sort
await tester.tapDatabaseSortButton();
await tester.tapCreateSortByFieldType(FieldType.Number, 'number');
@@ -162,7 +163,7 @@ void main() {
// open the sort menu and select order by descending
await tester.tapSortMenuInSettingBar();
await tester.tapSortButtonByName('number');
await tester.tapEditSortConditionButtonByFieldName('number');
await tester.tapSortByDescending();
for (final (index, content) in <String>[
'12',
@@ -186,15 +187,15 @@ void main() {
await tester.pumpAndSettle();
});
testWidgets('add checkbox and number sort', (tester) async {
await tester.openV020database();
testWidgets('checkbox and number', (tester) async {
await tester.openTestDatabase(v020GridFileName);
// create a sort
await tester.tapDatabaseSortButton();
await tester.tapCreateSortByFieldType(FieldType.Checkbox, 'Done');
// open the sort menu and sort checkbox by descending
await tester.tapSortMenuInSettingBar();
await tester.tapSortButtonByName('Done');
await tester.tapEditSortConditionButtonByFieldName('Done');
await tester.tapSortByDescending();
for (final (index, content) in <bool>[
true,
@@ -220,7 +221,7 @@ void main() {
FieldType.Number,
'number',
);
await tester.tapSortButtonByName('number');
await tester.tapEditSortConditionButtonByFieldName('number');
await tester.tapSortByDescending();
// check checkbox cell order
@@ -266,14 +267,14 @@ void main() {
});
testWidgets('reorder sort', (tester) async {
await tester.openV020database();
await tester.openTestDatabase(v020GridFileName);
// create a sort
await tester.tapDatabaseSortButton();
await tester.tapCreateSortByFieldType(FieldType.Checkbox, 'Done');
// open the sort menu and sort checkbox by descending
await tester.tapSortMenuInSettingBar();
await tester.tapSortButtonByName('Done');
await tester.tapEditSortConditionButtonByFieldName('Done');
await tester.tapSortByDescending();
// add another sort, this time by number descending
@@ -282,7 +283,7 @@ void main() {
FieldType.Number,
'number',
);
await tester.tapSortButtonByName('number');
await tester.tapEditSortConditionButtonByFieldName('number');
await tester.tapSortByDescending();
// check checkbox cell order
@@ -370,5 +371,101 @@ void main() {
);
}
});
testWidgets('edit field', (tester) async {
await tester.openTestDatabase(v020GridFileName);
// create a number sort
await tester.tapDatabaseSortButton();
await tester.tapCreateSortByFieldType(FieldType.Number, 'number');
// check the number cell order
for (final (index, content) in <String>[
'-2',
'-1',
'0.1',
'0.2',
'1',
'2',
'10',
'11',
'12',
'',
].indexed) {
tester.assertCellContent(
rowIndex: index,
fieldType: FieldType.Number,
content: content,
);
}
final textCells = <String>[
'B',
'A',
'C',
'D',
'E',
'',
'',
'',
'',
'',
];
for (final (index, content) in textCells.indexed) {
tester.assertCellContent(
rowIndex: index,
fieldType: FieldType.RichText,
content: content,
);
}
// edit the name of the number field
await tester.tapGridFieldWithName('number');
await tester.renameField('hello world');
await tester.dismissFieldEditor();
await tester.tapGridFieldWithName('hello world');
await tester.dismissFieldEditor();
// expect name to be changed as well
await tester.tapSortMenuInSettingBar();
final sortItem = find.ancestor(
of: find.text('hello world'),
matching: find.byType(DatabaseSortItem),
);
expect(sortItem, findsOneWidget);
// change the field type of the field to checkbox
await tester.tapGridFieldWithName('hello world');
await tester.changeFieldTypeOfFieldWithName(
'hello world',
FieldType.Checkbox,
);
// expect name to be changed as well
await tester.tapSortMenuInSettingBar();
expect(sortItem, findsOneWidget);
final newTextCells = <String>[
'A',
'B',
'C',
'D',
'E',
'',
'',
'',
'',
'',
];
for (final (index, content) in newTextCells.indexed) {
tester.assertCellContent(
rowIndex: index,
fieldType: FieldType.RichText,
content: content,
);
}
});
});
}
@@ -0,0 +1,20 @@
import 'package:integration_test/integration_test.dart';
import 'database_cell_test.dart' as database_cell_test;
import 'database_field_settings_test.dart' as database_field_settings_test;
import 'database_field_test.dart' as database_field_test;
import 'database_row_page_test.dart' as database_row_page_test;
import 'database_setting_test.dart' as database_setting_test;
import 'database_share_test.dart' as database_share_test;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
database_cell_test.main();
database_field_test.main();
database_field_settings_test.main();
database_share_test.main();
database_row_page_test.main();
database_setting_test.main();
// DON'T add more tests here.
}
@@ -0,0 +1,22 @@
import 'package:integration_test/integration_test.dart';
import 'database_calendar_test.dart' as database_calendar_test;
import 'database_filter_test.dart' as database_filter_test;
import 'database_media_test.dart' as database_media_test;
import 'database_row_cover_test.dart' as database_row_cover_test;
import 'database_share_test.dart' as database_share_test;
import 'database_sort_test.dart' as database_sort_test;
import 'database_view_test.dart' as database_view_test;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
database_filter_test.main();
database_sort_test.main();
database_view_test.main();
database_calendar_test.main();
database_media_test.main();
database_row_cover_test.main();
database_share_test.main();
// DON'T add more tests here.
}
@@ -0,0 +1,72 @@
import 'dart:ui';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../../shared/util.dart';
void main() {
final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('Editor AppLifeCycle tests', () {
testWidgets(
'Selection is added back after pausing AppFlowy',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
final selection = Selection.single(path: [4], startOffset: 0);
await tester.editor.updateSelection(selection);
binding.handleAppLifecycleStateChanged(AppLifecycleState.inactive);
expect(tester.editor.getCurrentEditorState().selection, null);
binding.handleAppLifecycleStateChanged(AppLifecycleState.resumed);
await tester.pumpAndSettle();
expect(tester.editor.getCurrentEditorState().selection, selection);
},
);
testWidgets(
'Null selection is retained after pausing AppFlowy',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
final selection = Selection.single(path: [4], startOffset: 0);
await tester.editor.updateSelection(selection);
await tester.editor.updateSelection(null);
binding.handleAppLifecycleStateChanged(AppLifecycleState.inactive);
expect(tester.editor.getCurrentEditorState().selection, null);
binding.handleAppLifecycleStateChanged(AppLifecycleState.resumed);
await tester.pumpAndSettle();
expect(tester.editor.getCurrentEditorState().selection, null);
},
);
testWidgets(
'Non-collapsed selection is retained after pausing AppFlowy',
(tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
final selection = Selection(
start: Position(path: [3]),
end: Position(path: [3], offset: 8),
);
await tester.editor.updateSelection(selection);
binding.handleAppLifecycleStateChanged(AppLifecycleState.inactive);
binding.handleAppLifecycleStateChanged(AppLifecycleState.resumed);
await tester.pumpAndSettle();
expect(tester.editor.getCurrentEditorState().selection, selection);
},
);
});
}
@@ -1,10 +1,10 @@
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_paste/clipboard_service.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -13,18 +13,21 @@ import '../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('paste in codeblock', () {
group('paste in codeblock:', () {
testWidgets('paste multiple lines in codeblock', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
// create a new document
await tester.createNewPageWithNameUnderParent();
await tester.createNewPageWithNameUnderParent(name: 'Test Document');
// focus on the editor
await tester.tapButton(find.byType(AppFlowyEditor));
// mock the clipboard
const lines = 3;
final text = List.generate(lines, (index) => 'line $index').join('\n');
AppFlowyClipboard.mockSetData(AppFlowyClipboardData(text: text));
ClipboardService.mockSetData(ClipboardServiceData(plainText: text));
await insertCodeBlockInDocument(tester);
@@ -51,7 +54,9 @@ Future<void> insertCodeBlockInDocument(WidgetTester tester) async {
// open the actions menu and insert the codeBlock
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName(
LocaleKeys.document_selectionMenu_codeBlock.tr(),
LocaleKeys.document_slashMenu_name_code.tr(),
offset: 150,
);
// wait for the codeBlock to be inserted
await tester.pumpAndSettle();
}
@@ -1,12 +1,19 @@
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/block_menu/block_menu_button.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_paste/clipboard_service.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/custom_image_block_component/custom_image_block_component.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/link_preview/custom_link_preview.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
import 'package:flutter/services.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:universal_platform/universal_platform.dart';
import '../../shared/util.dart';
@@ -116,13 +123,98 @@ void main() {
]);
});
});
testWidgets('paste bulleted list in numbered list', (tester) async {
const inAppJson =
'{"document":{"type":"page","children":[{"type":"bulleted_list","children":[{"type":"bulleted_list","data":{"delta":[{"insert":"World"}]}}],"data":{"delta":[{"insert":"Hello"}]}}]}}';
await tester.pasteContent(
inAppJson: inAppJson,
beforeTest: (editorState) async {
final transaction = editorState.transaction;
// Insert two numbered list nodes
// 1. Parent One
// 2.
transaction.insertNodes(
[0],
[
Node(
type: NumberedListBlockKeys.type,
attributes: {
'delta': [
{"insert": "One"},
],
},
),
Node(
type: NumberedListBlockKeys.type,
attributes: {'delta': []},
),
],
);
// Set the selection to the second numbered list node (which has empty delta)
transaction.afterSelection = Selection.collapsed(Position(path: [1]));
await editorState.apply(transaction);
await tester.pumpAndSettle();
},
(editorState) {
final secondNode = editorState.getNodeAtPath([1]);
expect(secondNode?.delta?.toPlainText(), 'Hello');
expect(secondNode?.children.length, 1);
final childNode = secondNode?.children.first;
expect(childNode?.delta?.toPlainText(), 'World');
expect(childNode?.type, BulletedListBlockKeys.type);
},
);
});
});
testWidgets('paste text on part of bullet list', (tester) async {
const plainText = 'test';
await tester.pasteContent(
plainText: plainText,
beforeTest: (editorState) async {
final transaction = editorState.transaction;
transaction.insertNodes(
[0],
[
Node(
type: BulletedListBlockKeys.type,
attributes: {
'delta': [
{"insert": "bullet list"},
],
},
),
],
);
// Set the selection to the second numbered list node (which has empty delta)
transaction.afterSelection = Selection(
start: Position(path: [0], offset: 7),
end: Position(path: [0], offset: 11),
);
await editorState.apply(transaction);
await tester.pumpAndSettle();
},
(editorState) {
final node = editorState.getNodeAtPath([0]);
expect(node?.delta?.toPlainText(), 'bullet test');
expect(node?.type, BulletedListBlockKeys.type);
},
);
});
testWidgets('paste image(png) from memory', (tester) async {
final image = await rootBundle.load('assets/test/images/sample.png');
final bytes = image.buffer.asUint8List();
await tester.pasteContent(image: ('png', bytes), (editorState) {
expect(editorState.document.root.children.length, 2);
expect(editorState.document.root.children.length, 1);
final node = editorState.getNodeAtPath([0])!;
expect(node.type, ImageBlockKeys.type);
expect(node.attributes[ImageBlockKeys.url], isNotNull);
@@ -133,7 +225,7 @@ void main() {
final image = await rootBundle.load('assets/test/images/sample.jpeg');
final bytes = image.buffer.asUint8List();
await tester.pasteContent(image: ('jpeg', bytes), (editorState) {
expect(editorState.document.root.children.length, 2);
expect(editorState.document.root.children.length, 1);
final node = editorState.getNodeAtPath([0])!;
expect(node.type, ImageBlockKeys.type);
expect(node.attributes[ImageBlockKeys.url], isNotNull);
@@ -141,15 +233,14 @@ void main() {
});
testWidgets('paste image(gif) from memory', (tester) async {
// It's not supported yet.
// final image = await rootBundle.load('assets/test/images/sample.gif');
// final bytes = image.buffer.asUint8List();
// await tester.pasteContent(image: ('gif', bytes), (editorState) {
// expect(editorState.document.root.children.length, 2);
// final node = editorState.getNodeAtPath([0])!;
// expect(node.type, ImageBlockKeys.type);
// expect(node.attributes[ImageBlockKeys.url], isNotNull);
// });
final image = await rootBundle.load('assets/test/images/sample.gif');
final bytes = image.buffer.asUint8List();
await tester.pasteContent(image: ('gif', bytes), (editorState) {
expect(editorState.document.root.children.length, 1);
final node = editorState.getNodeAtPath([0])!;
expect(node.type, ImageBlockKeys.type);
expect(node.attributes[ImageBlockKeys.url], isNotNull);
});
});
testWidgets(
@@ -195,13 +286,9 @@ void main() {
html: html,
image: ('png', bytes),
(editorState) {
expect(editorState.document.root.children.length, 2);
expect(editorState.document.root.children.length, 1);
final node = editorState.getNodeAtPath([0])!;
expect(node.type, ImageBlockKeys.type);
expect(
node.attributes[ImageBlockKeys.url],
'https://user-images.githubusercontent.com/9403740/262918875-603f4adb-58dd-49b5-8201-341d354935fd.png',
);
},
);
},
@@ -210,44 +297,176 @@ void main() {
testWidgets('paste the html content contains section', (tester) async {
const html =
'''<meta charset='utf-8'><section style="margin: 0px 8px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgba(255, 255, 255, 0.6); font-family: system-ui, -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(25, 25, 25); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><span style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgb(0, 160, 113);"><strong style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important;">AppFlowy</strong></span></section><section style="margin: 0px 8px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgba(255, 255, 255, 0.6); font-family: system-ui, -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(25, 25, 25); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><span style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgb(0, 160, 113);"><strong style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important;">Hello World</strong></span></section>''';
await tester.pasteContent(
html: html,
(editorState) {
expect(editorState.document.root.children.length, 2);
final node1 = editorState.getNodeAtPath([0])!;
final node2 = editorState.getNodeAtPath([1])!;
expect(node1.type, ParagraphBlockKeys.type);
expect(node2.type, ParagraphBlockKeys.type);
},
);
await tester.pasteContent(html: html, (editorState) {
expect(editorState.document.root.children.length, 2);
final node1 = editorState.getNodeAtPath([0])!;
final node2 = editorState.getNodeAtPath([1])!;
expect(node1.type, ParagraphBlockKeys.type);
expect(node2.type, ParagraphBlockKeys.type);
});
});
testWidgets('paste the html from google translation', (tester) async {
const html =
'''<meta charset='utf-8'><section style="margin: 0px 8px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgba(255, 255, 255, 0.6); font-family: system-ui, -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(25, 25, 25); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><span style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgb(0, 160, 113);"><strong style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important;"><font style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; vertical-align: inherit;"><font style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; vertical-align: inherit;">new force</font></font></strong></span></section><section style="margin: 0px 8px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgba(255, 255, 255, 0.6); font-family: system-ui, -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(25, 25, 25); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><span style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgb(0, 160, 113);"><strong style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important;"><font style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; vertical-align: inherit;"><font style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; vertical-align: inherit;">Assessment focus: potential motivations, empathy</font></font></strong></span></section><section style="margin: 0px 8px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgba(255, 255, 255, 0.6); font-family: system-ui, -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(25, 25, 25); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><br style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important;"></section><section style="margin: 0px 8px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; color: rgba(255, 255, 255, 0.6); font-family: system-ui, -apple-system, &quot;system-ui&quot;, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(25, 25, 25); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><font style="margin: 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-Line truncated
await tester.pasteContent(
html: html,
(editorState) {
expect(editorState.document.root.children.length, 8);
},
);
await tester.pasteContent(html: html, (editorState) {
expect(editorState.document.root.children.length, 8);
});
});
testWidgets(
'auto convert url to link preview block',
(widgetTester) async {
(tester) async {
const url = 'https://appflowy.io';
await widgetTester.pasteContent(
plainText: url,
(editorState) {
expect(editorState.document.root.children.length, 2);
final node = editorState.getNodeAtPath([0])!;
expect(node.type, LinkPreviewBlockKeys.type);
expect(node.attributes[LinkPreviewBlockKeys.url], url);
await tester.pasteContent(plainText: url, (editorState) async {
// the second one is the paragraph node
expect(editorState.document.root.children.length, 2);
final node = editorState.getNodeAtPath([0])!;
expect(node.type, LinkPreviewBlockKeys.type);
expect(node.attributes[LinkPreviewBlockKeys.url], url);
});
// hover on the link preview block
// click the more button
// and select convert to link
await tester.hoverOnWidget(
find.byType(CustomLinkPreviewWidget),
onHover: () async {
final convertToLinkButton = find.byWidgetPredicate((widget) {
return widget is MenuBlockButton &&
widget.tooltip ==
LocaleKeys.document_plugins_urlPreview_convertToLink.tr();
});
expect(convertToLinkButton, findsOneWidget);
await tester.tap(convertToLinkButton);
await tester.pumpAndSettle();
},
);
await tester.pumpAndSettle();
final editorState = tester.editor.getCurrentEditorState();
final textNode = editorState.getNodeAtPath([0])!;
expect(textNode.type, ParagraphBlockKeys.type);
expect(textNode.delta!.toJson(), [
{
'insert': url,
'attributes': {'href': url},
}
]);
},
);
testWidgets(
'ctrl/cmd+z to undo the auto convert url to link preview block',
(tester) async {
const url = 'https://appflowy.io';
await tester.pasteContent(plainText: url, (editorState) async {
// the second one is the paragraph node
expect(editorState.document.root.children.length, 2);
final node = editorState.getNodeAtPath([0])!;
expect(node.type, LinkPreviewBlockKeys.type);
expect(node.attributes[LinkPreviewBlockKeys.url], url);
});
await tester.editor.tapLineOfEditorAt(0);
await tester.simulateKeyEvent(
LogicalKeyboardKey.keyZ,
isControlPressed:
UniversalPlatform.isLinux || UniversalPlatform.isWindows,
isMetaPressed: UniversalPlatform.isMacOS,
);
await tester.pumpAndSettle();
final editorState = tester.editor.getCurrentEditorState();
final node = editorState.getNodeAtPath([0])!;
expect(node.type, ParagraphBlockKeys.type);
expect(node.delta!.toJson(), [
{
'insert': url,
'attributes': {'href': url},
}
]);
},
);
testWidgets(
'paste the nodes start with non-delta node',
(tester) async {
await tester.pasteContent((_) {});
const text = 'Hello World';
final editorState = tester.editor.getCurrentEditorState();
final transaction = editorState.transaction;
// [image_block]
// [paragraph_block]
transaction.insertNodes([
0,
], [
customImageNode(url: ''),
paragraphNode(text: text),
]);
await editorState.apply(transaction);
await tester.pumpAndSettle();
await tester.editor.tapLineOfEditorAt(0);
// select all and copy
await tester.simulateKeyEvent(
LogicalKeyboardKey.keyA,
isControlPressed:
UniversalPlatform.isLinux || UniversalPlatform.isWindows,
isMetaPressed: UniversalPlatform.isMacOS,
);
await tester.simulateKeyEvent(
LogicalKeyboardKey.keyC,
isControlPressed:
UniversalPlatform.isLinux || UniversalPlatform.isWindows,
isMetaPressed: UniversalPlatform.isMacOS,
);
// put the cursor to the end of the paragraph block
await tester.editor.tapLineOfEditorAt(0);
// paste the content
await tester.simulateKeyEvent(
LogicalKeyboardKey.keyV,
isControlPressed:
UniversalPlatform.isLinux || UniversalPlatform.isWindows,
isMetaPressed: UniversalPlatform.isMacOS,
);
await tester.pumpAndSettle();
// expect the image and the paragraph block are inserted below the cursor
expect(editorState.getNodeAtPath([0])!.type, CustomImageBlockKeys.type);
expect(editorState.getNodeAtPath([1])!.type, ParagraphBlockKeys.type);
expect(editorState.getNodeAtPath([2])!.type, CustomImageBlockKeys.type);
expect(editorState.getNodeAtPath([3])!.type, ParagraphBlockKeys.type);
},
);
testWidgets('paste the url without protocol', (tester) async {
// paste the image that from local file
const plainText = '1.jpg';
final image = await rootBundle.load('assets/test/images/sample.jpeg');
final bytes = image.buffer.asUint8List();
await tester.pasteContent(plainText: plainText, image: ('jpeg', bytes),
(editorState) {
final node = editorState.getNodeAtPath([0])!;
expect(node.type, ImageBlockKeys.type);
expect(node.attributes[ImageBlockKeys.url], isNotEmpty);
});
});
testWidgets('paste the image url', (tester) async {
const plainText = 'https://appflowy.io/1.jpg';
final image = await rootBundle.load('assets/test/images/sample.jpeg');
final bytes = image.buffer.asUint8List();
await tester.pasteContent(plainText: plainText, image: ('jpeg', bytes),
(editorState) {
final node = editorState.getNodeAtPath([0])!;
expect(node.type, ImageBlockKeys.type);
expect(node.attributes[ImageBlockKeys.url], isNotEmpty);
});
});
}
extension on WidgetTester {
@@ -256,13 +475,16 @@ extension on WidgetTester {
Future<void> Function(EditorState editorState)? beforeTest,
String? plainText,
String? html,
String? inAppJson,
(String, Uint8List?)? image,
}) async {
await initializeAppFlowy();
await tapAnonymousSignInButton();
// create a new document
await createNewPageWithNameUnderParent();
await createNewPageWithNameUnderParent(name: 'Test Document');
// tap the editor
await tapButton(find.byType(AppFlowyEditor));
await beforeTest?.call(editor.getCurrentEditorState());
@@ -271,6 +493,7 @@ extension on WidgetTester {
ClipboardServiceData(
plainText: plainText,
html: html,
inAppJson: inAppJson,
image: image,
),
);
@@ -1,6 +1,4 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
@@ -17,12 +15,11 @@ void main() {
await tester.tapAnonymousSignInButton();
// create a new document
await tester.createNewPageWithNameUnderParent();
const pageName = 'Test Document';
await tester.createNewPageWithNameUnderParent(name: pageName);
// expect to see a new document
tester.expectToSeePageName(
LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
);
tester.expectToSeePageName(pageName);
// and with one paragraph block
expect(find.byType(ParagraphBlockComponentWidget), findsOneWidget);
});
@@ -0,0 +1,61 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('customer:', () {
testWidgets('backtick issue - inline code', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
const pageName = 'backtick issue';
await tester.createNewPageWithNameUnderParent(name: pageName);
// focus on the editor
await tester.tap(find.byType(AppFlowyEditor));
// input backtick
const text = '`Hello` AppFlowy';
for (var i = 0; i < text.length; i++) {
await tester.ime.insertCharacter(text[i]);
}
final node = tester.editor.getNodeAtPath([0]);
expect(
node.delta?.toJson(),
equals([
{
"insert": "Hello",
"attributes": {"code": true},
},
{"insert": " AppFlowy"},
]),
);
});
testWidgets('backtick issue - inline code', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
const pageName = 'backtick issue';
await tester.createNewPageWithNameUnderParent(name: pageName);
// focus on the editor
await tester.tap(find.byType(AppFlowyEditor));
// input backtick
const text = '```';
for (var i = 0; i < text.length; i++) {
await tester.ime.insertCharacter(text[i]);
}
final node = tester.editor.getNodeAtPath([0]);
expect(node.type, equals(CodeBlockKeys.type));
});
});
}
Loaded 100 of 3753 files, more files were not shown because too many files have changed in this diff. Show more