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.Logic
: The command executor.Model
: Holds the data of the App in memory.Storage
: 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 Logic
component defines its API in the Logic.java
interface and implements its functionality using the LogicManager.java
class which follows the Logic
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 e.g.CommandBox
, ResultDisplay
, PersonListPanel
, LeaveListPanel
, 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
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
is specified in MainWindow.fxml
The UI
component,
Logic
component.Model
data so that the UI can be updated with the modified data.Logic
component, because the UI
relies on the Logic
to execute commands.Model
component, as it displays Person
and Leave
objects residing in the Model
.API : Logic.java
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.
Note: The lifeline for DeleteCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
How the Logic
component works:
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.Command
object (more precisely, an object of one of its subclasses e.g., DeleteCommand
) which is executed by the LogicManager
.Model
when it is executed (e.g. to delete a person).CommandResult
object which is returned back from Logic
.Here are the other classes in Logic
(omitted from the class diagram above) that are used for parsing a user command:
How the parsing works:
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.XYZCommandParser
classes (e.g., AddCommandParser
, DeleteCommandParser
, ...) inherit from the Parser
interface so that they can be treated similarly where possible e.g, during testing.API : Model.java
The Model
component,
Person
objects (which are contained in a UniquePersonList
object).Leaves
objects (which are contained in a UniqueLeavesList
object).Person
objects (e.g., results of find
) as a separate filtered list which is exposed to outsiders as an unmodifiable ObservableList<Person>
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 changes.Leave
objects (e.g. results of find-leave
) as a separate filtered list which is exposed to outsiders as an unmodifiable ObservableList<Leave>
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 changes.UserPref
object that represents the user’s preferences. This is exposed to the outside as a ReadOnlyUserPref
objects.Model
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 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.
API : Storage.java
The Storage
component,
AddressBookStorage
, LeavesBookStorage
and UserPrefStorage
, which means it can be treated as either one (if only the functionality of only one is needed).Model
component (because the Storage
component's job is to save/retrieve objects that belong to the Model
)Both AddressBookStorage
and LeavesBookStorage
contain JSON and CSV implementations. These implementations exist separately
as their methods invoke methods from different Util files - the JSON implementation invokes JsonUtil methods, while the
CSV implementation invokes CsvUtil methods. SerializableAddressBook
, SerializableLeavesBook
, AdaptedPerson
and
AdaptedLeave
have been abstracted out to promote code reusability, with the use of generics where possible to enforce
type safety.
Classes used by multiple components are in the seedu.addressbook.commons
package.
This section describes some noteworthy details on how certain features are implemented.
ManageHR keeps track of employees within the company with the use of Person
and UniquePersonList
. The UniquePersonList
serves as a container for the Person
objects,
while enforcing the constraints that no 2 employees have the same name.
The Person
class contains the following attributes.
Name
: The name of the employee.Phone
: The phone number of the employee.Email
: The email address of the employee.Address
: The address of the employee.Tags
: The customised tag added by the user.ManageHR keeps track of the leaves of employees within the company with the use of Leave
and UniqueLeaveList
. The UniqueLeaveList
serves as a container for the Leave
objects,
while enforcing the constraints that no 2 leaves can have same start date and end date for the same employee.
The Leave
class contains the following attributes.
ComparablePerson
: The employee.Title
: The title of the leave.Description
: The description of the leave.Date start
: The start date of the leave.Date end
: The end date of the leave.Status
: The status of the leave.Date start
must be earlier than or the same as the Date end
.
All the attributes except Description and Status are compulsory fields for adding a leave.
The add-leave command allows the HR manager to add a leave record for a specific employee. This feature enhances the HRMate system by providing a way to manage and track employee leaves efficiently.
Fields compulsory to enter for add-leave
as String
type include:
index
: The index of the person for the leave application. It will be parsed as Index
type to AddLeaveCommand
object and converted to Person
type based on the displayed list when a new Leave
object created.title
: The title of the leave, it will be parsed as Title
type to AddLeaveCommand
object and to the newly created Leave
object.date start
: The start date of the leave in "yyyy-MM-dd" format. It will be parsed together with date end
as Range
type to AddLeaveCommand
object and to the newly created Leave
object.date end
: The end date of the leave in "yyyy-MM-dd" format. It will be parsed together with date start
as Range
type to AddLeaveCommand
object and to the newly created Leave
object.description
: The description of the leave. It is optional and will be parsed as NONE
if no description field exists. Otherwise it will be parsed as Description
type to AddLeaveCommand
object and to the newly created Leave
object.AddLeaveCommand
.AddLeaveCommandParser
.model.addLeave(toAdd)
in AddLeaveCommand#execute
.The activity diagram for adding a leave is as followed:
Here is an example usage of the add-leave
feature:
find
command to filter for employees named Martin.add-leave 1 title/Sample Leave 1 start/2023-11-01 end/2023-11-01
with Martin being index 1.The command follows a structured format to ensure ease of use and to minimize errors. The use of an index ensures that the leave is associated with a specific employee. The format of the command is designed to be clear and straightforward.
FindAllTagCommand
and FindSomeTagCommand
are implemented similar to FindCommand
.
They use TagsContainAllTagsPredicate
and TagsContainAllTagsPredicate
respectively as predicate to filter the employee list. And then update the displayed employee list of the model
The following sequence diagram shows how FindAllTagCommand
executes.
FindAllTagCommand
matches employees with all specified tags while FindSomeTagCommand
matches employees with any of the specified tags.
The nuance difference is made to cater to users' needs for efficient searching.
AddTagCommand
is implemented similar to EditCommand
.
A new Person
is created with the information from the old Person
.
The tags are then added before replacing the old Person
with the new Person
.
The following activity diagram summarizes what happens when a user executes a new command:
Aspect: How AddTagCommand executes:
EditCommand
as reference), immutability allows for potential redo and undo commands.Person
.
Person
can affect implementation of potential redo and undo commands.FindLeaveByPeriodCommand
is implemented similar to FindCommand
. It uses a LeaveInPeriodPredicate
as the predicate to filter
the leaves list.
The predicate can be in 1 of 4 possible states
The following sequence diagram shows how FindLeaveByPeriodCommand
executes.
A LeaveInPeriodPredicate is constructed from the query supplied by the user, defining both a start (if provided) and end (if provided). When the command is executed, the model's FilteredLeaveList is updated to only returns leaves that satisfy the predicate.
The import feature allows users to import employee records and leave applications in CSV format, increasing portability of
the user's data. The import feature can provide a means of mass adding employee records and leave applications, without having to use
the add
command repeatedly. Since both importing employee records and leave applications involve similar sequences,
the following will describe the sequence for importing employee records.
Here is an example usage of the import feature:
import
command.The following activity diagram shows the steps involved in the Import command:
The CSV file is read into a CsvFile object, which is then converted into a CsvSerializableAddressBook object by reading each row and the corresponding values for each column. The CsvSerializableAddressBook is then converted into an AddressBook instance, which replaces the current AddressBook instance in the app.
Aspect: How the user selects files
The export feature enables users to export employee records and leave applications into CSV format, which can then be opened in other spreadsheet applications. It allows users to select filtered data to export, providing greater granularity in control over file content. Since both exporting employee records and leave applications involve similar sequences, the following will describe the sequence for exporting employee records.
Here is an example usage of the export
feature:
find-some-tag
command to filter for employees with the full time
tagexport fulltimers
{home folder of HRMate}/exports
, with the name fulltimers.csv
. This file contains employees
with the full time
tag.The following sequence diagram shows the steps involved in the Export command:
ExportContactCommandParser::parseFileName() checks if the file name provided is a valid file name. If the user provided a path, it strips the path to retain only the file name. Next, it appends a ".csv" extension to the end of the file name if the user did not supply the extension.
The export command works by retrieving the filtered employee list in the address book, which contains a list of employee records that are currently visible in the address book panel. A CsvSerializableAddressBook is constructed from this filtered person list, which is then serialized into a CsvFile object. CsvUtil then writes the CsvFile instance into a CSV file. This file is saved in the "export" folder that is created in the same location as the HRMate application file.
Aspect: Whether to allow the user to select the location to save the file to
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.These operations are exposed in the Model
interface as Model#commitAddressBook()
, Model#undoAddressBook()
and Model#redoAddressBook()
respectively.
Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
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.
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.
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
.
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
.
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.
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.
The following sequence diagram shows how the undo operation works:
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.
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.
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.
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.
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.
The following activity diagram summarizes what happens when a user executes a new command:
Aspect: How undo & redo executes:
Alternative 1 (current choice): Saves the entire address book.
Alternative 2: Individual command knows how to undo/redo by itself.
delete
, just save the person being deleted).Target user profile:
Value proposition: manage HR information faster than a typical mouse/GUI driven app
Priorities: High (must have) - * * *
, Medium (nice to have) - * *
, Low (unlikely to have) - *
Priority | As a … | I want to … | So that I can … |
---|---|---|---|
* * * | new user | see usage instructions | refer to instructions when I forget how to use the App |
* * * | HR manager | add a new employee | |
* * * | HR manager | delete an employee | remove employees who no longer work here |
* * * | HR manager | find an employee by name | locate details of employees without having to go through the entire list |
* * * | organised HR manager | add/delete a tag to an employee | change the label of an employee |
* * * | organised HR manager | view all my tags | filter by them |
* * * | organised HR manager | find employees by tags | find specific category of employees for higher level workflows |
* * * | HR manager | add a new leave application of an employee | keep track of the leaves applications |
* * * | HR manager | delete employees' leave applications | remove leave applications that have been cancelled by employees |
* * * | HR manager of a large organisation | find all leave applications of an employee | track the amount of leaves taken by an employee |
* * * | HR manager | approve/reject leave applications | update employees on their leave application status |
* * | HR manager | hide private contact details | minimize chance of someone else seeing them by accident |
* * | HR manager | import/export records in CSV format | open the records in other apps |
* * | HR manager of a large organisation | find all leave applications in a given period | forecast available manpower to avoid manpower shortages |
* * | HR manager of a large organisation | find all leave applications with a given status | check which applications are still pending |
* | HR manager of a large organisation | sort employees by name | locate an employee easily |
(For all use cases below, the System is the HRMate
and the Actor is the HR Manager
, unless specified otherwise)
Use case: Add/delete a tag from an employee
MSS
User requests to find employee by name
HRMate shows a list of employees with the same name
User requests to add/delete a tag from a specific employee in the list
HRMate adds/deletes tag from specified employee
Use case ends.
Extensions
2a. The list is empty.
Use case ends.
3a. The given tag is invalid. (already there for add, not there for delete)
3a1. HRMate shows an error message.
Use case resumes at step 2.
Use case: Delete an employee
MSS
User requests to list employees
HRMate shows a list of employees
User requests to delete a specific employee in the list
HRMate deletes the employee
Use case ends.
Extensions
2a. The list is empty.
Use case ends.
3a. The given index is invalid.
3a1. HRMate shows an error message.
Use case resumes at step 2.
Use case: Import employee records
MSS
User requests to import employee records
User selects CSV file from file dialog
HRMate adds records in CSV file inside its list of employee records
HRMate displays a message indicating successful importing of file
Use case ends.
Extensions
2a. User cancels the file selection operation.
2a1. HRMate closes the file selection window and aborts the operation.
Use case ends.
3a. File is not of CSV file type
3a1. HRMate displays an error message.
Use case ends.
3b. File is corrupted, unable to read employee records
3b1. HRMate discards all data read in.
3b2. HRMate displays an error message.
Use case ends.
Use case: Export employee records
MSS
User requests to export employee records.
User supplies a name and path to save the records.
HRMate creates the CSV file containing the employee records with the specified name at the specified location.
HRMate displays a message indicating the file has been created.
Use case ends.
Extensions
2a. User does not supply a name
2a1. HRMate displays an error message
Use case ends.
2b. User does not supply a path/supplies an invalid path
2b1. HRMate creates the CSV file containing the employee records with the specified name at the default location (same folder where the save files are located)
Use case resumes at step 3.
3a. HRMate is unable to create the file due to errors (e.g. permission errors)
3a1. HRMate aborts the file creation operation.
3a2. HRMate displays an error message.
Use case ends.
Use case: List all tags
MSS
User requests to view all tags
HRMate shows a list of all available tags
Use case ends.
Extensions
2a. There is no existing tag in the system.
2a1. HRMate notifies the user of no existing tag in the system.
Use case ends.
Use case: List employees with at least one specified tags
MSS
User requests to find employees who match at least one of the specified tags
HRMate shows a list of employees who match at least one of the specified tags
Use case ends.
Extensions
2a. The specified tags do not exist in the system.
2a1. HRMate notifies the user of invalid tags.
Use case resumes at step 1.
2b. User does not provide any tags.
2b1. HRMate notifies the user of missing parameters.
Use case resumes at step 1.
Use case: List employees with all specified tags
MSS
User requests to view all tags
HRMate shows a list of all available tags
Use case ends.
Extensions
2a. There is no existing tag in the system.
2a1. HRMate notifies the user of no existing tag in the system.
Use case resumes at step 1.
Use case: Add a leave application
MSS
The HR manager requests to find an employee by name.
HRMate shows a list of employees with the same name.
The HR manager requests to add a leave application for the selected employee
HRMate adds the leave application to the employee's record based on the provided information.
Use case ends.
Extensions:
2a. The list of employees with the provided name is empty.
2a1. HRMate informs the HR manager that no employees with the given name were found.
Use case ends.
3a. The provided employee index is invalid.
3a1. HRMate shows an error message indicating that the employee name is not valid.
Use case resumes at step 2.
4a. The provided leave application details are invalid.
4a1. HRMate shows an error message specifying the issue with the provided details (e.g., date format, missing fields).
Use case resumes at step 3.
11
or above installed.HRMate is built for extensibility. Not much effort is needed to implement new commands that are variations of existing features, but effort is needed to add new entities.
The first challenge given is understanding the code infrastructure. HRMate uses many design patterns like Facade pattern, Command pattern and MVC pattern. Without knowledge of these patterns, HRMate would seem complicated and difficult to understand.
Overall the understanding that the Model
is a Facade for AddressBook
and LeavesBook
, input commands follow the Command pattern, and that AddressBook
and LeavesBook
are the models, JavaFX is used for the view and ModelManager
functions as the controller greatly help in the understanding of HRMate's infrastructure.
Another significant challenge is the implementation of the leaves module. Given HRMate's immutable design philosophy, some design choices like replacing stale Leave
with new instances of Leave
with the updated Person
are chosen. Care must be taken to update Leave
everytime a Person
is replaced like in the EditCommand
, AddTagCommand
and DeleteCommand
. When adding a new potential module like Report
, we anticipate that care must be taken when the associated Person
or Leave
is replaced.
To illustrate the difference in effort, the effort needed to create AddTagCommand
and the Leave
module will be compared.
Given that AddTagCommand
is a specific case of EditCommand
, much of the logic is similar to EditCommand
. In this case, AddTagCommand
copies a Person
, adds the new Tag
before calling Model#SetPerson
.
Adding a new command is easy compared to the implementation of the Leave
module. We took inspiration from the Person
class and created wrapper classes for the fields like Title
, Description
and Date
. One of the significant challenges were the added constraint of comparing two fields, start
and end
. This logic was not present in Person
. For example Name
validations do not concern Tag
validations and vice versa. In Leave
case, start
affects the validations for end
, as end
must be on or after start
. To resolve this, we created Leave
's constructor to use Range
, whose creation mandates start
be on or before end
. This ensures that the created Leave
adheres to the constraint of start
being before or on end
. We anticipate that the creation of other entities like Report
to require the creation of new wrapper classes, or even validation classes to enforce validations that span across multiple fields.
Efforts were also spent on ensuring data validity for Person
and Leave
when the associated object is modified. As mentioned above, one of the challenges faced was the immutable principle that AB3 used. When a Person
is edited through EditCommand
, AddTagCommand
or DeleteTagCommand
, the old Person
is replaced by the newly created Person
. This results in some Leave
pointing to the stale Person
. Thus, Model#SetPerson
and Model#DeletePerson
must be amended to edit LeavesBook
as well to avoid any Leave
pointing to any stale Person
. We expect that such methods like Model#SetPerson
, Model#DeletePerson
, Model#SetLeave
, Model#DeleteLeave
must be amended when adding new modules if the new entities is reliant on information from pre-existing entities.
Leave
alongside Person
with information consistency even when Person
is edited or deleted.Leave
and Person
, opening up changing in app data to users who might not understand json.Given below are instructions to test the app manually.
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.
Adding an employee while all employees are being shown
Test case: add n/John Doe p/98765432 e/johnd@example.com a/John Street, block 123 #01-01
Expected: The employee is added to the list. Details of the added leave shown in the status message.
Test case: add n/John Two p/98765431 e/johnt@example.com a/John Street, block 122 #01-01 t/remote
Expected: The employee is added to the list. Error details shown in the status message. Status bar becomes red.
Test case: add n/John Two p/98765431 e/johnt@example.com
Expected: The employee is not added to the list. Details of the added leave shown in the status message.
Other incorrect add commands to try: add
, add
with missing compulsory fields, add
with illegal arguments in fields
Expected: Similar to previous.
Deleting a person while all persons are being shown
Prerequisites: List all persons using the list
command. Multiple persons in the list.
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: delete 0
Expected: No person is deleted. Error details shown in the status message. Status bar becomes red.
Other incorrect delete commands to try: delete
, delete x
, ...
(where x is larger than the list size)
Expected: Similar to previous.
Deleting a person after applying a filter
Prerequisites: Filter to the second person using find PERSON_NAME
where PERSON_NAME
is the name of the second person.
Test case: delete 1
Expected: First visible contact is delete from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated.
Test case: delete 2
Expected: No person is delete. Error details shown in the status message. Status bar becomes red.
Follow up actions: list
Expected: Only the previously deleted person is deleted.
Adding a tag to an employee while all employee are being shown
Prerequisites: List all employee using the list command. Multiple employees in the list.
Test case: add-tag 1 t/full time
Expected: The tag full time
is added to employee indexed 1 shown in the employee list. Details of the edited employee shown in the status message.
Test case: add-tag 1
Expected: No tag is added. Error details shown in the status message. Status bar becomes red.
Other incorrect add-tag commands to try: add-tag
, add-tag
with illegal arguments in fields, add-tag x
(where x is larger than the list size)
Expected: Similar to previous.
Editing an employee while all employee are being shown
Prerequisites: List all employee using the list command. Multiple employees in the list.
Test case: edit 2 p/98765432 e/johndoe@example.com t/full-time t/remote
Expected: Thephone number, email address and tags of the employee indexed 2 are changed to 98765432, johndoe@example.com and full-time and remote. Details of the edited employee shown in the status message.
Test case: edit 1 a/John street, block 123 #01-01 t/
Expected: The home address of the employee indexed 1 is changed to John street, block 123 #01-01 and all tags removed from the employee shown in the employee list. Details of the edited employee shown in the status message.
Test case: edit 1 a/ t/
Expected: No tag is added. Error details shown in the status message. Status bar becomes red.
Other incorrect edit commands to try: edit
, edit
with illegal arguments in fields, edit x
(where x is larger than the list size)
Expected: Similar to previous.
Prerequisites: There are tags attached to the employees.
Test case: view-tag
Expected: Tags shown in the status message.
remote
, full time
, part time
and on-site
.find-all-tag t/remote t/full time
Expected: GUI Changes: A dedicated interface section displays a list of employees with both tags remote
and full time
. Status message indicates the number of matched employees. Verify that employees with additional tags are also displayed.find-all-tag
Expected: Error message indicates an invalid command format.Status bar becomes red.find-all-tag t/Nonexistent tag
Expected: GUI Changes: A dedicated interface section displays no employee. Status message indicates 0 matched employee.find-all-tag t/REMOTE
Expected: GUI Changes: A dedicated interface section displays no employee. Status message indicates 0 matched employee.find-all-tag t/123!
Expected: Error message indicates illegal tag names. Status bar becomes red.find-all-tag t/re
Expected:Employees with tag named re
are displayed. Verify that employees with additional tags are also displayed.remote
, full time
, part time
and on-site
.find-some-tag t/remote t/full time
Expected: GUI Changes: A dedicated interface section displays a list of employees with either tags remote
and full time
. Status message indicates the number of matched employees. Verify that employees with additional tags are also displayed.find-some-tag
Expected: Error message indicates an invalid command format.Status bar becomes red.find-some-tag t/Nonexistent tag
Expected: GUI Changes: A dedicated interface section displays no employee. Status message indicates 0 matched employee.find-some-tag t/REMOTE
Expected: GUI Changes: A dedicated interface section displays no employee. Status message indicates 0 matched employee.find-some-tag t/123!
Expected: Error message indicates illegal tag names. Status bar becomes red.find-some-tag t/re
Expected:Employees with tag named re
are displayed. Verify that employees with additional tags are also displayed.Adding a leave while all leaves are being shown
Prerequisites: List all leaves using the list-leaves command. Multiple leaves in the list.
Test case: add-leave 1 title/Vacation start/2023-11-15 end/2023-11-20
Expected: The leave is added to the list. Details of the added leave shown in the status message. Timestamp in the status bar is updated.
Test case: add-leave 0 title/Conference start/2023-12-01 end/2023-12-03 d/Attending conference
Expected: No leave is added. Error details shown in the status message. Status bar becomes red.
Other incorrect add-leave commands to try: add-leave
, add-leave x
, ...
(where x is larger than the list size)
Expected: Similar to previous.
Dealing with missing/corrupted data files
Open ./data/addressbook.json
and delete the first character {
. Then open HRMate.
Expected: HRMate opens an empty address book.
Add a person using add
and a leave using add-leave
, then exit
. Open ./data/leavesbook.json
and edit the fullName of the name of the employee of a leave. Reopen HRMate.
Expected: HRMate restores all data except for the edited leave.
Person
and Leave
Dealing with edits to Person
Person
using add
and a Leave
using add-leave
. Edit the Person
name using edit
. Leave
is edited also.Dealing with deletes to Person
Person
using add
and a Leave
using add-leave
. Delete the Person
with delete
. Leave
is deleted also.export-all
would export both Person
and Leave
. HR Managers usually wants to move both Person
and Leave
to another application, so being able to export both in a single csv sheet would help them do so.
find-all-tags and find-any-tags searches for tags case insensitive. Since tags are used for categorising, HR Managers might see no difference between Intern and intern. Hence allowing case insensitive search in find-all-tags and find-any-tags would help HR Managers find employees more easily.
Mergable import
. Sometimes, HR Managers want to move data from one app to HRMate without removing all current employees. Allow HRMate to merge a csv file, with an option to overwrite current data or overwrite csv data when a same employee is encountered, would help HR Managers achieve this.
Filtered clear
. Allowing HR Managers to select a group of employees to delete would be good. For example, they could use find-any-tags t/intern
, clear
to delete all interns. Subsequently, list
would show all non intern employees.