feat: generic calculations (#4794)

* feat: add generic calculations

* chore: remove row count at bottom of grid

* fix: code review
This commit is contained in:
Mathias Mogensen 2024-03-05 19:16:56 +01:00 committed by GitHub
parent 3b0d82287d
commit 66aea29ab7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 222 additions and 127 deletions

View File

@ -16,7 +16,7 @@ void main() {
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.tapCreateRowButtonInGrid();
// The initial number of rows is 3
// 3 initial rows + 1 created
await tester.assertNumberOfRowsInGridPage(4);
await tester.pumpAndSettle();
});
@ -31,9 +31,8 @@ void main() {
await tester.tapCreateRowButtonInRowMenuOfGrid();
// The initial number of rows is 3
// 3 initial rows + 1 created
await tester.assertNumberOfRowsInGridPage(4);
await tester.assertRowCountInGridPage(4);
await tester.pumpAndSettle();
});
@ -48,9 +47,8 @@ void main() {
await tester.tapRowMenuButtonInGrid();
await tester.tapDeleteOnRowMenu();
// The initial number of rows is 3
// 3 initial rows - 1 deleted
await tester.assertNumberOfRowsInGridPage(2);
await tester.assertRowCountInGridPage(2);
await tester.pumpAndSettle();
});
@ -60,7 +58,6 @@ void main() {
await tester.tapGoButton();
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.assertRowCountInGridPage(3);
await tester.pumpAndSettle();
});

View File

@ -1,26 +1,12 @@
import 'dart:io';
import 'package:appflowy/plugins/database/application/calculations/calculation_type_ext.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/calculations/calculate_cell.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/calculations/calculation_type_item.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/common/type_option_separator.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/header/type_option/number.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/checkbox.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/checklist.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/date.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/number.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/select_option.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/text.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/timestamp.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/url.dart';
import 'package:appflowy/util/field_type_extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/application/calculations/calculation_type_ext.dart';
import 'package:appflowy/plugins/database/board/presentation/board_page.dart';
import 'package:appflowy/plugins/database/board/presentation/widgets/board_column_header.dart';
import 'package:appflowy/plugins/database/calendar/application/calendar_bloc.dart';
@ -30,6 +16,9 @@ import 'package:appflowy/plugins/database/calendar/presentation/calendar_event_e
import 'package:appflowy/plugins/database/calendar/presentation/calendar_page.dart';
import 'package:appflowy/plugins/database/calendar/presentation/toolbar/calendar_layout_setting.dart';
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/calculations/calculate_cell.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/calculations/calculation_type_item.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/common/type_option_separator.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/choicechip/checkbox.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/choicechip/checklist/checklist.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/choicechip/select_option/option_list.dart';
@ -43,6 +32,7 @@ import 'package:appflowy/plugins/database/grid/presentation/widgets/header/deskt
import 'package:appflowy/plugins/database/grid/presentation/widgets/header/field_editor.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/header/field_type_list.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/header/type_option/date/date_time_format.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/header/type_option/number.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/row/row.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/sort/create_sort_list.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/sort/order_panel.dart';
@ -52,14 +42,22 @@ import 'package:appflowy/plugins/database/grid/presentation/widgets/toolbar/filt
import 'package:appflowy/plugins/database/grid/presentation/widgets/toolbar/sort_button.dart';
import 'package:appflowy/plugins/database/tab_bar/desktop/tab_bar_add_button.dart';
import 'package:appflowy/plugins/database/tab_bar/desktop/tab_bar_header.dart';
import 'package:appflowy/plugins/database/widgets/database_layout_ext.dart';
import 'package:appflowy/plugins/database/widgets/row/accessory/cell_accessory.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/checkbox.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/checklist.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/date.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/number.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/select_option.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/text.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/timestamp.dart';
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/url.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/checklist_cell_editor.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/checklist_progress_bar.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/date_editor.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/extension.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/select_option_editor.dart';
import 'package:appflowy/plugins/database/widgets/cell_editor/select_option_text_field.dart';
import 'package:appflowy/plugins/database/widgets/database_layout_ext.dart';
import 'package:appflowy/plugins/database/widgets/row/accessory/cell_accessory.dart';
import 'package:appflowy/plugins/database/widgets/row/row_action.dart';
import 'package:appflowy/plugins/database/widgets/row/row_banner.dart';
import 'package:appflowy/plugins/database/widgets/row/row_detail.dart';
@ -70,6 +68,7 @@ import 'package:appflowy/plugins/database/widgets/setting/database_setting_actio
import 'package:appflowy/plugins/database/widgets/setting/database_settings_list.dart';
import 'package:appflowy/plugins/database/widgets/setting/setting_button.dart';
import 'package:appflowy/plugins/database/widgets/setting/setting_property_list.dart';
import 'package:appflowy/util/field_type_extension.dart';
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/clear_date_button.dart';
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/date_type_option_button.dart';
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/end_time_button.dart';
@ -77,6 +76,7 @@ import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/remi
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_board/appflowy_board.dart';
import 'package:calendar_view/calendar_view.dart';
@ -86,10 +86,9 @@ import 'package:flowy_infra_ui/style_widget/text_input.dart';
import 'package:flowy_infra_ui/widget/buttons/primary_button.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:path/path.dart' as p;
import 'package:table_calendar/table_calendar.dart';
// Non-exported member of the table_calendar library
import 'package:table_calendar/src/widgets/cell_content.dart';
import 'package:table_calendar/table_calendar.dart';
import 'base.dart';
import 'common_operations.dart';
@ -974,11 +973,6 @@ extension AppFlowyDatabaseTest on WidgetTester {
await tapButtonWithName(LocaleKeys.grid_row_delete.tr());
}
Future<void> assertRowCountInGridPage(int num) async {
final text = find.text('${rowCountString()} $num', findRichText: true);
expect(text, findsOneWidget);
}
Future<void> createField(FieldType fieldType, String name) async {
await scrollToRight(find.byType(GridPage));
await tapNewPropertyButton();

View File

@ -11,8 +11,22 @@ extension CalcTypeLabel on CalculationType {
LocaleKeys.grid_calculationTypeLabel_median.tr(),
CalculationType.Min => LocaleKeys.grid_calculationTypeLabel_min.tr(),
CalculationType.Sum => LocaleKeys.grid_calculationTypeLabel_sum.tr(),
CalculationType.Count =>
LocaleKeys.grid_calculationTypeLabel_count.tr(),
CalculationType.CountEmpty =>
LocaleKeys.grid_calculationTypeLabel_countEmpty.tr(),
CalculationType.CountNonEmpty =>
LocaleKeys.grid_calculationTypeLabel_countNonEmpty.tr(),
_ => throw UnimplementedError(
'Label for $this has not been implemented',
),
};
String get shortLabel => switch (this) {
CalculationType.CountEmpty =>
LocaleKeys.grid_calculationTypeLabel_countEmptyShort.tr(),
CalculationType.CountNonEmpty =>
LocaleKeys.grid_calculationTypeLabel_countNonEmptyShort.tr(),
_ => label,
};
}

