mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: collab workspace issues (#4961)
This commit is contained in:
parent
99ee60a60d
commit
c0642d3ff3
@ -13,7 +13,7 @@ import 'base.dart';
|
||||
extension AppFlowyWorkspace on WidgetTester {
|
||||
/// Open workspace menu
|
||||
Future<void> openWorkspaceMenu() async {
|
||||
final workspaceWrapper = find.byType(SidebarWorkspaceWrapper);
|
||||
final workspaceWrapper = find.byType(SidebarSwitchWorkspaceButton);
|
||||
expect(workspaceWrapper, findsOneWidget);
|
||||
await tapButton(workspaceWrapper);
|
||||
final workspaceMenu = find.byType(WorkspacesMenu);
|
||||
|
@ -1,9 +1,9 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/application/mobile_router.dart';
|
||||
import 'package:appflowy/mobile/presentation/home/section_folder/mobile_home_section_folder.dart';
|
||||
import 'package:appflowy/shared/feature_flags.dart';
|
||||
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/menu/sidebar_sections_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
@ -53,8 +53,7 @@ class MobileFolders extends StatelessWidget {
|
||||
},
|
||||
builder: (context, state) {
|
||||
final isCollaborativeWorkspace =
|
||||
user.authenticator != AuthenticatorPB.Local &&
|
||||
FeatureFlag.collaborativeWorkspace.isOn;
|
||||
context.read<UserWorkspaceBloc>().state.isCollabWorkspaceOn;
|
||||
return SlidableAutoCloseBehavior(
|
||||
child: Column(
|
||||
children: [
|
||||
|
@ -3,7 +3,6 @@ import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/home/mobile_home_setting_page.dart';
|
||||
import 'package:appflowy/plugins/base/emoji/emoji_picker_screen.dart';
|
||||
import 'package:appflowy/plugins/base/icon/icon_picker.dart';
|
||||
import 'package:appflowy/shared/feature_flags.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/workspace/application/user/settings_user_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
|
||||
@ -32,8 +31,7 @@ class MobileHomePageHeader extends StatelessWidget {
|
||||
child: BlocBuilder<SettingsUserViewBloc, SettingsUserState>(
|
||||
builder: (context, state) {
|
||||
final isCollaborativeWorkspace =
|
||||
userProfile.authenticator != AuthenticatorPB.Local &&
|
||||
FeatureFlag.collaborativeWorkspace.isOn;
|
||||
context.read<UserWorkspaceBloc>().state.isCollabWorkspaceOn;
|
||||
return ConstrainedBox(
|
||||
constraints: const BoxConstraints(minHeight: 52),
|
||||
child: Row(
|
||||
|
@ -10,7 +10,7 @@ class DocumentService {
|
||||
required ViewPB view,
|
||||
}) async {
|
||||
final canOpen = await openDocument(viewId: view.id);
|
||||
if (canOpen.isSuccess()) {
|
||||
if (canOpen.isSuccess) {
|
||||
return FlowyResult.success(null);
|
||||
}
|
||||
final payload = CreateDocumentPayloadPB()..documentId = view.id;
|
||||
|
@ -83,9 +83,9 @@ enum FeatureFlag {
|
||||
|
||||
switch (this) {
|
||||
case FeatureFlag.collaborativeWorkspace:
|
||||
return false;
|
||||
return true;
|
||||
case FeatureFlag.membersSettings:
|
||||
return false;
|
||||
return true;
|
||||
case FeatureFlag.syncDocument:
|
||||
return false;
|
||||
case FeatureFlag.unknown:
|
||||
|
@ -105,7 +105,7 @@ class SplashScreen extends StatelessWidget {
|
||||
|
||||
Future<void> _registerIfNeeded() async {
|
||||
final result = await UserEventGetUserProfile().send();
|
||||
if (result.isFailure()) {
|
||||
if (result.isFailure) {
|
||||
await getIt<AuthService>().signUpAsGuest();
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,13 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/shared/feature_flags.dart';
|
||||
import 'package:appflowy/user/application/user_service.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/code.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
import 'package:appflowy_result/appflowy_result.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@ -20,141 +24,133 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
||||
(event, emit) async {
|
||||
await event.when(
|
||||
initial: () async {
|
||||
add(const FetchWorkspaces());
|
||||
final result = await _fetchWorkspaces();
|
||||
final isCollabWorkspaceOn =
|
||||
userProfile.authenticator != AuthenticatorPB.Local &&
|
||||
FeatureFlag.collaborativeWorkspace.isOn;
|
||||
emit(
|
||||
state.copyWith(
|
||||
currentWorkspace: result?.$1,
|
||||
workspaces: result?.$2 ?? [],
|
||||
isCollabWorkspaceOn: isCollabWorkspaceOn,
|
||||
actionResult: null,
|
||||
),
|
||||
);
|
||||
},
|
||||
workspacesReceived: (workspaceId) async {},
|
||||
fetchWorkspaces: () async {
|
||||
final result = await _fetchWorkspaces();
|
||||
if (result != null) {
|
||||
final members = await _userService
|
||||
.getWorkspaceMembers(
|
||||
result.$1.workspaceId,
|
||||
)
|
||||
.fold((s) => s.items.length, (f) => -1);
|
||||
emit(
|
||||
state.copyWith(
|
||||
isCollaborativeWorkspace: members > 1,
|
||||
currentWorkspace: result.$1,
|
||||
workspaces: result.$2,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
emit(
|
||||
state.copyWith(
|
||||
actionResult: UserWorkspaceActionResult(
|
||||
actionType: UserWorkspaceActionType.none,
|
||||
result: FlowyResult.failure(
|
||||
FlowyError(
|
||||
code: ErrorCode.Internal,
|
||||
msg: LocaleKeys.workspace_fetchWorkspacesFailed.tr(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
createWorkspace: (name, desc) async {
|
||||
createWorkspace: (name) async {
|
||||
final result = await _userService.createUserWorkspace(name);
|
||||
final (workspaces, createWorkspaceResult) = result.fold(
|
||||
(s) {
|
||||
final workspaces = [...state.workspaces, s];
|
||||
return (
|
||||
workspaces,
|
||||
FlowyResult<void, FlowyError>.success(null)
|
||||
);
|
||||
},
|
||||
(e) {
|
||||
Log.error(e);
|
||||
return (state.workspaces, FlowyResult.failure(e));
|
||||
},
|
||||
final workspaces = result.fold(
|
||||
(s) => [...state.workspaces, s],
|
||||
(e) => state.workspaces,
|
||||
);
|
||||
emit(
|
||||
state.copyWith(
|
||||
openWorkspaceResult: null,
|
||||
deleteWorkspaceResult: null,
|
||||
updateWorkspaceIconResult: null,
|
||||
createWorkspaceResult: createWorkspaceResult,
|
||||
workspaces: workspaces,
|
||||
actionResult: UserWorkspaceActionResult(
|
||||
actionType: UserWorkspaceActionType.create,
|
||||
result: result,
|
||||
),
|
||||
),
|
||||
);
|
||||
// open the created workspace by default
|
||||
result.onSuccess((s) {
|
||||
add(OpenWorkspace(s.workspaceId));
|
||||
});
|
||||
},
|
||||
deleteWorkspace: (workspaceId) async {
|
||||
if (state.workspaces.length <= 1) {
|
||||
// do not allow to delete the last workspace
|
||||
return emit(
|
||||
state.copyWith(
|
||||
openWorkspaceResult: null,
|
||||
createWorkspaceResult: null,
|
||||
updateWorkspaceIconResult: null,
|
||||
renameWorkspaceResult: null,
|
||||
deleteWorkspaceResult: FlowyResult.failure(
|
||||
// do not allow to delete the last workspace, otherwise the user
|
||||
// cannot do create workspace again
|
||||
final result = FlowyResult.failure(
|
||||
FlowyError(
|
||||
code: ErrorCode.Internal,
|
||||
msg: 'Cannot delete the last workspace',
|
||||
msg: LocaleKeys.workspace_cannotDeleteTheOnlyWorkspace.tr(),
|
||||
),
|
||||
);
|
||||
return emit(
|
||||
state.copyWith(
|
||||
actionResult: UserWorkspaceActionResult(
|
||||
actionType: UserWorkspaceActionType.delete,
|
||||
result: result,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final result = await _userService.deleteWorkspaceById(workspaceId);
|
||||
final (workspaces, deleteWorkspaceResult) = result.fold(
|
||||
(s) {
|
||||
// if the current workspace is deleted, open the first workspace
|
||||
if (state.currentWorkspace?.workspaceId == workspaceId) {
|
||||
add(OpenWorkspace(state.workspaces.first.workspaceId));
|
||||
}
|
||||
final workspaces = result.fold(
|
||||
// remove the deleted workspace from the list instead of fetching
|
||||
// the workspaces again
|
||||
final workspaces = [...state.workspaces]..removeWhere(
|
||||
(e) => e.workspaceId == workspaceId,
|
||||
(s) => state.workspaces
|
||||
.where((e) => e.workspaceId != workspaceId)
|
||||
.toList(),
|
||||
(e) => state.workspaces,
|
||||
);
|
||||
return (
|
||||
workspaces,
|
||||
FlowyResult<void, FlowyError>.success(null)
|
||||
);
|
||||
},
|
||||
(e) {
|
||||
Log.error(e);
|
||||
return (state.workspaces, FlowyResult.failure(e));
|
||||
},
|
||||
);
|
||||
|
||||
result.onSuccess((_) {
|
||||
// if the current workspace is deleted, open the first workspace
|
||||
if (state.currentWorkspace?.workspaceId == workspaceId) {
|
||||
add(OpenWorkspace(workspaces.first.workspaceId));
|
||||
}
|
||||
});
|
||||
emit(
|
||||
state.copyWith(
|
||||
openWorkspaceResult: null,
|
||||
createWorkspaceResult: null,
|
||||
updateWorkspaceIconResult: null,
|
||||
renameWorkspaceResult: null,
|
||||
deleteWorkspaceResult: deleteWorkspaceResult,
|
||||
workspaces: workspaces,
|
||||
actionResult: UserWorkspaceActionResult(
|
||||
actionType: UserWorkspaceActionType.delete,
|
||||
result: result,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
openWorkspace: (workspaceId) async {
|
||||
final (currentWorkspace, openWorkspaceResult) =
|
||||
await _userService.openWorkspace(workspaceId).fold(
|
||||
(s) {
|
||||
final openedWorkspace = state.workspaces.firstWhere(
|
||||
final result = await _userService.openWorkspace(workspaceId);
|
||||
final currentWorkspace = result.fold(
|
||||
(s) => state.workspaces.firstWhereOrNull(
|
||||
(e) => e.workspaceId == workspaceId,
|
||||
),
|
||||
(e) => state.currentWorkspace,
|
||||
);
|
||||
return (
|
||||
openedWorkspace,
|
||||
FlowyResult<void, FlowyError>.success(null)
|
||||
);
|
||||
},
|
||||
(f) {
|
||||
Log.error(f);
|
||||
return (state.currentWorkspace, FlowyResult.failure(f));
|
||||
},
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
createWorkspaceResult: null,
|
||||
deleteWorkspaceResult: null,
|
||||
updateWorkspaceIconResult: null,
|
||||
openWorkspaceResult: openWorkspaceResult,
|
||||
currentWorkspace: currentWorkspace,
|
||||
actionResult: UserWorkspaceActionResult(
|
||||
actionType: UserWorkspaceActionType.open,
|
||||
result: result,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
renameWorkspace: (workspaceId, name) async {
|
||||
final result = await _userService.renameWorkspace(
|
||||
workspaceId,
|
||||
name,
|
||||
);
|
||||
final (workspaces, currentWorkspace, renameWorkspaceResult) =
|
||||
result.fold(
|
||||
(s) {
|
||||
final workspaces = state.workspaces.map((e) {
|
||||
final result =
|
||||
await _userService.renameWorkspace(workspaceId, name);
|
||||
final workspaces = result.fold(
|
||||
(s) => state.workspaces.map(
|
||||
(e) {
|
||||
if (e.workspaceId == workspaceId) {
|
||||
e.freeze();
|
||||
return e.rebuild((p0) {
|
||||
@ -162,36 +158,21 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
||||
});
|
||||
}
|
||||
return e;
|
||||
}).toList();
|
||||
|
||||
},
|
||||
).toList(),
|
||||
(f) => state.workspaces,
|
||||
);
|
||||
final currentWorkspace = workspaces.firstWhere(
|
||||
(e) => e.workspaceId == state.currentWorkspace?.workspaceId,
|
||||
);
|
||||
|
||||
return (
|
||||
workspaces,
|
||||
currentWorkspace,
|
||||
FlowyResult<void, FlowyError>.success(null),
|
||||
);
|
||||
},
|
||||
(e) {
|
||||
Log.error(e);
|
||||
return (
|
||||
state.workspaces,
|
||||
state.currentWorkspace,
|
||||
FlowyResult.failure(e),
|
||||
);
|
||||
},
|
||||
);
|
||||
emit(
|
||||
state.copyWith(
|
||||
createWorkspaceResult: null,
|
||||
deleteWorkspaceResult: null,
|
||||
openWorkspaceResult: null,
|
||||
updateWorkspaceIconResult: null,
|
||||
workspaces: workspaces,
|
||||
currentWorkspace: currentWorkspace,
|
||||
renameWorkspaceResult: renameWorkspaceResult,
|
||||
actionResult: UserWorkspaceActionResult(
|
||||
actionType: UserWorkspaceActionType.rename,
|
||||
result: result,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
@ -200,11 +181,9 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
||||
workspaceId,
|
||||
icon,
|
||||
);
|
||||
|
||||
final (workspaces, currentWorkspace, updateWorkspaceIconResult) =
|
||||
result.fold(
|
||||
(s) {
|
||||
final workspaces = state.workspaces.map((e) {
|
||||
final workspaces = result.fold(
|
||||
(s) => state.workspaces.map(
|
||||
(e) {
|
||||
if (e.workspaceId == workspaceId) {
|
||||
e.freeze();
|
||||
return e.rebuild((p0) {
|
||||
@ -212,37 +191,21 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
||||
});
|
||||
}
|
||||
return e;
|
||||
}).toList();
|
||||
|
||||
},
|
||||
).toList(),
|
||||
(f) => state.workspaces,
|
||||
);
|
||||
final currentWorkspace = workspaces.firstWhere(
|
||||
(e) => e.workspaceId == state.currentWorkspace?.workspaceId,
|
||||
);
|
||||
|
||||
return (
|
||||
workspaces,
|
||||
currentWorkspace,
|
||||
FlowyResult<void, FlowyError>.success(null),
|
||||
);
|
||||
},
|
||||
(e) {
|
||||
Log.error(e);
|
||||
return (
|
||||
state.workspaces,
|
||||
state.currentWorkspace,
|
||||
FlowyResult.failure(e),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
createWorkspaceResult: null,
|
||||
deleteWorkspaceResult: null,
|
||||
openWorkspaceResult: null,
|
||||
renameWorkspaceResult: null,
|
||||
updateWorkspaceIconResult: updateWorkspaceIconResult,
|
||||
workspaces: workspaces,
|
||||
currentWorkspace: currentWorkspace,
|
||||
actionResult: UserWorkspaceActionResult(
|
||||
actionType: UserWorkspaceActionType.updateIcon,
|
||||
result: result,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
@ -273,9 +236,9 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
||||
@freezed
|
||||
class UserWorkspaceEvent with _$UserWorkspaceEvent {
|
||||
const factory UserWorkspaceEvent.initial() = Initial;
|
||||
const factory UserWorkspaceEvent.createWorkspace(String name, String desc) =
|
||||
CreateWorkspace;
|
||||
const factory UserWorkspaceEvent.fetchWorkspaces() = FetchWorkspaces;
|
||||
const factory UserWorkspaceEvent.createWorkspace(String name) =
|
||||
CreateWorkspace;
|
||||
const factory UserWorkspaceEvent.deleteWorkspace(String workspaceId) =
|
||||
DeleteWorkspace;
|
||||
const factory UserWorkspaceEvent.openWorkspace(String workspaceId) =
|
||||
@ -288,24 +251,51 @@ class UserWorkspaceEvent with _$UserWorkspaceEvent {
|
||||
String workspaceId,
|
||||
String icon,
|
||||
) = _UpdateWorkspaceIcon;
|
||||
const factory UserWorkspaceEvent.workspacesReceived(
|
||||
FlowyResult<List<UserWorkspacePB>, FlowyError> workspacesOrFail,
|
||||
) = WorkspacesReceived;
|
||||
}
|
||||
|
||||
enum UserWorkspaceActionType {
|
||||
none,
|
||||
create,
|
||||
delete,
|
||||
open,
|
||||
rename,
|
||||
updateIcon,
|
||||
fetchWorkspaces;
|
||||
}
|
||||
|
||||
class UserWorkspaceActionResult {
|
||||
const UserWorkspaceActionResult({
|
||||
required this.actionType,
|
||||
required this.result,
|
||||
});
|
||||
|
||||
final UserWorkspaceActionType actionType;
|
||||
final FlowyResult<void, FlowyError> result;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class UserWorkspaceState with _$UserWorkspaceState {
|
||||
const UserWorkspaceState._();
|
||||
|
||||
const factory UserWorkspaceState({
|
||||
required UserWorkspacePB? currentWorkspace,
|
||||
required List<UserWorkspacePB> workspaces,
|
||||
@Default(false) bool isCollaborativeWorkspace,
|
||||
@Default(null) FlowyResult<void, FlowyError>? createWorkspaceResult,
|
||||
@Default(null) FlowyResult<void, FlowyError>? deleteWorkspaceResult,
|
||||
@Default(null) FlowyResult<void, FlowyError>? openWorkspaceResult,
|
||||
@Default(null) FlowyResult<void, FlowyError>? renameWorkspaceResult,
|
||||
@Default(null) FlowyResult<void, FlowyError>? updateWorkspaceIconResult,
|
||||
@Default(null) UserWorkspacePB? currentWorkspace,
|
||||
@Default([]) List<UserWorkspacePB> workspaces,
|
||||
@Default(null) UserWorkspaceActionResult? actionResult,
|
||||
@Default(false) bool isCollabWorkspaceOn,
|
||||
}) = _UserWorkspaceState;
|
||||
|
||||
factory UserWorkspaceState.initial() =>
|
||||
const UserWorkspaceState(currentWorkspace: null, workspaces: []);
|
||||
factory UserWorkspaceState.initial() => const UserWorkspaceState();
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other is UserWorkspaceState &&
|
||||
other.currentWorkspace == currentWorkspace &&
|
||||
other.workspaces == workspaces &&
|
||||
identical(other.actionResult, actionResult);
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ extension ViewExtension on ViewPB {
|
||||
}
|
||||
FlowyResult<ViewPB, FlowyError> parent =
|
||||
await ViewBackendService.getView(parentViewId);
|
||||
while (parent.isSuccess()) {
|
||||
while (parent.isSuccess) {
|
||||
// parent is not null
|
||||
final view = parent.fold((s) => s, (e) => null);
|
||||
if (view == null || (!includeRoot && view.parentViewId.isEmpty)) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:appflowy/shared/feature_flags.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/workspace/application/menu/sidebar_sections_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/notifications/notification_action.dart';
|
||||
@ -15,7 +14,6 @@ import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_trash.
|
||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_user.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_workspace.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/workspace.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/auth.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'
|
||||
show UserProfilePB;
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
@ -207,8 +205,7 @@ class _SidebarState extends State<_Sidebar> {
|
||||
// user or workspace, setting
|
||||
Padding(
|
||||
padding: menuHorizontalInset,
|
||||
child: widget.userProfile.authenticator != AuthenticatorPB.Local &&
|
||||
FeatureFlag.collaborativeWorkspace.isOn
|
||||
child: context.read<UserWorkspaceBloc>().state.isCollabWorkspaceOn
|
||||
? SidebarWorkspace(
|
||||
userProfile: widget.userProfile,
|
||||
)
|
||||
|
@ -1,9 +1,9 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/shared/feature_flags.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/menu/sidebar_sections_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/folder/_favorite_folder.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/folder/_section_folder.dart';
|
||||
@ -50,8 +50,7 @@ class SidebarFolder extends StatelessWidget {
|
||||
builder: (context, state) {
|
||||
// only show public and private section if the workspace is collaborative and not local
|
||||
final isCollaborativeWorkspace =
|
||||
userProfile.authenticator != AuthenticatorPB.Local &&
|
||||
FeatureFlag.collaborativeWorkspace.isOn;
|
||||
context.read<UserWorkspaceBloc>().state.isCollabWorkspaceOn;
|
||||
|
||||
return Column(
|
||||
children:
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/workspace/application/menu/sidebar_sections_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/rename_view_dialog.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
@ -26,10 +27,15 @@ class SidebarNewPageButton extends StatelessWidget {
|
||||
LocaleKeys.newPageText.tr(),
|
||||
(viewName, _) {
|
||||
if (viewName.isNotEmpty) {
|
||||
// if the workspace is collaborative, create the view in the private section by default.
|
||||
final section =
|
||||
context.read<UserWorkspaceBloc>().state.isCollabWorkspaceOn
|
||||
? ViewSectionPB.Private
|
||||
: ViewSectionPB.Public;
|
||||
context.read<SidebarSectionsBloc>().add(
|
||||
SidebarSectionsEvent.createRootViewInSection(
|
||||
name: viewName,
|
||||
viewSection: ViewSectionPB.Public,
|
||||
viewSection: section,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -6,13 +6,14 @@ import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sid
|
||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_menu.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/toast.dart';
|
||||
import 'package:appflowy/workspace/presentation/notifications/widgets/notification_button.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/code.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class SidebarWorkspace extends StatelessWidget {
|
||||
@ -29,14 +30,13 @@ class SidebarWorkspace extends StatelessWidget {
|
||||
listener: _showResultDialog,
|
||||
builder: (context, state) {
|
||||
final currentWorkspace = state.currentWorkspace;
|
||||
// todo: show something if there is no workspace
|
||||
if (currentWorkspace == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SidebarWorkspaceWrapper(
|
||||
child: SidebarSwitchWorkspaceButton(
|
||||
userProfile: userProfile,
|
||||
currentWorkspace: currentWorkspace,
|
||||
),
|
||||
@ -51,60 +51,79 @@ class SidebarWorkspace extends StatelessWidget {
|
||||
}
|
||||
|
||||
void _showResultDialog(BuildContext context, UserWorkspaceState state) {
|
||||
var result = state.createWorkspaceResult;
|
||||
final actionResult = state.actionResult;
|
||||
if (actionResult == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (result != null) {
|
||||
final message = result.fold(
|
||||
final actionType = actionResult.actionType;
|
||||
final result = actionResult.result;
|
||||
|
||||
result.onFailure((f) {
|
||||
Log.error(
|
||||
'[Workspace] Failed to perform ${actionType.toString()} action: $f',
|
||||
);
|
||||
});
|
||||
|
||||
// show a confirmation dialog if the action is create and the result is LimitExceeded failure
|
||||
if (actionType == UserWorkspaceActionType.create &&
|
||||
result.isFailure &&
|
||||
result.getFailure().code == ErrorCode.WorkspaceLimitExceeded) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => NavigatorOkCancelDialog(
|
||||
message: LocaleKeys.workspace_createLimitExceeded.tr(),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final String? message;
|
||||
switch (actionType) {
|
||||
case UserWorkspaceActionType.create:
|
||||
message = result.fold(
|
||||
(s) => LocaleKeys.workspace_createSuccess.tr(),
|
||||
(e) => '${LocaleKeys.workspace_createFailed.tr()}: ${e.msg}',
|
||||
);
|
||||
return showSnackBarMessage(context, message);
|
||||
}
|
||||
|
||||
result = state.deleteWorkspaceResult;
|
||||
if (result != null) {
|
||||
final message = result.fold(
|
||||
break;
|
||||
case UserWorkspaceActionType.delete:
|
||||
message = result.fold(
|
||||
(s) => LocaleKeys.workspace_deleteSuccess.tr(),
|
||||
(e) => '${LocaleKeys.workspace_deleteFailed.tr()}: ${e.msg}',
|
||||
);
|
||||
showSnackBarMessage(context, message);
|
||||
return;
|
||||
}
|
||||
|
||||
result = state.openWorkspaceResult;
|
||||
if (result != null) {
|
||||
final message = result.fold(
|
||||
break;
|
||||
case UserWorkspaceActionType.open:
|
||||
message = result.fold(
|
||||
(s) => LocaleKeys.workspace_openSuccess.tr(),
|
||||
(e) => '${LocaleKeys.workspace_openFailed.tr()}: ${e.msg}',
|
||||
);
|
||||
showSnackBarMessage(context, message);
|
||||
return;
|
||||
}
|
||||
|
||||
result = state.updateWorkspaceIconResult;
|
||||
if (result != null) {
|
||||
final message = result.fold(
|
||||
break;
|
||||
case UserWorkspaceActionType.updateIcon:
|
||||
message = result.fold(
|
||||
(s) => LocaleKeys.workspace_updateIconSuccess.tr(),
|
||||
(e) => '${LocaleKeys.workspace_updateIconFailed.tr()}: ${e.msg}',
|
||||
);
|
||||
showSnackBarMessage(context, message);
|
||||
return;
|
||||
}
|
||||
|
||||
result = state.renameWorkspaceResult;
|
||||
if (result != null) {
|
||||
final message = result.fold(
|
||||
break;
|
||||
case UserWorkspaceActionType.rename:
|
||||
message = result.fold(
|
||||
(s) => LocaleKeys.workspace_renameSuccess.tr(),
|
||||
(e) => '${LocaleKeys.workspace_renameFailed.tr()}: ${e.msg}',
|
||||
);
|
||||
break;
|
||||
case UserWorkspaceActionType.none:
|
||||
case UserWorkspaceActionType.fetchWorkspaces:
|
||||
message = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (message != null) {
|
||||
showSnackBarMessage(context, message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SidebarWorkspaceWrapper extends StatefulWidget {
|
||||
const SidebarWorkspaceWrapper({
|
||||
class SidebarSwitchWorkspaceButton extends StatefulWidget {
|
||||
const SidebarSwitchWorkspaceButton({
|
||||
super.key,
|
||||
required this.userProfile,
|
||||
required this.currentWorkspace,
|
||||
@ -114,40 +133,12 @@ class SidebarWorkspaceWrapper extends StatefulWidget {
|
||||
final UserProfilePB userProfile;
|
||||
|
||||
@override
|
||||
State<SidebarWorkspaceWrapper> createState() =>
|
||||
_SidebarWorkspaceWrapperState();
|
||||
State<SidebarSwitchWorkspaceButton> createState() =>
|
||||
_SidebarSwitchWorkspaceButtonState();
|
||||
}
|
||||
|
||||
class _SidebarWorkspaceWrapperState extends State<SidebarWorkspaceWrapper> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (PlatformExtension.isDesktopOrWeb) {
|
||||
return _DesktopWorkspaceWrapper(
|
||||
userProfile: widget.userProfile,
|
||||
currentWorkspace: widget.currentWorkspace,
|
||||
);
|
||||
} else {
|
||||
// TODO(Lucas) mobile workspace menu
|
||||
return const Placeholder();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _DesktopWorkspaceWrapper extends StatefulWidget {
|
||||
const _DesktopWorkspaceWrapper({
|
||||
required this.userProfile,
|
||||
required this.currentWorkspace,
|
||||
});
|
||||
|
||||
final UserWorkspacePB currentWorkspace;
|
||||
final UserProfilePB userProfile;
|
||||
|
||||
@override
|
||||
State<_DesktopWorkspaceWrapper> createState() =>
|
||||
_DesktopWorkspaceWrapperState();
|
||||
}
|
||||
|
||||
class _DesktopWorkspaceWrapperState extends State<_DesktopWorkspaceWrapper> {
|
||||
class _SidebarSwitchWorkspaceButtonState
|
||||
extends State<SidebarSwitchWorkspaceButton> {
|
||||
final controller = PopoverController();
|
||||
|
||||
@override
|
||||
|
@ -89,7 +89,7 @@ class WorkspacesMenu extends StatelessWidget {
|
||||
final workspaceBloc = context.read<UserWorkspaceBloc>();
|
||||
await CreateWorkspaceDialog(
|
||||
onConfirm: (name) {
|
||||
workspaceBloc.add(UserWorkspaceEvent.createWorkspace(name, ''));
|
||||
workspaceBloc.add(UserWorkspaceEvent.createWorkspace(name));
|
||||
},
|
||||
).show(context);
|
||||
}
|
||||
@ -120,7 +120,9 @@ class WorkspaceMenuItem extends StatelessWidget {
|
||||
// settings right icon inside the flowy button will
|
||||
// cause the popover dismiss intermediately when click the right icon.
|
||||
// so using the stack to put the right icon on the flowy button.
|
||||
return Stack(
|
||||
return SizedBox(
|
||||
height: 52,
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
FlowyButton(
|
||||
@ -131,9 +133,11 @@ class WorkspaceMenuItem extends StatelessWidget {
|
||||
workspace.workspaceId,
|
||||
),
|
||||
);
|
||||
PopoverContainer.of(context).closeAll();
|
||||
}
|
||||
},
|
||||
margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
||||
margin:
|
||||
const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
||||
iconPadding: 10.0,
|
||||
leftIconSize: const Size.square(32),
|
||||
leftIcon: const SizedBox.square(
|
||||
@ -142,15 +146,21 @@ class WorkspaceMenuItem extends StatelessWidget {
|
||||
rightIcon: const HSpace(42.0),
|
||||
text: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
FlowyText.medium(
|
||||
workspace.name,
|
||||
fontSize: 14.0,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
if (members.length > 1)
|
||||
FlowyText(
|
||||
'${members.length} ${LocaleKeys.settings_appearance_members_members.tr()}',
|
||||
state.isLoading
|
||||
? ''
|
||||
: LocaleKeys
|
||||
.settings_appearance_members_membersCount
|
||||
.plural(
|
||||
members.length,
|
||||
),
|
||||
fontSize: 10.0,
|
||||
color: Theme.of(context).hintColor,
|
||||
),
|
||||
@ -170,9 +180,12 @@ class WorkspaceMenuItem extends StatelessWidget {
|
||||
),
|
||||
Positioned(
|
||||
right: 12.0,
|
||||
child: Align(child: _buildRightIcon(context)),
|
||||
child: Align(
|
||||
child: _buildRightIcon(context),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
@ -182,7 +195,7 @@ class WorkspaceMenuItem extends StatelessWidget {
|
||||
Widget _buildRightIcon(BuildContext context) {
|
||||
// only the owner can update or delete workspace.
|
||||
// only show the more action button when the workspace is selected.
|
||||
if (!isSelected) {
|
||||
if (!isSelected || context.read<WorkspaceMemberBloc>().state.isLoading) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/size.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
|
||||
class FlowyMessageToast extends StatelessWidget {
|
||||
@ -70,6 +69,7 @@ void showSnackBarMessage(
|
||||
content: FlowyText(
|
||||
message,
|
||||
color: Colors.white,
|
||||
maxLines: 2,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -50,6 +50,7 @@ class SettingsDialog extends StatelessWidget {
|
||||
color: Theme.of(context).colorScheme.tertiary,
|
||||
),
|
||||
),
|
||||
width: MediaQuery.of(context).size.width * 0.7,
|
||||
child: ScaffoldMessenger(
|
||||
child: Scaffold(
|
||||
backgroundColor: Colors.transparent,
|
||||
|
@ -1,11 +1,13 @@
|
||||
import 'package:appflowy/user/application/user_service.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
import 'package:appflowy_result/appflowy_result.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:protobuf/protobuf.dart';
|
||||
|
||||
part 'workspace_member_bloc.freezed.dart';
|
||||
|
||||
@ -28,43 +30,113 @@ class WorkspaceMemberBloc
|
||||
on<WorkspaceMemberEvent>((event, emit) async {
|
||||
await event.when(
|
||||
initial: () async {
|
||||
if (workspace != null) {
|
||||
workspaceId = workspace!.workspaceId;
|
||||
} else {
|
||||
final currentWorkspace =
|
||||
await FolderEventReadCurrentWorkspace().send();
|
||||
currentWorkspace.fold((s) {
|
||||
workspaceId = s.id;
|
||||
}, (e) {
|
||||
assert(false, 'Failed to read current workspace: $e');
|
||||
Log.error('Failed to read current workspace: $e');
|
||||
workspaceId = '';
|
||||
});
|
||||
}
|
||||
await _setCurrentWorkspaceId();
|
||||
|
||||
add(const WorkspaceMemberEvent.getWorkspaceMembers());
|
||||
},
|
||||
getWorkspaceMembers: () async {
|
||||
final members = await _getWorkspaceMembers();
|
||||
final result = await _userBackendService.getWorkspaceMembers(
|
||||
_workspaceId,
|
||||
);
|
||||
final members = result.fold<List<WorkspaceMemberPB>>(
|
||||
(s) => s.items,
|
||||
(e) => [],
|
||||
);
|
||||
final myRole = _getMyRole(members);
|
||||
emit(
|
||||
state.copyWith(
|
||||
members: members,
|
||||
myRole: myRole,
|
||||
isLoading: false,
|
||||
actionResult: WorkspaceMemberActionResult(
|
||||
actionType: WorkspaceMemberActionType.get,
|
||||
result: result,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
getWorkspaceMembers: () async {
|
||||
final result = await _userBackendService.getWorkspaceMembers(
|
||||
_workspaceId,
|
||||
);
|
||||
final members = result.fold<List<WorkspaceMemberPB>>(
|
||||
(s) => s.items,
|
||||
(e) => [],
|
||||
);
|
||||
final myRole = _getMyRole(members);
|
||||
emit(
|
||||
state.copyWith(
|
||||
members: members,
|
||||
myRole: myRole,
|
||||
actionResult: WorkspaceMemberActionResult(
|
||||
actionType: WorkspaceMemberActionType.get,
|
||||
result: result,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
addWorkspaceMember: (email) async {
|
||||
await _addWorkspaceMember(email);
|
||||
final result = await _userBackendService.addWorkspaceMember(
|
||||
_workspaceId,
|
||||
email,
|
||||
);
|
||||
emit(
|
||||
state.copyWith(
|
||||
actionResult: WorkspaceMemberActionResult(
|
||||
actionType: WorkspaceMemberActionType.add,
|
||||
result: result,
|
||||
),
|
||||
),
|
||||
);
|
||||
// the addWorkspaceMember doesn't return the updated members,
|
||||
// so we need to get the members again
|
||||
result.onSuccess((s) {
|
||||
add(const WorkspaceMemberEvent.getWorkspaceMembers());
|
||||
});
|
||||
},
|
||||
removeWorkspaceMember: (email) async {
|
||||
await _removeWorkspaceMember(email);
|
||||
add(const WorkspaceMemberEvent.getWorkspaceMembers());
|
||||
final result = await _userBackendService.removeWorkspaceMember(
|
||||
_workspaceId,
|
||||
email,
|
||||
);
|
||||
final members = result.fold(
|
||||
(s) => state.members.where((e) => e.email != email).toList(),
|
||||
(e) => state.members,
|
||||
);
|
||||
emit(
|
||||
state.copyWith(
|
||||
members: members,
|
||||
actionResult: WorkspaceMemberActionResult(
|
||||
actionType: WorkspaceMemberActionType.remove,
|
||||
result: result,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
updateWorkspaceMember: (email, role) async {
|
||||
await _updateWorkspaceMember(email, role);
|
||||
add(const WorkspaceMemberEvent.getWorkspaceMembers());
|
||||
final result = await _userBackendService.updateWorkspaceMember(
|
||||
_workspaceId,
|
||||
email,
|
||||
role,
|
||||
);
|
||||
final members = result.fold(
|
||||
(s) => state.members.map((e) {
|
||||
if (e.email == email) {
|
||||
e.freeze();
|
||||
return e.rebuild((p0) {
|
||||
p0.role = role;
|
||||
});
|
||||
}
|
||||
return e;
|
||||
}).toList(),
|
||||
(e) => state.members,
|
||||
);
|
||||
emit(
|
||||
state.copyWith(
|
||||
members: members,
|
||||
actionResult: WorkspaceMemberActionResult(
|
||||
actionType: WorkspaceMemberActionType.updateRole,
|
||||
result: result,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
@ -75,18 +147,8 @@ class WorkspaceMemberBloc
|
||||
// if the workspace is null, use the current workspace
|
||||
final UserWorkspacePB? workspace;
|
||||
|
||||
late final String workspaceId;
|
||||
late final UserBackendService _userBackendService;
|
||||
|
||||
Future<List<WorkspaceMemberPB>> _getWorkspaceMembers() async {
|
||||
return _userBackendService.getWorkspaceMembers(workspaceId).fold(
|
||||
(s) => s.items,
|
||||
(e) {
|
||||
Log.error('Failed to read workspace members: $e');
|
||||
return [];
|
||||
},
|
||||
);
|
||||
}
|
||||
late final String _workspaceId;
|
||||
final UserBackendService _userBackendService;
|
||||
|
||||
AFRolePB _getMyRole(List<WorkspaceMemberPB> members) {
|
||||
final role = members
|
||||
@ -101,27 +163,19 @@ class WorkspaceMemberBloc
|
||||
return role;
|
||||
}
|
||||
|
||||
Future<void> _addWorkspaceMember(String email) async {
|
||||
return _userBackendService.addWorkspaceMember(workspaceId, email).fold(
|
||||
(s) => Log.debug('Added workspace member: $email'),
|
||||
(e) => Log.error('Failed to add workspace member: $e'),
|
||||
);
|
||||
Future<void> _setCurrentWorkspaceId() async {
|
||||
if (workspace != null) {
|
||||
_workspaceId = workspace!.workspaceId;
|
||||
} else {
|
||||
final currentWorkspace = await FolderEventReadCurrentWorkspace().send();
|
||||
currentWorkspace.fold((s) {
|
||||
_workspaceId = s.id;
|
||||
}, (e) {
|
||||
assert(false, 'Failed to read current workspace: $e');
|
||||
Log.error('Failed to read current workspace: $e');
|
||||
_workspaceId = '';
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _removeWorkspaceMember(String email) async {
|
||||
return _userBackendService.removeWorkspaceMember(workspaceId, email).fold(
|
||||
(s) => Log.debug('Removed workspace member: $email'),
|
||||
(e) => Log.error('Failed to remove workspace member: $e'),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _updateWorkspaceMember(String email, AFRolePB role) async {
|
||||
return _userBackendService
|
||||
.updateWorkspaceMember(workspaceId, email, role)
|
||||
.fold(
|
||||
(s) => Log.debug('Updated workspace member: $email'),
|
||||
(e) => Log.error('Failed to update workspace member: $e'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,12 +194,47 @@ class WorkspaceMemberEvent with _$WorkspaceMemberEvent {
|
||||
) = UpdateWorkspaceMember;
|
||||
}
|
||||
|
||||
enum WorkspaceMemberActionType {
|
||||
none,
|
||||
get,
|
||||
add,
|
||||
remove,
|
||||
updateRole,
|
||||
}
|
||||
|
||||
class WorkspaceMemberActionResult {
|
||||
const WorkspaceMemberActionResult({
|
||||
required this.actionType,
|
||||
required this.result,
|
||||
});
|
||||
|
||||
final WorkspaceMemberActionType actionType;
|
||||
final FlowyResult<void, FlowyError> result;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class WorkspaceMemberState with _$WorkspaceMemberState {
|
||||
const WorkspaceMemberState._();
|
||||
|
||||
const factory WorkspaceMemberState({
|
||||
@Default([]) List<WorkspaceMemberPB> members,
|
||||
@Default(AFRolePB.Guest) AFRolePB myRole,
|
||||
@Default(null) WorkspaceMemberActionResult? actionResult,
|
||||
@Default(true) bool isLoading,
|
||||
}) = _WorkspaceMemberState;
|
||||
|
||||
factory WorkspaceMemberState.initial() => const WorkspaceMemberState();
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other is WorkspaceMemberState &&
|
||||
other.members == members &&
|
||||
other.myRole == myRole &&
|
||||
identical(other.actionResult, actionResult);
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,14 @@ import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/shared/af_role_pb_extension.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/toast.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/members/workspace_member_bloc.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/code.pbenum.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/widget/buttons/primary_button.dart';
|
||||
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
||||
import 'package:flowy_infra_ui/widget/rounded_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -28,7 +30,8 @@ class WorkspaceMembersPage extends StatelessWidget {
|
||||
return BlocProvider<WorkspaceMemberBloc>(
|
||||
create: (context) => WorkspaceMemberBloc(userProfile: userProfile)
|
||||
..add(const WorkspaceMemberEvent.initial()),
|
||||
child: BlocBuilder<WorkspaceMemberBloc, WorkspaceMemberState>(
|
||||
child: BlocConsumer<WorkspaceMemberBloc, WorkspaceMemberState>(
|
||||
listener: _showResultDialog,
|
||||
builder: (context, state) {
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
@ -46,6 +49,7 @@ class WorkspaceMembersPage extends StatelessWidget {
|
||||
userProfile: userProfile,
|
||||
myRole: state.myRole,
|
||||
),
|
||||
const VSpace(48.0),
|
||||
],
|
||||
),
|
||||
);
|
||||
@ -53,6 +57,43 @@ class WorkspaceMembersPage extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showResultDialog(BuildContext context, WorkspaceMemberState state) {
|
||||
final actionResult = state.actionResult;
|
||||
if (actionResult == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final actionType = actionResult.actionType;
|
||||
final result = actionResult.result;
|
||||
|
||||
// only show the result dialog when the action is WorkspaceMemberActionType.add
|
||||
if (actionType == WorkspaceMemberActionType.add) {
|
||||
result.fold(
|
||||
(s) {
|
||||
showSnackBarMessage(
|
||||
context,
|
||||
LocaleKeys.settings_appearance_members_addMemberSuccess.tr(),
|
||||
);
|
||||
},
|
||||
(f) {
|
||||
final message = f.code == ErrorCode.WorkspaceMemberLimitExceeded
|
||||
? LocaleKeys.settings_appearance_members_memberLimitExceeded.tr()
|
||||
: LocaleKeys.settings_appearance_members_failedToAddMember.tr();
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => NavigatorOkCancelDialog(message: message),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
result.onFailure((f) {
|
||||
Log.error(
|
||||
'[Member] Failed to perform ${actionType.toString()} action: $f',
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class _InviteMember extends StatefulWidget {
|
||||
@ -111,6 +152,7 @@ class _InviteMemberState extends State<_InviteMember> {
|
||||
],
|
||||
),
|
||||
const VSpace(16.0),
|
||||
/* Enable this when the feature is ready
|
||||
PrimaryButton(
|
||||
backgroundColor: const Color(0xFFE0E0E0),
|
||||
child: Padding(
|
||||
@ -140,6 +182,7 @@ class _InviteMemberState extends State<_InviteMember> {
|
||||
},
|
||||
),
|
||||
const VSpace(16.0),
|
||||
*/
|
||||
const Divider(
|
||||
height: 1.0,
|
||||
thickness: 1.0,
|
||||
@ -160,10 +203,6 @@ class _InviteMemberState extends State<_InviteMember> {
|
||||
context
|
||||
.read<WorkspaceMemberBloc>()
|
||||
.add(WorkspaceMemberEvent.addWorkspaceMember(email));
|
||||
showSnackBarMessage(
|
||||
context,
|
||||
LocaleKeys.settings_appearance_members_emailSent.tr(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -310,13 +349,23 @@ class _MemberMoreActionList extends StatelessWidget {
|
||||
},
|
||||
);
|
||||
},
|
||||
onSelected: (action, controller) async {
|
||||
onSelected: (action, controller) {
|
||||
switch (action.inner) {
|
||||
case _MemberMoreAction.delete:
|
||||
context.read<WorkspaceMemberBloc>().add(
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (_) => NavigatorOkCancelDialog(
|
||||
title: LocaleKeys.settings_appearance_members_removeMember.tr(),
|
||||
message: LocaleKeys
|
||||
.settings_appearance_members_areYouSureToRemoveMember
|
||||
.tr(),
|
||||
onOkPressed: () => context.read<WorkspaceMemberBloc>().add(
|
||||
WorkspaceMemberEvent.removeWorkspaceMember(
|
||||
action.member.email,
|
||||
),
|
||||
),
|
||||
okTitle: LocaleKeys.button_yes.tr(),
|
||||
),
|
||||
);
|
||||
break;
|
||||
}
|
||||
@ -353,7 +402,7 @@ class _MemberRoleActionList extends StatelessWidget {
|
||||
return PopoverActionList<_MemberRoleActionWrapper>(
|
||||
asBarrier: true,
|
||||
direction: PopoverDirection.bottomWithLeftAligned,
|
||||
actions: [AFRolePB.Member, AFRolePB.Guest]
|
||||
actions: [AFRolePB.Member]
|
||||
.map((e) => _MemberRoleActionWrapper(e, member))
|
||||
.toList(),
|
||||
offset: const Offset(0, 10),
|
||||
|
@ -186,7 +186,7 @@ class NavigatorOkCancelDialog extends StatelessWidget {
|
||||
this.okTitle,
|
||||
this.cancelTitle,
|
||||
this.title,
|
||||
required this.message,
|
||||
this.message,
|
||||
this.maxWidth,
|
||||
});
|
||||
|
||||
@ -195,13 +195,14 @@ class NavigatorOkCancelDialog extends StatelessWidget {
|
||||
final String? okTitle;
|
||||
final String? cancelTitle;
|
||||
final String? title;
|
||||
final String message;
|
||||
final String? message;
|
||||
final double? maxWidth;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return StyledDialog(
|
||||
maxWidth: maxWidth ?? 500,
|
||||
padding: EdgeInsets.symmetric(horizontal: Insets.xl, vertical: Insets.l),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
@ -209,6 +210,7 @@ class NavigatorOkCancelDialog extends StatelessWidget {
|
||||
FlowyText.medium(
|
||||
title!.toUpperCase(),
|
||||
fontSize: FontSizes.s16,
|
||||
maxLines: 3,
|
||||
),
|
||||
VSpace(Insets.sm * 1.5),
|
||||
Container(
|
||||
@ -217,7 +219,11 @@ class NavigatorOkCancelDialog extends StatelessWidget {
|
||||
),
|
||||
VSpace(Insets.m * 1.5),
|
||||
],
|
||||
FlowyText.medium(message),
|
||||
if (message != null)
|
||||
FlowyText.medium(
|
||||
message!,
|
||||
maxLines: 3,
|
||||
),
|
||||
SizedBox(height: Insets.l),
|
||||
OkCancelButton(
|
||||
onOkPressed: () {
|
||||
|
@ -24,11 +24,11 @@ extension FlowyAsyncResultExtension<S, F extends Object>
|
||||
}
|
||||
|
||||
Future<bool> isError() {
|
||||
return then((result) => result.isFailure());
|
||||
return then((result) => result.isFailure);
|
||||
}
|
||||
|
||||
Future<bool> isSuccess() {
|
||||
return then((result) => result.isSuccess());
|
||||
return then((result) => result.isSuccess);
|
||||
}
|
||||
|
||||
FlowyAsyncResult<S, F> onFailure(void Function(F failure) onFailure) {
|
||||
|
@ -10,8 +10,8 @@ abstract class FlowyResult<S, F extends Object> {
|
||||
FlowyResult<T, F> map<T>(T Function(S success) fn);
|
||||
FlowyResult<S, T> mapError<T extends Object>(T Function(F failure) fn);
|
||||
|
||||
bool isSuccess();
|
||||
bool isFailure();
|
||||
bool get isSuccess;
|
||||
bool get isFailure;
|
||||
|
||||
S? toNullable();
|
||||
|
||||
@ -20,6 +20,8 @@ abstract class FlowyResult<S, F extends Object> {
|
||||
|
||||
S getOrElse(S Function(F failure) onFailure);
|
||||
S getOrThrow();
|
||||
|
||||
F getFailure();
|
||||
}
|
||||
|
||||
class FlowySuccess<S, F extends Object> implements FlowyResult<S, F> {
|
||||
@ -57,14 +59,10 @@ class FlowySuccess<S, F extends Object> implements FlowyResult<S, F> {
|
||||
}
|
||||
|
||||
@override
|
||||
bool isSuccess() {
|
||||
return true;
|
||||
}
|
||||
bool get isSuccess => true;
|
||||
|
||||
@override
|
||||
bool isFailure() {
|
||||
return false;
|
||||
}
|
||||
bool get isFailure => false;
|
||||
|
||||
@override
|
||||
S? toNullable() {
|
||||
@ -88,6 +86,11 @@ class FlowySuccess<S, F extends Object> implements FlowyResult<S, F> {
|
||||
S getOrThrow() {
|
||||
return _value;
|
||||
}
|
||||
|
||||
@override
|
||||
F getFailure() {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
class FlowyFailure<S, F extends Object> implements FlowyResult<S, F> {
|
||||
@ -125,14 +128,10 @@ class FlowyFailure<S, F extends Object> implements FlowyResult<S, F> {
|
||||
}
|
||||
|
||||
@override
|
||||
bool isSuccess() {
|
||||
return false;
|
||||
}
|
||||
bool get isSuccess => false;
|
||||
|
||||
@override
|
||||
bool isFailure() {
|
||||
return true;
|
||||
}
|
||||
bool get isFailure => true;
|
||||
|
||||
@override
|
||||
S? toNullable() {
|
||||
@ -156,4 +155,9 @@ class FlowyFailure<S, F extends Object> implements FlowyResult<S, F> {
|
||||
S getOrThrow() {
|
||||
throw _value;
|
||||
}
|
||||
|
||||
@override
|
||||
F getFailure() {
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
const _overlayContainerPadding = EdgeInsets.symmetric(vertical: 12);
|
||||
const overlayContainerMaxWidth = 760.0;
|
||||
const overlayContainerMinWidth = 320.0;
|
||||
@ -14,6 +15,7 @@ class FlowyDialog extends StatelessWidget {
|
||||
this.constraints,
|
||||
this.padding = _overlayContainerPadding,
|
||||
this.backgroundColor,
|
||||
this.width,
|
||||
});
|
||||
|
||||
final Widget? title;
|
||||
@ -22,11 +24,12 @@ class FlowyDialog extends StatelessWidget {
|
||||
final BoxConstraints? constraints;
|
||||
final EdgeInsets padding;
|
||||
final Color? backgroundColor;
|
||||
final double? width;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final windowSize = MediaQuery.of(context).size;
|
||||
final size = windowSize * 0.7;
|
||||
final size = windowSize * 0.6;
|
||||
return SimpleDialog(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
backgroundColor: backgroundColor ?? Theme.of(context).cardColor,
|
||||
@ -38,8 +41,11 @@ class FlowyDialog extends StatelessWidget {
|
||||
type: MaterialType.transparency,
|
||||
child: Container(
|
||||
height: size.height,
|
||||
width: max(min(size.width, overlayContainerMaxWidth),
|
||||
overlayContainerMinWidth),
|
||||
width: width ??
|
||||
max(
|
||||
min(size.width, overlayContainerMaxWidth),
|
||||
overlayContainerMinWidth,
|
||||
),
|
||||
constraints: constraints,
|
||||
child: child,
|
||||
),
|
||||
|
14
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
14
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -838,7 +838,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4b25d7d021a11c51583e6a404c139f49ee6a3bf9#4b25d7d021a11c51583e6a404c139f49ee6a3bf9"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=25c4be5#25c4be5d60fa67f0d2de7f69cc8292a4506e07de"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -862,7 +862,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4b25d7d021a11c51583e6a404c139f49ee6a3bf9#4b25d7d021a11c51583e6a404c139f49ee6a3bf9"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=25c4be5#25c4be5d60fa67f0d2de7f69cc8292a4506e07de"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -892,7 +892,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4b25d7d021a11c51583e6a404c139f49ee6a3bf9#4b25d7d021a11c51583e6a404c139f49ee6a3bf9"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=25c4be5#25c4be5d60fa67f0d2de7f69cc8292a4506e07de"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -911,7 +911,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4b25d7d021a11c51583e6a404c139f49ee6a3bf9#4b25d7d021a11c51583e6a404c139f49ee6a3bf9"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=25c4be5#25c4be5d60fa67f0d2de7f69cc8292a4506e07de"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -926,7 +926,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4b25d7d021a11c51583e6a404c139f49ee6a3bf9#4b25d7d021a11c51583e6a404c139f49ee6a3bf9"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=25c4be5#25c4be5d60fa67f0d2de7f69cc8292a4506e07de"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -963,7 +963,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4b25d7d021a11c51583e6a404c139f49ee6a3bf9#4b25d7d021a11c51583e6a404c139f49ee6a3bf9"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=25c4be5#25c4be5d60fa67f0d2de7f69cc8292a4506e07de"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@ -1002,7 +1002,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4b25d7d021a11c51583e6a404c139f49ee6a3bf9#4b25d7d021a11c51583e6a404c139f49ee6a3bf9"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=25c4be5#25c4be5d60fa67f0d2de7f69cc8292a4506e07de"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
|
@ -96,10 +96,10 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ab9
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
|
@ -65,10 +65,10 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ab9
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
|
@ -68,6 +68,7 @@
|
||||
"deleteWorkspaceHintText": "Are you sure you want to delete the workspace? This action cannot be undone.",
|
||||
"createSuccess": "Workspace created successfully",
|
||||
"createFailed": "Failed to create workspace",
|
||||
"createLimitExceeded": "You've reached the maximum workspace limit allowed for your account. If you need additional workspaces to continue your work, please request on Github",
|
||||
"deleteSuccess": "Workspace deleted successfully",
|
||||
"deleteFailed": "Failed to delete workspace",
|
||||
"openSuccess": "Open workspace successfully",
|
||||
@ -75,7 +76,9 @@
|
||||
"renameSuccess": "Workspace renamed successfully",
|
||||
"renameFailed": "Failed to rename workspace",
|
||||
"updateIconSuccess": "Updated workspace icon successfully",
|
||||
"updateIconFailed": "Updated workspace icon failed"
|
||||
"updateIconFailed": "Updated workspace icon failed",
|
||||
"cannotDeleteTheOnlyWorkspace": "Cannot delete the only workspace",
|
||||
"fetchWorkspacesFailed": "Failed to fetch workspaces"
|
||||
},
|
||||
"shareAction": {
|
||||
"buttonText": "Share",
|
||||
@ -436,7 +439,17 @@
|
||||
"guestHintText": "A Guest can read, react, comment, and can edit certain pages with permission.",
|
||||
"emailInvalidError": "Invalid email, please check and try again",
|
||||
"emailSent": "Email sent, please check the inbox",
|
||||
"members": "members"
|
||||
"members": "members",
|
||||
"membersCount": {
|
||||
"zero": "{} members",
|
||||
"one": "{} member",
|
||||
"other": "{} members"
|
||||
},
|
||||
"memberLimitExceeded": "You've reached the maximum member limit allowed for your account. If you want to add more additional members to continue your work, please request on Github",
|
||||
"failedToAddMember": "Failed to add member",
|
||||
"addMemberSuccess": "Member added successfully",
|
||||
"removeMember": "Remove Member",
|
||||
"areYouSureToRemoveMember": "Are you sure you want to remove this member?"
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
@ -1420,7 +1433,7 @@
|
||||
},
|
||||
"syncState": {
|
||||
"syncing": "Syncing",
|
||||
"synced": "Everything is up to date",
|
||||
"synced": "Synced",
|
||||
"noNetworkConnected": "No network connected"
|
||||
}
|
||||
}
|
||||
|
14
frontend/rust-lib/Cargo.lock
generated
14
frontend/rust-lib/Cargo.lock
generated
@ -764,7 +764,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4b25d7d021a11c51583e6a404c139f49ee6a3bf9#4b25d7d021a11c51583e6a404c139f49ee6a3bf9"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=25c4be5#25c4be5d60fa67f0d2de7f69cc8292a4506e07de"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -788,7 +788,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4b25d7d021a11c51583e6a404c139f49ee6a3bf9#4b25d7d021a11c51583e6a404c139f49ee6a3bf9"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=25c4be5#25c4be5d60fa67f0d2de7f69cc8292a4506e07de"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -818,7 +818,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4b25d7d021a11c51583e6a404c139f49ee6a3bf9#4b25d7d021a11c51583e6a404c139f49ee6a3bf9"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=25c4be5#25c4be5d60fa67f0d2de7f69cc8292a4506e07de"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -837,7 +837,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4b25d7d021a11c51583e6a404c139f49ee6a3bf9#4b25d7d021a11c51583e6a404c139f49ee6a3bf9"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=25c4be5#25c4be5d60fa67f0d2de7f69cc8292a4506e07de"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -852,7 +852,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4b25d7d021a11c51583e6a404c139f49ee6a3bf9#4b25d7d021a11c51583e6a404c139f49ee6a3bf9"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=25c4be5#25c4be5d60fa67f0d2de7f69cc8292a4506e07de"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@ -889,7 +889,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4b25d7d021a11c51583e6a404c139f49ee6a3bf9#4b25d7d021a11c51583e6a404c139f49ee6a3bf9"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=25c4be5#25c4be5d60fa67f0d2de7f69cc8292a4506e07de"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@ -928,7 +928,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=4b25d7d021a11c51583e6a404c139f49ee6a3bf9#4b25d7d021a11c51583e6a404c139f49ee6a3bf9"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=25c4be5#25c4be5d60fa67f0d2de7f69cc8292a4506e07de"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
|
@ -120,10 +120,10 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ab9
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "4b25d7d021a11c51583e6a404c139f49ee6a3bf9" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "25c4be5" }
|
||||
|
@ -123,7 +123,7 @@ async fn sign_up_as_guest_and_then_update_to_new_cloud_user_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let old_views = test
|
||||
.folder_manager
|
||||
.get_current_workspace_views()
|
||||
.get_current_workspace_public_views()
|
||||
.await
|
||||
.unwrap();
|
||||
let old_workspace = test.folder_manager.get_current_workspace().await.unwrap();
|
||||
@ -132,7 +132,7 @@ async fn sign_up_as_guest_and_then_update_to_new_cloud_user_test() {
|
||||
test.supabase_sign_up_with_uuid(&uuid, None).await.unwrap();
|
||||
let new_views = test
|
||||
.folder_manager
|
||||
.get_current_workspace_views()
|
||||
.get_current_workspace_public_views()
|
||||
.await
|
||||
.unwrap();
|
||||
let new_workspace = test.folder_manager.get_current_workspace().await.unwrap();
|
||||
@ -163,7 +163,7 @@ async fn sign_up_as_guest_and_then_update_to_existing_cloud_user_test() {
|
||||
let old_cloud_workspace = test.folder_manager.get_current_workspace().await.unwrap();
|
||||
let old_cloud_views = test
|
||||
.folder_manager
|
||||
.get_current_workspace_views()
|
||||
.get_current_workspace_public_views()
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(old_cloud_views.len(), 1);
|
||||
@ -189,7 +189,7 @@ async fn sign_up_as_guest_and_then_update_to_existing_cloud_user_test() {
|
||||
let new_cloud_workspace = test.folder_manager.get_current_workspace().await.unwrap();
|
||||
let new_cloud_views = test
|
||||
.folder_manager
|
||||
.get_current_workspace_views()
|
||||
.get_current_workspace_public_views()
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(new_cloud_workspace, old_cloud_workspace);
|
||||
|
@ -261,10 +261,10 @@ pub enum ErrorCode {
|
||||
CloudRequestPayloadTooLarge = 90,
|
||||
|
||||
#[error("Workspace limit exceeded")]
|
||||
WorkspaceLimitExeceeded = 91,
|
||||
WorkspaceLimitExceeded = 91,
|
||||
|
||||
#[error("Workspace member limit exceeded")]
|
||||
WorkspaceMemberLimitExeceeded = 92,
|
||||
WorkspaceMemberLimitExceeded = 92,
|
||||
}
|
||||
|
||||
impl ErrorCode {
|
||||
|
@ -22,8 +22,8 @@ impl From<AppResponseError> for FlowyError {
|
||||
AppErrorCode::NetworkError => ErrorCode::HttpError,
|
||||
AppErrorCode::PayloadTooLarge => ErrorCode::CloudRequestPayloadTooLarge,
|
||||
AppErrorCode::UserUnAuthorized => match &*error.message {
|
||||
"Workspace Limit Exceeded" => ErrorCode::WorkspaceLimitExeceeded,
|
||||
"Workspace Member Limit Exceeded" => ErrorCode::WorkspaceMemberLimitExeceeded,
|
||||
"Workspace Limit Exceeded" => ErrorCode::WorkspaceLimitExceeded,
|
||||
"Workspace Member Limit Exceeded" => ErrorCode::WorkspaceMemberLimitExceeded,
|
||||
_ => ErrorCode::UserUnauthorized,
|
||||
},
|
||||
_ => ErrorCode::Internal,
|
||||
|
@ -285,8 +285,7 @@ impl TryInto<CreateViewParams> for CreateOrphanViewPayloadPB {
|
||||
meta: Default::default(),
|
||||
set_as_current: false,
|
||||
index: None,
|
||||
// TODO: lucas.xu add section to CreateOrphanViewPayloadPB
|
||||
section: Some(ViewSectionPB::Public),
|
||||
section: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ pub(crate) async fn get_workspace_views_handler(
|
||||
) -> DataResult<RepeatedViewPB, FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let params: GetWorkspaceViewParams = data.into_inner().try_into()?;
|
||||
let child_views = folder.get_workspace_views(¶ms.value).await?;
|
||||
let child_views = folder.get_workspace_public_views(¶ms.value).await?;
|
||||
let repeated_view: RepeatedViewPB = child_views.into();
|
||||
data_result_ok(repeated_view)
|
||||
}
|
||||
@ -63,7 +63,7 @@ pub(crate) async fn get_current_workspace_views_handler(
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> DataResult<RepeatedViewPB, FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let child_views = folder.get_current_workspace_views().await?;
|
||||
let child_views = folder.get_current_workspace_public_views().await?;
|
||||
let repeated_view: RepeatedViewPB = child_views.into();
|
||||
data_result_ok(repeated_view)
|
||||
}
|
||||
@ -286,7 +286,7 @@ pub(crate) async fn read_trash_handler(
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> DataResult<RepeatedTrashPB, FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let trash = folder.get_all_trash().await;
|
||||
let trash = folder.get_my_trash_info().await;
|
||||
data_result_ok(trash.into())
|
||||
}
|
||||
|
||||
@ -323,11 +323,11 @@ pub(crate) async fn restore_all_trash_handler(
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(folder), err)]
|
||||
pub(crate) async fn delete_all_trash_handler(
|
||||
pub(crate) async fn delete_my_trash_handler(
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
folder.delete_all_trash().await;
|
||||
folder.delete_my_trash().await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ pub fn init(folder: Weak<FolderManager>) -> AFPlugin {
|
||||
.event(FolderEvent::RestoreTrashItem, putback_trash_handler)
|
||||
.event(FolderEvent::PermanentlyDeleteTrashItem, delete_trash_handler)
|
||||
.event(FolderEvent::RecoverAllTrashItems, restore_all_trash_handler)
|
||||
.event(FolderEvent::PermanentlyDeleteAllTrashItem, delete_all_trash_handler)
|
||||
.event(FolderEvent::PermanentlyDeleteAllTrashItem, delete_my_trash_handler)
|
||||
.event(FolderEvent::ImportData, import_data_handler)
|
||||
.event(FolderEvent::GetFolderSnapshots, get_folder_snapshots_handler)
|
||||
.event(FolderEvent::UpdateViewIcon, update_view_icon_handler)
|
||||
|
@ -128,7 +128,7 @@ impl FolderManager {
|
||||
|
||||
/// Return a list of views of the current workspace.
|
||||
/// Only the first level of child views are included.
|
||||
pub async fn get_current_workspace_views(&self) -> FlowyResult<Vec<ViewPB>> {
|
||||
pub async fn get_current_workspace_public_views(&self) -> FlowyResult<Vec<ViewPB>> {
|
||||
let workspace_id = self
|
||||
.mutex_folder
|
||||
.lock()
|
||||
@ -136,14 +136,14 @@ impl FolderManager {
|
||||
.map(|folder| folder.get_workspace_id());
|
||||
|
||||
if let Some(workspace_id) = workspace_id {
|
||||
self.get_workspace_views(&workspace_id).await
|
||||
self.get_workspace_public_views(&workspace_id).await
|
||||
} else {
|
||||
tracing::warn!("Can't get current workspace views");
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_workspace_views(&self, workspace_id: &str) -> FlowyResult<Vec<ViewPB>> {
|
||||
pub async fn get_workspace_public_views(&self, workspace_id: &str) -> FlowyResult<Vec<ViewPB>> {
|
||||
let views = self.with_folder(Vec::new, |folder| {
|
||||
get_workspace_public_view_pbs(workspace_id, folder)
|
||||
});
|
||||
@ -519,7 +519,7 @@ impl FolderManager {
|
||||
let folder = self.mutex_folder.lock();
|
||||
let folder = folder.as_ref().ok_or_else(folder_not_init_error)?;
|
||||
let trash_ids = folder
|
||||
.get_all_trash()
|
||||
.get_all_trash_sections()
|
||||
.into_iter()
|
||||
.map(|trash| trash.id)
|
||||
.collect::<Vec<String>>();
|
||||
@ -559,7 +559,7 @@ impl FolderManager {
|
||||
|folder| {
|
||||
if let Some(view) = folder.views.get_view(view_id) {
|
||||
self.unfavorite_view_and_decendants(view.clone(), folder);
|
||||
folder.add_trash(vec![view_id.to_string()]);
|
||||
folder.add_trash_view_ids(vec![view_id.to_string()]);
|
||||
// notify the parent view that the view is moved to trash
|
||||
send_notification(view_id, FolderNotification::DidMoveViewToTrash)
|
||||
.payload(DeletedViewPB {
|
||||
@ -590,7 +590,7 @@ impl FolderManager {
|
||||
.collect();
|
||||
|
||||
if !favorite_descendant_views.is_empty() {
|
||||
folder.delete_favorites(
|
||||
folder.delete_favorite_view_ids(
|
||||
favorite_descendant_views
|
||||
.iter()
|
||||
.map(|v| v.id.clone())
|
||||
@ -754,6 +754,16 @@ impl FolderManager {
|
||||
None
|
||||
};
|
||||
|
||||
let is_private = self.with_folder(
|
||||
|| false,
|
||||
|folder| folder.is_view_in_section(Section::Private, &view.id),
|
||||
);
|
||||
let section = if is_private {
|
||||
ViewSectionPB::Private
|
||||
} else {
|
||||
ViewSectionPB::Public
|
||||
};
|
||||
|
||||
let duplicate_params = CreateViewParams {
|
||||
parent_view_id: view.parent_view_id.clone(),
|
||||
name: format!("{} (copy)", &view.name),
|
||||
@ -764,8 +774,7 @@ impl FolderManager {
|
||||
meta: Default::default(),
|
||||
set_as_current: true,
|
||||
index,
|
||||
// TODO: lucas.xu fetch the section from the view
|
||||
section: Some(ViewSectionPB::Public),
|
||||
section: Some(section),
|
||||
};
|
||||
|
||||
self.create_view_with_params(duplicate_params).await?;
|
||||
@ -801,9 +810,9 @@ impl FolderManager {
|
||||
|folder| {
|
||||
if let Some(old_view) = folder.views.get_view(view_id) {
|
||||
if old_view.is_favorite {
|
||||
folder.delete_favorites(vec![view_id.to_string()]);
|
||||
folder.delete_favorite_view_ids(vec![view_id.to_string()]);
|
||||
} else {
|
||||
folder.add_favorites(vec![view_id.to_string()]);
|
||||
folder.add_favorite_view_ids(vec![view_id.to_string()]);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -878,8 +887,8 @@ impl FolderManager {
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(self))]
|
||||
pub(crate) async fn get_all_trash(&self) -> Vec<TrashInfo> {
|
||||
self.with_folder(Vec::new, |folder| folder.get_all_trash())
|
||||
pub(crate) async fn get_my_trash_info(&self) -> Vec<TrashInfo> {
|
||||
self.with_folder(Vec::new, |folder| folder.get_my_trash_info())
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(self))]
|
||||
@ -887,7 +896,7 @@ impl FolderManager {
|
||||
self.with_folder(
|
||||
|| (),
|
||||
|folder| {
|
||||
folder.remote_all_trash();
|
||||
folder.remove_all_my_trash_sections();
|
||||
},
|
||||
);
|
||||
send_notification("trash", FolderNotification::DidUpdateTrash)
|
||||
@ -900,15 +909,15 @@ impl FolderManager {
|
||||
self.with_folder(
|
||||
|| (),
|
||||
|folder| {
|
||||
folder.delete_trash(vec![trash_id.to_string()]);
|
||||
folder.delete_trash_view_ids(vec![trash_id.to_string()]);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Delete all the trash permanently.
|
||||
#[tracing::instrument(level = "trace", skip(self))]
|
||||
pub(crate) async fn delete_all_trash(&self) {
|
||||
let deleted_trash = self.with_folder(Vec::new, |folder| folder.get_all_trash());
|
||||
pub(crate) async fn delete_my_trash(&self) {
|
||||
let deleted_trash = self.with_folder(Vec::new, |folder| folder.get_my_trash_info());
|
||||
for trash in deleted_trash {
|
||||
let _ = self.delete_trash(&trash.id).await;
|
||||
}
|
||||
@ -926,7 +935,7 @@ impl FolderManager {
|
||||
self.with_folder(
|
||||
|| (),
|
||||
|folder| {
|
||||
folder.delete_trash(vec![view_id.to_string()]);
|
||||
folder.delete_trash_view_ids(vec![view_id.to_string()]);
|
||||
folder.views.delete_views(vec![view_id]);
|
||||
},
|
||||
);
|
||||
@ -977,8 +986,7 @@ impl FolderManager {
|
||||
meta: Default::default(),
|
||||
set_as_current: false,
|
||||
index: None,
|
||||
// TODO: Lucas.xu fetch the section from the view
|
||||
section: Some(ViewSectionPB::Public),
|
||||
section: None,
|
||||
};
|
||||
|
||||
let view = create_view(self.user.user_id()?, params, import_data.view_layout);
|
||||
@ -1117,14 +1125,14 @@ impl FolderManager {
|
||||
fn get_sections(&self, section_type: Section) -> Vec<SectionItem> {
|
||||
self.with_folder(Vec::new, |folder| {
|
||||
let trash_ids = folder
|
||||
.get_all_trash()
|
||||
.get_all_trash_sections()
|
||||
.into_iter()
|
||||
.map(|trash| trash.id)
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
let mut views = match section_type {
|
||||
Section::Favorite => folder.get_all_favorites(),
|
||||
Section::Recent => folder.get_all_recent_sections(),
|
||||
Section::Favorite => folder.get_my_favorite_sections(),
|
||||
Section::Recent => folder.get_my_recent_sections(),
|
||||
_ => vec![],
|
||||
};
|
||||
|
||||
@ -1139,14 +1147,14 @@ impl FolderManager {
|
||||
pub(crate) fn get_workspace_public_view_pbs(_workspace_id: &str, folder: &Folder) -> Vec<ViewPB> {
|
||||
// get the trash ids
|
||||
let trash_ids = folder
|
||||
.get_all_trash()
|
||||
.get_all_trash_sections()
|
||||
.into_iter()
|
||||
.map(|trash| trash.id)
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
// get the private view ids
|
||||
let private_view_ids = folder
|
||||
.get_all_private_views()
|
||||
.get_all_private_sections()
|
||||
.into_iter()
|
||||
.map(|view| view.id)
|
||||
.collect::<Vec<String>>();
|
||||
@ -1174,14 +1182,14 @@ pub(crate) fn get_workspace_public_view_pbs(_workspace_id: &str, folder: &Folder
|
||||
pub(crate) fn get_workspace_private_view_pbs(_workspace_id: &str, folder: &Folder) -> Vec<ViewPB> {
|
||||
// get the trash ids
|
||||
let trash_ids = folder
|
||||
.get_all_trash()
|
||||
.get_all_trash_sections()
|
||||
.into_iter()
|
||||
.map(|trash| trash.id)
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
// get the private view ids
|
||||
let private_view_ids = folder
|
||||
.get_my_private_views()
|
||||
.get_my_private_sections()
|
||||
.into_iter()
|
||||
.map(|view| view.id)
|
||||
.collect::<Vec<String>>();
|
||||
|
@ -125,7 +125,7 @@ pub(crate) fn subscribe_folder_trash_changed(
|
||||
unique_ids.insert(view.parent_view_id.clone());
|
||||
}
|
||||
|
||||
let repeated_trash: RepeatedTrashPB = folder.get_all_trash().into();
|
||||
let repeated_trash: RepeatedTrashPB = folder.get_my_trash_info().into();
|
||||
send_notification("trash", FolderNotification::DidUpdateTrash)
|
||||
.payload(repeated_trash)
|
||||
.send();
|
||||
@ -150,7 +150,7 @@ pub(crate) fn notify_parent_view_did_change<T: AsRef<str>>(
|
||||
let folder = folder.as_ref()?;
|
||||
let workspace_id = folder.get_workspace_id();
|
||||
let trash_ids = folder
|
||||
.get_all_trash()
|
||||
.get_all_trash_sections()
|
||||
.into_iter()
|
||||
.map(|trash| trash.id)
|
||||
.collect::<Vec<String>>();
|
||||
|
@ -42,7 +42,7 @@ impl UserDataMigration for FavoriteV1AndWorkspaceArrayMigration {
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
if !favorite_view_ids.is_empty() {
|
||||
folder.add_favorites(favorite_view_ids);
|
||||
folder.add_favorite_view_ids(favorite_view_ids);
|
||||
}
|
||||
|
||||
let encode = folder.encode_collab_v1();
|
||||
|
@ -38,7 +38,7 @@ impl UserDataMigration for WorkspaceTrashMapToSectionMigration {
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
if !trash_ids.is_empty() {
|
||||
folder.add_trash(trash_ids);
|
||||
folder.add_trash_view_ids(trash_ids);
|
||||
}
|
||||
|
||||
let encode = folder.encode_collab_v1();
|
||||
|
Loading…
Reference in New Issue
Block a user