Skip to content

Commit

Permalink
refactor: new data service
Browse files Browse the repository at this point in the history
  • Loading branch information
ImJeremyHe committed Dec 14, 2024
1 parent bdf1bd9 commit 14a11e3
Show file tree
Hide file tree
Showing 32 changed files with 574 additions and 566 deletions.
65 changes: 65 additions & 0 deletions packages/web/src/api/cell.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import {CellInfo, Value, Style} from '../bindings'

export class Cell {
public constructor(cellInfo: CellInfo) {
this._value = CellValue.from(cellInfo.value)
this._formula = cellInfo.formula
this._style = cellInfo.style
}

public getText(): string {
return this._value.valueStr ?? ''
}

public getStyle(): Style {
return this._style
}

public getFormula(): string {
return this._formula
}

private _value: CellValue
private _style: Style
private _formula = ''
}

export class CellValue {
cellValueOneof?:
| {$case: 'str'; str: string}
| {$case: 'number'; number: number}
| {$case: 'bool'; bool: boolean}
| {$case: 'error'; error: string}
get value() {
if (this.cellValueOneof?.$case === 'str') return this.cellValueOneof.str
else if (this.cellValueOneof?.$case === 'bool')
return this.cellValueOneof.bool
else if (this.cellValueOneof?.$case === 'error')
return this.cellValueOneof.error
else if (this.cellValueOneof?.$case === 'number')
return this.cellValueOneof.number
else return ''
}
get valueStr() {
return this.value.toString()
}
static from(value: Value) {
const v = new CellValue()
if (hasOwnProperty(value, 'str'))
v.cellValueOneof = {$case: 'str', str: value.str as string}
else if (hasOwnProperty(value, 'bool'))
v.cellValueOneof = {$case: 'bool', bool: value.bool as boolean}
else if (hasOwnProperty(value, 'number'))
v.cellValueOneof = {$case: 'number', number: value.number as number}
else if (hasOwnProperty(value, 'error'))
v.cellValueOneof = {$case: 'error', error: value.error as string}
return v
}
}

function hasOwnProperty<T, K extends PropertyKey>(
obj: T,
prop: K
): obj is T & Record<K, unknown> {
return Object.prototype.hasOwnProperty.call(obj, prop)
}
4 changes: 2 additions & 2 deletions packages/web/src/api/workbook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ export class Workbook {
return get_all_sheet_info(this._id)
}

