Skip to content

Commit

Permalink
feat: early tags support, prefixed with @; integrated with a few comm…
Browse files Browse the repository at this point in the history
…ands
  • Loading branch information
f3rno64 committed Feb 15, 2024
1 parent 8885122 commit 34a8c1e
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 30 deletions.
2 changes: 2 additions & 0 deletions src/color/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import clID from './id'
import clTag from './tag'
import clDate from './date'
import clText from './text'
import clError from './error'
Expand All @@ -9,6 +10,7 @@ import clHighlightRed from './highlight_red'

export {
clID,
clTag,
clText,
clDate,
clError,
Expand Down
5 changes: 5 additions & 0 deletions src/color/tag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import colors from 'colors'

const clTag = (tag: string): string => colors.bold.green.underline(tag)

export default clTag
10 changes: 6 additions & 4 deletions src/commands/in/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,17 @@ import parseDate from 'time-speak'
import _isEmpty from 'lodash/isEmpty'
import _isUndefined from 'lodash/isUndefined'

import { printCheckedInEntry } from '../../print'
import { type InCommandArgs } from './types'
import { printCheckedInEntry } from '../../print'

const handler = async (args: InCommandArgs): Promise<void> => {
const { at, db, description, help, yargs } = args
const { yargs, db, help } = args

if (help) {
yargs.showHelp()
process.exit(0)
}

const finalDescription = description.join(' ')
const activeSheetName = db.getActiveSheetName()

if (activeSheetName === null) {
Expand All @@ -30,10 +29,13 @@ const handler = async (args: InCommandArgs): Promise<void> => {
throw new Error(`An entry is already active (${id}): ${entryDescription}`)
}

// TODO: Rename description to input or content (or think of a better name)
const { at, description: inputArray } = args
const input = inputArray.join(' ')
const startDate =
_isUndefined(at) || _isEmpty(at) ? new Date() : new Date(+parseDate(at))

const entry = await db.addActiveSheetEntry(name, finalDescription, startDate)
const entry = await db.addActiveSheetEntry({ sheet: name, input, startDate })

printCheckedInEntry(entry)
}
Expand Down
11 changes: 7 additions & 4 deletions src/commands/resume/handler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import log from '../../log'
import { type ResumeCommandArgs } from './types'
import { clHighlight, clSheet, clText } from '../../color'
import { clTag, clHighlight, clSheet, clText } from '../../color'

const handler = async (args: ResumeCommandArgs): Promise<void> => {
const { db, help, yargs } = args
Expand All @@ -12,18 +12,21 @@ const handler = async (args: ResumeCommandArgs): Promise<void> => {

const sheet = db.getActiveSheet()
const entry = db.getMostRecentlyActiveSheetEntry(sheet)
const { description, end, id } = entry
const { description, end, tags, id } = entry
const { name } = sheet
const tagsUI = (tags ?? []).map(clTag).join(' ')

if (end === null) {
throw new Error(
`Sheet ${name} already has an active entry (${id}: ${description})`
)
}

await db.addActiveSheetEntry(sheet, description)
await db.addActiveSheetEntry({ sheet, description, tags })

log(`${clSheet(`${name}:`)} ${clText('resumed')} ${clHighlight(description)}`)
log(
`${clSheet(`${name}:`)} ${clText('resumed')} ${clHighlight(description)} ${tagsUI}`
)
}

export default handler
54 changes: 40 additions & 14 deletions src/db/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ const { DB_VERSION } = CONFIG
const { NODE_ENV } = process.env
const DEFAULT_DB_PATH = NODE_ENV === 'test' ? TEST_DB_PATH : DB_PATH

// TODO: Extract
interface AddActiveSheetEntryArgs {
sheet: TimeSheet | string
input?: string
description?: string
startDate?: Date
tags?: string[]
}

class DB {
db: TimeTrackerDB | null
dbPath: string
Expand Down Expand Up @@ -61,14 +70,16 @@ class DB {
id: number,
description: string,
start?: Date,
end?: Date | null
) {
end?: Date | null,
tags?: string[]
): TimeSheetEntry {
return {
id,
description,
end: end ?? null,
start: start ?? new Date()
} as TimeSheetEntry
start: start ?? new Date(),
tags: tags ?? []
}
}

constructor(dbPath: string = DEFAULT_DB_PATH) {
Expand Down Expand Up @@ -404,25 +415,40 @@ class DB {
}

async addActiveSheetEntry(
sheet: TimeSheet | string,
description: string,
startDate?: Date
args: AddActiveSheetEntryArgs
): Promise<TimeSheetEntry> {
if (this.db === null) {
throw new Error('DB not loaded')
}

const {
description: descriptionArg,
sheet,
input,
tags: tagsArg,
startDate
} = args

const targetSheet = this._parseSheetArg(sheet)
const { entries } = targetSheet
const newEntryID = entries.length
const entry = DB.genSheetEntry(
newEntryID,
description,
startDate ?? new Date()
)
const id = entries.length
const start = startDate ?? new Date()
const end = null

let description = descriptionArg as string
let tags: string[] = tagsArg ?? []

if (_isEmpty(tags) && !_isUndefined(input)) {
const res = U.parseEntryFromInput(id, input, start)

tags = res.tags
description = res.description
}

const entry = DB.genSheetEntry(id, description, start, end, tags)

entries.push(entry)
targetSheet.activeEntryID = newEntryID
targetSheet.activeEntryID = id

await this.save()

Expand Down
8 changes: 5 additions & 3 deletions src/print/active_sheet_entry.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { clDuration, clSheet, clText } from '../color'
import { clDuration, clSheet, clText, clTag } from '../color'
import log from '../log'
import { type TimeSheetEntry } from '../types'
import { getDurationLangString } from '../utils'
Expand All @@ -8,7 +8,7 @@ const printActiveSheetEntry = (
sheetName: string,
humanize?: boolean
): void => {
const { description, end, start } = entry
const { description, end, start, tags } = entry
const finalEnd = end === null ? new Date() : end
const duration = +finalEnd - +start
const descriptionUI = clText(description)
Expand All @@ -17,7 +17,9 @@ const printActiveSheetEntry = (
`[running for ${getDurationLangString(duration, humanize)}]`
)

log(`${sheetNameUI} ${durationUI} ${descriptionUI}`.trim())
const tagsUI = tags.map(clTag).join(' ')

log(`${sheetNameUI} ${durationUI} ${descriptionUI} ${tagsUI}`.trim())
}

export default printActiveSheetEntry
7 changes: 4 additions & 3 deletions src/print/checked_in_entry.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { clHighlight, clID, clText } from '../color'
import { clTag, clHighlight, clID, clText } from '../color'
import log from '../log'
import { type TimeSheetEntry } from '../types'

const printCheckedInEntry = (entry: TimeSheetEntry): void => {
const { description, id } = entry
const { tags, description, id } = entry
const idUI = clID(`${id}`)
const descriptionUI = clHighlight(description)
const tagsUI = (tags ?? []).map(clTag).join(' ')

log(`${clText('Checked in')}: ${descriptionUI} [${idUI}]`)
log(`${clText('Checked in')}: ${descriptionUI} [${idUI}] ${tagsUI}`.trim())
}

export default printCheckedInEntry
6 changes: 4 additions & 2 deletions src/print/columns/get_sheet_entry_columns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { type TimeSheetEntry } from '../../types'
import { getDurationLangString } from '../../utils'
import {
clID,
clTag,
clText,
clDate,
clSheet,
Expand All @@ -23,7 +24,7 @@ const getSheetEntryColumns = (
humanize?: boolean,
concise?: boolean
): string[] => {
const { description, end, id, start } = entry
const { tags, description, end, id, start } = entry
const idUI = clID(`${id}`)
const startUI = clDate(
printDateAgo ? (ago(start) as string) : new Date(start).toLocaleString()
Expand Down Expand Up @@ -65,7 +66,8 @@ const getSheetEntryColumns = (
? clHighlightRed('active')
: endUI,

descriptionUI
descriptionUI,
(tags ?? []).map(clTag).join(' ')
]).map((value: string): string => (isActive ? colors.bold(value) : value))
}

Expand Down
2 changes: 2 additions & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import isEntryInDay from './is_entry_in_day'
import getHourString from './get_hour_string'
import ensureDirExists from './ensure_dir_exists'
import parseVariadicArg from './parse_variadic_arg'
import parseEntryFromInput from './parse_entry_from_input'
import getDurationLangString from './get_duration_lang_string'
import getTotalSheetDuration from './get_total_sheet_duration'
import getEntryDurationInDay from './get_entry_duration_in_day'
Expand All @@ -17,6 +18,7 @@ export {
getHourString,
ensureDirExists,
parseVariadicArg,
parseEntryFromInput,
getDurationLangString,
getEntryDurationInDay,
getTotalSheetDuration,
Expand Down
22 changes: 22 additions & 0 deletions src/utils/parse_entry_from_input.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { type TimeSheetEntry } from '../types'

const parseEntryFromInput = (
id: number,
input: string,
start?: Date,
end?: Date | null
): TimeSheetEntry => {
const tags = input.match(/@\w+/g) || []
const description = input.split(/@\w+/).join(' ').trim()

return {
id,
tags,
description,
start: start ?? new Date(),
end: end ?? null
} as TimeSheetEntry
}

export default parseEntryFromInput
export { parseEntryFromInput }

0 comments on commit 34a8c1e

Please sign in to comment.