Skip to content

Commit

Permalink
feat(grid): support highlight the cell which match the keywords
Browse files Browse the repository at this point in the history
  • Loading branch information
minlovehua committed Dec 24, 2024
1 parent e6e9dd0 commit b317ca0
Show file tree
Hide file tree
Showing 19 changed files with 186 additions and 5 deletions.
1 change: 1 addition & 0 deletions packages/grid/src/constants/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const Colors = {
gray80: '#fafafa',
headSelectedBgColor: '#EAEFFA',
itemActiveBgColor: '#6698ff1a',
itemMatchBgColor: '#ff9f731a',
waring: '#ffcd5d',
success: '#73d897'
};
3 changes: 2 additions & 1 deletion packages/grid/src/core/types/ai-table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ export interface AITable {
fields: WritableSignal<AITableFields>;
context?: RendererContext;
selection: WritableSignal<AITableSelection>;
matchedCells: WritableSignal<string[]>; // [`${recordId}-${fieldId}`]
recordsMap: Signal<{ [kay: string]: AITableRecord }>;
fieldsMap: Signal<{ [kay: string]: AITableField }>;
recordsWillHidden: WritableSignal<string[]>;
recordsWillMove: WritableSignal<string[]>
recordsWillMove: WritableSignal<string[]>;
}

