diff --git a/TimeTrace/src/components/Collapsible.tsx b/TimeTrace/src/components/Collapsible.tsx index 72f3538..358b544 100644 --- a/TimeTrace/src/components/Collapsible.tsx +++ b/TimeTrace/src/components/Collapsible.tsx @@ -7,6 +7,10 @@ interface Collapsibleprop { children?: ReactNode; isOpen: boolean; // Add open prop } +/** + * + * @returns A component that can encompass other react components and show them based on whether it is collapsed or not. + */ function Collapsible({ label, children, isOpen }: Collapsibleprop) { const [open, setIsOpen] = useState(isOpen || false); diff --git a/TimeTrace/src/components/MappedItemsList.tsx b/TimeTrace/src/components/MappedItemsList.tsx index b803edb..20ad04c 100644 --- a/TimeTrace/src/components/MappedItemsList.tsx +++ b/TimeTrace/src/components/MappedItemsList.tsx @@ -6,11 +6,15 @@ import Button from "./button/Button"; import { ButtonStyle } from "./button/IButtonProps"; import Tooltip from "./tooltip/ToolTip"; +/** + * @returns The mappings list/table on the MappingsPage + */ function MappedItemsList() { const { mappings, setMappings } = useContext(AppdataContext); function removeMapping(eventText: string): void { mappings.remove(eventText) + // new reference to alert the frontend that it should reload HTML that relies on the mappings. const newMappings = new CustomMap(mappings); if (setMappings) { setMappings(newMappings); diff --git a/TimeTrace/src/components/SearchForm.tsx b/TimeTrace/src/components/SearchForm.tsx index f181e7d..24ad9d4 100644 --- a/TimeTrace/src/components/SearchForm.tsx +++ b/TimeTrace/src/components/SearchForm.tsx @@ -14,6 +14,10 @@ interface SearchFormProps { tooltip?: string; } +/** + * + * @returns A searchform which allows the user to type in a TRE and perform a search + */ export default function SearchForm({ tooltip }: SearchFormProps) { const { tre, setTre } = useContext(AppdataContext); const { mappings } = useContext(AppdataContext); @@ -28,11 +32,17 @@ export default function SearchForm({ tooltip }: SearchFormProps) { const { linesPerPage } = useContext(LogTableContext); const { currentPageSpan, setCurrentPageSpan } = useContext(LogTableContext); + /** + * we preventDefault on the event to stop a request from being sent in the browser - this would cause a 'page refresh' + */ const handleSubmit = (event: React.FormEvent) => { event.preventDefault(); callMonaa(tre); }; + /** + * Finds the first match in the match set. + */ function findFirstMatch(matches: MonaaZone[]) { if (matches.length === 0) { setShownLines(filteredFileLines.slice(0, linesPerPage)); @@ -56,6 +66,9 @@ export default function SearchForm({ tooltip }: SearchFormProps) { setMonaaMatchIndex(-1); //set to -1 to trigger a scroll to the first match (when use effect on LogTable sets it to 0 after this) } + /** + * Gets the results from Monaa using a tre. + */ async function callMonaa(tre: string) { setLoading(true); if (!uploadedFile) return; //should never happen diff --git a/TimeTrace/src/components/Warning.tsx b/TimeTrace/src/components/Warning.tsx index 4b5e6a3..3c4f0cf 100644 --- a/TimeTrace/src/components/Warning.tsx +++ b/TimeTrace/src/components/Warning.tsx @@ -3,6 +3,10 @@ import { useContext } from "react"; import Button from "./button/Button"; import { ButtonStyle } from "./button/IButtonProps"; +/** + * + * @returns A pop-up that exclaims that there was some sort of error + */ export default function Warning() { const { errorObj, setError } = useContext(AppdataContext); diff --git a/TimeTrace/src/components/logtable/LogTable.tsx b/TimeTrace/src/components/logtable/LogTable.tsx index 8662cfe..3f8dba7 100644 --- a/TimeTrace/src/components/logtable/LogTable.tsx +++ b/TimeTrace/src/components/logtable/LogTable.tsx @@ -48,6 +48,7 @@ function LogTable({ mappingsAreEditable }: LogTableProps) { scrollToMonaaMatch(); }, [monaaMatchIndex]); + //Ensures that whenever the currentPageSpan changes we still listen to the scroll event on the logtable. useEffect(() => { const logTable = document.querySelector("#log-table"); if (!logTable) return; @@ -61,6 +62,9 @@ function LogTable({ mappingsAreEditable }: LogTableProps) { setFilteredFileLines(filterAllMappedUnmappedLines(mapEventsToFileLine(events), shownLinesMode, mappings)) }, [shownLinesMode]) + /** + * Searches the logfile using either {@link searchUsingRegex} or {@link searchStandard} based on the boolean {@link advancedSearchMode} + */ function searchLog(query: string) { if (query === "") { setFilteredFileLines(filterAllMappedUnmappedLines(mapEventsToFileLine(events), shownLinesMode, mappings)); @@ -145,6 +149,9 @@ function LogTable({ mappingsAreEditable }: LogTableProps) { } }; + /** + * @returns A boolean that indicates whether a line is highlighted (that is when it is included in a currently shown match) + */ function lineIsHighlighted(line: number): boolean { if (mappingsAreEditable || !matches[monaaMatchIndex]) return false; let highlightLine = false; diff --git a/TimeTrace/src/components/modal/Modal.tsx b/TimeTrace/src/components/modal/Modal.tsx index 33aa528..b64f015 100644 --- a/TimeTrace/src/components/modal/Modal.tsx +++ b/TimeTrace/src/components/modal/Modal.tsx @@ -3,6 +3,10 @@ import { useContext } from 'react'; import Button from "../button/Button"; import { ButtonStyle } from "../button/IButtonProps"; +/** + * + * @returns A pop up used for non errors that display some sort of information. + */ export default function Modal() { const { modalObj, setModal } = useContext(AppdataContext); diff --git a/TimeTrace/src/components/predefined-res/Interval.tsx b/TimeTrace/src/components/predefined-res/Interval.tsx index 01f40c6..fe20c6b 100644 --- a/TimeTrace/src/components/predefined-res/Interval.tsx +++ b/TimeTrace/src/components/predefined-res/Interval.tsx @@ -2,7 +2,6 @@ import {FormEvent, useState } from "react"; import ModalInput from "../modal/ModalInput"; import { IntervalClass } from "./PredefinedREs"; import FormButtonGroup from "../button/FormButtonGroup"; -import { validateNumberInput } from "./numbersOnlyInput"; interface IntervalProps { reObject: IntervalClass; diff --git a/TimeTrace/src/components/predefined-res/Over.tsx b/TimeTrace/src/components/predefined-res/Over.tsx index 4655fdc..68b0f35 100644 --- a/TimeTrace/src/components/predefined-res/Over.tsx +++ b/TimeTrace/src/components/predefined-res/Over.tsx @@ -2,7 +2,6 @@ import {FormEvent, useState } from "react"; import ModalInput from "../modal/ModalInput"; import { OverClass } from "./PredefinedREs"; import FormButtonGroup from "../button/FormButtonGroup"; -import { validateNumberInput } from "./numbersOnlyInput"; interface InclusiveOverProps { reObject: OverClass; diff --git a/TimeTrace/src/components/predefined-res/PredefinedREs.ts b/TimeTrace/src/components/predefined-res/PredefinedREs.ts index c6145a6..069d3b2 100644 --- a/TimeTrace/src/components/predefined-res/PredefinedREs.ts +++ b/TimeTrace/src/components/predefined-res/PredefinedREs.ts @@ -9,12 +9,20 @@ export enum PredefinedREType { InclusiveUnder, } +/** + * Every predefinedRE must have a title for its modal and a method to insert the RE. + * {@link PredefinedRE.title} + * {@link PredefinedRE.insertRE} + */ export interface PredefinedRE { title: string; insertRE: () => string; } +/** + * These interfaces are just to make the predefinedRE classes more compact + */ export interface IntervalInput { prependedText: string; lowerBound: string; @@ -44,19 +52,29 @@ export interface OverInput { lowerBound: string; } +/** + * This class is used for the predefinedREs: "Greater or Equal", "Greater", "Smaller", "Smaller or Equal" + */ export class OverClass implements PredefinedRE { public input: OverInput; public title: string = ''; public includesLowerBound: boolean; + /** + * {@link negateRe} is used to turn the over into an under predefined RE. + */ public negateRe: boolean; public label: string = ''; public insertRE(): string { let re = ''; + //We want to include the lowerbound, this is done using inclusiveOver. if(this.includesLowerBound) { + //If the RE should be negated that is turned into under we prepend (?!( re = `${this.input.prependedText}${this.negateRe ? '(?!(': ''}${generateInclusiveOverRegex(this.input.lowerBound)}${this.negateRe ? '))': ''}`; } + //We want to exclude the lowerbound, this is done using strictOver. else { + //If the RE should be negated that is turned into under we prepend (?!( re = `${this.input.prependedText}${this.negateRe ? '(?!(': ''}${generateStrictOverRegex(this.input.lowerBound)}${this.negateRe ? '))': ''}`; } diff --git a/TimeTrace/src/components/predefined-res/numbersOnlyInput.ts b/TimeTrace/src/components/predefined-res/numbersOnlyInput.ts deleted file mode 100644 index 989d6dd..0000000 --- a/TimeTrace/src/components/predefined-res/numbersOnlyInput.ts +++ /dev/null @@ -1,7 +0,0 @@ -export function validateNumberInput(number: string): boolean { - if(Number(number)) { - return true; - } - - return false; -} \ No newline at end of file diff --git a/TimeTrace/src/components/predefined-tres/PredefinedTREs.ts b/TimeTrace/src/components/predefined-tres/PredefinedTREs.ts index 8ebfabf..c72ed3a 100644 --- a/TimeTrace/src/components/predefined-tres/PredefinedTREs.ts +++ b/TimeTrace/src/components/predefined-tres/PredefinedTREs.ts @@ -6,12 +6,18 @@ export enum PredefinedTre { TimedSequential, } +/** + * Every predefinedTRE must have a title ({@link IPredefinedTRE.title}) used for the title of the modal + * Every predefiendTRE must have a method ({@link IPredefinedTRE.insertTRE}) that returns the predefinedTRE as a string + */ export interface IPredefinedTRE { title: string; insertTRE: () => string; } - +/** + * To make the {@link WithinTREClass} a bit more compact + */ export interface WithinTREInput { firstGroup: string; secondGroup: string; diff --git a/TimeTrace/src/models/LogHandler.ts b/TimeTrace/src/models/LogHandler.ts index ea342d4..b31b2c9 100644 --- a/TimeTrace/src/models/LogHandler.ts +++ b/TimeTrace/src/models/LogHandler.ts @@ -18,6 +18,8 @@ export abstract class LogHandler { for (let i = 0; i < MonaaOutput.length; i++) { const line = MonaaOutput[i]; + + //Indicates that a new match begins if (line.includes("=======") && foundStart !== -1 && foundEnd !== -1) { //RESET interval let SearchInterval: SearchInterval = { start: foundStart, end: foundEnd }; foundIntervals.push(SearchInterval); @@ -25,10 +27,13 @@ export abstract class LogHandler { foundStart = -1; foundEnd = -1; } + //Lower bound of Monaazone else if (MonaaOutput[i].includes("<= t <") || MonaaOutput[i].includes("< t <") || MonaaOutput[i].includes("< t <=") || MonaaOutput[i].includes("<= t <=")) { //FIND Start foundStart = parseFloat(MonaaOutput[i].split(/\s+/).filter(part => !isNaN(parseFloat(part))).pop() || ''); } + + //Upper bound of Monaazone else if (MonaaOutput[i].includes("<= t' <") || MonaaOutput[i].includes("< t' <") || MonaaOutput[i].includes("< t' <=") || MonaaOutput[i].includes("<= t' <=")) { //FIND End foundEnd = parseFloat(MonaaOutput[i].split(/\s+/).filter(part => !isNaN(parseFloat(part))).shift() || ''); diff --git a/TimeTrace/src/models/LogSearcher.ts b/TimeTrace/src/models/LogSearcher.ts index 6ce12df..187a77d 100644 --- a/TimeTrace/src/models/LogSearcher.ts +++ b/TimeTrace/src/models/LogSearcher.ts @@ -17,22 +17,29 @@ export abstract class LogSearcher { return this._hashMap; } + /** + * Finds the indices in the logfile where there is a match + */ public static findZones(searchIntervals: SearchInterval[]): MonaaZone[] { console.time("findZones"); let binaryTime = 0, binaryCount = 0 let hashTime = 0, hashCount = 0 let startOfLastFoundMatch = 0; const MonaaZoneMatches: MonaaZone[] = []; + for (let i = 0; i < searchIntervals.length; i++) { let match = new MonaaZone(); let hashTimeStart = performance.now() let start: number | null = this.hashMap.get(Math.round(searchIntervals[i].start).toString()); let end: number | null = this.hashMap.get(Math.round(searchIntervals[i].end).toString()); + + // Start and end could be looked up in the hashmap. if (start !== null && end !== null) { match.lineMatches = Array.from({ length: end - start + 1 }, (_, index) => start! + index); //array containing numbers from start to end hashTime += performance.now() - hashTimeStart; hashCount++; } + // Start or end may be null. We will use binary search else { let binaryTimeStart = performance.now() match = this.findNearestZone(searchIntervals[i], start != null ? start : startOfLastFoundMatch); @@ -50,6 +57,9 @@ export abstract class LogSearcher { return MonaaZoneMatches } + /** + * Finds an individual match in the case where the start or end could not be found via the hashmap. + */ public static findNearestZone(searchInterval: SearchInterval, startOfLastMatch: number): MonaaZone { let foundmatch = new MonaaZone(); let startingIndex = this.findNearestIndex(startOfLastMatch, searchInterval); @@ -63,14 +73,16 @@ export abstract class LogSearcher { return foundmatch; } + /** + * + * Converts the timestamps to ms when a file is uploaded + */ public static updateTimestampInfo(logFile: string[]) { - let prevLineTime: number = 0; const timestamps: number[] = []; logFile.forEach((line: string) => { const eventTimeStamp = parseInt(LogFormatter.convertDateToMs(extractTimeStamp(line))); timestamps.push(eventTimeStamp); - prevLineTime = eventTimeStamp; }); let averageTimegrowth: number = (timestamps[timestamps.length - 1] - timestamps[0]) / timestamps.length @@ -79,15 +91,19 @@ export abstract class LogSearcher { this.averageGrowth = averageTimegrowth; } + /** Used to find the starting index. */ private static findNearestIndex(lastFoundIndex: number, searchInterval: SearchInterval): number { const firstTimestamp = this.timestamps[0]; const difference = searchInterval.start - firstTimestamp; const multiplum = difference / this.averageGrowth; let startingIndex = Math.floor(multiplum); - if (searchInterval.start < this.timestamps[startingIndex]) { // search in left side if we overshot estimation + // search in left side if we overshot estimation + if (searchInterval.start < this.timestamps[startingIndex]) { startingIndex = this.binarySearch(searchInterval.start, lastFoundIndex, startingIndex); - } else if (searchInterval.start > this.timestamps[startingIndex]) {//search in right side of array if we undershot estimation + } + // search in right side of array if we undershot estimation + else if (searchInterval.start > this.timestamps[startingIndex]) { startingIndex = startingIndex < lastFoundIndex ? lastFoundIndex : startingIndex; startingIndex = this.binarySearch(searchInterval.start, startingIndex, this.timestamps.length - 1); }else { diff --git a/TimeTrace/src/models/Types/EventMapping.ts b/TimeTrace/src/models/Types/EventMapping.ts index 020327b..d566c69 100644 --- a/TimeTrace/src/models/Types/EventMapping.ts +++ b/TimeTrace/src/models/Types/EventMapping.ts @@ -29,6 +29,9 @@ export class CustomMap { } } + /** + * Generic set that will either insert a key-value pair into the string or regexMap + */ set(key: MapKey, value: string) { if (key.isRegex) this.setRegex(key.key, value) @@ -36,28 +39,40 @@ export class CustomMap { this.setString(key.key, value) } + /** + * Creates an entry in the stringMap + */ setString(key: string, value: string): this { this.stringMap.set(key, value); return this; } + /** + * Creates an entry in the regexMap + */ setRegex(key: string, value: string): this { this.regexMap.set(key, value); return this; } + /** + * Used to retrieve the mapping of an event + * @returns string | undefined + */ get(eventString: string, fullString?: string): string | undefined { let value = this.stringMap.get(eventString); - if (value !== undefined && value!=="") { + if (value !== undefined && value !=="") { return value; } if (fullString !== undefined) { value = this.stringMap.get(fullString); + // A mapping for the event was found in the stringMap. if (value !== undefined && value!=="") { return value; } + // A mapping for the event was found in the regexMap. for (const [regex, val] of Array.from(this.regexMap.entries())) { if (new RegExp(regex).test(fullString)) { //only search in regex on full string return val; @@ -68,6 +83,9 @@ export class CustomMap { return undefined; } + /** + * Removes either a key from the string or regex map + */ remove(key: string): void { if (this.stringMap.has(key)) { this.stringMap.delete(key); @@ -80,6 +98,11 @@ export class CustomMap { } } + /** + * + * @returns An array of tuples [string, string], where each tuple is an entry in the map. + * The first item of the tuple is the key from one of the maps and the value is the value. + */ allMappings(): [string, string][] { let mappings: [string, string][] = []; for (const [regex, val] of Array.from(this.regexMap.entries())) { @@ -93,6 +116,10 @@ export class CustomMap { return mappings } + /** + * + * @returns A string[] containing the values from the regexMap concatenated with the values from the stringMap. + */ values(): string[] { return Array.from(this.regexMap.values()).concat(Array.from(this.stringMap.values())); } diff --git a/TimeTrace/src/models/Types/FileLine.ts b/TimeTrace/src/models/Types/FileLine.ts index eb49f04..cfcead5 100644 --- a/TimeTrace/src/models/Types/FileLine.ts +++ b/TimeTrace/src/models/Types/FileLine.ts @@ -5,8 +5,4 @@ export type FileLine = { export function mapEventsToFileLine(events: string[]): FileLine[] { return events.map((event, fileLine) => { return { text: event, line: fileLine } as FileLine }) -} - -export function mapFileLineToEvents(fileLines: FileLine[]): string[] { - return fileLines.map((fileLine) => fileLine.text); } \ No newline at end of file diff --git a/TimeTrace/src/models/Types/hashMap.ts b/TimeTrace/src/models/Types/hashMap.ts index 1a2a90f..14b5a4a 100644 --- a/TimeTrace/src/models/Types/hashMap.ts +++ b/TimeTrace/src/models/Types/hashMap.ts @@ -1,3 +1,7 @@ + +/** + * HashMap consisting of key-value pairs where the key is the timestamp from an event and the value is the index of the line in the logfile. + */ export class HashMap { private map: Record; diff --git a/TimeTrace/src/models/helpers/cn.ts b/TimeTrace/src/models/helpers/cn.ts index 24dfbb1..83de54c 100644 --- a/TimeTrace/src/models/helpers/cn.ts +++ b/TimeTrace/src/models/helpers/cn.ts @@ -1,3 +1,8 @@ + +/** + * Typically used when html classes are conditionally rendered + * @returns a string array of all the html classes that will be added to an element. + */ export function cn(...classes: String[]) { return classes.filter(Boolean).join(" "); } \ No newline at end of file diff --git a/TimeTrace/src/models/helpers/dateFormats.ts b/TimeTrace/src/models/helpers/dateFormats.ts index 497fd13..d0dcdcd 100644 --- a/TimeTrace/src/models/helpers/dateFormats.ts +++ b/TimeTrace/src/models/helpers/dateFormats.ts @@ -1,3 +1,8 @@ +import { LogFormatter } from "../LogFormatter"; + +/** + * Defines the different Dateformats one can choose. + */ export enum DateFormat { ISO_8601 = "ISO 8601", YYMMDD_HH_MM_SS = "YYMMDD HH.MM.SS", @@ -5,6 +10,9 @@ export enum DateFormat { YYYY_MM_DD_HH_MM_SS_MMM = "YYYY-DD-MM HH:MM:SS.MMM", } +/** + * Used to define the properties in the dateFormats object {@link dateFormats} + */ interface DateFormats { [DateFormat.ISO_8601]: RegExp; [DateFormat.YYMMDD_HH_MM_SS]: RegExp; @@ -12,6 +20,10 @@ interface DateFormats { [DateFormat.YYYY_MM_DD_HH_MM_SS_MMM]: RegExp; } +/** + * Object that is used to dynamically access the regex needed to extract timestamps based on the + * {@link LogFormatter.DateFormat} + */ export const dateFormats : DateFormats = { [DateFormat.ISO_8601]: /\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{1,6}(Z|[+-]\d{2}:\d{2})\b/g, [DateFormat.YYMMDD_HH_MM_SS]: /\b\d{6} \d{2}\.\d{2}\.\d{2}\b/g, diff --git a/TimeTrace/src/models/helpers/extractEventFromLine.ts b/TimeTrace/src/models/helpers/extractEventFromLine.ts index 99e062c..967cb3c 100644 --- a/TimeTrace/src/models/helpers/extractEventFromLine.ts +++ b/TimeTrace/src/models/helpers/extractEventFromLine.ts @@ -1,7 +1,13 @@ + +/** + * @returns a string that is only an event string from the log file + */ export function extractEventFromLine(line: string, timestamp: string): string { line = line.replace(timestamp, "") - line = line.replace(/(^\s*)|(\s*$)/gi,""); //remove leading and trailing spaces - line = line.replace(/\n /,"\n"); //remove newlines + //remove leading and trailing spaces + line = line.replace(/(^\s*)|(\s*$)/gi,""); + //remove newlines + line = line.replace(/\n /,"\n"); line = line.replace(/\r/, ""); return line; } \ No newline at end of file diff --git a/TimeTrace/src/models/helpers/extractEventsFromFileLines.ts b/TimeTrace/src/models/helpers/extractEventsFromFileLines.ts index 329de15..41beb00 100644 --- a/TimeTrace/src/models/helpers/extractEventsFromFileLines.ts +++ b/TimeTrace/src/models/helpers/extractEventsFromFileLines.ts @@ -1,6 +1,10 @@ import { extractEventFromLine } from "./extractEventFromLine"; import { extractTimeStamp } from "./extractTimeStamp"; + +/** + * @returns All the event strings in a log file + */ export function extractEventsFromFileLines(fileLines: string[]): string[] { let events = fileLines.map((line, i) => { diff --git a/TimeTrace/src/models/helpers/extractTimeStamp.ts b/TimeTrace/src/models/helpers/extractTimeStamp.ts index 9d9311b..efb2a13 100644 --- a/TimeTrace/src/models/helpers/extractTimeStamp.ts +++ b/TimeTrace/src/models/helpers/extractTimeStamp.ts @@ -1,6 +1,10 @@ import { LogFormatter } from "../LogFormatter"; import { dateFormats } from "./dateFormats"; + +/** + * @returns a timestamp extracted via {@link dateFormats} and the currently selected dateFormat {@link LogFormatter.dateFormat} + */ export function extractTimeStamp(line: string): string { let timestamp: string | undefined; diff --git a/TimeTrace/src/models/helpers/filterLinesBasedOnShowMode.ts b/TimeTrace/src/models/helpers/filterLinesBasedOnShowMode.ts index e2a5783..83552cf 100644 --- a/TimeTrace/src/models/helpers/filterLinesBasedOnShowMode.ts +++ b/TimeTrace/src/models/helpers/filterLinesBasedOnShowMode.ts @@ -1,10 +1,11 @@ import { ShowLinesMode } from "../../context/LogTableContext"; import { FileLine } from "../FileLine"; import { CustomMap } from "../Types/EventMapping"; -import { extractEventFromLine } from "./extractEventFromLine"; -import { extractTimeStamp } from "./extractTimeStamp"; +/** + * @returns Only the lines the user want to read based on {@link ShowLinesMode} + */ export function filterAllMappedUnmappedLines(lines: FileLine[], mode: ShowLinesMode, mappings: CustomMap): FileLine[] { const filtered = lines.filter((line: FileLine) => { //filter that either returns all lines, lines where mapping!==undefined (mapped) or mapping===undefined (unmapped) switch (mode) { diff --git a/TimeTrace/src/models/helpers/getFileLines.ts b/TimeTrace/src/models/helpers/getFileLines.ts index cbde796..c107a7a 100644 --- a/TimeTrace/src/models/helpers/getFileLines.ts +++ b/TimeTrace/src/models/helpers/getFileLines.ts @@ -1,16 +1,23 @@ - +/** + * @returns A promise Promise. That is a promise that when resolved contains all the lines from a logfile. + */ export async function getFileLines(file: File): Promise { - return new Promise((resolve, reject) => { //must return promise because reader is async + //must return promise because reader is async + return new Promise((resolve, reject) => { let reader = new FileReader(); reader.onload = async (event) => { - let textLines = (reader.result as string).split("\n"); //split file on newlines + //split file on newlines + let textLines = (reader.result as string).split("\n"); textLines = textLines.filter(line => line.replace(/(\r\n|\n|\r)/gm, "") !== '') - resolve(textLines); //all went well, return textLines + //all went well, return textLines + resolve(textLines); }; - reader.onerror = async (e) => { //on error reject + //on error reject + reader.onerror = async (e) => { console.error("Unable to read file", file.name, e); reject(e); }; - reader.readAsText(file); //call reader + //call reader + reader.readAsText(file); }); } \ No newline at end of file diff --git a/TimeTrace/src/models/helpers/predefinedRegexes.ts b/TimeTrace/src/models/helpers/predefinedRegexes.ts index 84068cb..2aba0cb 100644 --- a/TimeTrace/src/models/helpers/predefinedRegexes.ts +++ b/TimeTrace/src/models/helpers/predefinedRegexes.ts @@ -1,6 +1,7 @@ /** - * Generates a regex that maches all numbers from the next factor i.e. 100 -> [1-9][0-9][0-9][0-9]+ + * Generates a regex that maches all numbers from the next factor of the lowerbound + * e.g., lowerBound = 100 then this will return -> [1-9][0-9][0-9][0-9]+ * @param {*} lowerBound * @returns A regex that matches all numbers from the next factor. */ @@ -9,11 +10,13 @@ function generateLargerPart(lowerBound: string): string { let largerPart: string = ""; for (let i = 0; i < numLen; i++) { if (i === 0) { + //The beginning of the next factor | is prepended because this is also a pattern we want to match. largerPart += "|([1-9]"; } largerPart += "[0-9]"; } largerPart += "+"; + //To match numbers with decimals largerPart += "))(\\.\\d+)?"; return largerPart; } @@ -26,13 +29,17 @@ export function generateInclusiveOverRegex(lowerBound: string): string { let pattern = "(("; let currentFactor = 0; const lowerBoundStr = lowerBound.toString(); - // This pattern ensures that when 33 is entered, 40, 50, 60 and so on can be matched. + // The roundNumbersPattern ensures that when 33 is entered, 40, 50, 60 and so on can be matched. let roundNumbersPattern = "|("; const overflow: boolean = lowerBoundStr[0] === "9"; const sum: number = overflow ? parseInt(lowerBoundStr[0]) : parseInt(lowerBoundStr[0]) + 1; // If there is overflow then we must go to the next factor, therefore we add two parts. + // e.g., when lowerBound is '99' then this pattern should be able to match 100, 110 and so on. roundNumbersPattern += overflow ? "[1-9][0-9]" : `[${sum}-9]`; + //Constructs the inclusive over part. + //This simply repeats the digits in the lowerBound and then allows the range to go up to 9. + // e.g., if lowerbound is one this would be [1-9] the other patterns will handle the rest. for (const digit of lowerBoundStr) { if (currentFactor === 0) { pattern += `[${digit}-9]`; @@ -45,6 +52,7 @@ export function generateInclusiveOverRegex(lowerBound: string): string { roundNumbersPattern += ")"; pattern += ")"; const largerPart = generateLargerPart(lowerBound); + // Ensures that the pattern will not match any digits that are provided as decimals. const dontMatchDigitsAfterDot = "(?= current, then all good for (let i = 0; i < lines.length - 1; i++) { diff --git a/TimeTrace/src/pages/LogPage.tsx b/TimeTrace/src/pages/LogPage.tsx index c4c2557..a76b64a 100644 --- a/TimeTrace/src/pages/LogPage.tsx +++ b/TimeTrace/src/pages/LogPage.tsx @@ -12,6 +12,9 @@ import TimedEventTRE from "../components/predefined-tres/TimedEventTRE"; import TimedSequentialTRE from "../components/predefined-tres/TimedSequentialTRE"; import { ButtonStyle } from "../components/button/IButtonProps"; +/** + * @returns The page to analyse a log file with TREs. + */ function LogPage() { const { uploadedFile } = useContext(AppdataContext); const { setError } = useContext(AppdataContext); @@ -20,6 +23,9 @@ function LogPage() { + /** + * sets preventDefault on the event. + */ function handleOnBeforeUnload(e: BeforeUnloadEvent) { e.preventDefault(); return (e.returnValue = ''); @@ -44,6 +50,9 @@ function LogPage() { } }, [uploadedFile, setError]); + /** + * Function used to create a Modal based on a {@link PredefinedTre} that allows users to type information into predefinedTRES + */ function createModalObject(predefTREType: PredefinedTre) { let predefinedTRE: ReactNode; let modalTitle: string = ''; diff --git a/TimeTrace/src/pages/MappingsPage.tsx b/TimeTrace/src/pages/MappingsPage.tsx index 4655765..b5c8784 100644 --- a/TimeTrace/src/pages/MappingsPage.tsx +++ b/TimeTrace/src/pages/MappingsPage.tsx @@ -4,6 +4,10 @@ import MappedItemsList from "../components/MappedItemsList"; import LogTable from "../components/logtable/LogTable"; import LogTableProvider from '../context/LogTableContext'; +/** + * + * @returns The page to create mappings + */ function MappingsPage() { function handleOnBeforeUnload(e: BeforeUnloadEvent) {