Skip to content
Snippets Groups Projects
Unverified Commit 14dc53ca authored by Nemanja Glumac's avatar Nemanja Glumac Committed by GitHub
Browse files

Handle NULL value for integer fingerprints (#20003)


* Handle NULL value for integer fingerprints

Fixes #19976.

* conditionally show some or none of component depending on if numbers are present in fingerprint

* Make jsdoc return type accurate

* add unit tests for this scenario

* rmv unused import

Co-authored-by: default avatarDalton Johnson <daltojohnso@users.noreply.github.com>
parent f4d57e73
No related branches found
No related tags found
No related merge requests found
......@@ -64,6 +64,18 @@ function DateTimeFingerprint({ className, field }) {
);
}
/**
* @param {(number|null|undefined)} num - a number value from the type/Number fingerprint; might not be a number
* @returns {[boolean, string]} - a tuple, [isFormattedNumber, formattedNumber]
*/
function roundNumber(num) {
if (num == null) {
return [false, ""];
}
return [true, formatNumber(Number.isInteger(num) ? num : num.toFixed(2))];
}
function NumberFingerprint({ className, field }) {
const numberFingerprint = field.fingerprint.type?.["type/Number"];
if (!numberFingerprint) {
......@@ -71,28 +83,30 @@ function NumberFingerprint({ className, field }) {
}
const { avg, min, max } = numberFingerprint;
const fixedAvg = formatNumber(Number.isInteger(avg) ? avg : avg.toFixed(2));
const fixedMin = formatNumber(Number.isInteger(min) ? min : min.toFixed(2));
const fixedMax = formatNumber(Number.isInteger(max) ? max : max.toFixed(2));
const [isAvgNumber, formattedAvg] = roundNumber(avg);
const [isMinNumber, formattedMin] = roundNumber(min);
const [isMaxNumber, formattedMax] = roundNumber(max);
return (
const someNumberIsDefined = isAvgNumber || isMinNumber || isMaxNumber;
return someNumberIsDefined ? (
<Table className={className}>
<thead>
<tr>
<th>{t`Average`}</th>
<th>{t`Min`}</th>
<th>{t`Max`}</th>
{isAvgNumber && <th>{t`Average`}</th>}
{isMinNumber && <th>{t`Min`}</th>}
{isMaxNumber && <th>{t`Max`}</th>}
</tr>
</thead>
<tbody>
<tr>
<td>{fixedAvg}</td>
<td>{fixedMin}</td>
<td>{fixedMax}</td>
{isAvgNumber && <td>{formattedAvg}</td>}
{isMinNumber && <td>{formattedMin}</td>}
{isMaxNumber && <td>{formattedMax}</td>}
</tr>
</tbody>
</Table>
);
) : null;
}
FieldFingerprintInfo.propTypes = propTypes;
......
......@@ -122,6 +122,46 @@ describe("FieldFingerprintInfo", () => {
expect(screen.getByText("5")).toBeVisible();
});
});
describe("with empty type/Number fingerprint", () => {
beforeEach(() => {
numberField.fingerprint = {
type: {
"type/Number": {},
},
};
setup(numberField);
});
it("should render nothing", () => {
expect(container.firstChild).toBeNull();
});
});
describe("with missing type/Number property", () => {
beforeEach(() => {
numberField.fingerprint = {
type: {
"type/Number": {
min: 1,
max: 5,
},
},
};
setup(numberField);
});
it("should not render anything for the avg", () => {
expect(screen.queryByText("Average")).toBeNull();
});
it("should still render min and max", () => {
expect(screen.getByText("1")).toBeVisible();
expect(screen.getByText("5")).toBeVisible();
});
});
});
describe("Other field types", () => {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment