Skip to content

Commit

Permalink
feat(logger): devtools draft
Browse files Browse the repository at this point in the history
  • Loading branch information
krulod committed Oct 20, 2023
1 parent 5d4e752 commit f6a81b2
Show file tree
Hide file tree
Showing 16 changed files with 745 additions and 106 deletions.
30 changes: 30 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 8 additions & 5 deletions packages/logger/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@ All atoms and actions with names or without underscore logs automatically
```ts
import { connectLogger, createLogBatched } from '@reatom/logger'

connectLogger(ctx)

// OR

connectLogger(
const disconnectLogger = connectLogger(
ctx,
// optional configuration
{
// whether to connect devtools
devtools: false,
// the length of the atom history (patches) to store
history: 10,
// `false` by default to made your logs short
Expand Down Expand Up @@ -46,6 +44,11 @@ connectLogger(
domain: '',
},
)

// if using HMR
if (import.meta.hot) {
import.meta.hot.accept(disconnectLogger)
}
```

Every log record includes a number in the start of the name to fix autosorting keys in a console.
Expand Down
5 changes: 5 additions & 0 deletions packages/logger/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,13 @@
"test:watch": "tsx watch src/index.test.ts"
},
"dependencies": {
"@observablehq/inspector": "^5.0.0",
"@reatom/core": "^3.1.0",
"@reatom/jsx": "^3.4.0",
"@reatom/lens": "^3.6.2",
"@reatom/persist": "^3.3.0",
"@reatom/persist-web-storage": "^3.2.3",
"@reatom/primitives": "^3.2.1",
"stylerun": "^1.0.0"
},
"author": "artalar",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Ctx } from '@reatom/core'
import { noop } from '@reatom/utils'
import { mount } from '@reatom/jsx'
import { h, hf, mount } from '@reatom/jsx'
import { Rld } from './rld'