View File

@ -128,7 +128,7 @@ extension NumberFormatExtension on NumberFormatPB {
}
}
String iconSymbol() {
String iconSymbol([bool defaultPrefixInc = true]) {
switch (this) {
case NumberFormatPB.ArgentinePeso:
return "\$";
@ -169,7 +169,7 @@ extension NumberFormatExtension on NumberFormatPB {
case NumberFormatPB.NorwegianKrone:
return "kr";
case NumberFormatPB.Num:
return "#";
return defaultPrefixInc ? "#" : "";
case NumberFormatPB.Percent:
return "%";
case NumberFormatPB.PhilippinePeso:

View File

@ -0,0 +1,34 @@
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
extension AvailableCalculations on FieldType {
List<CalculationType> calculationsForFieldType() {
final calculationTypes = [
CalculationType.Count,
];
// These FieldTypes cannot be empty, no need to count empty/non-empty
if (![FieldType.Checkbox, FieldType.LastEditedTime, FieldType.CreatedTime]
.contains(this)) {
calculationTypes.addAll([
CalculationType.CountEmpty,
CalculationType.CountNonEmpty,
]);
}
switch (this) {
case FieldType.Number:
calculationTypes.addAll([
CalculationType.Sum,
CalculationType.Average,
CalculationType.Min,
CalculationType.Max,
CalculationType.Median,
]);
break;
default:
break;
}
return calculationTypes;
}
}

View File

@ -12,7 +12,6 @@ import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_scrollview.dart';
import 'package:flowy_infra_ui/widget/error_page.dart';
@ -237,7 +236,6 @@ class _GridPageContentState extends State<GridPageContent> {
viewId: widget.view.id,
scrollController: _scrollController,
),
const _GridFooter(),
],
);
}
@ -431,40 +429,3 @@ class _WrapScrollView extends StatelessWidget {
);
}
}
class _GridFooter extends StatelessWidget {
const _GridFooter();
@override
Widget build(BuildContext context) {
return BlocSelector<GridBloc, GridState, int>(
selector: (state) => state.rowCount,
builder: (context, rowCount) {
return Padding(
padding: GridSize.contentInsets,
child: RichText(
text: TextSpan(
text: rowCountString(),
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(color: Theme.of(context).hintColor),
children: [
TextSpan(
text: ' $rowCount',
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: AFThemeExtension.of(context).gridRowCountColor,
),
),
],
),
),
);
},
);
}
}
String rowCountString() {
return '${LocaleKeys.grid_row_count.tr()} :';
}

