Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Graph manual points editing #2220

Merged
merged 48 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
602da84
Basically working version
bgoldowsky Feb 28, 2024
04541d6
Merge branch '186549943-dataset-naming' into 186610168-manual-points
bgoldowsky Feb 29, 2024
33435be
Only one editable layer. Update tests
bgoldowsky Feb 29, 2024
669be01
Update test
bgoldowsky Feb 29, 2024
2d47972
Editable dataset name
bgoldowsky Mar 1, 2024
ca7efca
Merge branch '186549943-dataset-naming' into 186610168-manual-points
bgoldowsky Mar 1, 2024
67414be
Generalize editor component
bgoldowsky Mar 1, 2024
19571e7
Cypress test
bgoldowsky Mar 1, 2024
eb62ed5
Generalize editor component; cleanups
bgoldowsky Mar 1, 2024
31f2232
Fix CSS
bgoldowsky Mar 1, 2024
40f2b37
Add toolbar buttons
bgoldowsky Mar 1, 2024
f65b48b
Name of data card changed
bgoldowsky Mar 4, 2024
5244f9d
Add point on click
bgoldowsky Mar 4, 2024
ffac53e
useEffect was missing some case additions
bgoldowsky Mar 4, 2024
e5c9672
Define add and edit modes
bgoldowsky Mar 4, 2024
0391aa7
Drag on background
bgoldowsky Mar 4, 2024
b6af59c
Update existing drag code to work again & not reset values.
bgoldowsky Mar 5, 2024
06cab9f
Fix rectangle selection
bgoldowsky Mar 5, 2024
4fb7ef7
Improve rescaling
bgoldowsky Mar 5, 2024
31af0a9
withoutUndo tweak
bgoldowsky Mar 5, 2024
3b18d54
Merge branch '186610168-manual-points' into 185581730-add-points
bgoldowsky Mar 5, 2024
c5c3137
Merge remote-tracking branch 'origin/master' into 185581730-add-points
bgoldowsky Mar 5, 2024
59389c9
Fix ability to undo/redo adding editable layer
bgoldowsky Mar 5, 2024
5d411e6
Toolbar naming & doc
bgoldowsky Mar 6, 2024
060df0e
Don't animate when dots are added.
bgoldowsky Mar 6, 2024
877de6c
Better fix for animation issue
bgoldowsky Mar 6, 2024
dd0b41d
Better add-points handling
bgoldowsky Mar 7, 2024
5481fc2
Can add a graph dot on top of another dot.
bgoldowsky Mar 7, 2024
5b0b81c
Merge remote-tracking branch 'origin/master' into 186610168-manual-po…
bgoldowsky Mar 7, 2024
4bd3e59
Fix some remaining bugs & add test.
bgoldowsky Mar 8, 2024
853bb26
Update testing unit
bgoldowsky Mar 8, 2024
c73b7b2
Merge branch '186610168-manual-points' into 185581730-add-points
bgoldowsky Mar 8, 2024
004205f
Merge remote-tracking branch 'origin/master' into 185581730-add-points
bgoldowsky Mar 8, 2024
36cd675
Merge branch 'master' of https://github.com/concord-consortium/collab…
bgoldowsky Mar 8, 2024
858d9d0
Fit graph copying bug.
bgoldowsky Mar 8, 2024
8ac1414
Remove verbose logging
bgoldowsky Mar 8, 2024
b2d2362
Merge branch '187179213-fix-copy-graph' into 185581730-add-points
bgoldowsky Mar 8, 2024
7d24249
Fix issue that broke dragging of tiles
bgoldowsky Mar 11, 2024
f895f0a
Try to fix mysterious cypress failure.
bgoldowsky Mar 11, 2024
67d2e57
Cleanups and comments.
bgoldowsky Mar 11, 2024
9566175
Try delay and scroll to fix mysterious cypress failure.
bgoldowsky Mar 11, 2024
e1539a6
GraphEditingContext no longer needed.
bgoldowsky Mar 11, 2024
b065a38
Refactor how drags are organized.
bgoldowsky Mar 11, 2024
28f86aa
De-nest component definitions
bgoldowsky Mar 12, 2024
3b317e0
Don't select attribute when adding manual dataset
bgoldowsky Mar 12, 2024
bd785ee
Fix color of toolbar dot
bgoldowsky Mar 12, 2024
fd793f4
Merge remote-tracking branch 'origin/master' into 185581730-add-points
bgoldowsky Mar 12, 2024
9828047
Make edit button active whenever there's a dataset
bgoldowsky Mar 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions cypress/e2e/functional/tile_tests/xy_plot_tool_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,23 @@ function buildTable(data) {
});
}

