Skip to content

Commit

Permalink
fix: insert cases in hierarchical collection; insert cases undo/redo (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
kswenson authored Aug 22, 2024
1 parent 7a85b74 commit 72f6d49
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 104 deletions.
42 changes: 41 additions & 1 deletion v3/cypress/e2e/hierarchical-table.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { TableTileElements as table } from "../support/elements/table-tile"
import { ToolbarElements as toolbar } from "../support/elements/toolbar-elements"
import hierarchical from '../fixtures/hierarchical.json'
type HierarchicalTest = typeof hierarchical.tests[number] & { only?: boolean }

const values = hierarchical.attributes

context("hierarchical collections", () => {
beforeEach(function () {
const queryParams = "?sample=mammals&dashboard&mouseSensor"
const queryParams = "?sample=mammals&mouseSensor"
const url = `${Cypress.config("index")}${queryParams}`
cy.visit(url)
cy.wait(1000)
Expand Down Expand Up @@ -61,4 +62,43 @@ context("hierarchical collections", () => {
// table.getNumOfRows(1).should("contain", 15)
// table.getNumOfRows(2).should("contain", 31)
})

it("verify insert case in hierarchical table", () => {
table.moveAttributeToParent("Order", "newCollection")
table.getNumOfRows(1).should("contain", 14)
table.getNumOfRows(2).should("contain", 29)

// Insert a new case
table.openIndexMenuForRow(3, 2)
table.insertCase()
table.getNumOfRows(1).should("contain", 14)
table.getNumOfRows(2).should("contain", 30)

// delete the new case
table.openIndexMenuForRow(3, 2)
table.deleteCase()
table.getNumOfRows(1).should("contain", 14)
table.getNumOfRows(2).should("contain", 29)

// Undo delete
toolbar.getUndoTool().click()
table.getNumOfRows(1).should("contain", 14)
table.getNumOfRows(2).should("contain", 30)

// Undo insert
toolbar.getUndoTool().click()
table.getNumOfRows(1).should("contain", 14)
table.getNumOfRows(2).should("contain", 29)

// Redo insert
toolbar.getRedoTool().click()
table.getNumOfRows(1).should("contain", 14)
table.getNumOfRows(2).should("contain", 30)

// Redo delete
toolbar.getRedoTool().click()
table.getNumOfRows(1).should("contain", 14)
table.getNumOfRows(2).should("contain", 29)
})

})
43 changes: 16 additions & 27 deletions v3/cypress/e2e/table.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ context("case table ui", () => {
describe("index menu", () => {
it("verify index menu insert case and delete case work", () => {

let initialRowCount = 0, postInsertRowCount, postDeleteRowCount
let initialRowCount = 0, postInsertRowCount = -1, postDeleteRowCount = -1

// Get initial row count
table.getNumOfRows().then(rowCount => {
Expand Down Expand Up @@ -525,21 +525,19 @@ context("case table ui", () => {
toolbar.getUndoTool().click()

// Verify undo (check if row count is back to post-insert count)
// TODO: add the check once bug is fixed (PT #187083170)
// table.getNumOfRows().then(rowCount => {
// const rowCountAfterUndo = Number(rowCount)
// expect(rowCountAfterUndo).to.eq(postInsertRowCount)
//})
table.getNumOfRows().then(rowCount => {
const rowCountAfterUndo = Number(rowCount)
expect(rowCountAfterUndo).to.eq(postInsertRowCount)
})

// Redo delete
toolbar.getRedoTool().click()

// Verify redo (check if row count is back to initial count)
// TODO: add the check once bug is fixed (PT #187083170)
// table.getNumOfRows().then(rowCount => {
// const rowCountAfterRedo = Number(rowCount)
// expect(rowCountAfterRedo).to.eq(initialRowCount)
// })
table.getNumOfRows().then(rowCount => {
const rowCountAfterRedo = Number(rowCount)
expect(rowCountAfterRedo).to.eq(initialRowCount)
})
})
it("verify insert cases before a row by typing num of cases", () => {

Expand Down Expand Up @@ -604,7 +602,6 @@ context("case table ui", () => {
table.openIndexMenuForRow(lastRowIndex)
table.insertCase()
table.getCaseTableGrid().scrollTo("bottom")
cy.wait(500)
table.openIndexMenuForRow(lastRowIndex)
table.deleteCase()
table.getNumOfRows().should("equal", numOfCases)
Expand All @@ -631,7 +628,6 @@ context("case table ui", () => {
table.openIndexMenuForRow(lastRowIndex)
table.insertCases(2, "after")
table.getCaseTableGrid().scrollTo("bottom")
cy.wait(500)
table.openIndexMenuForRow(lastRowIndex + 1)
table.deleteCase()
table.openIndexMenuForRow(lastRowIndex + 1)
Expand All @@ -655,7 +651,6 @@ context("case table ui", () => {
table.openIndexMenuForRow(lastRowIndex)
table.insertCases(2, "before")
table.getCaseTableGrid().scrollTo("bottom")
cy.wait(500)
table.openIndexMenuForRow(lastRowIndex + 1)
table.deleteCase()
table.openIndexMenuForRow(lastRowIndex)
Expand Down Expand Up @@ -693,7 +688,6 @@ context("case table ui", () => {
table.openIndexMenuForRow(firstRowIndex)
table.insertCase()
table.getCaseTableGrid().scrollTo("top")
cy.wait(500)
table.openIndexMenuForRow(firstRowIndex)
table.deleteCase()
table.getNumOfRows().should("equal", numOfCases)
Expand All @@ -715,7 +709,6 @@ context("case table ui", () => {
table.openIndexMenuForRow(firstRowIndex)
table.insertCases(3, "after")
table.getCaseTableGrid().scrollTo("top")
cy.wait(500)
table.openIndexMenuForRow(firstRowIndex + 1)
table.deleteCase()
table.openIndexMenuForRow(firstRowIndex + 1)
Expand All @@ -741,7 +734,6 @@ context("case table ui", () => {
table.openIndexMenuForRow(firstRowIndex)
table.insertCases(3, "before")
table.getCaseTableGrid().scrollTo("top")
cy.wait(500)
table.openIndexMenuForRow(firstRowIndex)
table.deleteCase()
table.openIndexMenuForRow(firstRowIndex)
Expand Down Expand Up @@ -785,7 +777,6 @@ context("case table ui", () => {
table.openIndexMenuForRow(middleRowIndex)
table.insertCase()
table.getCaseTableGrid().scrollTo("top")
cy.wait(500)
table.openIndexMenuForRow(middleRowIndex)
table.deleteCase()
table.getNumOfRows().should("equal", numOfCases)
Expand All @@ -807,7 +798,6 @@ context("case table ui", () => {
table.openIndexMenuForRow(middleRowIndex)
table.insertCases(3, "after")
table.getCaseTableGrid().scrollTo("top")
cy.wait(500)
table.openIndexMenuForRow(middleRowIndex + 1)
table.deleteCase()
table.openIndexMenuForRow(middleRowIndex + 1)
Expand All @@ -833,7 +823,6 @@ context("case table ui", () => {
table.openIndexMenuForRow(middleRowIndex)
table.insertCases(3, "before")
table.getCaseTableGrid().scrollTo("top")
cy.wait(500)
table.openIndexMenuForRow(middleRowIndex)
table.deleteCase()
table.openIndexMenuForRow(middleRowIndex)
Expand Down Expand Up @@ -964,7 +953,7 @@ context("case table ui", () => {
cy.log("double-clicking the cell")
// double-click to initiate editing cell
table.getGridCell(2, 2).dblclick()
cy.wait(1000) // Wait for the editing input to appear
cy.wait(100) // Wait for the editing input to appear

cy.log("check the editing cell contents")
table.getGridCell(2, 2).find("[data-testid='cell-text-editor']").should("have.value", "African Elephant")
Expand All @@ -976,19 +965,19 @@ context("case table ui", () => {
cy.log("double-click to begin editing cell")
table.getGridCell(2, 2).click()
table.getGridCell(2, 2).dblclick()
cy.wait(1000) // Wait for the editing input to appear
cy.wait(100) // Wait for the editing input to appear

cy.log("click color swatch to bring up color palette")
table.getGridCell(2, 2)
.find("button.cell-edit-color-swatch") // Simplified selector
.should('exist')
.should('be.visible')
.dblclick({ force: true }) // Double-click the button
cy.wait(1000) // Wait for the color palette to appear
cy.wait(100) // Wait for the color palette to appear

cy.log("click hue bar to change color")
cy.get(`.react-colorful .react-colorful__hue [aria-label="Hue"]`).should('be.visible').click()
cy.wait(1000) // Wait for the color change to be reflected
cy.wait(100) // Wait for the color change to be reflected

cy.log("verify that the color actually changed")
table.verifyEditCellSwatchColor(2, 2, "rgb(0, 255,")
Expand All @@ -1001,19 +990,19 @@ context("case table ui", () => {

cy.log("double-click to begin editing cell again")
table.getGridCell(2, 2).dblclick()
cy.wait(1000) // Wait for the editing input to appear
cy.wait(100) // Wait for the editing input to appear

cy.log("click color swatch to bring up color palette again")
table.getGridCell(2, 2)
.find("button.cell-edit-color-swatch") // Simplified selector
.should('exist')
.should('be.visible')
.dblclick({ force: true }) // Double-click the button
cy.wait(1000) // Wait for the color palette to appear
cy.wait(100) // Wait for the color palette to appear

cy.log("click hue bar to change color again")
cy.get(`.react-colorful .react-colorful__hue [aria-label="Hue"]`).should('be.visible').click()
cy.wait(1000) // Wait for the color change to be reflected
cy.wait(100) // Wait for the color change to be reflected

cy.log("verify that the color actually changed again")
table.verifyEditCellSwatchColor(2, 2, "rgb(0, 255,")
Expand Down
2 changes: 0 additions & 2 deletions v3/cypress/support/elements/table-tile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ export const TableTileElements = {
insertCase() {
this.getIndexMenu().should("be.visible")
cy.clickMenuItem("Insert Case")
cy.wait(500)
},
insertCases(num_of_cases: number, location: string) {
this.getIndexMenu().should("be.visible")
Expand All @@ -76,7 +75,6 @@ export const TableTileElements = {
deleteCase() {
this.getIndexMenu().should("be.visible")
cy.clickMenuItem("Delete Case")
cy.wait(500)
},
getInsertCasesModalHeader() {
return cy.get("[data-testid=codap-modal-header]")
Expand Down
96 changes: 56 additions & 40 deletions v3/src/components/case-table/index-menu-list.tsx
Original file line number Diff line number Diff line change
@@ -1,69 +1,85 @@
import { MenuItem, MenuList, useDisclosure, useToast } from "@chakra-ui/react"
import { MenuItem, MenuList, useDisclosure } from "@chakra-ui/react"
import React from "react"
import { useDataSetContext } from "../../hooks/use-data-set-context"
import { removeCasesWithCustomUndoRedo } from "../../models/data/data-set-undo"
import { insertCasesWithCustomUndoRedo, removeCasesWithCustomUndoRedo } from "../../models/data/data-set-undo"
import { t } from "../../utilities/translation/translate"
import { InsertCasesModal } from "./insert-cases-modal"
import { IInsertSpec, InsertCasesModal } from "./insert-cases-modal"
import { isItemEditable } from "../../utilities/plugin-utils"
import { ICaseCreation } from "../../models/data/data-set-types"

interface IProps {
caseId: string
index?: number
}

export const IndexMenuList = ({caseId, index}: IProps) => {
const toast = useToast()
const data = useDataSetContext()
const { isOpen, onOpen, onClose } = useDisclosure()
const { isOpen, onOpen: onOpenInsertCasesModal, onClose: onCloseInsertCasesModal } = useDisclosure()
const deletableSelectedItems = data?.selection
? Array.from(data.selection).filter(itemId => isItemEditable(data, itemId))
: []
const disableEdits = deletableSelectedItems.length < 1
const deleteCasesItemText = deletableSelectedItems.length === 1
? t("DG.CaseTable.indexMenu.deleteCase")
: t("DG.CaseTable.indexMenu.deleteCases")

const handleInsertCase = () => {
data?.addCases([{}], {before: caseId})
}

const handleInsertCases = () => {
onOpen()
function handleCloseInsertCasesModel(insertSpec?: IInsertSpec) {
const { count, position } = insertSpec || {}
if (data && count && position) {
const casesToInsert: ICaseCreation[] = Array<ICaseCreation>(count).fill({})
insertCasesWithCustomUndoRedo(data, casesToInsert, { [position]: caseId })
}
onCloseInsertCasesModal()
}

const handleMenuItemClick = (menuItem: string) => {
toast({
title: 'Menu item clicked',
description: `You clicked on ${menuItem} on index=${index} id=${caseId}`,
status: 'success',
duration: 9000,
isClosable: true,
})
interface IMenuItem {
itemKey: string
// defaults to true if not implemented
isEnabled?: (item: IMenuItem) => boolean
handleClick?: (item: IMenuItem) => void
}

const handleDeleteCases = () => {
if (data?.selection.size) {
removeCasesWithCustomUndoRedo(data, deletableSelectedItems)
const menuItems: IMenuItem[] = [
{
itemKey: "DG.CaseTable.indexMenu.moveEntryRow"
},
{
itemKey: "DG.CaseTable.indexMenu.insertCase",
isEnabled: () => !disableEdits,
handleClick: () => {
if (data) {
insertCasesWithCustomUndoRedo(data, [{}], { before: caseId })
}
}
},
{
itemKey: "DG.CaseTable.indexMenu.insertCases",
isEnabled: () => !disableEdits,
handleClick: () => onOpenInsertCasesModal()
},
{
itemKey: `DG.CaseTable.indexMenu.delete${deletableSelectedItems.length === 1 ? "Case" : "Cases" }`,
isEnabled: () => deletableSelectedItems.length >= 1,
handleClick: () => {
if (data?.selection.size) {
removeCasesWithCustomUndoRedo(data, deletableSelectedItems)
}
}
}
}
]

return (
<>
<MenuList data-testid="index-menu-list" >
<MenuItem onClick={()=>handleMenuItemClick("Move Data Entry Row")}>
{t("DG.CaseTable.indexMenu.moveEntryRow")}
</MenuItem>
<MenuItem isDisabled={disableEdits} onClick={handleInsertCase}>
{t("DG.CaseTable.indexMenu.insertCase")}
</MenuItem>
<MenuItem isDisabled={disableEdits} onClick={handleInsertCases}>
{t("DG.CaseTable.indexMenu.insertCases")}
</MenuItem>
<MenuItem isDisabled={disableEdits} onClick={handleDeleteCases}>
{deleteCasesItemText}
</MenuItem>
<MenuList data-testid="index-menu-list">
{
menuItems.map(item => {
const isDisabled = !item.handleClick || item.isEnabled?.(item) === false
return (
<MenuItem key={item.itemKey} isDisabled={isDisabled} onClick={() => item.handleClick?.(item)}>
{`${t(item.itemKey)}${item.handleClick ? "" : " 🚧"}`}
</MenuItem>
)
})
}
</MenuList>
<InsertCasesModal caseId={caseId} isOpen={isOpen} onClose={onClose}/>
<InsertCasesModal caseId={caseId} isOpen={isOpen} onClose={handleCloseInsertCasesModel}/>
</>
)
}
Loading

0 comments on commit 72f6d49

Please sign in to comment.