diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 621b5b6e223..8c8c7f8ec62 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -10,8 +10,7 @@ title: Developer Guide ## **Acknowledgements** -- {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well} - +- This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org/). --- ## **Setting up, getting started** @@ -54,7 +53,7 @@ The bulk of the app's work is done by the following four components: **How the architecture components interact with each other** -The _Sequence Diagram_ below shows how the components interact with each other for the scenario where the user issues the command `delete 1`. +The _Sequence Diagram_ below shows how the components interact with each other for the scenario where the user issues the command `delete project Duke`. @@ -75,7 +74,7 @@ The **API** of this component is specified in [`Ui.java`](https://github.com/se- ![Structure of the UI Component](images/UiClassDiagram.png) -The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI. +The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `ProjectListPanel`, `StatusBarFooter`, `CurrentProjectPanel` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI. The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the [`MainWindow`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/resources/view/MainWindow.fxml) @@ -84,7 +83,7 @@ The `UI` component, - executes user commands using the `Logic` component. - listens for changes to `Model` data so that the UI can be updated with the modified data. - keeps a reference to the `Logic` component, because the `UI` relies on the `Logic` to execute commands. -- depends on some classes in the `Model` component, as it displays `Person` object residing in the `Model`. +- depends on some classes in the `Model` component, as it displays `Project` object residing in the `Model`. ### Logic component @@ -94,18 +93,18 @@ Here's a (partial) class diagram of the `Logic` component: -The sequence diagram below illustrates the interactions within the `Logic` component, taking `execute("delete 1")` API call as an example. +The sequence diagram below illustrates the interactions within the `Logic` component, taking `execute("delete project Duke")` API call as an example. -![Interactions Inside the Logic Component for the `delete project Duke` Command](images/DeleteSequenceDiagram.png) +![Interactions Inside the Logic Component for the `delete project Duke` Command](images/DeleteProjectSequenceDiagram.png) -
:information_source: **Note:** The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram. +
:information_source: **Note:** The lifeline for `DeleteProjectCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram.
How the `Logic` component works: -1. When `Logic` is called upon to execute a command, it is passed to an `AddressBookParser` object which in turn creates a parser that matches the command (e.g., `DeleteCommandParser`) and uses it to parse the command. -1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `DeleteCommand`) which is executed by the `LogicManager`. -1. The command can communicate with the `Model` when it is executed (e.g. to delete a person).
+1. When `Logic` is called upon to execute a command, it is passed to an `PlannerParser` object which in turn creates a parser that matches the command (e.g., `DeleteProjectCommandParser`) and uses it to parse the command. +1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `DeleteProjectCommand`) which is executed by the `LogicManager`. +1. The command can communicate with the `Model` when it is executed (e.g. to delete a project).
Note that although this is shown as a single step in the diagram above (for simplicity), in the code it can take several interactions (between the command object and the `Model`) to achieve. 1. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`. @@ -115,8 +114,8 @@ Here are the other classes in `Logic` (omitted from the class diagram above) tha How the parsing works: -- When called upon to parse a user command, the `AddressBookParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `AddressBookParser` returns back as a `Command` object. -- All `XYZCommandParser` classes (e.g., `AddCommandParser`, `DeleteCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing. +- When called upon to parse a user command, the `PlannerParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddProjectCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddProjectCommand`) which the `PlannerParser` returns back as a `Command` object. +- All `XYZCommandParser` classes (e.g., `AddProjectCommandParser`, `DeleteProjectCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing. ### Model component @@ -126,12 +125,12 @@ How the parsing works: The `Model` component, -- stores the address book data i.e., all `Person` objects (which are contained in a `UniquePersonList` object). -- stores the currently 'selected' `Person` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. +- stores the DevPlanPro data i.e., all `Project` objects (which are contained in a `ProjectList` object). +- stores the currently 'selected' `Project` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. - stores a `UserPref` object that represents the user’s preferences. This is exposed to the outside as a `ReadOnlyUserPref` objects. - does not depend on any of the other three components (as the `Model` represents data entities of the domain, they should make sense on their own without depending on other components) -
:information_source: **Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `AddressBook`, which `Person` references. This allows `AddressBook` to only require one `Tag` object per unique tag, instead of each `Person` needing their own `Tag` objects.
+
:information_source: **Note:** An alternative (arguably, a more OOP) model is given below.
@@ -145,8 +144,8 @@ The `Model` component, The `Storage` component, -- can save both address book data and user preference data in JSON format, and read them back into corresponding objects. -- inherits from both `AddressBookStorage` and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed). +- can save both DevPlanPro data and user preference data in JSON format, and read them back into corresponding objects. +- inherits from both `PlannerStorage` and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed). - depends on some classes in the `Model` component (because the `Storage` component's job is to save/retrieve objects that belong to the `Model`) ### Common classes @@ -163,7 +162,7 @@ This section describes some noteworthy details on how certain features are imple #### Implementation -1. The AddressBookParser parses the command string given by the user, and looks for the command word "add project". Then AddProjectCommandParser parse function is called. +1. The PlannerParser parses the command string given by the user, and looks for the command word "add project". Then AddProjectCommandParser parse function is called. 2. If the PROJECT_NAME is an empty string, an exception is thrown, else the addProjectCommand execution function is called. 3. The `AddProjectCommand` class is responsible for adding a project to the project list. - The constructor of the class takes in a project of type Project. @@ -203,126 +202,232 @@ This section describes some noteworthy details on how certain features are imple #### Implementation -1. The AddressBookParser parses the command string given by the user, and looks for the command word "delete project". Then DeleteProjectCommandParser parse function is called. +1. The PlannerParser parses the command string given by the user, and looks for the command word "delete project". Then DeleteProjectCommandParser parse function is called. 2. If the PROJECT_NAME is an empty string, an exception is thrown, else the deleteProjectCommand execution function is called. 3. The `DeleteProjectCommand` class is responsible for adding a project to the project list. - The constructor of the class takes in a project of type Project. - The project used to construct the command is a new project created using the argument string as the name - If the same project doesn't exist within the project list, then an exception is thrown - - The check is done by using `java.util.stream.Stream.anyMatch(Predicate predicate)` - - The predicate used is implemented at `seedu.address.model.person.Person.isSamePerson(Person otherProject)` which checks if the two projects are the same using their names + - The check is done by using `java.util.stream.Stream.anyMatch(Predicate predicate)` + - The predicate used is implemented at `seedu.address.model.project.Project.isSameProject(Project otherProject)` which checks if the two projects are the same using their names - As the projects in the list have unique name, we don't need to worry about returning the wrong project - Else the project is successfully deleted -![Interactions Inside the Logic Component for the `delete task ui /in Duke` Command](images/DeleteProjectSequenceDiagram.png) +![Interactions Inside the Logic Component for the `delete project Duke` Command](images/DeleteProjectSequenceDiagram.png) + +### Adding a task + +#### Implementation + +1. The PlannerParser parses the command string given by the user, and looks for the command word "delete task". Then AddTaskCommandParser parse function is called. +2. If the PROJECT_NAME or TASK_NAME is an empty string, an exception is thrown, else the AddTaskCommand execution function is called. +3. The `AddTaskCommand` class is responsible for adding a task within a project. + - The constructor of the class takes in a project of type Project and a task of type Task. + - If the project doesn't exist within the project list, then an exception is thrown. + - The check is done by using `java.util.stream.Stream.anyMatch(Predicate predicate)` + - The predicate used is implemented at `seedu.address.model.project.Project.isSameProject(Project otherProject)` which checks if the two projects are the same using their names. + - If the task already exist within the project, then an exception is thrown. + - The check is done by using `Project::hasTask` + - Else the task is successfully added. ### Deleting a task #### Implementation -1. The AddressBookParser parses the command string given by the user, and looks for the command word "delete task". Then DeleteTaskCommandParser parse function is called. +1. The PlannerParser parses the command string given by the user, and looks for the command word "delete task". Then DeleteTaskCommandParser parse function is called. 2. If the PROJECT_NAME or TASK_NAME is an empty string, an exception is thrown, else the deleteTaskCommand execution function is called. 3. The `DeleteTaskCommand` class is responsible for deleting a task within a project. - The constructor of the class takes in a project of type Project and a task of type Task. - If the project doesn't exist within the project list, then an exception is thrown - - The check is done by using `java.util.stream.Stream.anyMatch(Predicate predicate)` - - The predicate used is implemented at `seedu.address.model.person.Person.isSamePerson(Person otherProject)` which checks if the two projects are the same using their names + - The check is done by using `java.util.stream.Stream.anyMatch(Predicate predicate)` + - The predicate used is implemented at `seedu.address.model.project.Project.isSameProject(Project otherProject)` which checks if the two projects are the same using their names - If the task doesn't exist within the project, then an exception is thrown - - The check is done by using `Person::hasTask` + - The check is done by using `Project::hasTask` - Else the task is successfully deleted -![Interactions Inside the Logic Component for the `delete project Duke` Command](images/DeleteTaskSequenceDiagram.png) +![Interactions Inside the Logic Component for the `delete task ui /in Duke` Command](images/DeleteTaskSequenceDiagram.png) -### \[Proposed\] Undo/redo feature +### Setting deadline for both tasks and projects -#### Proposed Implementation +#### Implementation + +1. The PlannerParser parses the command string given by the user, and looks for the command word "set deadline". Then `SetDeadlineCommandParser` parse function is called. +2. The function checks if the command string includes '/in'. + 1. If it does, and if the PROJECT_NAME or TASK_NAME is an empty string, an exception is thrown. Else, the `SetTaskDeadlineCommand` execution function is called. + 2. If the string does not include '/in', and if the PROJECT_NAME is an empty string or if the project cannot be found, an exception is thrown. Else, the `SetProjectDeadlineCommand` execution function is called. +3. The `SetTaskDeadlineCommand` and `SetProjectDeadlineCommand` class is responsible for setting a deadline to the task or project. + - The constructor of the `SetTaskDeadlineCommand` class takes in a project of type Project and a task of type Task as well as a deadline of type String. + - The constructor of the `SetProjectDeadlineCommand` class takes in a project of type Project and a deadline of type String. + - If the project doesn't exist, then an exception is thrown. + - If the task doesn't exist within the project, then an exception is thrown. + - If the deadline is not a valid date or is in the wrong format, an exception is thrown as well. + - Else the deadline is successfully set. -The proposed undo/redo mechanism is facilitated by `VersionedAddressBook`. It extends `AddressBook` with an undo/redo history, stored internally as an `addressBookStateList` and `currentStatePointer`. Additionally, it implements the following operations: -- `VersionedAddressBook#commit()` — Saves the current address book state in its history. -- `VersionedAddressBook#undo()` — Restores the previous address book state from its history. -- `VersionedAddressBook#redo()` — Restores a previously undone address book state from its history. +### Setting category to a project + +#### Implementation -These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively. +1. The PlannerParser parses the command string given by the user, and looks for the command word "set category". Then `SetProjectCategoryCommandParser` parse function is called. +2. The function checks if the command string includes '/to'. If not, an exception is thrown to inform users on the correct command format. +3. If PROJECT_NAME or TASK_NAME is an empty string, an exception is thrown. +4. The `SetProjectCategoryCommand` class is responsible for setting a project category. + - The constructor of the `SetProjectCategoryCommand` class takes in a project of type Project and a category of type String. + - If the project doesn't exist, then an exception is thrown. + - Else the category is successfully set. -Given below is an example usage scenario and how the undo/redo mechanism behaves at each step. +![Interactions Inside the Logic Component for the `set category urgent /to Duke` Command](images/SetProjectCategorySequenceDiagram.png) -Step 1. The user launches the application for the first time. The `VersionedAddressBook` will be initialized with the initial address book state, and the `currentStatePointer` pointing to that single address book state. +### Setting status to a project and task -![UndoRedoState0](images/UndoRedoState0.png) +#### Implementation -Step 2. The user executes `delete 5` command to delete the 5th person in the address book. The `delete` command calls `Model#commitAddressBook()`, causing the modified state of the address book after the `delete 5` command executes to be saved in the `addressBookStateList`, and the `currentStatePointer` is shifted to the newly inserted address book state. +1. The PlannerParser parses the command string given by the user, and looks for the command word "set status". Then `SetStatusCommandParser` parse function is called. +2. The function checks if the command string includes '/in'. Additionally, if the status is not equals to either 'complete' or 'incomplete', an exception is thrown. + 1. If it does, and if the PROJECT_NAME or TASK_NAME is an empty string, an exception is thrown. Else, the `SetTaskStatusCommand` execution function is called. + 2. If the string does not include '/in', and if the PROJECT_NAME is an empty string or if the project cannot be found, an exception is thrown. Else, the `SetProjectstatusCommand` execution function is called. +3. The `SetTaskStatusCommand` and `SetProjectstatusCommand` class is responsible for setting a status to the task or project. + - The constructor of the `SetTaskStatusCommand` class takes in a project of type Project and a task of type Task as well as a status of type String. + - The constructor of the `SetProjectstatusCommand` class takes in a project of type Project and a status of type String. + - If the project doesn't exist, then an exception is thrown. + - If the task doesn't exist within the project, then an exception is thrown. + - Else the status is successfully set. -![UndoRedoState1](images/UndoRedoState1.png) +### Assigning a team to a project -Step 3. The user executes `add n/David …​` to add a new person. The `add` command also calls `Model#commitAddressBook()`, causing another modified address book state to be saved into the `addressBookStateList`. +#### Implementation -![UndoRedoState2](images/UndoRedoState2.png) +1. The PlannerParser parses the command string given by the user, and looks for the command word "assign team". Then AssignTeamCommandParser parse function is called. +2. If the PROJECT_NAME is an empty string or the user input 0 or invalid PERSON_NAME, an exception is thrown, else the AssignTeamCommand execution function is called. +3. The AssignTeamCommand class is responsible for assigning a team to a project. + - The constructor of the class takes in a project of type Project and a team which is a list of String. + - If the project doesn't exist within the project list, then an exception is thrown. + - Else the team is successfully assigned to the project. -
:information_source: **Note:** If a command fails its execution, it will not call `Model#commitAddressBook()`, so the address book state will not be saved into the `addressBookStateList`. +### Adding a member to a project -
+#### Implementation -Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing the `undo` command. The `undo` command will call `Model#undoAddressBook()`, which will shift the `currentStatePointer` once to the left, pointing it to the previous address book state, and restores the address book to that state. +1. The PlannerParser parses the command string given by the user, and looks for the command word "add person". Then AddPersonCommandParser parse function is called. +2. If the PROJECT_NAME or PERSON_NAME is an empty string or an invalid name, an exception is thrown, else the AddPersonCommand execution function is called. +3. The `AddPersonCommand` class is responsible for adding a member to a project. + - The constructor of the class takes in a project of type Project and a member of type Member. + - If the project doesn't exist within the project list, then an exception is thrown. + - Else the member is successfully added to the project. -![UndoRedoState3](images/UndoRedoState3.png) +### Assigning a member to a task -
:information_source: **Note:** If the `currentStatePointer` is at index 0, pointing to the initial AddressBook state, then there are no previous AddressBook states to restore. The `undo` command uses `Model#canUndoAddressBook()` to check if this is the case. If so, it will return an error to the user rather -than attempting to perform the undo. +#### Implementation -
+1. The PlannerParser parses the command string given by the user, and looks for the command word "assign person". Then AssignPersonCommandParser parse function is called. +2. If the PROJECT_NAME, TASK_NAME, or PERSON_NAME is an empty string or an invalid name, an exception is thrown, else the AssignPersonCommand execution function is called. +3. The `AssignPersonCommand` class is responsible for assigning a member to a task. + - The constructor of the class takes in a project of type Project and a member of type Member. + - If the project doesn't exist within the project list, then an exception is thrown. + - If the task doesn't exist within the project, then an exception is thrown. + - If the member isn't a member of the project, then an exception is thrown. + - Else the member is successfully assigned to the task. -The following sequence diagram shows how an undo operation goes through the `Logic` component: +### Removing a member from a project -![UndoSequenceDiagram](images/UndoSequenceDiagram-Logic.png) +#### Implementation +1. The PlannerParser parses the command string given by the user, and looks for the command word "delete person". Then DeletePersonCommandParser parse function is called. +2. If the PROJECT_NAME or PERSON_NAME is an empty string or an invalid name, an exception is thrown, else the DeletePersonCommand execution function is called. +3. The `DeletePersonCommand` class is responsible for removing a member from a project. + - The constructor of the class takes in a project of type Project and a member of type Member. + - If the project doesn't exist within the project list, then an exception is thrown. + - If the member isn't a member of the project, then an exception is thrown. + - Else the member is successfully removed from the project, and all the tasks the member is responsible for will have their member fields set as NULL. -
:information_source: **Note:** The lifeline for `UndoCommand` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram. +#### Design Considerations -
+Aspect of creating 2 different commands to add member to a project -Similarly, how an undo operation goes through the `Model` component is shown below: +- Alternative 1 Only use add person but allow multiple person to be added in one command. + - Pros: No additional commands to do the same action for one person or multiple people. Easier for user to get used to the command list. + - Cons: Since there is no clear person command, it is inconvenient when trying to reassign a smaller team to the project -![UndoSequenceDiagram](images/UndoSequenceDiagram-Model.png) +- Alternative 2 (current choice) Have an assign team command and an add person command. + - Pros: Convenient to reassign a smaller team to a project. Add person also makes more sense as we would always be adding one person instead of multiple persons(people?). + - Cons: An additional command that might be confusing to the users and can cause data loss (user trying to add multiple people to a project only to find the original members gone after the command). -The `redo` command does the opposite — it calls `Model#redoAddressBook()`, which shifts the `currentStatePointer` once to the right, pointing to the previously undone state, and restores the address book to that state. +Aspect of creating a command to unassign the task -
:information_source: **Note:** If the `currentStatePointer` is at index `addressBookStateList.size() - 1`, pointing to the latest address book state, then there are no undone AddressBook states to restore. The `redo` command uses `Model#canRedoAddressBook()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo. +- Alternative 1 Create a command unassign person to allow user to unassign a person from a task. + - Pros: More freedom to the user. More convenient to remove a person from one task. + - Cons: An additional command for the user to remember which might be prone to empty input bugs. User can also simply assign a task to a different person. -
+- Alternative 2 (current choice) Only have an assign person command that doesn't allow empty inputs. + - Pros: Less prone to bugs involving empty inputs. Also one less command for the user to remember. User can also remove the member from the project before adding the member back to remove them from all tasks. + - Cons: Less freedom for the user and less convenient when trying to unassign everyone from one specific task. -Step 5. The user then decides to execute the command `list`. Commands that do not modify the address book, such as `list`, will usually not call `Model#commitAddressBook()`, `Model#undoAddressBook()` or `Model#redoAddressBook()`. Thus, the `addressBookStateList` remains unchanged. +### Renaming a project -![UndoRedoState4](images/UndoRedoState4.png) +#### Implementation + +1. The PlannerParser parses the command string given by the user, and looks for the command word "set name". Then RenameCommandParser parse function is called. +2. If the PROJECT_NAME is an empty string or the command is incomplete or wrong, an exception is thrown, else the addProjectCommand execution function is called. +3. The `EditProjectNameCommand` class is responsible for editing a project's name to the specified name. + - The constructor of the class takes in a project of type Project and the new name of type Name. + - If the target name is the same as the project that already exists within the project list, then an exception is thrown to alert users that the new name is a duplicate. + - Else the project's name is successfully updated. + +![Interactions Inside the Logic Component for the `renaming nn /of Duke` Command](images/EditProjectNameDiagram.png) + +#### Design considerations: + +**Aspect of command word** + +- **Alternative 1:** Command word is `rename` + + - Pros: More intuitive and straightforward than set name + - Cons: Users have to remember new prefix since we planned to use other features with set (category/status) prefix -Step 6. The user executes `clear`, which calls `Model#commitAddressBook()`. Since the `currentStatePointer` is not pointing at the end of the `addressBookStateList`, all address book states after the `currentStatePointer` will be purged. Reason: It no longer makes sense to redo the `add n/David …​` command. This is the behavior that most modern desktop applications follow. +- **Alternative 2 (current choice):** Command word is `set name`. + - Pros: align with other commands and less keywords to remember for users. + - Cons: More words to type for users. -![UndoRedoState5](images/UndoRedoState5.png) -The following activity diagram summarizes what happens when a user executes a new command: - +### Renaming a task + +#### Implementation + +1. The PlannerParser parses the command string given by the user, and looks for the command word "set name". Then RenameCommandParser parse function is called. +2. If the PROJECT_NAME or / and TASK_NAME is an empty string or the command is incomplete or wrong, an exception is thrown, else the addProjectCommand execution function is called. +3. The `EditTaskNameCommand` class is responsible for editing a task's name within the specified project to the specified name. + - The constructor of the class takes in a project of type Project,target task of type Task, and the new name of type Name. + - If the target name is the same as the any tasks in project that already exists within the project, then an exception is thrown to alert users that the new name is a duplicate. + - Else the task's name is successfully updated. + #### Design considerations: -**Aspect: How undo & redo executes:** +**Aspect of command word** -- **Alternative 1 (current choice):** Saves the entire address book. +- **Alternative 1:** Command word is `rename` - - Pros: Easy to implement. - - Cons: May have performance issues in terms of memory usage. + - Pros: More intuitive and straightforward than set name + - Cons: Users have to remember new prefix since we planned to use other features with set (category/status) prefix -- **Alternative 2:** Individual command knows how to undo/redo by - itself. - - Pros: Will use less memory (e.g. for `delete`, just save the person being deleted). - - Cons: We must ensure that the implementation of each individual command are correct. +- **Alternative 2 (current choice):** Command word is `set name`. + - Pros: align with other commands and less keywords to remember for users. + - Cons: More words to type for users. -_{more aspects and alternatives to be added}_ -### \[Proposed\] Data archiving -_{Explain here how the data archiving feature will be implemented}_ +### Adding a Comment ---- +#### Implementation + +1. The PlannerParser parses the command string given by the user, and looks for the command word "add comment". Then AddCommentCommandParser parse function is called. +2. If the PROJECT_NAME or / and the member is not added to the team, an error will be thrown to reflect the error. +3. The `AddCommentCommand` class is responsible for adding specific comment by specific team member to the project. + - The constructor of the class takes in a project of type Project, commentator of type Member, and comment of type String. + - If the target name is the same as the project that already exists within the project list, then an exception is thrown to alert users that the target name is a duplicate. + - Else the project's name is successfully updated. + +![Interactions Inside the Logic Component for the `add comment c1 /from p2 /to Duke` Command](images/AddCommentDiagram.png) ## **Documentation, logging, testing, configuration, dev-ops** @@ -353,7 +458,7 @@ _{Explain here how the data archiving feature will be implemented}_ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*` | Priority | As a …​ | I want to …​ | So that I can…​ | -| -------- | -------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- | +|----------|----------------------|--------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------| | `* * *` | software developer | keep track of all my projects’ tasks in the app | meet all my deadlines on time | | `* *` | user | sort my tasks by their deadlines | see what is the next pending task to complete | | `* *` | user | see what my tasks are due next week | schedule my timetable accordingly | @@ -721,49 +826,199 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli Given below are instructions to test the app manually. -
:information_source: **Note:** These instructions only provide a starting point for testers to work on; +**Note:** These instructions only provide a starting point for testers to work on; testers are expected to do more *exploratory* testing. -
-### Launch and shutdown +### Launch + 1. Initial launch + 1.1 Download the jar file and copy into an empty folder + 1.2 Double-click the jar file Expected: Shows the GUI with a set of sample projects. + + 2. Non-Initial launch: + 2.1 Double-click the jar file Expected: Shows the GUI with last session files saved. + +### Add project + To get started lets add some projects for testing: + add project CS2101 Presentation + add project IS1128 project + add project Duke chatbot + add project CS2103T Ab3 + add project Coding Project + + Test case: add project A + Expected: Successful result shown. Ui is updated with project A at the bottom of the list. + + Test case: add project + Expected: Error result. Project cannot be empty. + +### Show project + Test case: show project Coding Project + Expected: Successful result shown in the command result box. Details about Coding Project being shown + + Test case: show project CODING PROJECT + Expected: Error result. Project name is case sensitive. + +### Find project and list project + Test case: find project Duke + Expected result: Duke chatbot shown. Use list project to reset the filter + + Test case: find project C + Expected result: Nothing shown. Only projects with C AS A WORD, not a character, are shown. + + Test case: find project Project C + Expected result: IS2218 project and Coding Project is shown. Find project is case insensitive. Projects that contain Project or C or Project and C as a word (case insensitive) will be shown. + +### Add task + Test case: add task dummy to CS2103T Ab3 + Expected: Error result. Users need to use /to to indicate that users are adding something to the project name after /to + + Test case: add task /to CS2103T Ab3 + Expected: Error result. User need to include the name of the task. + + Test case: add task dummy /to CS2103T Ab3 + Expected: Successful result. Using the show project command (how project CS2103T Ab3) will show a task called dummy under the Not Done Section. + + Given that users already added “dummy” task into CS2103T Ab3, users could try: + + Test case: add task dummy /to CS2103T Ab3 + Expected: Error result. Duplicate task within a project is not allowed. + + Test case: add task Dummy /to CS2103T Ab3 + Expected: Successful result command shown. Using the show project command (how project CS2103T Ab3) will show 2 tasks called dummy and Dummy under the Not Done Section since the task name is also case sensitive. + +### Deleting a project + Test case: delete project Duke chatbot + Expected: Duke chatbot project deleted. Numbers in front of the other tasks are reordered. + + Test case: delete project CS2103T AB3 + Expected: Error result. No project was deleted since the project name is case sensitive. + +### Deleting a task in a project + Starting with add task A /to IS1128 project, users could try the following test case: + + Test case: delete task A in IS1128 project + Expected: Error shown since users are required to include / in front of “to” ("/to") to indicate that users are referring to existing project / task name. + + Test case: delete task A /in IS1128 project + Expected: Successful command. With show project command of IS1128 project, the task A should not be present. + +### Add person to a project + Test case: add person A /to CS2103T Ab3 + Expected: Successful result. Showing project CS2103T Ab3, would show A under team member section. + + Adding another person with same name + Test case: add person A /to CS2103T Ab3 + Expected: Successful result. Showing project CS2103T Ab3, would show 2 persons with name A under team member section. + +### Assign a person in current team to a project + Assuming add person A /to CS2103T Ab3 was used and no member were added to CS2103T Ab3, users could try: + Test case: assign person A /to /in CS2103T Ab3 + Expected: Successful result. Showing project CS2103T Ab3, would show A under team member below the task Name. + + Test case: assign person B /to /in CS2103T Ab3 + Expected: Error result. The person must be added to the project first before assigning to a task. + + Test case: assign person A /to /in CS2103T Ab3 + Expected: Error result. The task must exist in the project. + +### Delete person from a project + Assuming users already added 2 member of the same name “A” into CS2103T Ab3, + + Test case: delete person A /in CS2103T Ab3 + Expected: Successful result. The first (leftmost) A in the list is deleted. + +### Setting a status of a task in a project + Test case: set status incomplete /of /in + Expected: Successful result. Showing the corresponding project, ui would show the task under Not Done Section if the task is marked as completed or else nothing changes. + + Test case: set status complete /of /in + Expected: Successful result. Showing the corresponding project, ui would show the task under Done Section if it was not marked as completed before else nothing changes. + +### Setting a status of a project + Test case: set status complete /of + Expected: Successful result. Showing the completed tag besides the project name. + + Test case: set status incomplete /of + Expected: Successful result. Showing nothing if the task is not completed else delete the completed tag + +### Setting a project category + Test case: set category f /to + Expected: Successful result. Showing f tag beside the project name overriding the old tag if any. + +### Filter category + Test case: filter category + Expected: Successful result. Showing project with EXACT tag name. + Use list project to reset the filter and show all the project + +### Add comment + Assuming a is the only team member of project Coding Project + + Test case: add comment dummy /from a /to Coding Project + Expected: Successful result. Showing project, comment section will be added with name and the comment content (dummy). + + Test case: add comment dummy /from b /to Coding project + Expected: Error result. Showing project, nothing shown on comment part. The commentator must be a member of the project. -1. Initial launch +### Set deadline of a project + Test case: set deadline Apr 01 2030 /to IS1128 project + Expected: Successful result. Ui updates the due date under the IS1128 project to Apr 01 2030. - 1. Download the jar file and copy into an empty folder + Test case: set deadline Apr 1 2030 /to IS1128 project + Expected: Successful result. Ui updates the due date under the IS1128 project to Apr 1 2030. - 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum. + Test case: set deadline Apr012030 /to IS1128 project + Expected: Error result. The Date must be in the MMM dd YYYY or MMM d YYYY (for single digit day date) format separated by spaces. -1. Saving window preferences +### Set deadline of a task + Assuming a is the one of the tasks in IS1128 project, - 1. Resize the window to an optimum size. Move the window to a different location. Close the window. + Test case: set deadline Apr 01 2030 /of a /in IS1128 project + Expected: Successful result. Showing the project, Ui updates the due date under the task a to Apr 01 2030 overriding the prior date if any. - 1. Re-launch the app by double-clicking the jar file.
- Expected: The most recent window size and location is retained. +### Setting name of a task + Assuming IS1128 project have only three tasks called: dummy, Dummy, dummy3, -1. _{ more test cases …​ }_ + Test case: set name dummy2 /of dummy /in IS1128 project + Expected: Successful result. Showing the project, Ui updates the name of dummy to dummy2 while Dummy still stays the same. -### Deleting a person + Test case: set name dummy3 /of Dummy /in IS1128 project + Expected: Error result. The new name dummy3 already exists. -1. Deleting a person while all persons are being shown +### Setting name of a project + Assuming IS1128 project and Coding Project coexist - 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list. + Test case: set name Coding project /of IS1128 project + Expected: Successful result. Ui updates the name of IS1128 project to Coding Project (Project name is case sensitive) - 1. Test case: `delete 1`
- Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated. + Test case: set name Coding Project /of IS1128 project + Expected: Error result. The new name Coding project is a duplicate of the existing project name. - 1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same. +## Appendix: Effort - 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
- Expected: Similar to previous. +Since this project is brownfield, we streamlined our efforts by leveraging the AB3 Design as a reference point, incorporating additional classes or structures where needed. For instance, we expanded functionalities within AB3’s Person class to align with our Project Class requirements. Referring to AB3's original structure provided a clear framework for any new features. When adding a new feature, we found that the core components required were often new Command and CommandParser classes, whose internal flow we could refer to AB3's. Without this reference, we would have grappled with structuring and possibly switching between different designs, causing delays if our initial plans fell short. -1. _{ more test cases …​ }_ +The most challenging part would be the user interface (UI). Understanding the linkage between front-end and back-end, as laid out in AB3's source code, demanded significant time and effort. Particularly when introducing new interfaces for additional functionalities beyond AB3's scope, we encountered several bugs. While the back-end functionality usually functioned as expected, the UI occasionally failed to display or behaved unexpectedly. +Certain instances of UI-related problems we faced: +Our attempt to integrate a feature allowing users to add multiple category tags to a task led to UI malfunctions, causing the app to display a black screen. Thus, we discussed and designed to only allow one tag per task and spent our time and effort more on developing new features. +Efforts to include the changing of project names or categories didn't update immediately in the UI. +Addressing a reported bug related to truncated display of team members' information and comment boxes (as highlighted by the PED) involved experimenting with different UI structures, such as choosing between Vbox and Hbox, or deciding on the placement of scroll panes whether within the box or placing the box within the pane. Once the structure was finalized, we encountered issues with scroll pane visibility due to background color, prompting research into CSS syntax for achieving a transparent scroll pane that behaved as expected. -### Saving data +Ultimately, through collective team and individual efforts involving extensive learning, research, flexibility, and comprehension of underlying systems, we overcome these challenges. We are eventually able to come up with a design that closely mirrors our initial plans, both in functionality and interactivity. -1. Dealing with missing/corrupted data files +## **Appendix: Planned Enhancements** +Team size: 4 - 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_ +1. **Allow more than 1 category to be set for each project**:Currently, + only 1 category can be set to each project. However, this is not ideal + as projects can be categorised in many ways + such as scope and urgency, or type or purpose etc. +2. **Prevent duplicate names from added to each project**: Currently, + we allow duplicate names to be added to each project, but this is not + ideal because when the user assign 1 of the duplicate name to do a task, + there will be confusion on which team member is being referred to. We plan + to have an error message when the user assigns a duplicate name to a project. +3. **Allow more than 1 person to be assigned to each task**: Currently, + only 1 person can be responsible for each task, but this is not ideal + because some tasks may require collaboration between members. -1. _{ more test cases …​ }_ diff --git a/docs/diagrams/AddCommentDiagram.puml b/docs/diagrams/AddCommentDiagram.puml new file mode 100644 index 00000000000..c1d8a618879 --- /dev/null +++ b/docs/diagrams/AddCommentDiagram.puml @@ -0,0 +1,84 @@ +@startuml +!include style.puml +skinparam ArrowFontStyle plain + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":PlannerParser" as PlannerParser LOGIC_COLOR +participant ":AddCommentCommandParser" as AddCommentCommandParser LOGIC_COLOR +participant "d:AddCommentCommand" as AddCommentCommand LOGIC_COLOR +participant "r:CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant "m:Model" as Model MODEL_COLOR +participant "Duke:Project" as Project1 MODEL_COLOR + +end box + +[-> LogicManager : execute("add comment c1 /from p2 /to Duke") +activate LogicManager + +LogicManager -> PlannerParser : parseCommand("add comment c1 /from pa /to a") +activate PlannerParser + +create AddCommentCommandParser +PlannerParser -> AddCommentCommandParser +activate AddCommentCommandParser + +AddCommentCommandParser --> PlannerParser +deactivate AddCommentCommandParser + +PlannerParser -> AddCommentCommandParser : parse("c1 /from p2 /to Duke") +activate AddCommentCommandParser + +create AddCommentCommand +AddCommentCommandParser -> AddCommentCommand +activate AddCommentCommand + +AddCommentCommand --> AddCommentCommandParser : +deactivate AddCommentCommand + +AddCommentCommandParser --> PlannerParser : d +deactivate AddCommentCommandParser +'Hidden arrow to position the destroy marker below the end of the activation bar. +AddCommentCommandParser -[hidden]-> PlannerParser +destroy AddCommentCommandParser + +PlannerParser --> LogicManager : d +deactivate PlannerParser + +LogicManager -> AddCommentCommand : execute(m) +activate AddCommentCommand + +AddCommentCommand -> Model : findProject(Duke) +activate Model + +Model --> AddCommentCommand: Duke +deactivate Model + +AddCommentCommand -> Project1: addComment(c1) + +activate Project1 + + +Project1 --> AddCommentCommand: +deactivate Project1 + + + +create CommandResult +AddCommentCommand -> CommandResult +activate CommandResult + +CommandResult --> AddCommentCommand +deactivate CommandResult + + + +AddCommentCommand --> LogicManager : r +deactivate AddCommentCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/AddProjectSequenceDiagram.puml b/docs/diagrams/AddProjectSequenceDiagram.puml index dae3e5230be..44c124fe0a2 100644 --- a/docs/diagrams/AddProjectSequenceDiagram.puml +++ b/docs/diagrams/AddProjectSequenceDiagram.puml @@ -4,7 +4,7 @@ skinparam ArrowFontStyle plain box Logic LOGIC_COLOR_T1 participant ":LogicManager" as LogicManager LOGIC_COLOR -participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":PlannerParser" as PlannerParser LOGIC_COLOR participant ":AddProjectCommandParser" as AddProjectCommandParser LOGIC_COLOR participant "d:AddProjectCommand" as AddProjectCommand LOGIC_COLOR participant "r:CommandResult" as CommandResult LOGIC_COLOR @@ -17,17 +17,17 @@ end box [-> LogicManager : execute("add project Duke") activate LogicManager -LogicManager -> AddressBookParser : parseCommand("add project Duke") -activate AddressBookParser +LogicManager -> PlannerParser : parseCommand("add project Duke") +activate PlannerParser create AddProjectCommandParser -AddressBookParser -> AddProjectCommandParser +PlannerParser -> AddProjectCommandParser activate AddProjectCommandParser -AddProjectCommandParser --> AddressBookParser +AddProjectCommandParser --> PlannerParser deactivate AddProjectCommandParser -AddressBookParser -> AddProjectCommandParser : parse("Duke") +PlannerParser -> AddProjectCommandParser : parse("Duke") activate AddProjectCommandParser create AddProjectCommand @@ -37,14 +37,14 @@ activate AddProjectCommand AddProjectCommand --> AddProjectCommandParser : deactivate AddProjectCommand -AddProjectCommandParser --> AddressBookParser : d +AddProjectCommandParser --> PlannerParser : d deactivate AddProjectCommandParser 'Hidden arrow to position the destroy marker below the end of the activation bar. -AddProjectCommandParser -[hidden]-> AddressBookParser +AddProjectCommandParser -[hidden]-> PlannerParser destroy AddProjectCommandParser -AddressBookParser --> LogicManager : d -deactivate AddressBookParser +PlannerParser --> LogicManager : d +deactivate PlannerParser LogicManager -> AddProjectCommand : execute(m) activate AddProjectCommand diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml index 48b6cc4333c..c60988ccb78 100644 --- a/docs/diagrams/ArchitectureSequenceDiagram.puml +++ b/docs/diagrams/ArchitectureSequenceDiagram.puml @@ -8,19 +8,19 @@ Participant ":Logic" as logic LOGIC_COLOR Participant ":Model" as model MODEL_COLOR Participant ":Storage" as storage STORAGE_COLOR -user -[USER_COLOR]> ui : "delete 1" +user -[USER_COLOR]> ui : "delete project Duke" activate ui UI_COLOR -ui -[UI_COLOR]> logic : execute("delete 1") +ui -[UI_COLOR]> logic : execute("delete project Duke") activate logic LOGIC_COLOR -logic -[LOGIC_COLOR]> model : deletePerson(p) +logic -[LOGIC_COLOR]> model : deleteProject("Duke") activate model MODEL_COLOR model -[MODEL_COLOR]-> logic deactivate model -logic -[LOGIC_COLOR]> storage : saveAddressBook(addressBook) +logic -[LOGIC_COLOR]> storage : savePlanner(planner) activate storage STORAGE_COLOR storage -[STORAGE_COLOR]> storage : Save to file diff --git a/docs/diagrams/BetterModelClassDiagram.puml b/docs/diagrams/BetterModelClassDiagram.puml index 598474a5c82..f17602b3327 100644 --- a/docs/diagrams/BetterModelClassDiagram.puml +++ b/docs/diagrams/BetterModelClassDiagram.puml @@ -4,18 +4,16 @@ skinparam arrowThickness 1.1 skinparam arrowColor MODEL_COLOR skinparam classBackgroundColor MODEL_COLOR -AddressBook *-right-> "1" UniquePersonList -AddressBook *-right-> "1" UniqueTagList -UniqueTagList -[hidden]down- UniquePersonList -UniqueTagList -[hidden]down- UniquePersonList +Planner *-right-> "1" ProjectList -UniqueTagList -right-> "*" Tag -UniquePersonList -right-> Person +ProjectList -right-> Project -Person -up-> "*" Tag +Project *--> Name +Project *--> Comment +Project *--> Member +Member *--> Name +Task *--> Name +Task *--> Member +Project *--> Task -Person *--> Name -Person *--> Phone -Person *--> Email -Person *--> Address @enduml diff --git a/docs/diagrams/DeleteProjectSequenceDiagram.puml b/docs/diagrams/DeleteProjectSequenceDiagram.puml index 2450813ce60..7760de2541a 100644 --- a/docs/diagrams/DeleteProjectSequenceDiagram.puml +++ b/docs/diagrams/DeleteProjectSequenceDiagram.puml @@ -4,7 +4,7 @@ skinparam ArrowFontStyle plain box Logic LOGIC_COLOR_T1 participant ":LogicManager" as LogicManager LOGIC_COLOR -participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":PlannerParser" as PlannerParser LOGIC_COLOR participant ":DeleteProjectCommandParser" as DeleteProjectCommandParser LOGIC_COLOR participant "d:DeleteProjectCommand" as DeleteProjectCommand LOGIC_COLOR participant "r:CommandResult" as CommandResult LOGIC_COLOR @@ -17,17 +17,17 @@ end box [-> LogicManager : execute("delete project Duke") activate LogicManager -LogicManager -> AddressBookParser : parseCommand("delete project Duke") -activate AddressBookParser +LogicManager -> PlannerParser : parseCommand("delete project Duke") +activate PlannerParser create DeleteProjectCommandParser -AddressBookParser -> DeleteProjectCommandParser +PlannerParser -> DeleteProjectCommandParser activate DeleteProjectCommandParser -DeleteProjectCommandParser --> AddressBookParser +DeleteProjectCommandParser --> PlannerParser deactivate DeleteProjectCommandParser -AddressBookParser -> DeleteProjectCommandParser : parse("Duke") +PlannerParser -> DeleteProjectCommandParser : parse("Duke") activate DeleteProjectCommandParser create DeleteProjectCommand @@ -37,18 +37,24 @@ activate DeleteProjectCommand DeleteProjectCommand --> DeleteProjectCommandParser : deactivate DeleteProjectCommand -DeleteProjectCommandParser --> AddressBookParser : d +DeleteProjectCommandParser --> PlannerParser : d deactivate DeleteProjectCommandParser 'Hidden arrow to position the destroy marker below the end of the activation bar. -DeleteProjectCommandParser -[hidden]-> AddressBookParser +DeleteProjectCommandParser -[hidden]-> PlannerParser destroy DeleteProjectCommandParser -AddressBookParser --> LogicManager : d -deactivate AddressBookParser +PlannerParser --> LogicManager : d +deactivate PlannerParser LogicManager -> DeleteProjectCommand : execute(m) activate DeleteProjectCommand +DeleteProjectCommand -> Model : findProject(Duke) +activate Model + +Model --> DeleteProjectCommand +deactivate Model + DeleteProjectCommand -> Model : deleteProject(Duke) activate Model diff --git a/docs/diagrams/DeleteTaskSequenceDiagram.puml b/docs/diagrams/DeleteTaskSequenceDiagram.puml index 61b77d11563..d6a171d02c7 100644 --- a/docs/diagrams/DeleteTaskSequenceDiagram.puml +++ b/docs/diagrams/DeleteTaskSequenceDiagram.puml @@ -4,31 +4,31 @@ skinparam ArrowFontStyle plain box Logic LOGIC_COLOR_T1 participant ":LogicManager" as LogicManager LOGIC_COLOR -participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant ":PlannerParser" as PlannerParser LOGIC_COLOR participant ":DeleteTaskCommandParser" as DeleteTaskCommandParser LOGIC_COLOR participant "d:DeleteTaskCommand" as DeleteTaskCommand LOGIC_COLOR participant "r:CommandResult" as CommandResult LOGIC_COLOR -participant "p:Person" as Person LOGIC_COLOR end box box Model MODEL_COLOR_T1 +participant ":Project" as Project MODEL_COLOR participant "m:Model" as Model MODEL_COLOR end box -[-> LogicManager : execute("delete task ui /in project Duke") +[-> LogicManager : execute("delete task ui /in Duke") activate LogicManager -LogicManager -> AddressBookParser : parseCommand("delete task ui /in project Duke") -activate AddressBookParser +LogicManager -> PlannerParser : parseCommand("delete task ui /in Duke") +activate PlannerParser create DeleteTaskCommandParser -AddressBookParser -> DeleteTaskCommandParser +PlannerParser -> DeleteTaskCommandParser activate DeleteTaskCommandParser -DeleteTaskCommandParser --> AddressBookParser +DeleteTaskCommandParser --> PlannerParser deactivate DeleteTaskCommandParser -AddressBookParser -> DeleteTaskCommandParser : parse("ui /in Duke") +PlannerParser -> DeleteTaskCommandParser : parse("ui /in Duke") activate DeleteTaskCommandParser create DeleteTaskCommand @@ -38,14 +38,14 @@ activate DeleteTaskCommand DeleteTaskCommand --> DeleteTaskCommandParser : deactivate DeleteTaskCommand -DeleteTaskCommandParser --> AddressBookParser : d +DeleteTaskCommandParser --> PlannerParser : d deactivate DeleteTaskCommandParser 'Hidden arrow to position the destroy marker below the end of the activation bar. -DeleteTaskCommandParser -[hidden]-> AddressBookParser +DeleteTaskCommandParser -[hidden]-> PlannerParser destroy DeleteTaskCommandParser -AddressBookParser --> LogicManager : d -deactivate AddressBookParser +PlannerParser --> LogicManager : d +deactivate PlannerParser LogicManager -> DeleteTaskCommand : execute(m) activate DeleteTaskCommand @@ -56,10 +56,10 @@ activate Model Model --> DeleteTaskCommand: p deactivate Model -DeleteTaskCommand -> Person : removeTask(ui) -activate Person -Person --> DeleteTaskCommand -deactivate Person +DeleteTaskCommand -> Project : removeTask(ui) +activate Project +Project --> DeleteTaskCommand +deactivate Project create CommandResult DeleteTaskCommand -> CommandResult diff --git a/docs/diagrams/EditProjectNameDiagram.puml b/docs/diagrams/EditProjectNameDiagram.puml new file mode 100644 index 00000000000..305c6260c57 --- /dev/null +++ b/docs/diagrams/EditProjectNameDiagram.puml @@ -0,0 +1,94 @@ +@startuml +!include style.puml +skinparam ArrowFontStyle plain + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":PlannerParser" as PlannerParser LOGIC_COLOR +participant ":RenameCommandParser" as RenameCommandParser LOGIC_COLOR +participant "d:EditProjectNameCommand" as EditProjectNameCommand LOGIC_COLOR +participant "r:CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant "m:Model" as Model MODEL_COLOR +participant "Duke:Project" as Project1 MODEL_COLOR +participant "p2:Project" as Project2 MODEL_COLOR +end box + +[-> LogicManager : execute("set name nn /of Duke") +activate LogicManager + +LogicManager -> PlannerParser : parseCommand("set name nn /of Duke") +activate PlannerParser + +create RenameCommandParser +PlannerParser -> RenameCommandParser +activate RenameCommandParser + +RenameCommandParser --> PlannerParser +deactivate RenameCommandParser + +PlannerParser -> RenameCommandParser : parse("nn /of Duke") +activate RenameCommandParser + +create EditProjectNameCommand +RenameCommandParser -> EditProjectNameCommand +activate EditProjectNameCommand + +EditProjectNameCommand --> RenameCommandParser : +deactivate EditProjectNameCommand + +RenameCommandParser --> PlannerParser : d +deactivate RenameCommandParser +'Hidden arrow to position the destroy marker below the end of the activation bar. +RenameCommandParser -[hidden]-> PlannerParser +destroy RenameCommandParser + +PlannerParser --> LogicManager : d +deactivate PlannerParser + +LogicManager -> EditProjectNameCommand : execute(m) +activate EditProjectNameCommand + +EditProjectNameCommand -> Model : findProject(Duke) +activate Model + +Model --> EditProjectNameCommand: Duke +deactivate Model + +EditProjectNameCommand -> Project1: createEditedProject(nn) + +activate Project1 +create Project2 +Project1 -> Project2 +activate Project2 + + +Project2 --> Project1: +Project1 --> EditProjectNameCommand: +deactivate Project1 + +deactivate Project2 + + +EditProjectNameCommand -> Model : setProject(Duke,p2) +activate Model +Model --> EditProjectNameCommand +deactivate Model + +create CommandResult +EditProjectNameCommand -> CommandResult +activate CommandResult + +CommandResult --> EditProjectNameCommand +deactivate CommandResult + + + +EditProjectNameCommand --> LogicManager : r +deactivate EditProjectNameCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/LogicClassDiagram.puml b/docs/diagrams/LogicClassDiagram.puml index 58b4f602ce6..ff583780e04 100644 --- a/docs/diagrams/LogicClassDiagram.puml +++ b/docs/diagrams/LogicClassDiagram.puml @@ -39,7 +39,7 @@ LogicManager --> Storage Storage --[hidden] Model Command .[hidden]up.> Storage Command .right.> Model -note right of XYZCommand: XYZCommand = AddCommand, \nFindCommand, etc +note right of XYZCommand: XYZCommand = AddProjectCommand, \nFindProjectCommand, etc Logic ..> CommandResult LogicManager .down.> CommandResult diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml index 55307d85bef..70d840ecae9 100644 --- a/docs/diagrams/ModelClassDiagram.puml +++ b/docs/diagrams/ModelClassDiagram.puml @@ -5,18 +5,19 @@ skinparam arrowColor MODEL_COLOR skinparam classBackgroundColor MODEL_COLOR Package Model as ModelPackage <>{ -Class "<>\nReadOnlyAddressBook" as ReadOnlyAddressBook +Class "<>\nReadOnlyPlanner" as ReadOnlyPlanner Class "<>\nReadOnlyUserPrefs" as ReadOnlyUserPrefs Class "<>\nModel" as Model -Class AddressBook +Class Planner Class ModelManager Class UserPrefs -Class UniquePersonList -Class Person +Class ProjectList +Class Project Class Task Class Member Class Name +Class Comment Class I #FFFFFF } @@ -24,29 +25,30 @@ Class I #FFFFFF Class HiddenOutside #FFFFFF HiddenOutside ..> Model -AddressBook .up.|> ReadOnlyAddressBook +Planner .up.|> ReadOnlyPlanner ModelManager .up.|> Model Model .right.> ReadOnlyUserPrefs -Model .left.> ReadOnlyAddressBook -ModelManager -left-> "1" AddressBook +Model .left.> ReadOnlyPlanner +ModelManager -left-> "1" Planner ModelManager -right-> "1" UserPrefs UserPrefs .up.|> ReadOnlyUserPrefs -AddressBook *--> "1" UniquePersonList -UniquePersonList --> Person : "~* all" -Person *--> "~*" Member -Person *--> Name -Person *--> "~*" Task +Planner *--> "1" ProjectList +ProjectList --> Project : "~* all" +Project *--> "~*" Member +Project *--> Name +Project *--> "~*" Task +Project *--> "~*" Comment Task --> Member Task --> Name -Person -[hidden]up--> I -UniquePersonList -[hidden]right-> I +Project -[hidden]up--> I +ProjectList -[hidden]right-> I Member -[hidden]right-> Name Name -[hidden]right-> Task Member --> Name -ModelManager --> Person : filtered +ModelManager --> Project : filtered @enduml diff --git a/docs/diagrams/ParserClasses.puml b/docs/diagrams/ParserClasses.puml index ce4c5ce8c8d..db53107320f 100644 --- a/docs/diagrams/ParserClasses.puml +++ b/docs/diagrams/ParserClasses.puml @@ -9,7 +9,7 @@ Class XYZCommand package "Parser classes"{ Class "<>\nParser" as Parser -Class AddressBookParser +Class PlannerParser Class XYZCommandParser Class CliSyntax Class ParserUtil @@ -19,12 +19,12 @@ Class Prefix } Class HiddenOutside #FFFFFF -HiddenOutside ..> AddressBookParser +HiddenOutside ..> PlannerParser -AddressBookParser .down.> XYZCommandParser: <> +PlannerParser .down.> XYZCommandParser: <> XYZCommandParser ..> XYZCommand : <> -AddressBookParser ..> Command : <> +PlannerParser ..> Command : <> XYZCommandParser .up.|> Parser XYZCommandParser ..> ArgumentMultimap XYZCommandParser ..> ArgumentTokenizer diff --git a/docs/diagrams/SetProjectCategorySequenceDiagram.puml b/docs/diagrams/SetProjectCategorySequenceDiagram.puml new file mode 100644 index 00000000000..b4fbe57caa4 --- /dev/null +++ b/docs/diagrams/SetProjectCategorySequenceDiagram.puml @@ -0,0 +1,83 @@ +@startuml +!include style.puml +skinparam ArrowFontStyle plain + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":PlannerParser" as PlannerParser LOGIC_COLOR +participant ":SetProjectCategoryCommandParser" as SetProjectCategoryCommandParser LOGIC_COLOR +participant "d:SetProjectCategoryCommand" as SetProjectCategoryCommand LOGIC_COLOR +participant "r:CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Project" as Project MODEL_COLOR +participant "m:Model" as Model MODEL_COLOR +end box + +[-> LogicManager : execute("set category urgent /to Duke") +activate LogicManager + +LogicManager -> PlannerParser : parseCommand("set category urgent /to Duke") +activate PlannerParser + +create SetProjectCategoryCommandParser +PlannerParser -> SetProjectCategoryCommandParser +activate SetProjectCategoryCommandParser + +SetProjectCategoryCommandParser --> PlannerParser +deactivate SetProjectCategoryCommandParser + +PlannerParser -> SetProjectCategoryCommandParser : parse("urgent /to Duke") +activate SetProjectCategoryCommandParser + +create SetProjectCategoryCommand +SetProjectCategoryCommandParser -> SetProjectCategoryCommand +activate SetProjectCategoryCommand + +SetProjectCategoryCommand --> SetProjectCategoryCommandParser : +deactivate SetProjectCategoryCommand + +SetProjectCategoryCommandParser --> PlannerParser : d +deactivate SetProjectCategoryCommandParser +'Hidden arrow to position the destroy marker below the end of the activation bar. +SetProjectCategoryCommandParser -[hidden]-> PlannerParser +destroy SetProjectCategoryCommandParser + +PlannerParser --> LogicManager : d +deactivate PlannerParser + +LogicManager -> SetProjectCategoryCommand : execute(m) +activate SetProjectCategoryCommand + +SetProjectCategoryCommand -> Model : findProject("Duke") +activate Model + +Model --> SetProjectCategoryCommand : oldDuke +deactivate Model + +SetProjectCategoryCommand -> Project : createEditedProject() +activate Project + +Project -> SetProjectCategoryCommand : newDukeWithCategory +deactivate Project + +SetProjectCategoryCommand -> Model : setProject(oldDuke, newDukeWithCategory) +activate Model + +Model --> SetProjectCategoryCommand +deactivate Model + +create CommandResult +SetProjectCategoryCommand -> CommandResult +activate CommandResult + +CommandResult --> SetProjectCategoryCommand +deactivate CommandResult + +SetProjectCategoryCommand --> LogicManager : r +deactivate SetProjectCategoryCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml index a821e06458c..633ac7924fb 100644 --- a/docs/diagrams/StorageClassDiagram.puml +++ b/docs/diagrams/StorageClassDiagram.puml @@ -14,12 +14,14 @@ Class JsonUserPrefsStorage Class "<>\nStorage" as Storage Class StorageManager -package "AddressBook Storage" #F4F6F6{ -Class "<>\nAddressBookStorage" as AddressBookStorage -Class JsonAddressBookStorage -Class JsonSerializableAddressBook -Class JsonAdaptedPerson -Class JsonAdaptedTag +package "Planner Storage" #F4F6F6{ +Class "<>\nPlannerStorage" as PlannerStorage +Class JsonPlannerStorage +Class JsonSerializablePlanner +Class JsonAdaptedProject +Class JsonAdaptedTask +Class JsonAdaptedComment +Class JsonAdaptedMember } } @@ -29,15 +31,17 @@ HiddenOutside ..> Storage StorageManager .up.|> Storage StorageManager -up-> "1" UserPrefsStorage -StorageManager -up-> "1" AddressBookStorage +StorageManager -up-> "1" PlannerStorage Storage -left-|> UserPrefsStorage -Storage -right-|> AddressBookStorage +Storage -right-|> PlannerStorage JsonUserPrefsStorage .up.|> UserPrefsStorage -JsonAddressBookStorage .up.|> AddressBookStorage -JsonAddressBookStorage ..> JsonSerializableAddressBook -JsonSerializableAddressBook --> "*" JsonAdaptedPerson -JsonAdaptedPerson --> "*" JsonAdaptedTag +JsonPlannerStorage .up.|> PlannerStorage +JsonPlannerStorage ..> JsonSerializablePlanner +JsonSerializablePlanner --> "*" JsonAdaptedProject +JsonAdaptedProject --> "*" JsonAdaptedTask +JsonAdaptedProject --> "*" JsonAdaptedComment +JsonAdaptedProject --> "*" JsonAdaptedMember @enduml diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml index 95473d5aa19..d9244671e89 100644 --- a/docs/diagrams/UiClassDiagram.puml +++ b/docs/diagrams/UiClassDiagram.puml @@ -11,10 +11,14 @@ Class UiManager Class MainWindow Class HelpWindow Class ResultDisplay -Class PersonListPanel -Class PersonCard +Class ProjectListPanel +Class ProjectCard Class StatusBarFooter Class CommandBox +Class CurrentProjectPanel +Class TaskListPanel +Class TaskCard +Class CommentCard } package Model <> { @@ -32,26 +36,34 @@ UiManager .left.|> Ui UiManager -down-> "1" MainWindow MainWindow *-down-> "1" CommandBox MainWindow *-down-> "1" ResultDisplay -MainWindow *-down-> "1" PersonListPanel +MainWindow *-down-> "1" ProjectListPanel +MainWindow *-down-> "1" CurrentProjectPanel MainWindow *-down-> "1" StatusBarFooter MainWindow --> "0..1" HelpWindow -PersonListPanel -down-> "*" PersonCard +ProjectListPanel -down-> "*" ProjectCard + +CurrentProjectPanel -down-> "3" TaskListPanel +TaskListPanel -down-> "*" TaskCard +TaskListPanel -down-> "*" CommentCard + MainWindow -left-|> UiPart ResultDisplay --|> UiPart CommandBox --|> UiPart -PersonListPanel --|> UiPart -PersonCard --|> UiPart +ProjectListPanel --|> UiPart +ProjectCard --|> UiPart StatusBarFooter --|> UiPart HelpWindow --|> UiPart -PersonCard ..> Model +ProjectCard ..> Model +TaskCard ..> Model +CommentCard ..> Model UiManager -right-> Logic MainWindow -left-> Logic -PersonListPanel -[hidden]left- HelpWindow +ProjectListPanel -[hidden]left- HelpWindow HelpWindow -[hidden]left- CommandBox CommandBox -[hidden]left- ResultDisplay ResultDisplay -[hidden]left- StatusBarFooter diff --git a/docs/images/AddCommentDiagram.png b/docs/images/AddCommentDiagram.png new file mode 100644 index 00000000000..c38c16fcc1d Binary files /dev/null and b/docs/images/AddCommentDiagram.png differ diff --git a/docs/images/AddProjectSequenceDiagram.png b/docs/images/AddProjectSequenceDiagram.png index 2da04ed1439..5ad392d4e2c 100644 Binary files a/docs/images/AddProjectSequenceDiagram.png and b/docs/images/AddProjectSequenceDiagram.png differ diff --git a/docs/images/ArchitectureSequenceDiagram.png b/docs/images/ArchitectureSequenceDiagram.png index 37ad06a2803..1027de55a85 100644 Binary files a/docs/images/ArchitectureSequenceDiagram.png and b/docs/images/ArchitectureSequenceDiagram.png differ diff --git a/docs/images/BetterModelClassDiagram.png b/docs/images/BetterModelClassDiagram.png index 02a42e35e76..84ff4e11872 100644 Binary files a/docs/images/BetterModelClassDiagram.png and b/docs/images/BetterModelClassDiagram.png differ diff --git a/docs/images/DeleteProjectSequenceDiagram.png b/docs/images/DeleteProjectSequenceDiagram.png index 922e33dae59..fa19e428690 100644 Binary files a/docs/images/DeleteProjectSequenceDiagram.png and b/docs/images/DeleteProjectSequenceDiagram.png differ diff --git a/docs/images/DeleteTaskSequenceDiagram.png b/docs/images/DeleteTaskSequenceDiagram.png index 9ccc975e3e3..bb25b6afe77 100644 Binary files a/docs/images/DeleteTaskSequenceDiagram.png and b/docs/images/DeleteTaskSequenceDiagram.png differ diff --git a/docs/images/EditProjectNameDiagram.png b/docs/images/EditProjectNameDiagram.png new file mode 100644 index 00000000000..416c22161f9 Binary files /dev/null and b/docs/images/EditProjectNameDiagram.png differ diff --git a/docs/images/LogicClassDiagram.png b/docs/images/LogicClassDiagram.png index fe91c69efe7..437e0ea4d16 100644 Binary files a/docs/images/LogicClassDiagram.png and b/docs/images/LogicClassDiagram.png differ diff --git a/docs/images/ModelClassDiagram.png b/docs/images/ModelClassDiagram.png index a19fb1b4ac8..e45ceaf4d5a 100644 Binary files a/docs/images/ModelClassDiagram.png and b/docs/images/ModelClassDiagram.png differ diff --git a/docs/images/ParserClasses.png b/docs/images/ParserClasses.png index 2caeeb1a067..38242371910 100644 Binary files a/docs/images/ParserClasses.png and b/docs/images/ParserClasses.png differ diff --git a/docs/images/SetProjectCategorySequenceDiagram.png b/docs/images/SetProjectCategorySequenceDiagram.png new file mode 100644 index 00000000000..170ed88fe3f Binary files /dev/null and b/docs/images/SetProjectCategorySequenceDiagram.png differ diff --git a/docs/images/StorageClassDiagram.png b/docs/images/StorageClassDiagram.png index 18fa4d0d51f..675961b28e9 100644 Binary files a/docs/images/StorageClassDiagram.png and b/docs/images/StorageClassDiagram.png differ diff --git a/docs/images/UiClassDiagram.png b/docs/images/UiClassDiagram.png index 11f06d68671..844f1ccdebc 100644 Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