export type AIPlugin = (aiTable: AITable) => AITable;
Expand Down
1 change: 1 addition & 0 deletions packages/grid/src/core/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export function createAITable(records: WritableSignal<AITableRecords>, fields: W
selectedFields: new Map(),
selectedCells: new Map()
}),
matchedCells: signal([]),
recordsMap: computed(() => {
return records().reduce(
(object, item) => {
Expand Down
5 changes: 5 additions & 0 deletions packages/grid/src/grid-base.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { AI_TABLE_GRID_FIELD_SERVICE_MAP, AITableGridFieldService } from './serv
import { AITableGridSelectionService } from './services/selection.service';
import { AIFieldConfig, AITableFieldMenuItem, AITableContextMenuItem, AITableReferences } from './types';
import { AITableFieldPropertyEditor } from './components';
import { AITableGridMatchCellService } from './services/match-cell.service';

@Component({
selector: 'ai-table-grid-base',
Expand All @@ -59,6 +60,8 @@ export class AITableGridBase implements OnInit {

aiBuildRenderDataFn = input<(aiTable: AITable) => AITableValue>();

aiKeywords = input<string>();

AITableFieldType = AITableFieldType;

AITableSelectOptionStyle = AITableSelectOptionStyle;
Expand Down Expand Up @@ -99,6 +102,7 @@ export class AITableGridBase implements OnInit {
protected aiTableGridFieldService = inject(AITableGridFieldService);
protected aiTableGridEventService = inject(AITableGridEventService);
protected aiTableGridSelectionService = inject(AITableGridSelectionService);
protected aiTableGridMatchCellService = inject(AITableGridMatchCellService);

ngOnInit(): void {
this.initAITable();
Expand All @@ -116,6 +120,7 @@ export class AITableGridBase implements OnInit {
initService() {
this.aiTableGridEventService.initialize(this.aiTable, this.aiFieldConfig()?.fieldPropertyEditor);
this.aiTableGridSelectionService.initialize(this.aiTable);
this.aiTableGridMatchCellService.initialize(this.aiTable);
this.aiTableGridEventService.registerEvents(this.elementRef.nativeElement);
this.aiTableGridFieldService.initAIFieldConfig(this.aiFieldConfig());
AI_TABLE_GRID_FIELD_SERVICE_MAP.set(this.aiTable, this.aiTableGridFieldService);
Expand Down
11 changes: 10 additions & 1 deletion packages/grid/src/grid.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import { AITableGridSelectionService } from './services/selection.service';
import { AITableMouseDownType, AITableRendererConfig, ScrollActionOptions } from './types';
import { buildGridLinearRows, getColumnIndicesMap, getDetailByTargetName, handleMouseStyle, isWindows } from './utils';
import { getMousePosition } from './utils/position';
import { AITableGridMatchCellService } from './services/match-cell.service';

@Component({
selector: 'ai-table-grid',
Expand All @@ -53,7 +54,7 @@ import { getMousePosition } from './utils/position';
class: 'ai-table-grid'
},
imports: [AITableRenderer],
providers: [AITableGridEventService, AITableGridFieldService, AITableGridSelectionService]
providers: [AITableGridEventService, AITableGridFieldService, AITableGridSelectionService, AITableGridMatchCellService]
})
export class AITableGrid extends AITableGridBase implements OnInit, OnDestroy {
private viewContainerRef = inject(ViewContainerRef);
Expand Down Expand Up @@ -147,6 +148,14 @@ export class AITableGrid extends AITableGridBase implements OnInit, OnDestroy {
this.toggleHoverCellEditor();
}
});
effect(
() => {
if (this.aiKeywords()) {
this.aiTableGridMatchCellService.findMatchedCells(this.aiKeywords()!, this.aiReferences());
}
},
{ allowSignalWrites: true }
);
}

override ngOnInit(): void {
Expand Down
12 changes: 10 additions & 2 deletions packages/grid/src/renderer/creations/create-cells.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
DEFAULT_FONT_STYLE
} from '../../constants';
import { AITable, AITableQueries, RendererContext } from '../../core';
import { AITableAreaType, AITableCellsDrawerConfig, AITableRender, AITableRowType } from '../../types';
import { AITableCellsDrawerConfig, AITableRender, AITableRowType } from '../../types';
import { getCellHorizontalPosition, transformCellValue } from '../../utils';
import { addRowLayout } from '../drawers/add-row-layout-drawer';
import { cellDrawer } from '../drawers/cell-drawer';
Expand Down Expand Up @@ -85,7 +85,15 @@ export const createCells = (config: AITableCellsDrawerConfig) => {
const isSiblingActiveCell = recordId === activeCell?.recordId && fieldId !== activeCell?.fieldId;
const isActiveCell = recordId === activeCell?.recordId;

if (isCheckedRow || isSelected || isSiblingActiveCell) {
let matchedCellsMap: { [key: string]: boolean } = {};
aiTable.matchedCells().forEach((key) => {
matchedCellsMap[key] = true;
});
const isMatchedCell = matchedCellsMap[`${recordId}-${fieldId}`];

if (isMatchedCell) {
background = colors.itemMatchBgColor;
} else if (isCheckedRow || isSelected || isSiblingActiveCell) {
background = colors.itemActiveBgColor;
} else if (isHoverRow && !isActiveCell) {
background = colors.gray80;
Expand Down
1 change: 1 addition & 0 deletions packages/grid/src/services/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './event.service';
export * from './field.service';
export * from './selection.service';
export * from './match-cell.service';
38 changes: 38 additions & 0 deletions packages/grid/src/services/match-cell.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Injectable } from '@angular/core';
import { AITable, AITableField, AITableQueries } from '../core';
import { AITableReferences } from '../types';
import { transformCellValue, ViewOperationMap } from '../utils';

@Injectable()
export class AITableGridMatchCellService {
aiTable!: AITable;

initialize(aiTable: AITable) {
this.aiTable = aiTable;
}

findMatchedCells(keywords: string, references: AITableReferences) {
let matchedCells: string[] = [];
this.aiTable.records().forEach((record) => {
this.aiTable.fields().forEach((field) => {
if (this.isCellMatchKeywords(this.aiTable, field, record._id, keywords, references)) {
matchedCells.push(`${record._id}-${field._id}`);
}
});
});
this.aiTable.matchedCells.set([...matchedCells]);
}

private isCellMatchKeywords(aiTable: AITable, field: AITableField, recordId: string, keywords: string, references: AITableReferences) {
const cellValue = AITableQueries.getFieldValue(aiTable, [recordId, field._id]);
const transformValue = transformCellValue(aiTable, field, cellValue);
const fieldMethod = ViewOperationMap[field.type];
let cellFullText: string[] = fieldMethod.cellFullText(transformValue, field, references);

try {
return keywords && cellFullText.length && cellFullText.some((item) => item.toLowerCase().includes(keywords.toLowerCase()));
} catch (error) {
return false;
}
}
}
13 changes: 13 additions & 0 deletions packages/grid/src/utils/common.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { isArray, isEmpty as isArrayEmpty, isObject, isUndefinedOrNull } from 'ngx-tethys/util';
import { AI_TABLE_BLANK } from '../constants';
import { AITableTargetNameDetail, AITableTargetNameOptions } from '../types';

Expand Down Expand Up @@ -51,3 +52,15 @@ export const castToString = (value: string): string | null => {
}
return typeof value !== 'string' ? String(value) : value;
};

export function isEmpty(value: any) {
if (isArray(value)) {
return isArrayEmpty(value);
}

if (isObject(value)) {
return Reflect.ownKeys(value).length === 0;
}

return isUndefinedOrNull(value) || value === '';
}
5 changes: 5 additions & 0 deletions packages/grid/src/utils/field/field.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { AITableField, AITableReferences } from '../../index';

export abstract class Field {
abstract cellFullText(transformValue: any, field: AITableField, references?: AITableReferences): string[];
}
22 changes: 22 additions & 0 deletions packages/grid/src/utils/field/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { AITableFieldType } from '../../index';
import { Field } from './field';
import { LinkField } from './link';
import { MemberField } from './member';
import { SelectField } from './select';
import { TextField } from './text';

export const ViewOperationMap: Record<AITableFieldType, Field> = {
[AITableFieldType.text]: new TextField(),
[AITableFieldType.richText]: new TextField(),
[AITableFieldType.select]: new SelectField(),
[AITableFieldType.date]: new TextField(),
[AITableFieldType.createdAt]: new TextField(),
[AITableFieldType.updatedAt]: new TextField(),
[AITableFieldType.number]: new TextField(),
[AITableFieldType.rate]: new TextField(),
[AITableFieldType.link]: new LinkField(),
[AITableFieldType.member]: new MemberField(),
[AITableFieldType.progress]: new TextField(),
[AITableFieldType.createdBy]: new MemberField(),
[AITableFieldType.updatedBy]: new MemberField()
};
13 changes: 13 additions & 0 deletions packages/grid/src/utils/field/link.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { AITableField, LinkFieldValue } from '../../index';
import { Field } from './field';
import { isEmpty } from '../common';

export class LinkField extends Field {
override cellFullText(transformValue: LinkFieldValue, field: AITableField): string[] {
let fullText: string[] = [];
if (!isEmpty(transformValue?.text)) {
fullText.push(transformValue.text);
}
return fullText;
}
}
20 changes: 20 additions & 0 deletions packages/grid/src/utils/field/member.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { AITableField, AITableReferences } from '../../index';
import { Field } from './field';

export class MemberField extends Field {
override cellFullText(transformValue: string[], field: AITableField, references?: AITableReferences): string[] {
let fullText: string[] = [];
if (transformValue?.length && references) {
for (let index = 0; index < transformValue.length; index++) {
const userInfo = references?.members[transformValue[index]];
if (!userInfo) {
continue;
}
if (userInfo.display_name) {
fullText.push(userInfo.display_name);
}
}
}
return fullText;
}
}
9 changes: 9 additions & 0 deletions packages/grid/src/utils/field/progress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { AITableField } from '../../index';
import { Field } from './field';

export class ProgressField extends Field {
override cellFullText(transformValue: number, field: AITableField): string[] {
const fullText = `${transformValue}%`;
return [fullText];
}
}
17 changes: 17 additions & 0 deletions packages/grid/src/utils/field/select.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Field } from './field';
import { AITableField, AITableSelectField } from '../../index';

export class SelectField extends Field {
override cellFullText(transformValue: string[], field: AITableField): string[] {
let cellText: string[] = [];
if (transformValue && Array.isArray(transformValue) && transformValue.length) {
transformValue.forEach((optionId) => {
const item = (field as AITableSelectField).settings?.options?.find((option) => option._id === optionId);
if (item?.text) {
cellText.push(item.text);
}
});
}
return cellText;
}
}
12 changes: 12 additions & 0 deletions packages/grid/src/utils/field/text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { AITableField, AITableReferences, isEmpty } from '../../index';
import { Field } from './field';

export class TextField extends Field {
override cellFullText(transformValue: any, field: AITableField, references?: AITableReferences): string[] {
let fullText: string[] = [];
if (!isEmpty(transformValue)) {
fullText.push(String(transformValue));
}
return fullText;
}
}
1 change: 1 addition & 0 deletions packages/grid/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export * from './position';
export * from './style';
export * from './text-measure';
export * from './visible-range';
export * from './field';
6 changes: 5 additions & 1 deletion packages/state/src/types/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export enum AITableFilterOperation {
notContain = 'not_contain'
}

export type ViewSettings = AITableFilterConditions & AITableSortOptions;
export type ViewSettings = AITableSearchOptions & AITableFilterConditions & AITableSortOptions;

export interface AITableView {
_id: string;
Expand Down Expand Up @@ -78,4 +78,8 @@ export interface AITableSortOptions {
}[];
}

export interface AITableSearchOptions {
keywords?: string;
}

export type AITableViews = AITableView[];
1 change: 1 addition & 0 deletions src/app/component/common/content/content.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
[(aiRecords)]="tableService.records"
[(aiFields)]="tableService.fields"
[aiFieldConfig]="aiFieldConfig()"
[aiKeywords]="tableService.keywords()"
[aiPlugins]="plugins"
[aiReferences]="references()"
(aiAddRecord)="addRecord($event)"
Expand Down

0 comments on commit b317ca0

Please sign in to comment.