import { resolve as resolveMap } from "@thi.ng/resolve-map" ; import { fromInterval } from "@thi.ng/rstream/interval" ; import { resolve as resolvePromise } from "@thi.ng/rstream/resolve" ; import { reactive , stream } from "@thi.ng/rstream/stream" ; import { sync } from "@thi.ng/rstream/sync" ; import { updateDOM } from "@thi.ng/transducers-hdom" ; import { add } from "@thi.ng/transducers/add" ; import { conj } from "@thi.ng/transducers/conj" ; import { map } from "@thi.ng/transducers/map" ; import { pluck } from "@thi.ng/transducers/pluck" ; import { throttleTime } from "@thi.ng/transducers/throttle-time" ; import { transduce } from "@thi.ng/transducers/transduce" ; import type { AppContext , Commit } from "../common/api" ; import { header } from "../common/components/header" ; import { link } from "../common/components/link" ; import { repoTable } from "../common/components/repo-table" ; import { ctx } from "../common/config" ; const COMMITS_URL = process . env . NODE_ENV === "production" ? "./commits.json" : "/commits" ; const app = ( state ) => [ "div" , [ header , ctx . repo . name ] , [ stats , state ] , [ repoTable , state . commits ] , ] ; const stats = ( ctx , state ) => [ "div" , ctx . ui . stats . root , [ "div.tl" , ctx . ui . stats . col , [ searchFilter , state ] ] , [ "div.tc" , ctx . ui . stats . col , [ "div" , `Authors: ${ state . authors }` ] , [ "div" , `Total adds: ${ state . adds } (${ state . avgAdds } avg / commit)` ] , [ "div" , `Total dels: ${ state . dels } (${ state . avgDels } avg / commit)` ] , ] , [ "div.tr" , ctx . ui . stats . col , [ link , { ... ctx . ui . stats . link , href : ctx . repo . url } , ctx . repo . url ] , ] , ] ; const searchFilter = ( ctx , state ) => [ "div" , "Filter:" , [ "input" , { ... ctx . ui . search , type : "text" , value : state . search , oninput : ( e ) => search . next ( e . target . value . toLowerCase ( ) ) , } , ] , `(${ state . commits . length } commits)` , ] ; const filterCommits = ( { commits , search , } ) => ( { search , commits : search ? commits . filter ( ( x ) => x . msg . toLowerCase ( ) . indexOf ( search ) !== - 1 ) : commits , } ) ; const computeStats = ( state ) => resolveMap ( { ... state , adds : ( { commits } ) => transduce ( map ( ( x ) => x . add || 0 ) , add ( ) , commits ) , dels : ( { commits } ) => transduce ( map ( ( x ) => x . del || 0 ) , add ( ) , commits ) , authors : ( { commits } ) => transduce ( pluck ( "author" ) , conj ( ) , commits ) . size , avgAdds : ( { commits , adds } ) => ( adds / commits . length ) | 0 , avgDels : ( { commits , dels } ) => ( dels / commits . length ) | 0 , } ) ; const error = stream ( ) ; error . subscribe ( { next : ( e ) => alert ( `An error occurred:\n${ e }` ) } ) ; const commits = fromInterval ( 60 * 60 * 1000 ) . transform ( map ( ( ) => fetch ( COMMITS_URL ) . then ( ( res ) => res . ok ? res . json ( ) : error . next ( "error loading commits" ) , ( e ) => error . next ( e . message ) ) ) ) . subscribe ( resolvePromise ( { fail : ( e ) => error . next ( e . message ) } ) ) ; const search = reactive ( "" ) ; sync ( { src : { commits , search : search . transform ( throttleTime ( 100 ) ) , } , } ) . transform ( map ( filterCommits ) , map ( computeStats ) , map ( app ) , updateDOM ( { ctx } ) ) ;