Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## Unreleased

* [Zoom shortcuts in context menu only on gantt area, not on item context menu](https://github.com/flower-platform/react-timeline-10000/pull/115)
* [ContextMenu: scrollable and always visible](https://github.com/flower-platform/react-timeline-10000/pull/114/changes)

## v2.15.0
Expand Down
85 changes: 85 additions & 0 deletions demo-app/featurebook/testsAreDemo/ZoomTestsAreDemo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Featurebook > ZoomTestsAreDemo.md
Go to [Featurebook > Index](../FEATUREBOOK.md)

## TOC

* [`@Scenario` `whenRightClickOnGanttArea()`](#whenRightClickOnGanttArea)
* [`@Scenario` `whenRightClickOnAnItem()`](#whenRightClickOnAnItem)
* [`@Scenario` `whenMaxZoomOutClickZoomOut()`](#whenMaxZoomOutClickZoomOut)
* [`@Scenario` `whenClickZoomIn()`](#whenClickZoomIn)
* [`@Scenario` `whenClickZoomOut()`](#whenClickZoomOut)
* [`@Scenario` `whenClickZoomReset()`](#whenClickZoomReset)
* [`@Scenario` `whenClickZoomEnabled()`](#whenClickZoomEnabled)

## Scenarios

<a id="whenRightClickOnGanttArea"></a>
<table>
<tr><td>

`@Scenario` `whenRightClickOnGanttArea()`<br />
</td></tr>
<tr><td>

* WHEN right click on gantt area
* THEN the zoom actions are available on the CM
</td></tr>
</table>

<a id="whenRightClickOnAnItem"></a>
<table>
<tr><td>

`@Scenario` `whenRightClickOnAnItem()`<br />
</td></tr>
<tr><td>

* WHEN right click on an item
* THEN the zoom actions are not available on the CM
</td></tr>
</table>

<a id="whenMaxZoomOutClickZoomOut"></a>
<table>
<tr><td>

`@Scenario` `whenMaxZoomOutClickZoomOut()`<br />**WHEN the gantt was maxim zoom out AND click on zoom out, THEN the startDate and endDate not changed**
</td></tr>

</table>

<a id="whenClickZoomIn"></a>
<table>
<tr><td>

`@Scenario` `whenClickZoomIn()`<br />**When click zoomIn from context menu, THEN zoomed in AND show the message `Zoomed in` with fade effect.**
</td></tr>

</table>

<a id="whenClickZoomOut"></a>
<table>
<tr><td>

`@Scenario` `whenClickZoomOut()`<br />**When click zoomOut from context menu, THEN zoomed out AND show the message `Zoomed out` with fade effect.**
</td></tr>

</table>

<a id="whenClickZoomReset"></a>
<table>
<tr><td>

`@Scenario` `whenClickZoomReset()`<br />**When click zoomReset from context menu, THEN zoomed reset AND show the message `Zoom reset` with fade effect.**
</td></tr>

</table>

<a id="whenClickZoomEnabled"></a>
<table>
<tr><td>

`@Scenario` `whenClickZoomEnabled()`<br />**When `Zoom enabled` is checked/unchecked AND we click zoomIn/zoomOut from context menu, THEN the gantt zooms/ doesn't zoom in accordingly**
</td></tr>

</table>
41 changes: 40 additions & 1 deletion demo-app/src/testsAreDemo/ZoomTestsAreDemo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import moment from "moment";
import { rightClick } from "./testUtils";
import { contextMenuTestIds } from "../../../src/components/ContextMenu/ContextMenu";
import { zoomStoriesTestIds } from "../stories/zoom/Zoom.stories";
import Timeline, { ZOOM_PERCENT, timelineTestids as testids } from "../../../src/timeline";
import Timeline, { ZOOM_IN_ACTION_LABEL, ZOOM_OUT_ACTION_LABEL, ZOOM_PERCENT, ZOOM_RESET_ACTION_LABEL, timelineTestids as testids } from "../../../src/timeline";
import { Main } from "../stories/zoom/Zoom.stories";

export class ZoomTestsAreDemo {
Expand Down Expand Up @@ -42,6 +42,45 @@ export class ZoomTestsAreDemo {
return { expetedStartDate: startDate, expetedEndDate: endDate };
}

/**
* * WHEN right click on gantt area
* * THEN the zoom actions are available on the CM
*/
@Scenario()
async whenRightClickOnGanttArea() {
tad.ref("WHEN");
const firstRow = tad.screenCapturing.getByTestId('2_' + testids.row + "_0");
rightClick(firstRow, {
clientX: Math.round(firstRow.getBoundingClientRect().x) + 40,
clientY: Math.round(firstRow.getBoundingClientRect().y) + 40
});

tad.ref("THEN");
const popup = tad.screenCapturing.getByTestId(contextMenuTestIds.popup);
await tad.assertWaitable.exists(popup);
await tad.assertWaitable.equal(tad.withinCapturing(popup).getByTestId(contextMenuTestIds.menuItem + "_0").textContent, ZOOM_IN_ACTION_LABEL);
await tad.assertWaitable.equal(tad.withinCapturing(popup).getByTestId(contextMenuTestIds.menuItem + "_1").textContent, ZOOM_OUT_ACTION_LABEL);
await tad.assertWaitable.equal(tad.withinCapturing(popup).getByTestId(contextMenuTestIds.menuItem + "_2").textContent, ZOOM_RESET_ACTION_LABEL);
}

/**
* * WHEN right click on an item
* * THEN the zoom actions are not available on the CM
*/
@Scenario()
async whenRightClickOnAnItem() {
tad.ref("WHEN");
const segment = tad.screenCapturing.getByTestId('2_' + testids.item + "_0");
const rect = segment.getBoundingClientRect();
rightClick(segment, {
clientX: Math.round(rect.x + rect.width / 2),
clientY: Math.round(rect.y + rect.height / 2)
});
tad.ref("THEN");
await tad.assertWaitable.notExists(tad.screenCapturing.queryByTestId(contextMenuTestIds.popup));
}


@Scenario("WHEN the gantt was maxim zoom out AND click on zoom out, THEN the startDate and endDate not changed")
async whenMaxZoomOutClickZoomOut() {
const initialStartDate = this.timeline.state.startDate;
Expand Down
17 changes: 13 additions & 4 deletions src/timeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,11 @@ export default class Timeline extends React.Component {
param.closeContextMenu();
}
};
const ZOOM_BASE_ACTION = {
isVisible(param) {
return !param || !param.selection || param.selection.length === 0;
}
};
Comment on lines +751 to +755

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To prevent potential runtime errors (e.g., TypeError: Cannot read properties of undefined) if param or param.selection is not provided, it is safer to use defensive checks. Since zoom is a global action, it should default to being visible if no selection context is present.

Suggested change
const ZOOM_BASE_ACTION = {
isVisible(param) {
return param.selection.length === 0;
}
};
const ZOOM_BASE_ACTION = {
isVisible(param) {
return !param || !param.selection || param.selection.length === 0;
}
};

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

this.ZOOM_IN_ACTION = {
label: ZOOM_IN_ACTION_LABEL,
icon: 'zoom-in',
Expand All @@ -762,7 +767,8 @@ export default class Timeline extends React.Component {
that._gridDomNode.dispatchEvent(event);
params.dontCloseContextMenuAfterRunAutomatically = true;
that.startFadeOutEffect('Zoomed in');
}
},
...ZOOM_BASE_ACTION
};
this.ZOOM_OUT_ACTION = {
label: ZOOM_OUT_ACTION_LABEL,
Expand All @@ -778,7 +784,8 @@ export default class Timeline extends React.Component {
that._gridDomNode.dispatchEvent(event);
params.dontCloseContextMenuAfterRunAutomatically = true;
that.startFadeOutEffect('Zoomed out');
}
},
...ZOOM_BASE_ACTION
};
this.ZOOM_RESET_ACTION = {
label: ZOOM_RESET_ACTION_LABEL,
Expand All @@ -789,7 +796,8 @@ export default class Timeline extends React.Component {
endDate: this.props.useMoment ? moment(this.props.endDate) : this.props.endDate
});
that.startFadeOutEffect('Zoom reset');
}
},
...ZOOM_BASE_ACTION
};
}

Expand Down Expand Up @@ -2033,7 +2041,8 @@ export default class Timeline extends React.Component {
this.props.verticalGapBetweenOverlappingItems,
this.props.rowTopBottomPadding,
this.props.zIndexFunction,
rowIndex
rowIndex,
this.props.componentId
)}
{rowLayerRenderer(
layersInRow,
Expand Down
5 changes: 3 additions & 2 deletions src/utils/itemUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ export function rowItemsRenderer(
verticalGapBetweenOverlappingItems,
rowTopBottomPadding,
zIndexFunction,
rowIndex
rowIndex,
timelineComponentId = 'r9k1'
) {
const start_end_ms = vis_end.diff(vis_start, 'milliseconds');
const pixels_per_ms = total_width / start_end_ms;
Expand Down Expand Up @@ -79,7 +80,7 @@ export function rowItemsRenderer(

return (
<span
data-testid={'r9k1_' + timelineTestids.item + '_' + i.key}
data-testid={timelineComponentId + '_' + timelineTestids.item + '_' + i.key}
key={i.key}
data-item-index={i.key}
className={outerClassnames}
Expand Down
Loading