diff --git a/README.md b/README.md index 3a8ca52504..3d384e022e 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This is the web frontend for Vikunja, written in Vue.js. -Take a look at [our roadmap](https://my.vikunja.cloud/share/UrdhKPqumxDXUbYpEGJLSIyNTwAnbBzVlwdDpRbv/auth) (hosted on Vikunja!) for a list of things we're currently working on! +Take a look at [our roadmap](https://my.vikunja.cloud/share/UrdhKPqumxDXUbYpEGJLSIyNTwAnbBzVlwdDpRbv/auth) (hosted on Vikunja!) for a project of things we're currently working on! ## Security Reports diff --git a/cypress/e2e/list/list-history.spec.ts b/cypress/e2e/list/list-history.spec.ts index 69592a84b8..5b43f4852e 100644 --- a/cypress/e2e/list/list-history.spec.ts +++ b/cypress/e2e/list/list-history.spec.ts @@ -1,41 +1,41 @@ import {createFakeUserAndLogin} from '../../support/authenticateUser' -import {ListFactory} from '../../factories/list' -import {prepareLists} from './prepareLists' +import {ProjectFactory} from '../../factories/project' +import {prepareProjects} from './prepareProjects' -describe('List History', () => { +describe('Project History', () => { createFakeUserAndLogin() prepareLists() - it('should show a list history on the home page', () => { + it('should show a project history on the home page', () => { cy.intercept(Cypress.env('API_URL') + '/namespaces*').as('loadNamespaces') - cy.intercept(Cypress.env('API_URL') + '/lists/*').as('loadList') + cy.intercept(Cypress.env('API_URL') + '/projects/*').as('loadProject') - const lists = ListFactory.create(6) + const projects = ProjectFactory.create(6) cy.visit('/') cy.wait('@loadNamespaces') cy.get('body') .should('not.contain', 'Last viewed') - cy.visit(`/lists/${lists[0].id}`) + cy.visit(`/projects/${projects[0].id}`) cy.wait('@loadNamespaces') - cy.wait('@loadList') - cy.visit(`/lists/${lists[1].id}`) + cy.wait('@loadProject') + cy.visit(`/projects/${projects[1].id}`) cy.wait('@loadNamespaces') - cy.wait('@loadList') - cy.visit(`/lists/${lists[2].id}`) + cy.wait('@loadProject') + cy.visit(`/projects/${projects[2].id}`) cy.wait('@loadNamespaces') - cy.wait('@loadList') - cy.visit(`/lists/${lists[3].id}`) + cy.wait('@loadProject') + cy.visit(`/projects/${projects[3].id}`) cy.wait('@loadNamespaces') - cy.wait('@loadList') - cy.visit(`/lists/${lists[4].id}`) + cy.wait('@loadProject') + cy.visit(`/projects/${projects[4].id}`) cy.wait('@loadNamespaces') - cy.wait('@loadList') - cy.visit(`/lists/${lists[5].id}`) + cy.wait('@loadProject') + cy.visit(`/projects/${projects[5].id}`) cy.wait('@loadNamespaces') - cy.wait('@loadList') + cy.wait('@loadProject') // cy.visit('/') // cy.wait('@loadNamespaces') @@ -47,11 +47,11 @@ describe('List History', () => { cy.get('body') .should('contain', 'Last viewed') cy.get('[data-cy="listCardGrid"]') - .should('not.contain', lists[0].title) - .should('contain', lists[1].title) - .should('contain', lists[2].title) - .should('contain', lists[3].title) - .should('contain', lists[4].title) - .should('contain', lists[5].title) + .should('not.contain', projects[0].title) + .should('contain', projects[1].title) + .should('contain', projects[2].title) + .should('contain', projects[3].title) + .should('contain', projects[4].title) + .should('contain', projects[5].title) }) }) \ No newline at end of file diff --git a/cypress/e2e/list/list-view-gantt.spec.ts b/cypress/e2e/list/list-view-gantt.spec.ts index 177f791ad7..5a67c70818 100644 --- a/cypress/e2e/list/list-view-gantt.spec.ts +++ b/cypress/e2e/list/list-view-gantt.spec.ts @@ -3,15 +3,15 @@ import {formatISO, format} from 'date-fns' import {createFakeUserAndLogin} from '../../support/authenticateUser' import {TaskFactory} from '../../factories/task' -import {prepareLists} from './prepareLists' +import {prepareProjects} from './prepareProjects' -describe('List View Gantt', () => { +describe('Project View Gantt', () => { createFakeUserAndLogin() - prepareLists() + prepareProjects() it('Hides tasks with no dates', () => { const tasks = TaskFactory.create(1) - cy.visit('/lists/1/gantt') + cy.visit('/projects/1/gantt') cy.get('.g-gantt-rows-container') .should('not.contain', tasks[0].title) @@ -25,7 +25,7 @@ describe('List View Gantt', () => { nextMonth.setDate(1) nextMonth.setMonth(9) - cy.visit('/lists/1/gantt') + cy.visit('/projects/1/gantt') cy.get('.g-timeunits-container') .should('contain', format(now, 'MMMM')) @@ -38,7 +38,7 @@ describe('List View Gantt', () => { start_date: now.toISOString(), end_date: new Date(new Date(now).setDate(now.getDate() + 4)).toISOString(), }) - cy.visit('/lists/1/gantt') + cy.visit('/projects/1/gantt') cy.get('.g-gantt-rows-container') .should('not.be.empty') @@ -50,7 +50,7 @@ describe('List View Gantt', () => { start_date: null, end_date: null, }) - cy.visit('/lists/1/gantt') + cy.visit('/projects/1/gantt') cy.get('.gantt-options .fancycheckbox') .contains('Show tasks which don\'t have dates set') @@ -69,7 +69,7 @@ describe('List View Gantt', () => { start_date: now.toISOString(), end_date: new Date(new Date(now).setDate(now.getDate() + 4)).toISOString(), }) - cy.visit('/lists/1/gantt') + cy.visit('/projects/1/gantt') cy.get('.g-gantt-rows-container .g-gantt-row .g-gantt-row-bars-container div .g-gantt-bar') .first() @@ -83,9 +83,9 @@ describe('List View Gantt', () => { const now = Date.UTC(2022, 10, 9) cy.clock(now, ['Date']) - cy.visit('/lists/1/gantt') + cy.visit('/projects/1/gantt') - cy.get('.list-gantt .gantt-options .field .control input.input.form-control') + cy.get('.project-gantt .gantt-options .field .control input.input.form-control') .click() cy.get('.flatpickr-calendar .flatpickr-innerContainer .dayContainer .flatpickr-day') .first() @@ -99,13 +99,13 @@ describe('List View Gantt', () => { }) it('Should change the date range based on date query parameters', () => { - cy.visit('/lists/1/gantt?dateFrom=2022-09-25&dateTo=2022-11-05') + cy.visit('/projects/1/gantt?dateFrom=2022-09-25&dateTo=2022-11-05') cy.get('.g-timeunits-container') .should('contain', 'September 2022') .should('contain', 'October 2022') .should('contain', 'November 2022') - cy.get('.list-gantt .gantt-options .field .control input.input.form-control') + cy.get('.project-gantt .gantt-options .field .control input.input.form-control') .should('have.value', '25 Sep 2022 to 5 Nov 2022') }) @@ -115,7 +115,7 @@ describe('List View Gantt', () => { start_date: formatISO(now), end_date: formatISO(now.setDate(now.getDate() + 4)), }) - cy.visit('/lists/1/gantt') + cy.visit('/projects/1/gantt') cy.get('.gantt-container .g-gantt-chart .g-gantt-row-bars-container .g-gantt-bar') .dblclick() diff --git a/cypress/e2e/list/list-view-kanban.spec.ts b/cypress/e2e/list/list-view-kanban.spec.ts index c2677c6890..719319373d 100644 --- a/cypress/e2e/list/list-view-kanban.spec.ts +++ b/cypress/e2e/list/list-view-kanban.spec.ts @@ -1,13 +1,13 @@ import {createFakeUserAndLogin} from '../../support/authenticateUser' import {BucketFactory} from '../../factories/bucket' -import {ListFactory} from '../../factories/list' +import {ProjectFactory} from '../../factories/project' import {TaskFactory} from '../../factories/task' -import {prepareLists} from './prepareLists' +import {prepareProjects} from './prepareProjects' -describe('List View Kanban', () => { +describe('Project View Kanban', () => { createFakeUserAndLogin() - prepareLists() + prepareProjects() let buckets beforeEach(() => { @@ -16,10 +16,10 @@ describe('List View Kanban', () => { it('Shows all buckets with their tasks', () => { const data = TaskFactory.create(10, { - list_id: 1, + project_id: 1, bucket_id: 1, }) - cy.visit('/lists/1/kanban') + cy.visit('/projects/1/kanban') cy.get('.kanban .bucket .title') .contains(buckets[0].title) @@ -34,10 +34,10 @@ describe('List View Kanban', () => { it('Can add a new task to a bucket', () => { TaskFactory.create(2, { - list_id: 1, + project_id: 1, bucket_id: 1, }) - cy.visit('/lists/1/kanban') + cy.visit('/projects/1/kanban') cy.get('.kanban .bucket') .contains(buckets[0].title) @@ -55,7 +55,7 @@ describe('List View Kanban', () => { }) it('Can create a new bucket', () => { - cy.visit('/lists/1/kanban') + cy.visit('/projects/1/kanban') cy.get('.kanban .bucket.new-bucket .button') .click() @@ -69,7 +69,7 @@ describe('List View Kanban', () => { }) it('Can set a bucket limit', () => { - cy.visit('/lists/1/kanban') + cy.visit('/projects/1/kanban') cy.get('.kanban .bucket .bucket-header .dropdown.options .dropdown-trigger') .first() @@ -90,7 +90,7 @@ describe('List View Kanban', () => { }) it('Can rename a bucket', () => { - cy.visit('/lists/1/kanban') + cy.visit('/projects/1/kanban') cy.get('.kanban .bucket .bucket-header .title') .first() @@ -101,7 +101,7 @@ describe('List View Kanban', () => { }) it('Can delete a bucket', () => { - cy.visit('/lists/1/kanban') + cy.visit('/projects/1/kanban') cy.get('.kanban .bucket .bucket-header .dropdown.options .dropdown-trigger') .first() @@ -125,10 +125,10 @@ describe('List View Kanban', () => { it('Can drag tasks around', () => { const tasks = TaskFactory.create(2, { - list_id: 1, + project_id: 1, bucket_id: 1, }) - cy.visit('/lists/1/kanban') + cy.visit('/projects/1/kanban') cy.get('.kanban .bucket .tasks .task') .contains(tasks[0].title) @@ -144,10 +144,10 @@ describe('List View Kanban', () => { it('Should navigate to the task when the task card is clicked', () => { const tasks = TaskFactory.create(5, { id: '{increment}', - list_id: 1, + project_id: 1, bucket_id: 1, }) - cy.visit('/lists/1/kanban') + cy.visit('/projects/1/kanban') cy.get('.kanban .bucket .tasks .task') .contains(tasks[0].title) @@ -158,18 +158,18 @@ describe('List View Kanban', () => { .should('contain', `/tasks/${tasks[0].id}`, { timeout: 1000 }) }) - it('Should remove a task from the kanban board when moving it to another list', () => { - const lists = ListFactory.create(2) + it('Should remove a task from the kanban board when moving it to another project', () => { + const projects = ProjectFactory.create(2) BucketFactory.create(2, { - list_id: '{increment}', + project_id: '{increment}', }) const tasks = TaskFactory.create(5, { id: '{increment}', - list_id: 1, + project_id: 1, bucket_id: 1, }) const task = tasks[0] - cy.visit('/lists/1/kanban') + cy.visit('/projects/1/kanban') cy.get('.kanban .bucket .tasks .task') .contains(task.title) @@ -180,7 +180,7 @@ describe('List View Kanban', () => { .contains('Move') .click() cy.get('.task-view .content.details .field .multiselect.control .input-wrapper input') - .type(`${lists[1].title}{enter}`) + .type(`${projects[1].title}{enter}`) // The requests happen with a 200ms timeout. Because of that, the results are not yet there when cypress // presses enter and we can't simulate pressing on enter to select the item. cy.get('.task-view .content.details .field .multiselect.control .search-results') @@ -197,26 +197,26 @@ describe('List View Kanban', () => { it('Shows a button to filter the kanban board', () => { const data = TaskFactory.create(10, { - list_id: 1, + project_id: 1, bucket_id: 1, }) - cy.visit('/lists/1/kanban') + cy.visit('/projects/1/kanban') - cy.get('.list-kanban .filter-container .base-button') + cy.get('.project-kanban .filter-container .base-button') .should('exist') }) it('Should remove a task from the board when deleting it', () => { - const lists = ListFactory.create(1) + const projects = ProjectFactory.create(1) const buckets = BucketFactory.create(2, { - list_id: lists[0].id, + project_id: projects[0].id, }) const tasks = TaskFactory.create(5, { - list_id: 1, + project_id: 1, bucket_id: buckets[0].id, }) const task = tasks[0] - cy.visit('/lists/1/kanban') + cy.visit('/projects/1/kanban') cy.get('.kanban .bucket .tasks .task') .contains(task.title) diff --git a/cypress/e2e/list/list-view-list.spec.ts b/cypress/e2e/list/list-view-list.spec.ts index 0601894d4f..9dd332d3b1 100644 --- a/cypress/e2e/list/list-view-list.spec.ts +++ b/cypress/e2e/list/list-view-list.spec.ts @@ -1,32 +1,32 @@ import {createFakeUserAndLogin} from '../../support/authenticateUser' -import {UserListFactory} from '../../factories/users_list' +import {UserProjectFactory} from '../../factories/users_project' import {TaskFactory} from '../../factories/task' import {UserFactory} from '../../factories/user' -import {ListFactory} from '../../factories/list' -import {prepareLists} from './prepareLists' +import {ProjectFactory} from '../../factories/project' +import {prepareProjects} from './prepareProjects' -describe('List View List', () => { +describe('Project View Project', () => { createFakeUserAndLogin() - prepareLists() + prepareProjects() - it('Should be an empty list', () => { - cy.visit('/lists/1') + it('Should be an empty project', () => { + cy.visit('/projects/1') cy.url() - .should('contain', '/lists/1/list') - cy.get('.list-title h1') - .should('contain', 'First List') - cy.get('.list-title .dropdown') + .should('contain', '/projects/1/project') + cy.get('.project-title h1') + .should('contain', 'First Project') + cy.get('.project-title .dropdown') .should('exist') cy.get('p') - .contains('This list is currently empty.') + .contains('This project is currently empty.') .should('exist') }) it('Should create a new task', () => { const newTaskTitle = 'New task' - cy.visit('/lists/1') + cy.visit('/projects/1') cy.get('.task-add textarea') .type(newTaskTitle+'{enter}') cy.get('.tasks') @@ -36,9 +36,9 @@ describe('List View List', () => { it('Should navigate to the task when the title is clicked', () => { const tasks = TaskFactory.create(5, { id: '{increment}', - list_id: 1, + project_id: 1, }) - cy.visit('/lists/1/list') + cy.visit('/projects/1/project') cy.get('.tasks .task .tasktext') .contains(tasks[0].title) @@ -49,35 +49,35 @@ describe('List View List', () => { .should('contain', `/tasks/${tasks[0].id}`) }) - it('Should not see any elements for a list which is shared read only', () => { + it('Should not see any elements for a project which is shared read only', () => { UserFactory.create(2) - UserListFactory.create(1, { - list_id: 2, + UserProjectFactory.create(1, { + project_id: 2, user_id: 1, right: 0, }) - const lists = ListFactory.create(2, { + const projects = ProjectFactory.create(2, { owner_id: '{increment}', namespace_id: '{increment}', }) - cy.visit(`/lists/${lists[1].id}/`) + cy.visit(`/projects/${projects[1].id}/`) - cy.get('.list-title .icon') + cy.get('.project-title .icon') .should('not.exist') cy.get('input.input[placeholder="Add a new task..."') .should('not.exist') }) - it('Should only show the color of a list in the navigation and not in the list view', () => { - const lists = ListFactory.create(1, { + it('Should only show the color of a project in the navigation and not in the project view', () => { + const projects = ProjectFactory.create(1, { hex_color: '00db60', }) TaskFactory.create(10, { - list_id: lists[0].id, + project_id: projects[0].id, }) - cy.visit(`/lists/${lists[0].id}/`) + cy.visit(`/projects/${projects[0].id}/`) - cy.get('.menu-list li .list-menu-link .color-bubble') + cy.get('.menu-project li .project-menu-link .color-bubble') .should('have.css', 'background-color', 'rgb(0, 219, 96)') cy.get('.tasks .color-bubble') .should('not.exist') @@ -87,9 +87,9 @@ describe('List View List', () => { const tasks = TaskFactory.create(100, { id: '{increment}', title: i => `task${i}`, - list_id: 1, + project_id: 1, }) - cy.visit('/lists/1/list') + cy.visit('/projects/1/project') cy.get('.tasks') .should('contain', tasks[1].title) diff --git a/cypress/e2e/list/list-view-table.spec.ts b/cypress/e2e/list/list-view-table.spec.ts index dac79224d4..ce52fb9bf6 100644 --- a/cypress/e2e/list/list-view-table.spec.ts +++ b/cypress/e2e/list/list-view-table.spec.ts @@ -2,37 +2,37 @@ import {createFakeUserAndLogin} from '../../support/authenticateUser' import {TaskFactory} from '../../factories/task' -describe('List View Table', () => { +describe('Project View Table', () => { createFakeUserAndLogin() it('Should show a table with tasks', () => { const tasks = TaskFactory.create(1) - cy.visit('/lists/1/table') + cy.visit('/projects/1/table') - cy.get('.list-table table.table') + cy.get('.project-table table.table') .should('exist') - cy.get('.list-table table.table') + cy.get('.project-table table.table') .should('contain', tasks[0].title) }) it('Should have working column switches', () => { TaskFactory.create(1) - cy.visit('/lists/1/table') + cy.visit('/projects/1/table') - cy.get('.list-table .filter-container .items .button') + cy.get('.project-table .filter-container .items .button') .contains('Columns') .click() - cy.get('.list-table .filter-container .card.columns-filter .card-content .fancycheckbox .check') + cy.get('.project-table .filter-container .card.columns-filter .card-content .fancycheckbox .check') .contains('Priority') .click() - cy.get('.list-table .filter-container .card.columns-filter .card-content .fancycheckbox .check') + cy.get('.project-table .filter-container .card.columns-filter .card-content .fancycheckbox .check') .contains('Done') .click() - cy.get('.list-table table.table th') + cy.get('.project-table table.table th') .contains('Priority') .should('exist') - cy.get('.list-table table.table th') + cy.get('.project-table table.table th') .contains('Done') .should('not.exist') }) @@ -40,11 +40,11 @@ describe('List View Table', () => { it('Should navigate to the task when the title is clicked', () => { const tasks = TaskFactory.create(5, { id: '{increment}', - list_id: 1, + project_id: 1, }) - cy.visit('/lists/1/table') + cy.visit('/projects/1/table') - cy.get('.list-table table.table') + cy.get('.project-table table.table') .contains(tasks[0].title) .click() diff --git a/cypress/e2e/list/list.spec.ts b/cypress/e2e/list/list.spec.ts index 6f7c0b3a4d..40c530d3d7 100644 --- a/cypress/e2e/list/list.spec.ts +++ b/cypress/e2e/list/list.spec.ts @@ -1,90 +1,90 @@ import {createFakeUserAndLogin} from '../../support/authenticateUser' import {TaskFactory} from '../../factories/task' -import {prepareLists} from './prepareLists' +import {prepareProjects} from './prepareProjects' -describe('Lists', () => { +describe('Projects', () => { createFakeUserAndLogin() - let lists - prepareLists((newLists) => (lists = newLists)) + let projects + prepareProjects((newProjects) => (projects = newProjects)) - it('Should create a new list', () => { + it('Should create a new project', () => { cy.visit('/') cy.get('.namespace-title .dropdown-trigger') .click() cy.get('.namespace-title .dropdown .dropdown-item') - .contains('New list') + .contains('New project') .click() cy.url() - .should('contain', '/lists/new/1') + .should('contain', '/projects/new/1') cy.get('.card-header-title') - .contains('New list') + .contains('New project') cy.get('input.input') - .type('New List') + .type('New Project') cy.get('.button') .contains('Create') .click() - cy.get('.global-notification', { timeout: 1000 }) // Waiting until the request to create the new list is done + cy.get('.global-notification', { timeout: 1000 }) // Waiting until the request to create the new project is done .should('contain', 'Success') cy.url() - .should('contain', '/lists/') - cy.get('.list-title h1') - .should('contain', 'New List') + .should('contain', '/projects/') + cy.get('.project-title h1') + .should('contain', 'New Project') }) - it('Should redirect to a specific list view after visited', () => { - cy.visit('/lists/1/kanban') + it('Should redirect to a specific project view after visited', () => { + cy.visit('/projects/1/kanban') cy.url() - .should('contain', '/lists/1/kanban') - cy.visit('/lists/1') + .should('contain', '/projects/1/kanban') + cy.visit('/projects/1') cy.url() - .should('contain', '/lists/1/kanban') + .should('contain', '/projects/1/kanban') }) - it('Should rename the list in all places', () => { + it('Should rename the project in all places', () => { TaskFactory.create(5, { id: '{increment}', - list_id: 1, + project_id: 1, }) - const newListName = 'New list name' + const newProjectName = 'New project name' - cy.visit('/lists/1') - cy.get('.list-title h1') - .should('contain', 'First List') + cy.visit('/projects/1') + cy.get('.project-title h1') + .should('contain', 'First Project') - cy.get('.namespace-container .menu.namespaces-lists .menu-list li:first-child .dropdown .menu-list-dropdown-trigger') + cy.get('.namespace-container .menu.namespaces-projects .menu-project li:first-child .dropdown .menu-list-dropdown-trigger') .click() - cy.get('.namespace-container .menu.namespaces-lists .menu-list li:first-child .dropdown .dropdown-content') + cy.get('.namespace-container .menu.namespaces-projects .menu-project li:first-child .dropdown .dropdown-content') .contains('Edit') .click() cy.get('#title') - .type(`{selectall}${newListName}`) + .type(`{selectall}${newProjectName}`) cy.get('footer.card-footer .button') .contains('Save') .click() cy.get('.global-notification') .should('contain', 'Success') - cy.get('.list-title h1') - .should('contain', newListName) - .should('not.contain', lists[0].title) - cy.get('.namespace-container .menu.namespaces-lists .menu-list li:first-child') - .should('contain', newListName) - .should('not.contain', lists[0].title) + cy.get('.project-title h1') + .should('contain', newProjectName) + .should('not.contain', projects[0].title) + cy.get('.namespace-container .menu.namespaces-projects .menu-project li:first-child') + .should('contain', newProjectName) + .should('not.contain', projects[0].title) cy.visit('/') cy.get('.card-content') - .should('contain', newListName) - .should('not.contain', lists[0].title) + .should('contain', newProjectName) + .should('not.contain', projects[0].title) }) - it('Should remove a list', () => { - cy.visit(`/lists/${lists[0].id}`) + it('Should remove a project', () => { + cy.visit(`/projects/${projects[0].id}`) - cy.get('.namespace-container .menu.namespaces-lists .menu-list li:first-child .dropdown .menu-list-dropdown-trigger') + cy.get('.namespace-container .menu.namespaces-projects .menu-project li:first-child .dropdown .menu-list-dropdown-trigger') .click() - cy.get('.namespace-container .menu.namespaces-lists .menu-list li:first-child .dropdown .dropdown-content') + cy.get('.namespace-container .menu.namespaces-projects .menu-project li:first-child .dropdown .dropdown-content') .contains('Delete') .click() cy.url() @@ -95,28 +95,28 @@ describe('Lists', () => { cy.get('.global-notification') .should('contain', 'Success') - cy.get('.namespace-container .menu.namespaces-lists .menu-list') - .should('not.contain', lists[0].title) + cy.get('.namespace-container .menu.namespaces-projects .menu-project') + .should('not.contain', projects[0].title) cy.location('pathname') .should('equal', '/') }) - it('Should archive a list', () => { - cy.visit(`/lists/${lists[0].id}`) + it('Should archive a project', () => { + cy.visit(`/projects/${projects[0].id}`) - cy.get('.list-title .dropdown') + cy.get('.project-title .dropdown') .click() - cy.get('.list-title .dropdown .dropdown-menu .dropdown-item') + cy.get('.project-title .dropdown .dropdown-menu .dropdown-item') .contains('Archive') .click() cy.get('.modal-content') - .should('contain.text', 'Archive this list') + .should('contain.text', 'Archive this project') cy.get('.modal-content [data-cy=modalPrimary]') .click() - cy.get('.namespace-container .menu.namespaces-lists .menu-list') - .should('not.contain', lists[0].title) + cy.get('.namespace-container .menu.namespaces-projects .menu-project') + .should('not.contain', projects[0].title) cy.get('main.app-content') - .should('contain.text', 'This list is archived. It is not possible to create new or edit tasks for it.') + .should('contain.text', 'This project is archived. It is not possible to create new or edit tasks for it.') }) }) diff --git a/cypress/e2e/list/namespaces.spec.ts b/cypress/e2e/list/namespaces.spec.ts index 58d57159b1..72cc643a07 100644 --- a/cypress/e2e/list/namespaces.spec.ts +++ b/cypress/e2e/list/namespaces.spec.ts @@ -1,6 +1,6 @@ import {createFakeUserAndLogin} from '../../support/authenticateUser' -import {ListFactory} from '../../factories/list' +import {ProjectFactory} from '../../factories/project' import {NamespaceFactory} from '../../factories/namespace' describe('Namepaces', () => { @@ -10,7 +10,7 @@ describe('Namepaces', () => { beforeEach(() => { namespaces = NamespaceFactory.create(1) - ListFactory.create(1) + ProjectFactory.create(1) }) it('Should be all there', () => { @@ -51,9 +51,9 @@ describe('Namepaces', () => { cy.visit('/namespaces') - cy.get(`.namespace-container .menu.namespaces-lists .namespace-title:contains(${newNamespaces[0].title}) .dropdown .dropdown-trigger`) + cy.get(`.namespace-container .menu.namespaces-projects .namespace-title:contains(${newNamespaces[0].title}) .dropdown .dropdown-trigger`) .click() - cy.get('.namespace-container .menu.namespaces-lists .namespace-title .dropdown .dropdown-content') + cy.get('.namespace-container .menu.namespaces-projects .namespace-title .dropdown .dropdown-content') .contains('Edit') .click() cy.url() @@ -69,10 +69,10 @@ describe('Namepaces', () => { cy.get('.global-notification', { timeout: 1000 }) .should('contain', 'Success') - cy.get('.namespace-container .menu.namespaces-lists') + cy.get('.namespace-container .menu.namespaces-projects') .should('contain', newNamespaceName) .should('not.contain', newNamespaces[0].title) - cy.get('[data-cy="namespaces-list"]') + cy.get('[data-cy="namespaces-project"]') .should('contain', newNamespaceName) .should('not.contain', newNamespaces[0].title) }) @@ -82,9 +82,9 @@ describe('Namepaces', () => { cy.visit('/') - cy.get(`.namespace-container .menu.namespaces-lists .namespace-title:contains(${newNamespaces[0].title}) .dropdown .dropdown-trigger`) + cy.get(`.namespace-container .menu.namespaces-projects .namespace-title:contains(${newNamespaces[0].title}) .dropdown .dropdown-trigger`) .click() - cy.get('.namespace-container .menu.namespaces-lists .namespace-title .dropdown .dropdown-content') + cy.get('.namespace-container .menu.namespaces-projects .namespace-title .dropdown .dropdown-content') .contains('Delete') .click() cy.url() @@ -95,21 +95,21 @@ describe('Namepaces', () => { cy.get('.global-notification') .should('contain', 'Success') - cy.get('.namespace-container .menu.namespaces-lists') + cy.get('.namespace-container .menu.namespaces-projects') .should('not.contain', newNamespaces[0].title) }) - it('Should not show archived lists & namespaces if the filter is not checked', () => { + it('Should not show archived projects & namespaces if the filter is not checked', () => { const n = NamespaceFactory.create(1, { id: 2, is_archived: true, }, false) - ListFactory.create(1, { + ProjectFactory.create(1, { id: 2, namespace_id: n[0].id, }, false) - ListFactory.create(1, { + ProjectFactory.create(1, { id: 3, is_archived: true, }, false) diff --git a/cypress/e2e/list/prepareLists.ts b/cypress/e2e/list/prepareLists.ts index 8fa70e9c78..19b9241758 100644 --- a/cypress/e2e/list/prepareLists.ts +++ b/cypress/e2e/list/prepareLists.ts @@ -1,19 +1,19 @@ -import {ListFactory} from '../../factories/list' +import {ProjectFactory} from '../../factories/project' import {NamespaceFactory} from '../../factories/namespace' import {TaskFactory} from '../../factories/task' -export function createLists() { +export function createProjects() { NamespaceFactory.create(1) - const lists = ListFactory.create(1, { - title: 'First List' + const projects = ProjectFactory.create(1, { + title: 'First Project' }) TaskFactory.truncate() - return lists + return projects } -export function prepareLists(setLists = () => {}) { +export function prepareProjects(setProjects = () => {}) { beforeEach(() => { - const lists = createLists() - setLists(lists) + const projects = createProjects() + setProjects(projects) }) } \ No newline at end of file diff --git a/cypress/e2e/misc/editor.spec.ts b/cypress/e2e/misc/editor.spec.ts index c1edb37e39..3ed7a47dcc 100644 --- a/cypress/e2e/misc/editor.spec.ts +++ b/cypress/e2e/misc/editor.spec.ts @@ -1,18 +1,18 @@ import {createFakeUserAndLogin} from '../../support/authenticateUser' import {TaskFactory} from '../../factories/task' -import {ListFactory} from '../../factories/list' +import {ProjectFactory} from '../../factories/project' import {NamespaceFactory} from '../../factories/namespace' -import {UserListFactory} from '../../factories/users_list' +import {UserProjectFactory} from '../../factories/users_project' describe('Editor', () => { createFakeUserAndLogin() beforeEach(() => { NamespaceFactory.create(1) - ListFactory.create(1) + const projects = ProjectFactory.create(1) TaskFactory.truncate() - UserListFactory.truncate() + UserProjectFactory.truncate() }) it('Has a preview with checkable checkboxes', () => { diff --git a/cypress/e2e/sharing/linkShare.spec.ts b/cypress/e2e/sharing/linkShare.spec.ts index bc616cc6f0..de825f183e 100644 --- a/cypress/e2e/sharing/linkShare.spec.ts +++ b/cypress/e2e/sharing/linkShare.spec.ts @@ -1,22 +1,22 @@ import {LinkShareFactory} from '../../factories/link_sharing' -import {ListFactory} from '../../factories/list' +import {ProjectFactory} from '../../factories/project' import {TaskFactory} from '../../factories/task' describe('Link shares', () => { it('Can view a link share', () => { - const lists = ListFactory.create(1) + const projects = ProjectFactory.create(1) const tasks = TaskFactory.create(10, { - list_id: lists[0].id + project_id: projects[0].id }) const linkShares = LinkShareFactory.create(1, { - list_id: lists[0].id, + project_id: projects[0].id, right: 0, }) cy.visit(`/share/${linkShares[0].hash}/auth`) cy.get('h1.title') - .should('contain', lists[0].title) + .should('contain', projects[0].title) cy.get('input.input[placeholder="Add a new task..."') .should('not.exist') cy.get('.tasks') diff --git a/cypress/e2e/task/overview.spec.ts b/cypress/e2e/task/overview.spec.ts index 39153c191e..222b84430d 100644 --- a/cypress/e2e/task/overview.spec.ts +++ b/cypress/e2e/task/overview.spec.ts @@ -1,6 +1,6 @@ import {createFakeUserAndLogin} from '../../support/authenticateUser' -import {ListFactory} from '../../factories/list' +import {ProjectFactory} from '../../factories/project' import {seed} from '../../support/seed' import {TaskFactory} from '../../factories/task' import {NamespaceFactory} from '../../factories/namespace' @@ -9,9 +9,9 @@ import {updateUserSettings} from '../../support/updateUserSettings' function seedTasks(numberOfTasks = 50, startDueDate = new Date()) { NamespaceFactory.create(1) - const list = ListFactory.create()[0] + const project = ProjectFactory.create()[0] BucketFactory.create(1, { - list_id: list.id, + project_id: project.id, }) const tasks = [] let dueDate = startDueDate @@ -20,7 +20,7 @@ function seedTasks(numberOfTasks = 50, startDueDate = new Date()) { dueDate = new Date(new Date(dueDate).setDate(dueDate.getDate() + 2)) tasks.push({ id: i + 1, - list_id: list.id, + project_id: project.id, done: false, created_by_id: 1, title: 'Test Task ' + i, @@ -31,7 +31,7 @@ function seedTasks(numberOfTasks = 50, startDueDate = new Date()) { }) } seed(TaskFactory.table, tasks) - return {tasks, list} + return {tasks, project} } describe('Home Page Task Overview', () => { @@ -73,7 +73,7 @@ describe('Home Page Task Overview', () => { due_date: new Date().toISOString(), }, false) - cy.visit(`/lists/${tasks[0].list_id}/list`) + cy.visit(`/projects/${tasks[0].project_id}/project`) cy.get('.tasks .task') .first() .should('contain.text', newTaskTitle) @@ -90,7 +90,7 @@ describe('Home Page Task Overview', () => { cy.visit('/') - cy.visit(`/lists/${tasks[0].list_id}/list`) + cy.visit(`/projects/${tasks[0].project_id}/project`) cy.get('.task-add textarea') .type(newTaskTitle+'{enter}') cy.visit('/') @@ -113,10 +113,10 @@ describe('Home Page Task Overview', () => { .should('contain.text', newTaskTitle) }) - it('Should show a task without a due date added via default list at the bottom', () => { - const {list} = seedTasks(40) + it('Should show a task without a due date added via default project at the bottom', () => { + const {project} = seedTasks(40) updateUserSettings({ - default_list_id: list.id, + default_project_id: project.id, overdue_tasks_reminders_time: '9:00', }) @@ -131,23 +131,23 @@ describe('Home Page Task Overview', () => { .should('contain.text', newTaskTitle) }) - it('Should show the cta buttons for new list when there are no tasks', () => { + it('Should show the cta buttons for new project when there are no tasks', () => { TaskFactory.truncate() cy.visit('/') cy.get('.home.app-content .content') - .should('contain.text', 'You can create a new list for your new tasks:') - .should('contain.text', 'Or import your lists and tasks from other services into Vikunja:') + .should('contain.text', 'You can create a new project for your new tasks:') + .should('contain.text', 'Or import your projects and tasks from other services into Vikunja:') }) - it('Should not show the cta buttons for new list when there are tasks', () => { + it('Should not show the cta buttons for new project when there are tasks', () => { seedTasks() cy.visit('/') cy.get('.home.app-content .content') - .should('not.contain.text', 'You can create a new list for your new tasks:') - .should('not.contain.text', 'Or import your lists and tasks from other services into Vikunja:') + .should('not.contain.text', 'You can create a new project for your new tasks:') + .should('not.contain.text', 'Or import your projects and tasks from other services into Vikunja:') }) }) diff --git a/cypress/e2e/task/task.spec.ts b/cypress/e2e/task/task.spec.ts index f441dc742a..9622628b30 100644 --- a/cypress/e2e/task/task.spec.ts +++ b/cypress/e2e/task/task.spec.ts @@ -1,11 +1,11 @@ import {createFakeUserAndLogin} from '../../support/authenticateUser' import {TaskFactory} from '../../factories/task' -import {ListFactory} from '../../factories/list' +import {ProjectFactory} from '../../factories/project' import {TaskCommentFactory} from '../../factories/task_comment' import {UserFactory} from '../../factories/user' import {NamespaceFactory} from '../../factories/namespace' -import {UserListFactory} from '../../factories/users_list' +import {UserProjectFactory} from '../../factories/users_project' import {TaskAssigneeFactory} from '../../factories/task_assignee' import {LabelFactory} from '../../factories/labels' import {LabelTaskFactory} from '../../factories/label_task' @@ -48,22 +48,22 @@ describe('Task', () => { createFakeUserAndLogin() let namespaces - let lists + let projects let buckets beforeEach(() => { // UserFactory.create(1) namespaces = NamespaceFactory.create(1) - lists = ListFactory.create(1) + projects = ProjectFactory.create(1) buckets = BucketFactory.create(1, { - list_id: lists[0].id, + project_id: projects[0].id, }) TaskFactory.truncate() - UserListFactory.truncate() + UserProjectFactory.truncate() }) it('Should be created new', () => { - cy.visit('/lists/1/list') + cy.visit('/projects/1/project') cy.get('.input[placeholder="Add a new task…"') .type('New Task') cy.get('.button') @@ -74,11 +74,11 @@ describe('Task', () => { .should('contain', 'New Task') }) - it('Inserts new tasks at the top of the list', () => { + it('Inserts new tasks at the top of the project', () => { TaskFactory.create(1) - cy.visit('/lists/1/list') - cy.get('.list-is-empty-notice') + cy.visit('/projects/1/project') + cy.get('.project-is-empty-notice') .should('not.exist') cy.get('.input[placeholder="Add a new task…"') .type('New Task') @@ -95,7 +95,7 @@ describe('Task', () => { it('Marks a task as done', () => { TaskFactory.create(1) - cy.visit('/lists/1/list') + cy.visit('/projects/1/project') cy.get('.tasks .task .fancycheckbox label.check') .first() .click() @@ -106,11 +106,11 @@ describe('Task', () => { it('Can add a task to favorites', () => { TaskFactory.create(1) - cy.visit('/lists/1/list') + cy.visit('/projects/1/project') cy.get('.tasks .task .favorite') .first() .click() - cy.get('.menu.namespaces-lists') + cy.get('.menu.namespaces-projects') .should('contain', 'Favorites') }) @@ -134,7 +134,7 @@ describe('Task', () => { .should('contain', '#1') cy.get('.task-view h6.subtitle') .should('contain', namespaces[0].title) - .should('contain', lists[0].title) + .should('contain', projects[0].title) cy.get('.task-view .details.content.description') .should('contain', tasks[0].description) cy.get('.task-view .action-buttons p.created') @@ -179,21 +179,21 @@ describe('Task', () => { .should('contain', 'Mark as undone') }) - it('Shows a task identifier since the list has one', () => { - const lists = ListFactory.create(1, { + it('Shows a task identifier since the project has one', () => { + const projects = ProjectFactory.create(1, { id: 1, identifier: 'TEST', }) const tasks = TaskFactory.create(1, { id: 1, - list_id: lists[0].id, + project_id: projects[0].id, index: 1, }) cy.visit(`/tasks/${tasks[0].id}`) cy.get('.task-view h1.title.task-id') - .should('contain', `${lists[0].identifier}-${tasks[0].index}`) + .should('contain', `${projects[0].identifier}-${tasks[0].index}`) }) it('Can edit the description', () => { @@ -236,14 +236,14 @@ describe('Task', () => { .should('contain', 'Success') }) - it('Can move a task to another list', () => { - const lists = ListFactory.create(2) + it('Can move a task to another project', () => { + const projects = ProjectFactory.create(2) BucketFactory.create(2, { - list_id: '{increment}' + project_id: '{increment}' }) const tasks = TaskFactory.create(1, { id: 1, - list_id: lists[0].id, + project_id: projects[0].id, }) cy.visit(`/tasks/${tasks[0].id}`) @@ -251,7 +251,7 @@ describe('Task', () => { .contains('Move') .click() cy.get('.task-view .content.details .field .multiselect.control .input-wrapper input') - .type(`${lists[1].title}{enter}`) + .type(`${projects[1].title}{enter}`) // The requests happen with a 200ms timeout. Because of that, the results are not yet there when cypress // presses enter and we can't simulate pressing on enter to select the item. cy.get('.task-view .content.details .field .multiselect.control .search-results') @@ -261,7 +261,7 @@ describe('Task', () => { cy.get('.task-view h6.subtitle') .should('contain', namespaces[0].title) - .should('contain', lists[1].title) + .should('contain', projects[1].title) cy.get('.global-notification') .should('contain', 'Success') }) @@ -269,7 +269,7 @@ describe('Task', () => { it('Can delete a task', () => { const tasks = TaskFactory.create(1, { id: 1, - list_id: 1, + project_id: 1, }) cy.visit(`/tasks/${tasks[0].id}`) @@ -286,17 +286,17 @@ describe('Task', () => { cy.get('.global-notification') .should('contain', 'Success') cy.url() - .should('contain', `/lists/${tasks[0].list_id}/`) + .should('contain', `/projects/${tasks[0].project_id}/`) }) it('Can add an assignee to a task', () => { const users = UserFactory.create(5) const tasks = TaskFactory.create(1, { id: 1, - list_id: 1, + project_id: 1, }) - UserListFactory.create(5, { - list_id: 1, + UserProjectFactory.create(5, { + project_id: 1, user_id: '{increment}', }) @@ -321,10 +321,10 @@ describe('Task', () => { const users = UserFactory.create(2) const tasks = TaskFactory.create(1, { id: 1, - list_id: 1, + project_id: 1, }) - UserListFactory.create(5, { - list_id: 1, + UserProjectFactory.create(5, { + project_id: 1, user_id: '{increment}', }) TaskAssigneeFactory.create(1, { @@ -347,7 +347,7 @@ describe('Task', () => { it('Can add a new label to a task', () => { const tasks = TaskFactory.create(1, { id: 1, - list_id: 1, + project_id: 1, }) LabelFactory.truncate() const newLabelText = 'some new label' @@ -375,7 +375,7 @@ describe('Task', () => { it('Can add an existing label to a task', () => { const tasks = TaskFactory.create(1, { id: 1, - list_id: 1, + project_id: 1, }) const labels = LabelFactory.create(1) LabelTaskFactory.truncate() @@ -388,13 +388,13 @@ describe('Task', () => { it('Can add a label to a task and it shows up on the kanban board afterwards', () => { const tasks = TaskFactory.create(1, { id: 1, - list_id: lists[0].id, + project_id: projects[0].id, bucket_id: buckets[0].id, }) const labels = LabelFactory.create(1) LabelTaskFactory.truncate() - cy.visit(`/lists/${lists[0].id}/kanban`) + cy.visit(`/projects/${projects[0].id}/kanban`) cy.get('.bucket .task') .contains(tasks[0].title) @@ -412,7 +412,7 @@ describe('Task', () => { it('Can remove a label from a task', () => { const tasks = TaskFactory.create(1, { id: 1, - list_id: 1, + project_id: 1, }) const labels = LabelFactory.create(1) LabelTaskFactory.create(1, { @@ -527,13 +527,13 @@ describe('Task', () => { TaskAttachmentFactory.truncate() const tasks = TaskFactory.create(1, { id: 1, - list_id: lists[0].id, + project_id: projects[0].id, bucket_id: buckets[0].id, }) const labels = LabelFactory.create(1) LabelTaskFactory.truncate() - cy.visit(`/lists/${lists[0].id}/kanban`) + cy.visit(`/projects/${projects[0].id}/kanban`) cy.get('.bucket .task') .contains(tasks[0].title) diff --git a/cypress/e2e/user/logout.spec.ts b/cypress/e2e/user/logout.spec.ts index aeb07e5878..e95174678d 100644 --- a/cypress/e2e/user/logout.spec.ts +++ b/cypress/e2e/user/logout.spec.ts @@ -26,21 +26,21 @@ describe('Log out', () => { }) }) - it.skip('Should clear the list history after logging the user out', () => { - const lists = createLists() - cy.visit(`/lists/${lists[0].id}`) + it.skip('Should clear the project history after logging the user out', () => { + const projects = createProjects() + cy.visit(`/projects/${projects[0].id}`) .then(() => { - expect(localStorage.getItem('listHistory')).to.not.eq(null) + expect(localStorage.getItem('projectHistory')).to.not.eq(null) }) logout() - cy.wait(1000) // This makes re-loading of the list and associated entities (and the resulting error) visible + cy.wait(1000) // This makes re-loading of the project and associated entities (and the resulting error) visible cy.url() .should('contain', '/login') .then(() => { - expect(localStorage.getItem('listHistory')).to.eq(null) + expect(localStorage.getItem('projectHistory')).to.eq(null) }) }) }) diff --git a/cypress/factories/bucket.ts b/cypress/factories/bucket.ts index d333531bf1..2e0e910777 100644 --- a/cypress/factories/bucket.ts +++ b/cypress/factories/bucket.ts @@ -10,7 +10,7 @@ export class BucketFactory extends Factory { return { id: '{increment}', title: faker.lorem.words(3), - list_id: 1, + project_id: 1, created_by_id: 1, created: now.toISOString(), updated: now.toISOString(), diff --git a/cypress/factories/link_sharing.ts b/cypress/factories/link_sharing.ts index 672d2fc145..465dcd240c 100644 --- a/cypress/factories/link_sharing.ts +++ b/cypress/factories/link_sharing.ts @@ -10,7 +10,7 @@ export class LinkShareFactory extends Factory { return { id: '{increment}', hash: faker.random.word(32), - list_id: 1, + project_id: 1, right: 0, sharing_type: 0, shared_by_id: 1, diff --git a/cypress/factories/list.ts b/cypress/factories/list.ts index aff7167c54..6de5d48fc4 100644 --- a/cypress/factories/list.ts +++ b/cypress/factories/list.ts @@ -1,8 +1,8 @@ import {Factory} from '../support/factory' import {faker} from '@faker-js/faker' -export class ListFactory extends Factory { - static table = 'lists' +export class ProjectFactory extends Factory { + static table = 'projects' static factory() { const now = new Date() diff --git a/cypress/factories/task.ts b/cypress/factories/task.ts index e7c5769ebe..bc97446a87 100644 --- a/cypress/factories/task.ts +++ b/cypress/factories/task.ts @@ -11,7 +11,7 @@ export class TaskFactory extends Factory { id: '{increment}', title: faker.lorem.words(3), done: false, - list_id: 1, + project_id: 1, created_by_id: 1, index: '{increment}', position: '{increment}', diff --git a/cypress/factories/users_list.ts b/cypress/factories/users_list.ts index 60b08be507..53eb0180eb 100644 --- a/cypress/factories/users_list.ts +++ b/cypress/factories/users_list.ts @@ -1,14 +1,14 @@ import {Factory} from '../support/factory' -export class UserListFactory extends Factory { - static table = 'users_lists' +export class UserProjectFactory extends Factory { + static table = 'users_projects' static factory() { const now = new Date() return { id: '{increment}', - list_id: 1, + project_id: 1, user_id: 1, right: 0, created: now.toISOString(), diff --git a/docs/models-services.md b/docs/models-services.md index e69af85cba..6b74866f9f 100644 --- a/docs/models-services.md +++ b/docs/models-services.md @@ -30,21 +30,21 @@ A basic service can look like this: ```javascript import AbstractService from './abstractService' -import ListModel from '../models/list' +import ProjectModel from '../models/project' -export default class ListService extends AbstractService { +export default class ProjectService extends AbstractService { constructor() { super({ - getAll: '/lists', - get: '/lists/{id}', - create: '/namespaces/{namespaceID}/lists', - update: '/lists/{id}', - delete: '/lists/{id}', + getAll: '/projects', + get: '/projects/{id}', + create: '/namespaces/{namespaceID}/projects', + update: '/projects/{id}', + delete: '/projects/{id}', }) } modelFactory(data) { - return new ListModel(data) + return new ProjectModel(data) } } ``` @@ -132,7 +132,7 @@ import AbstractModel from './abstractModel' import TaskModel from './task' import UserModel from './user' -export default class ListModel extends AbstractModel { +export default class ProjectModel extends AbstractModel { constructor(data) { // The constructor of AbstractModel handles all the default parsing. diff --git a/scripts/run.sh b/scripts/run.sh index 40c4bc1cf5..4b7cd91467 100755 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -18,8 +18,8 @@ sed -i "s/'\/api\/v1/'$VIKUNJA_API_URL/g" /usr/share/nginx/html/index.html sed -i "s/\.SENTRY_ENABLED = false/\.SENTRY_ENABLED = $VIKUNJA_SENTRY_ENABLED/g" /usr/share/nginx/html/index.html sed -i "s|\.SENTRY_DSN = '.*'|\.SENTRY_DSN = '$VIKUNJA_SENTRY_DSN'|g" /usr/share/nginx/html/index.html -sed -i "s/listen 80/listen $VIKUNJA_HTTP_PORT/g" /etc/nginx/nginx.conf -sed -i "s/listen 443/listen $VIKUNJA_HTTPS_PORT/g" /etc/nginx/nginx.conf +sed -i "s/projecten 80/projecten $VIKUNJA_HTTP_PORT/g" /etc/nginx/nginx.conf +sed -i "s/projecten 443/projecten $VIKUNJA_HTTPS_PORT/g" /etc/nginx/nginx.conf # Set the uid and gid of the nginx run user usermod --non-unique --uid ${PUID} nginx diff --git a/src/components/home/TheNavigation.vue b/src/components/home/TheNavigation.vue index 77d0b6e0eb..de77845269 100644 --- a/src/components/home/TheNavigation.vue +++ b/src/components/home/TheNavigation.vue @@ -8,19 +8,19 @@ -
-