Skip to content

Commit

Permalink
feat: added green github activity like color to the calendar
Browse files Browse the repository at this point in the history
  • Loading branch information
darraghoriordan committed Sep 28, 2023
1 parent 402cd98 commit 0218611
Show file tree
Hide file tree
Showing 20 changed files with 325 additions and 31 deletions.
7 changes: 7 additions & 0 deletions src/app/@types/bridge.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ import {
import {
DevHistoryDayResponse,
DevHistoryGetDayRequest,
GitActivityForMonthRequest,
GitActivityForMonthResponse,
} from '../../electron/devHistory/channels/MessageTypes'

declare global {
Expand Down Expand Up @@ -156,5 +158,10 @@ declare global {
message: DevHistoryGetDayRequest,
) => Promise<DevHistoryDayResponse>
}
GitActivityForMonth: {
invoke: (
message: GitActivityForMonthRequest,
) => Promise<GitActivityForMonthResponse>
}
}
}
11 changes: 11 additions & 0 deletions src/app/MarketingWeek/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
subMonths,
addMonths,
} from 'date-fns'
import { useGitActivityGetMonth } from './ReactQueryWrappers'

const firstDayOfMonth = new Date(2023, 8, 1)
let nearestMonday = new Date(firstDayOfMonth)
Expand Down Expand Up @@ -98,6 +99,11 @@ export default function Calendar({
setOpenDateActions: React.Dispatch<React.SetStateAction<boolean>>
date: Date
}) {
const { data: gitActivity } = useGitActivityGetMonth({
startDate: days[0]?.jsDate,
endDate: days.at(-1)?.jsDate,
})

const container = useRef<HTMLDivElement | null>(null)
const containerNav = useRef<HTMLDivElement | null>(null)
const containerOffset = useRef<HTMLDivElement | null>(null)
Expand Down Expand Up @@ -297,13 +303,18 @@ export default function Calendar({
<div className="mt-2 text-sm bg-gray-200 rounded-lg shadow isolate grid grid-cols-7 gap-px ring-1 ring-gray-200">
{days.map((day, dayIdx) => {
day.isSelected = isSameDay(day.jsDate, date)
const hasGitActivity =
gitActivity?.activity.get(day.jsDate.getTime()) &&
'!bg-green-500'

return (
<button
disabled={day.isFuture}
key={day.date}
type="button"
onClick={() => setSelectedDate(day.jsDate)}
className={classNames(
hasGitActivity && '!bg-green-500/80',
'py-1.5 hover:bg-gray-100 focus:z-10',
day.isCurrentMonth ? 'bg-white' : 'bg-gray-50',
(day.isSelected || day.isToday) && 'font-semibold',
Expand Down
2 changes: 2 additions & 0 deletions src/app/MarketingWeek/Components/DateActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ export default function DateActions({
<div className="relative px-4 sm:px-6">
<details>
<summary className="my-4 text-lg font-semibold text-gray-900 leading-6">
{increment?.raw.analysis?.blogPosts?.length || '0'}{' '}
Generated Blog Posts
</summary>

Expand All @@ -180,6 +181,7 @@ export default function DateActions({
<div className="relative px-4 sm:px-6">
<details>
<summary className="my-4 text-lg font-semibold text-gray-900 leading-6">
{increment?.raw.analysis?.tweets?.length || '0'}{' '}
Generated Tweets / Social Posts
</summary>
<div className="grid grid-cols-2 gap-2">
Expand Down
23 changes: 14 additions & 9 deletions src/app/MarketingWeek/MarketingWeekScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export function MarketingWeekScreen() {
const [selectedDate, setSelectedDate] = React.useState<Date>(new Date())
const [isDateActionsOpen, setOpenDateActions] = React.useState(false)
const { data, isLoading } = useDevHistoryGetDay({ date: selectedDate })

const [selectedIncrement, setSelectedIncrement] = React.useState<
IncrementAnalysis | undefined
>(data?.analysis?.[0])
Expand All @@ -30,12 +31,14 @@ export function MarketingWeekScreen() {
logAMessage({ message: 'Refresh Clicked', level: 'info' })
}

const sumOfBlogPosts = data?.analysis.reduce((acc, cur) => {
return acc + (cur?.raw?.analysis?.blogPosts?.length || 0)
}, 0)
const sumOfTweets = data?.analysis.reduce((acc, cur) => {
return acc + (cur?.raw?.analysis?.tweets?.length || 0)
}, 0)
const sumOfBlogPosts =
data?.analysis.reduce((acc, cur) => {
return acc + (cur?.raw?.analysis?.blogPosts?.length || 0)
}, 0) || 0
const sumOfTweets =
data?.analysis.reduce((acc, cur) => {
return acc + (cur?.raw?.analysis?.tweets?.length || 0)
}, 0) || 0
control = (
<div className="flex flex-col h-[70vh]">
<header className="flex items-center justify-between flex-none py-4 border-b border-gray-200">
Expand Down Expand Up @@ -72,9 +75,11 @@ export function MarketingWeekScreen() {
<div className="flex items-center">
{isLoading ? (
<div role="status" className="mx-8">
<span className="text-xm">
Please wait! Crunching your data and it might take 3-4
minutes...
<span className="text-xs">
Please wait! Crunching your data and setting GPUs on fire. It
might take{' '}
<span className="font-semibold">3-4 minutes or more</span> for
an entire day!...
</span>{' '}
<svg
aria-hidden="true"
Expand Down
45 changes: 44 additions & 1 deletion src/app/MarketingWeek/ReactQueryWrappers.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { useQuery } from '@tanstack/react-query'
import { useContext } from 'react'
import { ConsoleContext } from '../ConsoleArea/ConsoleContext'
import { GitActivityForMonthResponse } from '../../electron/devHistory/channels/MessageTypes'

export const wellKnownQueries = {
getSingleDay: 'get-single-day',
getGitCommitActivityForMonth: 'get-git-commit-activity-for-month',
}
export function useDevHistoryGetDay({ date }: { date: Date }) {
const [_logMessages, logAMessage] = useContext(ConsoleContext)
Expand All @@ -26,7 +28,48 @@ export function useDevHistoryGetDay({ date }: { date: Date }) {
},
onSuccess: () => {
logAMessage({
message: `${wellKnownQueries.getSingleDay} tool completed successfully.`,
message: `${wellKnownQueries.getSingleDay} completed successfully.`,
level: 'info',
})
},
},
)
}

export function useGitActivityGetMonth({
startDate,
endDate,
}: {
startDate: Date | undefined
endDate: Date | undefined
}) {
const [_logMessages, logAMessage] = useContext(ConsoleContext)
return useQuery(
[wellKnownQueries.getGitCommitActivityForMonth, startDate, endDate],
async () => {
if (!startDate || !endDate) {
return {
activity: new Map<number, boolean>(),
} as GitActivityForMonthResponse
}
return window.GitActivityForMonth.invoke({
startDate,
endDate,
})
},

{
// never invalidate
staleTime: Infinity,
retry: 0,
refetchOnWindowFocus: false,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onError: (error: any) => {
logAMessage({ message: error.message, level: 'error' })
},
onSuccess: () => {
logAMessage({
message: `${wellKnownQueries.getSingleDay} completed successfully.`,
level: 'info',
})
},
Expand Down
1 change: 0 additions & 1 deletion src/app/TimestampConverter/LocaleSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export default function LocaleSelector({
setSelectedLocale(newLocale)
}

console.log(`configuring locale selector with default value ${defaultValue}`)
return (
<select name="locale" onChange={onChange} defaultValue={defaultValue}>
{locale.all.map(l => (
Expand Down
2 changes: 2 additions & 0 deletions src/electron/channelConfigurationsPubs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { SelectSshConfigFilePathChannelPub } from './userSettings/channels/Selec
import { SelectGitConfigFilePathChannelPub } from './userSettings/channels/SelectGitConfigFilePathChannelPub'
import { DevHistoryGetDayChannelPub } from './devHistory/channels/DevHistoryGetDayChannelPub'
import { SelectChromeHistoryFilePathChannelPub } from './userSettings/channels/SelectChromeHistoryFilePathChannelPub'
import { GitActivityForMonthChannelPub } from './devHistory/channels/GitActivityForMonthChannelPub'

export const ChannelConfigurationPubs: ChannelConfigurationTypePub = {
rtmSendChannels: [
Expand Down Expand Up @@ -71,5 +72,6 @@ export const ChannelConfigurationPubs: ChannelConfigurationTypePub = {
new SelectSshConfigFilePathChannelPub(),
new DevHistoryGetDayChannelPub(),
new SelectChromeHistoryFilePathChannelPub(),
new GitActivityForMonthChannelPub(),
],
}
2 changes: 2 additions & 0 deletions src/electron/channelConfigurationsSubs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { SelectSshConfigFilePathChannelSub } from './userSettings/channels/Selec
import { SelectGitConfigFilePathChannelSub } from './userSettings/channels/SelectGitConfigFilePathChannelSub'
import { DevHistoryGetDayChannelSub } from './devHistory/channels/DevHistoryGetDayChannelSub'
import { SelectChromeHistoryFilePathChannelSub } from './userSettings/channels/SelectChromeHistoryFilePathChannelSub'
import { GitActivityForMonthChannelSub } from './devHistory/channels/GitActivityForMonthChannelSub'

export const ChannelConfigurationSubs: ChannelConfigurationTypeSub = {
rtmSendChannels: [
Expand Down Expand Up @@ -72,5 +73,6 @@ export const ChannelConfigurationSubs: ChannelConfigurationTypeSub = {
new SelectSshConfigFilePathChannelSub(),
new DevHistoryGetDayChannelSub(),
new SelectChromeHistoryFilePathChannelSub(),
new GitActivityForMonthChannelSub(),
],
}
1 change: 1 addition & 0 deletions src/electron/devHistory/channels/DevHistoryChannelEnum.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-disable no-unused-vars */
export enum DevHistoryChannels {
GET_DAY = 'GET_DAY',
GET_GIT_ACTIVITY_FOR_MONTH = 'GET_GIT_ACTIVITY_FOR_MONTH',
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class DevHistoryGetDayChannelSub
// read the list of entries from the chrome history sqlite database
// return the list of entries
const analysis = await analyseDay(request.date)
console.log(analysis)

return {
analysis,
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { InvokeChannelBasePub } from '../../IpcChannelTypes/InvokeChannelBasePub'
import { DevHistoryChannels } from './DevHistoryChannelEnum'

export class GitActivityForMonthChannelPub extends InvokeChannelBasePub {
constructor() {
super('GitActivityForMonth', DevHistoryChannels.GET_GIT_ACTIVITY_FOR_MONTH)
}
}
35 changes: 35 additions & 0 deletions src/electron/devHistory/channels/GitActivityForMonthChannelSub.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { IpcMainEvent } from 'electron'
import { IIpcMainInvokeEventSub } from '../../IpcChannelTypes/IIpcMainInvokeEventSub'
import { GitActivityForMonthChannelPub } from './GitActivityForMonthChannelPub'
import {
GitActivityForMonthRequest,
GitActivityForMonthResponse,
} from './MessageTypes'
import { gitActivityForMonth } from '../services/month-analyser'

export class GitActivityForMonthChannelSub
extends GitActivityForMonthChannelPub
implements
IIpcMainInvokeEventSub<
GitActivityForMonthRequest,
GitActivityForMonthResponse
>
{
async handle(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
event: IpcMainEvent,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
request: GitActivityForMonthRequest,
): Promise<GitActivityForMonthResponse> {
// read the list of entries from the chrome history sqlite database
// return the list of entries
const analysis = await gitActivityForMonth(
request.startDate,
request.endDate,
)

return {
activity: analysis,
}
}
}
8 changes: 8 additions & 0 deletions src/electron/devHistory/channels/MessageTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,11 @@ export type DevHistoryGetDayRequest = {
export type DevHistoryDayResponse = {
analysis: IncrementAnalysis[]
}

export type GitActivityForMonthRequest = {
startDate: Date
endDate: Date
}
export type GitActivityForMonthResponse = {
activity: Map<number, boolean>
}
7 changes: 3 additions & 4 deletions src/electron/devHistory/services/chrome-browser-history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,8 @@ export async function copyLatestChromeHistory(): Promise<void> {
'Chrome history database path not found. Please set the path in the settings.',
)
}
console.log('opening chrome history database', historyDBPath)
console.log('filesize', await getFileSizeInMB(historyDBPath))

await copyFileAsync(historyDBPath, electronAppTempPath)
console.log('copied file to', electronAppTempPath)
}

export async function readChromeHistory({
Expand Down Expand Up @@ -86,7 +83,9 @@ function mapToBrowserHistoryEvent(row: {
}
}

async function getFileSizeInMB(filePath: string): Promise<number | null> {
export async function getFileSizeInMB(
filePath: string,
): Promise<number | null> {
try {
// Get the file stats (including size) asynchronously
const stats = await fs.promises.stat(filePath)
Expand Down
8 changes: 1 addition & 7 deletions src/electron/devHistory/services/day-analyser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,7 @@ export async function analyseDay(date: Date) {
if (cachedDayAnalysis && cachedDayAnalysis.length === increments.length) {
return cachedDayAnalysis
}
console.log(`Cached analysis not complete for ${dayRange.startDate}`, {
dayRange,
cachedIncrementsLength: cachedDayAnalysis?.length,
incrementCount: increments.length,
lastCachedIncrement: cachedDayAnalysis?.[cachedDayAnalysis.length - 1],
})
console.log(`Cached analysis not complete for ${dayRange.startDate}`)

// we have to copy the chrome history sqlite file so that we can read it even if it
// is locked by chrome. This might not work for multi instances of getting a day history in parallel
Expand All @@ -60,7 +55,6 @@ export async function analyseDay(date: Date) {
if (cachedItem) {
console.log(
`using cached analysis for ${increment.startDate} to ${increment.endDate}`,
cachedItem,
)
return cachedItem
}
Expand Down
1 change: 0 additions & 1 deletion src/electron/devHistory/services/git-repository-history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ export async function readSingleGitRepoHistory({
const commitDiff = await git.raw(['--no-pager', 'show', commit.hash])

const filenames = await git.raw(['diff', commit.hash, '--name-only'])
console.log('filenames', filenames)

commitAndDiffs.push({
type: 'git commit',
Expand Down
48 changes: 48 additions & 0 deletions src/electron/devHistory/services/month-analyser-cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import path from 'path'
import fs from 'fs'
import fsp from 'fs/promises'
import { app } from 'electron'

export async function getFromCache(
start: number,
end: number,
): Promise<Map<number, boolean> | undefined> {
const cachePath = await getCachePath(start, end)

if (!fs.existsSync(cachePath)) {
console.log(`Cache file not found for ${start}-${end}`)
return undefined
}
const fileUtf8 = await fsp.readFile(cachePath, { encoding: 'utf-8' })

const cache: [number, boolean][] = JSON.parse(fileUtf8)

// Create a new map and populate it with the parsed key-value pairs
const numberBooleanMap = new Map<number, boolean>(cache)

return numberBooleanMap
}

export async function saveToCache(
start: number,
end: number,
activity: Map<number, boolean>,
): Promise<void> {
const cachePath = await getCachePath(start, end)
console.log('saving to cache', cachePath)
if (!fs.existsSync(path.dirname(cachePath))) {
await fsp.mkdir(path.dirname(cachePath), { recursive: true })
}
const jsonString = JSON.stringify(Array.from(activity.entries()))

await fsp.writeFile(cachePath, jsonString)
}

async function getCachePath(start: number, end: number): Promise<string> {
const cachePath = path.join(
app.getPath('userData'),
'month-git-activity-cache',
`${start}-${end}.json`,
)
return cachePath
}
Loading

0 comments on commit 0218611

Please sign in to comment.