export function devtoolsCreate(app: Ctx) {
if (typeof window === 'undefined') {
Expand All @@ -11,10 +12,10 @@ export function devtoolsCreate(app: Ctx) {
root.id = 'reatom-logger-devtools'
document.body.appendChild(root)

mount(root, <Rld app={app} />)
mount(root, h(Rld, { app }))

return () => {
// mount(root, <></>)
mount(root, h(hf, {}))
root.remove()
}
}
79 changes: 0 additions & 79 deletions packages/logger/src/graphView.ts

This file was deleted.

16 changes: 2 additions & 14 deletions packages/logger/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { AtomCache, AtomProto, Ctx, Fn, Rec, __root } from '@reatom/core'
import { isShallowEqual, noop } from '@reatom/utils'
import { logGraph } from './graphView'
// import { devtoolsCreate } from './devtools'
import { devtoolsCreate } from './devtools'

export interface unstable_ChangeMsg {
newState?: any
Expand Down Expand Up @@ -76,17 +75,6 @@ export const createLogBatched = ({
`Reatom ${domain}${length} transaction${length > 1 ? 's' : ''}`,
)

if (shouldLogGraph) {
logGraph(
new Set(
queue
.flatMap(({ changes }) => Object.values(changes))
.sort((a, b) => a.time - b.time)
.map(({ patch }) => patch),
),
)
}

for (const { changes, time, error } of queue) {
console.log(
`%c ${time}`,
Expand Down Expand Up @@ -179,7 +167,7 @@ export const connectLogger = (
let read: Fn<[AtomProto], undefined | AtomCache>
ctx.get((r) => (read = r))

const devtoolsDispose = /* devtools ? devtoolsCreate(ctx) : */ noop
const devtoolsDispose = devtools ? devtoolsCreate(ctx) : noop

const ctxUnsubscribe = ctx.subscribe((logs, error) => {
let i = -1
Expand Down
140 changes: 140 additions & 0 deletions packages/logger/src/rld-filter-model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { atom, AtomCache, Ctx, action, AtomMut } from '@reatom/core'
import { parseAtoms } from '@reatom/lens'
import { WithPersistOptions } from '@reatom/persist'
import {
withSessionStorage,
withLocalStorage,
} from '@reatom/persist-web-storage'
import { reatomArray, ArrayAtom } from '@reatom/primitives'

export type FilterColor = (typeof FilterColors)[number]
export const FilterColors = [
'red',
'green',
'blue',
'yellow',
'gray',
'black',
] as const

export type FilterAction = (typeof FilterActions)[number]
export const FilterActions = ['hide', ...FilterColors] as const

export type Filter = {
code: AtomMut<string>
action: AtomMut<FilterAction>
}

const filterMake = (code: string, action: FilterAction) => ({
code: atom(code),
action: atom(action),
})

// FIXME https://t.me/reatom_ru/49316
const filterPersistOptions: Partial<WithPersistOptions<Filter[]>> = {
toSnapshot: parseAtoms,
fromSnapshot: (ctx, snapshot = []) =>
(snapshot as any[]).map((filter) => filterMake(filter.code, filter.action)),
}

export const filtersSession = reatomArray(
[] as Filter[],
'filtersSession',
).pipe(
withSessionStorage({
key: 'rld/filtersSession',
...filterPersistOptions,
}),
)

export const filtersLocal = reatomArray([] as Filter[], 'rldFiltersLocal').pipe(
withLocalStorage({
key: 'rld/filterLocal',
...filterPersistOptions,
}),
)

// TODO preserve order
export const filters = atom(
(ctx) => [...ctx.spy(filtersSession), ...ctx.spy(filtersLocal)],
'filters',
)

export const filterFunctions = atom((ctx) => {
return ctx.spy(filters).map((filter) => {
// TODO execute in a worker
return new Function(
'log',
`var proto = log.proto; var name = proto.name; return ${ctx.spy(
filter.code,
)}`,
) as (node: AtomCache) => unknown
})
}, 'filterFunctions')

const filterRun = action((ctx, node: AtomCache) => {
return ctx.get(filterFunctions).map((fn, i) => {
try {
if (fn(node)) return ctx.get(ctx.get(filters).at(i)!.action)
} catch (error) {
console.error(error)
// TODO report error in UI
}
})
})

export const filterHide = action((ctx, node: AtomCache) =>
filterRun(ctx, node).some((action) => action === 'hide'),
)

export const filterColor = action(
(ctx, node: AtomCache) =>
filterRun(ctx, node).find((action) => action !== 'hide') as
| FilterColor
| undefined,
)

export function filterList(ctx: Ctx, filter: Filter) {
let list: ArrayAtom<Filter>

if (ctx.get(filtersSession).includes(filter)) list = filtersSession
else if (ctx.get(filtersLocal).includes(filter)) list = filtersLocal
else throw new Error('Unknown filter')

return list
}

export const filterSplice = action(
(ctx, filter: Filter, ...replaceWith: Filter[]) => {
const list = filterList(ctx, filter)
const index = ctx.get(list).indexOf(filter)
list(ctx, list.toSpliced(ctx, index, 1, ...replaceWith))
},
'filterSplice',
)

export const filterPersistSet = action(
(ctx, filter: Filter, persist: boolean) => {
const nextList = persist ? filtersLocal : filtersSession
filterSplice(ctx, filter)
nextList(ctx, (prev) => [...prev, filter])
},
'filterPersistSet',
)

export const draftCode = atom('', 'draftCode')
export const draftAction = atom('hide' as FilterAction, 'filterDraftAction')
export const draftPersist = atom(false, 'filterDraftPersist')
export const draftCreate = action((ctx) => {
const filter: Filter = {
code: atom(ctx.get(draftCode)),
action: atom(ctx.get(draftAction)),
}

const list = ctx.get(draftPersist) ? filtersLocal : filtersSession
list(ctx, (prev) => [...prev, filter])

draftCode(ctx, '')
draftAction(ctx, 'hide')
draftPersist(ctx, false)
}, 'filterDraftCreate')
Loading

0 comments on commit f6a81b2

Please sign in to comment.