diff --git a/src/components/flat-table.tsx b/src/components/flat-table.tsx
index 1a96165..4d3edd7 100644
--- a/src/components/flat-table.tsx
+++ b/src/components/flat-table.tsx
@@ -1,6 +1,7 @@
import React from "react";
import { ITableProps, IValues } from "../types";
import { DraggableTableContainer, DraggagleTableHeader } from "./draggable-table-tags";
+import { getAttrPrecisions, getAttrTypes, getAttrVisibility } from "../utils/utils";
import css from "./tables.scss";
@@ -12,8 +13,12 @@ export const FlatTable = (props: IFlatProps) => {
const {selectedDataSet, collections, collectionClasses, items, mapCellsFromValues, showHeaders} = props;
const collection = collections[0];
const {className} = collectionClasses[0];
+ const attrVisibilities = getAttrVisibility(collections);
+ const collectionAttrsToUse = collection.attrs.filter(attr => !attrVisibilities[attr.title]);
- const titles = collection.attrs.map(attr => attr.title);
+ const titles = collectionAttrsToUse.map(attr => attr.title);
+ const precisions = getAttrPrecisions(collections);
+ const attrTypes = getAttrTypes(collections);
const orderedItems = items.map(item => {
const orderedItem: IValues = {};
titles.forEach(title => {
@@ -34,7 +39,7 @@ export const FlatTable = (props: IFlatProps) => {
{collections[0].title} |
}
- {collection.attrs.map((attr: any) =>
+ {collectionAttrsToUse.map((attr: any) =>
{
{orderedItems.map((item, index) => {
return (
- {mapCellsFromValues(collection.id, `row-${index}`, item)}
+
+ {mapCellsFromValues(collection.id, `row-${index}`, item, precisions, attrTypes, attrVisibilities)}
+
);
})}
diff --git a/src/components/landscape-view.tsx b/src/components/landscape-view.tsx
index d9fcab3..5b896f3 100644
--- a/src/components/landscape-view.tsx
+++ b/src/components/landscape-view.tsx
@@ -1,6 +1,7 @@
import React from "react";
import { ICollection, IProcessedCaseObj, ITableProps } from "../types";
import { DraggagleTableHeader } from "./draggable-table-tags";
+import { getAttrPrecisions, getAttrTypes, getAttrVisibility } from "../utils/utils";
import css from "./tables.scss";
@@ -12,6 +13,9 @@ export const LandscapeView = (props: ITableProps) => {
const firstRowValues = parentColl.cases.map(caseObj => caseObj.values);
const valueCount = getValueLength(firstRowValues);
const className = getClassName(parentColl.cases[0]);
+ const precisions = getAttrPrecisions(collections);
+ const attrTypes = getAttrTypes(collections);
+ const attrVisibilities = getAttrVisibility(collections);
return (
<>
{showHeaders &&
@@ -19,10 +23,12 @@ export const LandscapeView = (props: ITableProps) => {
{parentColl.name} |
}
- {firstRowValues.map(values => mapHeadersFromValues(parentColl.id, "first-row", values))}
+ {firstRowValues.map(values => mapHeadersFromValues(parentColl.id, "first-row", values, attrVisibilities))}
- {firstRowValues.map(values => mapCellsFromValues(parentColl.id, "first-row", values))}
+ {firstRowValues.map(values =>
+ mapCellsFromValues(parentColl.id, "first-row", values, precisions, attrTypes, attrVisibilities))
+ }
{parentColl.cases.map((caseObj) => {
@@ -46,6 +52,10 @@ export const LandscapeView = (props: ITableProps) => {
const renderColFromCaseObj = (collection: ICollection, caseObj: IProcessedCaseObj, index?: number) => {
const {children, values} = caseObj;
const isFirstIndex = index === 0;
+ const precisions = getAttrPrecisions(collections);
+ const attrTypes = getAttrTypes(collections);
+ const attrVisibilities = getAttrVisibility(collections);
+
if (!children.length) {
const className = getClassName(caseObj);
return (
@@ -57,10 +67,10 @@ export const LandscapeView = (props: ITableProps) => {
}
{isFirstIndex &&
- {mapHeadersFromValues(collection.id, `first-row-${index}`, values)}
+ {mapHeadersFromValues(collection.id, `first-row-${index}`, values, attrVisibilities)}
}
- {mapCellsFromValues(collection.id, `row-${index}`, values)}
+ {mapCellsFromValues(collection.id, `row-${index}`, values, precisions, attrTypes, attrVisibilities)}
>
);
} else {
diff --git a/src/components/nested-table.tsx b/src/components/nested-table.tsx
index f3ab55c..f9b1257 100644
--- a/src/components/nested-table.tsx
+++ b/src/components/nested-table.tsx
@@ -89,11 +89,12 @@ export const NestedTable = (props: IProps) => {
updateInteractiveState({displayMode: e.target.value});
}, [updateInteractiveState]);
- const mapHeadersFromValues = (collectionId: number, rowKey: string, values: IValues) => {
+ const mapHeadersFromValues = (collectionId: number, rowKey: string, values: IValues,
+ attrVisibilities: Record) => {
return (
<>
{(Object.keys(values)).map((key, index) => {
- if (typeof values[key] === "string" || typeof values[key] === "number") {
+ if (!attrVisibilities[key] && (typeof values[key] === "string" || typeof values[key] === "number")) {
return (
{
);
};
- const mapCellsFromValues = (collectionId: number, rowKey: string, values: IValues, isParent?: boolean,
- resizeCounter?: number, parentLevel?: number) => {
+ const mapCellsFromValues = (collectionId: number, rowKey: string, values: IValues,
+ precisions: Record, attrTypes: Record,
+ attrVisibilities: Record, isParent?: boolean, resizeCounter?: number, parentLevel?: number) => {
return Object.keys(values).map((key, index) => {
- const val = values[key];
+ const isWholeNumber = values[key] % 1 === 0;
+ const precision = precisions[key];
+ // Numbers are sometimes passed in from CODAP as a string so we use the attribute type to
+ // determine if it should be parsed as a number.
+ // Numbers that are whole numbers are treated as integers, so we should ignore the precision.
+ // Numeric cells that are empty should be treated as empty strings.
+ const val = (attrTypes[key] !== "numeric" && attrTypes[key] !== null)
+ || (values[key] === "")
+ || (typeof values[key] !== "number")
+ ? values[key]
+ : isWholeNumber
+ ? parseInt(values[key],10)
+ : precision !== undefined
+ ? (parseFloat(values[key])).toFixed(precision)
+ : (parseFloat(values[key])).toFixed(2); // default to 2 decimal places
+ if (attrVisibilities[key]) {
+ return null;
+ }
if (typeof val === "string" || typeof val === "number") {
return (
,
+ attrTypes: Record,
+ attrVisibilities: Record,
isParent: boolean, resizeCounter: number, parentLevel?: number}
& ITableProps;
export const PortraitViewRow = (props: PortraitViewRowProps) => {
- const {paddingStyle, mapCellsFromValues, mapHeadersFromValues, showHeaders,
+ const {paddingStyle, mapCellsFromValues, mapHeadersFromValues, showHeaders, precisions, attrTypes, attrVisibilities,
getClassName, collectionId, caseObj, index, isParent, resizeCounter, parentLevel} = props;
const {children, values} = caseObj;
if (!children.length) {
return (
- {mapCellsFromValues(collectionId, `row-${index}`, values)}
+ {mapCellsFromValues(collectionId, `row-${index}`, values, precisions, attrTypes, attrVisibilities)}
);
} else {
return (
<>
{index === 0 &&
- {mapHeadersFromValues(collectionId, `first-row-${index}`, values)}
+ {mapHeadersFromValues(collectionId, `first-row-${index}`, values, attrVisibilities)}
{showHeaders ? (
{children[0].collection.name}
) : | }
}
- {mapCellsFromValues(collectionId, `parent-row-${index}`, values, isParent, resizeCounter, parentLevel)}
+ {mapCellsFromValues(collectionId, `parent-row-${index}`, values, precisions, attrTypes, attrVisibilities,
+ isParent, resizeCounter, parentLevel)}
@@ -49,7 +54,8 @@ export const PortraitViewRow = (props: PortraitViewRowProps) => {
return (
- {mapHeadersFromValues(child.collection.id, `child-row-${index}-${i}`, child.values)}
+ {mapHeadersFromValues(child.collection.id, `child-row-${index}-${i}`, child.values,
+ attrVisibilities)}
@@ -104,6 +110,9 @@ export const PortraitView = (props: ITableProps) => {
const {className} = collectionClasses[0];
const firstRowValues = parentColl.cases.map(caseObj => caseObj.values);
const valueCount = getValueLength(firstRowValues);
+ const precisions = getAttrPrecisions(collections);
+ const attrTypes = getAttrTypes(collections);
+ const attrVisibilities = getAttrVisibility(collections);
return (
@@ -122,6 +131,9 @@ export const PortraitView = (props: ITableProps) => {
collectionId={caseObj.collection.id}
caseObj={caseObj}
index={index}
+ precisions={precisions}
+ attrTypes={attrTypes}
+ attrVisibilities={attrVisibilities}
isParent={true}
resizeCounter={resizeCounter}
parentLevel={0}
diff --git a/src/hooks/useCodapState.tsx b/src/hooks/useCodapState.tsx
index 4d4ae63..191564b 100644
--- a/src/hooks/useCodapState.tsx
+++ b/src/hooks/useCodapState.tsx
@@ -100,6 +100,7 @@ export const useCodapState = () => {
case `updateAttributes`:
case `hideAttributes`:
case `showAttributes`:
+ case `unhideAttributes`:
refreshDataSetInfo();
break;
case `updateDataContext`: // includes renaming dataset, so we have to redo the menu
diff --git a/src/types.tsx b/src/types.tsx
index 9ba0c2c..2008040 100644
--- a/src/types.tsx
+++ b/src/types.tsx
@@ -55,9 +55,11 @@ export interface ITableProps {
getClassName: (caseObj: IProcessedCaseObj) => string,
selectedDataSet: IDataSet,
collections: Array,
- mapCellsFromValues: (collectionId: number, rowKey: string, values: IValues, isParent?: boolean,
- resizeCounter?: number, parentLevel?: number) => void,
- mapHeadersFromValues: (collectionId: number, rowKey: string, values: IValues) => void,
+ mapCellsFromValues: (collectionId: number, rowKey: string, values: IValues, precisions: Record,
+ attrTypes: Record, attrVisibilities: Record,
+ isParent?: boolean, resizeCounter?: number, parentLevel?: number) => void,
+ mapHeadersFromValues: (collectionId: number, rowKey: string, values: IValues,
+ attrVisibilities: Record) => void,
getValueLength: (firstRow: Array) => number
paddingStyle: Record
}
diff --git a/src/utils/utils.ts b/src/utils/utils.ts
new file mode 100644
index 0000000..a9ca49f
--- /dev/null
+++ b/src/utils/utils.ts
@@ -0,0 +1,39 @@
+import { ICollections } from "../types";
+
+const getAllAttributesFromCollections = (collections: ICollections[]) => {
+ const attrArray: any[] = [];
+ collections.forEach((collection: any) => {
+ attrArray.push(...collection.attrs);
+ });
+ return attrArray;
+};
+
+export const getAttrPrecisions = (collections: any) => {
+ const attrs = getAllAttributesFromCollections(collections);
+ const precisions = attrs.reduce((acc: Record, attr: any) => {
+ const numPrecision = parseInt(attr.precision, 10);
+ acc[attr.name] = isNaN(numPrecision) ? 2 : numPrecision;
+ return acc;
+ }, {});
+ return precisions;
+};
+
+export const getAttrTypes = (collections: any) => {
+ const attrs = getAllAttributesFromCollections(collections);
+ const attrTypes = attrs.reduce(
+ (acc: Record, attr: any) => {
+ acc[attr.name] = attr.type || null;
+ return acc;
+ }, {});
+ return attrTypes;
+};
+
+export const getAttrVisibility = (collections: any) => {
+ const attrs = getAllAttributesFromCollections(collections);
+ const attrVisibilities = attrs.reduce(
+ (acc: Record, attr: any) => {
+ acc[attr.name] = attr.hidden || false;
+ return acc;
+ }, {});
+ return attrVisibilities;
+};