Test logging plugin used to retrieve more detailed test logs.
Referenced and modified use of java.utils.Optionals
when retrieving CommandResult
from an executed Command
from
Team W17-2,
MainWindow.java
lines 191 - 194.
Refer to the guide Setting up and getting started.
The Architecture Diagram given above explains the high-level design of the App.
Given below is a quick overview of main components and how they interact with each other.
Main components of the architecture
Main
(consisting of classes Main
and MainApp
)
is in charge of the app launch and shut down.
The bulk of the app's work is done by the following four components:
UI
: The UI of the App.AnimalLogic
: The command executor.AnimalModel
: Holds the data of the App in memory.AnimalStorage
: Reads data from, and writes data to, the hard disk.Commons
represents a collection of classes used by multiple other 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
.
Each of the four main components (also shown in the diagram above),
interface
with the same name as the Component.{Component Name}Manager
class (which follows the corresponding API
interface
mentioned in the previous point.For example, the AnimalLogic
component defines its API in the AnimalLogic.java
interface and implements its functionality using the AnimalLogicManager.java
class which follows the AnimalLogic
interface. Other components interact with a given component through its interface
rather than the concrete class (reason: to prevent outside component's being coupled to the implementation of a
component), as illustrated in the (partial) class diagram below.
The sections below give more details of each component.
The API of this component is specified in Ui.java
The UI consists of a MainWindow
that is made up of parts. Some core components include: CommandBox
, ResultDisplay
,
AnimalListPanel
, AnimalDetailPanel
, and AnimalCard
, along with other components. 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.
Generally, the UI consists of the command box for the user to input commands, a result display to give an output based on the command given, and a main animal display panel consisting of 2 parts:
AnimalListPanel
which consists of a list of AnimalCard
objectsAnimalDetailPanel
which is a detailed view of Animal
objects.The layout of the MainWindow
is specified in MainWindow.fxml
The UI
component does the following actions:
CommandBox
class of the UI where
users can input a command.Model
data so that the UI can be updated with the modified data. For example, when an animal
is deleted or added to the catalog, the UI is updated through the AnimalListPanel
class, where the list that is
referenced is an Observable<Animal>
list that is updated live.Logic
component, because the UI
relies on the Logic
to execute commands.Model
component, as it displays Animal
object residing in the Model
.API : AnimalLogic.java
Here's a (partial) class diagram of the AnimalLogic
component:
The sequence diagram below illustrates the interactions within the AnimalLogic
component, taking execute("delete 1")
API call as an example.
Note: The lifeline for DeleteAnimalCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
How the AnimalLogic
component works:
AnimalLogic
is called upon to execute a command, it is passed to an AnimalCatalogParser
object which in
turn creates a parser that matches the command (e.g., DeleteAnimalCommandParser
) and uses it to parse the command.AnimalCommand
object (more precisely, an object of one of its subclasses e.g., DeleteAnimalCommand
) which is executed by the AnimalLogicManager
.AnimalModel
when it is executed (e.g. to delete a person).CommandResult
object which is returned back from AnimalLogic
.Here are the other classes in AnimalLogic
(omitted from the class diagram above) that are used for parsing a user command:
How the parsing works:
AnimalCatalogParser
class creates an XYZCommandParser
(XYZ
is a placeholder for the specific command name e.g., AddAnimalCommandParser
) which uses the other classes shown above to parse the user command and create a XYZCommand
object (e.g., AddAnimalCommand
) which the AnimalCatalogParser
returns back as a AnimalCommand
object.XYZCommandParser
classes (e.g., AddAnimalCommandParser
, DeleteAnimalCommandParser
, ...) inherit from the AnimalParser
interface so that they can be treated similarly where possible e.g, during testing.API : AnimalModel.java
The AnimalModel
component,
Animal
objects (which are contained in a UniqueAnimalList
object).Animal
objects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiable ObservableList<Animal>
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.AnimalUserPref
object that represents the user’s preferences. This is exposed to the outside as a AnimalReadOnlyUserPref
objects.AnimalModel
represents data entities of the domain, they should make sense on their own without depending on other components)Note: An alternative (arguably, a more OOP) model is given below. It has a PetId
list in the AnimalCatalog
, which Animal
can reference. This allows AnimalCatalog
to only require PetId
object, instead of each Animal
needing their own PetId
objects.
API : AnimalStorage.java
AnimalStorage
and Storage
are used synonymously.
The AnimalStorage
component,
can save both animal catalog data and user preference data in JSON format, and read them back into corresponding objects.
inherits from both AnimalCatalogStorage
and AnimalUserPrefStorage
, which means it can be treated as either
one (if only the functionality of only one is needed). This also allows AnimalStorage to act as a unified facade that
exposes the relevant APIs for other classes to interact with the Storage.
depends on some classes in the Model
component (because the Storage
component's job is to save/retrieve objects
that belong to the Model
). Specifically, it depends on the Animal
model. To decrease the amount of coupling,
JsonAdaptedAnimal
is used, which acts as an adapter for Animal
to be serialized/deserialized by Jackson. As such, it
is important for developers to take extra caution when modifying Animal
and its attributes, and update
JsonAdaptedAnimal
accordingly.
Classes used by multiple components are in the commons package.
This section describes some noteworthy details on how certain features are implemented.
HelpAnimalCommand
FeatureThe HelpAnimalCommand
is a command designed to display useful help messages to the User, without having them refer to
the User Guide constantly, which could be a cumbersome and frustrating user experience.
Here's a brief outline of the HelpAnimalCommand
's operations and attributes:
HelpAnimalCommandParser#parse
- Parses the user input to create a HelpAnimalCommand
that may or may not contain
an argument.HelpAnimalCommand#execute(AnimalModel model)
Executes the command to display a help message to the User.Given below is an example usage scenario of the HelpAnimalCommand
:
help
command to find out how to use the App. The user can optionally include a known command's
name as argument, e.g. help add
to find out how to use the AddAnimalCommand
.CommandException
is thrown. Otherwise, if the syntax is valid, the help
command displays 1 of 2 possible outcomes:
The following activity diagram shows how the HelpAnimalCommand
works:
Aspect: How the help is implemented
help
command searches for the specified command in a CommandEnum
class.
CommandEnum
encapsulates the commands' name and help
message, rather than hard-coding and maintaining a Map of commandName: helpMessage. If the help message were
to be updated, developers only have to update the getHelp
method in the respective commands, and it would
automatically be refllected by help
.CommandEnum
for help
command to display the relevant help message.Command
classes at run-time.
CommandEnum
class for the help
command to display the newly added command's help message.AddAnimalCommand
FeatureThe AddAnimalCommand
is a specific command designed to add an animal to the animal catalog. It identifies the animal to
be added with attributes such as its name, ID, sex, species, breed, age, date of birth and date of admission.
Here's a brief outline of its operations and attributes:
AddAnimalCommandParser#parse
— Parses the user input to create an AddAnimalCommand
with the various
attributes of the Animal to be added.AddAnimalCommand#execute(AnimalModel model)
— Executes the command to add the specified animal to the model.Given below is an example usage scenario of the AddAnimalCommand
:
add
command with the proper CLI syntax, giving a compulsory input field for each attribute.
Note that the position of the cli syntax can be in any order.CommandException
describing the error is thrown. Otherwise, it adds the animal with its
inputted attributes to the model and returns a successful command result.The following sequence diagrams shows how the AddAnimalCommand
works:
In the logic component:
list
, search
and reset
) have similar logic sequence diagrams, and hence only AddAnimalCommand
will be explained in detail.
In the model component:
Aspect: How the addition is handled
DeleteAnimalCommand
FeatureThe DeleteAnimalCommand
is a specific command designed to remove an animal from the animal catalog. It identifies the animal to be deleted based on its displayed index in the animal list.
Here's a brief outline of its operations and attributes:
DeleteAnimalCommand#execute(AnimalModel model)
— Executes the command to delete a specified animal.targetIndex
— An attribute that holds the index of the animal to be deleted.Given below is an example usage scenario of the DeleteAnimalCommand
:
find
command.delete
command, providing the index of the animal to be deleted. For instance, delete 3
would attempt to delete the third animal on the list.CommandException
. Otherwise, it retrieves the animal corresponding to the index, removes it from the model, and returns a successful command result.AddAnimalCommand
for the sequence diagrams of the logic and model components of DeleteAnimalCommand
as they are largely similar.
Aspect: How the deletion is handled
EditAnimalCommand
FeatureThe EditAnimalCommand
is a specific command designed to edit the field(s) of a selected animal from the animal catalog. It identifies the animal to be edited based on its displayed index in the animal list.
EditAnimalCommandParser#parse(String args)
— Parses the user input to create a EditAnimalCommand
object with the given animal index.EditAnimalCommand#execute(AnimalModel model)
— Executes the command to edit an animal's attribute(s) for an animal in the animal catalog.Given below is an example usage scenario of the EditAnimalCommand
:
edit
command with the animal index and the prefixes of the attribute to be edited. For instance, edit 1 n/Boo s/Cat
will edit the first animal's name to "Boo" and the species to "Cat".CommandException
. Otherwise, it proceeds to edit the attributes of the selected animal, and returns a successful command result.AddAnimalCommand
for the sequence diagrams of the logic and model components of EditAnimalCommand
as they are largely similar.
Aspect: Choices of attributes to edit
ID
.
ID
.ID
when adding animal, user has to delete the entry and add again.ID
can be edited, user does not have to delete the entry and add a new animal.ListAnimalCommand
FeatureThe ListAnimalCommand
is a command designed to list all animals in the animal catalog. It does not take in any arguments.
Here's a brief outline of its operations and attributes:
ListAnimalCommand#execute(AnimalModel model)
— Executes the command to list all animals in the animal catalog.Given below is an example usage scenario of the ListAnimalCommand
:
list
command.The following sequence diagram shows how the ListAnimalCommand
works:
In the logic component:
Aspect: How the listing is handled
SearchAnimalCommand
FeatureThe SearchAnimalCommand
is a command designed to search for animals in the animal catalog. It takes in at least one prefix as an argument.
Here's a brief outline of its operations and attributes:
SearchAnimalCommandParser#parse(String args)
— Parses the user input to create a SearchAnimalCommand
object with the given predicates based on the prefixes.SearchAnimalCommand#execute(AnimalModel model)
— Executes the command to filter animals in the animal catalog based on the predicate.Given below is an example usage scenario of the SearchAnimalCommand
:
search
command with the prefixes of the attributes to be searched. For instance, search b/Poodle
would search for animals of breed Poodle.CommandException
. Otherwise, it retrieves the animals that match the valid prefixes, and returns a successful command result.ListAnimalCommand
for the sequence diagrams of the model component of SearchAnimalCommand
as they are largely similar, except for the predicate passed into updateFilteredAnimalList.
Aspect: How the search is handled
AddTaskCommand
FeatureThe AddTaskCommand
is a specific command designed to add a task to the task list of an animal. It identifies the animal to be selected based on its index in the current animal list.
Here's a brief outline of its operations and attributes:
AddTaskCommand#execute(AnimalModel model)
— Executes the command to add a task to the task list of a specified animal.targetIndex
— An attribute that holds the index of the specified animal.task
— An attribute that holds the task that is to be added.Given below is an example usage scenario of the AddTaskCommand
:
find
command.addtask
command, providing the index of the specified animal and a task description of "Feed dog". For instance, addtask 3 Feed dog
will add the task with task description "Feed dog" to the third animal in the list.CommandException
. Otherwise, it retrieves the animal corresponding to the index, adds the task to the task list of that animal, and returns a successful command result.The following sequence diagram shows how the AddTaskCommand
works:
AddAnimalCommand
for the sequence diagrams of the logic and model components of AddTaskCommand
as they are largely similar.
Aspect: Multiplicity of tasks to be added and animals to be modified
addtask
command multiple times to add multiple tasks.DeleteTaskCommand
FeatureThe DeleteTaskCommand
is a specific command designed to delete a task to the task list of an animal. It identifies the animal to be selected based on its index in the current animal list and the task to be deleted based on its index in the task list of the selected animal.
Here's a brief outline of its operations and attributes:
DeleteTaskCommand#execute(AnimalModel model)
— Executes the command to delete a specified task of a specified animal.targetAnimalIndex
— An attribute that holds the index of the specified animal.targetTaskIndex
— An attribute that holds the index of the task to be deleted.Given below is an example usage scenario of the DeleteTaskCommand
:
find
command.deletetask
command, providing the index of the specified animal and the index of the task to be deleted. For instance, deletetask 3 1
will delete the first task in the task list of the third animal in the displayed animal list.CommandException
. Otherwise, it retrieves the animal corresponding to the animal index, deletes the task corresponding to the task index of the task list of that animal, and returns a successful command result.AddAnimalCommand
for the sequence diagrams of the logic and model components of DeleteTaskCommand
as they are largely similar.
Aspect: Multiplicity of tasks to be deleted and animals to be modified
deletetask
command multiple times to delete multiple tasks.MarkTaskCommand
and UnmarkTaskCommand
FeatureThe MarkTaskCommand
is a command designed to mark task(s) as done for an animal in the animal catalog.
The UnmarkTaskCommand
is a command designed to mark task(s) as uncompleted for an animal in the animal catalog.
Both commands take in one animal index and at least one task index as arguments.
MarkTaskCommand
and UnmarkTaskCommand
have very similar implementations, hence only MarkTaskCommand
will be explained in detail.
Here's a brief outline of its operations and attributes:
MarkTaskCommandParser#parse(String args)
— Parses the user input to create a MarkTaskCommand
object with the given animal index and task index(s).MarkTaskCommand#execute(AnimalModel model)
— Executes the command to mark task(s) as done for an animal in the animal catalog.Given below is an example usage scenario of the MarkTaskCommand
:
mark
command with the animal index and task indexes. For instance, mark 1 2 3
would mark tasks 2 and 3 as done for the animal at index 1.CommandException
. Otherwise, it retrieves the animal and tasks that match its respective indexes, marks it as done, and returns a successful command result.The following sequence diagrams shows how the MarkTaskCommand
works:
In the logic component:
In the model component:
UnmarkTaskCommand
works similarly to MarkTaskCommand
, except that updateTask
takes in false
instead of true
.
Aspect: How the marking is handled
ResetTaskCommand
FeatureThe ResetTaskCommand
is a command designed to reset all tasks as uncompleted for all animals in the animal catalog. It does not take in any arguments.
Here's a brief outline of its operations and attributes:
ResetTaskCommand#execute(AnimalModel model)
— Executes the command to reset all tasks as uncompleted for all animals in the animal catalog.Given below is an example usage scenario of the ResetTaskCommand
:
reset
command.The following sequence diagram shows how the ResetTaskCommand
works:
In the logic component:
In the model component:
Aspect: How the resetting is handled
Detailed View
FeatureThe detailed view is a feature that shows the details of the animals not seen in the entries of the animal list. These include
Date of Birth(DOB), Date of Admission(DOA), Age, and Tasks that are added to the animal. The detailed view is handled by the AnimalDetailPanel
class.
Here's a brief outline of its operations:
AnimalDetailPanel#updateDetails(Animal animal)
— Updates the detail panel of the application with the input animal's details.AnimalDetailPanel
is either updated by the user by clicking on an animal entry cell, or using animal-specific commands. The following activity diagram shows how the detailed view works:
For update of AnimalDetailPanel
by clicking, this is handled in the AnimalListPanel
class using a Listener
. The Listener
will listen to changes in selected cell, and update the animal details to show the selected animal.
For update of AnimalDetailPanel
by animal-specific commands, animal-specific commands that automatically update the Detailed View
with the targeted animal include add
, edit
, addtask
,
deletetask
, mark
, and unmark
. All other commands are considered non-animal-specific. For such animal-specific commands, the CommandResult
will accept an additional argument Animal
,
and this is retrieved by the AnimalDetailView
in the MainWindow
class. To differentiate between CommandResult
that contains an Animal
(animal-specific commands) and non-animal-specific commands, OptionalCommandResult
class.
Aspect: How the detailed view is displayed
Target user profile: Volunteers at animal shelters.
Value proposition: Our application aims to provide a centralized platform to ensure efficient storage and access to critical details, enhancing the volunteer experience in animal shelters.
Priorities: High (must have) - * * *
, Medium (nice to have) - * *
, Low (unlikely to have) - *
Priority | As a... | I want to... | So that I can... |
---|---|---|---|
*** | volunteer | view specific information about each pet. | understand their unique needs. |
*** | volunteer | be able to access a user manual. | easily learn how to navigate the app. |
*** | volunteer | view all animals in a single page. | - |
*** | volunteer | add new animal entries | - |
*** | volunteer | update existing animal profiles | - |
** | volunteer | add tasks to each animal | know each animal's needs. |
** | volunteer | mark tasks as done | keep track of which animal's needs has been taken care of. |
(For all use cases below, the System is the AnimalCatalog
and the Actor is the user
, unless specified
otherwise)
Use Case: UC01 - Help on Animal Commands
MSS:
Extensions:
Use Case: UC02 - Add Animal to Catalog
MSS:
Extensions:
Use Case: UC03 - Delete Animal from Catalog
MSS:
Extensions:
Use Case: UC04 - Edit Animal Details in Catalog
MSS:
Extensions:
Use Case: UC05 - List All Animals in Catalog
MSS:
Use Case: UC06 - Search for Animals in Catalog
MSS:
Extensions:
Use Case: UC07 - Add Task to Animal's Task List
MSS:
Extensions:
Use Case: UC08 - Delete Task from Animal's Task List
MSS:
Extensions:
Use Case: UC09 - Mark Task as Done in Animal's Task List
MSS:
Extensions:
Use Case: UC10 - Unmark Task as Uncompleted in Animal's Task List
MSS:
Extensions:
add
, edit
, addtask
, deletetask
, mark
, unmark
.Given below are instructions to test the app manually.
Note: These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.
Initial launch
Download the jar file and copy into an empty folder
Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
Saving window preferences
Resize the window to an optimum size. Move the window to a different location. Close the window.
Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
Implement more detailed error messages for search
command. The current error message for invalid inputs for the search
command is not very accurate. It will be improved in the future by providing more accurate error messages. e.g. search nil/other
will return an error message saying that the prefix provided is invalid, instead of saying that the search input is empty since it is not recognised.
Include INDEX
numbers of tasks in the detailedView. Currently, tasks are listed in the detailedView without the INDEX
. While usable, it can get inconvenient to figure out which INDEX
a task is when the task list gets longer, as users have to manually count up/down. It will be improved by displaying the INDEX
of the task beside each task, e.g
1. [ ] Task 1
2. [ ] Task 2
3. [X] Task 3
Add a view
command, to view details of animals. Currently, to view the details of an animal, users have two approaches:
3.1. Click on an animal entry in the animal list to see the detailed view.
3.2. Most animal-specific commands that involve specifying an INDEX
of animal will automatically show the details of the animal in the detailed view. Commands include: add
, edit
, addtask
, deletetask
, mark
, unmark
.
While intuitive, it was an oversight to not include a view
animal command to make it more CLI-friendly. We plan on adding a view INDEX
command in the future, where the detailed view will show the details of the animal at the specified INDEX
of the view INDEX
command.
Implement persistent search
status. Currently, the search
command filters the animals based on the tags passed in. If the user follows up with any command other than delete
, the filtered list will reset to show all animals.
For example, search s/Dog
will show all animals whose species is Dog. If user uses the following command (add
, edit
, addtask
, deletetask
, mark
, unmark
, reset
) right after the search
command, the list will reset and show all animals.
To implement the persistent search
status, we plan to keep track of the last FilteredAnimalList
and display the animals within the last FilteredAnimalList
after the update.
Accommodate extreme length inputs for Animal name
and Task description
. Currently, when a user inputs an animal name
and task description
of extreme length, the text will be cut off in the UI. While it's highly unlikely to have such extreme length name
and task description
, it will still be good to include a horizontal scrollbar in the JavaFX AnimalDetailPanel
component to accommodate such scenarios.
Implement more detailed error messages for add
command. Currently, our AnimalCatalog prevents adding of identical animals, and this identity is tracked using the primary key ID
of the animal. When a user tries to add an animal and specifies an ID
that already exists in the AnimalCatalog, the error message states that This animal already exists in the Catalog
. While performing as expected, it can be further enhanced with the animal ID
, such as Animal with ID: 1111 already exists in the Catalog
.
Allow for multiple task creations for single animal and creations of the same tasks for multiple animals. Currently, we only allow for one task creation for one animal per command. This can be implemented by allowing a user to specify if they are adding a single task to multiple animals with an additional single
keyword or multiple tasks to a single animal with an additional multiple
keyword.
Our groups faced challenges and required to put great effort for this project. These included:
PetId
, AdmissionDate
, DateOfBirth
, Sex
, Task
, and many more to fit the target audience. These meant a lot more test cases and error handling for all inputs for these classes.