Skip to content

Commit

Permalink
feat(core): set kanban field id
Browse files Browse the repository at this point in the history
  • Loading branch information
nichenqin committed Dec 31, 2022
1 parent 35bc857 commit f078435
Show file tree
Hide file tree
Showing 21 changed files with 121 additions and 35 deletions.
4 changes: 2 additions & 2 deletions apps/web/components/kanban-ui/kanban.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { QueryRecords } from '@egodb/core'
import { ITableBaseProps } from '../table/table-base-props'
import type { QueryRecords } from '@egodb/core'
import type { ITableBaseProps } from '../table/table-base-props'
import { SelectKanbanField } from './select-kanban-field'

interface IProps extends ITableBaseProps {
Expand Down
10 changes: 8 additions & 2 deletions apps/web/components/kanban-ui/select-kanban-field.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { setKanbanFieldSchema } from '@egodb/core'
import { Button, Card, Center, Container, Group, Radio, Text, useForm, zodResolver } from '@egodb/ui'
import { trpc } from '../../trpc'
import { ITableBaseProps } from '../table/table-base-props'
import type { ITableBaseProps } from '../table/table-base-props'

export const SelectKanbanField: React.FC<ITableBaseProps> = ({ table }) => {
const selectFields = table.schema.selectFields
const setKanbanField = trpc.table.setKanbanField.useMutation()
const utils = trpc.useContext()
const setKanbanField = trpc.table.setKanbanField.useMutation({
onSuccess() {
utils.table.get.refetch()
},
})

const form = useForm({
initialValues: {
field: '',
Expand Down
1 change: 1 addition & 0 deletions packages/core/__snapshots__/table.factory.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ ResultType {
},
"fieldsOrder": undefined,
"filter": undefined,
"kanban": undefined,
"name": ViewName {
"props": {
"value": "table",
Expand Down
1 change: 1 addition & 0 deletions packages/core/__snapshots__/table.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ Table {
},
"fieldsOrder": undefined,
"filter": undefined,
"kanban": undefined,
"name": ViewName {
"props": {
"value": "name",
Expand Down
1 change: 1 addition & 0 deletions packages/core/fixtures/table.fixtuer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ test('createTestTable', () => {
},
"fieldsOrder": undefined,
"filter": undefined,
"kanban": undefined,
"name": ViewName {
"props": {
"value": "name",
Expand Down
2 changes: 2 additions & 0 deletions packages/core/specifications/interface.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { CompositeSpecification, ISpecVisitor } from '@egodb/domain'
import { type ISpecification } from '@egodb/domain'
import { type Table } from '../table'
import type { WithKanbanField } from '../view'
import type { WithDisplayType } from '../view/specifications/display-type.specification'
import type { WithFilter } from './filters.specificaiton'
import type { WithNewField } from './table-field.specification'
Expand All @@ -26,6 +27,7 @@ export interface ITableSpecVisitor extends ISpecVisitor {
fieldVisibility(s: WithFieldVisibility): void

displayTypeEqual(s: WithDisplayType): void
kanbanFieldEqual(s: WithKanbanField): void
}

export type ITableSpec = ISpecification<Table, ITableSpecVisitor>
Expand Down
6 changes: 3 additions & 3 deletions packages/core/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ export class Table {

public switchDisplayType(input: ISwitchDisplayTypeSchema): TableCompositeSpecificaiton {
const view = this.mustGetView(input.viewName)
const spec = view.switchDisplayType(view.name.unpack(), input.displayType)
const spec = view.switchDisplayType(input.displayType)
spec.mutate(this)
return spec
}
Expand All @@ -184,8 +184,8 @@ export class Table {

public setKanbanField(input: ISetKanbanFieldSchema): TableCompositeSpecificaiton {
const view = this.mustGetView(input.viewName)
const field = this.schema.getField(input.field).unwrap()
const spec = view.setKanbanField(field.id)
const field = this.schema.getFieldById(input.field).unwrap()
const spec = view.setKanbanFieldSpec(field.id)
spec.mutate(this)
return spec
}
Expand Down
7 changes: 6 additions & 1 deletion packages/core/value-objects/table-schema.vo.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { ValueObject } from '@egodb/domain'
import { Option } from 'oxide.ts'
import * as z from 'zod'
import { createFieldSchema, Field, fieldNameSchema, ICreateFieldSchema, SelectField } from '../field'
import type { Field, ICreateFieldSchema } from '../field'
import { createFieldSchema, fieldNameSchema, SelectField } from '../field'
import { FieldFactory } from '../field/field.factory'
import type { TableCompositeSpecificaiton } from '../specifications/interface'
import { WithNewField } from '../specifications/table-field.specification'
Expand Down Expand Up @@ -55,6 +56,10 @@ export class TableSchema extends ValueObject<Field[]> {
return Option(this.fields.find((f) => f.name.value === name))
}

public getFieldById(id: string): Option<Field> {
return Option(this.fields.find((f) => f.id.value === id))
}

public addField(field: Field) {
this.props.push(field)
}
Expand Down
4 changes: 3 additions & 1 deletion packages/core/view/kanban.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@ import { z } from 'zod'
import { fieldIdSchema } from '../field'

export const kanbanSchema = z.object({
selectField: fieldIdSchema,
fieldId: fieldIdSchema.optional(),
})

export type IKanbanSchema = z.infer<typeof kanbanSchema>
16 changes: 14 additions & 2 deletions packages/core/view/kanban.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
import { ValueObject } from '@egodb/domain'
import { FieldId } from '../field'
import type { IKanbanSchema } from './kanban.schema'
import type { IKanban } from './kanban.type'

export class Kanban extends ValueObject<IKanban> {
public get selectField() {
return this.props.selectField
static from(input: IKanbanSchema) {
return new this({
fieldId: input.fieldId ? FieldId.from(input.fieldId) : undefined,
})
}

public get fieldId() {
return this.props.fieldId
}

public set fieldId(fieldId: FieldId | undefined) {
this.props.fieldId = fieldId
}
}
2 changes: 1 addition & 1 deletion packages/core/view/kanban.type.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { FieldId } from '../field'

export interface IKanban {
selectField: FieldId
fieldId?: FieldId
}
10 changes: 5 additions & 5 deletions packages/core/view/specifications/display-type.specification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@ import type { Result } from 'oxide.ts'
import { Ok } from 'oxide.ts'
import type { ITableSpecVisitor } from '../../specifications'
import type { Table } from '../../table'
import type { View } from '../view'
import type { IViewDisplayType } from '../view.type'

export class WithDisplayType extends CompositeSpecification<Table, ITableSpecVisitor> {
constructor(public readonly viewName: string, public readonly displayType: IViewDisplayType) {
constructor(public readonly view: View, public readonly displayType: IViewDisplayType) {
super()
}

isSatisfiedBy(t: Table): boolean {
return t.mustGetView(this.viewName).displayType === this.displayType
isSatisfiedBy(): boolean {
return this.view.displayType === this.displayType
}

mutate(t: Table): Result<Table, string> {
const view = t.mustGetView(this.viewName)
view.displayType = this.displayType
this.view.displayType = this.displayType
return Ok(t)
}

Expand Down
23 changes: 14 additions & 9 deletions packages/core/view/specifications/kanban.specification.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
import { CompositeSpecification } from '@egodb/domain'
import { Result } from 'oxide.ts/dist'
import { FieldId } from '../../field'
import { ITableSpecVisitor } from '../../specifications'
import { Table } from '../../table'
import { View } from '../view'
import type { Result } from 'oxide.ts'
import { Ok } from 'oxide.ts'
import type { FieldId } from '../../field'
import type { ITableSpecVisitor } from '../../specifications'
import type { Table } from '../../table'
import type { View } from '../view'

export class WithKanbanField extends CompositeSpecification<Table, ITableSpecVisitor> {
constructor(public readonly view: View, public readonly fieldId: FieldId) {
super()
}

isSatisfiedBy(t: Table): boolean {
throw new Error('Method not implemented.')
isSatisfiedBy(): boolean {
return this.view.kanbanSelectFieldId.mapOr(false, (fieldId) => fieldId.equals(this.fieldId))
}

mutate(t: Table): Result<Table, string> {
throw new Error('Method not implemented.')
this.view.getOrCreateKanban().fieldId = this.fieldId
return Ok(t)
}

accept(v: ITableSpecVisitor): Result<void, string> {
throw new Error('Method not implemented.')
v.kanbanFieldEqual(this)
return Ok(undefined)
}
}
3 changes: 3 additions & 0 deletions packages/core/view/view-name.vo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { z } from 'zod'
export const viewNameSchema = z.string().min(1, { message: 'view name should has at least one character' })

export class ViewName extends ValueObject<string> {
public get value() {
return this.props.value
}
static create(name: string): ViewName {
return new ViewName({ value: viewNameSchema.parse(name) })
}
Expand Down
3 changes: 3 additions & 0 deletions packages/core/view/view.schema.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { z } from 'zod'
import { fieldIdSchema, fieldNameSchema } from '../field'
import { rootFilter } from '../filter/filter'
import { kanbanSchema } from './kanban.schema'
import { fieldHiddenSchema, fieldWidthSchema, viewFieldOption } from './view-field-options'
import { viewNameSchema } from './view-name.vo'

export const viewDisplayType = z.enum(['grid', 'kanban'])

export const createViewInput_internal = z.object({
name: viewNameSchema,
kanban: kanbanSchema.optional(),
displayType: viewDisplayType.optional(),
filter: rootFilter.optional(),
fieldOptions: z.record(viewFieldOption).optional(),
Expand All @@ -16,6 +18,7 @@ export const createViewInput_internal = z.object({

export const queryView = z.object({
name: z.string(),
kanban: kanbanSchema.optional(),
displayType: viewDisplayType,
filter: rootFilter.optional(),
fieldOptions: z.record(viewFieldOption).optional(),
Expand Down
19 changes: 14 additions & 5 deletions packages/core/view/view.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { CompositeSpecification } from '@egodb/domain'
import { ValueObject } from '@egodb/domain'
import { None, Option } from 'oxide.ts'
import { FieldId } from '../field'
import type { FieldId } from '../field'
import type { IFilterOrGroupList, IRootFilter } from '../filter'
import { RootFilter } from '../filter'
import type { TableCompositeSpecificaiton } from '../specifications/interface'
Expand Down Expand Up @@ -40,7 +40,7 @@ export class View extends ValueObject<IView> {
}

public get kanbanSelectFieldId(): Option<FieldId> {
return this.kanban.mapOr(None, (kanban) => Option(kanban.selectField))
return this.kanban.mapOr(None, (kanban) => Option(kanban.fieldId))
}

public get spec(): Option<CompositeSpecification> {
Expand Down Expand Up @@ -68,6 +68,14 @@ export class View extends ValueObject<IView> {
return this.fieldOptions.getOrCreateOption(fieldName)
}

public getOrCreateKanban(): Kanban {
const kanban = this.kanban
if (kanban.isSome()) return kanban.unwrap()

this.props.kanban = new Kanban({})
return this.props.kanban
}

public getFieldHidden(fieldName: string): boolean {
return this.fieldOptions.getHidden(fieldName)
}
Expand All @@ -80,15 +88,15 @@ export class View extends ValueObject<IView> {
return new WithFieldWidth(fieldName, this.name.unpack(), width)
}

public switchDisplayType(viewName: string, type: IViewDisplayType): TableCompositeSpecificaiton {
return new WithDisplayType(viewName, type)
public switchDisplayType(type: IViewDisplayType): TableCompositeSpecificaiton {
return new WithDisplayType(this, type)
}

public setFieldVisibility(fieldName: string, hidden: boolean): TableCompositeSpecificaiton {
return new WithFieldVisibility(fieldName, this.name.unpack(), hidden)
}

public setKanbanField(fieldId: FieldId): TableCompositeSpecificaiton {
public setKanbanFieldSpec(fieldId: FieldId): TableCompositeSpecificaiton {
return new WithKanbanField(this, fieldId)
}

Expand All @@ -115,6 +123,7 @@ export class View extends ValueObject<IView> {
const parsed = createViewInput_internal.parse(input)
return new View({
name: ViewName.create(parsed.name),
kanban: input.kanban ? Kanban.from(input.kanban) : undefined,
displayType: parsed.displayType || defaultViewDiaplyType,
filter: parsed.filter ? new RootFilter(parsed.filter) : undefined,
fieldOptions: ViewFieldOptions.from(input.fieldOptions),
Expand Down
4 changes: 3 additions & 1 deletion packages/core/view/view.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,24 @@ import type { z } from 'zod'
import type { IRootFilter } from '../filter'
import type { RootFilter } from '../filter/root-filter'
import type { Kanban } from './kanban'
import type { IKanbanSchema } from './kanban.schema'
import type { IViewFieldOption, ViewFieldOptions } from './view-field-options'
import type { ViewFieldsOrder } from './view-fields-order.vo'
import type { ViewName } from './view-name.vo'
import type { createViewInput_internal, viewDisplayType } from './view.schema'

export interface IView {
name: ViewName
kanban?: Kanban
displayType: IViewDisplayType
filter?: RootFilter
fieldOptions: ViewFieldOptions
fieldsOrder?: ViewFieldsOrder
kanban?: Kanban
}

export interface IQueryView {
name: string
kanban?: IKanbanSchema
displayType: IViewDisplayType
filter?: IRootFilter
fieldOptions?: Record<string, IViewFieldOption>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Field, Table, TableSchema, View, Views } from '@egodb/core'
import { TableFactory } from '@egodb/core'
import type { Result } from 'oxide.ts'
import type { FieldInMemory, SchemaInMemory, TableInMemory, ViewInMemory, ViewsInMemory } from './table'
import type { FieldInMemory, KanbanInMemory, SchemaInMemory, TableInMemory, ViewInMemory, ViewsInMemory } from './table'

export class TableInMemoryMapper {
static toDomain(t: TableInMemory): Result<Table, string> {
Expand Down Expand Up @@ -35,9 +35,18 @@ export class TableInMemoryMapper {
return schema.fields.map((f) => this.fieldToInMemopy(f))
}

static kanbanToInMemory(v: View): KanbanInMemory | undefined {
if (v.kanban.isSome()) {
return { fieldId: v.kanban.unwrap().fieldId?.value }
}

return undefined
}

static viewToInMemory(v: View): ViewInMemory {
return {
name: v.name.unpack(),
kanban: this.kanbanToInMemory(v),
displayType: v.displayType,
filter: v.filter?.value,
fieldOptions: Object.fromEntries(v.fieldOptions.value),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
WithFieldVisibility,
WithFieldWidth,
WithFilter,
WithKanbanField,
WithNewField,
WithTableName,
WithTableSchema,
Expand Down Expand Up @@ -89,9 +90,20 @@ export class TableInMemoryMutationVisitor implements ITableSpecVisitor {
}

displayTypeEqual(s: WithDisplayType): void {
const view = this.table.views.find((v) => v.name === s.viewName)
const view = this.table.views.find((v) => v.name === s.view.name.value)
if (view) {
view.displayType = s.displayType
}
}

kanbanFieldEqual(s: WithKanbanField): void {
const view = this.table.views.find((v) => v.name === s.view.name.value)
if (view) {
if (view.kanban) {
view.kanban.fieldId = s.fieldId.value
} else {
view.kanban = { fieldId: s.fieldId.value }
}
}
}
}
Loading

0 comments on commit f078435

Please sign in to comment.