feat(editor): add grouping support for member property of the database block (#12243)

close: BS-3433

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Introduced advanced group-by configurations for database blocks with user membership support.
  - Added a React hook for fetching and displaying user information in member-related components.
  - Enabled dynamic user and membership data types in database properties.

- **Improvements**
  - Replaced context-based service access with a dependency injection system for shared services and state.
  - Enhanced type safety and consistency across group-by UI components and data handling.
  - Centralized group data management with a new Group class and refined group trait logic.

- **Bug Fixes**
  - Improved reliability and consistency in retrieving and rendering user and group information.

- **Style**
  - Removed obsolete member selection styles for cleaner UI code.

- **Chores**
  - Registered external group-by configurations via dependency injection.
  - Refactored internal APIs for data sources, views, and group-by matchers to use service-based patterns.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
zzj3720
2025-05-13 13:53:37 +00:00
parent fe2fc892df
commit a2a90df276
59 changed files with 702 additions and 374 deletions
@@ -13,7 +13,7 @@ import { repeat } from 'lit/directives/repeat.js';
import type { DataViewRenderer } from '../../../core/data-view.js';
import { GroupTitle } from '../../../core/group-by/group-title.js';
import type { GroupData } from '../../../core/group-by/trait.js';
import type { Group } from '../../../core/group-by/trait.js';
import type { Row } from '../../../core/index.js';
import { LEFT_TOOL_BAR_WIDTH } from '../consts.js';
import type { DataViewTable } from '../pc/table-view.js';
@@ -185,7 +185,7 @@ export class MobileTableGroup extends SignalWatcher(
accessor dataViewEle!: DataViewRenderer;
@property({ attribute: false })
accessor group: GroupData | undefined = undefined;
accessor group: Group | undefined = undefined;
@query('.affine-database-block-rows')
accessor rowsContainer: HTMLElement | null = null;
@@ -4,7 +4,7 @@ import { css, html } from 'lit';
import { property } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
import type { GroupData } from '../../../../../../core/group-by/trait';
import type { Group } from '../../../../../../core/group-by/trait';
import { LEFT_TOOL_BAR_WIDTH, STATS_BAR_HEIGHT } from '../../../../consts';
import type { TableSingleView } from '../../../../table-view-manager';
@@ -38,7 +38,7 @@ export class VirtualDataBaseColumnStats extends SignalWatcher(
}
@property({ attribute: false })
accessor group: GroupData | undefined = undefined;
accessor group: Group | undefined = undefined;
@property({ attribute: false })
accessor view!: TableSingleView;
@@ -15,7 +15,7 @@ import { property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import { typeSystem } from '../../../../../../core';
import type { GroupData } from '../../../../../../core/group-by/trait';
import type { Group } from '../../../../../../core/group-by/trait';
import { statsFunctions } from '../../../../../../core/statistics';
import type { StatisticsConfig } from '../../../../../../core/statistics/types';
import type { TableProperty } from '../../../../table-view-manager';
@@ -236,7 +236,7 @@ export class VirtualDatabaseColumnStatsCell extends SignalWatcher(
}
@property({ attribute: false })
accessor group: GroupData | undefined = undefined;
accessor group: Group | undefined = undefined;
}
declare global {
@@ -4,7 +4,7 @@ import { nothing } from 'lit';
import { html } from 'lit/static-html.js';
import {
type GroupData,
type Group,
type GroupRenderProps,
renderUniLit,
} from '../../../../../core';
@@ -18,7 +18,7 @@ import {
show,
} from './group-title-css';
function GroupHeaderCount(group: GroupData) {
function GroupHeaderCount(group: Group) {
const cards = group.rows;
if (!cards.length) {
return;
@@ -27,7 +27,7 @@ function GroupHeaderCount(group: GroupData) {
}
export const GroupTitle = (
groupData: GroupData,
groupData: Group,
ops: {
groupHover: boolean;
readonly: boolean;
@@ -35,24 +35,20 @@ export const GroupTitle = (
clickOps: (evt: MouseEvent) => void;
}
) => {
const data = groupData.manager.config$.value;
if (!data) return nothing;
const view = groupData.view;
const type = groupData.property.dataType$.value;
if (!view || !type) {
return nothing;
}
const icon =
groupData.value == null
? ''
: html` <uni-lit
class="${groupHeaderIcon}"
.uni="${groupData.manager.property$.value?.icon}"
.uni="${groupData.property.icon}"
></uni-lit>`;
const props: GroupRenderProps = {
value: groupData.value,
data: groupData.property.data$.value,
updateData: groupData.manager.updateData,
updateValue: value =>
groupData.manager.updateValue(
groupData.rows.map(row => row.rowId),
value
),
group: groupData,
readonly: ops.readonly,
};
@@ -65,7 +61,7 @@ export const GroupTitle = (
const opsClass = clsx(ops.groupHover && show, groupHeaderOps);
return html`
<div class="${groupTitleRow}">
${icon} ${renderUniLit(data.view, props)} ${columnName}
${icon} ${renderUniLit(view, props)} ${columnName}
${GroupHeaderCount(groupData)}
</div>
${!ops.readonly
@@ -7,7 +7,7 @@ import { repeat } from 'lit/directives/repeat.js';
import { styleMap } from 'lit/directives/style-map.js';
import { html } from 'lit/static-html.js';
import type { GroupData } from '../../../../../../core/group-by/trait';
import type { Group } from '../../../../../../core/group-by/trait';
import type { Row } from '../../../../../../core/view-manager/row';
import type {
TableProperty,
@@ -84,7 +84,7 @@ export class DataViewColumnPreview extends SignalWatcher(
accessor container!: HTMLElement;
@property({ attribute: false })
accessor group: GroupData | undefined = undefined;
accessor group: Group | undefined = undefined;
}
declare global {
@@ -40,7 +40,10 @@ import {
} from '../../../../../../core/utils/wc-dnd/dnd-context';
import type { Property } from '../../../../../../core/view-manager/property';
import { numberFormats } from '../../../../../../property-presets/number/utils/formats';
import { ShowQuickSettingBarContextKey } from '../../../../../../widget-presets/quick-setting-bar/context';
import {
createDefaultShowQuickSettingBar,
ShowQuickSettingBarKey,
} from '../../../../../../widget-presets/quick-setting-bar/context';
import { DEFAULT_COLUMN_TITLE_HEIGHT } from '../../../../consts';
import type {
TableProperty,
@@ -193,7 +196,10 @@ export class DatabaseHeaderColumn extends SignalWatcher(
}
private _toggleQuickSettingBar(show = true) {
const map = this.tableViewManager.contextGet(ShowQuickSettingBarContextKey);
const map = this.tableViewManager.serviceGetOrCreate(
ShowQuickSettingBarKey,
createDefaultShowQuickSettingBar
);
map.value = {
...map.value,
[this.tableViewManager.id]: show,
@@ -14,7 +14,7 @@ import { repeat } from 'lit/directives/repeat.js';
import type { DataViewRenderer } from '../../../core/data-view.js';
import { GroupTitle } from '../../../core/group-by/group-title.js';
import type { GroupData } from '../../../core/group-by/trait.js';
import type { Group } from '../../../core/group-by/trait.js';
import type { Row } from '../../../core/index.js';
import { createDndContext } from '../../../core/utils/wc-dnd/dnd-context.js';
import { defaultActivators } from '../../../core/utils/wc-dnd/sensors/index.js';
@@ -150,7 +150,7 @@ export class TableGroup extends SignalWatcher(
};
@property({ attribute: false })
accessor group: GroupData | undefined = undefined;
accessor group: Group | undefined = undefined;
@property({ attribute: false })
accessor view!: TableSingleView;
@@ -7,7 +7,7 @@ import { repeat } from 'lit/directives/repeat.js';
import { styleMap } from 'lit/directives/style-map.js';
import { html } from 'lit/static-html.js';
import type { GroupData } from '../../../../core/group-by/trait.js';
import type { Group } from '../../../../core/group-by/trait.js';
import type { Row } from '../../../../core/index.js';
import type {
TableProperty,
@@ -84,7 +84,7 @@ export class DataViewColumnPreview extends SignalWatcher(
accessor container!: HTMLElement;
@property({ attribute: false })
accessor group: GroupData | undefined = undefined;
accessor group: Group | undefined = undefined;
}
declare global {
@@ -40,7 +40,10 @@ import {
} from '../../../../core/utils/wc-dnd/dnd-context.js';
import type { Property } from '../../../../core/view-manager/property.js';
import { numberFormats } from '../../../../property-presets/number/utils/formats.js';
import { ShowQuickSettingBarContextKey } from '../../../../widget-presets/quick-setting-bar/context.js';
import {
createDefaultShowQuickSettingBar,
ShowQuickSettingBarKey,
} from '../../../../widget-presets/quick-setting-bar/context.js';
import { DEFAULT_COLUMN_TITLE_HEIGHT } from '../../consts.js';
import type {
TableProperty,
@@ -193,7 +196,10 @@ export class DatabaseHeaderColumn extends SignalWatcher(
}
private _toggleQuickSettingBar(show = true) {
const map = this.tableViewManager.contextGet(ShowQuickSettingBarContextKey);
const map = this.tableViewManager.serviceGetOrCreate(
ShowQuickSettingBarKey,
createDefaultShowQuickSettingBar
);
map.value = {
...map.value,
[this.tableViewManager.id]: show,
@@ -4,7 +4,7 @@ import { css, html } from 'lit';
import { property } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
import type { GroupData } from '../../../core/group-by/trait.js';
import type { Group } from '../../../core/group-by/trait.js';
import { LEFT_TOOL_BAR_WIDTH, STATS_BAR_HEIGHT } from '../consts.js';
import type { TableSingleView } from '../table-view-manager.js';
@@ -38,7 +38,7 @@ export class DataBaseColumnStats extends SignalWatcher(
}
@property({ attribute: false })
accessor group: GroupData | undefined = undefined;
accessor group: Group | undefined = undefined;
@property({ attribute: false })
accessor view!: TableSingleView;
@@ -14,7 +14,7 @@ import { css, html } from 'lit';
import { property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import type { GroupData } from '../../../core/group-by/trait.js';
import type { Group } from '../../../core/group-by/trait.js';
import { typeSystem } from '../../../core/index.js';
import { statsFunctions } from '../../../core/statistics/index.js';
import type { StatisticsConfig } from '../../../core/statistics/types.js';
@@ -236,7 +236,7 @@ export class DatabaseColumnStatsCell extends SignalWatcher(
}
@property({ attribute: false })
accessor group: GroupData | undefined = undefined;
accessor group: Group | undefined = undefined;
}
declare global {