Skip to content

Commit

Permalink
Merge pull request #2327 from concord-consortium/185741802-categorica…
Browse files Browse the repository at this point in the history
…l-graph-copy-retains-data

feat: Categorical Graph copy retains data (PT-185741802)
  • Loading branch information
emcelroy authored Jul 3, 2024
2 parents 75b87a9 + 2f98e82 commit 5135999
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 25 deletions.
64 changes: 57 additions & 7 deletions cypress/e2e/functional/document_tests/tiles_copy_test_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import DataCardToolTile from '../../../support/elements/tile/DataCardToolTile';
import DataflowToolTile from '../../../support/elements/tile/DataflowToolTile';
import SimulatorTile from '../../../support/elements/tile/SimulatorTile';
import DiagramToolTile from '../../../support/elements/tile/DiagramToolTile';
import XYPlotToolTile from "../../../support/elements/tile/XYPlotToolTile";

const student5 = `${Cypress.config("qaUnitStudent5")}`;
const student6 = `${Cypress.config("qaUnitStudent6")}`;
Expand All @@ -24,22 +25,28 @@ let clueCanvas = new ClueCanvas,
dc = new DataCardToolTile,
dataflowToolTile = new DataflowToolTile,
simulatorTile = new SimulatorTile,
diagramTile = new DiagramToolTile;
diagramTile = new DiagramToolTile,
graphTile = new XYPlotToolTile;
let canvas = new Canvas;

const imageName = "Image Tile";
const simName = "Test Simulation";
const diagramName = "Test Diagram";
const categoricalGraphName = "Categorical Graph Test";
const categoricalGraphCopyName = "Categorical Graph Test 1";

const studentWorkspace = 'QA 1.1 Solving a Mystery with Proportional Reasoning';
const studentWorkspaceCopyTiles = 'Test Workspace Copy Tiles';
const studentClassWorkCopyTiles = 'Test Class Work Copy Tiles';

const tiles1 = [{ "name": "table" },
{ "name": "geometry" },
{ "name": "drawing" },
{ "name": "expression" },
{ "name": "numberline" },
{ "name": "image" }];
const tiles1 = [
{ "name": "table" },
{ "name": "geometry" },
{ "name": "drawing" },
{ "name": "expression" },
{ "name": "numberline" },
{ "name": "image" }
];
const tiles2 = [
{ "name": "data-card" },
{ "name": "dataflow" },
Expand Down Expand Up @@ -302,3 +309,46 @@ context('Test copy tiles from one document to other document', function () {

});
});

