Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin' into shared
Browse files Browse the repository at this point in the history
  • Loading branch information
huanhuanwa committed Jul 25, 2024
2 parents 4ae0bbc + 0392723 commit aa18b7b
Show file tree
Hide file tree
Showing 16 changed files with 223 additions and 26 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.

## [0.0.3](https://github.com/worktile/ai-table/compare/0.0.2...0.0.3) (2024-07-22)


### Features

* support add and extend field #WIK-16038 ([#10](https://github.com/worktile/ai-table/issues/10)) ([74edbbb](https://github.com/worktile/ai-table/commit/74edbbbca3f387454bb22f436eaef0f67367b5e1)), closes [#WIK-16038](https://github.com/worktile/ai-table/issues/WIK-16038)



## 0.0.2 (2024-07-16)


Expand Down
3 changes: 3 additions & 0 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,5 +123,8 @@
}
}
}
},
"cli": {
"analytics": false
}
}
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ai-table",
"version": "0.0.2",
"version": "0.0.3",
"workspaces": [
"packages/*"
],
Expand Down
2 changes: 1 addition & 1 deletion packages/grid/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ai-table/grid",
"version": "0.0.2",
"version": "0.0.3",
"peerDependencies": {
"@angular/common": "^18.0.0",
"@angular/core": "^18.0.0"
Expand Down
3 changes: 3 additions & 0 deletions packages/grid/src/core/types/core.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { WritableSignal } from '@angular/core';
import { AITableAction } from './action';
import { AITableSelection } from '../../types';

export enum AITableFieldType {
// NotSupport = 0,
Expand Down Expand Up @@ -57,6 +58,7 @@ export interface AITableField {

export interface AITableRecord {
id: string;
checked?: boolean;
value: Record<string, any>;
}

Expand All @@ -73,6 +75,7 @@ export interface AITable {
records: WritableSignal<AITableRecords>;
fields: WritableSignal<AITableFields>;
actions: AITableAction[];
selection: WritableSignal<AITableSelection>;
onChange: () => void;
apply: (action: AITableAction) => void;
}
Expand Down
7 changes: 6 additions & 1 deletion packages/grid/src/core/utils/common.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import { Actions } from '../action';
import { AITable, AITableAction, AITableFields, AITableRecords } from '../types';
import { FLUSHING } from './weak-map';
import { WritableSignal } from '@angular/core';
import { WritableSignal, signal } from '@angular/core';

export function createAITable(records: WritableSignal<AITableRecords>, fields: WritableSignal<AITableFields>): AITable {
const aiTable: AITable = {
records,
fields,
actions: [],
selection: signal({
selectedRecords: new Map(),
selectedFields: new Map(),
selectedCells: new Map()
}),
onChange: () => {},
apply: (action: AITableAction) => {
aiTable.actions.push(action);
Expand Down
33 changes: 28 additions & 5 deletions packages/grid/src/grid.component.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
<div class="grid-header d-flex">
<div class="grid-column-checkbox grid-cell">
<input type="checkbox" />
<label thyCheckbox thyLabelText="" [ngModel]="isSelectedAll" (ngModelChange)="toggleSelectAll($event)"></label>
</div>
@for (field of gridData().fields; track field.id) {
<div class="grid-cell grid-field" #fieldAction>
<div
class="grid-cell grid-column-field"
#fieldAction
[attr.fieldId]="field.id"
[ngClass]="{ highlight: aiTable.selection().selectedFields.has(field.id) }"
>
{{ field.name }}
<a thyAction thyActiveClass="active" thyIcon="more-vertical" [thyDropdown]="fieldMenu" href="javascript:;">
<thy-dropdown-menu #fieldMenu>
Expand All @@ -18,12 +23,29 @@
</div>
<div class="grid-body d-flex">
@for (record of gridData().records; track record.id; let index = $index) {
<div class="grid-row d-flex">
<div class="grid-row d-flex" [ngClass]="{ highlight: aiTable.selection().selectedRecords.has(record.id) }">
<div class="grid-row-index">
{{ index + 1 }}
<label
[ngClass]="record.checked ? 'checked-box' : 'unchecked-box'"
thyCheckbox
thyLabelText=""
[ngModel]="record.checked"
(ngModelChange)="selectRecord(record.id)"
></label>
<span [ngClass]="record.checked ? 'grid-row-no-number' : 'grid-row-number'"> {{ index + 1 }} </span>
</div>
@for (field of gridData().fields; track $index) {
<div class="grid-cell" [attr.type]="[field.type]" [attr.fieldId]="[field.id]" [attr.recordId]="[record.id]" #cell>
<div
class="grid-cell"
[ngClass]="{
highlight: aiTable.selection().selectedCells.has(record.id) || aiTable.selection().selectedFields.has(field.id),
selected: aiTable.selection().selectedCells.get(record.id)?.hasOwnProperty(field.id)
}"
[attr.type]="[field.type]"
[attr.fieldId]="[field.id]"
[attr.recordId]="[record.id]"
#cell
>
@switch (field.type) {
@case (AITableFieldType.SingleSelect) {
@if (record.value[field.id] | selectOption: field['options']; as selectedOption) {
Expand Down Expand Up @@ -51,6 +73,7 @@
{{ record.value[field.id] }}
}
}
<div class="autofill-container"></div>
</div>
}
<div class="grid-column-blank"></div>
Expand Down
35 changes: 30 additions & 5 deletions packages/grid/src/grid.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, computed, ElementRef, input, model, OnInit, output, signal, viewChild } from '@angular/core';
import { ChangeDetectionStrategy, Component, computed, ElementRef, input, model, NgZone, OnInit, output, signal } from '@angular/core';
import { CommonModule, NgClass, NgComponentOutlet, NgForOf } from '@angular/common';
import { SelectOptionPipe } from './pipes/grid';
import { ThyTag } from 'ngx-tethys/tag';
Expand All @@ -25,12 +25,14 @@ import { ThyRate } from 'ngx-tethys/rate';
import { FormsModule } from '@angular/forms';
import { ThyFlexibleText } from 'ngx-tethys/flexible-text';
import { ThyTooltipModule, ThyTooltipService } from 'ngx-tethys/tooltip';
import { ThyCheckboxModule } from 'ngx-tethys/checkbox';
import { ThyStopPropagationDirective } from 'ngx-tethys/shared';
import { FieldMenu } from './components/field-menu/field-menu.component';
import { ThyAction } from 'ngx-tethys/action';
import { ThyDropdownDirective, ThyDropdownMenuComponent } from 'ngx-tethys/dropdown';
import { DefaultFieldMenus } from './constants';
import { AI_TABLE_GRID_FIELD_SERVICE_MAP, AITableGridFieldService } from './services/field.service';
import { AITableGridSelectionService } from './services/selection.servive';

@Component({
selector: 'ai-table-grid',
Expand Down Expand Up @@ -59,9 +61,10 @@ import { AI_TABLE_GRID_FIELD_SERVICE_MAP, AITableGridFieldService } from './serv
FieldMenu,
ThyAction,
ThyDropdownDirective,
ThyDropdownMenuComponent
ThyDropdownMenuComponent,
ThyCheckboxModule
],
providers: [ThyTooltipService, AITableGridEventService, AITableGridFieldService]
providers: [ThyTooltipService, AITableGridEventService, AITableGridFieldService, AITableGridSelectionService]
})
export class AITableGrid implements OnInit {
aiRecords = model.required<AITableRecords>();
Expand All @@ -80,26 +83,39 @@ export class AITableGrid implements OnInit {

aiTable!: AITable;

get isSelectedAll() {
return this.aiTable.selection().selectedRecords.size === this.aiRecords().length;
}

onChange = output<AITableChangeOptions>();

aiTableInitialized = output<AITable>();

fieldMenus!: AITableFieldMenu[];

gridData = computed(() => {
return buildGridData(this.aiRecords(), this.aiFields());
return buildGridData(this.aiRecords(), this.aiFields(), this.aiTable.selection());
});

constructor(
private elementRef: ElementRef,
private aiTableGridEventService: AITableGridEventService,
private aiTableGridFieldService: AITableGridFieldService
public aiTableGridSelectionService: AITableGridSelectionService,
private aiTableGridFieldService: AITableGridFieldService,
private ngZone: NgZone
) {}

ngOnInit(): void {
this.initAITable();
this.initService();
this.buildFieldMenus();
this.ngZone.runOutsideAngular(() => {
this.aiTableGridEventService.mousedownEvent$.pipe(this.takeUntilDestroyed).subscribe((event) => {
if ((event as MouseEvent)?.target) {
this.aiTableGridSelectionService.updateSelect(event as MouseEvent);
}
});
});
}

initAITable() {
Expand All @@ -116,6 +132,7 @@ export class AITableGrid implements OnInit {

initService() {
this.aiTableGridEventService.initialize(this.aiTable, this.aiFieldConfig()?.fieldPropertyEditor);
this.aiTableGridSelectionService.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 All @@ -129,6 +146,14 @@ export class AITableGrid implements OnInit {
Actions.addRecord(this.aiTable, getDefaultRecord(this.aiFields()), [this.aiRecords().length]);
}

selectRecord(recordId: string) {
this.aiTableGridSelectionService.selectRecord(recordId);
}

toggleSelectAll(checked: boolean) {
this.aiTableGridSelectionService.toggleSelectAll(checked);
}

addField(gridColumnBlank: HTMLElement) {
const field = signal(createDefaultField(this.aiTable, AITableFieldType.Text));
this.aiTableGridFieldService.editFieldProperty(gridColumnBlank, this.aiTable, field, false);
Expand Down
2 changes: 1 addition & 1 deletion packages/grid/src/pipes/grid.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Pipe, PipeTransform } from '@angular/core';
import { AITableSelectOption } from '../core';;
import { AITableSelectOption } from '../core';

@Pipe({
name: 'selectOption',
Expand Down
10 changes: 9 additions & 1 deletion packages/grid/src/services/event.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Injectable, Signal } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { fromEvent } from 'rxjs';
import { fromEvent, Subject } from 'rxjs';
import { DBL_CLICK_EDIT_TYPE } from '../constants';
import { getRecordOrField } from '../utils';
import { AITable, AITableField, AITableFieldType, AITableRecord } from '../core';
Expand All @@ -16,6 +16,8 @@ export class AITableGridEventService {

takeUntilDestroyed = takeUntilDestroyed();

mousedownEvent$ = new Subject<MouseEvent>();

constructor(private thyPopover: ThyPopover) {}

initialize(aiTable: AITable, aiFieldRenderers?: Partial<Record<AITableFieldType, AITableGridCellRenderSchema>>) {
Expand All @@ -29,6 +31,12 @@ export class AITableGridEventService {
.subscribe((event) => {
this.dblClick(event as MouseEvent);
});

fromEvent<MouseEvent>(element, 'mousedown')
.pipe(this.takeUntilDestroyed)
.subscribe((event) => {
this.mousedownEvent$.next(event as MouseEvent);
});
}

private dblClick(event: MouseEvent) {
Expand Down
68 changes: 68 additions & 0 deletions packages/grid/src/services/selection.servive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Injectable } from '@angular/core';
import { AITable } from '../core';

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

constructor() {}

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

clearSelection() {
this.aiTable.selection.set({
selectedRecords: new Map(),
selectedFields: new Map(),
selectedCells: new Map()
});
}

selectCell(recordId: string, fieldId: string) {
this.clearSelection();
this.aiTable.selection().selectedCells.set(recordId, { [fieldId]: true });
}

selectField(fieldId: string) {
this.clearSelection();
this.aiTable.selection().selectedFields.set(fieldId, true);
}

selectRecord(recordId: string) {
if (this.aiTable.selection().selectedRecords.has(recordId)) {
this.aiTable.selection().selectedRecords.delete(recordId);
} else {
this.aiTable.selection().selectedRecords.set(recordId, true);
}
this.aiTable.selection.set({
selectedRecords: this.aiTable.selection().selectedRecords,
selectedFields: new Map(),
selectedCells: new Map()
});
}

toggleSelectAll(checked: boolean) {
this.clearSelection();
if (checked) {
this.aiTable.records().forEach((item) => {
this.selectRecord(item.id);
});
}
}

updateSelect(event: MouseEvent) {
const target = event.target as HTMLElement;
const cellDom = target.closest('.grid-cell');
const colDom = target.closest('.grid-column-field');
if (cellDom) {
const fieldId = cellDom.getAttribute('fieldId');
const recordId = cellDom.getAttribute('recordId');
fieldId && recordId && this.selectCell(recordId, fieldId);
}
if (colDom) {
const fieldId = colDom.getAttribute('fieldId');
fieldId && this.selectField(fieldId);
}
}
}
Loading

0 comments on commit aa18b7b

Please sign in to comment.