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

feat: support exporting raw json format for document and database #6030

Closed
wants to merge 2 commits into from
Closed
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
49 changes: 49 additions & 0 deletions frontend/appflowy_flutter/lib/plugins/shared/share/export_tab.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/file_picker/file_picker_service.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

Expand Down Expand Up @@ -51,6 +52,14 @@ class ExportTab extends StatelessWidget {
svg: FlowySvgs.duplicate_s,
onTap: () => _exportToClipboard(context),
),
if (kDebugMode) ...[
const VSpace(10),
_ExportButton(
title: 'JSON (Debug Mode)',
svg: FlowySvgs.duplicate_s,
onTap: () => _exportJSON(context),
),
],
],
);
}
Expand All @@ -64,6 +73,14 @@ class ExportTab extends StatelessWidget {
svg: FlowySvgs.database_layout_m,
onTap: () => _exportCSV(context),
),
if (kDebugMode) ...[
const VSpace(10),
_ExportButton(
title: 'Raw Database Data (Debug Mode)',
svg: FlowySvgs.duplicate_s,
onTap: () => _exportRawDatabaseData(context),
),
],
],
);
}
Expand Down Expand Up @@ -100,6 +117,22 @@ class ExportTab extends StatelessWidget {
}
}

Future<void> _exportJSON(BuildContext context) async {
final viewName = context.read<ShareBloc>().state.viewName;
final exportPath = await getIt<FilePickerService>().saveFile(
dialogTitle: '',
fileName: '${viewName.toFileName()}.json',
);
if (context.mounted && exportPath != null) {
context.read<ShareBloc>().add(
ShareEvent.share(
ShareType.json,
exportPath,
),
);
}
}

