Skip to content

Commit

Permalink
fix: restore attributes with formulas properly (#1239)
Browse files Browse the repository at this point in the history
  • Loading branch information
kswenson authored May 2, 2024
1 parent 19ec614 commit f4ab50b
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 10 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/v3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
fail-fast: false
matrix:
# run multiple copies of the current job in parallel
containers: [1, 2, 3]
containers: [1, 2, 3, 4]
# containers: [1]
steps:
- name: Checkout
Expand Down
12 changes: 8 additions & 4 deletions v3/cypress/e2e/map.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ context("Map UI", () => {
c.checkToolTip($element, c.tooltips.mapCameraButton)
})
})
it("checks numerical and categorical attributes for map legend", () => {
// flaky test skipped in PR #1239, see PT #187534790
it.skip("checks numerical and categorical attributes for map legend", () => {
cfm.openLocalDoc(filename2)
c.getIconFromToolshelf("map").click()
cy.dragAttributeToTarget("attribute", arrayOfAttributes[0], "map")
Expand Down Expand Up @@ -162,7 +163,8 @@ context("Map UI", () => {
map.getHideUnselectedCases().should("not.be.disabled")
map.getShowAllCases().should("be.disabled")
})
it("checks show/hide map boundaries with legend selections", () => {
// flaky test skipped in PR #1239, see PT #187534790
it.skip("checks show/hide map boundaries with legend selections", () => {
cfm.openLocalDoc(filename2)
c.getIconFromToolshelf("map").click()
cy.dragAttributeToTarget("attribute", arrayOfAttributes[0], "map")
Expand Down Expand Up @@ -202,7 +204,8 @@ context("Map UI", () => {
// PT bug - #186916697
// mlh.verifyCategoricalLegend(1)
})
it("checks show/hide map points with legend selections", () => {
// flaky test skipped in PR #1239, see PT #187534790
it.skip("checks show/hide map points with legend selections", () => {
cfm.openLocalDoc(filename1)
c.getIconFromToolshelf("map").click()
cy.wait(1000)
Expand Down Expand Up @@ -243,7 +246,8 @@ context("Map UI", () => {
// PT bug - #186916697
// mlh.verifyCategoricalLegend(1)
})
it("checks legend attribute menu", () => {
// flaky test skipped in PR #1239, see PT #187534790
it.skip("checks legend attribute menu", () => {
cfm.openLocalDoc(filename2)
c.getIconFromToolshelf("map").click()
cy.dragAttributeToTarget("attribute", arrayOfAttributes[0], "map")
Expand Down
14 changes: 14 additions & 0 deletions v3/src/models/data/attribute.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,13 @@ describe("Attribute", () => {
expect(x2.values).toBeUndefined()
expect(x2.strValues).toEqual([])
expect(x2.numValues).toEqual([])

// after attributes with formulas restore without values, setLength initializes the values
// so that formula evaluation can fill them in later.
x2.setLength(3)
expect(x2.values).toBeUndefined()
expect(x2.strValues).toEqual(["", "", ""])
expect(x2.numValues).toEqual([NaN, NaN, NaN])
})

test("Serialization of an attribute with formula (production)", () => {
Expand All @@ -369,6 +376,13 @@ describe("Attribute", () => {
expect(x2.values).toEqual([])
expect(x2.strValues).toEqual([])
expect(x2.numValues).toEqual([])

// after attributes with formulas restore without values, setLength initializes the values
// so that formula evaluation can fill them in later.
x2.setLength(3)
expect(x2.values).toEqual(["", "", ""])
expect(x2.strValues).toEqual(["", "", ""])
expect(x2.numValues).toEqual([NaN, NaN, NaN])
})

test("Attribute formulas", () => {
Expand Down
17 changes: 15 additions & 2 deletions v3/src/models/data/attribute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { V2Model } from "./v2-model"
export const kDefaultFormatStr = ".3~f"

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

export type IValueType = string | number | boolean | undefined

Expand Down Expand Up @@ -170,7 +171,7 @@ export const Attribute = V2Model.named("Attribute").props({
withoutUndo({ suppressWarning: true })
self.values = [...self.strValues]
}
if (!isDevelopment() && !self.shouldSerializeValues) {
if (isProduction() && !self.shouldSerializeValues) {
// In development, values is set to the volatile strValues (see .afterCreate()). If the attribute values should
// NOT be serialized (non-empty formula) we need to temporarily set it to undefined.
withoutUndo({ suppressWarning: true })
Expand All @@ -184,7 +185,7 @@ export const Attribute = V2Model.named("Attribute").props({
withoutUndo({ suppressWarning: true })
self.values = undefined
}
if (!isDevelopment() && !self.shouldSerializeValues) {
if (isProduction() && !self.shouldSerializeValues) {
// values should be set back to the volatile strValues in production mode.
withoutUndo({ suppressWarning: true })
self.values = self.strValues
Expand Down Expand Up @@ -316,6 +317,18 @@ export const Attribute = V2Model.named("Attribute").props({
}
self.incChangeCount()
},
setLength(length: number) {
if (self.strValues.length < length) {
self.strValues = self.strValues.concat(new Array(length - self.strValues.length).fill(""))
if (isProduction()) {
// in production mode, `strValues` shares the `values` array since it isn't frozen
self.values = self.strValues
}
}
if (self.numValues.length < length) {
self.numValues = self.numValues.concat(new Array(length - self.numValues.length).fill(NaN))
}
},
removeValues(index: number, count = 1) {
if ((index != null) && (index < self.strValues.length) && (count > 0)) {
self.strValues.splice(index, count)
Expand Down
10 changes: 7 additions & 3 deletions v3/src/models/data/data-set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,11 @@ export const DataSet = V2Model.named("DataSet").props({
self.caseIDMap.set(aCase.__id__, index)
})

// make sure attributes have appropriate length, including attributes with formulas
self.attributesMap.forEach(attr => {
attr.setLength(self.cases.length)
})

if (!srcDataSet) {
// set up middleware to add ids to inserted attributes and cases
// adding the ids in middleware makes them available as action arguments
Expand Down Expand Up @@ -925,9 +930,8 @@ export const DataSet = V2Model.named("DataSet").props({
}

// fill out any missing values
for (let i = attribute.strValues.length; i < self.cases.length; ++i) {
attribute.addValue()
}
attribute.setLength(self.cases.length)

// add the attribute to the specified collection (if any)
if (collectionId) {
const collection = self.getGroupedCollection(collectionId)
Expand Down

0 comments on commit f4ab50b

Please sign in to comment.