diff --git a/frontend/utilities/convert_to_csv/convert_to_csv.tests.ts b/frontend/utilities/convert_to_csv/convert_to_csv.tests.ts index 0937a81f46..21f66ede87 100644 --- a/frontend/utilities/convert_to_csv/convert_to_csv.tests.ts +++ b/frontend/utilities/convert_to_csv/convert_to_csv.tests.ts @@ -11,6 +11,7 @@ const objArray = [ }, ]; +// tests json known value edge case and hypothetical key edge case const objArray2 = [ { host_display_name: "Rachel@Fleet", @@ -22,6 +23,7 @@ const objArray2 = [ hibernatefile: "/var/vm/sleepimage", }, }, + 'edge","case': "true", }, ]; @@ -30,6 +32,7 @@ const tableHeaders = [ { id: "last_fetched", sortType: "caseInsensitive" }, { id: "uid", sortType: "alphanumeric" }, { id: "json_result", sortType: "caseInsensitive" }, + { id: 'edge","case', sortType: "caseInsensitve" }, ]; describe("convertToCSV - utility", () => { @@ -38,9 +41,9 @@ describe("convertToCSV - utility", () => { '"first_name","last_name"\n"Mike","Stone"\n"Paul","Simon"' ); }); - it("correctly creates table headers and fields with quotes and commas to CSV format", () => { + it("correctly creates table headers and fields including quotes and commas to CSV format", () => { expect(convertToCSV({ objArray: objArray2, tableHeaders })).toEqual( - '"host_display_name","last_fetched","uid","json_result"\n"Rachel@Fleet","2024-06-25T13:11:18Z","145","{""AC Power:"":{""acwake"":""0"",""hibernatefile"":""/var/vm/sleepimage""}}"' + '"host_display_name","last_fetched","uid","json_result","edge"",""case"\n"Rachel@Fleet","2024-06-25T13:11:18Z","145","{""AC Power:"":{""acwake"":""0"",""hibernatefile"":""/var/vm/sleepimage""}}","true"' ); }); }); diff --git a/frontend/utilities/convert_to_csv/index.ts b/frontend/utilities/convert_to_csv/index.ts index e6b5eb9962..5a4b7b4769 100644 --- a/frontend/utilities/convert_to_csv/index.ts +++ b/frontend/utilities/convert_to_csv/index.ts @@ -6,6 +6,21 @@ interface ConvertToCSV { tableHeaders?: any[]; // TODO: typing } +const formatFieldForCSV = (value: any): string => { + // If the value is an object, stringify it first + if (typeof value === "object") { + value = JSON.stringify(value); + } + // Escape double quotes in the value by doubling them + if (typeof value === "string") { + value = value.replace(/"/g, '""'); + } + + // Wrap the value in double quotes to enclose any value that may + // have a, or a " in it to distinguish them from a comma separated delimiter + return `"${value}"`; +}; + const convertToCSV = ({ objArray, fieldSortFunc = defaultFieldSortFunc, @@ -15,45 +30,18 @@ const convertToCSV = ({ ? tableHeaders.map((header: { id: string }) => header.id) : Object.keys(objArray[0]); - const fields = fieldSortFunc(tableHeadersStrings); + let fields = fieldSortFunc(tableHeadersStrings); // TODO: Revisit after v5 if column names are modified/removed from API response. - const hostNameIndex = fields.indexOf("Host"); - if (hostNameIndex >= 0) { - fields.splice(hostNameIndex, 1); - } + fields = fields.filter((field) => field !== "Host"); // Revisit end - const jsonFields = fields.map((field) => JSON.stringify(field)); - const rows = objArray.map((row: any) => { - // TODO: typing - return fields - .map((field) => { - // Check if the value of the field is a string and needs to be quoted - let value = row[field]; + const headerRow = fields.map((field) => formatFieldForCSV(field)).join(","); + const dataRows = objArray.map((row) => + fields.map((field) => formatFieldForCSV(row[field])).join(",") + ); - // If the value is an object, stringify it first - if (typeof value === "object") { - value = JSON.stringify(value); - } - - // Escape double quotes in the value by doubling them - if (typeof value === "string") { - value = value.replace(/"/g, '""'); - } - - // Wrap the value in double quotes to enclose any value tha - // might have a, or a " in it to distinguish them from a comma separated delimiter - value = `"${value}"`; - - return value; - }) - .join(","); - }); - - rows.unshift(jsonFields.join(",")); - - return rows.join("\n"); + return [headerRow, ...dataRows].join("\n"); }; export default convertToCSV;