Skip to content

Commit

Permalink
feat: can render database
Browse files Browse the repository at this point in the history
  • Loading branch information
0xzio committed May 27, 2024
1 parent 3603971 commit 0d10a01
Show file tree
Hide file tree
Showing 27 changed files with 457 additions and 55 deletions.
1 change: 1 addition & 0 deletions apps/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@penx/api": "workspace:*",
"@penx/app": "workspace:*",
"@penx/cmdk": "workspace:*",
"@penx/cell-fields": "workspace:*",
"@penx/constants": "workspace:*",
"@penx/encryption": "workspace:*",
"@penx/event": "workspace:*",
Expand Down
15 changes: 3 additions & 12 deletions apps/desktop/src/common/installBuiltinExtension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ export async function installBuiltinExtension() {
isDeveloping: false,
commands: [
{
name: 'database',
title: 'Database',
icon: '/icons/copy.svg',
name: 'marketplace',
title: 'marketplace',
icon: '/icons/marketplace.svg',
subtitle: '',
description: '',
code: '',
Expand All @@ -35,15 +35,6 @@ export async function installBuiltinExtension() {
code: '',
isBuiltIn: true,
},
{
name: 'marketplace',
title: 'marketplace',
icon: '/icons/marketplace.svg',
subtitle: '',
description: '',
code: '',
isBuiltIn: true,
},
],
createdAt: new Date(),
updatedAt: new Date(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Spinner } from 'uikit'
import { Markdown } from '~/components/Markdown'
import { CommandAppUI } from '~/hooks/useCommandAppUI'
import { ClipboardHistoryApp } from './ClipboardHistoryApp'
import { DatabaseApp } from './DatabaseApp'
import { DatabaseApp } from './DatabaseApp/DatabaseApp'
import { ListApp } from './ListApp'
import { MarketplaceApp } from './MarketplaceApp/MarketplaceApp'
import { TodayApp } from './TodayApp'
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useQuery } from '@tanstack/react-query'
import { db } from '@penx/local-db'
import { useCurrentDatabase } from '~/hooks/useCurrentDatabase'
import { useSearch } from '~/hooks/useSearch'
import { StyledCommandGroup } from '../../CommandComponents'
import { DatabaseDetail } from './DatabaseDetail'

export function DatabaseApp() {
const { database } = useCurrentDatabase()
const { search } = useSearch()

const { data, isLoading } = useQuery({
queryKey: ['database', database.id],
queryFn: () => db.getDatabase(database.id),
})

if (isLoading || !data) {
return <StyledCommandGroup></StyledCommandGroup>
}

return <DatabaseDetail {...data} text={search} />
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { useEffect, useMemo } from 'react'
import { Box } from '@fower/react'
import { Divider } from 'uikit'
import {
ICellNode,
IColumnNode,
IDatabaseNode,
IOptionNode,
IRowNode,
IViewNode,
} from '@penx/model-types'
import { mappedByKey } from '@penx/shared'
import { useValue } from '~/hooks/useValue'
import { StyledCommandEmpty, StyledCommandGroup } from '../../CommandComponents'
import { ListItemUI } from '../../ListItemUI'
import { RowForm } from './RowForm'

interface Props {
text: string
database: IDatabaseNode
views: IViewNode[]
columns: IColumnNode[]
rows: IRowNode[]
cells: ICellNode[]
options: IOptionNode[]
}

interface Item {
row: IRowNode
cell: ICellNode
rowCells: ICellNode[]
}

export function DatabaseDetail(props: Props) {
const { value, setValue } = useValue()
const { text, ...rest } = props
const { columns, rows, views, cells } = rest
const currentView = views[0]
const { viewColumns = [] } = currentView.props
const columnMap = mappedByKey(columns, 'id')
const sortedColumns = viewColumns.map(({ columnId }) => columnMap[columnId])

const filteredRows: Item[] = useMemo(() => {
const items = rows
.map((row) => {
const rowCells = cells.filter((cell) => cell.props.rowId === row.id)

if (!text) {
const cell = rowCells.find(
(cell) => cell.props.columnId === sortedColumns[0].id,
)!
return { row, rowCells, cell }
}

const cell = rowCells.find((cell) => {
// console.log('cell-----:', cell.props.data)
const data = String(cell.props?.data || '').toLowerCase()
return data.includes(text.toLowerCase())
})!
return { row, rowCells, cell }
})
.filter((item) => !!item.cell)
.slice(0, 20)
return items
}, [rows, cells, text, sortedColumns])

useEffect(() => {
if (!isUuidV4(value) && filteredRows.length) {
setValue(filteredRows[0].row.id)
}
}, [filteredRows, value, setValue])

// console.log('=======filteredRows:', filteredRows, 'value:', value)
const currentItem = filteredRows.find((item) => item.row.id === value)

if (!filteredRows.length)
return (
<StyledCommandGroup block--i>
<StyledCommandEmpty gray500>No results found.</StyledCommandEmpty>
</StyledCommandGroup>
)

return (
<Box toLeft overflowHidden absolute top0 bottom0 left0 right0>
<StyledCommandGroup p2 flex-2 overflowYAuto>
{filteredRows.map((item, index) => {
// console.log('=======item:', item)

const listItem = {
title: dataToString(item.cell.props.data),
}
return (
<ListItemUI
key={index}
index={index}
showIcon={false}
value={item.row.id}
item={listItem}
/>
)
})}
</StyledCommandGroup>

<Divider orientation="vertical" />

<Box flex-3 overflowAuto p3>
{currentItem && <RowForm {...rest} rowId={currentItem.row.id} />}
</Box>
</Box>
)
}

function dataToString(data: any) {
if (!data) return 'Untitled'
if (typeof data === 'string') return data
if (typeof data === 'number') return data.toString()
if (Array.isArray(data)) return data.join(',')
return JSON.stringify(data, null)
}

function isUuidV4(uuid: string): boolean {
const uuidV4Regex =
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
return uuidV4Regex.test(uuid)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Box } from '@fower/react'
import {
CalendarDays,
CheckCircle2,
Hash,
Home,
Key,
Link,
ListChecks,
Text,
} from 'lucide-react'
import { FieldType } from '@penx/model-types'

interface Props {
index?: number
fieldType: `${FieldType}`
size?: number
}

export const FieldIcon = ({ fieldType, size = 16, index }: Props) => {
const iconsMap: Record<string, any> = {
[FieldType.TEXT]: Text,
[FieldType.NUMBER]: Hash,
[FieldType.URL]: Link,
[FieldType.PASSWORD]: Key,
[FieldType.SINGLE_SELECT]: CheckCircle2,
[FieldType.MULTIPLE_SELECT]: ListChecks,
[FieldType.MARKDOWN]: Text,
[FieldType.DATE]: CalendarDays,
[FieldType.CREATED_AT]: CalendarDays,
[FieldType.UPDATED_AT]: CalendarDays,
}
let Icon = iconsMap[fieldType]

if (index === 0) Icon = Home

if (Icon)
return (
<Box gray500 inlineFlex>
<Icon size={size} />
</Box>
)
return null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { forwardRef } from 'react'
import { Box } from '@fower/react'
import { CellField } from '@penx/cell-fields'
import {
ICellNode,
IColumnNode,
IDatabaseNode,
IOptionNode,
IRowNode,
IViewNode,
} from '@penx/model-types'
import { mappedByKey } from '@penx/shared'
import { FieldIcon } from './FieldIcon'

interface Props {
rowId: string
database: IDatabaseNode
views: IViewNode[]
columns: IColumnNode[]
rows: IRowNode[]
cells: ICellNode[]
options: IOptionNode[]
}

export const RowForm = forwardRef<HTMLDivElement, Props>(
function TagForm(props, ref) {
const { columns, views, cells, rowId } = props

// console.log('========cells;', cells, 'rowId:', rowId)

const currentView = views[0]

const columnMap = mappedByKey(columns, 'id')
const { viewColumns = [] } = currentView.props
const sortedColumns = viewColumns.map(({ columnId }) => columnMap[columnId])

const rowCells = sortedColumns.map((column) => {
return cells.find(
(cell) =>
cell.props.rowId === rowId && cell.props.columnId === column.id,
)!
})

// console.log('========rowCells:', rowCells)

return (
<Box ref={ref} column gap4>
{rowCells.map((cell, index) => {
// console.log('=====cell:', cell)

const column = columns.find((col) => col.id === cell.props.columnId)!

if (!column) return null

return (
<Box key={cell.id}>
<Box mb2 toCenterY gap1 gray600>
<FieldIcon fieldType={column.props.fieldType} />
<Box textXS>{column.props.displayName}</Box>
</Box>
<CellField index={index} cell={cell} columns={sortedColumns} />
</Box>
)
})}
</Box>
)
},
)
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ export const StyledCommandInput = styled(Command.Input)
export const StyledCommandList = styled(Command.List)

export const StyledCommandGroup = styled(Command.Group)

export const StyledCommandEmpty = styled(Command.Empty)
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@ export const CommandPaletteFooter = ({ footerHeight }: Props) => {
px4
toBetween
>
{currentCommand && (
{currentCommand && currentCommand.data.extensionIcon ? (
<ListItemIcon icon={currentCommand.data.extensionIcon} />
)}
{!currentCommand && (
) : (
<Image
src="/logo/128x128.png"
alt=""
Expand Down
21 changes: 21 additions & 0 deletions apps/desktop/src/components/CommandPalette/DatabaseName.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Box } from '@fower/react'
import { useCurrentDatabase } from '~/hooks/useCurrentDatabase'

export const DatabaseName = () => {
const { database } = useCurrentDatabase()
return (
<Box
h-30
roundedFull
px3
bg={database.props.color}
toCenter
mr--8
ml3
white
textXS
>
# {database.props.name}
</Box>
)
}
Loading

0 comments on commit 0d10a01

Please sign in to comment.