context("Test copy tile within a document", function () {
it("Copies a graph tile within a document", function () {
beforeTest(student5);

// Add table tile and populate it with categorical data.
cy.log("Add table tile with categorical data");
clueCanvas.addTile("table");
cy.get(".primary-workspace").within((workspace) => {
tableToolTile.typeInTableCellXY(0, 0, "small");
tableToolTile.getTableCellXY(0, 0).should("contain", "small");
tableToolTile.typeInTableCellXY(1, 0, "medium");
tableToolTile.getTableCellXY(1, 0).should("contain", "medium");
tableToolTile.typeInTableCellXY(0, 1, "red");
tableToolTile.getTableCellXY(0, 1).should("contain", "red");
tableToolTile.typeInTableCellXY(1, 1, "green");
tableToolTile.getTableCellXY(1, 1).should("contain", "green");
});

// Graph the table data in a new graph tile
cy.get("[data-original-title='Graph It!']").click();
cy.get("[data-test=link-tile-select]").select("New Graph");
cy.get(".modal-button").contains("Graph It").click();
graphTile.getTile().should("have.length", 1);
graphTile.getXYPlotTitle().first().should("contain", "Graph 1");
graphTile.getXYPlotTitle().first().click();
cy.get(".primary-workspace .graph-wrapper .editable-tile-title").first().type(categoricalGraphName + "{enter}");
graphTile.getXYPlotTitle().first().should("contain", categoricalGraphName);
graphTile.getGraphDot().should("have.length", 2).each(($g) => {
cy.wrap($g).should("have.attr", "transform").should("not.be.empty");
});

// Click on new graph tile to select it, then copy it
graphTile.getTile().first().click();
cy.get("[data-testid=tool-duplicate]").click();
graphTile.getTile().should("have.length", 2);
graphTile.getXYPlotTitle().eq(1).should("contain", categoricalGraphCopyName);
graphTile.getTile().eq(1).find("g.graph-dot").should("have.length", 2).each(($g) => {
cy.wrap($g).should("have.attr", "transform").should("not.be.empty");
});

});
});
62 changes: 44 additions & 18 deletions src/plugins/graph/models/graph-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -735,19 +735,18 @@ export const GraphModel = TileContentModel
}
},
afterAttach() {
if (self.layers.length === 1 && !self.layers[0].config.dataset && !self.layers[0].config.isEmpty) {
// Non-empty DataConfiguration lacking a dataset reference = legacy data needing a one-time fix.
// We can't do that fix until the SharedModelManager is ready, though.
addDisposer(self, reaction(
() => {
return self.tileEnv?.sharedModelManager?.isReady;
},
(ready) => {
if (!ready) return;
this.setDataConfigurationReferences();
}
));
}
// Some shared model references may need to be updated. We can't update them until the SharedModelManager
// is ready, though.
addDisposer(self, reaction(
() => {
return self.tileEnv?.sharedModelManager?.isReady;
},
(ready) => {
if (!ready) return;
this.initializeSharedModelReferences();

}, { fireImmediately: true }
));

// Automatically asign colors to anything that might need them.
addDisposer(self, reaction(
Expand All @@ -765,21 +764,48 @@ export const GraphModel = TileContentModel
}
));
},
setDataConfigurationReferences() {
// Updates pre-existing DataConfiguration objects that don't have the now-required references
// for dataset and metadata. We can determine these from the unique shared models these
// legacy tile models should have.
initializeSharedModelReferences() {
const smm = getSharedModelManager(self);
if (smm && smm.isReady) {
const sharedDataSets = smm.getTileSharedModelsByType(self, SharedDataSet);
let sharedMetadata = smm.getTileSharedModelsByType(self, SharedCaseMetadata);

// If there's a shared dataset without corresponding shared case metadata, create a new shared case
// metadata instance, link it to the dataset, and add it to the tile. This is needed when graph tiles are
// copied since the original graph tile's case metadata is not copied along with the shared dataset.
sharedDataSets.forEach((sds) => {
if (!isSharedDataSet(sds)) return;
const hasLinkedCaseMetadata = sharedMetadata.some((smd) => {
if (isSharedCaseMetadata(smd)) {
return smd.data === sds.dataSet;
}
});
if (!hasLinkedCaseMetadata) {
const smd = SharedCaseMetadata.create();
smd.setData(sds.dataSet);
smm.addTileSharedModel(self, smd);
const datasetLayer = self.layers.find((layer) => layer.config.dataset === sds.dataSet);
if (datasetLayer) {
datasetLayer.config.metadata = smd;
}
}
});

// Update pre-existing, legacy DataConfiguration objects that don't have the now-required references
// for dataset and metadata. We can determine these from the unique shared models these
// legacy tile models should have.
const legacyGraph = self.layers.length === 1 && !self.layers[0].config.dataset &&
!self.layers[0].config.isEmpty;
if (!legacyGraph) return;

if (sharedDataSets.length === 1) {
const sds = sharedDataSets[0];
if (isSharedDataSet(sds)) {
self.layers[0].config.dataset = sds.dataSet;
console.log('Updated legacy document - set dataset reference');
}
}
const sharedMetadata = smm.getTileSharedModelsByType(self, SharedCaseMetadata);
sharedMetadata = smm.getTileSharedModelsByType(self, SharedCaseMetadata);
if (sharedMetadata.length === 1) {
const smd = sharedMetadata[0];
if (isSharedCaseMetadata(smd)) {
Expand Down

0 comments on commit 5135999

Please sign in to comment.