// Parse `transform` attributes (used for point positioning)
function xAttributeOfTransform(matcher) {
return attributeOfTransform(matcher, 1);
}
function yAttributeOfTransform(matcher) {
return attributeOfTransform(matcher, 2);
}
function attributeOfTransform(matcher, n) {
return matcher
.invoke('attr', 'transform')
.then(transform => {
return transform.match(/translate\((-?[0-9.]+), *(-?[0-9.]+)\)/)[n];
})
.then(parseFloat);
}


function beforeTest(params) {
cy.clearQAData('all');
cy.visit(params);
Expand Down Expand Up @@ -80,6 +97,8 @@ context('XYPlot Tool Tile', function () {
cy.log("Link Table");
clueCanvas.clickToolbarButton('graph', 'link-tile-multiple');
xyTile.linkTable("Table Data 1");
cy.wait(1000); // Needs a little extra time, probably due to legend resizing.
// Otherwise the upcoming typeInTableCell fails.

cy.log("shows edit boxes on axes");
xyTile.getEditableAxisBox("bottom", "min").should("exist");
Expand Down Expand Up @@ -468,5 +487,66 @@ context('XYPlot Tool Tile', function () {
// Only the unlink remove button should remain
xyTile.getRemoveVariablesButtons().should("have.length", 1);
});

it('Test points by hand', () => {
beforeTest(queryParamsMultiDataset);
cy.log('Add XY Plot Tile');
cy.collapseResourceTabs();
clueCanvas.addTile('graph');
xyTile.getTile('.primary-workspace').should('be.visible');
clueCanvas.toolbarButtonIsDisabled('graph', 'move-points');
clueCanvas.toolbarButtonIsNotSelected('graph', 'move-points');
clueCanvas.toolbarButtonIsDisabled('graph', 'add-points');
clueCanvas.toolbarButtonIsNotSelected('graph', 'add-points');

// Create manual layer
clueCanvas.clickToolbarButton('graph', 'add-points-by-hand');
clueCanvas.toolbarButtonIsDisabled('graph', 'add-points-by-hand'); // only one manual set allowed
clueCanvas.toolbarButtonIsEnabled('graph', 'move-points');
clueCanvas.toolbarButtonIsEnabled('graph', 'add-points');
clueCanvas.toolbarButtonIsSelected('graph', 'add-points'); // automatically turns on "add" mode
xyTile.getXAttributesLabel().should('have.length', 1).should('contain.text', 'X Variable');
xyTile.getYAttributesLabel().should('have.length', 1).should('contain.text', 'Y Variable 1');
xyTile.getLayerName().should('have.length', 1).should('contain.text', 'Added by hand');
xyTile.getLayerNameInput().should('not.be.visible');

// Rename manual layer
xyTile.getLayerNameEditButton().click();
xyTile.getLayerNameEditButton().should('have.length', 0);
xyTile.getLayerNameInput().should('be.visible').type('Renamed{enter}');
xyTile.getLayerNameInput().should('not.be.visible');
xyTile.getLayerName().should('have.length', 1).should('contain.text', 'Renamed');

// Add points
xyTile.getGraphDot().should('have.length', 0);
xyTile.getTile('.primary-workspace').should('have.length', 1);
xyTile.getGraphBackground().should('have.length', 1).click(150, 50);
xyTile.getGraphBackground().click(200, 100);
xyTile.getGraphDot().should('have.length', 2);

// Switch to 'select/move' mode
clueCanvas.clickToolbarButton('graph', 'move-points');
clueCanvas.toolbarButtonIsSelected('graph', 'move-points');
clueCanvas.toolbarButtonIsNotSelected('graph', 'add-points');
xyTile.getGraphBackground().click(250, 100); // should not add a point
xyTile.getGraphDot().should('have.length', 2);

// Drag a point to reposition. Should start out where we initially clicked
xAttributeOfTransform(xyTile.getGraphDot().eq(0)).should("be.closeTo", 150, 10);
yAttributeOfTransform(xyTile.getGraphDot().eq(0)).should("be.closeTo", 50, 10);
// {force: true} seems to be necessary, not sure why
xyTile.getGraphDot().eq(0).children('circle').eq(1)
.trigger("mousedown", 150, 50, { force: true })
.trigger("drag", 175, 75, { force: true })
.trigger("mouseup", 175, 75, { force: true });
cy.wait(1000);
xAttributeOfTransform(xyTile.getGraphDot().eq(0)).should("be.closeTo", 175, 10);
yAttributeOfTransform(xyTile.getGraphDot().eq(0)).should("be.closeTo", 75, 10);

// Click toolbar button again to leave edit mode
clueCanvas.clickToolbarButton('graph', 'move-points');
clueCanvas.toolbarButtonIsNotSelected('graph', 'move-points');
clueCanvas.toolbarButtonIsNotSelected('graph', 'add-points');
});
});
});
10 changes: 4 additions & 6 deletions cypress/support/elements/tile/TableToolTile.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,12 @@ class TableToolTile{
return cy.get('.rdg-row .rdg-cell .rdg-text-editor');
}
typeInTableCellXY(row, col, text) {
this.getTableCellXY(row, col).dblclick().then(() => {
this.getTableCellEdit().type(`${text}{enter}`);
});
this.getTableCellXY(row, col).dblclick();
this.getTableCellEdit().type(`${text}{enter}`);
}
typeInTableCell(i, text) {
this.getTableCell().eq(i).dblclick().then(() => {
this.getTableCellEdit().type(`${text}{enter}`);
});
this.getTableCell().eq(i).dblclick();
this.getTableCellEdit().type(`${text}{enter}`);
}
getTableCellWithColIndex(colIndex, colValue){
return cy.get('.rdg-row').contains('.rdg-cell[aria-colindex="' + colIndex + '"]', colValue);
Expand Down
12 changes: 12 additions & 0 deletions cypress/support/elements/tile/XYPlotToolTile.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ class XYPlotToolTile {
getTile(workspaceClass) {
return cy.get(`${wsClass(workspaceClass)} .canvas-area .graph-tool-tile`);
}
getGraphBackground(workspaceClass) {
return cy.get(`${wsClass(workspaceClass)} svg [data-testid=graph-background]`);
}
getXYPlotTitle(workspaceClass) {
return cy.get(`${wsClass(workspaceClass)} .canvas-area .editable-tile-title`);
}
Expand Down Expand Up @@ -51,6 +54,15 @@ class XYPlotToolTile {
getYAxisInput(workspaceClass) {
return this.getAxisInput("left", workspaceClass);
}
getLayerName(workspaceClass) {
return cy.get(`${wsClass(workspaceClass)} .canvas-area .multi-legend .legend-row .layer-name`);
}
getLayerNameEditButton(workspaceClass) {
return cy.get(`${wsClass(workspaceClass)} .canvas-area .multi-legend .legend-row .layer-name button`);
}
getLayerNameInput(workspaceClass) {
return cy.get(`${wsClass(workspaceClass)} .canvas-area .multi-legend .legend-row .layer-name input`);
}
getXAttributesLabel(workspaceClass) {
return cy.get(`${wsClass(workspaceClass)} .canvas-area .multi-legend .legend-row .bottom .simple-attribute-label`);
}
Expand Down
2 changes: 1 addition & 1 deletion docs/mst-detached-error.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Below is a strategy for tracking down the cause and a solution for one particula

Hopefully from the message you can figure out the rough area of the code where the problem is happening. If you can pin point the UI action that causes the warning to be printed then you can use the following approach.

In your local code find `kEnableLivelinessChecking` located in `index.tsx` and set to be `true`. This will cause these console warnings to actually be thrown errors instead. In many cases these thrown errors will be caught and ignored so after you set this to true you probably won't see any messages in the console if you try to duplicate the problem again.
In your local code find `kEnableLivelinessChecking` located in `initialize-app.tsx` and set to be `true`. This will cause these console warnings to actually be thrown errors instead. In many cases these thrown errors will be caught and ignored so after you set this to true you probably won't see any messages in the console if you try to duplicate the problem again.

Instead of looking in the console, what you should do is use the dev tools debugger to track it down. Setup the app to just before the error would normally be printed to the console. Then in the debug panel turn on "pause on exceptions" and check the box "pause on caught exceptions". Now trigger the error. The app should pause and you should be in the debugger.

Expand Down
7 changes: 5 additions & 2 deletions docs/unit-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,13 +165,16 @@ Not updated to common toolbar framework and does not support toolbar configurati
- `emptyPlotIsNumeric`: boolean, default true
- `scalePlotOnValueChange`: boolean, default true

Common toolbar framework; default toolbar buttons:
Uses the common toolbar framework. Default toolbar buttons:

- `link-tile` (opens dialog to replace dataset with a new one)
- `add-points-by-hand` (creates a dataset owned by the graph)
- `fit-all` (rescale axes to fit all points in view)
- `toggle-lock` (lock axes so they won't automatically rescale)
- `move-points` (mode where points can be moved)
- `add-points` (mode where points can be added)

Also available:
Additional buttons available not in default set:

- `link-tile-multiple` (opens dialog to add an additional dataset or link variables)

Expand Down
3 changes: 3 additions & 0 deletions src/assets/edit.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion src/clue/app-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -269,9 +269,13 @@
"disableAttributeDnD": true,
"tools": [
"link-tile",
"add-points-by-hand",
"|",
"fit-all",
"toggle-lock"
"toggle-lock",
"|",
"move-points",
"add-points"
]
},
"simulator": {
Expand Down
23 changes: 23 additions & 0 deletions src/components/utilities/editable-label-with-button.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
@import "../vars.sass";

.chakra-editable {
.chakra-editable__preview[hidden] {
display: none;
}

button {
background: inherit;
border: none;
cursor: pointer;

&:hover {
background-color: $workspace-teal-light-6;
}

svg {
height: 1em;
width: 1em;
vertical-align: baseline;
}
}
}
46 changes: 46 additions & 0 deletions src/components/utilities/editable-label-with-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from "react";
import { observer } from "mobx-react";
import { Editable, EditableInput, EditablePreview, useEditableControls } from "@chakra-ui/react";

import EditIcon from "../../assets/edit.svg";

import "./editable-label-with-button.scss";

interface IProps {
defaultValue: string|undefined;
onSubmit: (value:string) => void;
}

/**
* Generic component for an in-place editable label.
*
* Differs from stock <Editable> in that there's an explicit edit button rather
* than invoking edit mode by clicking on the label text itself.
*/
export const EditableLabelWithButton = observer(function EditableDataSetName({defaultValue, onSubmit}: IProps) {

return (
<Editable
defaultValue={defaultValue}
isPreviewFocusable={false}
onSubmit={onSubmit}
>
<EditablePreview />
<EditableInput />
<EditButton />
</Editable>
);
});

function EditButton() {
const { isEditing, getEditButtonProps } = useEditableControls();
if (!isEditing) {
return (
<button aria-label="Edit name" {...getEditButtonProps()}>
<EditIcon/>
</button>
);
} else {

Check warning on line 43 in src/components/utilities/editable-label-with-button.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/utilities/editable-label-with-button.tsx#L43

Added line #L43 was not covered by tests
return null;
}
}
10 changes: 7 additions & 3 deletions src/models/data/data-set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ export const DataSet = types.model("DataSet", {
self.cases.push(newCase);
beforeIndex = self.cases.length - 1;
}
return newCase;
}

// `affectedAttributes` are not used in the function, but are present as a potential
Expand Down Expand Up @@ -639,6 +640,7 @@ export const DataSet = types.model("DataSet", {
for (let i = attribute.values.length; i < self.cases.length; ++i) {
attribute.values.push("");
}
return attribute;
},

setAttributeName(attributeID: string, name: string) {
Expand Down Expand Up @@ -688,14 +690,16 @@ export const DataSet = types.model("DataSet", {
},

addCanonicalCasesWithIDs(cases: ICase[], beforeID?: string | string[]) {
const newCases: ICase[] = [];
cases.forEach((aCase, index) => {
const beforeIndex = beforeIndexForInsert(index, beforeID);
self.attributes.forEach((attr: IAttribute) => {
const value = aCase[attr.id];
attr.addValue(value != null ? value : undefined, beforeIndex);
});
insertCaseIDAtIndex(aCase.__id__, beforeIndex);
newCases.push(insertCaseIDAtIndex(aCase.__id__, beforeIndex));
});
return newCases;
},

setCaseValues(cases: ICase[], affectedAttributes?: string[]) {
Expand Down Expand Up @@ -882,7 +886,7 @@ export function addAttributeToDataSet(dataset: IDataSet, snapshot: IAttributeSna
if (!snapshot.id) {
snapshot.id = uniqueId();
}
dataset.addAttributeWithID(snapshot, beforeID);
return dataset.addAttributeWithID(snapshot, beforeID);
}

export function addCasesToDataSet(dataset: IDataSet, cases: ICaseCreation[], beforeID?: string | string[]) {
Expand All @@ -903,7 +907,7 @@ export function addCanonicalCasesToDataSet(dataset: IDataSet, cases: ICaseCreati
aCase.__id__ = newCaseId();
}
});
dataset.addCanonicalCasesWithIDs(newCases, beforeID);
return dataset.addCanonicalCasesWithIDs(newCases, beforeID);
}

export function getDataSetBounds(dataSet: IDataSet) {
Expand Down
8 changes: 0 additions & 8 deletions src/models/document/document-content-types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { IArrowAnnotation } from "../annotations/arrow-annotation";
import { SharedModelSnapshotType } from "../shared/shared-model";
import { IDragSharedModelItem } from "../shared/shared-model-manager";
import { IDragTileItem } from "../tiles/tile-model";
import { IDropRowInfo } from "./tile-row";
Expand Down Expand Up @@ -46,10 +45,3 @@ export interface IDragTilesData {
annotations: IArrowAnnotation[];
}

export interface PartialTile {
id: string;
}
export interface PartialSharedModelEntry {
sharedModel: SharedModelSnapshotType;
tiles: PartialTile[];
}
Loading
Loading