mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: enable relation to (#4866)
* chore: enable relation to * chore: fix database name and improve UI * chore: remove database view id from relation type option * chore: add remove row id test * chore: improve appearance of untitled rows * chore: empty in row detail * fix: cannot add events after closing --------- Co-authored-by: Richard Shiue <71320345+richardshiue@users.noreply.github.com>
This commit is contained in:
@ -1,8 +1,9 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/database/application/cell/cell_controller.dart';
|
||||
import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
|
||||
import 'package:appflowy/plugins/database/application/database_controller.dart';
|
||||
import 'package:appflowy/plugins/database/application/cell/bloc/relation_cell_bloc.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
@ -52,15 +53,19 @@ class _RelationCellState extends State<RelationCardCell> {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
final children = state.rows
|
||||
.map(
|
||||
(row) => FlowyText.medium(
|
||||
row.name,
|
||||
final children = state.rows.map(
|
||||
(row) {
|
||||
final isEmpty = row.name.isEmpty;
|
||||
return Text(
|
||||
isEmpty ? LocaleKeys.grid_row_titlePlaceholder.tr() : row.name,
|
||||
style: widget.style.textStyle.copyWith(
|
||||
color: isEmpty ? Theme.of(context).hintColor : null,
|
||||
decoration: TextDecoration.underline,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
overflow: TextOverflow.ellipsis,
|
||||
);
|
||||
},
|
||||
).toList();
|
||||
|
||||
return Container(
|
||||
alignment: AlignmentDirectional.topStart,
|
||||
|
@ -1,10 +1,12 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
|
||||
import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart';
|
||||
import 'package:appflowy/plugins/database/widgets/cell_editor/relation_cell_editor.dart';
|
||||
import 'package:appflowy/plugins/database/application/cell/bloc/relation_cell_bloc.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../editable_cell_skeleton/relation.dart';
|
||||
@ -29,10 +31,6 @@ class DesktopGridRelationCellSkin extends IEditableRelationCellSkin {
|
||||
value: bloc,
|
||||
child: RelationCellEditor(
|
||||
selectedRowIds: state.rows.map((row) => row.rowId).toList(),
|
||||
databaseId: state.relatedDatabaseId,
|
||||
onSelectRow: (rowId) {
|
||||
bloc.add(RelationCellEvent.selectRow(rowId));
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
@ -42,15 +40,17 @@ class DesktopGridRelationCellSkin extends IEditableRelationCellSkin {
|
||||
child: Wrap(
|
||||
runSpacing: 4.0,
|
||||
spacing: 4.0,
|
||||
children: state.rows
|
||||
.map(
|
||||
(row) => FlowyText.medium(
|
||||
row.name,
|
||||
decoration: TextDecoration.underline,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
children: state.rows.map(
|
||||
(row) {
|
||||
final isEmpty = row.name.isEmpty;
|
||||
return FlowyText.medium(
|
||||
isEmpty ? LocaleKeys.grid_row_titlePlaceholder.tr() : row.name,
|
||||
color: isEmpty ? Theme.of(context).hintColor : null,
|
||||
decoration: TextDecoration.underline,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
);
|
||||
},
|
||||
).toList(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -1,9 +1,12 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart';
|
||||
import 'package:appflowy/plugins/database/widgets/cell_editor/relation_cell_editor.dart';
|
||||
import 'package:appflowy/plugins/database/application/cell/bloc/relation_cell_bloc.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../editable_cell_skeleton/relation.dart';
|
||||
@ -26,36 +29,43 @@ class DesktopRowDetailRelationCellSkin extends IEditableRelationCellSkin {
|
||||
popupBuilder: (context) {
|
||||
return BlocProvider.value(
|
||||
value: bloc,
|
||||
child: BlocBuilder<RelationCellBloc, RelationCellState>(
|
||||
builder: (context, state) => RelationCellEditor(
|
||||
selectedRowIds: state.rows.map((row) => row.rowId).toList(),
|
||||
databaseId: state.relatedDatabaseId,
|
||||
onSelectRow: (rowId) {
|
||||
context
|
||||
.read<RelationCellBloc>()
|
||||
.add(RelationCellEvent.selectRow(rowId));
|
||||
},
|
||||
),
|
||||
child: RelationCellEditor(
|
||||
selectedRowIds: state.rows.map((row) => row.rowId).toList(),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
child: Wrap(
|
||||
runSpacing: 4.0,
|
||||
spacing: 4.0,
|
||||
children: state.rows
|
||||
.map(
|
||||
(row) => FlowyText.medium(
|
||||
row.name,
|
||||
decoration: TextDecoration.underline,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
child: state.rows.isEmpty
|
||||
? _buildPlaceholder(context)
|
||||
: _buildRows(context, state.rows),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPlaceholder(BuildContext context) {
|
||||
return FlowyText(
|
||||
LocaleKeys.grid_row_textPlaceholder.tr(),
|
||||
color: Theme.of(context).hintColor,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRows(BuildContext context, List<RelatedRowDataPB> rows) {
|
||||
return Wrap(
|
||||
runSpacing: 4.0,
|
||||
spacing: 4.0,
|
||||
children: rows.map(
|
||||
(row) {
|
||||
final isEmpty = row.name.isEmpty;
|
||||
return FlowyText.medium(
|
||||
isEmpty ? LocaleKeys.grid_row_titlePlaceholder.tr() : row.name,
|
||||
color: isEmpty ? Theme.of(context).hintColor : null,
|
||||
decoration: TextDecoration.underline,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
);
|
||||
},
|
||||
).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
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/grid/presentation/layout/sizes.dart';
|
||||
import 'package:appflowy/plugins/database/grid/presentation/widgets/common/type_option_separator.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
@ -13,38 +14,24 @@ import '../../application/cell/bloc/relation_row_search_bloc.dart';
|
||||
class RelationCellEditor extends StatelessWidget {
|
||||
const RelationCellEditor({
|
||||
super.key,
|
||||
required this.databaseId,
|
||||
required this.selectedRowIds,
|
||||
required this.onSelectRow,
|
||||
});
|
||||
|
||||
final String databaseId;
|
||||
final List<String> selectedRowIds;
|
||||
final void Function(String rowId) onSelectRow;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (databaseId.isEmpty) {
|
||||
// no i18n here because UX needs thorough checking.
|
||||
return const Center(
|
||||
child: FlowyText(
|
||||
'''
|
||||
No database has been selected,
|
||||
please select one first in the field editor.
|
||||
''',
|
||||
maxLines: null,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
return BlocBuilder<RelationCellBloc, RelationCellState>(
|
||||
builder: (context, cellState) {
|
||||
if (cellState.relatedDatabaseMeta == null) {
|
||||
return const _RelationCellEditorDatabaseList();
|
||||
}
|
||||
|
||||
return BlocProvider<RelationRowSearchBloc>(
|
||||
create: (context) => RelationRowSearchBloc(
|
||||
databaseId: databaseId,
|
||||
),
|
||||
child: BlocBuilder<RelationCellBloc, RelationCellState>(
|
||||
builder: (context, cellState) {
|
||||
return BlocBuilder<RelationRowSearchBloc, RelationRowSearchState>(
|
||||
return BlocProvider<RelationRowSearchBloc>(
|
||||
create: (context) => RelationRowSearchBloc(
|
||||
databaseId: cellState.relatedDatabaseMeta!.databaseId,
|
||||
),
|
||||
child: BlocBuilder<RelationRowSearchBloc, RelationRowSearchState>(
|
||||
builder: (context, state) {
|
||||
final children = state.filteredRows
|
||||
.map(
|
||||
@ -68,7 +55,9 @@ please select one first in the field editor.
|
||||
color: Theme.of(context).primaryColor,
|
||||
)
|
||||
: null,
|
||||
onTap: () => onSelectRow(row.rowId),
|
||||
onTap: () => context
|
||||
.read<RelationCellBloc>()
|
||||
.add(RelationCellEvent.selectRow(row.rowId)),
|
||||
),
|
||||
),
|
||||
)
|
||||
@ -78,7 +67,6 @@ please select one first in the field editor.
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const VSpace(6.0),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6.0) +
|
||||
GridSize.typeOptionContentInsets,
|
||||
@ -90,15 +78,13 @@ please select one first in the field editor.
|
||||
fontSize: 11,
|
||||
color: Theme.of(context).hintColor,
|
||||
),
|
||||
const HSpace(2.0),
|
||||
FlowyButton(
|
||||
useIntrinsicWidth: true,
|
||||
margin: const EdgeInsets.symmetric(
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 4,
|
||||
vertical: 2,
|
||||
),
|
||||
text: FlowyText.regular(
|
||||
cellState.relatedDatabaseId,
|
||||
child: FlowyText.regular(
|
||||
cellState.relatedDatabaseMeta!.databaseName,
|
||||
fontSize: 11,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
@ -106,10 +92,16 @@ please select one first in the field editor.
|
||||
],
|
||||
),
|
||||
),
|
||||
VSpace(GridSize.typeOptionSeparatorHeight),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6.0),
|
||||
child: FlowyTextField(
|
||||
hintText: LocaleKeys
|
||||
.grid_relation_rowSearchTextFieldPlaceholder
|
||||
.tr(),
|
||||
hintStyle: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall
|
||||
?.copyWith(color: Theme.of(context).hintColor),
|
||||
onChanged: (text) => context
|
||||
.read<RelationRowSearchBloc>()
|
||||
.add(RelationRowSearchEvent.updateFilter(text)),
|
||||
@ -140,6 +132,62 @@ please select one first in the field editor.
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _RelationCellEditorDatabaseList extends StatelessWidget {
|
||||
const _RelationCellEditorDatabaseList();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (_) => RelationDatabaseListCubit(),
|
||||
child: BlocBuilder<RelationDatabaseListCubit, RelationDatabaseListState>(
|
||||
builder: (context, state) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(6, 6, 6, 0),
|
||||
child: FlowyText(
|
||||
LocaleKeys.grid_relation_noDatabaseSelected.tr(),
|
||||
maxLines: null,
|
||||
fontSize: 10,
|
||||
color: Theme.of(context).hintColor,
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: ListView.separated(
|
||||
padding: const EdgeInsets.all(6),
|
||||
separatorBuilder: (context, index) =>
|
||||
VSpace(GridSize.typeOptionSeparatorHeight),
|
||||
itemCount: state.databaseMetas.length,
|
||||
shrinkWrap: true,
|
||||
itemBuilder: (context, index) {
|
||||
final databaseMeta = state.databaseMetas[index];
|
||||
return SizedBox(
|
||||
height: GridSize.popoverItemHeight,
|
||||
child: FlowyButton(
|
||||
onTap: () => context.read<RelationCellBloc>().add(
|
||||
RelationCellEvent.selectDatabaseId(
|
||||
databaseMeta.databaseId,
|
||||
),
|
||||
),
|
||||
text: FlowyText.medium(
|
||||
databaseMeta.databaseName,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
|
Reference in New Issue
Block a user