mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-08-18 05:41:48 +00:00
feat: use new api to get the workspace member role (#6783)
* chore: update to latest client api * chore: merge with main * chore: remove unneeded code * fix: sqlite migration * fix: cargo fmt * feat: use new api to get the member role --------- Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
This commit is contained in:
parent
dda3962249
commit
ee96a44fef
@ -15,8 +15,11 @@ part 'local_ai_on_boarding_bloc.freezed.dart';
|
|||||||
|
|
||||||
class LocalAIOnBoardingBloc
|
class LocalAIOnBoardingBloc
|
||||||
extends Bloc<LocalAIOnBoardingEvent, LocalAIOnBoardingState> {
|
extends Bloc<LocalAIOnBoardingEvent, LocalAIOnBoardingState> {
|
||||||
LocalAIOnBoardingBloc(this.userProfile, this.member, this.workspaceId)
|
LocalAIOnBoardingBloc(
|
||||||
: super(const LocalAIOnBoardingState()) {
|
this.userProfile,
|
||||||
|
this.currentWorkspaceMemberRole,
|
||||||
|
this.workspaceId,
|
||||||
|
) : super(const LocalAIOnBoardingState()) {
|
||||||
_userService = UserBackendService(userId: userProfile.id);
|
_userService = UserBackendService(userId: userProfile.id);
|
||||||
_successListenable = getIt<SubscriptionSuccessListenable>();
|
_successListenable = getIt<SubscriptionSuccessListenable>();
|
||||||
_successListenable.addListener(_onPaymentSuccessful);
|
_successListenable.addListener(_onPaymentSuccessful);
|
||||||
@ -36,7 +39,7 @@ class LocalAIOnBoardingBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
final UserProfilePB userProfile;
|
final UserProfilePB userProfile;
|
||||||
final WorkspaceMemberPB member;
|
final AFRolePB? currentWorkspaceMemberRole;
|
||||||
final String workspaceId;
|
final String workspaceId;
|
||||||
late final IUserBackendService _userService;
|
late final IUserBackendService _userService;
|
||||||
late final SubscriptionSuccessListenable _successListenable;
|
late final SubscriptionSuccessListenable _successListenable;
|
||||||
|
@ -14,13 +14,18 @@ class SettingsAIBloc extends Bloc<SettingsAIEvent, SettingsAIState> {
|
|||||||
SettingsAIBloc(
|
SettingsAIBloc(
|
||||||
this.userProfile,
|
this.userProfile,
|
||||||
this.workspaceId,
|
this.workspaceId,
|
||||||
WorkspaceMemberPB? member,
|
AFRolePB? currentWorkspaceMemberRole,
|
||||||
) : _userListener = UserListener(userProfile: userProfile),
|
) : _userListener = UserListener(userProfile: userProfile),
|
||||||
_userService = UserBackendService(userId: userProfile.id),
|
_userService = UserBackendService(userId: userProfile.id),
|
||||||
super(SettingsAIState(userProfile: userProfile, member: member)) {
|
super(
|
||||||
|
SettingsAIState(
|
||||||
|
userProfile: userProfile,
|
||||||
|
currentWorkspaceMemberRole: currentWorkspaceMemberRole,
|
||||||
|
),
|
||||||
|
) {
|
||||||
_dispatch();
|
_dispatch();
|
||||||
|
|
||||||
if (member == null) {
|
if (currentWorkspaceMemberRole == null) {
|
||||||
_userService.getWorkspaceMember().then((result) {
|
_userService.getWorkspaceMember().then((result) {
|
||||||
result.fold(
|
result.fold(
|
||||||
(member) {
|
(member) {
|
||||||
@ -85,7 +90,7 @@ class SettingsAIBloc extends Bloc<SettingsAIEvent, SettingsAIState> {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
refreshMember: (member) {
|
refreshMember: (member) {
|
||||||
emit(state.copyWith(member: member));
|
emit(state.copyWith(currentWorkspaceMemberRole: member.role));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -152,7 +157,7 @@ class SettingsAIState with _$SettingsAIState {
|
|||||||
const factory SettingsAIState({
|
const factory SettingsAIState({
|
||||||
required UserProfilePB userProfile,
|
required UserProfilePB userProfile,
|
||||||
UseAISettingPB? aiSettings,
|
UseAISettingPB? aiSettings,
|
||||||
WorkspaceMemberPB? member,
|
AFRolePB? currentWorkspaceMemberRole,
|
||||||
@Default(true) bool enableSearchIndexing,
|
@Default(true) bool enableSearchIndexing,
|
||||||
}) = _SettingsAIState;
|
}) = _SettingsAIState;
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ class SettingsDialogBloc
|
|||||||
extends Bloc<SettingsDialogEvent, SettingsDialogState> {
|
extends Bloc<SettingsDialogEvent, SettingsDialogState> {
|
||||||
SettingsDialogBloc(
|
SettingsDialogBloc(
|
||||||
this.userProfile,
|
this.userProfile,
|
||||||
this.workspaceMember, {
|
this.currentWorkspaceMemberRole, {
|
||||||
SettingsPage? initPage,
|
SettingsPage? initPage,
|
||||||
}) : _userListener = UserListener(userProfile: userProfile),
|
}) : _userListener = UserListener(userProfile: userProfile),
|
||||||
super(SettingsDialogState.initial(userProfile, initPage)) {
|
super(SettingsDialogState.initial(userProfile, initPage)) {
|
||||||
@ -41,7 +41,7 @@ class SettingsDialogBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
final UserProfilePB userProfile;
|
final UserProfilePB userProfile;
|
||||||
final WorkspaceMemberPB? workspaceMember;
|
final AFRolePB? currentWorkspaceMemberRole;
|
||||||
final UserListener _userListener;
|
final UserListener _userListener;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -57,8 +57,10 @@ class SettingsDialogBloc
|
|||||||
initial: () async {
|
initial: () async {
|
||||||
_userListener.start(onProfileUpdated: _profileUpdated);
|
_userListener.start(onProfileUpdated: _profileUpdated);
|
||||||
|
|
||||||
final isBillingEnabled =
|
final isBillingEnabled = await _isBillingEnabled(
|
||||||
await _isBillingEnabled(userProfile, workspaceMember);
|
userProfile,
|
||||||
|
currentWorkspaceMemberRole,
|
||||||
|
);
|
||||||
if (isBillingEnabled) {
|
if (isBillingEnabled) {
|
||||||
emit(state.copyWith(isBillingEnabled: true));
|
emit(state.copyWith(isBillingEnabled: true));
|
||||||
}
|
}
|
||||||
@ -86,7 +88,7 @@ class SettingsDialogBloc
|
|||||||
|
|
||||||
Future<bool> _isBillingEnabled(
|
Future<bool> _isBillingEnabled(
|
||||||
UserProfilePB userProfile, [
|
UserProfilePB userProfile, [
|
||||||
WorkspaceMemberPB? member,
|
AFRolePB? currentWorkspaceMemberRole,
|
||||||
]) async {
|
]) async {
|
||||||
if ([
|
if ([
|
||||||
AuthenticatorPB.Local,
|
AuthenticatorPB.Local,
|
||||||
@ -94,7 +96,8 @@ class SettingsDialogBloc
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (member == null || member.role != AFRolePB.Owner) {
|
if (currentWorkspaceMemberRole == null ||
|
||||||
|
currentWorkspaceMemberRole != AFRolePB.Owner) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,13 +63,6 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
|||||||
actionResult: null,
|
actionResult: null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
/// We wait with fetching the workspace member as it may take some time,
|
|
||||||
/// to avoid blocking the UI from rendering (the sidebar).
|
|
||||||
final workspaceMemberResult =
|
|
||||||
await _userService.getWorkspaceMember();
|
|
||||||
final workspaceMember = workspaceMemberResult.toNullable();
|
|
||||||
emit(state.copyWith(currentWorkspaceMember: workspaceMember));
|
|
||||||
},
|
},
|
||||||
fetchWorkspaces: () async {
|
fetchWorkspaces: () async {
|
||||||
final result = await _fetchWorkspaces();
|
final result = await _fetchWorkspaces();
|
||||||
@ -238,14 +231,6 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
/// We wait with fetching the workspace member as it may take some time,
|
|
||||||
/// to avoid blocking the UI from rendering (the sidebar).
|
|
||||||
final workspaceMemberResult =
|
|
||||||
await _userService.getWorkspaceMember();
|
|
||||||
final workspaceMember = workspaceMemberResult.toNullable();
|
|
||||||
|
|
||||||
emit(state.copyWith(currentWorkspaceMember: workspaceMember));
|
|
||||||
},
|
},
|
||||||
renameWorkspace: (workspaceId, name) async {
|
renameWorkspace: (workspaceId, name) async {
|
||||||
final result =
|
final result =
|
||||||
@ -515,7 +500,6 @@ class UserWorkspaceState with _$UserWorkspaceState {
|
|||||||
const factory UserWorkspaceState({
|
const factory UserWorkspaceState({
|
||||||
@Default(null) UserWorkspacePB? currentWorkspace,
|
@Default(null) UserWorkspacePB? currentWorkspace,
|
||||||
@Default([]) List<UserWorkspacePB> workspaces,
|
@Default([]) List<UserWorkspacePB> workspaces,
|
||||||
@Default(null) WorkspaceMemberPB? currentWorkspaceMember,
|
|
||||||
@Default(null) UserWorkspaceActionResult? actionResult,
|
@Default(null) UserWorkspaceActionResult? actionResult,
|
||||||
@Default(false) bool isCollabWorkspaceOn,
|
@Default(false) bool isCollabWorkspaceOn,
|
||||||
}) = _UserWorkspaceState;
|
}) = _UserWorkspaceState;
|
||||||
@ -533,7 +517,6 @@ class UserWorkspaceState with _$UserWorkspaceState {
|
|||||||
if (identical(this, other)) return true;
|
if (identical(this, other)) return true;
|
||||||
|
|
||||||
return other is UserWorkspaceState &&
|
return other is UserWorkspaceState &&
|
||||||
other.currentWorkspaceMember == currentWorkspaceMember &&
|
|
||||||
other.currentWorkspace == currentWorkspace &&
|
other.currentWorkspace == currentWorkspace &&
|
||||||
_deepCollectionEquality.equals(other.workspaces, workspaces) &&
|
_deepCollectionEquality.equals(other.workspaces, workspaces) &&
|
||||||
identical(other.actionResult, actionResult);
|
identical(other.actionResult, actionResult);
|
||||||
|
@ -94,15 +94,15 @@ class SidebarToast extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final userWorkspaceBloc = context.read<UserWorkspaceBloc>();
|
final userWorkspaceBloc = context.read<UserWorkspaceBloc>();
|
||||||
final member = userWorkspaceBloc.state.currentWorkspaceMember;
|
final role = userWorkspaceBloc.state.currentWorkspace?.role;
|
||||||
if (member == null) {
|
if (role == null) {
|
||||||
return Log.error(
|
return Log.error(
|
||||||
"Member is null. It should not happen. If you see this error, it's a bug",
|
"Member is null. It should not happen. If you see this error, it's a bug",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only if the user is the workspace owner will we navigate to the plan page.
|
// Only if the user is the workspace owner will we navigate to the plan page.
|
||||||
if (member.role.isOwner) {
|
if (role.isOwner) {
|
||||||
showSettingsDialog(
|
showSettingsDialog(
|
||||||
context,
|
context,
|
||||||
userProfile,
|
userProfile,
|
||||||
|
@ -150,7 +150,7 @@ class SpaceMoreActionTypeWrapper extends CustomActionCell {
|
|||||||
final isOwner = context
|
final isOwner = context
|
||||||
.read<UserWorkspaceBloc?>()
|
.read<UserWorkspaceBloc?>()
|
||||||
?.state
|
?.state
|
||||||
.currentWorkspaceMember
|
.currentWorkspace
|
||||||
?.role
|
?.role
|
||||||
.isOwner ??
|
.isOwner ??
|
||||||
false;
|
false;
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/shared/af_role_pb_extension.dart';
|
import 'package:appflowy/shared/af_role_pb_extension.dart';
|
||||||
import 'package:appflowy/shared/feature_flags.dart';
|
import 'package:appflowy/shared/feature_flags.dart';
|
||||||
import 'package:appflowy/workspace/application/settings/ai/local_ai_on_boarding_bloc.dart';
|
import 'package:appflowy/workspace/application/settings/ai/local_ai_on_boarding_bloc.dart';
|
||||||
|
import 'package:appflowy/workspace/application/settings/ai/settings_ai_bloc.dart';
|
||||||
import 'package:appflowy/workspace/presentation/settings/pages/setting_ai_view/local_ai_setting.dart';
|
import 'package:appflowy/workspace/presentation/settings/pages/setting_ai_view/local_ai_setting.dart';
|
||||||
import 'package:appflowy/workspace/presentation/settings/pages/setting_ai_view/model_selection.dart';
|
import 'package:appflowy/workspace/presentation/settings/pages/setting_ai_view/model_selection.dart';
|
||||||
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
|
|
||||||
import 'package:flowy_infra/theme_extension.dart';
|
|
||||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
|
||||||
import 'package:appflowy/workspace/application/settings/ai/settings_ai_bloc.dart';
|
|
||||||
import 'package:appflowy/workspace/presentation/settings/shared/settings_body.dart';
|
import 'package:appflowy/workspace/presentation/settings/shared/settings_body.dart';
|
||||||
|
import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart';
|
||||||
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
|
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flowy_infra/theme_extension.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||||
|
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
class AIFeatureOnlySupportedWhenUsingAppFlowyCloud extends StatelessWidget {
|
class AIFeatureOnlySupportedWhenUsingAppFlowyCloud extends StatelessWidget {
|
||||||
@ -39,18 +38,19 @@ class SettingsAIView extends StatelessWidget {
|
|||||||
const SettingsAIView({
|
const SettingsAIView({
|
||||||
super.key,
|
super.key,
|
||||||
required this.userProfile,
|
required this.userProfile,
|
||||||
required this.member,
|
required this.currentWorkspaceMemberRole,
|
||||||
required this.workspaceId,
|
required this.workspaceId,
|
||||||
});
|
});
|
||||||
|
|
||||||
final UserProfilePB userProfile;
|
final UserProfilePB userProfile;
|
||||||
final WorkspaceMemberPB? member;
|
final AFRolePB? currentWorkspaceMemberRole;
|
||||||
final String workspaceId;
|
final String workspaceId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider<SettingsAIBloc>(
|
return BlocProvider<SettingsAIBloc>(
|
||||||
create: (_) => SettingsAIBloc(userProfile, workspaceId, member)
|
create: (_) =>
|
||||||
|
SettingsAIBloc(userProfile, workspaceId, currentWorkspaceMemberRole)
|
||||||
..add(const SettingsAIEvent.started()),
|
..add(const SettingsAIEvent.started()),
|
||||||
child: BlocBuilder<SettingsAIBloc, SettingsAIState>(
|
child: BlocBuilder<SettingsAIBloc, SettingsAIState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
@ -60,11 +60,11 @@ class SettingsAIView extends StatelessWidget {
|
|||||||
|
|
||||||
children.add(const _AISearchToggle(value: false));
|
children.add(const _AISearchToggle(value: false));
|
||||||
|
|
||||||
if (state.member != null) {
|
if (state.currentWorkspaceMemberRole != null) {
|
||||||
children.add(
|
children.add(
|
||||||
_LocalAIOnBoarding(
|
_LocalAIOnBoarding(
|
||||||
userProfile: userProfile,
|
userProfile: userProfile,
|
||||||
member: state.member!,
|
currentWorkspaceMemberRole: state.currentWorkspaceMemberRole!,
|
||||||
workspaceId: workspaceId,
|
workspaceId: workspaceId,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -129,11 +129,11 @@ class _AISearchToggle extends StatelessWidget {
|
|||||||
class _LocalAIOnBoarding extends StatelessWidget {
|
class _LocalAIOnBoarding extends StatelessWidget {
|
||||||
const _LocalAIOnBoarding({
|
const _LocalAIOnBoarding({
|
||||||
required this.userProfile,
|
required this.userProfile,
|
||||||
required this.member,
|
required this.currentWorkspaceMemberRole,
|
||||||
required this.workspaceId,
|
required this.workspaceId,
|
||||||
});
|
});
|
||||||
final UserProfilePB userProfile;
|
final UserProfilePB userProfile;
|
||||||
final WorkspaceMemberPB member;
|
final AFRolePB? currentWorkspaceMemberRole;
|
||||||
final String workspaceId;
|
final String workspaceId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -142,16 +142,18 @@ class _LocalAIOnBoarding extends StatelessWidget {
|
|||||||
return BillingGateGuard(
|
return BillingGateGuard(
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) =>
|
create: (context) => LocalAIOnBoardingBloc(
|
||||||
LocalAIOnBoardingBloc(userProfile, member, workspaceId)
|
userProfile,
|
||||||
..add(const LocalAIOnBoardingEvent.started()),
|
currentWorkspaceMemberRole,
|
||||||
|
workspaceId,
|
||||||
|
)..add(const LocalAIOnBoardingEvent.started()),
|
||||||
child: BlocBuilder<LocalAIOnBoardingBloc, LocalAIOnBoardingState>(
|
child: BlocBuilder<LocalAIOnBoardingBloc, LocalAIOnBoardingState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
// Show the local AI settings if the user has purchased the AI Local plan
|
// Show the local AI settings if the user has purchased the AI Local plan
|
||||||
if (kDebugMode || state.isPurchaseAILocal) {
|
if (kDebugMode || state.isPurchaseAILocal) {
|
||||||
return const LocalAISetting();
|
return const LocalAISetting();
|
||||||
} else {
|
} else {
|
||||||
if (member.role.isOwner) {
|
if (currentWorkspaceMemberRole?.isOwner ?? false) {
|
||||||
// Show the upgrade to AI Local plan button if the user has not purchased the AI Local plan
|
// Show the upgrade to AI Local plan button if the user has not purchased the AI Local plan
|
||||||
return _UpgradeToAILocalPlan(
|
return _UpgradeToAILocalPlan(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/plugins/document/application/document_appearance_cubit.dart';
|
import 'package:appflowy/plugins/document/application/document_appearance_cubit.dart';
|
||||||
@ -45,6 +43,7 @@ import 'package:flowy_infra/theme.dart';
|
|||||||
import 'package:flowy_infra/theme_extension.dart';
|
import 'package:flowy_infra/theme_extension.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
|
||||||
@ -52,11 +51,11 @@ class SettingsWorkspaceView extends StatelessWidget {
|
|||||||
const SettingsWorkspaceView({
|
const SettingsWorkspaceView({
|
||||||
super.key,
|
super.key,
|
||||||
required this.userProfile,
|
required this.userProfile,
|
||||||
this.workspaceMember,
|
this.currentWorkspaceMemberRole,
|
||||||
});
|
});
|
||||||
|
|
||||||
final UserProfilePB userProfile;
|
final UserProfilePB userProfile;
|
||||||
final WorkspaceMemberPB? workspaceMember;
|
final AFRolePB? currentWorkspaceMemberRole;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -93,7 +92,11 @@ class SettingsWorkspaceView extends StatelessWidget {
|
|||||||
SettingsCategory(
|
SettingsCategory(
|
||||||
title: LocaleKeys.settings_workspacePage_workspaceName_title
|
title: LocaleKeys.settings_workspacePage_workspaceName_title
|
||||||
.tr(),
|
.tr(),
|
||||||
children: [_WorkspaceNameSetting(member: workspaceMember)],
|
children: [
|
||||||
|
_WorkspaceNameSetting(
|
||||||
|
currentWorkspaceMemberRole: currentWorkspaceMemberRole,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
const SettingsCategorySpacer(),
|
const SettingsCategorySpacer(),
|
||||||
SettingsCategory(
|
SettingsCategory(
|
||||||
@ -104,7 +107,7 @@ class SettingsWorkspaceView extends StatelessWidget {
|
|||||||
.tr(),
|
.tr(),
|
||||||
children: [
|
children: [
|
||||||
_WorkspaceIconSetting(
|
_WorkspaceIconSetting(
|
||||||
enableEdit: workspaceMember?.role.isOwner ?? false,
|
enableEdit: currentWorkspaceMemberRole?.isOwner ?? false,
|
||||||
workspace: state.workspace,
|
workspace: state.workspace,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -185,14 +188,14 @@ class SettingsWorkspaceView extends StatelessWidget {
|
|||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
onPressed: () => showConfirmDialog(
|
onPressed: () => showConfirmDialog(
|
||||||
context: context,
|
context: context,
|
||||||
title: workspaceMember?.role.isOwner ?? false
|
title: currentWorkspaceMemberRole?.isOwner ?? false
|
||||||
? LocaleKeys
|
? LocaleKeys
|
||||||
.settings_workspacePage_deleteWorkspacePrompt_title
|
.settings_workspacePage_deleteWorkspacePrompt_title
|
||||||
.tr()
|
.tr()
|
||||||
: LocaleKeys
|
: LocaleKeys
|
||||||
.settings_workspacePage_leaveWorkspacePrompt_title
|
.settings_workspacePage_leaveWorkspacePrompt_title
|
||||||
.tr(),
|
.tr(),
|
||||||
description: workspaceMember?.role.isOwner ?? false
|
description: currentWorkspaceMemberRole?.isOwner ?? false
|
||||||
? LocaleKeys
|
? LocaleKeys
|
||||||
.settings_workspacePage_deleteWorkspacePrompt_content
|
.settings_workspacePage_deleteWorkspacePrompt_content
|
||||||
.tr()
|
.tr()
|
||||||
@ -201,13 +204,13 @@ class SettingsWorkspaceView extends StatelessWidget {
|
|||||||
.tr(),
|
.tr(),
|
||||||
style: ConfirmPopupStyle.cancelAndOk,
|
style: ConfirmPopupStyle.cancelAndOk,
|
||||||
onConfirm: () => context.read<WorkspaceSettingsBloc>().add(
|
onConfirm: () => context.read<WorkspaceSettingsBloc>().add(
|
||||||
workspaceMember?.role.isOwner ?? false
|
currentWorkspaceMemberRole?.isOwner ?? false
|
||||||
? const WorkspaceSettingsEvent.deleteWorkspace()
|
? const WorkspaceSettingsEvent.deleteWorkspace()
|
||||||
: const WorkspaceSettingsEvent.leaveWorkspace(),
|
: const WorkspaceSettingsEvent.leaveWorkspace(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
buttonType: SingleSettingsButtonType.danger,
|
buttonType: SingleSettingsButtonType.danger,
|
||||||
buttonLabel: workspaceMember?.role.isOwner ?? false
|
buttonLabel: currentWorkspaceMemberRole?.isOwner ?? false
|
||||||
? LocaleKeys
|
? LocaleKeys
|
||||||
.settings_workspacePage_manageWorkspace_deleteWorkspace
|
.settings_workspacePage_manageWorkspace_deleteWorkspace
|
||||||
.tr()
|
.tr()
|
||||||
@ -225,9 +228,11 @@ class SettingsWorkspaceView extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _WorkspaceNameSetting extends StatefulWidget {
|
class _WorkspaceNameSetting extends StatefulWidget {
|
||||||
const _WorkspaceNameSetting({this.member});
|
const _WorkspaceNameSetting({
|
||||||
|
this.currentWorkspaceMemberRole,
|
||||||
|
});
|
||||||
|
|
||||||
final WorkspaceMemberPB? member;
|
final AFRolePB? currentWorkspaceMemberRole;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_WorkspaceNameSetting> createState() => _WorkspaceNameSettingState();
|
State<_WorkspaceNameSetting> createState() => _WorkspaceNameSettingState();
|
||||||
@ -255,7 +260,8 @@ class _WorkspaceNameSettingState extends State<_WorkspaceNameSetting> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
builder: (_, state) {
|
builder: (_, state) {
|
||||||
if (widget.member == null || !widget.member!.role.isOwner) {
|
if (widget.currentWorkspaceMemberRole == null ||
|
||||||
|
!widget.currentWorkspaceMemberRole!.isOwner) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 2.5),
|
padding: const EdgeInsets.symmetric(vertical: 2.5),
|
||||||
child: FlowyText.regular(
|
child: FlowyText.regular(
|
||||||
|
@ -109,7 +109,7 @@ class _HomePageButton extends StatelessWidget {
|
|||||||
final isOwner = context
|
final isOwner = context
|
||||||
.watch<UserWorkspaceBloc>()
|
.watch<UserWorkspaceBloc>()
|
||||||
.state
|
.state
|
||||||
.currentWorkspaceMember
|
.currentWorkspace
|
||||||
?.role
|
?.role
|
||||||
.isOwner ??
|
.isOwner ??
|
||||||
false;
|
false;
|
||||||
@ -227,7 +227,7 @@ class _FreePlanUpgradeButton extends StatelessWidget {
|
|||||||
final isOwner = context
|
final isOwner = context
|
||||||
.watch<UserWorkspaceBloc>()
|
.watch<UserWorkspaceBloc>()
|
||||||
.state
|
.state
|
||||||
.currentWorkspaceMember
|
.currentWorkspace
|
||||||
?.role
|
?.role
|
||||||
.isOwner ??
|
.isOwner ??
|
||||||
false;
|
false;
|
||||||
|
@ -82,7 +82,7 @@ class _DomainMoreActionState extends State<DomainMoreAction> {
|
|||||||
final isOwner = context
|
final isOwner = context
|
||||||
.watch<UserWorkspaceBloc>()
|
.watch<UserWorkspaceBloc>()
|
||||||
.state
|
.state
|
||||||
.currentWorkspaceMember
|
.currentWorkspace
|
||||||
?.role
|
?.role
|
||||||
.isOwner ??
|
.isOwner ??
|
||||||
false;
|
false;
|
||||||
|
@ -57,7 +57,7 @@ class SettingsDialog extends StatelessWidget {
|
|||||||
return BlocProvider<SettingsDialogBloc>(
|
return BlocProvider<SettingsDialogBloc>(
|
||||||
create: (context) => SettingsDialogBloc(
|
create: (context) => SettingsDialogBloc(
|
||||||
user,
|
user,
|
||||||
context.read<UserWorkspaceBloc>().state.currentWorkspaceMember,
|
context.read<UserWorkspaceBloc>().state.currentWorkspace?.role,
|
||||||
initPage: initPage,
|
initPage: initPage,
|
||||||
)..add(const SettingsDialogEvent.initial()),
|
)..add(const SettingsDialogEvent.initial()),
|
||||||
child: BlocBuilder<SettingsDialogBloc, SettingsDialogState>(
|
child: BlocBuilder<SettingsDialogBloc, SettingsDialogState>(
|
||||||
@ -80,10 +80,6 @@ class SettingsDialog extends StatelessWidget {
|
|||||||
currentPage:
|
currentPage:
|
||||||
context.read<SettingsDialogBloc>().state.page,
|
context.read<SettingsDialogBloc>().state.page,
|
||||||
isBillingEnabled: state.isBillingEnabled,
|
isBillingEnabled: state.isBillingEnabled,
|
||||||
member: context
|
|
||||||
.read<UserWorkspaceBloc>()
|
|
||||||
.state
|
|
||||||
.currentWorkspaceMember,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
@ -98,7 +94,8 @@ class SettingsDialog extends StatelessWidget {
|
|||||||
context
|
context
|
||||||
.read<UserWorkspaceBloc>()
|
.read<UserWorkspaceBloc>()
|
||||||
.state
|
.state
|
||||||
.currentWorkspaceMember,
|
.currentWorkspace
|
||||||
|
?.role,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -114,7 +111,7 @@ class SettingsDialog extends StatelessWidget {
|
|||||||
String workspaceId,
|
String workspaceId,
|
||||||
SettingsPage page,
|
SettingsPage page,
|
||||||
UserProfilePB user,
|
UserProfilePB user,
|
||||||
WorkspaceMemberPB? member,
|
AFRolePB? currentWorkspaceMemberRole,
|
||||||
) {
|
) {
|
||||||
switch (page) {
|
switch (page) {
|
||||||
case SettingsPage.account:
|
case SettingsPage.account:
|
||||||
@ -126,7 +123,7 @@ class SettingsDialog extends StatelessWidget {
|
|||||||
case SettingsPage.workspace:
|
case SettingsPage.workspace:
|
||||||
return SettingsWorkspaceView(
|
return SettingsWorkspaceView(
|
||||||
userProfile: user,
|
userProfile: user,
|
||||||
workspaceMember: member,
|
currentWorkspaceMemberRole: currentWorkspaceMemberRole,
|
||||||
);
|
);
|
||||||
case SettingsPage.manageData:
|
case SettingsPage.manageData:
|
||||||
return SettingsManageDataView(userProfile: user);
|
return SettingsManageDataView(userProfile: user);
|
||||||
@ -140,7 +137,7 @@ class SettingsDialog extends StatelessWidget {
|
|||||||
if (user.authenticator == AuthenticatorPB.AppFlowyCloud) {
|
if (user.authenticator == AuthenticatorPB.AppFlowyCloud) {
|
||||||
return SettingsAIView(
|
return SettingsAIView(
|
||||||
userProfile: user,
|
userProfile: user,
|
||||||
member: member,
|
currentWorkspaceMemberRole: currentWorkspaceMemberRole,
|
||||||
workspaceId: workspaceId,
|
workspaceId: workspaceId,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -16,14 +16,12 @@ class SettingsMenu extends StatelessWidget {
|
|||||||
required this.currentPage,
|
required this.currentPage,
|
||||||
required this.userProfile,
|
required this.userProfile,
|
||||||
required this.isBillingEnabled,
|
required this.isBillingEnabled,
|
||||||
this.member,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final Function changeSelectedPage;
|
final Function changeSelectedPage;
|
||||||
final SettingsPage currentPage;
|
final SettingsPage currentPage;
|
||||||
final UserProfilePB userProfile;
|
final UserProfilePB userProfile;
|
||||||
final bool isBillingEnabled;
|
final bool isBillingEnabled;
|
||||||
final WorkspaceMemberPB? member;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -667,6 +667,7 @@ fn to_user_workspace(af_workspace: AFWorkspace) -> UserWorkspace {
|
|||||||
workspace_database_id: af_workspace.database_storage_id.to_string(),
|
workspace_database_id: af_workspace.database_storage_id.to_string(),
|
||||||
icon: af_workspace.icon,
|
icon: af_workspace.icon,
|
||||||
member_count: af_workspace.member_count.unwrap_or(0),
|
member_count: af_workspace.member_count.unwrap_or(0),
|
||||||
|
role: af_workspace.role.map(|r| r.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ impl UserCloudService for LocalServerUserAuthServiceImpl {
|
|||||||
let params = params.unbox_or_error::<SignUpParams>()?;
|
let params = params.unbox_or_error::<SignUpParams>()?;
|
||||||
let uid = ID_GEN.lock().await.next_id();
|
let uid = ID_GEN.lock().await.next_id();
|
||||||
let workspace_id = uuid::Uuid::new_v4().to_string();
|
let workspace_id = uuid::Uuid::new_v4().to_string();
|
||||||
let user_workspace = UserWorkspace::new(&workspace_id, uid);
|
let user_workspace = UserWorkspace::new_local(&workspace_id, uid);
|
||||||
let user_name = if params.name.is_empty() {
|
let user_name = if params.name.is_empty() {
|
||||||
DEFAULT_USER_NAME()
|
DEFAULT_USER_NAME()
|
||||||
} else {
|
} else {
|
||||||
@ -214,6 +214,7 @@ fn make_user_workspace() -> UserWorkspace {
|
|||||||
created_at: Default::default(),
|
created_at: Default::default(),
|
||||||
workspace_database_id: uuid::Uuid::new_v4().to_string(),
|
workspace_database_id: uuid::Uuid::new_v4().to_string(),
|
||||||
icon: "".to_string(),
|
icon: "".to_string(),
|
||||||
member_count: 0,
|
member_count: 1,
|
||||||
|
role: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE user_workspace_table DROP COLUMN role;
|
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE user_workspace_table ADD COLUMN role INT;
|
@ -102,6 +102,7 @@ diesel::table! {
|
|||||||
database_storage_id -> Text,
|
database_storage_id -> Text,
|
||||||
icon -> Text,
|
icon -> Text,
|
||||||
member_count -> BigInt,
|
member_count -> BigInt,
|
||||||
|
role -> Nullable<Integer>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ use std::str::FromStr;
|
|||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
pub use client_api::entity::billing_dto::RecurringInterval;
|
pub use client_api::entity::billing_dto::RecurringInterval;
|
||||||
|
use client_api::entity::AFRole;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use serde_repr::*;
|
use serde_repr::*;
|
||||||
@ -145,10 +146,12 @@ pub struct UserWorkspace {
|
|||||||
pub icon: String,
|
pub icon: String,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub member_count: i64,
|
pub member_count: i64,
|
||||||
|
#[serde(default)]
|
||||||
|
pub role: Option<Role>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserWorkspace {
|
impl UserWorkspace {
|
||||||
pub fn new(workspace_id: &str, _uid: i64) -> Self {
|
pub fn new_local(workspace_id: &str, _uid: i64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: workspace_id.to_string(),
|
id: workspace_id.to_string(),
|
||||||
name: "".to_string(),
|
name: "".to_string(),
|
||||||
@ -156,6 +159,7 @@ impl UserWorkspace {
|
|||||||
workspace_database_id: Uuid::new_v4().to_string(),
|
workspace_database_id: Uuid::new_v4().to_string(),
|
||||||
icon: "".to_string(),
|
icon: "".to_string(),
|
||||||
member_count: 1,
|
member_count: 1,
|
||||||
|
role: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -420,6 +424,16 @@ impl From<Role> for i32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<AFRole> for Role {
|
||||||
|
fn from(value: AFRole) -> Self {
|
||||||
|
match value {
|
||||||
|
AFRole::Owner => Role::Owner,
|
||||||
|
AFRole::Member => Role::Member,
|
||||||
|
AFRole::Guest => Role::Guest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct WorkspaceMember {
|
pub struct WorkspaceMember {
|
||||||
pub email: String,
|
pub email: String,
|
||||||
pub role: Role,
|
pub role: Role,
|
||||||
|
@ -75,7 +75,8 @@ impl<'de> Visitor<'de> for SessionVisitor {
|
|||||||
// For historical reasons, the database_storage_id is constructed by the user_id.
|
// For historical reasons, the database_storage_id is constructed by the user_id.
|
||||||
workspace_database_id: STANDARD.encode(format!("{}:user:database", user_id)),
|
workspace_database_id: STANDARD.encode(format!("{}:user:database", user_id)),
|
||||||
icon: "".to_owned(),
|
icon: "".to_owned(),
|
||||||
member_count: 0,
|
member_count: 1,
|
||||||
|
role: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ use crate::entities::{AIModelPB, AuthenticatorPB};
|
|||||||
use crate::errors::ErrorCode;
|
use crate::errors::ErrorCode;
|
||||||
|
|
||||||
use super::parser::UserStabilityAIKey;
|
use super::parser::UserStabilityAIKey;
|
||||||
|
use super::AFRolePB;
|
||||||
|
|
||||||
#[derive(Default, ProtoBuf)]
|
#[derive(Default, ProtoBuf)]
|
||||||
pub struct UserTokenPB {
|
pub struct UserTokenPB {
|
||||||
@ -237,6 +238,9 @@ pub struct UserWorkspacePB {
|
|||||||
|
|
||||||
#[pb(index = 5)]
|
#[pb(index = 5)]
|
||||||
pub member_count: i64,
|
pub member_count: i64,
|
||||||
|
|
||||||
|
#[pb(index = 6, one_of)]
|
||||||
|
pub role: Option<AFRolePB>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<UserWorkspace> for UserWorkspacePB {
|
impl From<UserWorkspace> for UserWorkspacePB {
|
||||||
@ -247,6 +251,7 @@ impl From<UserWorkspace> for UserWorkspacePB {
|
|||||||
created_at_timestamp: value.created_at.timestamp(),
|
created_at_timestamp: value.created_at.timestamp(),
|
||||||
icon: value.icon,
|
icon: value.icon,
|
||||||
member_count: value.member_count,
|
member_count: value.member_count,
|
||||||
|
role: value.role.map(AFRolePB::from),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ pub struct UpdateWorkspaceMemberPB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Workspace Role
|
// Workspace Role
|
||||||
#[derive(ProtoBuf_Enum, Clone, Default)]
|
#[derive(Debug, ProtoBuf_Enum, Clone, Default)]
|
||||||
pub enum AFRolePB {
|
pub enum AFRolePB {
|
||||||
Owner = 0,
|
Owner = 0,
|
||||||
Member = 1,
|
Member = 1,
|
||||||
|
@ -17,6 +17,7 @@ pub struct UserWorkspaceTable {
|
|||||||
pub database_storage_id: String,
|
pub database_storage_id: String,
|
||||||
pub icon: String,
|
pub icon: String,
|
||||||
pub member_count: i64,
|
pub member_count: i64,
|
||||||
|
pub role: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_user_workspace_op(workspace_id: &str, mut conn: DBConnection) -> Option<UserWorkspace> {
|
pub fn get_user_workspace_op(workspace_id: &str, mut conn: DBConnection) -> Option<UserWorkspace> {
|
||||||
@ -94,6 +95,7 @@ impl TryFrom<(i64, &UserWorkspace)> for UserWorkspaceTable {
|
|||||||
database_storage_id: value.1.workspace_database_id.clone(),
|
database_storage_id: value.1.workspace_database_id.clone(),
|
||||||
icon: value.1.icon.clone(),
|
icon: value.1.icon.clone(),
|
||||||
member_count: value.1.member_count,
|
member_count: value.1.member_count,
|
||||||
|
role: value.1.role.clone().map(|v| v as i32),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,6 +112,7 @@ impl From<UserWorkspaceTable> for UserWorkspace {
|
|||||||
workspace_database_id: value.database_storage_id,
|
workspace_database_id: value.database_storage_id,
|
||||||
icon: value.icon,
|
icon: value.icon,
|
||||||
member_count: value.member_count,
|
member_count: value.member_count,
|
||||||
|
role: value.role.map(|v| v.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -730,6 +730,7 @@ pub fn save_all_user_workspaces(
|
|||||||
user_workspace_table::database_storage_id.eq(&user_workspace.database_storage_id),
|
user_workspace_table::database_storage_id.eq(&user_workspace.database_storage_id),
|
||||||
user_workspace_table::icon.eq(&user_workspace.icon),
|
user_workspace_table::icon.eq(&user_workspace.icon),
|
||||||
user_workspace_table::member_count.eq(&user_workspace.member_count),
|
user_workspace_table::member_count.eq(&user_workspace.member_count),
|
||||||
|
user_workspace_table::role.eq(&user_workspace.role),
|
||||||
))
|
))
|
||||||
.execute(conn)?;
|
.execute(conn)?;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user