Skip to content

Commit

Permalink
Merge pull request #1679 from concord-consortium/188614511-attribute-…
Browse files Browse the repository at this point in the history
…value-types

chore: enhance attribute value types
  • Loading branch information
kswenson authored Dec 11, 2024
2 parents 7b918cf + b51a36a commit 9fd5270
Show file tree
Hide file tree
Showing 20 changed files with 58 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { graphPlaceToAttrRole } from "../../data-display/data-display-types"
import { useDataConfigurationContext } from "../../data-display/hooks/use-data-configuration-context"
import { useOutsidePointerDown } from "../../../hooks/use-outside-pointer-down"
import { useOverlayBounds } from "../../../hooks/use-overlay-bounds"
import { AttributeType } from "../../../models/data/attribute"
import { AttributeType } from "../../../models/data/attribute-types"
import { IDataSet } from "../../../models/data/data-set"
import {IUseDraggableAttribute, useDraggableAttribute} from "../../../hooks/use-drag-drop"
import {useInstanceIdContext} from "../../../hooks/use-instance-id-context"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Button, FormControl, FormLabel, HStack, Input, ModalBody, ModalCloseBut
import React, { useEffect, useState } from "react"
import { useDataSetContext } from "../../../hooks/use-data-set-context"
import { logMessageWithReplacement } from "../../../lib/log-message"
import { AttributeType, attributeTypes } from "../../../models/data/attribute"
import { AttributeType, attributeTypes } from "../../../models/data/attribute-types"
import { updateAttributesNotification } from "../../../models/data/data-set-notifications"
import { DatePrecision } from "../../../utilities/date-utils"
import { uniqueName } from "../../../utilities/js-utils"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { GraphPlace } from "../../axis-graph-shared"
import { useDataDisplayLayout } from "../hooks/use-data-display-layout"
import { useDataDisplayModelContext } from "../hooks/use-data-display-model"
import { AxisOrLegendAttributeMenu } from "../../axis/components/axis-or-legend-attribute-menu"
import { AttributeType } from "../../../models/data/attribute"
import { AttributeType } from "../../../models/data/attribute-types"
import { mstAutorun } from "../../../utilities/mst-autorun"

import "./attribute-label.scss"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, {useCallback, useEffect, useRef} from "react"
import {select} from "d3"
import {AttributeType} from "../../../../models/data/attribute"
import {AttributeType} from "../../../../models/data/attribute-types"
import {IDataSet} from "../../../../models/data/data-set"
import {axisGap} from "../../../axis/axis-types"
import {GraphPlace} from "../../../axis-graph-shared"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {applyModelChange} from "../../../models/history/apply-model-change"
import {cachedFnWithArgsFactory} from "../../../utilities/mst-utils"
import { isFiniteNumber } from "../../../utilities/math-utils"
import { stringValuesToDateSeconds } from "../../../utilities/date-utils"
import {AttributeType, attributeTypes} from "../../../models/data/attribute"
import {AttributeType, attributeTypes} from "../../../models/data/attribute-types"
import {DataSet, IDataSet} from "../../../models/data/data-set"
import {ICase} from "../../../models/data/data-set-types"
import {idOfChildmostCollectionForAttributes} from "../../../models/data/data-set-utils"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { t } from "../../../utilities/translation/translate"
import { useGraphDataConfigurationContext } from "../hooks/use-graph-data-configuration-context"
import { useGraphContentModelContext } from "../hooks/use-graph-content-model-context"
import { useGraphLayoutContext } from "../hooks/use-graph-layout-context"
import { AttributeType } from "../../../models/data/attribute"
import { AttributeType } from "../../../models/data/attribute-types"
import { IDataSet } from "../../../models/data/data-set"
import { GraphPlace, isVertical } from "../../axis-graph-shared"
import { AttributeLabel } from "../../data-display/components/attribute-label"
Expand Down
2 changes: 1 addition & 1 deletion v3/src/components/graph/components/graph-axis.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {useInstanceIdContext} from "../../../hooks/use-instance-id-context"
import {useGraphDataConfigurationContext} from "../hooks/use-graph-data-configuration-context"
import {useGraphContentModelContext} from "../hooks/use-graph-content-model-context"
import {useGraphLayoutContext} from "../hooks/use-graph-layout-context"
import {AttributeType} from "../../../models/data/attribute"
import {AttributeType} from "../../../models/data/attribute-types"
import {IDataSet} from "../../../models/data/data-set"
import {AxisPlace} from "../../axis/axis-types"
import {Axis} from "../../axis/components/axis"
Expand Down
2 changes: 1 addition & 1 deletion v3/src/components/graph/components/graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {GraphPlace} from "../../axis-graph-shared"
import {MarqueeState} from "../../data-display/models/marquee-state"
import {DataTip} from "../../data-display/components/data-tip"
import {MultiLegend} from "../../data-display/components/legend/multi-legend"
import {AttributeType} from "../../../models/data/attribute"
import {AttributeType} from "../../../models/data/attribute-types"
import {IDataSet} from "../../../models/data/data-set"
import {isUndoingOrRedoing} from "../../../models/history/tree-types"
import {useDataDisplayAnimation} from "../../data-display/hooks/use-data-display-animation"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {addDisposer, getSnapshot, Instance, SnapshotIn, types} from "mobx-state-tree"
import {comparer, reaction} from "mobx"
import {AttributeType} from "../../../models/data/attribute"
import {AttributeType} from "../../../models/data/attribute-types"
import {IDataSet} from "../../../models/data/data-set"
import {typedId} from "../../../utilities/js-utils"
import { cachedFnFactory, cachedFnWithArgsFactory, safeGetSnapshot } from "../../../utilities/mst-utils"
Expand Down
9 changes: 5 additions & 4 deletions v3/src/data-interactive/data-interactive-types.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { RequireAtLeastOne } from "type-fest"
import { LoggableValue } from "../lib/log-message"
import { IAttribute } from "../models/data/attribute"
import { ICodapV2Attribute, ICodapV2Collection, ICodapV2DataContext } from "../v2/codap-v2-types"
import { IValueType } from "../models/data/attribute-types"
import { ICollectionLabels, ICollectionModel } from "../models/data/collection"
import { IDataSet } from "../models/data/data-set"
import { ICase, ICaseID } from "../models/data/data-set-types"
import { IGlobalValue } from "../models/global/global-value"
import { ITileModel } from "../models/tiles/tile-model"
import { ICollectionLabels, ICollectionModel } from "../models/data/collection"
import { ICodapV2Attribute, ICodapV2Collection, ICodapV2DataContext } from "../v2/codap-v2-types"
import { V2SpecificComponent } from "./data-interactive-component-types"
import { LoggableValue } from "../lib/log-message"

