Skip to content

Commit

Permalink
feat(action): add AIPlugin (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
cmm-va authored Jul 26, 2024
1 parent 488a8e1 commit 024fa5f
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 3 deletions.
2 changes: 2 additions & 0 deletions packages/grid/src/core/types/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,5 @@ export interface AITableFieldInfo {
icon: string;
width: number;
}

export type AIPlugin = (aiTable: AITable) => AITable;
8 changes: 7 additions & 1 deletion packages/grid/src/grid.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import {
AITableFields,
AITableFieldType,
AITableRecords,
createDefaultField
createDefaultField,
AIPlugin
} from './core';
import { ThyIcon } from 'ngx-tethys/icon';
import { AITableGridEventService } from './services/event.service';
Expand Down Expand Up @@ -77,6 +78,8 @@ export class AITableGrid implements OnInit {

aiReadonly = input<boolean>();

aiPlugins = input<AIPlugin[]>();

AITableFieldType = AITableFieldType;

takeUntilDestroyed = takeUntilDestroyed();
Expand Down Expand Up @@ -120,6 +123,9 @@ export class AITableGrid implements OnInit {

initAITable() {
this.aiTable = createAITable(this.aiRecords, this.aiFields);
this.aiPlugins()?.forEach((plugin) => {
this.aiTable = plugin(this.aiTable);
});
this.aiTableInitialized.emit(this.aiTable);
this.aiTable.onChange = () => {
this.onChange.emit({
Expand Down
7 changes: 7 additions & 0 deletions src/app/action/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { setView, applyView, GeneralActions } from './view';

export const CustomActions = {
setView,
applyView,
...GeneralActions
};
38 changes: 38 additions & 0 deletions src/app/action/view.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { AITableView, AIViewAction, ViewActionName } from '../types/view';
import { AIViewTable } from '../types/view';
import { createDraft, finishDraft } from 'immer';

export function setView(aiTable: AIViewTable, newView: AITableView, path: [number]) {
const [index] = path;
const view = aiTable.views()[index];
if (JSON.stringify(view) !== JSON.stringify(newView)) {
const operation = {
type: ViewActionName.setView,
view,
newView,
path
};
aiTable.viewApply(operation);
}
}

export const GeneralActions = {
transform(aiTable: AIViewTable, op: AIViewAction): void {
const views = createDraft(aiTable.views());
applyView(aiTable, views, op);
aiTable.views.update(() => {
return finishDraft(views);
});
}
};

export const applyView = (aiTable: AIViewTable, views: AITableView[], options: AIViewAction) => {
const [viewIndex] = options.path;
views[viewIndex] = options.newView;
return views;
};

export const ViewActions = {
setView,
applyView
};
5 changes: 5 additions & 0 deletions src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
行高:
<thy-select [(ngModel)]="activeView().rowHeight" style="width: 200px" (ngModelChange)="changeRowHeight($event)">
<thy-option *ngFor="let option of listOfOption" [thyValue]="option.value" [thyLabelText]="option.text"> </thy-option>
</thy-select>
<ai-table-grid
[(aiRecords)]="records"
[(aiFields)]="fields"
(onChange)="onChange($event)"
[aiFieldConfig]="aiFieldConfig"
[aiPlugins]="plugins"
(aiTableInitialized)="aiTableInitialized($event)"
></ai-table-grid>
40 changes: 38 additions & 2 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AfterViewInit, Component, OnDestroy, OnInit, Signal, signal, WritableSignal } from '@angular/core';
import { AfterViewInit, Component, OnDestroy, computed, OnInit, Signal, signal, WritableSignal } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { RouterOutlet } from '@angular/router';
import {
Expand All @@ -15,6 +15,13 @@ import {
import { ThyIconRegistry } from 'ngx-tethys/icon';
import { ThyPopover, ThyPopoverModule } from 'ngx-tethys/popover';
import { FieldPropertyEditor } from './component/field-property-editor/field-property-editor.component';
import { withCustomApply } from './plugins/custom-action.plugin';
import { ThyOption } from 'ngx-tethys/shared';
import { ThySelect } from 'ngx-tethys/select';
import { FormsModule } from '@angular/forms';
import { NgFor } from '@angular/common';
import { CustomActions } from './action';
import { AITableView, AIViewTable, RowHeight } from './types/view';
import { WebsocketProvider } from 'y-websocket';
import { connectProvider } from './share/provider';
import { SharedType, getSharedType } from './share/shared';
Expand Down Expand Up @@ -124,7 +131,7 @@ const initValue = {
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet, AITableGrid, ThyPopoverModule, FieldPropertyEditor],
imports: [RouterOutlet, AITableGrid, ThyPopoverModule, FieldPropertyEditor, ThySelect, FormsModule, NgFor, ThyOption],
templateUrl: './app.component.html',
styleUrl: './app.component.scss'
})
Expand All @@ -135,6 +142,27 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {

aiTable!: AITable;

views = signal([
{ rowHeight: RowHeight.short, id: 'view1', name: '表格1', isActive: true },
{ rowHeight: RowHeight.short, id: '3', name: '表格视图3' }
]);

plugins = [withCustomApply];

listOfOption = [
{
value: 'short',
text: 'short'
},
{
value: 'medium',
text: 'medium'
},
{
value: 'tall',
text: 'tall'
}
];
sharedType!: SharedType | null;

provider!: WebsocketProvider | null;
Expand All @@ -155,6 +183,10 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
]
};

activeView = computed(() => {
return { ...this.views().find((view) => view?.isActive) } as AITableView;
});

constructor(
private iconRegistry: ThyIconRegistry,
private sanitizer: DomSanitizer,
Expand Down Expand Up @@ -227,6 +259,7 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {

aiTableInitialized(aiTable: AITable) {
this.aiTable = aiTable;
(this.aiTable as AIViewTable).views = this.views;
}

setLocalData(data: string) {
Expand All @@ -238,6 +271,9 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
return data ? JSON.parse(data) : initValue;
}

changeRowHeight(event: string) {
CustomActions.setView(this.aiTable as any, this.activeView(), [0]);
}

disconnect() {
if (this.provider) {
Expand Down
20 changes: 20 additions & 0 deletions src/app/plugins/custom-action.plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { AITable, AITableAction, FLUSHING } from '@ai-table/grid';
import { CustomActions } from '../action';
import { AIViewAction, AIViewTable } from '../types/view';

export const withCustomApply = (aiTable: AITable) => {
const viewTable = aiTable as AIViewTable;
viewTable.viewApply = (action: AIViewAction) => {
aiTable.actions.push(action as unknown as AITableAction);
CustomActions.transform(viewTable, action);
if (!FLUSHING.get(aiTable)) {
FLUSHING.set(aiTable, true);
Promise.resolve().then(() => {
FLUSHING.set(aiTable, false);
aiTable.onChange();
aiTable.actions = [];
});
}
};
return aiTable;
};
47 changes: 47 additions & 0 deletions src/app/types/view.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { AITable } from '@ai-table/grid';
import { Direction } from '@angular/cdk/bidi';
import { Signal, WritableSignal } from '@angular/core';

export enum RowHeight {
short = 'short',
medium = 'medium',
tall = 'tall'
}

export interface AITableView {
id: string;
name: string;
emoji_icon?: string;
isActive?: boolean;
rowHeight?: RowHeight;
sortCondition?: {
keepSort: boolean;
conditions: {
sortBy: string;
direction: Direction;
}[];
};
// filterCondition?: {
// fieldKey: string;
// operation: OperationSymbol;
// logical: LogicalOperator;
// value?: SafeAny;
// disabled?: boolean;
// }[];
}

export enum ViewActionName {
setView = 'set_view'
}

export interface AIViewAction {
type: ViewActionName.setView;
view: AITableView;
newView: AITableView;
path: [number];
}

export interface AIViewTable extends AITable {
views: WritableSignal<AITableView[]>;
viewApply: (action: AIViewAction) => void;
}

0 comments on commit 024fa5f

Please sign in to comment.