Skip to content

Commit

Permalink
feat: support views share #WIK-16187
Browse files Browse the repository at this point in the history
  • Loading branch information
cmm-va committed Jul 30, 2024
1 parent 024fa5f commit db0bdca
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 23 deletions.
5 changes: 5 additions & 0 deletions src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
<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>

{{ activeView().sortCondition | json }}

<thy-button thyButton="primary" (click)="sort()">排序</thy-button>

<ai-table-grid
[(aiRecords)]="records"
[(aiFields)]="fields"
Expand Down
39 changes: 30 additions & 9 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AfterViewInit, Component, OnDestroy, computed, OnInit, Signal, signal, WritableSignal } from '@angular/core';
import { AfterViewInit, Component, OnDestroy, computed, OnInit, Signal, signal, WritableSignal , effect, untracked } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { RouterOutlet } from '@angular/router';
import {
Expand All @@ -19,16 +19,18 @@ 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 { JsonPipe, NgFor } from '@angular/common';
import { CustomActions } from './action';
import { AITableView, AIViewTable, RowHeight } from './types/view';
import { AITableView, AIViewTable, Direction, RowHeight } from './types/view';
import { WebsocketProvider } from 'y-websocket';
import { connectProvider } from './share/provider';
import { SharedType, getSharedType } from './share/shared';
import { YjsAITable } from './share/yjs-table';
import applyActionOps from './share/apply-to-yjs';
import { applyYjsEvents } from './share/apply-to-table';
import { translateSharedTypeToTable } from './share/utils/translate-to-table';
import { ThyButton } from 'ngx-tethys/button';


const LOCAL_STORAGE_KEY = 'ai-table-data';

Expand All @@ -43,7 +45,7 @@ const initValue = {
url: 'https://www.baidu.com',
text: '百度链接'
},
'column-4': 3
'column-4': 1
}
},
{
Expand All @@ -52,7 +54,7 @@ const initValue = {
'column-1': '文本 2-1',
'column-2': '2',
'column-3': {},
'column-4': 1
'column-4': 3
}
},
{
Expand All @@ -61,7 +63,7 @@ const initValue = {
'column-1': '文本 3-1',
'column-2': '3',
'column-3': {},
'column-4': 1
'column-4': 2
}
}
],
Expand Down Expand Up @@ -131,7 +133,7 @@ const initValue = {
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet, AITableGrid, ThyPopoverModule, FieldPropertyEditor, ThySelect, FormsModule, NgFor, ThyOption],
imports: [RouterOutlet, AITableGrid, ThyPopoverModule, FieldPropertyEditor, ThySelect, FormsModule, NgFor, ThyOption, ThyButton , JsonPipe],
templateUrl: './app.component.html',
styleUrl: './app.component.scss'
})
Expand Down Expand Up @@ -184,7 +186,7 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
};

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

constructor(
Expand All @@ -193,6 +195,16 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
private thyPopover: ThyPopover
) {
this.registryIcon();
effect(()=>{
const sortCondition = this.activeView().sortCondition;
if(sortCondition){
untracked(()=>{
const {sortBy, direction} = sortCondition?.conditions[0]
const records = this.records().sort((a:any,b:any)=>{ return direction === Direction.ascending ? a.value[sortBy] - b.value[sortBy] : b.value[sortBy] - a.value[sortBy] });
this.records.set([...records])
})
}
},{allowSignalWrites:true})
}

ngOnInit(): void {
Expand All @@ -208,7 +220,8 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
this.sharedType = getSharedType(
{
records: this.records(),
fields: this.fields()
fields: this.fields(),
views: this.views()
},
!!isInitializeSharedType
);
Expand All @@ -221,6 +234,7 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
console.log(123, data);
this.records.set(data.records);
this.fields.set(data.fields);
this.views.set(data.views);
isInitialized = true;
} else {
applyYjsEvents(this.aiTable, events);
Expand Down Expand Up @@ -282,6 +296,13 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
}
}

sort(){
const direction = this.activeView().sortCondition?.conditions[0].direction
const sortCondition = { keepSort:true , conditions:[{sortBy: 'column-4', direction: direction=== Direction.ascending ? Direction.descending: Direction.ascending}]}
this.activeView().sortCondition = sortCondition
CustomActions.setView(this.aiTable as any, this.activeView(), [0]);
}

ngOnDestroy(): void {
this.disconnect();
}
Expand Down
16 changes: 16 additions & 0 deletions src/app/share/apply-to-table/array-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import { ActionName, AIFieldValuePath, AITable, AITableAction, AITableField, AIT
import * as Y from 'yjs';
import { toTablePath, translateRecord } from '../utils/translate-to-table';
import { isArray } from 'ngx-tethys/util';
import { AIViewTable, ViewActionName } from '../../types/view';

export default function translateArrayEvent(aiTable: AITable, event: Y.YEvent<any>): AITableAction[] {
const actions: AITableAction[] = [];
let offset = 0;
let targetPath = toTablePath(event.path);
const isRecordsTranslate = event.path.includes('records');
const isFieldsTranslate = event.path.includes('fields');
const isViewsTranslate = event.path.includes('views');

event.changes.delta.forEach((delta) => {
if ('retain' in delta) {
Expand Down Expand Up @@ -60,6 +62,20 @@ export default function translateArrayEvent(aiTable: AITable, event: Y.YEvent<an
}
});
}
if(isViewsTranslate){
delta.insert?.map((item: Y.Map<any>, index) => {
const data = item.toJSON();
const view = (aiTable as AIViewTable).views()[index]
if (event.path.includes('views')) {
actions.push({
type: ViewActionName.setView,
view ,
newView: data,
path: [index]
} as any);
}
});
}
}
}
});
Expand Down
26 changes: 16 additions & 10 deletions src/app/share/apply-to-table/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as Y from 'yjs';
import { AITable, AITableAction } from '@ai-table/grid';
import translateArrayEvent from './array-event';
import { YjsAITable } from '../yjs-table';
import { AIViewAction, AIViewTable } from '../../types/view';

