Sfoglia il codice sorgente

Merge pull request #11016 from overleaf/ii-dashboard-wrong-action-buttons

[web] Project dashboard wrong action buttons

GitOrigin-RevId: d76c64616a34c63b60bc499b96c6507c1196e666
Mathias Jakobsen 3 anni fa
parent
commit
2f5eb9c1d4

+ 2 - 2
services/web/frontend/js/features/project-list/context/project-list-context.tsx

@@ -186,7 +186,6 @@ export function ProjectListProvider({ children }: ProjectListProviderProps) {
             tag?.project_ids?.includes(project.id)
           )
         } else {
-          setFilter('all')
           setSelectedTagId(undefined)
         }
       }
@@ -290,9 +289,10 @@ export function ProjectListProvider({ children }: ProjectListProviderProps) {
 
   const selectTag = useCallback(
     (tagId: string) => {
+      setFilter('all')
       setSelectedTagId(tagId)
     },
-    [setSelectedTagId]
+    [setSelectedTagId, setFilter]
   )
 
   const addTag = useCallback((tag: Tag) => {

+ 164 - 127
services/web/test/frontend/features/project-list/components/project-list-root.test.tsx

@@ -665,159 +665,196 @@ describe('<ProjectListRoot />', function () {
         })
       })
 
-      describe('project tools "More" dropdown', function () {
-        beforeEach(async function () {
-          const filterButton = screen.getAllByText('All Projects')[0]
-          fireEvent.click(filterButton)
-          allCheckboxes = screen.getAllByRole<HTMLInputElement>('checkbox')
-          // first one is the select all checkbox
-          fireEvent.click(allCheckboxes[2])
+      describe('project tools', function () {
+        it('renders download, archive, trash buttons followed by tags and "more" dropdowns when selecting an archived or trashed filter before selecting tag filter', function () {
+          const assertToolbarButtonsExists = () => {
+            within(actionsToolbar).getByLabelText(/download/i)
+            within(actionsToolbar).getByLabelText(/archive/i)
+            within(actionsToolbar).getByLabelText(/trash/i)
+            within(actionsToolbar).getByLabelText(/tags/i)
+            within(actionsToolbar).getByText(/more/i)
+          }
+
+          // Select archived projects
+          const [archivedProjectsButton] =
+            screen.getAllByText(/archived projects/i)
+          fireEvent.click(archivedProjectsButton)
+          const [tag] = screen.getAllByText(this.tagName)
+          fireEvent.click(tag)
+
+          allCheckboxes = screen.getAllByRole('checkbox')
+          fireEvent.click(allCheckboxes[1])
+          actionsToolbar = screen.getAllByRole('toolbar')[0]
+
+          assertToolbarButtonsExists()
+
+          // select trashed projects
+          const [trashedProjectsButton] =
+            screen.getAllByText(/trashed projects/i)
+          fireEvent.click(trashedProjectsButton)
+          fireEvent.click(tag)
+
+          allCheckboxes = screen.getAllByRole('checkbox')
+          fireEvent.click(allCheckboxes[1])
           actionsToolbar = screen.getAllByRole('toolbar')[0]
+
+          assertToolbarButtonsExists()
         })
 
-        it('does not show the dropdown when more than 1 project is selected', async function () {
-          await waitFor(() => {
-            within(actionsToolbar).getByText<HTMLElement>('More')
+        describe('"More" dropdown', function () {
+          beforeEach(async function () {
+            const filterButton = screen.getAllByText('All Projects')[0]
+            fireEvent.click(filterButton)
+            allCheckboxes = screen.getAllByRole<HTMLInputElement>('checkbox')
+            // first one is the select all checkbox
+            fireEvent.click(allCheckboxes[2])
+            actionsToolbar = screen.getAllByRole('toolbar')[0]
           })
-          fireEvent.click(allCheckboxes[0])
-          expect(within(actionsToolbar).queryByText<HTMLElement>('More')).to.be
-            .null
-        })
 
-        it('validates the project name', async function () {
-          const moreDropdown = await within(
-            actionsToolbar
-          ).findByText<HTMLElement>('More')
-          fireEvent.click(moreDropdown)
+          it('does not show the dropdown when more than 1 project is selected', async function () {
+            await waitFor(() => {
+              within(actionsToolbar).getByText<HTMLElement>('More')
+            })
+            fireEvent.click(allCheckboxes[0])
+            expect(within(actionsToolbar).queryByText<HTMLElement>('More')).to
+              .be.null
+          })
 
-          const renameButton =
-            screen.getAllByText<HTMLButtonElement>('Rename')[1] // first one is for the tag in the sidebar
-          fireEvent.click(renameButton)
+          it('validates the project name', async function () {
+            const moreDropdown = await within(
+              actionsToolbar
+            ).findByText<HTMLElement>('More')
+            fireEvent.click(moreDropdown)
 
-          const modals = await screen.findAllByRole('dialog')
-          const modal = modals[0]
+            const renameButton =
+              screen.getAllByText<HTMLButtonElement>('Rename')[1] // first one is for the tag in the sidebar
+            fireEvent.click(renameButton)
 
-          expect(sendSpy).to.be.calledOnce
-          expect(sendSpy).calledWith('project-list-page-interaction')
+            const modals = await screen.findAllByRole('dialog')
+            const modal = modals[0]
 
-          // same name
-          let confirmButton =
-            within(modal).getByText<HTMLButtonElement>('Rename')
-          expect(confirmButton.disabled).to.be.true
-          let input = screen.getByLabelText('New Name') as HTMLButtonElement
+            expect(sendSpy).to.be.calledOnce
+            expect(sendSpy).calledWith('project-list-page-interaction')
 
-          // no name
-          input = screen.getByLabelText('New Name') as HTMLButtonElement
-          fireEvent.change(input, {
-            target: { value: '' },
-          })
-          confirmButton = within(modal).getByText<HTMLButtonElement>('Rename')
-          expect(confirmButton.disabled).to.be.true
-        })
+            // same name
+            let confirmButton =
+              within(modal).getByText<HTMLButtonElement>('Rename')
+            expect(confirmButton.disabled).to.be.true
+            let input = screen.getByLabelText('New Name') as HTMLButtonElement
 
-        it('opens the rename modal, and can rename the project, and view updated', async function () {
-          const renameProjectMock = fetchMock.post(
-            `express:/project/:id/rename`,
-            {
-              status: 200,
-            }
-          )
-          const moreDropdown = await within(
-            actionsToolbar
-          ).findByText<HTMLElement>('More')
-          fireEvent.click(moreDropdown)
-
-          const renameButton =
-            within(actionsToolbar).getByText<HTMLButtonElement>('Rename') // first one is for the tag in the sidebar
-          fireEvent.click(renameButton)
-
-          const modals = await screen.findAllByRole('dialog')
-          const modal = modals[0]
-
-          // a valid name
-          const newProjectName = 'A new project name'
-          const input = (await within(modal).findByLabelText(
-            'New Name'
-          )) as HTMLButtonElement
-          const oldName = input.value
-          fireEvent.change(input, {
-            target: { value: newProjectName },
+            // no name
+            input = screen.getByLabelText('New Name') as HTMLButtonElement
+            fireEvent.change(input, {
+              target: { value: '' },
+            })
+            confirmButton = within(modal).getByText<HTMLButtonElement>('Rename')
+            expect(confirmButton.disabled).to.be.true
           })
 
-          const confirmButton =
-            within(modal).getByText<HTMLButtonElement>('Rename')
-          expect(confirmButton.disabled).to.be.false
-          fireEvent.click(confirmButton)
+          it('opens the rename modal, and can rename the project, and view updated', async function () {
+            const renameProjectMock = fetchMock.post(
+              `express:/project/:id/rename`,
+              {
+                status: 200,
+              }
+            )
+            const moreDropdown = await within(
+              actionsToolbar
+            ).findByText<HTMLElement>('More')
+            fireEvent.click(moreDropdown)
 
-          await fetchMock.flush(true)
+            const renameButton =
+              within(actionsToolbar).getByText<HTMLButtonElement>('Rename') // first one is for the tag in the sidebar
+            fireEvent.click(renameButton)
+
+            const modals = await screen.findAllByRole('dialog')
+            const modal = modals[0]
+
+            // a valid name
+            const newProjectName = 'A new project name'
+            const input = (await within(modal).findByLabelText(
+              'New Name'
+            )) as HTMLButtonElement
+            const oldName = input.value
+            fireEvent.change(input, {
+              target: { value: newProjectName },
+            })
 
-          expect(
-            renameProjectMock.called(`/project/${projectsData[1].id}/rename`)
-          ).to.be.true
+            const confirmButton =
+              within(modal).getByText<HTMLButtonElement>('Rename')
+            expect(confirmButton.disabled).to.be.false
+            fireEvent.click(confirmButton)
 
-          const table = await screen.findByRole('table')
-          within(table).getByText(newProjectName)
-          expect(within(table).queryByText(oldName)).to.be.null
+            await fetchMock.flush(true)
 
-          const allCheckboxes = await within(
-            table
-          ).findAllByRole<HTMLInputElement>('checkbox')
-          const allCheckboxesChecked = allCheckboxes.filter(c => c.checked)
-          expect(allCheckboxesChecked.length).to.equal(0)
-        })
+            expect(
+              renameProjectMock.called(`/project/${projectsData[1].id}/rename`)
+            ).to.be.true
 
-        it('opens the copy modal, can copy the project, and view updated', async function () {
-          const tableRows = screen.getAllByRole('row')
-          const linkForProjectToCopy = within(tableRows[1]).getByRole('link')
-          const projectNameToCopy = linkForProjectToCopy.textContent || '' // needed for type checking
-          screen.getByText(projectNameToCopy) // make sure not just empty string
-          const copiedProjectName = `${projectNameToCopy} (Copy)`
-          const cloneProjectMock = fetchMock.post(
-            `express:/project/:id/clone`,
-            {
-              status: 200,
-              body: {
-                name: copiedProjectName,
-                lastUpdated: new Date(),
-                project_id: userId,
-                owner_ref: userId,
-                owner,
-                id: '6328e14abec0df019fce0be5',
-                lastUpdatedBy: owner,
-                accessLevel: 'owner',
-                source: 'owner',
-                trashed: false,
-                archived: false,
-              },
-            }
-          )
+            const table = await screen.findByRole('table')
+            within(table).getByText(newProjectName)
+            expect(within(table).queryByText(oldName)).to.be.null
 
-          await waitFor(() => {
-            const moreDropdown =
-              within(actionsToolbar).getByText<HTMLElement>('More')
-            fireEvent.click(moreDropdown)
+            const allCheckboxes = await within(
+              table
+            ).findAllByRole<HTMLInputElement>('checkbox')
+            const allCheckboxesChecked = allCheckboxes.filter(c => c.checked)
+            expect(allCheckboxesChecked.length).to.equal(0)
           })
 
-          const copyButton =
-            within(actionsToolbar).getByText<HTMLButtonElement>('Make a copy')
-          fireEvent.click(copyButton)
+          it('opens the copy modal, can copy the project, and view updated', async function () {
+            const tableRows = screen.getAllByRole('row')
+            const linkForProjectToCopy = within(tableRows[1]).getByRole('link')
+            const projectNameToCopy = linkForProjectToCopy.textContent || '' // needed for type checking
+            screen.getByText(projectNameToCopy) // make sure not just empty string
+            const copiedProjectName = `${projectNameToCopy} (Copy)`
+            const cloneProjectMock = fetchMock.post(
+              `express:/project/:id/clone`,
+              {
+                status: 200,
+                body: {
+                  name: copiedProjectName,
+                  lastUpdated: new Date(),
+                  project_id: userId,
+                  owner_ref: userId,
+                  owner,
+                  id: '6328e14abec0df019fce0be5',
+                  lastUpdatedBy: owner,
+                  accessLevel: 'owner',
+                  source: 'owner',
+                  trashed: false,
+                  archived: false,
+                },
+              }
+            )
+
+            await waitFor(() => {
+              const moreDropdown =
+                within(actionsToolbar).getByText<HTMLElement>('More')
+              fireEvent.click(moreDropdown)
+            })
 
-          // confirm in modal
-          const copyConfirmButton = document.querySelector(
-            'button[type="submit"]'
-          ) as HTMLElement
-          fireEvent.click(copyConfirmButton)
+            const copyButton =
+              within(actionsToolbar).getByText<HTMLButtonElement>('Make a copy')
+            fireEvent.click(copyButton)
 
-          await fetchMock.flush(true)
+            // confirm in modal
+            const copyConfirmButton = document.querySelector(
+              'button[type="submit"]'
+            ) as HTMLElement
+            fireEvent.click(copyConfirmButton)
 
-          expect(
-            cloneProjectMock.called(`/project/${projectsData[1].id}/clone`)
-          ).to.be.true
+            await fetchMock.flush(true)
 
-          expect(sendSpy).to.be.calledOnce
-          expect(sendSpy).calledWith('project-list-page-interaction')
+            expect(
+              cloneProjectMock.called(`/project/${projectsData[1].id}/clone`)
+            ).to.be.true
 
-          screen.getByText(copiedProjectName)
+            expect(sendSpy).to.be.calledOnce
+            expect(sendSpy).calledWith('project-list-page-interaction')
+
+            screen.getByText(copiedProjectName)
+          })
         })
       })
 

+ 1 - 1
services/web/test/frontend/features/project-list/components/table/project-tools/project-tools.test.tsx

@@ -6,7 +6,7 @@ import {
   resetProjectListContextFetch,
 } from '../../../helpers/render-with-context'
 
-describe('<ProjectListTable />', function () {
+describe('<ProjectTools />', function () {
   afterEach(function () {
     resetProjectListContextFetch()
   })