Future<void> _exportCSV(BuildContext context) async {
final viewName = context.read<ShareBloc>().state.viewName;
final exportPath = await getIt<FilePickerService>().saveFile(
Expand All @@ -116,6 +149,22 @@ class ExportTab extends StatelessWidget {
}
}

Future<void> _exportRawDatabaseData(BuildContext context) async {
final viewName = context.read<ShareBloc>().state.viewName;
final exportPath = await getIt<FilePickerService>().saveFile(
dialogTitle: '',
fileName: '${viewName.toFileName()}.json',
);
if (context.mounted && exportPath != null) {
context.read<ShareBloc>().add(
ShareEvent.share(
ShareType.rawDatabaseData,
exportPath,
),
);
}
}

Future<void> _exportToClipboard(BuildContext context) async {
final documentExporter = DocumentExporter(context.read<ShareBloc>().view);
final result = await documentExporter.export(DocumentExportType.markdown);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,14 @@ class ShareBloc extends Bloc<ShareEvent, ShareState> {
(s) => FlowyResult.success(s.data),
(f) => FlowyResult.failure(f),
);
} else if (type == ShareType.rawDatabaseData) {
final exportResult = await BackendExportService.exportDatabaseAsRawData(
view.id,
);
result = exportResult.fold(
(s) => FlowyResult.success(s.data),
(f) => FlowyResult.failure(f),
);
} else {
result = await documentExporter.export(type.documentExportType);
}
Expand All @@ -189,6 +197,8 @@ class ShareBloc extends Bloc<ShareEvent, ShareState> {
case ShareType.markdown:
case ShareType.html:
case ShareType.csv:
case ShareType.json:
case ShareType.rawDatabaseData:
File(path).writeAsStringSync(s);
return FlowyResult.success(type);
default:
Expand All @@ -208,9 +218,11 @@ enum ShareType {
html,
text,
link,
json,

// only available in database
csv;
csv,
rawDatabaseData;

static List<ShareType> get unimplemented => [link];

Expand All @@ -222,10 +234,16 @@ enum ShareType {
return DocumentExportType.html;
case ShareType.text:
return DocumentExportType.text;
case ShareType.json:
return DocumentExportType.json;
case ShareType.csv:
throw UnsupportedError('DocumentShareType.csv is not supported');
case ShareType.link:
throw UnsupportedError('DocumentShareType.link is not supported');
case ShareType.rawDatabaseData:
throw UnsupportedError(
'DocumentShareType.rawDatabaseData is not supported',
);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'package:appflowy_backend/log.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

import '../startup.dart';

Expand All @@ -17,6 +19,23 @@ class PlatformErrorCatcherTask extends LaunchTask {
return true;
};
}

ErrorWidget.builder = (details) {
if (kDebugMode) {
return Container(
width: double.infinity,
height: 30,
color: Colors.red,
child: FlowyText(
'ERROR: ${details.exceptionAsString()}',
color: Colors.white,
),
);
}

// hide the error widget in release mode
return const SizedBox.shrink();
};
}

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,12 @@ class BackendExportService {
final payload = DatabaseViewIdPB.create()..value = viewId;
return DatabaseEventExportCSV(payload).send();
}

static Future<FlowyResult<DatabaseExportDataPB, FlowyError>>
exportDatabaseAsRawData(
String viewId,
) async {
final payload = DatabaseViewIdPB.create()..value = viewId;
return DatabaseEventExportRawDatabaseData(payload).send();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ impl FolderOperationHandler for DatabaseFolderOperation {
}

async fn duplicate_view(&self, view_id: &str) -> Result<Bytes, FlowyError> {
let delta_bytes = self.0.duplicate_database(view_id).await?;
let delta_bytes = self.0.get_database_json_bytes(view_id).await?;
Ok(Bytes::from(delta_bytes))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
pub enum DatabaseExportDataType {
#[default]
CSV = 0,

// DatabaseData
RawDatabaseData = 1,
}

#[derive(Debug, ProtoBuf, Default, Clone)]
Expand Down
14 changes: 14 additions & 0 deletions frontend/rust-lib/flowy-database2/src/event_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1021,6 +1021,20 @@ pub(crate) async fn export_csv_handler(
})
}

#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn export_raw_database_data_handler(
data: AFPluginData<DatabaseViewIdPB>,
manager: AFPluginState<Weak<DatabaseManager>>,
) -> DataResult<DatabaseExportDataPB, FlowyError> {
let manager = upgrade_manager(manager)?;
let view_id = data.into_inner().value;
let data = manager.get_database_json_string(&view_id).await?;
data_result_ok(DatabaseExportDataPB {
export_type: DatabaseExportDataType::RawDatabaseData,
data,
})
}

#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn get_snapshots_handler(
data: AFPluginData<DatabaseViewIdPB>,
Expand Down
4 changes: 4 additions & 0 deletions frontend/rust-lib/flowy-database2/src/event_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ pub fn init(database_manager: Weak<DatabaseManager>) -> AFPlugin {
.event(DatabaseEvent::CreateDatabaseView, create_database_view)
// Export
.event(DatabaseEvent::ExportCSV, export_csv_handler)
.event(DatabaseEvent::ExportRawDatabaseData, export_raw_database_data_handler)
.event(DatabaseEvent::GetDatabaseSnapshots, get_snapshots_handler)
// Field settings
.event(DatabaseEvent::GetFieldSettings, get_field_settings_handler)
Expand Down Expand Up @@ -385,4 +386,7 @@ pub enum DatabaseEvent {

#[event(input = "DatabaseViewIdPB", output = "RepeatedRowMetaPB")]
GetAllRows = 177,

#[event(input = "DatabaseViewIdPB", output = "DatabaseExportDataPB")]
ExportRawDatabaseData = 178,
}
10 changes: 9 additions & 1 deletion frontend/rust-lib/flowy-database2/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,14 +352,22 @@ impl DatabaseManager {
Ok(())
}

pub async fn duplicate_database(&self, view_id: &str) -> FlowyResult<Vec<u8>> {
pub async fn get_database_json_bytes(&self, view_id: &str) -> FlowyResult<Vec<u8>> {
let lock = self.workspace_database()?;
let wdb = lock.read().await;
let data = wdb.get_database_data(view_id).await?;
let json_bytes = data.to_json_bytes()?;
Ok(json_bytes)
}

pub async fn get_database_json_string(&self, view_id: &str) -> FlowyResult<String> {
let lock = self.workspace_database()?;
let wdb = lock.read().await;
let data = wdb.get_database_data(view_id).await?;
let json_string = serde_json::to_string(&data)?;
Ok(json_string)
}

/// Create a new database with the given data that can be deserialized to [DatabaseData].
#[tracing::instrument(level = "trace", skip_all, err)]
pub async fn create_database_with_database_data(
Expand Down
Loading