export function translateYjsEvent(aiTable: AITable, event: Y.YEvent<any>): AITableAction[] {
if (event instanceof Y.YArrayEvent) {
Expand All @@ -10,20 +11,25 @@ export function translateYjsEvent(aiTable: AITable, event: Y.YEvent<any>): AITab
return [];
}

export function applyEvents(aiTable: AITable, events: Y.YEvent<any>[]){
events.forEach((event) =>
translateYjsEvent(aiTable, event).forEach((item: AIViewAction| AITableAction) => {
if(item.type === 'set_view'){
(aiTable as AIViewTable).viewApply(item)
}else {
aiTable.apply(item);
}

})
);
}

export function applyYjsEvents(aiTable: AITable, events: Y.YEvent<any>[]): void {
if (YjsAITable.isUndo(aiTable)) {
events.forEach((event) =>
translateYjsEvent(aiTable, event).forEach((item) => {
aiTable.apply(item);
})
);
applyEvents(aiTable, events)
} else {
YjsAITable.asRemote(aiTable, () => {
events.forEach((event) =>
translateYjsEvent(aiTable, event).forEach((item) => {
aiTable.apply(item);
})
);
applyEvents(aiTable, events)
});
}
}
6 changes: 4 additions & 2 deletions src/app/share/apply-to-yjs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@ import { SharedType } from '../shared';
import updateFieldValue from './update-field-value';
import addRecord from './add-record';
import addField from './add-field';
import setView from './set-view';

export type ActionMapper<O extends AITableAction = AITableAction> = {
[K in O['type']]: O extends { type: K } ? ApplyFunc<O> : never;
};

export type ApplyFunc<O extends AITableAction = AITableAction> = (sharedType: SharedType, op: O) => SharedType;

export const actionMappers: Partial<ActionMapper<AITableAction>> = {
export const actionMappers: Partial<ActionMapper<any>> = {
update_field_value: updateFieldValue,
add_record: addRecord,
add_field: addField
add_field: addField,
set_view: setView
};

export default function applyActionOps(sharedType: SharedType, actions: AITableAction[], aiTable: AITable): SharedType {
Expand Down
13 changes: 13 additions & 0 deletions src/app/share/apply-to-yjs/set-view.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { AIViewAction } from "../../types/view";
import { SharedType, toSyncElement } from "../shared";

export default function setView(sharedType: SharedType, action: AIViewAction): SharedType {
const views = sharedType.get('views');
if (views) {
const index = action.path[0];
views.delete(index);
views.insert(index, [toSyncElement(action.newView)]);
}

return sharedType;
}
7 changes: 7 additions & 0 deletions src/app/share/shared.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AITableFields, AITableRecord, AITableRecords } from '@ai-table/grid';
import { isArray, isObject } from 'ngx-tethys/util';
import * as Y from 'yjs';
import { AITableView } from '../types/view';

export type SyncMapElement = Y.Map<any>;
export type SyncArrayElement = Y.Array<Y.Array<any>>;
Expand All @@ -11,6 +12,7 @@ export const getSharedType = (
initializeValue: {
fields: AITableFields;
records: AITableRecords;
views: AITableView[]
},
isInitializeSharedType: boolean
) => {
Expand All @@ -27,6 +29,7 @@ export function toSharedType(
data: {
fields: AITableFields;
records: AITableRecords;
views: AITableView[]
}
): void {
const fieldSharedType = new Y.Array();
Expand All @@ -36,6 +39,10 @@ export function toSharedType(
const recordSharedType = new Y.Array<Y.Array<any>>();
sharedType.set('records', recordSharedType);
recordSharedType.insert(0, data.records.map(toRecordSyncElement));

const viewsSharedType = new Y.Array();
sharedType.set('views', viewsSharedType);
viewsSharedType.insert(0, data.views.map(toSyncElement))
}

export function toSyncElement(node: any): SyncMapElement {
Expand Down
4 changes: 3 additions & 1 deletion src/app/share/utils/translate-to-table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ export const translateSharedTypeToTable = (sharedType: SharedType) => {
value: translateRecord(customField, fields)
};
});
const views = data['views']
return {
records,
fields
fields,
views
};
};

Expand Down
7 changes: 6 additions & 1 deletion src/app/types/view.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { AITable } from '@ai-table/grid';
import { Direction } from '@angular/cdk/bidi';
import { Signal, WritableSignal } from '@angular/core';

export enum RowHeight {
Expand All @@ -8,6 +7,12 @@ export enum RowHeight {
tall = 'tall'
}

export enum Direction {
default = 0,
ascending = 1,
descending = -1
}

export interface AITableView {
id: string;
name: string;
Expand Down

0 comments on commit db0bdca

Please sign in to comment.