-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
## [2.3.33](v2.3.32...v2.3.33) (2022-03-18) ### Bug Fixes * test new semantic release strategy ([c2d3570](c2d3570))
- Loading branch information
1 parent
c2d3570
commit eecd19c
Showing
31 changed files
with
1,477 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.removeAllAliases = exports.removeAlias = exports.getAliasOrCreate = exports.addAlias = void 0; | ||
const harvest_1 = require("../../service/api/harvest"); | ||
const error_1 = require("../error"); | ||
const alias_1 = require("../../service/filesystem/alias"); | ||
const alias_2 = require("../../cli/user-input/alias"); | ||
const cli_output_1 = require("../../cli/cli-output"); | ||
class AliasNotFoundError extends error_1.HarveyError { | ||
} | ||
async function addAlias(aliasKey, searchString) { | ||
return new Promise((resolve) => { | ||
const aliasSearchTerm = searchString ?? aliasKey; | ||
(0, harvest_1.getMyProjectTaskAssignments)().then((projectTaskAssignments) => { | ||
const filteredProjectTaskAssignments = projectTaskAssignments.filter((projectTaskAssignment) => { | ||
return projectTaskAssignment.task.name.includes(aliasSearchTerm); | ||
}); | ||
if (filteredProjectTaskAssignments.length === 0) { | ||
throw new Error(`Task "${aliasSearchTerm}" was not found.`); | ||
} | ||
if (filteredProjectTaskAssignments.length > 10) { | ||
throw new Error(`Too many tasks for "${aliasSearchTerm}" were found. Please use a more specific alias.`); | ||
} | ||
findSingleProjectTaskAssignment(aliasKey, filteredProjectTaskAssignments).then((projectTaskAssignment) => { | ||
const alias = mapProjectTaskAssignmentToAlias(aliasKey, projectTaskAssignment); | ||
storeAlias(alias); | ||
resolve(alias); | ||
}); | ||
}); | ||
}); | ||
} | ||
exports.addAlias = addAlias; | ||
async function getAliasOrCreate(aliasKey) { | ||
return new Promise((resolve) => { | ||
try { | ||
const alias = getAlias(aliasKey); | ||
resolve(alias); | ||
} | ||
catch (error) { | ||
if (!(error instanceof AliasNotFoundError)) { | ||
throw error; | ||
} | ||
addAlias(aliasKey).then(resolve); | ||
} | ||
}); | ||
} | ||
exports.getAliasOrCreate = getAliasOrCreate; | ||
function getAlias(aliasKey) { | ||
const alias = (0, alias_1.readAliasFile)().get(aliasKey); | ||
if (!alias) { | ||
throw new AliasNotFoundError(); | ||
} | ||
return alias; | ||
} | ||
function removeAlias(aliasKey) { | ||
const aliases = (0, alias_1.readAliasFile)(); | ||
if (!aliases.has(aliasKey)) { | ||
throw new Error(`"${aliasKey}" was not found. Nothing to remove.`); | ||
} | ||
aliases.delete(aliasKey); | ||
(0, alias_1.writeAliasFile)(aliases); | ||
} | ||
exports.removeAlias = removeAlias; | ||
function removeAllAliases() { | ||
(0, alias_1.writeAliasFile)(new Map()); | ||
} | ||
exports.removeAllAliases = removeAllAliases; | ||
async function findSingleProjectTaskAssignment(aliasKey, projectTaskAssignments) { | ||
return new Promise((resolve) => { | ||
if (projectTaskAssignments.length == 1) { | ||
resolve(projectTaskAssignments[0]); | ||
return; | ||
} | ||
(0, cli_output_1.printMessage)(`Multiple tasks for "${aliasKey}" were found:`); | ||
projectTaskAssignments.forEach((projectTaskAssignment, index) => { | ||
(0, cli_output_1.printMessage)(`${index} - ${projectTaskAssignment.task.name} (${projectTaskAssignment.project.name})`); | ||
}); | ||
(0, alias_2.askToChooseTaskProjectAssignmentForAliasing)(projectTaskAssignments).then(resolve); | ||
}); | ||
} | ||
function mapProjectTaskAssignmentToAlias(aliasKey, projectTaskAssignment) { | ||
return { | ||
alias: aliasKey, | ||
idProject: projectTaskAssignment.project.id, | ||
idTask: projectTaskAssignment.task.id, | ||
}; | ||
} | ||
function storeAlias(alias) { | ||
const aliases = (0, alias_1.readAliasFile)(); | ||
aliases.set(alias.alias, alias); | ||
(0, alias_1.writeAliasFile)(aliases); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.initializeConfig = exports.defaultConfig = exports.HarveyConfig = void 0; | ||
const cli_output_1 = require("../../cli/cli-output"); | ||
const config_1 = require("../../cli/user-input/config"); | ||
const harvest_1 = require("../../service/api/harvest"); | ||
const config_2 = require("../../service/filesystem/config"); | ||
class HarveyConfig { | ||
constructor() { | ||
throw new Error("Don't use the constructor of this class. Only use it's static methods."); | ||
} | ||
static getConfig() { | ||
if (!this.config) { | ||
throw new Error('Global config was never initialised.'); | ||
} | ||
return this.config; | ||
} | ||
static loadConfig(configFilePath) { | ||
this.config = (0, config_2.readConfigFile)(configFilePath); | ||
return this.config; | ||
} | ||
static setConfig(config) { | ||
this.config = config; | ||
} | ||
static resetConfig() { | ||
this.config = undefined; | ||
} | ||
} | ||
exports.HarveyConfig = HarveyConfig; | ||
exports.defaultConfig = { | ||
accountId: '', | ||
accessToken: '', | ||
aliasFilePath: '~/.config/harvey/aliases.json', | ||
pausedTimerFilePath: '~/.config/harvey/paused_timer.json', | ||
defaultRoundingInterval: 15, | ||
fileParser: { | ||
type: 'xlsx', | ||
worksheet: 'Timebooking', | ||
aliasColumn: 'Link', | ||
minutesColumn: 'Minutes', | ||
}, | ||
}; | ||
async function initializeConfig(filePath) { | ||
return new Promise((resolve) => { | ||
const newConfig = exports.defaultConfig; | ||
(0, config_1.askForHarvestAccountId)().then((accountId) => { | ||
newConfig.accountId = accountId; | ||
(0, config_1.askForPersonalAccessToken)().then((token) => { | ||
newConfig.accessToken = token; | ||
(0, harvest_1.isAccountIdAndTokenValid)(newConfig.accountId, newConfig.accessToken).then((credentialsAreValid) => { | ||
if (credentialsAreValid) { | ||
(0, config_2.writeConfigFile)(newConfig, filePath); | ||
(0, cli_output_1.printMessage)(`Sucessfully generated config "${filePath}".`); | ||
resolve(); | ||
} | ||
else { | ||
(0, cli_output_1.printMessage)('Could not authenticate, please try again.'); | ||
initializeConfig(filePath).then(resolve); | ||
} | ||
}); | ||
}); | ||
}); | ||
}); | ||
} | ||
exports.initializeConfig = initializeConfig; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.TimeEntryModifyAction = exports.modifyDay = exports.roundDay = exports.printDay = void 0; | ||
const harvest_1 = require("../../service/api/harvest"); | ||
const day_1 = require("../../cli/user-input/day"); | ||
const day_2 = require("../../cli/cli-output/day"); | ||
const round_1 = require("../round"); | ||
async function printDay(date) { | ||
return new Promise((resolve) => { | ||
(0, harvest_1.getMyTimeEntriesPerDate)(date).then((timeEntries) => { | ||
(0, day_2.printTimeEntryTable)(timeEntries); | ||
resolve(); | ||
}); | ||
}); | ||
} | ||
exports.printDay = printDay; | ||
async function roundDay(date, roundingInterval) { | ||
return new Promise((resolve) => { | ||
(0, harvest_1.getMyTimeEntriesPerDate)(date).then((timeEntries) => { | ||
const updatePromises = []; | ||
timeEntries.forEach((timeEntry) => { | ||
timeEntry = (0, round_1.roundTimeEntry)(timeEntry, roundingInterval); | ||
updatePromises.push((0, harvest_1.saveTimeEntry)(timeEntry)); | ||
}); | ||
Promise.all(updatePromises).then(() => resolve()); | ||
}); | ||
}); | ||
} | ||
exports.roundDay = roundDay; | ||
async function modifyDay(date, roundingInterval) { | ||
return new Promise((resolve) => { | ||
(0, harvest_1.getMyTimeEntriesPerDate)(date).then((timeEntries) => { | ||
(0, day_2.printTimeEntryTable)(timeEntries); | ||
(0, day_1.askToChooseTimeEntryToModify)(timeEntries).then((timeEntry) => { | ||
modifyTimeEntry(timeEntry, roundingInterval).then(resolve); | ||
}); | ||
}); | ||
}); | ||
} | ||
exports.modifyDay = modifyDay; | ||
var TimeEntryModifyAction; | ||
(function (TimeEntryModifyAction) { | ||
TimeEntryModifyAction[TimeEntryModifyAction["time"] = 0] = "time"; | ||
TimeEntryModifyAction[TimeEntryModifyAction["notes"] = 1] = "notes"; | ||
TimeEntryModifyAction[TimeEntryModifyAction["round"] = 2] = "round"; | ||
TimeEntryModifyAction[TimeEntryModifyAction["delete"] = 3] = "delete"; | ||
})(TimeEntryModifyAction = exports.TimeEntryModifyAction || (exports.TimeEntryModifyAction = {})); | ||
async function modifyTimeEntry(timeEntry, roundingInterval) { | ||
return new Promise((resolve) => { | ||
(0, day_1.askForTimeEntryModifyAction)().then((modifyAction) => { | ||
switch (modifyAction) { | ||
case TimeEntryModifyAction.time: | ||
setNewTimeEntryTime(timeEntry).then(resolve); | ||
break; | ||
case TimeEntryModifyAction.notes: | ||
setNewTimeEntryNote(timeEntry).then(resolve); | ||
break; | ||
case TimeEntryModifyAction.round: | ||
roundAndSaveTimeEntry(timeEntry, roundingInterval).then(resolve); | ||
break; | ||
case TimeEntryModifyAction.delete: | ||
(0, harvest_1.deleteTimeEntry)(timeEntry).then(resolve); | ||
break; | ||
} | ||
}); | ||
}); | ||
} | ||
async function roundAndSaveTimeEntry(timeEntry, roundingInterval) { | ||
return new Promise((resolve) => { | ||
timeEntry = (0, round_1.roundTimeEntry)(timeEntry, roundingInterval); | ||
(0, harvest_1.saveTimeEntry)(timeEntry).then(() => resolve()); | ||
}); | ||
} | ||
async function setNewTimeEntryTime(timeEntry) { | ||
return new Promise((resolve) => { | ||
(0, day_1.askForNewHours)().then((hours) => { | ||
timeEntry.hours = hours; | ||
(0, harvest_1.saveTimeEntry)(timeEntry).then(() => resolve()); | ||
}); | ||
}); | ||
} | ||
async function setNewTimeEntryNote(timeEntry) { | ||
return new Promise((resolve) => { | ||
(0, day_1.askForNewNote)().then((newNote) => { | ||
timeEntry.notes = newNote; | ||
(0, harvest_1.saveTimeEntry)(timeEntry).then(() => { | ||
resolve(); | ||
}); | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.handleError = exports.HarveyFileNotFoundError = exports.HarveyError = void 0; | ||
const cli_output_1 = require("../../cli/cli-output"); | ||
class HarveyError extends Error { | ||
} | ||
exports.HarveyError = HarveyError; | ||
class HarveyFileNotFoundError extends HarveyError { | ||
} | ||
exports.HarveyFileNotFoundError = HarveyFileNotFoundError; | ||
function handleError(error) { | ||
if (error instanceof HarveyError) { | ||
(0, cli_output_1.printMessage)(`${error.message}`); | ||
} | ||
else { | ||
throw error; | ||
} | ||
} | ||
exports.handleError = handleError; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.CsvFileParser = void 0; | ||
const error_1 = require("../../error"); | ||
class CsvFileParser { | ||
constructor() { | ||
this.parserKey = 'csv'; | ||
} | ||
async parseFile(filePath) { | ||
throw new error_1.HarveyError(`Cannot parse ${filePath} yet. CSV file parser is not yet implemented.`); | ||
} | ||
} | ||
exports.CsvFileParser = CsvFileParser; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.XlsxFileParser = void 0; | ||
const exceljs_1 = require("exceljs"); | ||
const user_input_1 = require("../../../cli/user-input"); | ||
const config_1 = require("../../config"); | ||
const error_1 = require("../../error"); | ||
class XlsxFileParser { | ||
constructor() { | ||
this.parserKey = 'xlsx'; | ||
} | ||
async parseFile(filePath) { | ||
return new Promise((resolve) => { | ||
const config = config_1.HarveyConfig.getConfig(); | ||
this.readFile(filePath).then((workbook) => { | ||
var _a, _b, _c; | ||
const worksheet = this.findWorksheetByName(((_a = config.fileParser).worksheet ?? (_a.worksheet = 'Timebooking')), workbook); | ||
const aliasHeadingCell = this.findCellByValue(((_b = config.fileParser).aliasColumn ?? (_b.aliasColumn = 'Link')), worksheet); | ||
const minutesHeadingCell = this.findCellByValue(((_c = config.fileParser).minutesColumn ?? (_c.minutesColumn = 'Minutes')), worksheet); | ||
let aliasCell = worksheet.getCell(aliasHeadingCell.row + 1, aliasHeadingCell.col); | ||
let minutesCell = worksheet.getCell(minutesHeadingCell.row + 1, minutesHeadingCell.col); | ||
const entries = []; | ||
while (aliasCell.text) { | ||
entries.push({ | ||
alias: aliasCell.text, | ||
hours: (0, user_input_1.parseUserTimeInput)(minutesCell.text), | ||
}); | ||
aliasCell = worksheet.getCell(aliasCell.row + 1, aliasCell.col); | ||
minutesCell = worksheet.getCell(minutesCell.row + 1, minutesCell.col); | ||
} | ||
resolve(entries); | ||
}); | ||
}); | ||
} | ||
async readFile(filePath) { | ||
const workbook = new exceljs_1.Workbook(); | ||
return workbook.xlsx.readFile(filePath); | ||
} | ||
findWorksheetByName(name, workbook) { | ||
const foundWorksheet = workbook.worksheets.find((worksheet) => { | ||
return worksheet.name.toLowerCase().includes(name.toLowerCase()); | ||
}); | ||
if (foundWorksheet) { | ||
return foundWorksheet; | ||
} | ||
throw new error_1.HarveyError(`Could not find worksheet "${name}".`); | ||
} | ||
findCellByValue(value, worksheet) { | ||
let match; | ||
worksheet.eachRow((row) => row.eachCell((cell) => { | ||
if (cell.text && cell.text.toLowerCase().includes(value.toLowerCase())) { | ||
match = cell; | ||
} | ||
})); | ||
if (match) { | ||
return match; | ||
} | ||
throw new error_1.HarveyError(`Could not find cell with value "${value}".`); | ||
} | ||
} | ||
exports.XlsxFileParser = XlsxFileParser; |
Oops, something went wrong.