Skip to content

Commit

Permalink
Change sidebar tree creation to use path instead of parentId. Also move
Browse files Browse the repository at this point in the history
sidebar to web-ui
  • Loading branch information
andresgutgon committed Jul 19, 2024
1 parent 6d93bf1 commit 5f4611f
Show file tree
Hide file tree
Showing 8 changed files with 689 additions and 7 deletions.
13 changes: 11 additions & 2 deletions packages/web-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
"scripts": {
"lint": "eslint ./src",
"tc": "tsc --noEmit",
"prettier": "prettier --write src/**/*.ts"
"prettier": "prettier --write src/**/*.ts",
"test": "vitest run",
"test:watch": "vitest",
"test:debug": "pnpm run test:watch --inspect-brk --pool threads --poolOptions.threads.singleThread"
},
"type": "module",
"main": "src/index.ts",
Expand Down Expand Up @@ -47,10 +50,16 @@
"devDependencies": {
"@latitude-data/eslint-config": "workspace:*",
"@latitude-data/typescript-config": "workspace:*",
"@testing-library/dom": "^10.3.2",
"@testing-library/react": "^16.0.0",
"@testing-library/react-hooks": "^8.0.1",
"@types/react": "18.3.0",
"@types/react-dom": "18.3.0",
"autoprefixer": "^10.4.19",
"jsdom": "^24.1.0",
"postcss": "^8.4.39",
"tailwindcss": "^3.4.4"
"tailwindcss": "^3.4.4",
"vite-tsconfig-paths": "^4.3.2",
"vitest": "^2.0.3"
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = {
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
Expand Down
1 change: 1 addition & 0 deletions packages/web-ui/src/layouts/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { default as FocusLayout } from './FocusLayout'
export { default as AppLayout } from './AppLayout'
export { default as AppHeader } from './AppLayout/Header'
export { default as DocumentsSidebar } from './DocumentsSidebar'
37 changes: 37 additions & 0 deletions packages/web-ui/src/sections/DocumentsSidebar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use client'

import { SidebarDocument, useTree, Node } from '$ui/sections/DocumentsSidebar/useTree'

function TreeNode({ node, level = 0 }: { node: Node; level?: number }) {
return (
<div key={node.doc?.id || 'root'}>
<div className='flex flex-col gap-2' style={{ paddingLeft: level * 2 }}>
{!!node.doc && (
<div className='flex flex-row align-items justify-between'>
{node.doc.documentType === 'folder' ? (
<>
<p>{node.doc.name}</p>
<CreateNode parentId={node.doc.id} />
</>
) : (
<p className='font-bold'>{node.doc.name}</p>
)}
</div>
)}
{node.children.map((node, idx) => (
<TreeNode key={idx} node={node} level={level + 1} />
))}
</div>
</div>
)
}

export default function DocumentTree({
documents,
}: {
documents: SidebarDocument[]
}) {
const rootNode = useTree({ documents })

return <TreeNode node={rootNode} />
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { renderHook } from '@testing-library/react'
import { describe, expect, it } from 'vitest'

import { Node, useTree } from './index'

let list = [
{ path: 'things/doc1', doumentUuid: '1' },
{ path: 'things/doc2', doumentUuid: '2' },
{ path: 'things/other-things/doc3', doumentUuid: '3' },
{ path: 'something-else/doc4', doumentUuid: '4' },
]

describe('useTree', () => {
it('should return a tree with children', () => {
const { result } = renderHook(() => useTree({ documents: list }))
expect(result.current).toEqual(
new Node({
doc: undefined,
isRoot: true,
name: 'root',
children: [
new Node({
doc: undefined,
name: 'things',
children: [
new Node({
doc: { path: 'things/doc1', doumentUuid: '1' },
name: 'doc1',
children: [],
}),
new Node({
doc: { path: 'things/doc2', doumentUuid: '2' },
name: 'doc2',
children: [],
}),
new Node({
doc: undefined,
name: 'other-things',
children: [
new Node({
doc: { path: 'things/other-things/doc3', doumentUuid: '3' },
name: 'doc3',
children: [],
}),
],
}),
],
}),
new Node({
doc: undefined,
name: 'something-else',
children: [
new Node({
doc: { path: 'something-else/doc4', doumentUuid: '4' },
name: 'doc4',
children: [],
}),
],
}),
],
}),
)
})
})
84 changes: 84 additions & 0 deletions packages/web-ui/src/sections/DocumentsSidebar/useTree/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { useMemo } from 'react'

export type SidebarDocument = {
path: string
doumentUuid: string
}

export class Node {
public doc?: SidebarDocument
public children: Node[] = []
public isRoot: boolean = false
private name: string = ''

constructor({
doc,
children = [],
isRoot = false,
name = '',
}: {
doc?: SidebarDocument
children?: Node[]
isRoot?: boolean
name?: string
}) {
this.doc = doc
this.children = children
this.isRoot = isRoot
this.name = isRoot ? 'root' : name
}
}

function sortByPathDepth(a: SidebarDocument, b: SidebarDocument) {
const depth1 = (a.path.match(/\//g) || []).length
const depth2 = (b.path.match(/\//g) || []).length
return depth1 - depth2
}

function buildTree({
root,
nodeMap,
documents,
}: {
root: Node
nodeMap: Map<string, Node>
documents: SidebarDocument[]
}) {
documents.forEach((doc) => {
const segments = doc.path.split('/')
let path = ''

segments.forEach((segment, index) => {
const isFile = index === segments.length - 1
path = path ? `${path}/${segment}` : segment

if (!nodeMap.has(path)) {
const file = isFile ? doc : undefined
const node = new Node({ doc: file, name: segment })
nodeMap.set(path, node)

const parentPath = path.split('/').slice(0, -1).join('/')

// We force TypeScript to check that the parentPath is not empty
// We pre-sorted documents by path depth, so we know
// that the parent node exists
const parent = nodeMap.get(parentPath)!
parent.children.push(node)
}
})
})

return root
}

export function useTree({ documents }: { documents: SidebarDocument[] }) {
return useMemo(() => {
const root = new Node({ children: [], isRoot: true })
const nodeMap = new Map<string, Node>()
nodeMap.set('', root)
const sorted = documents.slice().sort(sortByPathDepth)

const tree = buildTree({ root, nodeMap, documents: sorted })
return tree
}, [documents])
}
13 changes: 13 additions & 0 deletions packages/web-ui/vitest.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { defineConfig } from 'vitest/config'
import { resolve } from 'path'

export default defineConfig({
resolve: {
alias: {
$ui: resolve(__dirname, './src'),
},
},
test: {
environment: 'jsdom',
},
})
Loading

0 comments on commit 5f4611f

Please sign in to comment.