mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: add check workspace health button in settings page (#5631)
This commit is contained in:
parent
b24fbc6b60
commit
a1dec0f269
@ -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),
|
||||
|
@ -22,7 +22,7 @@ class WorkspaceSettingsBloc
|
||||
|
||||
try {
|
||||
final currentWorkspace =
|
||||
await _userService!.getCurrentWorkspace().getOrThrow();
|
||||
await UserBackendService.getCurrentWorkspace().getOrThrow();
|
||||
|
||||
final workspaces =
|
||||
await _userService!.getWorkspaces().getOrThrow();
|
||||
|
@ -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));
|
||||
|
@ -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)');
|
||||
}
|
||||
}
|
||||
}
|
@ -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(
|
||||
|
@ -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) {
|
||||
|
@ -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": {
|
||||
|
Loading…
Reference in New Issue
Block a user