View File

@ -5,6 +5,7 @@ import 'package:appflowy/plugins/database/application/calculations/calculation_t
import 'package:appflowy/plugins/database/application/field/field_info.dart';
import 'package:appflowy/plugins/database/application/field/type_option/number_format_bloc.dart';
import 'package:appflowy/plugins/database/grid/application/calculations/calculations_bloc.dart';
import 'package:appflowy/plugins/database/grid/application/calculations/field_type_calc_ext.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/calculations/calculation_selector.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/calculations/calculation_type_item.dart';
import 'package:appflowy/plugins/database/grid/presentation/widgets/calculations/remove_calculation_button.dart';
@ -67,31 +68,29 @@ class _CalculateCellState extends State<CalculateCell> {
),
),
),
...CalculationType.values.map(
(type) => CalculationTypeItem(
type: type,
onTap: () {
if (type != widget.calculation?.calculationType) {
context.read<CalculationsBloc>().add(
CalculationsEvent.updateCalculationType(
widget.fieldInfo.id,
type,
calculationId: widget.calculation?.id,
),
);
}
},
),
),
...widget.fieldInfo.fieldType.calculationsForFieldType().map(
(type) => CalculationTypeItem(
type: type,
onTap: () {
if (type != widget.calculation?.calculationType) {
context.read<CalculationsBloc>().add(
CalculationsEvent.updateCalculationType(
widget.fieldInfo.id,
type,
calculationId: widget.calculation?.id,
),
);
}
},
),
),
],
),
);
},
child: widget.fieldInfo.fieldType == FieldType.Number
? widget.calculation != null
? _showCalculateValue(context, prefix)
: CalculationSelector(isSelected: isSelected)
: const SizedBox.shrink(),
child: widget.calculation != null
? _showCalculateValue(context, prefix)
: CalculationSelector(isSelected: isSelected),
),
);
}
@ -107,7 +106,7 @@ class _CalculateCellState extends State<CalculateCell> {
children: [
Flexible(
child: FlowyText(
widget.calculation!.calculationType.label,
widget.calculation!.calculationType.shortLabel,
color: Theme.of(context).hintColor,
overflow: TextOverflow.ellipsis,
),
@ -146,7 +145,7 @@ class _CalculateCellState extends State<CalculateCell> {
FieldType.Number =>
NumberTypeOptionPB.fromBuffer(widget.fieldInfo.field.typeOptionData)
.format
.iconSymbol(),
.iconSymbol(false),
_ => null,
};
}

View File

@ -1,7 +1,8 @@
import 'package:appflowy/plugins/database/grid/application/grid_bloc.dart';
import 'package:appflowy/plugins/database/application/database_controller.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:appflowy/plugins/database/grid/application/grid_bloc.dart';
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'util.dart';
void main() {
@ -17,7 +18,8 @@ void main() {
context = await gridTest.createTestGrid();
});
// The initial number of rows is 3 for each grid.
// The initial number of rows is 3 for each grid
// We create one row so we expect 4 rows
blocTest<GridBloc, GridState>(
"create a row",
build: () => GridBloc(

View File

@ -739,7 +739,12 @@
"max": "Max",
"median": "Median",
"min": "Min",
"sum": "Sum"
"sum": "Sum",
"count": "Count",
"countEmpty": "Count empty",
"countEmptyShort": "Empty",
"countNonEmpty": "Count non empty",
"countNonEmptyShort": "Not empty"
}
},
"document": {
@ -1350,4 +1355,4 @@
"userIcon": "User icon"
},
"noLogFiles": "There're no log files"
}
}

View File

