mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-11-04 20:13:59 +00:00
fix: various grid ui issues (#6182)
* fix: delete field confirmation dialog only closes top most popover * fix: prioritize single-line checklist items * chore: wrap text toggle persist * test: update integration tests * chore: delete conflicting outputs on freezed * chore: slightly make field editor faster * chore: use standard dialog componet * chore: enable multiline checklist tasks on mobile * chore: Update frontend/appflowy_flutter/lib/plugins/database/application/field/field_editor_bloc.dart Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com> * chore: code cleanup * fix: create field from row detail and add test * chore: allow opening related database from editor * test: integration test flake --------- Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
This commit is contained in:
parent
aa621289e9
commit
0fd0483302
@ -22,7 +22,7 @@ void main() {
|
|||||||
const fieldName = "test change field";
|
const fieldName = "test change field";
|
||||||
await tester.createField(
|
await tester.createField(
|
||||||
FieldType.RichText,
|
FieldType.RichText,
|
||||||
fieldName,
|
name: fieldName,
|
||||||
layout: ViewLayoutPB.Board,
|
layout: ViewLayoutPB.Board,
|
||||||
);
|
);
|
||||||
await tester.tapButton(card1);
|
await tester.tapButton(card1);
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:appflowy/util/field_type_extension.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
@ -41,7 +42,7 @@ void main() {
|
|||||||
name: 'my grid',
|
name: 'my grid',
|
||||||
layout: ViewLayoutPB.Grid,
|
layout: ViewLayoutPB.Grid,
|
||||||
);
|
);
|
||||||
await tester.createField(FieldType.RichText, 'description');
|
await tester.createField(FieldType.RichText, name: 'description');
|
||||||
|
|
||||||
await tester.editCell(
|
await tester.editCell(
|
||||||
rowIndex: 0,
|
rowIndex: 0,
|
||||||
@ -81,7 +82,7 @@ void main() {
|
|||||||
const fieldType = FieldType.Number;
|
const fieldType = FieldType.Number;
|
||||||
|
|
||||||
// Create a number field
|
// Create a number field
|
||||||
await tester.createField(fieldType, fieldType.name);
|
await tester.createField(fieldType);
|
||||||
|
|
||||||
await tester.editCell(
|
await tester.editCell(
|
||||||
rowIndex: 0,
|
rowIndex: 0,
|
||||||
@ -157,7 +158,7 @@ void main() {
|
|||||||
const fieldType = FieldType.CreatedTime;
|
const fieldType = FieldType.CreatedTime;
|
||||||
// Create a create time field
|
// Create a create time field
|
||||||
// The create time field is not editable
|
// The create time field is not editable
|
||||||
await tester.createField(fieldType, fieldType.name);
|
await tester.createField(fieldType);
|
||||||
|
|
||||||
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
|
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
|
||||||
|
|
||||||
@ -175,7 +176,7 @@ void main() {
|
|||||||
const fieldType = FieldType.LastEditedTime;
|
const fieldType = FieldType.LastEditedTime;
|
||||||
// Create a last time field
|
// Create a last time field
|
||||||
// The last time field is not editable
|
// The last time field is not editable
|
||||||
await tester.createField(fieldType, fieldType.name);
|
await tester.createField(fieldType);
|
||||||
|
|
||||||
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
|
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
|
||||||
|
|
||||||
@ -191,7 +192,7 @@ void main() {
|
|||||||
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
|
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
|
||||||
|
|
||||||
const fieldType = FieldType.DateTime;
|
const fieldType = FieldType.DateTime;
|
||||||
await tester.createField(fieldType, fieldType.name);
|
await tester.createField(fieldType);
|
||||||
|
|
||||||
// Tap the cell to invoke the field editor
|
// Tap the cell to invoke the field editor
|
||||||
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
|
await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
|
||||||
@ -366,7 +367,7 @@ void main() {
|
|||||||
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
|
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
|
||||||
|
|
||||||
const fieldType = FieldType.MultiSelect;
|
const fieldType = FieldType.MultiSelect;
|
||||||
await tester.createField(fieldType, fieldType.name);
|
await tester.createField(fieldType, name: fieldType.i18n);
|
||||||
|
|
||||||
// Tap the cell to invoke the selection option editor
|
// Tap the cell to invoke the selection option editor
|
||||||
await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
|
await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
|
||||||
@ -449,7 +450,7 @@ void main() {
|
|||||||
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
|
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
|
||||||
|
|
||||||
const fieldType = FieldType.Checklist;
|
const fieldType = FieldType.Checklist;
|
||||||
await tester.createField(fieldType, fieldType.name);
|
await tester.createField(fieldType);
|
||||||
|
|
||||||
// assert that there is no progress bar in the grid
|
// assert that there is no progress bar in the grid
|
||||||
tester.assertChecklistCellInGrid(rowIndex: 0, percent: null);
|
tester.assertChecklistCellInGrid(rowIndex: 0, percent: null);
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
|
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
|
||||||
import 'package:appflowy/plugins/database/widgets/field/type_option_editor/select/select_option.dart';
|
import 'package:appflowy/plugins/database/widgets/field/type_option_editor/select/select_option.dart';
|
||||||
import 'package:appflowy/util/field_type_extension.dart';
|
import 'package:appflowy/util/field_type_extension.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
import 'package:intl/intl.dart';
|
|
||||||
|
|
||||||
import '../../shared/database_test_op.dart';
|
import '../../shared/database_test_op.dart';
|
||||||
import '../../shared/util.dart';
|
import '../../shared/util.dart';
|
||||||
@ -56,11 +57,22 @@ void main() {
|
|||||||
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
|
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
|
||||||
|
|
||||||
// create a field
|
// create a field
|
||||||
await tester.createField(FieldType.Checklist, 'checklist');
|
await tester.createField(FieldType.Checklist);
|
||||||
|
tester.findFieldWithName(FieldType.Checklist.i18n);
|
||||||
|
|
||||||
// check the field is created successfully
|
// editing field type during field creation should change title
|
||||||
tester.findFieldWithName('checklist');
|
await tester.createField(FieldType.MultiSelect);
|
||||||
await tester.pumpAndSettle();
|
tester.findFieldWithName(FieldType.MultiSelect.i18n);
|
||||||
|
|
||||||
|
// not if the user changes the title manually though
|
||||||
|
const name = "New field";
|
||||||
|
await tester.createField(FieldType.DateTime);
|
||||||
|
await tester.tapGridFieldWithName(FieldType.DateTime.i18n);
|
||||||
|
await tester.renameField(name);
|
||||||
|
await tester.tapEditFieldButton();
|
||||||
|
await tester.tapSwitchFieldTypeButton();
|
||||||
|
await tester.selectFieldType(FieldType.URL);
|
||||||
|
tester.findFieldWithName(name);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('delete field', (tester) async {
|
testWidgets('delete field', (tester) async {
|
||||||
@ -70,14 +82,14 @@ void main() {
|
|||||||
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
|
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
|
||||||
|
|
||||||
// create a field
|
// create a field
|
||||||
await tester.createField(FieldType.Checkbox, 'New field 1');
|
await tester.createField(FieldType.Checkbox, name: 'New field 1');
|
||||||
|
|
||||||
// Delete the field
|
// Delete the field
|
||||||
await tester.tapGridFieldWithName('New field 1');
|
await tester.tapGridFieldWithName('New field 1');
|
||||||
await tester.tapDeletePropertyButton();
|
await tester.tapDeletePropertyButton();
|
||||||
|
|
||||||
// confirm delete
|
// confirm delete
|
||||||
await tester.tapDialogOkButton();
|
await tester.tapButtonWithName(LocaleKeys.space_delete.tr());
|
||||||
|
|
||||||
tester.noFieldWithName('New field 1');
|
tester.noFieldWithName('New field 1');
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
@ -90,10 +102,7 @@ void main() {
|
|||||||
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
|
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
|
||||||
|
|
||||||
// create a field
|
// create a field
|
||||||
await tester.scrollToRight(find.byType(GridPage));
|
await tester.createField(FieldType.RichText, name: 'New field 1');
|
||||||
await tester.tapNewPropertyButton();
|
|
||||||
await tester.renameField('New field 1');
|
|
||||||
await tester.dismissFieldEditor();
|
|
||||||
|
|
||||||
// duplicate the field
|
// duplicate the field
|
||||||
await tester.tapGridFieldWithName('New field 1');
|
await tester.tapGridFieldWithName('New field 1');
|
||||||
@ -126,26 +135,6 @@ void main() {
|
|||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('create checklist field', (tester) async {
|
|
||||||
await tester.initializeAppFlowy();
|
|
||||||
await tester.tapAnonymousSignInButton();
|
|
||||||
|
|
||||||
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
|
|
||||||
|
|
||||||
await tester.scrollToRight(find.byType(GridPage));
|
|
||||||
await tester.tapNewPropertyButton();
|
|
||||||
|
|
||||||
// Open the type option menu
|
|
||||||
await tester.tapSwitchFieldTypeButton();
|
|
||||||
|
|
||||||
await tester.selectFieldType(FieldType.Checklist);
|
|
||||||
|
|
||||||
// After update the field type, the cells should be updated
|
|
||||||
await tester.findCellByFieldType(FieldType.Checklist);
|
|
||||||
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('create list of fields', (tester) async {
|
testWidgets('create list of fields', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
await tester.tapAnonymousSignInButton();
|
await tester.tapAnonymousSignInButton();
|
||||||
@ -162,18 +151,10 @@ void main() {
|
|||||||
FieldType.CreatedTime,
|
FieldType.CreatedTime,
|
||||||
FieldType.Checkbox,
|
FieldType.Checkbox,
|
||||||
]) {
|
]) {
|
||||||
await tester.scrollToRight(find.byType(GridPage));
|
await tester.createField(fieldType);
|
||||||
await tester.tapNewPropertyButton();
|
|
||||||
await tester.renameField(fieldType.name);
|
|
||||||
|
|
||||||
// Open the type option menu
|
|
||||||
await tester.tapSwitchFieldTypeButton();
|
|
||||||
|
|
||||||
await tester.selectFieldType(fieldType);
|
|
||||||
await tester.dismissFieldEditor();
|
|
||||||
|
|
||||||
// After update the field type, the cells should be updated
|
// After update the field type, the cells should be updated
|
||||||
await tester.findCellByFieldType(fieldType);
|
tester.findCellByFieldType(fieldType);
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -190,15 +171,7 @@ void main() {
|
|||||||
FieldType.Checklist,
|
FieldType.Checklist,
|
||||||
FieldType.URL,
|
FieldType.URL,
|
||||||
]) {
|
]) {
|
||||||
// create the field
|
await tester.createField(fieldType);
|
||||||
await tester.scrollToRight(find.byType(GridPage));
|
|
||||||
await tester.tapNewPropertyButton();
|
|
||||||
await tester.renameField(fieldType.i18n);
|
|
||||||
|
|
||||||
// change field type
|
|
||||||
await tester.tapSwitchFieldTypeButton();
|
|
||||||
await tester.selectFieldType(fieldType);
|
|
||||||
await tester.dismissFieldEditor();
|
|
||||||
|
|
||||||
// open the field editor
|
// open the field editor
|
||||||
await tester.tapGridFieldWithName(fieldType.i18n);
|
await tester.tapGridFieldWithName(fieldType.i18n);
|
||||||
@ -218,11 +191,7 @@ void main() {
|
|||||||
await tester.scrollToRight(find.byType(GridPage));
|
await tester.scrollToRight(find.byType(GridPage));
|
||||||
|
|
||||||
// create a number field
|
// create a number field
|
||||||
await tester.tapNewPropertyButton();
|
await tester.createField(FieldType.Number);
|
||||||
await tester.renameField("Number");
|
|
||||||
await tester.tapSwitchFieldTypeButton();
|
|
||||||
await tester.selectFieldType(FieldType.Number);
|
|
||||||
await tester.dismissFieldEditor();
|
|
||||||
|
|
||||||
// enter some data into the first number cell
|
// enter some data into the first number cell
|
||||||
await tester.editCell(
|
await tester.editCell(
|
||||||
@ -243,7 +212,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// open editor and change number format
|
// open editor and change number format
|
||||||
await tester.tapGridFieldWithName('Number');
|
await tester.tapGridFieldWithName(FieldType.Number.i18n);
|
||||||
await tester.tapEditFieldButton();
|
await tester.tapEditFieldButton();
|
||||||
await tester.changeNumberFieldFormat();
|
await tester.changeNumberFieldFormat();
|
||||||
await tester.dismissFieldEditor();
|
await tester.dismissFieldEditor();
|
||||||
@ -292,11 +261,7 @@ void main() {
|
|||||||
await tester.scrollToRight(find.byType(GridPage));
|
await tester.scrollToRight(find.byType(GridPage));
|
||||||
|
|
||||||
// create a date field
|
// create a date field
|
||||||
await tester.tapNewPropertyButton();
|
await tester.createField(FieldType.DateTime);
|
||||||
await tester.renameField(FieldType.DateTime.i18n);
|
|
||||||
await tester.tapSwitchFieldTypeButton();
|
|
||||||
await tester.selectFieldType(FieldType.DateTime);
|
|
||||||
await tester.dismissFieldEditor();
|
|
||||||
|
|
||||||
// edit the first date cell
|
// edit the first date cell
|
||||||
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.DateTime);
|
await tester.tapCellInGrid(rowIndex: 0, fieldType: FieldType.DateTime);
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
import 'package:appflowy/plugins/database/grid/presentation/widgets/header/desktop_field_cell.dart';
|
||||||
|
import 'package:appflowy/plugins/database/widgets/row/row_detail.dart';
|
||||||
|
import 'package:appflowy/util/field_type_extension.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:appflowy/plugins/database/widgets/row/row_banner.dart';
|
import 'package:appflowy/plugins/database/widgets/row/row_banner.dart';
|
||||||
@ -121,15 +124,24 @@ void main() {
|
|||||||
FieldType.Checkbox,
|
FieldType.Checkbox,
|
||||||
]) {
|
]) {
|
||||||
await tester.tapRowDetailPageCreatePropertyButton();
|
await tester.tapRowDetailPageCreatePropertyButton();
|
||||||
await tester.renameField(fieldType.name);
|
|
||||||
|
|
||||||
// Open the type option menu
|
// Open the type option menu
|
||||||
await tester.tapSwitchFieldTypeButton();
|
await tester.tapSwitchFieldTypeButton();
|
||||||
|
|
||||||
await tester.selectFieldType(fieldType);
|
await tester.selectFieldType(fieldType);
|
||||||
|
|
||||||
|
final field = find.descendant(
|
||||||
|
of: find.byType(RowDetailPage),
|
||||||
|
matching: find.byWidgetPredicate(
|
||||||
|
(widget) =>
|
||||||
|
widget is FieldCellButton &&
|
||||||
|
widget.field.name == fieldType.i18n,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(field, findsOneWidget);
|
||||||
|
|
||||||
// After update the field type, the cells should be updated
|
// After update the field type, the cells should be updated
|
||||||
await tester.findCellByFieldType(fieldType);
|
tester.findCellByFieldType(fieldType);
|
||||||
await tester.scrollRowDetailByOffset(const Offset(0, -50));
|
await tester.scrollRowDetailByOffset(const Offset(0, -50));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -74,7 +74,6 @@ 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/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/date_type_option_button.dart';
|
||||||
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/reminder_selector.dart';
|
import 'package:appflowy/workspace/presentation/widgets/date_picker/widgets/reminder_selector.dart';
|
||||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
|
||||||
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
||||||
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.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-database2/protobuf.dart';
|
||||||
@ -476,7 +475,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
|||||||
await pumpAndSettle();
|
await pumpAndSettle();
|
||||||
if (enter) {
|
if (enter) {
|
||||||
await testTextInput.receiveAction(TextInputAction.done);
|
await testTextInput.receiveAction(TextInputAction.done);
|
||||||
await pumpAndSettle();
|
await pumpAndSettle(const Duration(milliseconds: 500));
|
||||||
} else {
|
} else {
|
||||||
await tapButton(
|
await tapButton(
|
||||||
find.descendant(
|
find.descendant(
|
||||||
@ -629,12 +628,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
|||||||
(w) => w is FieldActionCell && w.action == FieldAction.delete,
|
(w) => w is FieldActionCell && w.action == FieldAction.delete,
|
||||||
);
|
);
|
||||||
await tapButton(deleteButton);
|
await tapButton(deleteButton);
|
||||||
|
await tapButtonWithName(LocaleKeys.space_delete.tr());
|
||||||
final confirmButton = find.descendant(
|
|
||||||
of: find.byType(NavigatorAlertDialog),
|
|
||||||
matching: find.byType(PrimaryTextButton),
|
|
||||||
);
|
|
||||||
await tapButton(confirmButton);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> scrollRowDetailByOffset(Offset offset) async {
|
Future<void> scrollRowDetailByOffset(Offset offset) async {
|
||||||
@ -788,7 +782,7 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
|||||||
|
|
||||||
/// Each field has its own cell, so we can find the corresponding cell by
|
/// Each field has its own cell, so we can find the corresponding cell by
|
||||||
/// the field type after create a new field.
|
/// the field type after create a new field.
|
||||||
Future<void> findCellByFieldType(FieldType fieldType) async {
|
void findCellByFieldType(FieldType fieldType) {
|
||||||
final finder = finderForFieldType(fieldType);
|
final finder = finderForFieldType(fieldType);
|
||||||
expect(finder, findsWidgets);
|
expect(finder, findsWidgets);
|
||||||
}
|
}
|
||||||
@ -894,18 +888,19 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> createField(
|
Future<void> createField(
|
||||||
FieldType fieldType,
|
FieldType fieldType, {
|
||||||
String name, {
|
String? name,
|
||||||
ViewLayoutPB layout = ViewLayoutPB.Grid,
|
ViewLayoutPB layout = ViewLayoutPB.Grid,
|
||||||
}) async {
|
}) async {
|
||||||
if (layout == ViewLayoutPB.Grid) {
|
if (layout == ViewLayoutPB.Grid) {
|
||||||
await scrollToRight(find.byType(GridPage));
|
await scrollToRight(find.byType(GridPage));
|
||||||
}
|
}
|
||||||
await tapNewPropertyButton();
|
await tapNewPropertyButton();
|
||||||
await renameField(name);
|
if (name != null) {
|
||||||
|
await renameField(name);
|
||||||
|
}
|
||||||
await tapSwitchFieldTypeButton();
|
await tapSwitchFieldTypeButton();
|
||||||
await selectFieldType(fieldType);
|
await selectFieldType(fieldType);
|
||||||
await dismissFieldEditor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> tapDatabaseSettingButton() async {
|
Future<void> tapDatabaseSettingButton() async {
|
||||||
|
|||||||
@ -62,7 +62,7 @@ class _QuickEditFieldState extends State<QuickEditField> {
|
|||||||
create: (_) => FieldEditorBloc(
|
create: (_) => FieldEditorBloc(
|
||||||
viewId: widget.viewId,
|
viewId: widget.viewId,
|
||||||
fieldController: widget.fieldController,
|
fieldController: widget.fieldController,
|
||||||
field: widget.fieldInfo.field,
|
fieldInfo: widget.fieldInfo,
|
||||||
isNew: false,
|
isNew: false,
|
||||||
),
|
),
|
||||||
child: BlocConsumer<FieldEditorBloc, FieldEditorState>(
|
child: BlocConsumer<FieldEditorBloc, FieldEditorState>(
|
||||||
|
|||||||
@ -18,32 +18,33 @@ part 'field_editor_bloc.freezed.dart';
|
|||||||
class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
|
class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
|
||||||
FieldEditorBloc({
|
FieldEditorBloc({
|
||||||
required this.viewId,
|
required this.viewId,
|
||||||
|
required this.fieldInfo,
|
||||||
required this.fieldController,
|
required this.fieldController,
|
||||||
this.onFieldInserted,
|
this.onFieldInserted,
|
||||||
required FieldPB field,
|
|
||||||
required this.isNew,
|
required this.isNew,
|
||||||
}) : fieldId = field.id,
|
}) : _fieldService = FieldBackendService(
|
||||||
fieldService = FieldBackendService(
|
|
||||||
viewId: viewId,
|
viewId: viewId,
|
||||||
fieldId: field.id,
|
fieldId: fieldInfo.id,
|
||||||
),
|
),
|
||||||
fieldSettingsService = FieldSettingsBackendService(viewId: viewId),
|
fieldSettingsService = FieldSettingsBackendService(viewId: viewId),
|
||||||
super(FieldEditorState(field: FieldInfo.initial(field))) {
|
super(FieldEditorState(field: fieldInfo)) {
|
||||||
_dispatch();
|
_dispatch();
|
||||||
_startListening();
|
_startListening();
|
||||||
_init();
|
_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
final String viewId;
|
final String viewId;
|
||||||
final String fieldId;
|
final FieldInfo fieldInfo;
|
||||||
final bool isNew;
|
final bool isNew;
|
||||||
final FieldController fieldController;
|
final FieldController fieldController;
|
||||||
final FieldBackendService fieldService;
|
final FieldBackendService _fieldService;
|
||||||
final FieldSettingsBackendService fieldSettingsService;
|
final FieldSettingsBackendService fieldSettingsService;
|
||||||
final void Function(String newFieldId)? onFieldInserted;
|
final void Function(String newFieldId)? onFieldInserted;
|
||||||
|
|
||||||
late final OnReceiveField _listener;
|
late final OnReceiveField _listener;
|
||||||
|
|
||||||
|
String get fieldId => fieldInfo.id;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> close() {
|
Future<void> close() {
|
||||||
fieldController.removeSingleFieldListener(
|
fieldController.removeSingleFieldListener(
|
||||||
@ -66,13 +67,13 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
|
|||||||
fieldName = fieldType.i18n;
|
fieldName = fieldType.i18n;
|
||||||
}
|
}
|
||||||
|
|
||||||
await fieldService.updateType(
|
await _fieldService.updateType(
|
||||||
fieldType: fieldType,
|
fieldType: fieldType,
|
||||||
fieldName: fieldName,
|
fieldName: fieldName,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
renameField: (newName) async {
|
renameField: (newName) async {
|
||||||
final result = await fieldService.updateField(name: newName);
|
final result = await _fieldService.updateField(name: newName);
|
||||||
_logIfError(result);
|
_logIfError(result);
|
||||||
emit(state.copyWith(wasRenameManually: true));
|
emit(state.copyWith(wasRenameManually: true));
|
||||||
},
|
},
|
||||||
@ -85,14 +86,14 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
|
|||||||
_logIfError(result);
|
_logIfError(result);
|
||||||
},
|
},
|
||||||
insertLeft: () async {
|
insertLeft: () async {
|
||||||
final result = await fieldService.createBefore();
|
final result = await _fieldService.createBefore();
|
||||||
result.fold(
|
result.fold(
|
||||||
(newField) => onFieldInserted?.call(newField.id),
|
(newField) => onFieldInserted?.call(newField.id),
|
||||||
(err) => Log.error("Failed creating field $err"),
|
(err) => Log.error("Failed creating field $err"),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
insertRight: () async {
|
insertRight: () async {
|
||||||
final result = await fieldService.createAfter();
|
final result = await _fieldService.createAfter();
|
||||||
result.fold(
|
result.fold(
|
||||||
(newField) => onFieldInserted?.call(newField.id),
|
(newField) => onFieldInserted?.call(newField.id),
|
||||||
(err) => Log.error("Failed creating field $err"),
|
(err) => Log.error("Failed creating field $err"),
|
||||||
@ -106,7 +107,7 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
|
|||||||
? FieldVisibility.AlwaysShown
|
? FieldVisibility.AlwaysShown
|
||||||
: FieldVisibility.AlwaysHidden;
|
: FieldVisibility.AlwaysHidden;
|
||||||
final result = await fieldSettingsService.updateFieldSettings(
|
final result = await fieldSettingsService.updateFieldSettings(
|
||||||
fieldId: state.field.id,
|
fieldId: fieldId,
|
||||||
fieldVisibility: newVisibility,
|
fieldVisibility: newVisibility,
|
||||||
);
|
);
|
||||||
_logIfError(result);
|
_logIfError(result);
|
||||||
|
|||||||
@ -82,6 +82,15 @@ class RowDetailBloc extends Bloc<RowDetailEvent, RowDetailState> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
startEditingField: (fieldId) {
|
||||||
|
emit(state.copyWith(editingFieldId: fieldId));
|
||||||
|
},
|
||||||
|
startEditingNewField: (fieldId) {
|
||||||
|
emit(state.copyWith(editingFieldId: fieldId, newFieldId: fieldId));
|
||||||
|
},
|
||||||
|
endEditingField: () {
|
||||||
|
emit(state.copyWith(editingFieldId: "", newFieldId: ""));
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -219,6 +228,16 @@ class RowDetailEvent with _$RowDetailEvent {
|
|||||||
/// Used to hide/show the hidden fields in the row detail page
|
/// Used to hide/show the hidden fields in the row detail page
|
||||||
const factory RowDetailEvent.toggleHiddenFieldVisibility() =
|
const factory RowDetailEvent.toggleHiddenFieldVisibility() =
|
||||||
_ToggleHiddenFieldVisibility;
|
_ToggleHiddenFieldVisibility;
|
||||||
|
|
||||||
|
/// Begin editing an event;
|
||||||
|
const factory RowDetailEvent.startEditingField(String fieldId) =
|
||||||
|
_StartEditingField;
|
||||||
|
|
||||||
|
const factory RowDetailEvent.startEditingNewField(String fieldId) =
|
||||||
|
_StartEditingNewField;
|
||||||
|
|
||||||
|
/// End editing an event
|
||||||
|
const factory RowDetailEvent.endEditingField() = _EndEditingField;
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
@ -228,6 +247,8 @@ class RowDetailState with _$RowDetailState {
|
|||||||
required List<CellContext> visibleCells,
|
required List<CellContext> visibleCells,
|
||||||
required bool showHiddenFields,
|
required bool showHiddenFields,
|
||||||
required int numHiddenFields,
|
required int numHiddenFields,
|
||||||
|
required String editingFieldId,
|
||||||
|
required String newFieldId,
|
||||||
}) = _RowDetailState;
|
}) = _RowDetailState;
|
||||||
|
|
||||||
factory RowDetailState.initial() => const RowDetailState(
|
factory RowDetailState.initial() => const RowDetailState(
|
||||||
@ -235,5 +256,7 @@ class RowDetailState with _$RowDetailState {
|
|||||||
visibleCells: [],
|
visibleCells: [],
|
||||||
showHiddenFields: false,
|
showHiddenFields: false,
|
||||||
numHiddenFields: 0,
|
numHiddenFields: 0,
|
||||||
|
editingFieldId: "",
|
||||||
|
newFieldId: "",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -86,7 +86,7 @@ class _GridFieldCellState extends State<GridFieldCell> {
|
|||||||
return FieldEditor(
|
return FieldEditor(
|
||||||
viewId: widget.viewId,
|
viewId: widget.viewId,
|
||||||
fieldController: widget.fieldController,
|
fieldController: widget.fieldController,
|
||||||
field: widget.fieldInfo.field,
|
fieldInfo: widget.fieldInfo,
|
||||||
isNewField: widget.isNew,
|
isNewField: widget.isNew,
|
||||||
initialPage: widget.isNew
|
initialPage: widget.isNew
|
||||||
? FieldEditorPage.details
|
? FieldEditorPage.details
|
||||||
|
|||||||
@ -174,7 +174,7 @@ class _CellTrailing extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CreateFieldButton extends StatefulWidget {
|
class CreateFieldButton extends StatelessWidget {
|
||||||
const CreateFieldButton({
|
const CreateFieldButton({
|
||||||
super.key,
|
super.key,
|
||||||
required this.viewId,
|
required this.viewId,
|
||||||
@ -184,11 +184,6 @@ class CreateFieldButton extends StatefulWidget {
|
|||||||
final String viewId;
|
final String viewId;
|
||||||
final void Function(String fieldId) onFieldCreated;
|
final void Function(String fieldId) onFieldCreated;
|
||||||
|
|
||||||
@override
|
|
||||||
State<CreateFieldButton> createState() => _CreateFieldButtonState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CreateFieldButtonState extends State<CreateFieldButton> {
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return FlowyButton(
|
return FlowyButton(
|
||||||
@ -202,10 +197,10 @@ class _CreateFieldButtonState extends State<CreateFieldButton> {
|
|||||||
hoverColor: AFThemeExtension.of(context).greyHover,
|
hoverColor: AFThemeExtension.of(context).greyHover,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final result = await FieldBackendService.createField(
|
final result = await FieldBackendService.createField(
|
||||||
viewId: widget.viewId,
|
viewId: viewId,
|
||||||
);
|
);
|
||||||
result.fold(
|
result.fold(
|
||||||
(field) => widget.onFieldCreated(field.id),
|
(field) => onFieldCreated(field.id),
|
||||||
(err) => Log.error("Failed to create field type option: $err"),
|
(err) => Log.error("Failed to create field type option: $err"),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -174,6 +174,8 @@ class _ChecklistItemState extends State<ChecklistItem> {
|
|||||||
meta: Platform.isMacOS,
|
meta: Platform.isMacOS,
|
||||||
control: !Platform.isMacOS,
|
control: !Platform.isMacOS,
|
||||||
): const _SelectTaskIntent(),
|
): const _SelectTaskIntent(),
|
||||||
|
const SingleActivator(LogicalKeyboardKey.enter):
|
||||||
|
const _EndEditingTaskIntent(),
|
||||||
const SingleActivator(LogicalKeyboardKey.escape):
|
const SingleActivator(LogicalKeyboardKey.escape):
|
||||||
const _EndEditingTaskIntent(),
|
const _EndEditingTaskIntent(),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -138,7 +138,7 @@ class _ChecklistItemState extends State<_ChecklistItem> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 5),
|
padding: const EdgeInsets.symmetric(horizontal: 5),
|
||||||
height: 44,
|
constraints: const BoxConstraints(minHeight: 44),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
InkWell(
|
InkWell(
|
||||||
@ -164,6 +164,8 @@ class _ChecklistItemState extends State<_ChecklistItem> {
|
|||||||
controller: _textController,
|
controller: _textController,
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
keyboardType: TextInputType.multiline,
|
||||||
|
maxLines: null,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
enabledBorder: InputBorder.none,
|
enabledBorder: InputBorder.none,
|
||||||
|
|||||||
@ -2,8 +2,15 @@ import 'package:appflowy/generated/locale_keys.g.dart';
|
|||||||
import 'package:appflowy/plugins/database/application/field/type_option/relation_type_option_cubit.dart';
|
import 'package:appflowy/plugins/database/application/field/type_option/relation_type_option_cubit.dart';
|
||||||
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
|
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
|
||||||
import 'package:appflowy/plugins/database/grid/presentation/widgets/common/type_option_separator.dart';
|
import 'package:appflowy/plugins/database/grid/presentation/widgets/common/type_option_separator.dart';
|
||||||
|
import 'package:appflowy/plugins/database/tab_bar/tab_bar_view.dart';
|
||||||
import 'package:appflowy/plugins/database/widgets/row/relation_row_detail.dart';
|
import 'package:appflowy/plugins/database/widgets/row/relation_row_detail.dart';
|
||||||
|
import 'package:appflowy/startup/startup.dart';
|
||||||
|
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
||||||
|
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
||||||
|
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||||
|
import 'package:appflowy_backend/log.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||||
|
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
|
||||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
@ -126,7 +133,7 @@ class _RelationCellEditorContentState
|
|||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
slivers: [
|
slivers: [
|
||||||
_CellEditorTitle(
|
_CellEditorTitle(
|
||||||
databaseName: widget.relatedDatabaseMeta.databaseName,
|
databaseMeta: widget.relatedDatabaseMeta,
|
||||||
),
|
),
|
||||||
_SearchField(
|
_SearchField(
|
||||||
focusNode: focusNode,
|
focusNode: focusNode,
|
||||||
@ -204,10 +211,10 @@ class _RelationCellEditorContentState
|
|||||||
|
|
||||||
class _CellEditorTitle extends StatelessWidget {
|
class _CellEditorTitle extends StatelessWidget {
|
||||||
const _CellEditorTitle({
|
const _CellEditorTitle({
|
||||||
required this.databaseName,
|
required this.databaseMeta,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String databaseName;
|
final DatabaseMeta databaseMeta;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -223,15 +230,20 @@ class _CellEditorTitle extends StatelessWidget {
|
|||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
color: Theme.of(context).hintColor,
|
color: Theme.of(context).hintColor,
|
||||||
),
|
),
|
||||||
Padding(
|
MouseRegion(
|
||||||
padding: const EdgeInsets.symmetric(
|
cursor: SystemMouseCursors.click,
|
||||||
horizontal: 4,
|
child: GestureDetector(
|
||||||
vertical: 2,
|
onTap: () => _openRelatedDatbase(context),
|
||||||
),
|
child: Padding(
|
||||||
child: FlowyText.regular(
|
padding:
|
||||||
databaseName,
|
const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
|
||||||
fontSize: 11,
|
child: FlowyText.regular(
|
||||||
overflow: TextOverflow.ellipsis,
|
databaseMeta.databaseName,
|
||||||
|
fontSize: 11,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
decoration: TextDecoration.underline,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -239,6 +251,28 @@ class _CellEditorTitle extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _openRelatedDatbase(BuildContext context) {
|
||||||
|
FolderEventGetView(ViewIdPB(value: databaseMeta.inlineViewId))
|
||||||
|
.send()
|
||||||
|
.then((result) {
|
||||||
|
result.fold(
|
||||||
|
(view) {
|
||||||
|
PopoverContainer.of(context).closeAll();
|
||||||
|
Navigator.of(context).maybePop();
|
||||||
|
getIt<TabsBloc>().add(
|
||||||
|
TabsEvent.openPlugin(
|
||||||
|
plugin: DatabaseTabBarViewPlugin(
|
||||||
|
view: view,
|
||||||
|
pluginType: view.pluginType,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
(err) => Log.error(err),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SearchField extends StatelessWidget {
|
class _SearchField extends StatelessWidget {
|
||||||
|
|||||||
@ -31,7 +31,7 @@ class FieldEditor extends StatefulWidget {
|
|||||||
const FieldEditor({
|
const FieldEditor({
|
||||||
super.key,
|
super.key,
|
||||||
required this.viewId,
|
required this.viewId,
|
||||||
required this.field,
|
required this.fieldInfo,
|
||||||
required this.fieldController,
|
required this.fieldController,
|
||||||
required this.isNewField,
|
required this.isNewField,
|
||||||
this.initialPage = FieldEditorPage.details,
|
this.initialPage = FieldEditorPage.details,
|
||||||
@ -39,7 +39,7 @@ class FieldEditor extends StatefulWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
final String viewId;
|
final String viewId;
|
||||||
final FieldPB field;
|
final FieldInfo fieldInfo;
|
||||||
final FieldController fieldController;
|
final FieldController fieldController;
|
||||||
final FieldEditorPage initialPage;
|
final FieldEditorPage initialPage;
|
||||||
final void Function(String fieldId)? onFieldInserted;
|
final void Function(String fieldId)? onFieldInserted;
|
||||||
@ -51,13 +51,13 @@ class FieldEditor extends StatefulWidget {
|
|||||||
|
|
||||||
class _FieldEditorState extends State<FieldEditor> {
|
class _FieldEditorState extends State<FieldEditor> {
|
||||||
late FieldEditorPage _currentPage;
|
late FieldEditorPage _currentPage;
|
||||||
late final TextEditingController textController;
|
late final TextEditingController textController =
|
||||||
|
TextEditingController(text: widget.fieldInfo.name);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_currentPage = widget.initialPage;
|
_currentPage = widget.initialPage;
|
||||||
textController = TextEditingController(text: widget.field.name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -71,14 +71,14 @@ class _FieldEditorState extends State<FieldEditor> {
|
|||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (_) => FieldEditorBloc(
|
create: (_) => FieldEditorBloc(
|
||||||
viewId: widget.viewId,
|
viewId: widget.viewId,
|
||||||
field: widget.field,
|
fieldInfo: widget.fieldInfo,
|
||||||
fieldController: widget.fieldController,
|
fieldController: widget.fieldController,
|
||||||
onFieldInserted: widget.onFieldInserted,
|
onFieldInserted: widget.onFieldInserted,
|
||||||
isNew: widget.isNewField,
|
isNew: widget.isNewField,
|
||||||
),
|
),
|
||||||
child: _currentPage == FieldEditorPage.details
|
child: _currentPage == FieldEditorPage.general
|
||||||
? _fieldDetails()
|
? _fieldGeneral()
|
||||||
: _fieldGeneral(),
|
: _fieldDetails(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,6 +120,21 @@ class _FieldEditorState extends State<FieldEditor> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _actionCell(FieldAction action) {
|
||||||
|
return BlocBuilder<FieldEditorBloc, FieldEditorState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
|
child: FieldActionCell(
|
||||||
|
viewId: widget.viewId,
|
||||||
|
fieldInfo: state.field,
|
||||||
|
action: action,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget _fieldDetails() {
|
Widget _fieldDetails() {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: 260,
|
width: 260,
|
||||||
@ -129,19 +144,6 @@ class _FieldEditorState extends State<FieldEditor> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _actionCell(FieldAction action) {
|
|
||||||
return BlocBuilder<FieldEditorBloc, FieldEditorState>(
|
|
||||||
builder: (context, state) => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
|
||||||
child: FieldActionCell(
|
|
||||||
viewId: widget.viewId,
|
|
||||||
fieldInfo: state.field,
|
|
||||||
action: action,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _EditFieldButton extends StatelessWidget {
|
class _EditFieldButton extends StatelessWidget {
|
||||||
@ -322,32 +324,33 @@ enum FieldAction {
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case FieldAction.clearData:
|
case FieldAction.clearData:
|
||||||
NavigatorAlertDialog(
|
PopoverContainer.of(context).closeAll();
|
||||||
constraints: const BoxConstraints(
|
showCancelAndConfirmDialog(
|
||||||
maxWidth: 250,
|
context: context,
|
||||||
maxHeight: 260,
|
title: LocaleKeys.grid_field_label.tr(),
|
||||||
),
|
description: LocaleKeys.grid_field_clearFieldPromptMessage.tr(),
|
||||||
title: LocaleKeys.grid_field_clearFieldPromptMessage.tr(),
|
confirmLabel: LocaleKeys.button_confirm.tr(),
|
||||||
confirm: () {
|
onConfirm: () {
|
||||||
FieldBackendService.clearField(
|
FieldBackendService.clearField(
|
||||||
viewId: viewId,
|
viewId: viewId,
|
||||||
fieldId: fieldInfo.id,
|
fieldId: fieldInfo.id,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
).show(context);
|
);
|
||||||
PopoverContainer.of(context).close();
|
|
||||||
break;
|
break;
|
||||||
case FieldAction.delete:
|
case FieldAction.delete:
|
||||||
NavigatorAlertDialog(
|
PopoverContainer.of(context).closeAll();
|
||||||
title: LocaleKeys.grid_field_deleteFieldPromptMessage.tr(),
|
showConfirmDeletionDialog(
|
||||||
confirm: () {
|
context: context,
|
||||||
|
name: LocaleKeys.grid_field_label.tr(),
|
||||||
|
description: LocaleKeys.grid_field_deleteFieldPromptMessage.tr(),
|
||||||
|
onConfirm: () {
|
||||||
FieldBackendService.deleteField(
|
FieldBackendService.deleteField(
|
||||||
viewId: viewId,
|
viewId: viewId,
|
||||||
fieldId: fieldInfo.id,
|
fieldId: fieldInfo.id,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
).show(context);
|
);
|
||||||
PopoverContainer.of(context).close();
|
|
||||||
break;
|
break;
|
||||||
case FieldAction.wrap:
|
case FieldAction.wrap:
|
||||||
context
|
context
|
||||||
@ -574,7 +577,10 @@ class _FieldNameTextFieldState extends State<FieldNameTextField> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SwitchFieldButton extends StatefulWidget {
|
class SwitchFieldButton extends StatefulWidget {
|
||||||
const SwitchFieldButton({super.key, required this.popoverMutex});
|
const SwitchFieldButton({
|
||||||
|
super.key,
|
||||||
|
required this.popoverMutex,
|
||||||
|
});
|
||||||
|
|
||||||
final PopoverMutex popoverMutex;
|
final PopoverMutex popoverMutex;
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,6 @@ import 'package:appflowy/plugins/database/grid/presentation/widgets/header/deskt
|
|||||||
import 'package:appflowy/plugins/database/widgets/field/field_editor.dart';
|
import 'package:appflowy/plugins/database/widgets/field/field_editor.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/block_action_button.dart';
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/block_action_button.dart';
|
||||||
import 'package:appflowy_backend/log.dart';
|
import 'package:appflowy_backend/log.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
|
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
|
||||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
@ -130,50 +129,11 @@ class _PropertyCell extends StatefulWidget {
|
|||||||
|
|
||||||
class _PropertyCellState extends State<_PropertyCell> {
|
class _PropertyCellState extends State<_PropertyCell> {
|
||||||
final PopoverController _popoverController = PopoverController();
|
final PopoverController _popoverController = PopoverController();
|
||||||
final PopoverController _fieldPopoverController = PopoverController();
|
|
||||||
|
|
||||||
final ValueNotifier<bool> _isFieldHover = ValueNotifier(false);
|
final ValueNotifier<bool> _isFieldHover = ValueNotifier(false);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final dragThumb = MouseRegion(
|
|
||||||
cursor: Platform.isWindows
|
|
||||||
? SystemMouseCursors.click
|
|
||||||
: SystemMouseCursors.grab,
|
|
||||||
child: SizedBox(
|
|
||||||
width: 16,
|
|
||||||
height: 30,
|
|
||||||
child: AppFlowyPopover(
|
|
||||||
controller: _fieldPopoverController,
|
|
||||||
constraints: BoxConstraints.loose(const Size(240, 600)),
|
|
||||||
margin: EdgeInsets.zero,
|
|
||||||
triggerActions: PopoverTriggerFlags.none,
|
|
||||||
direction: PopoverDirection.bottomWithLeftAligned,
|
|
||||||
popupBuilder: (popoverContext) => FieldEditor(
|
|
||||||
viewId: widget.fieldController.viewId,
|
|
||||||
field: widget.fieldController
|
|
||||||
.getField(widget.cellContext.fieldId)!
|
|
||||||
.field,
|
|
||||||
fieldController: widget.fieldController,
|
|
||||||
isNewField: false,
|
|
||||||
),
|
|
||||||
child: ValueListenableBuilder(
|
|
||||||
valueListenable: _isFieldHover,
|
|
||||||
builder: (_, isHovering, child) =>
|
|
||||||
isHovering ? child! : const SizedBox.shrink(),
|
|
||||||
child: BlockActionButton(
|
|
||||||
onTap: () => _fieldPopoverController.show(),
|
|
||||||
svg: FlowySvgs.drag_element_s,
|
|
||||||
richMessage: TextSpan(
|
|
||||||
text: LocaleKeys.grid_rowPage_fieldDragElementTooltip.tr(),
|
|
||||||
style: context.tooltipTextStyle(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
final cell = widget.cellBuilder.buildStyled(
|
final cell = widget.cellBuilder.buildStyled(
|
||||||
widget.cellContext,
|
widget.cellContext,
|
||||||
EditableCellStyle.desktopRowDetail,
|
EditableCellStyle.desktopRowDetail,
|
||||||
@ -210,53 +170,12 @@ class _PropertyCellState extends State<_PropertyCell> {
|
|||||||
return ReorderableDragStartListener(
|
return ReorderableDragStartListener(
|
||||||
index: widget.index,
|
index: widget.index,
|
||||||
enabled: value,
|
enabled: value,
|
||||||
child: dragThumb,
|
child: _buildDragHandle(context),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const HSpace(4),
|
const HSpace(4),
|
||||||
BlocSelector<RowDetailBloc, RowDetailState, FieldInfo?>(
|
_buildFieldButton(context),
|
||||||
selector: (state) => state.fields.firstWhereOrNull(
|
|
||||||
(fieldInfo) => fieldInfo.field.id == widget.cellContext.fieldId,
|
|
||||||
),
|
|
||||||
builder: (context, fieldInfo) {
|
|
||||||
if (fieldInfo == null) {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
return AppFlowyPopover(
|
|
||||||
controller: _popoverController,
|
|
||||||
constraints: BoxConstraints.loose(const Size(240, 600)),
|
|
||||||
margin: EdgeInsets.zero,
|
|
||||||
triggerActions: PopoverTriggerFlags.none,
|
|
||||||
direction: PopoverDirection.bottomWithLeftAligned,
|
|
||||||
popupBuilder: (popoverContext) => FieldEditor(
|
|
||||||
viewId: widget.fieldController.viewId,
|
|
||||||
field: fieldInfo.field,
|
|
||||||
fieldController: widget.fieldController,
|
|
||||||
isNewField: false,
|
|
||||||
),
|
|
||||||
child: SizedBox(
|
|
||||||
width: 160,
|
|
||||||
height: 30,
|
|
||||||
child: Tooltip(
|
|
||||||
waitDuration: const Duration(seconds: 1),
|
|
||||||
preferBelow: false,
|
|
||||||
verticalOffset: 15,
|
|
||||||
message: fieldInfo.name,
|
|
||||||
child: FieldCellButton(
|
|
||||||
field: fieldInfo.field,
|
|
||||||
onTap: () => _popoverController.show(),
|
|
||||||
radius: BorderRadius.circular(6),
|
|
||||||
margin: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 4,
|
|
||||||
vertical: 6,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const HSpace(8),
|
const HSpace(8),
|
||||||
Expanded(child: gesture),
|
Expanded(child: gesture),
|
||||||
],
|
],
|
||||||
@ -264,6 +183,96 @@ class _PropertyCellState extends State<_PropertyCell> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildDragHandle(BuildContext context) {
|
||||||
|
return MouseRegion(
|
||||||
|
cursor: Platform.isWindows
|
||||||
|
? SystemMouseCursors.click
|
||||||
|
: SystemMouseCursors.grab,
|
||||||
|
child: SizedBox(
|
||||||
|
width: 16,
|
||||||
|
height: 30,
|
||||||
|
child: BlocListener<RowDetailBloc, RowDetailState>(
|
||||||
|
listenWhen: (previous, current) =>
|
||||||
|
previous.editingFieldId != current.editingFieldId,
|
||||||
|
listener: (context, state) {
|
||||||
|
if (state.editingFieldId == widget.cellContext.fieldId) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
_popoverController.show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: ValueListenableBuilder(
|
||||||
|
valueListenable: _isFieldHover,
|
||||||
|
builder: (_, isHovering, child) =>
|
||||||
|
isHovering ? child! : const SizedBox.shrink(),
|
||||||
|
child: BlockActionButton(
|
||||||
|
onTap: () => context.read<RowDetailBloc>().add(
|
||||||
|
RowDetailEvent.startEditingField(
|
||||||
|
widget.cellContext.fieldId,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
svg: FlowySvgs.drag_element_s,
|
||||||
|
richMessage: TextSpan(
|
||||||
|
text: LocaleKeys.grid_rowPage_fieldDragElementTooltip.tr(),
|
||||||
|
style: context.tooltipTextStyle(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildFieldButton(BuildContext context) {
|
||||||
|
return BlocSelector<RowDetailBloc, RowDetailState, FieldInfo?>(
|
||||||
|
selector: (state) => state.fields.firstWhereOrNull(
|
||||||
|
(fieldInfo) => fieldInfo.field.id == widget.cellContext.fieldId,
|
||||||
|
),
|
||||||
|
builder: (context, fieldInfo) {
|
||||||
|
if (fieldInfo == null) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
return AppFlowyPopover(
|
||||||
|
controller: _popoverController,
|
||||||
|
constraints: BoxConstraints.loose(const Size(240, 600)),
|
||||||
|
margin: EdgeInsets.zero,
|
||||||
|
triggerActions: PopoverTriggerFlags.none,
|
||||||
|
direction: PopoverDirection.bottomWithLeftAligned,
|
||||||
|
onClose: () => context
|
||||||
|
.read<RowDetailBloc>()
|
||||||
|
.add(const RowDetailEvent.endEditingField()),
|
||||||
|
popupBuilder: (popoverContext) => FieldEditor(
|
||||||
|
viewId: widget.fieldController.viewId,
|
||||||
|
fieldInfo: fieldInfo,
|
||||||
|
fieldController: widget.fieldController,
|
||||||
|
isNewField: context.watch<RowDetailBloc>().state.newFieldId ==
|
||||||
|
widget.cellContext.fieldId,
|
||||||
|
),
|
||||||
|
child: SizedBox(
|
||||||
|
width: 160,
|
||||||
|
height: 30,
|
||||||
|
child: Tooltip(
|
||||||
|
waitDuration: const Duration(seconds: 1),
|
||||||
|
preferBelow: false,
|
||||||
|
verticalOffset: 15,
|
||||||
|
message: fieldInfo.name,
|
||||||
|
child: FieldCellButton(
|
||||||
|
field: fieldInfo.field,
|
||||||
|
onTap: () => context.read<RowDetailBloc>().add(
|
||||||
|
RowDetailEvent.startEditingField(
|
||||||
|
widget.cellContext.fieldId,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
radius: BorderRadius.circular(6),
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 4, vertical: 6),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ToggleHiddenFieldsVisibilityButton extends StatelessWidget {
|
class ToggleHiddenFieldsVisibilityButton extends StatelessWidget {
|
||||||
@ -357,7 +366,7 @@ class ToggleHiddenFieldsVisibilityButton extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CreateRowFieldButton extends StatefulWidget {
|
class CreateRowFieldButton extends StatelessWidget {
|
||||||
const CreateRowFieldButton({
|
const CreateRowFieldButton({
|
||||||
super.key,
|
super.key,
|
||||||
required this.viewId,
|
required this.viewId,
|
||||||
@ -367,61 +376,35 @@ class CreateRowFieldButton extends StatefulWidget {
|
|||||||
final String viewId;
|
final String viewId;
|
||||||
final FieldController fieldController;
|
final FieldController fieldController;
|
||||||
|
|
||||||
@override
|
|
||||||
State<CreateRowFieldButton> createState() => _CreateRowFieldButtonState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CreateRowFieldButtonState extends State<CreateRowFieldButton> {
|
|
||||||
final PopoverController popoverController = PopoverController();
|
|
||||||
FieldPB? createdField;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppFlowyPopover(
|
return SizedBox(
|
||||||
constraints: BoxConstraints.loose(const Size(240, 200)),
|
height: 30,
|
||||||
controller: popoverController,
|
child: FlowyButton(
|
||||||
direction: PopoverDirection.topWithLeftAligned,
|
margin: const EdgeInsets.symmetric(horizontal: 4, vertical: 6),
|
||||||
triggerActions: PopoverTriggerFlags.none,
|
text: FlowyText.medium(
|
||||||
margin: EdgeInsets.zero,
|
lineHeight: 1.0,
|
||||||
child: SizedBox(
|
LocaleKeys.grid_field_newProperty.tr(),
|
||||||
height: 30,
|
color: Theme.of(context).hintColor,
|
||||||
child: FlowyButton(
|
),
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 4, vertical: 6),
|
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
||||||
text: FlowyText.medium(
|
onTap: () async {
|
||||||
lineHeight: 1.0,
|
final result = await FieldBackendService.createField(
|
||||||
LocaleKeys.grid_field_newProperty.tr(),
|
viewId: viewId,
|
||||||
color: Theme.of(context).hintColor,
|
);
|
||||||
),
|
await Future.delayed(const Duration(milliseconds: 50));
|
||||||
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
result.fold(
|
||||||
onTap: () async {
|
(field) => context
|
||||||
final result = await FieldBackendService.createField(
|
.read<RowDetailBloc>()
|
||||||
viewId: widget.viewId,
|
.add(RowDetailEvent.startEditingNewField(field.id)),
|
||||||
);
|
(err) => Log.error("Failed to create field type option: $err"),
|
||||||
result.fold(
|
);
|
||||||
(newField) {
|
},
|
||||||
createdField = newField;
|
leftIcon: FlowySvg(
|
||||||
popoverController.show();
|
FlowySvgs.add_m,
|
||||||
},
|
color: Theme.of(context).hintColor,
|
||||||
(r) => Log.error("Failed to create field type option: $r"),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
leftIcon: FlowySvg(
|
|
||||||
FlowySvgs.add_m,
|
|
||||||
color: Theme.of(context).hintColor,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
popupBuilder: (BuildContext popoverContext) {
|
|
||||||
if (createdField == null) {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
return FieldEditor(
|
|
||||||
viewId: widget.viewId,
|
|
||||||
field: createdField!,
|
|
||||||
fieldController: widget.fieldController,
|
|
||||||
isNewField: true,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -204,7 +204,7 @@ class _DatabasePropertyCellState extends State<DatabasePropertyCell> {
|
|||||||
popupBuilder: (BuildContext context) {
|
popupBuilder: (BuildContext context) {
|
||||||
return FieldEditor(
|
return FieldEditor(
|
||||||
viewId: widget.viewId,
|
viewId: widget.viewId,
|
||||||
field: widget.fieldInfo.field,
|
fieldInfo: widget.fieldInfo,
|
||||||
fieldController: widget.fieldController,
|
fieldController: widget.fieldController,
|
||||||
isNewField: false,
|
isNewField: false,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -133,10 +133,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: bidi
|
name: bidi
|
||||||
sha256: "1a7d0c696324b2089f72e7671fd1f1f64fef44c980f3cebc84e803967c597b63"
|
sha256: "9a712c7ddf708f7c41b1923aa83648a3ed44cfd75b04f72d598c45e5be287f9d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.10"
|
version: "2.0.12"
|
||||||
bitsdojo_window:
|
bitsdojo_window:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|||||||
@ -34,7 +34,7 @@ void main() {
|
|||||||
|
|
||||||
final editorBloc = FieldEditorBloc(
|
final editorBloc = FieldEditorBloc(
|
||||||
viewId: context.gridView.id,
|
viewId: context.gridView.id,
|
||||||
field: fieldInfo.field,
|
fieldInfo: fieldInfo,
|
||||||
fieldController: context.fieldController,
|
fieldController: context.fieldController,
|
||||||
isNew: false,
|
isNew: false,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -78,15 +78,13 @@ class BoardTestContext {
|
|||||||
|
|
||||||
FieldEditorBloc makeFieldEditor({
|
FieldEditorBloc makeFieldEditor({
|
||||||
required FieldInfo fieldInfo,
|
required FieldInfo fieldInfo,
|
||||||
}) {
|
}) =>
|
||||||
final editorBloc = FieldEditorBloc(
|
FieldEditorBloc(
|
||||||
viewId: databaseController.viewId,
|
viewId: databaseController.viewId,
|
||||||
fieldController: fieldController,
|
fieldController: fieldController,
|
||||||
field: fieldInfo.field,
|
fieldInfo: fieldInfo,
|
||||||
isNew: false,
|
isNew: false,
|
||||||
);
|
);
|
||||||
return editorBloc;
|
|
||||||
}
|
|
||||||
|
|
||||||
CellController makeCellControllerFromFieldId(String fieldId) {
|
CellController makeCellControllerFromFieldId(String fieldId) {
|
||||||
return makeCellController(
|
return makeCellController(
|
||||||
|
|||||||
@ -10,7 +10,7 @@ Future<FieldEditorBloc> createEditorBloc(AppFlowyGridTest gridTest) async {
|
|||||||
return FieldEditorBloc(
|
return FieldEditorBloc(
|
||||||
viewId: context.gridView.id,
|
viewId: context.gridView.id,
|
||||||
fieldController: context.fieldController,
|
fieldController: context.fieldController,
|
||||||
field: fieldInfo.field,
|
fieldInfo: fieldInfo,
|
||||||
isNew: false,
|
isNew: false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -102,7 +102,7 @@ Future<FieldEditorBloc> createFieldEditor({
|
|||||||
return FieldEditorBloc(
|
return FieldEditorBloc(
|
||||||
viewId: databaseController.viewId,
|
viewId: databaseController.viewId,
|
||||||
fieldController: databaseController.fieldController,
|
fieldController: databaseController.fieldController,
|
||||||
field: field,
|
fieldInfo: databaseController.fieldController.getField(field.id)!,
|
||||||
isNew: true,
|
isNew: true,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1298,6 +1298,7 @@
|
|||||||
"isNotEmpty": "Is not empty"
|
"isNotEmpty": "Is not empty"
|
||||||
},
|
},
|
||||||
"field": {
|
"field": {
|
||||||
|
"label": "Property",
|
||||||
"hide": "Hide",
|
"hide": "Hide",
|
||||||
"show": "Show",
|
"show": "Show",
|
||||||
"insertLeft": "Insert Left",
|
"insertLeft": "Insert Left",
|
||||||
@ -1351,7 +1352,7 @@
|
|||||||
"editProperty": "Edit property",
|
"editProperty": "Edit property",
|
||||||
"newProperty": "New property",
|
"newProperty": "New property",
|
||||||
"openRowDocument": "Open as a page",
|
"openRowDocument": "Open as a page",
|
||||||
"deleteFieldPromptMessage": "Are you sure? This property will be deleted",
|
"deleteFieldPromptMessage": "Are you sure? This property and all its data will be deleted",
|
||||||
"clearFieldPromptMessage": "Are you sure? All cells in this column will be emptied",
|
"clearFieldPromptMessage": "Are you sure? All cells in this column will be emptied",
|
||||||
"newColumn": "New Column",
|
"newColumn": "New Column",
|
||||||
"format": "Format",
|
"format": "Format",
|
||||||
|
|||||||
@ -110,7 +110,7 @@ fi
|
|||||||
if [ "$verbose" = true ]; then
|
if [ "$verbose" = true ]; then
|
||||||
dart run build_runner build -d &
|
dart run build_runner build -d &
|
||||||
else
|
else
|
||||||
dart run build_runner build >/dev/null 2>&1 &
|
dart run build_runner build -d >/dev/null 2>&1 &
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get the PID of the background process
|
# Get the PID of the background process
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user