export type DICaseValue = string | number | boolean | Date | undefined
export type DICaseValue = IValueType
export type DICaseValues = Record<string, DICaseValue>
export interface DIFullCase {
children?: number[]
Expand Down
3 changes: 2 additions & 1 deletion v3/src/data-interactive/handlers/di-handler-utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { IAttribute, isAttributeType } from "../../models/data/attribute"
import { IAttribute } from "../../models/data/attribute"
import { isAttributeType } from "../../models/data/attribute-types"
import { ICollectionModel } from "../../models/data/collection"
import { IDataSet } from "../../models/data/data-set"
import { IAddCollectionOptions } from "../../models/data/data-set-types"
Expand Down
4 changes: 2 additions & 2 deletions v3/src/hooks/use-drop-hint-string.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AttributeType } from "../models/data/attribute"
import {determineBaseString} from "./use-drop-hint-string"
import {GraphAttrRole} from "../components/data-display/data-display-types"
import {AttributeType} from "../models/data/attribute-types"
import {determineBaseString} from "./use-drop-hint-string"

interface Scenario {
role: GraphAttrRole
Expand Down
2 changes: 1 addition & 1 deletion v3/src/hooks/use-drop-hint-string.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {useDndContext} from "@dnd-kit/core"
import {AttributeType} from "../models/data/attribute"
import {AttributeType} from "../models/data/attribute-types"
import {getDragAttributeInfo} from "./use-drag-drop"
import {GraphPlace} from "../components/axis-graph-shared"
import {GraphAttrRole, attrRoleToGraphPlace} from "../components/data-display/data-display-types"
Expand Down
28 changes: 27 additions & 1 deletion v3/src/models/data/attribute-types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
import { formatStdISODateString } from "../../utilities/date-iso-utils"

export const kDefaultNumPrecision = 3
export const kDefaultNumFormatStr = `.${kDefaultNumPrecision}~f`

export const isDevelopment = () => process.env.NODE_ENV !== "production"
export const isProduction = () => process.env.NODE_ENV === "production"

export type IValueType = string | number | boolean | Date | undefined
export type IValueType = string | number | boolean | Date | object | undefined

export function importValueToString(value: IValueType): string {
if (value == null) {
return ""
}
if (typeof value === "string") {
return value
}
if (value instanceof Date) {
return formatStdISODateString(value)
}
if (typeof value === "object") {
return JSON.stringify(value)
}
return value.toString()
}

export const attributeTypes = [
"categorical", "numeric", "date", "qualitative", "boundary", "checkbox", "color"
] as const
export type AttributeType = typeof attributeTypes[number]
export function isAttributeType(type?: string | null): type is AttributeType {
return type != null && (attributeTypes as readonly string[]).includes(type)
}
6 changes: 3 additions & 3 deletions v3/src/models/data/attribute.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { cloneDeep } from "lodash"
import { reaction } from "mobx"
import { getSnapshot } from "mobx-state-tree"
import {
Attribute, IAttributeSnapshot, importValueToString, isAttributeType, isFormulaAttr, isValidFormulaAttr
} from "./attribute"
import { Attribute, IAttributeSnapshot, isFormulaAttr, isValidFormulaAttr } from "./attribute"
import { isAttributeType, importValueToString } from "./attribute-types"

describe("Attribute", () => {

Expand Down Expand Up @@ -47,6 +46,7 @@ describe("Attribute", () => {
expect(importValueToString(1e-6)).toBe("0.000001")
expect(importValueToString(true)).toBe("true")
expect(importValueToString(false)).toBe("false")
expect(importValueToString({ foo: "bar" })).toBe(`{"foo":"bar"}`)
expect(importValueToString(new Date(2020, 5, 14, 10, 13, 34, 123))).toBe("2020-06-14T10:13:34.123Z")

const attr = Attribute.create({ name: "a" })
Expand Down
26 changes: 3 additions & 23 deletions v3/src/models/data/attribute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,42 +28,22 @@
import { Instance, SnapshotIn, types } from "mobx-state-tree"
import { kAttrIdPrefix, typeV3Id } from "../../utilities/codap-utils"
import { parseColor } from "../../utilities/color-utils"
import { formatStdISODateString } from "../../utilities/date-iso-utils"
import { isDateString } from "../../utilities/date-parser"
import { DatePrecision } from "../../utilities/date-utils"
import { cachedFnFactory } from "../../utilities/mst-utils"
import { isBoundaryValue, kPolygonNames } from "../boundaries/boundary-types"
import { Formula, IFormula } from "../formula/formula"
import { applyModelChange } from "../history/apply-model-change"
import { withoutUndo } from "../history/without-undo"
import { isDevelopment, isProduction, IValueType } from "./attribute-types"
import {
AttributeType, attributeTypes, importValueToString, isDevelopment, isProduction, IValueType
} from "./attribute-types"
import { V2Model } from "./v2-model"

export interface ISetValueOptions {
noInvalidate?: boolean
}

export function importValueToString(value: IValueType): string {
if (value == null) {
return ""
}
if (typeof value === "string") {
return value
}
if (value instanceof Date) {
return formatStdISODateString(value)
}
return value.toString()
}

export const attributeTypes = [
"categorical", "numeric", "date", "qualitative", "boundary", "checkbox", "color"
] as const
export type AttributeType = typeof attributeTypes[number]
export function isAttributeType(type?: string | null): type is AttributeType {
return type != null && (attributeTypes as readonly string[]).includes(type)
}

export const Attribute = V2Model.named("Attribute").props({
id: typeV3Id(kAttrIdPrefix),
_cid: types.maybe(types.string), // cid was a v2 property that is used by some plugins (Collaborative)
Expand Down
3 changes: 2 additions & 1 deletion v3/src/models/data/data-set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import {
} from "mobx-state-tree"
import pluralize from "pluralize"
import { Attribute, IAttribute, IAttributeSnapshot } from "./attribute"
import { importValueToString } from "./attribute-types"
import {
CollectionModel, ICollectionModel, ICollectionModelSnapshot, IItemData, isCollectionModel, syncCollectionLinks
} from "./collection"
Expand Down Expand Up @@ -110,7 +111,7 @@ export function toCanonicalCase(ds: IDataSet, aCase: ICase | ICaseCreation): ICa
if (key !== "__id__") {
const id = ds.attrIDFromName(key)
if (id) {
canonical[id] = aCase[key]
canonical[id] = importValueToString(aCase[key] ?? "")
}
else {
console.warn(`Dataset.toCanonical failed to convert attribute: "${key}"`)
Expand Down
2 changes: 1 addition & 1 deletion v3/src/models/formula/formula-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export interface ILookupDependency {
export type IFormulaDependency = ILocalAttributeDependency | IBoundaryDependency |
IGlobalValueDependency | ILookupDependency

export type FValue = string | number | boolean | Date
export type FValue = string | number | boolean | Date | object

export type FValueOrArray = FValue | FValue[]

Expand Down
7 changes: 2 additions & 5 deletions v3/src/v2/codap-v2-document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,14 +204,11 @@ export class CodapV2Document {
this.guidMap.set(guid, { type: "DG.Case", object: _case })
// for level 0 (child-most collection), add items with their item ids and stash case ids
if (level === 0) {
// FIXME: values can include objects not just the primitives defined by IValueType
// FIXME: should the itemID overwrite any __id__ returned by toCanonical?
let itemValues = { ...toCanonical(data, values as any), __id__: itemID }
let itemValues = { __id__: itemID, ...toCanonical(data, values) }
// look up parent case attributes and add them to caseValues
for (let parentCase = this.getParentCase(_case); parentCase; parentCase = this.getParentCase(parentCase)) {
itemValues = {
// FIXME: see above
...(parentCase.values ? toCanonical(data, parentCase.values as any) : undefined),
...(parentCase.values ? toCanonical(data, parentCase.values) : undefined),
...itemValues
}
}
Expand Down
2 changes: 1 addition & 1 deletion v3/src/v2/codap-v2-types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { SetOptional } from "type-fest"
import {AttributeType} from "../models/data/attribute"
import { AttributeType } from "../models/data/attribute-types"

export interface ICodapV2Attribute {
guid: number
Expand Down

0 comments on commit 9fd5270

Please sign in to comment.