mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-11-01 18:43:22 +00:00
feat: optimize the workspace menu loading speed (#6758)
* feat: optimize the workspace menu loading speed * chore: add workspace menu animation * feat: optimize workspace menu loading speed on mobile * test: workspace member count test * fix: rust ci
This commit is contained in:
parent
57933736ea
commit
cd3be696dc
5
.github/workflows/rust_ci.yaml
vendored
5
.github/workflows/rust_ci.yaml
vendored
@ -43,6 +43,7 @@ jobs:
|
||||
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|APPFLOWY_AI_OPENAI_API_KEY=.*|APPFLOWY_AI_OPENAI_API_KEY=${{ secrets.CI_OPENAI_API_KEY }}|' .env
|
||||
|
||||
- name: Ensure AppFlowy-Cloud is Running with Correct Version
|
||||
working-directory: AppFlowy-Cloud
|
||||
@ -137,7 +138,7 @@ jobs:
|
||||
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|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
|
||||
@ -160,7 +161,7 @@ jobs:
|
||||
else
|
||||
echo "No volumes to remove."
|
||||
fi
|
||||
|
||||
|
||||
docker compose pull
|
||||
docker compose up -d
|
||||
echo "Waiting for the container to be ready..."
|
||||
|
||||
@ -13,7 +13,7 @@ import '../../../shared/util.dart';
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
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 {
|
||||
@ -74,5 +74,32 @@ void main() {
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('check the member count immediately after creating a workspace',
|
||||
(tester) async {
|
||||
// only run the test when the feature flag is on
|
||||
if (!FeatureFlag.collaborativeWorkspace.isOn) {
|
||||
return;
|
||||
}
|
||||
|
||||
await tester.initializeAppFlowy(
|
||||
cloudType: AuthenticatorType.appflowyCloudSelfHost,
|
||||
);
|
||||
await tester.tapGoogleLoginInButton();
|
||||
await tester.expectToSeeHomePageWithGetStartedPage();
|
||||
|
||||
const name = 'AppFlowy.IO';
|
||||
// the workspace will be opened after created
|
||||
await tester.createCollaborativeWorkspace(name);
|
||||
|
||||
final loading = find.byType(Loading);
|
||||
await tester.pumpUntilNotFound(loading);
|
||||
|
||||
await tester.openCollaborativeWorkspaceMenu();
|
||||
|
||||
// expect to see the member count
|
||||
final memberCount = find.text('1 member');
|
||||
expect(memberCount, findsNWidgets(2));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -234,6 +234,7 @@ class _WorkspaceMenuItemContent extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final memberCount = workspace.memberCount.toInt();
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 12),
|
||||
child: Column(
|
||||
@ -247,10 +248,10 @@ class _WorkspaceMenuItemContent extends StatelessWidget {
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
FlowyText(
|
||||
context.read<WorkspaceMemberBloc>().state.isLoading
|
||||
memberCount == 0
|
||||
? ''
|
||||
: LocaleKeys.settings_appearance_members_membersCount.plural(
|
||||
context.read<WorkspaceMemberBloc>().state.members.length,
|
||||
memberCount,
|
||||
),
|
||||
fontSize: 10.0,
|
||||
color: Theme.of(context).hintColor,
|
||||
|
||||
@ -170,7 +170,7 @@ class _WorkspaceMoreActionWrapper extends CustomActionCell {
|
||||
switch (inner) {
|
||||
case WorkspaceMoreAction.delete:
|
||||
return FlowySvg(
|
||||
FlowySvgs.delete_s,
|
||||
FlowySvgs.trash_s,
|
||||
color: onHover ? Theme.of(context).colorScheme.error : null,
|
||||
);
|
||||
case WorkspaceMoreAction.rename:
|
||||
|
||||
@ -196,26 +196,23 @@ class _WorkspaceMenuItemState extends State<WorkspaceMenuItem> {
|
||||
}
|
||||
|
||||
Widget _buildRightIcon(BuildContext context, ValueNotifier<bool> isHovered) {
|
||||
// only the owner can update or delete workspace.
|
||||
if (context.read<WorkspaceMemberBloc>().state.isLoading) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
ValueListenableBuilder(
|
||||
valueListenable: isHovered,
|
||||
builder: (context, value, child) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 8.0),
|
||||
child: Opacity(
|
||||
opacity: value ? 1.0 : 0.0,
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: WorkspaceMoreActionList(workspace: widget.workspace),
|
||||
),
|
||||
// only the owner can update or delete workspace.
|
||||
if (!context.read<WorkspaceMemberBloc>().state.isLoading)
|
||||
ValueListenableBuilder(
|
||||
valueListenable: isHovered,
|
||||
builder: (context, value, child) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 8.0),
|
||||
child: Opacity(
|
||||
opacity: value ? 1.0 : 0.0,
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: WorkspaceMoreActionList(workspace: widget.workspace),
|
||||
),
|
||||
const HSpace(8.0),
|
||||
if (widget.isSelected) ...[
|
||||
const Padding(
|
||||
@ -244,43 +241,38 @@ class _WorkspaceInfo extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<WorkspaceMemberBloc, WorkspaceMemberState>(
|
||||
builder: (context, state) {
|
||||
final members = state.members;
|
||||
return FlowyButton(
|
||||
onTap: () => _openWorkspace(context),
|
||||
iconPadding: 10.0,
|
||||
leftIconSize: const Size.square(32),
|
||||
leftIcon: const SizedBox.square(dimension: 32),
|
||||
rightIcon: const HSpace(32.0),
|
||||
text: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// workspace name
|
||||
FlowyText.medium(
|
||||
workspace.name,
|
||||
fontSize: 14.0,
|
||||
figmaLineHeight: 17.0,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
withTooltip: true,
|
||||
),
|
||||
// workspace members count
|
||||
FlowyText.regular(
|
||||
state.isLoading
|
||||
? ''
|
||||
: LocaleKeys.settings_appearance_members_membersCount
|
||||
.plural(
|
||||
members.length,
|
||||
),
|
||||
fontSize: 10.0,
|
||||
figmaLineHeight: 12.0,
|
||||
color: Theme.of(context).hintColor,
|
||||
),
|
||||
],
|
||||
final memberCount = workspace.memberCount.toInt();
|
||||
return FlowyButton(
|
||||
onTap: () => _openWorkspace(context),
|
||||
iconPadding: 10.0,
|
||||
leftIconSize: const Size.square(32),
|
||||
leftIcon: const SizedBox.square(dimension: 32),
|
||||
rightIcon: const HSpace(32.0),
|
||||
text: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// workspace name
|
||||
FlowyText.medium(
|
||||
workspace.name,
|
||||
fontSize: 14.0,
|
||||
figmaLineHeight: 17.0,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
withTooltip: true,
|
||||
),
|
||||
);
|
||||
},
|
||||
// workspace members count
|
||||
FlowyText.regular(
|
||||
memberCount == 0
|
||||
? ''
|
||||
: LocaleKeys.settings_appearance_members_membersCount.plural(
|
||||
memberCount,
|
||||
),
|
||||
fontSize: 10.0,
|
||||
figmaLineHeight: 12.0,
|
||||
color: Theme.of(context).hintColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -204,9 +204,12 @@ class _SidebarSwitchWorkspaceButtonState
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppFlowyPopover(
|
||||
direction: PopoverDirection.bottomWithLeftAligned,
|
||||
direction: PopoverDirection.bottomWithCenterAligned,
|
||||
offset: const Offset(0, 5),
|
||||
constraints: const BoxConstraints(maxWidth: 300, maxHeight: 600),
|
||||
animationDuration: Durations.short3,
|
||||
beginScaleFactor: 1.0,
|
||||
beginOpacity: 0.8,
|
||||
controller: _popoverController,
|
||||
triggerActions: PopoverTriggerFlags.none,
|
||||
onOpen: () {
|
||||
|
||||
@ -679,6 +679,7 @@ pub fn save_user_workspace(
|
||||
user_workspace_table::created_at.eq(&user_workspace.created_at),
|
||||
user_workspace_table::database_storage_id.eq(&user_workspace.database_storage_id),
|
||||
user_workspace_table::icon.eq(&user_workspace.icon),
|
||||
user_workspace_table::member_count.eq(&user_workspace.member_count),
|
||||
))
|
||||
.execute(conn)?;
|
||||
|
||||
@ -729,6 +730,7 @@ pub fn save_all_user_workspaces(
|
||||
user_workspace_table::created_at.eq(&user_workspace.created_at),
|
||||
user_workspace_table::database_storage_id.eq(&user_workspace.database_storage_id),
|
||||
user_workspace_table::icon.eq(&user_workspace.icon),
|
||||
user_workspace_table::member_count.eq(&user_workspace.member_count),
|
||||
))
|
||||
.execute(conn)?;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user