feat: add check workspace health button in settings page (#5631)

This commit is contained in:
Lucas.Xu 2024-06-27 09:57:06 +08:00 committed by GitHub
parent b24fbc6b60
commit a1dec0f269
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 132 additions and 10 deletions

View File

@ -109,7 +109,7 @@ class UserBackendService implements IUserBackendService {
return UserEventOpenWorkspace(payload).send();
}
Future<FlowyResult<WorkspacePB, FlowyError>> getCurrentWorkspace() {
static Future<FlowyResult<WorkspacePB, FlowyError>> getCurrentWorkspace() {
return FolderEventReadCurrentWorkspace().send().then((result) {
return result.fold(
(workspace) => FlowyResult.success(workspace),

View File

@ -22,7 +22,7 @@ class WorkspaceSettingsBloc
try {
final currentWorkspace =
await _userService!.getCurrentWorkspace().getOrThrow();
await UserBackendService.getCurrentWorkspace().getOrThrow();
final workspaces =
await _userService!.getWorkspaces().getOrThrow();

View File

@ -1,5 +1,3 @@
import 'package:flutter/foundation.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/shared/feature_flags.dart';
import 'package:appflowy/user/application/user_listener.dart';
@ -12,6 +10,7 @@ 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';
import 'package:protobuf/protobuf.dart';
@ -406,7 +405,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
)> _fetchWorkspaces() async {
try {
final currentWorkspace =
await _userService.getCurrentWorkspace().getOrThrow();
await UserBackendService.getCurrentWorkspace().getOrThrow();
final workspaces = await _userService.getWorkspaces().getOrThrow();
if (workspaces.isEmpty) {
workspaces.add(convertWorkspacePBToUserWorkspace(currentWorkspace));

View File

@ -0,0 +1,115 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/user/application/user_service.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart';
import 'package:appflowy/workspace/application/view/view_service.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_category.dart';
import 'package:appflowy/workspace/presentation/settings/shared/single_setting_action.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
class FixDataWidget extends StatelessWidget {
const FixDataWidget({super.key});
@override
Widget build(BuildContext context) {
return SettingsCategory(
title: LocaleKeys.settings_manageDataPage_data_fixYourData.tr(),
children: [
SingleSettingAction(
labelMaxLines: 4,
label: LocaleKeys.settings_manageDataPage_data_fixYourDataDescription
.tr(),
buttonLabel: LocaleKeys.settings_manageDataPage_data_fixButton.tr(),
onPressed: () {
FixDataManager.checkWorkspaceHealth(dryRun: true);
},
),
],
);
}
}
class FixDataManager {
static Future<void> checkWorkspaceHealth({
required bool dryRun,
}) async {
try {
final currentWorkspace =
await UserBackendService.getCurrentWorkspace().getOrThrow();
// get all the views in the workspace
final result = await ViewBackendService.getAllViews().getOrThrow();
final allViews = result.items;
// dump all the views in the workspace
dumpViews('all views', allViews);
// get the workspace
final workspaces = allViews.where(
(e) => e.parentViewId == '' && e.id == currentWorkspace.id,
);
dumpViews('workspaces', workspaces.toList());
if (workspaces.length != 1) {
Log.error('Failed to fix workspace: workspace not found');
// there should be only one workspace
return;
}
final workspace = workspaces.first;
// check the health of the spaces
await checkSpaceHealth(workspace: workspace, allViews: allViews);
// add other checks here
// ...
} catch (e) {
Log.error('Failed to fix space relation: $e');
}
}
static Future<void> checkSpaceHealth({
required ViewPB workspace,
required List<ViewPB> allViews,
bool dryRun = true,
}) async {
try {
final workspaceChildViews =
await ViewBackendService.getChildViews(viewId: workspace.id)
.getOrThrow();
final workspaceChildViewIds =
workspaceChildViews.map((e) => e.id).toSet();
final spaces = allViews.where((e) => e.isSpace).toList();
//
for (final space in spaces) {
// the space is the top level view, so its parent view id should be the workspace id
// and the workspace should have the space in its child views
if (space.parentViewId != workspace.id ||
!workspaceChildViewIds.contains(space.id)) {
Log.info('found an issue: space is not in the workspace: $space');
if (!dryRun) {
// move the space to the workspace if it is not in the workspace
await ViewBackendService.moveViewV2(
viewId: space.id,
newParentId: workspace.id,
prevViewId: null,
);
}
workspaceChildViewIds.add(space.id);
}
}
} catch (e) {
Log.error('Failed to check space health: $e');
}
}
static void dumpViews(String prefix, List<ViewPB> views) {
for (int i = 0; i < views.length; i++) {
final view = views[i];
Log.info('$prefix $i: $view)');
}
}
}

View File

@ -1,8 +1,5 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:appflowy/core/helpers/url_launcher.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
@ -13,6 +10,7 @@ import 'package:appflowy/util/theme_extension.dart';
import 'package:appflowy/workspace/application/settings/setting_file_importer_bloc.dart';
import 'package:appflowy/workspace/application/settings/settings_location_cubit.dart';
import 'package:appflowy/workspace/presentation/home/toast.dart';
import 'package:appflowy/workspace/presentation/settings/pages/fix_data_widget.dart';
import 'package:appflowy/workspace/presentation/settings/shared/setting_action.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_alert_dialog.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_body.dart';
@ -29,6 +27,8 @@ import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/hover.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:fluttertoast/fluttertoast.dart';
@ -110,7 +110,10 @@ class SettingsManageDataView extends StatelessWidget {
if (kDebugMode) ...[
SettingsCategory(
title: LocaleKeys.settings_files_exportData.tr(),
children: const [SettingsExportFileWidget()],
children: const [
SettingsExportFileWidget(),
FixDataWidget(),
],
),
],
SettingsCategory(

View File

@ -59,7 +59,7 @@ class AppFlowyUnitTest {
WorkspacePB get currentWorkspace => workspace;
Future<void> _loadWorkspace() async {
final result = await userService.getCurrentWorkspace();
final result = await UserBackendService.getCurrentWorkspace();
result.fold(
(value) => workspace = value,
(error) {

View File

@ -491,6 +491,11 @@
"description": "Clearing the cache will cause images and fonts to be re-downloaded on load. This action will not remove or modify your data.",
"successHint": "Cache cleared!"
}
},
"data": {
"fixYourData": "Fix your data",
"fixButton": "Fix",
"fixYourDataDescription": "If you're experiencing issues with your data, you can try to fix it here."
}
},
"shortcutsPage": {