@ -6,7 +6,7 @@ use std::{
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::{impl_into_calculation_type, services::calculations::Calculation};
use crate::{entities::FieldType, impl_into_calculation_type, services::calculations::Calculation};
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct CalculationPB {
@ -56,10 +56,13 @@ impl std::convert::From<&Arc<Calculation>> for CalculationPB {
pub enum CalculationType {
#[default]
Average = 0, // Number
Max = 1, // Number
Median = 2, // Number
Min = 3, // Number
Sum = 4, // Number
Max = 1, // Number
Median = 2, // Number
Min = 3, // Number
Sum = 4, // Number
Count = 5, // All
CountEmpty = 6, // All
CountNonEmpty = 7, // All
}
impl Display for CalculationType {
@ -102,6 +105,23 @@ impl From<&CalculationType> for i64 {
}
}
impl CalculationType {
pub fn is_allowed(&self, field_type: FieldType) -> bool {
match self {
// Number fields only
CalculationType::Max
| CalculationType::Min
| CalculationType::Average
| CalculationType::Median
| CalculationType::Sum => {
matches!(field_type, FieldType::Number)
},
// All fields
CalculationType::Count | CalculationType::CountEmpty | CalculationType::CountNonEmpty => true,
}
}
}
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct RepeatedCalculationsPB {
#[pb(index = 1)]

View File

@ -55,6 +55,9 @@ macro_rules! impl_into_calculation_type {
2 => CalculationType::Median,
3 => CalculationType::Min,
4 => CalculationType::Sum,
5 => CalculationType::Count,
6 => CalculationType::CountEmpty,
7 => CalculationType::CountNonEmpty,
_ => {
tracing::error!("🔴 Can't parse CalculationType from value: {}", ty);
CalculationType::Average

View File

@ -23,6 +23,7 @@ pub trait CalculationsDelegate: Send + Sync + 'static {
fn get_cells_for_field(&self, view_id: &str, field_id: &str) -> Fut<Vec<Arc<RowCell>>>;
fn get_field(&self, field_id: &str) -> Option<Field>;
fn get_calculation(&self, view_id: &str, field_id: &str) -> Fut<Option<Arc<Calculation>>>;
fn get_all_calculations(&self, view_id: &str) -> Fut<Arc<Vec<Arc<Calculation>>>>;
fn update_calculation(&self, view_id: &str, calculation: Calculation);
fn remove_calculation(&self, view_id: &str, calculation_id: &str);
}
@ -76,7 +77,7 @@ impl CalculationsController {
}
}
#[tracing::instrument(name = "schedule_filter_task", level = "trace", skip(self))]
#[tracing::instrument(name = "schedule_calculation_task", level = "trace", skip(self))]
async fn gen_task(&self, task_type: CalculationEvent, qos: QualityOfService) {
let task_id = self.task_scheduler.read().await.next_task_id();
let task = Task::new(
@ -89,10 +90,10 @@ impl CalculationsController {
}
#[tracing::instrument(
name = "process_filter_task",
name = "process_calculation_task",
level = "trace",
skip_all,
fields(filter_result),
fields(calculation_result),
err
)]
pub async fn process(&self, predicate: &str) -> FlowyResult<()> {
@ -160,7 +161,8 @@ impl CalculationsController {
.await;
if let Some(calculation) = calculation {
if new_field_type != FieldType::Number {
let calc_type: CalculationType = calculation.calculation_type.into();
if !calc_type.is_allowed(new_field_type) {
self
.delegate
.remove_calculation(&self.view_id, &calculation.id);
@ -228,6 +230,19 @@ impl CalculationsController {
let cells = row.cells.iter();
let mut updates = vec![];
// In case there are calculations where empty cells are counted
// as a contribution to the value.
if cells.len() == 0 {
let calculations = self.delegate.get_all_calculations(&self.view_id).await;
for calculation in calculations.iter() {
let update = self.get_updated_calculation(calculation.clone()).await;
if let Some(update) = update {
updates.push(CalculationPB::from(&update));
self.delegate.update_calculation(&self.view_id, update);
}
}
}
// Iterate each cell in the row
for cell in cells {
let field_id = cell.0;
@ -260,17 +275,13 @@ impl CalculationsController {
.await;
let field = self.delegate.get_field(&calculation.field_id)?;
if field_cells.is_empty() {
return Some(calculation.with_value(String::new()));
} else {
let value =
self
.calculations_service
.calculate(&field, calculation.calculation_type, field_cells);
let value =
self
.calculations_service
.calculate(&field, calculation.calculation_type, field_cells);
if value != calculation.value {
return Some(calculation.with_value(value));
}
if value != calculation.value {
return Some(calculation.with_value(value));
}
None

View File

@ -26,6 +26,9 @@ impl CalculationsService {
CalculationType::Median => self.calculate_median(field, row_cells),
CalculationType::Min => self.calculate_min(field, row_cells),
CalculationType::Sum => self.calculate_sum(field, row_cells),
CalculationType::Count => self.calculate_count(row_cells),
CalculationType::CountEmpty => self.calculate_count_empty(row_cells),
CalculationType::CountNonEmpty => self.calculate_count_non_empty(row_cells),
}
}
@ -62,7 +65,7 @@ impl CalculationsService {
if !values.is_empty() {
format!("{:.5}", Self::median(&values))
} else {
"".to_owned()
String::new()
}
}
@ -89,7 +92,7 @@ impl CalculationsService {
}
}
"".to_owned()
String::new()
}
fn calculate_max(&self, field: &Field, row_cells: Vec<Arc<RowCell>>) -> String {
@ -105,7 +108,7 @@ impl CalculationsService {
}
}
"".to_owned()
String::new()
}
fn calculate_sum(&self, field: &Field, row_cells: Vec<Arc<RowCell>>) -> String {
@ -114,7 +117,45 @@ impl CalculationsService {
if !values.is_empty() {
format!("{:.5}", values.iter().sum::<f64>())
} else {
"".to_owned()
String::new()
}
}
fn calculate_count(&self, row_cells: Vec<Arc<RowCell>>) -> String {
if !row_cells.is_empty() {
format!("{}", row_cells.len())
} else {
String::new()
}
}
fn calculate_count_empty(&self, row_cells: Vec<Arc<RowCell>>) -> String {
if !row_cells.is_empty() {
format!(
"{}",
row_cells
.iter()
.filter(|c| c.is_none())
.collect::<Vec<_>>()
.len()
)
} else {
String::new()
}
}
fn calculate_count_non_empty(&self, row_cells: Vec<Arc<RowCell>>) -> String {
if !row_cells.is_empty() {
format!(
"{}",
row_cells
.iter()
.filter(|c| c.is_some())
.collect::<Vec<_>>()
.len()
)
} else {
String::new()
}
}

View File

@ -66,4 +66,9 @@ impl CalculationsDelegate for DatabaseViewCalculationsDelegateImpl {
fn remove_calculation(&self, view_id: &str, calculation_id: &str) {
self.0.remove_calculation(view_id, calculation_id)
}
fn get_all_calculations(&self, view_id: &str) -> Fut<Arc<Vec<Arc<Calculation>>>> {
let calculations = Arc::new(self.0.get_all_calculations(view_id));
to_fut(async move { calculations })
}
}

View File

@ -161,14 +161,14 @@ impl DatabaseViewEditor {
.payload(changes)
.send();
self
.gen_did_create_row_view_tasks(row_detail.row.id.clone())
.gen_did_create_row_view_tasks(row_detail.row.clone())
.await;
}
pub async fn v_did_duplicate_row(&self, row_detail: &RowDetail) {
self
.calculations_controller
.did_receive_row_changed(row_detail.clone().row)
.did_receive_row_changed(row_detail.row.clone())
.await;
}
@ -1090,7 +1090,7 @@ impl DatabaseViewEditor {
sort_controller
.read()
.await
.did_receive_row_changed(row_id)
.did_receive_row_changed(row_id.clone())
.await;
}
if let Some(calculations_controller) = weak_calculations_controller.upgrade() {
@ -1101,11 +1101,20 @@ impl DatabaseViewEditor {
});
}
async fn gen_did_create_row_view_tasks(&self, row_id: RowId) {
async fn gen_did_create_row_view_tasks(&self, row: Row) {
let weak_sort_controller = Arc::downgrade(&self.sort_controller);
let weak_calculations_controller = Arc::downgrade(&self.calculations_controller);
af_spawn(async move {
if let Some(sort_controller) = weak_sort_controller.upgrade() {
sort_controller.read().await.did_create_row(row_id).await;
sort_controller
.read()
.await
.did_create_row(row.id.clone())
.await;
}
if let Some(calculations_controller) = weak_calculations_controller.upgrade() {
calculations_controller.did_receive_row_changed(row).await;
}
});
}