public execTransaction(tx: Transaction, undoable: boolean): ActionEffect {
public execTransaction(tx: Transaction): ActionEffect {
transaction_start(this._id)
tx.payloads.forEach((p: Payload) => {
this._addPayload(p)
})
const result = transaction_end(this._id, undoable) as ActionEffect
const result = transaction_end(this._id, tx.undoable) as ActionEffect
if (result.asyncTasks.length > 0) {
const asyncResult = this._calculator.calc(result.asyncTasks)
asyncResult.then((result) => {
Expand Down
11 changes: 8 additions & 3 deletions packages/web/src/api/worksheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import {
Value,
} from '../bindings'
import {CellInfo} from '../bindings/cell_info'
import {Result} from './utils'
import {Cell} from './cell'
import {isErrorMessage, Result} from './utils'

export class Worksheet {
public constructor(id: number, idx: number) {
Expand Down Expand Up @@ -98,13 +99,17 @@ export class Worksheet {
return get_col_info(this._id, this._sheetIdx, colIdx) as Result<ColInfo>
}

public getCellInfo(rowIdx: number, colIdx: number): Result<CellInfo> {
return get_cell_info(
public getCell(rowIdx: number, colIdx: number): Result<Cell> {
const cellInfo = get_cell_info(
this._id,
this._sheetIdx,
rowIdx,
colIdx
) as Result<CellInfo>
if (isErrorMessage(cellInfo)) {
return cellInfo
}
return new Cell(cellInfo)
}

public getFormula(rowIdx: number, colIdx: number): Result<string> {
Expand Down
23 changes: 18 additions & 5 deletions packages/web/src/transactions.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
import {Payload} from './payloads'

export class Transaction {
public constructor(payloads: Payload[], public readonly undoable: boolean) {
this.payloads = payloads
public constructor(
public payloads: readonly Payload[],
public readonly undoable: boolean
) {}
}

export class TransactionBuilder {
public payload(p: Payload): this {
this._payloads.push(p)
return this
}

public addPayload(p: Payload): Transaction {
this.payloads.push(p)
public undoable(v: boolean): this {
this._undoable = v
return this
}

public payloads: Payload[] = []
public build(): Transaction {
return new Transaction(this._payloads, this._undoable)
}

private _payloads: Payload[] = []
private _undoable = true
}
27 changes: 14 additions & 13 deletions src/components/content/edit-bar.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import {SelectedCell} from '@/components/canvas'
import {toA1notation, parseA1notation} from '@/core'
import {CellInputBuilder} from '@logisheets_bg'
import {CellInputBuilder, Transaction} from '@logisheets_bg'
import {FC, useEffect, useState} from 'react'
import styles from './edit-bar.module.scss'
import {useInjection} from '@/core/ioc/provider'
import {Backend, SheetService} from '@/core/data'
import {DataService} from '@/core/data2'
import {TYPES} from '@/core/ioc/types'
import {isErrorMessage} from 'packages/web/src/api/utils'
export interface EditBarProps {
selectedCell: SelectedCell
selectedCell$: (e: SelectedCell) => void
Expand All @@ -15,27 +16,27 @@ export const EditBarComponent: FC<EditBarProps> = ({
selectedCell,
selectedCell$,
}) => {
const sheetSvc = useInjection<SheetService>(TYPES.Sheet)
const backendSvc = useInjection<Backend>(TYPES.Backend)
const dataSvc = useInjection<DataService>(TYPES.Data)
const [coordinate, setCoordinate] = useState('')
const [formula, setFormula] = useState('')
useEffect(() => {
const {row, col} = selectedCell
const notation = toA1notation(selectedCell.col)
setCoordinate(`${notation}${row + 1}`)
const cell = sheetSvc.getCell(row, col)
if (cell === undefined) return
if (cell.formula === '') setFormula(cell.getText())
else setFormula(cell.getFormular())
const sheet = dataSvc.getActiveSheet()
const cell = sheet.getCell(row, col)
if (isErrorMessage(cell)) return
if (cell.getFormula() === '') setFormula(cell.getText())
else setFormula(cell.getFormula())
}, [selectedCell])
const formulaTextChange = (newText: string) => {
const payload = new CellInputBuilder()
.sheetIdx(sheetSvc.getActiveSheet())
.sheetIdx(dataSvc.getCurrentSheetIdx())
.row(selectedCell.row)
.col(selectedCell.col)
.input(newText)
.build()
backendSvc.sendTransaction([payload], true)
dataSvc.handleTransaction(new Transaction([payload], true))
}
const locationChange = (newText: string) => {
const result = parseA1notation(newText)
Expand All @@ -52,13 +53,13 @@ export const EditBarComponent: FC<EditBarProps> = ({
className={styles.a1notation}
defaultValue={coordinate}
onBlur={(e) => locationChange(e.target.value)}
></input>
<div className={styles.middle}></div>
/>
<div className={styles.middle} />
<input
className={styles.formula}
onChange={(e) => formulaTextChange(e.target.value)}
value={formula}
></input>
/>
</div>
)
}
6 changes: 3 additions & 3 deletions src/components/content/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ export const ContentComponent: FC<ContentProps> = ({
<EditBarComponent
selectedCell={selectedCell}
selectedCell$={selectedCell$}
></EditBarComponent>
/>
<div className={styles.middle}>
<div className={styles.canvas}>
<CanvasComponent
selectedCell={selectedCell}
selectedCell$={selectedCell$}
></CanvasComponent>
/>
</div>
</div>
<SheetsTabComponent></SheetsTabComponent>
<SheetsTabComponent />
</div>
)
}
4 changes: 2 additions & 2 deletions src/components/dnd/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const DndComponent: FC<DndProps> = ({
<div
className={styles['dragging-mask']}
data-selector-dnd-mask
></div>
/>
</div>
<div
className={styles.dragging}
Expand All @@ -48,7 +48,7 @@ export const DndComponent: FC<DndProps> = ({
width: `${width}px`,
height: `${height}px`,
}}
></div>
/>
</div>
)
}
14 changes: 9 additions & 5 deletions src/components/sheets-tab/contextmenu.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import {SheetRenameBuilder, DeleteSheetBuilder} from '@logisheets_bg'
import {
SheetRenameBuilder,
DeleteSheetBuilder,
Transaction,
} from '@logisheets_bg'
import {useState} from 'react'
import Modal from 'react-modal'
import {Backend} from '@/core/data'
import {DataService} from '@/core/data2'
import {useInjection} from '@/core/ioc/provider'
import {TYPES} from '@/core/ioc/types'

Expand All @@ -17,7 +21,7 @@ export const ContextMenuComponent = (props: ContextMenuProps) => {
const [renameIsOpen, setRenameIsOpen] = useState(false)
const oldName = sheetnames[index]
const [sheetName, setSheetName] = useState(oldName)
const BACKEND_SERVICE = useInjection<Backend>(TYPES.Sheet)
const DATA_SERVICE = useInjection<DataService>(TYPES.Data)
const openRename = () => {
setRenameIsOpen(true)
setIsOpen(false)
Expand All @@ -28,12 +32,12 @@ export const ContextMenuComponent = (props: ContextMenuProps) => {
.oldName(oldName)
.newName(sheetName)
.build()
BACKEND_SERVICE.sendTransaction([sheetRename])
DATA_SERVICE.handleTransaction(new Transaction([sheetRename], true))
}

const deleteSheet = () => {
const payload = new DeleteSheetBuilder().sheetIdx(index).build()
BACKEND_SERVICE.sendTransaction([payload])
DATA_SERVICE.handleTransaction(new Transaction([payload], true))
}
return (
<div>
Expand Down
21 changes: 10 additions & 11 deletions src/components/sheets-tab/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,25 @@ import {useState, FC, useEffect} from 'react'
import styles from './sheets-tab.module.scss'
import {ContextMenuComponent} from './contextmenu'
import {DeleteSheetBuilder, InsertSheetBuilder} from '@logisheets_bg'
import {Backend, SheetService} from '@/core/data'
import {useInjection} from '@/core/ioc/provider'
import {TYPES} from '@/core/ioc/types'
import {Tabs, Dropdown} from 'antd'
import {Subscription} from 'rxjs'
import {DataService} from '@/core/data2'

export type SheetsTabprops = Record<string, unknown>

export const SheetsTabComponent: FC<SheetsTabprops> = () => {
const BACKEND_SERVICE = useInjection<Backend>(TYPES.Backend)
const SHEET_SERVICE = useInjection<SheetService>(TYPES.Sheet)
const getSheets = () => SHEET_SERVICE.getSheets().map((s) => s.name)
const DATASERVICE = useInjection<DataService>(TYPES.Data)
const getSheets = () => DATASERVICE.getSheets().map((s) => s.name)
const [sheets, setSheets] = useState(getSheets())
const [active, setActive] = useState(0)
const [isOpen, setIsOpen] = useState(false)

useEffect(() => {
const subs = new Subscription()
subs.add(
BACKEND_SERVICE.render$.subscribe(() => {
DATASERVICE.render$.subscribe(() => {
setSheets(getSheets())
})
)
Expand All @@ -38,16 +37,16 @@ export const SheetsTabComponent: FC<SheetsTabprops> = () => {

const add = () => {
const payload = new InsertSheetBuilder().sheetIdx(active).build()
BACKEND_SERVICE.sendTransaction([payload])
DATASERVICE.sendTransaction([payload])
}

const onDelete = (i: number) => {
const payload = new DeleteSheetBuilder().sheetIdx(i).build()
BACKEND_SERVICE.sendTransaction([payload])
DATASERVICE.sendTransaction([payload])
}
return (
<div className={styles['host']}>
<div className={styles['pre-btns']}></div>
<div className={styles['pre-btns']} />
<Tabs
type="editable-card"
tabPosition="bottom"
Expand All @@ -73,21 +72,21 @@ export const SheetsTabComponent: FC<SheetsTabprops> = () => {
const payload = new InsertSheetBuilder()
.sheetIdx(sheets.length)
.build()
BACKEND_SERVICE.sendTransaction([payload])
DATASERVICE.sendTransaction([payload])
} else if (action === 'remove') {
if (typeof e !== 'string') return
const i = sheets.findIndex((s) => s === e)
onDelete(i)
}
}}
activeKey={sheets[active]}
></Tabs>
/>
<ContextMenuComponent
isOpen={isOpen}
setIsOpen={setIsOpen}
index={active}
sheetnames={sheets}
></ContextMenuComponent>
/>
</div>
)
}
Loading

0 comments on commit 14a11e3

Please sign in to comment.