Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(grid): support highlight the cell which match the keywords #204

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
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 {
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 {
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 {
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 {
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
Loading
Loading