Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: reset space relationship when clearing cache #5737

Merged
merged 6 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/.vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,4 @@
"cwd": "${workspaceRoot}/appflowy_tauri/"
},
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class DatabaseTabBarBloc
_createLinkedView(layout.layoutType, name ?? layout.layoutName);
},
deleteView: (String viewId) async {
final result = await ViewBackendService.delete(viewId: viewId);
final result = await ViewBackendService.deleteView(viewId: viewId);
result.fold(
(l) {},
(r) => Log.error(r),
Expand Down
16 changes: 12 additions & 4 deletions frontend/appflowy_flutter/lib/shared/feature_flags.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ enum FeatureFlag {
// used for controlling whether to show plan+billing options in settings
planBilling,

// used for space design
spaceDesign,

// used for ignore the conflicted feature flag
unknown;

Expand Down Expand Up @@ -88,6 +91,8 @@ enum FeatureFlag {

bool get isOn {
if ([
// release this feature in version 0.6.1
FeatureFlag.spaceDesign,
// release this feature in version 0.5.9
FeatureFlag.search,
// release this feature in version 0.5.6
Expand All @@ -105,15 +110,16 @@ enum FeatureFlag {
}

switch (this) {
case FeatureFlag.search:
case FeatureFlag.syncDocument:
case FeatureFlag.syncDatabase:
case FeatureFlag.spaceDesign:
return true;
case FeatureFlag.collaborativeWorkspace:
case FeatureFlag.membersSettings:
case FeatureFlag.planBilling:
case FeatureFlag.unknown:
return false;
case FeatureFlag.search:
case FeatureFlag.syncDocument:
case FeatureFlag.syncDatabase:
return true;
}
}

Expand All @@ -131,6 +137,8 @@ enum FeatureFlag {
return 'if it\'s on, the command palette and search button will be available';
case FeatureFlag.planBilling:
return 'if it\'s on, plan and billing pages will be available in Settings';
case FeatureFlag.spaceDesign:
return 'if it\'s on, the space design feature will be available';
case FeatureFlag.unknown:
return '';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
if (deletedSpace == null) {
return;
}
await ViewBackendService.delete(viewId: deletedSpace.id);
await ViewBackendService.deleteView(viewId: deletedSpace.id);
},
rename: (space, name) async {
add(SpaceEvent.update(name: name));
Expand Down Expand Up @@ -433,6 +433,7 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
workspaceId: workspaceId,
)..start(
sectionChanged: (result) async {
Log.info('did receive section views changed');
add(const SpaceEvent.didReceiveSpaceUpdate());
},
);
Expand Down Expand Up @@ -503,6 +504,7 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
if (_workspaceId == null) {
return false;
}

try {
final user =
await UserBackendService.getCurrentUserProfile().getOrThrow();
Expand All @@ -526,6 +528,13 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
(e) => e.isSpace && e.spacePermission == SpacePermission.publicToAll,
);
publicViews = publicViews.where((e) => !e.isSpace).toList();

for (final view in publicViews) {
Log.info(
'migrating: the public view should be migrated: ${view.name}(${view.id})',
);
}

// if there is already a public space, don't migrate the public space
// only migrate the public space if there are any public views
if (publicViews.isEmpty || containsPublicSpace) {
Expand Down Expand Up @@ -568,6 +577,13 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
(e) => e.isSpace && e.spacePermission == SpacePermission.private,
);
privateViews = privateViews.where((e) => !e.isSpace).toList();

for (final view in privateViews) {
Log.info(
'migrating: the private view should be migrated: ${view.name}(${view.id})',
);
}

if (privateViews.isEmpty || containsPrivateSpace) {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
// unpublish the page and all its child pages if they are published
await _unpublishPage(view);

final result = await ViewBackendService.delete(viewId: view.id);
final result = await ViewBackendService.deleteView(viewId: view.id);

emit(
result.fold(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,17 +122,17 @@ class ViewBackendService {
});
}

static Future<FlowyResult<void, FlowyError>> delete({
static Future<FlowyResult<void, FlowyError>> deleteView({
required String viewId,
}) {
final request = RepeatedViewIdPB.create()..items.add(viewId);
return FolderEventDeleteView(request).send();
}

static Future<FlowyResult<void, FlowyError>> deleteView({
required String viewId,
static Future<FlowyResult<void, FlowyError>> deleteViews({
required List<String> viewIds,
}) {
final request = RepeatedViewIdPB.create()..items.add(viewId);
final request = RepeatedViewIdPB.create()..items.addAll(viewIds);
return FolderEventDeleteView(request).send();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,11 +292,15 @@ class ConfirmPopup extends StatefulWidget {
required this.title,
required this.description,
required this.onConfirm,
this.confirmLabel,
this.confirmButtonColor,
});

final String title;
final String description;
final VoidCallback onConfirm;
final String? confirmLabel;
final Color? confirmButtonColor;
final ConfirmPopupStyle style;

@override
Expand Down Expand Up @@ -376,8 +380,9 @@ class _ConfirmPopupState extends State<ConfirmPopup> {
widget.onConfirm();
Navigator.of(context).pop();
},
confirmButtonName: LocaleKeys.button_ok.tr(),
confirmButtonColor: Theme.of(context).colorScheme.primary,
confirmButtonName: widget.confirmLabel ?? LocaleKeys.button_ok.tr(),
confirmButtonColor: widget.confirmButtonColor ??
Theme.of(context).colorScheme.primary,
);
case ConfirmPopupStyle.cancelAndOk:
return SpaceCancelOrConfirmButton(
Expand All @@ -386,8 +391,10 @@ class _ConfirmPopupState extends State<ConfirmPopup> {
widget.onConfirm();
Navigator.of(context).pop();
},
confirmButtonName: LocaleKeys.space_delete.tr(),
confirmButtonColor: Theme.of(context).colorScheme.error,
confirmButtonName:
widget.confirmLabel ?? LocaleKeys.space_delete.tr(),
confirmButtonColor:
widget.confirmButtonColor ?? Theme.of(context).colorScheme.error,
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:appflowy/workspace/presentation/settings/shared/single_setting_a
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:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';

Expand All @@ -24,15 +25,15 @@ class FixDataWidget extends StatelessWidget {
.tr(),
buttonLabel: LocaleKeys.settings_manageDataPage_data_fixButton.tr(),
onPressed: () {
FixDataManager.checkWorkspaceHealth(dryRun: true);
WorkspaceDataManager.checkWorkspaceHealth(dryRun: true);
},
),
],
);
}
}

class FixDataManager {
class WorkspaceDataManager {
static Future<void> checkWorkspaceHealth({
required bool dryRun,
}) async {
Expand Down Expand Up @@ -63,6 +64,9 @@ class FixDataManager {
// check the health of the spaces
await checkSpaceHealth(workspace: workspace, allViews: allViews);

// check the health of the views
await checkViewHealth(workspace: workspace, allViews: allViews);

// add other checks here
// ...
} catch (e) {
Expand All @@ -83,7 +87,6 @@ class FixDataManager {
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
Expand All @@ -106,6 +109,93 @@ class FixDataManager {
}
}

static Future<List<ViewPB>> checkViewHealth({
ViewPB? workspace,
List<ViewPB>? allViews,
bool dryRun = true,
}) async {
// Views whose parent view does not have the view in its child views
final List<ViewPB> unlistedChildViews = [];
// Views whose parent is not in allViews
final List<ViewPB> orphanViews = [];

try {
if (workspace == null || allViews == null) {
final currentWorkspace =
await UserBackendService.getCurrentWorkspace().getOrThrow();
// get all the views in the workspace
final result = await ViewBackendService.getAllViews().getOrThrow();
allViews = result.items;
workspace = allViews.firstWhereOrNull(
(e) => e.id == currentWorkspace.id,
);
}

for (final view in allViews) {
if (view.parentViewId == '') {
continue;
}

final parentView = allViews.firstWhereOrNull(
(e) => e.id == view.parentViewId,
);

if (parentView == null) {
orphanViews.add(view);
continue;
}

final childViewsOfParent =
await ViewBackendService.getChildViews(viewId: parentView.id)
.getOrThrow();
final result = childViewsOfParent.any((e) => e.id == view.id);
if (!result) {
unlistedChildViews.add(view);
}
}
} catch (e) {
Log.error('Failed to check space health: $e');
return [];
}

for (final view in unlistedChildViews) {
Log.info(
'[workspace] found an issue: view is not in the parent view\'s child views, view: ${view.toProto3Json()}}',
);
}

for (final view in orphanViews) {
Log.debug('[workspace] orphanViews: ${view.toProto3Json()}');
}

if (!dryRun && unlistedChildViews.isNotEmpty) {
Log.info(
'[workspace] start to fix ${unlistedChildViews.length} unlistedChildViews ...',
);
for (final view in unlistedChildViews) {
// move the view to the parent view if it is not in the parent view's child views
Log.info(
'[workspace] move view: $view to its parent view ${view.parentViewId}',
);
await ViewBackendService.moveViewV2(
viewId: view.id,
newParentId: view.parentViewId,
prevViewId: null,
);
}

Log.info('[workspace] end to fix unlistedChildViews');
}

if (unlistedChildViews.isEmpty && orphanViews.isEmpty) {
Log.info('[workspace] all views are healthy');
}

Log.info('[workspace] done checking view health');

return unlistedChildViews;
}

static void dumpViews(String prefix, List<ViewPB> views) {
for (int i = 0; i < views.length; i++) {
final view = views[i];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,26 +126,34 @@ class SettingsManageDataView extends StatelessWidget {
buttonLabel:
LocaleKeys.settings_manageDataPage_cache_title.tr(),
onPressed: () {
SettingsAlertDialog(
showCancelAndConfirmDialog(
context: context,
title: LocaleKeys
.settings_manageDataPage_cache_dialog_title
.tr(),
subtitle: LocaleKeys
description: LocaleKeys
.settings_manageDataPage_cache_dialog_description
.tr(),
confirm: () async {
confirmLabel: LocaleKeys.button_ok.tr(),
onConfirm: () async {
// clear all cache
await getIt<FlowyCacheManager>().clearAllCache();

// check the workspace and space health
await WorkspaceDataManager.checkViewHealth(
dryRun: false,
);

if (context.mounted) {
showSnackBarMessage(
showToastNotification(
context,
LocaleKeys
message: LocaleKeys
.settings_manageDataPage_cache_dialog_successHint
.tr(),
);
Navigator.of(context).pop();
}
},
).show(context);
);
},
),
],
Expand Down
Loading
Loading