diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index c4b4be27ce1..96358b3fe01 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -9,11 +9,19 @@ 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} +* UI rendering via: [JavaFX](https://openjfx.io/) +* Testing suite via: [JUnit5](https://github.com/junit-team/junit5) +* JSON data saving and loading via: [Jackson](https://github.com/FasterXML/jackson) + +* Jobby base UI adapted from: [AddressBook Level-3](https://se-education.org/addressbook-level3/) +* Autocompletion base UI adapted from: [@floralvikings's AutoCompleteTextBox.java](https://gist.github.com/floralvikings/10290131) + +* New user tutorial structure inspired from: [AY2324S1-CS2103T-T17-03](https://ay2324s1-cs2103t-t17-3.github.io/tp/UserGuide.html) -------------------------------------------------------------------------------------------------------------------- ## **Setting up, getting started** +{: .reset-page-break-defaults} Refer to the guide [_Setting up and getting started_](SettingUp.md). @@ -21,9 +29,10 @@ Refer to the guide [_Setting up and getting started_](SettingUp.md). ## **Design** -
+
:bulb: **Tip:** The `.puml` files used to create diagrams in this document `docs/diagrams` folder. Refer to the [_PlantUML Tutorial_ at se-edu/guides](https://se-education.org/guides/tutorials/plantUml.html) to learn how to create and edit diagrams. +
### Architecture @@ -36,7 +45,7 @@ Given below is a quick overview of main components and how they interact with ea **Main components of the architecture** -**`Main`** (consisting of classes [`Main`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/MainApp.java)) is in charge of the app launch and shut down. +**`Main`** (consisting of classes [`Main`](https://github.com/AY2324S1-CS2103T-W08-3/tp/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/AY2324S1-CS2103T-W08-3/tp/tree/master/src/main/java/seedu/address/MainApp.java)) is in charge of the app launch and shut down. * At app launch, it initializes the other components in the correct sequence, and connects them up with each other. * At shut down, it shuts down the other components and invokes cleanup methods where necessary. @@ -68,13 +77,13 @@ The sections below give more details of each component. ### UI component -The **API** of this component is specified in [`Ui.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/Ui.java) +**API Reference** : [`Ui.java`](https://github.com/AY2324S1-CS2103T-W08-3/tp/tree/master/src/main/java/seedu/address/ui/Ui.java) ![Structure of the UI Component](images/UiClassDiagram.png) The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `ContactListPanel`, `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`](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) +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/AY2324S1-CS2103T-W08-3/tp/tree/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/AY2324S1-CS2103T-W08-3/tp/tree/master/src/main/resources/view/MainWindow.fxml) The `UI` component, @@ -85,7 +94,7 @@ The `UI` component, ### Logic component -**API** : [`Logic.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/logic/Logic.java) +**API Reference** : [`Logic.java`](https://github.com/AY2324S1-CS2103T-W08-3/tp/tree/master/src/main/java/seedu/address/logic/Logic.java) Here's a (partial) class diagram of the `Logic` component: @@ -100,26 +109,76 @@ The sequence diagram below illustrates the interactions within the `Logic` compo How the `Logic` component works: -1. When `Logic` is called upon to execute a command, it is passed to an `AppParser` 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 contact). -1. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`. +* Executing a command: + + 1. When `Logic` is called upon to execute a command, it is passed to `AppParser` which in turn creates a parser that matches the command (e.g., `DeleteCommandParser`) and uses it to parse the command. + + 2. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `DeleteCommand`) which is executed by the `LogicManager`. + + 3. The command can communicate with the `Model` when it is executed (e.g. to delete a contact). + + 4. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`. + +* Autocompleting a command: + + 1. When `Logic` is called upon to autocomplete a command, it is passed to `AppParser` which in turn creates an autocompletion generator capable of generate autocompletion results for this command. + + 2. This results in an `AutocompleteGenerator` which is executed by the `LogicManager`. + + 3. The `AutocompleteGenerator` can communicate with the `Model` to obtain the current application state (e.g. to obtain the list of all contact ids) when supplying autocompletion results. + + 4. This results in a `Stream` representing the possible completions, 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: +Here are the other classes in `Logic` (omitted from the class diagram above) that are used for parsing a user command for both execution and autocompletion: + +#### Parser classes How the parsing works: -* When called upon to parse a user command, the `AppParser` 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 `AppParser` 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. + +1. When called upon to parse a user command, the `AppParser` class looks up the corresponding **Command Parser** (e.g., `AddCommandParser` if it detects an "add" command). + +2. There are two cases here: + + 1. If there exists a `Parser` for the corresponding command, it will use the other classes shown above to parse the user command and create a `Command` object (e.g., `AddCommand`). + + 2. Otherwise, it will create a `Command` object corresponding to the command name (e.g., `AddCommand`) with no arguments. + +3. Finally, `AppParser` returns back the `Command` object. How arguments from a raw command input may be obtained by parsers: + * When arguments are needed for a command, `ArgumentTokenizer` is used to prepare and tokenize the raw input string, which can then convert it to an `ArgumentMultimap` for easy access. + * An `ArgumentMultimap` represents the command data (which has the format `name preamble text --flag1 value 1 --flag2 value 2`) in their distinct fields: **preamble**, **flags** and their mapped **values**. Note that as a multimap, multiple values can be mapped to the same flag. -* All parsers can use the `ArgumentMultimap` (obtained from using the raw input on `ArgumentTokenizer`) to access the required arguments to create and execute a `Command`. + +* With that, all parsers can use resulting `ArgumentMultimap` (obtained from using the raw input on `ArgumentTokenizer`) to access the required arguments to create and execute a `Command`. + +Design Notes: + +* All **Command Parser** classes (e.g., `AddCommandParser`, `DeleteCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing. + +#### Autocomplete classes + + + +How autocompletion works: + +1. When called upon to generate autocompletions for a partially typed command, `Logic` passes the request to `AppParser` class. + +2. There are two cases after this happens: + + 1. If a command name is specified and complete (i.e., user added a space after the command name), `AppParser` will look up the corresponding `AutocompleteSupplier` for the command, and create an `AutocompleteGenerator` with it. + + 2. Otherwise, `AppParser` will create an `AutocompleteGenerator` with a `Supplier>` that returns all possible command names. + +3. `AppParser` then returns the `AutocompleteGenerator` to the requester so as they can generate autocompletion results. + +For full details of the autocomplete design and implementation, refer to the [Command Autocompletion Internals](#command-autocompletion-internals) section. ### Model component -**API** : [`Model.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/model/Model.java) +**API Reference** : [`Model.java`](https://github.com/AY2324S1-CS2103T-W08-3/tp/tree/master/src/main/java/seedu/address/model/Model.java) @@ -140,7 +199,7 @@ The `Model` component, ### Storage component -**API** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/storage/Storage.java) +**API Reference** : [`Storage.java`](https://github.com/AY2324S1-CS2103T-W08-3/tp/tree/master/src/main/java/seedu/address/storage/Storage.java) @@ -159,89 +218,235 @@ Classes used by multiple components are in the `seedu.addressbook.commons` packa This section describes some noteworthy details on how certain features are implemented. -### Command Autocompletion +### Command Autocompletion Internals #### Overview Jobby's Command Autocompletion is designed to provide users with intelligent command suggestions and offer autocompletion by analyzing the existing partial command input and the current application state. -Just like programming IDEs, a user may type a prefix subsequence of a long command part, and simply press **TAB** to finish the command using the suggested match. +Just like programming IDEs, a user may type a prefix subsequence of a long command part, and simply press **TAB** to finish the command using the suggested match. For instance, type "sort -tt" and press **TAB** to finish the command as "sort --title". + +#### The Autocomplete Package + +The full autocomplete package (and some of its dependencies) can be summarized by the following class diagram: + + -It consists of several key components: +The implementation consists of two notable classes that will be used by high-level users: - **`AutocompleteSupplier`**: - This class is responsible for generating possible flags and values to be used for suggestions. - - It takes an `AutocompleteItemSet` of flags, an optional `FlagValueSupplier` mapped to each flag, and can have corresponding `AutocompleteConstraint` applied to flags. + - It takes an `AutocompleteItemSet`, an optional `FlagValueSupplier` mapped to each flag, and can have corresponding `AutocompleteConstraint`s applied to flags. - It helps determine what flags can be added to an existing command phrase based on constraints and existing flags. + - All commands with customizable input should prepare an instance of this class to be used for autocompletion. - **`AutocompleteGenerator`**: - This component takes in an `AutocompleteSupplier` or a `Supplier>` and generates autocomplete results based on a partial command input and the current application model. - Users can invoke `AutocompleteGenerator#generateCompletions(command, model)` to get autocomplete suggestions. - It does the hard work of taking the possible values provided by either supplier, performing subsequence fuzzy match, and then "predict" what the user is typing. +The process used to generate autocomplete suggestions with these two classes is mentioned in the [high-level Logic component previously discussed](#logic-component). + +In summary, the `AutocompleteGenerator` class is used to generate completions, and any command that has the ability to supply autocomplete results should have their respective `AutocompleteSupplier`s defined and available to be fed into the generator. + +#### Autocompletion Constraints + +Autocompletion constraints are defined via the `AutocompleteConstraint` functional interface. It provides a way to specify rules for autocomplete suggestions. + +```java +@FunctionalInterface +public interface AutocompleteConstraint { + boolean isAllowed(T input, Set existingFlags); +} +``` + +**API Reference:** [AutocompleteConstraint,java](https://github.com/AY2324S1-CS2103T-W08-3/tp/tree/master/src/main/java/seedu/address/logic/autocomplete/components/AutocompleteConstraint.java) + +This interface can be thought of as a lambda function that takes in the *input item* and *existing items*, then returns a boolean value indicating whether the input should be allowed. -#### `AutocompleteConstraint` +In our autocomplete implementation, we use constraints to define rules for what flags can be added to an existing set of flags. We hence use the type `AutocompleteConstraint`. -The `AutocompleteConstraint` class provides a way to specify rules for autocomplete suggestions. It is a functional interface, so it can be treated as a lambda function. +##### Built-in Constraints -It offers static factory methods for quickly defining common rulesets. Examples include: -- `#oneAmongAllOf(items...)`: Specifies that one of the provided items must be present in the command. -- `#onceForEachOf(items...)`: Ensures that each of the provided items can only appear once in the command. -- `#where(item)#isPrerequisiteFor(dependents...)`: Defines dependencies between items, indicating that certain flags are prerequisites for others. -- `#where(item)#cannotExistAlongsideAnyOf(items...)`: Defines that an item cannot be present when any of the others are present. +The interface offers static factory methods for quick creation of many common constraints. For example: -#### `AutocompleteItemSet` +- `#oneAmongAllOf(items...)`: Enforces that at most one of the provided items must be present in the command. +- `#onceForEachOf(items...)`: Enforces that each of the provided items can only appear once in the command. +- `#where(item)#isPrerequisiteFor(dependents...)`: Defines dependencies between items, indicating that certain items are prerequisites before its dependents may appear. -The `AutocompleteItemSet` is a set of flags that retains knowledge of which flags have what rules and constraints. It helps determine which flags can be added to an existing set of flags given the known constraints. +##### Custom Constraints + +It is possible to declare your own constraints. + +Hence, to create a constraint that **all** flags cannot be used more than once, we can simply declare it just like so: + +```java +AutocompleteConstraint cannotBeUsedMoreThanOnce = (input, existingItems) -> + !existingFlags.contains(input); +``` + +#### Autocomplete Item Sets + +An autocomplete item set - represented by the `AutocompleteItemSet` class - is a custom set of items with an additional perk: it retains knowledge of which items have what rules and constraints. + +Hence, in our autocomplete implementation, we use `AutocompleteItemSet` to easily store and determine which flags can be added to an existing set of flags given the known constraints. + +**API Reference:** [AutocompleteItemSet.java](https://github.com/AY2324S1-CS2103T-W08-3/tp/tree/master/src/main/java/seedu/address/logic/autocomplete/components/AutocompleteItemSet.java) + +##### Built-in Item Set Factories This dataset can be constructed manually with flags and constraints, but it also offers static factory methods for quick creation of flag sets with common constraints. For example: + - `#oneAmongAllOf(items...)`: Creates a set where at most one out of all the provided items may appear. - `#onceForEachOf(items...)`: Ensures that each of the provided items can appear only once. - `#anyNumberOf(items...)`: Creates a set with the rule that items in the set may appear any number of times. -Additionally, some helper operations are provided in a chainable fashion. For example: -- `#concat(sets...)`: Combines sets together to create complex combinations of flag rules and flags. -- `#addDependents(items...)`: Establishes dependencies between flags. This way, flag may require another flag to exist in order to be used. +##### Helper Chainable Operations + +Some helper operations are provided in a chainable fashion to simplify workflows. For example: + +- `#concat(sets...)`: Combines sets together to create complex combinations of items and their rules. +- `#addDependents(items...)`: Establishes dependencies between items. This way, an item may require another different item to exist in order to be used. - `#addConstraints(constraints...)`: Adds more custom constraints as desired. -Finally, we need a way to compute what items are usable given existing set of items that are present. This class exposes one such method: +##### Usage Example + +Suppose we have a set of flags, some supporting repeated usage (`FLAG_REP_1`, `FLAG_REP_2`), and some that may only be used once (`FLAG_ONCE_1`, `FLAG_ONCE_2`). + +We can create such a set, with all the constraints automatically combined, like so: + +```java +AutocompleteItemSet set = AutocompleteItemSet.concat( + AutocompleteItemSet.anyNumberOf(FLAG_REP_1, FLAG_REP_2), + AutocompleteItemSet.onceForEachOf(FLAG_ONCE_1, FLAG_ONCE_2) +); +``` + +##### Computing Usable Items + +Finally, we need a way to compute what items are usable given existing set of items that are present. `AutocompleteItemSet` exposes one final method that is exactly what we need: + - `#getElementsAfterConsuming(items...)`: Gets the remaining set of elements after "consuming" the given ones. -#### `FlagValueSupplier` +#### Flag Value Suppliers + +In some cases, Jobby should be capable of provide suggestions for flags with preset or known values, such as "`--status pending`", or "`--oid alex_yeoh_inc`". This is where flag value suppliers come in. + +The `FlagValueSupplier` functional interface is a simple one that behaves like a lambda function with one task: Given a **partial command** for a flag and the app's **model**, generate all possible values a flag may have. -The `FlagValueSupplier` interface is a simple one that behaves like a lambda function with one task: Given a partial command for a flag and the app's **model** generate all possible suggestion results. +```java +@FunctionalInterface +public interface FlagValueSupplier extends + BiFunction> { + + Stream apply(PartitionedCommand partialCommand, Model model); +} +``` -By taking in both the command and the app model, it is possible to specify arbitrary suppliers with any data, even from the model itself, like corresponding Id values when using the `--oid` flag for recruiters. +**API Reference:** [FlagValueSupplier.java](https://github.com/AY2324S1-CS2103T-W08-3/tp/tree/master/src/main/java/seedu/address/logic/autocomplete/components/FlagValueSupplier.java) -#### `AutocompleteSupplier` +With the provided details, it is possible to specify arbitrary suppliers with any data. You can supply a preset list of completions, or even retrieve values from the model itself. -The `AutocompleteSupplier` leverages the capabilities of `AutocompleteItemSet` and `FlagValueSupplier`. +Accessing the partial command is useful if you'd like to change the results based on the heuristically detected type, such as fields that accept either an `INDEX` or an `ID`. -Internally, it uses `AutocompleteItemSet` to determine what flags can be added after a given set of flags has been used in a command. +**Note to developers:** Custom `FlagValueSupplier`s need not actually do any prefix or subsequence matching - that is done automatically at the `AutocompleteGenerator` class later. -This allows it to make suggestions based on constraints like "`--org` cannot exist together with `--rec`." +#### Partitioning Command Strings -Additionally, it uses `FlagValueSupplier` to provide suggestions for flags with preset values, such as "`--status pending`." +The `PartitionedCommand` class is a simple class for quick access for a command string's constituent parts, specifically for the purposes of autocomplete. This is done simply by initializing it with a partial command string. -#### `AutocompleteGenerator` +**API Reference:** [PartitionedCommand.java](https://github.com/AY2324S1-CS2103T-W08-3/tp/tree/master/src/main/java/seedu/address/logic/autocomplete/components/PartitionedCommand.java) -The `AutocompleteGenerator` serves as a wrapper for autocomplete functionality, regardless of it's source. +For example, given the partial command "`add --org --name Alice --oid ama`", you will be able to extract the partitions in the following forms: -It takes an `AutocompleteSupplier` or a `Supplier` and generates autocomplete suggestions. +| Command Name | Middle Text | Autocompletable Text | +|:------------:|:--------------------------:|:--------------------:| +| `add` | `--org --name Alice --oid` | `ama` | -Once initialized, users can call `AutocompleteGenerator#generateCompletions(command, model)` to receive suggestions from their partial command input. +| Leading Text | Trailing Text | +|:------------------------------:|:-------------:| +| `add --org --name Alice --oid` | `ama` | +There are also helper methods to detect flag strings and other properties of the command, which can be found in the API reference. -#### Design Considerations +#### The Autocomplete Supplier + +The `AutocompleteSupplier` leverages the capabilities of `AutocompleteItemSet` and `FlagValueSupplier` together to form a full supplier for a single command. + +**API Reference:** [AutocompleteSupplier.java](https://github.com/AY2324S1-CS2103T-W08-3/tp/tree/master/src/main/java/seedu/address/logic/autocomplete/AutocompleteSupplier.java) + +Internally, it must be initialized with an `AutocompleteItemSet` to determine what flags can be added to a command at any point in time, inclusive of all known restrictions. It is most easily done via the factory method `#from`. + +Additionally, one may optionally assign `FlagValueSupplier`s into `Flag`s by inputting `Map`. This allows the supplier to provide suggestions for flags with preset or known values. + +You may configure both `AutocompleteItemSet` and `Map` in the same constructor call, or use factory and chaining methods to create such a set - refer to publicly exposed API calls for more details. + +##### Usage Example + +Recall the example from earlier where we created an `AutocompleteItemSet`? A way to create a full `AutocompleteSupplier` from that is as follows: + +```java +AutocompleteSupplier supplier = AutocompleteSupplier.from(set); +``` + +We can add more details on an existing supplier by using a configurator. Suppose we have a `FlagValueSupplier` for a status flag. This is how we can add it to the supplier: + +```java +supplier.configureValueMap(map -> map.put(FLAG_STATUS, statusFlagValueSupplier)); +``` + +##### Obtaining Results + +The supplier exposes methods to obtain the possible flags and values: + +- `#getOtherPossibleFlagsAsideFromFlagsPresent(Flags...)`: Gets the remaining set of flags that can be added to the command, given the flags that are already present. + +- `#getValidValuesForFlag(Flag, PartitionedCommand, Model)`: Gets the possible values for a flag, given the partial command and the model. + +This is used by `AutocompleteGenerator` to generate suggestions later. + +#### The Autocomplete Generator + +The `AutocompleteGenerator` is the final stage of the autocompletion generation process. + +It supports generating results based on those supplied by an `AutocompleteSupplier`, or any arbitrary `Supplier`, and generates autocomplete suggestions. + +Once initialized, users can simply call the `#generateCompletions(command, model)` method to receive suggestions from their partial command input. It's that easy! + +**API Reference:** [AutocompleteGenerator.java](https://github.com/ay2324s1-cs2103t-w08-3/tp/tree/master/src/main/java/seedu/address/logic/autocomplete/AutocompleteGenerator.java) + +##### Execution Flow + +Internally, whenever requested, the `AutocompleteGenerator`: +1. obtains a command's parts with `PartitionedCommand`, +2. uses the `AutocompleteSupplier` provided when initialized to obtain the results based on the available parts, +3. automatically performs fuzzy (subsequence) matching to filter results, +4. ranks them based on their relevance, +5. and finally returns a stream of autocompleted commands. + +### Design Considerations When designing the Autocomplete feature, important considerations include the ability to flexibly define and craft new constraints based on heuristically determined rules. -By abstracting away all operations into simple components like sets and constraints, the current carefully crafted design allows -Jobby's Command Autocompletion to provide context-aware suggestions to users, while adhering to simple constraints defined on a per command basis. +By abstracting away all operations into simple components like sets and constraints, the current carefully crafted design allows Jobby's Command Autocompletion to provide context-aware suggestions to users, while adhering to simple constraints defined on a per command basis. Most notably, it also allows for advanced rulesets to be specified in a human-readable fashion. Take a look at [AddCommand#AUTOCOMPLETE_SUPPLIER](https://github.com/AY2324S1-CS2103T-W08-3/tp/blob/c484696fe4c12d514ad3fb6a71ff2dfea089fe32/src/main/java/seedu/address/logic/commands/AddCommand.java#L47). +#### Alternatives Considered + +##### Alternative 1: Using Hardcoded Rules in Java + +One obvious alternative is to simply the possible autocompletion results for each command in standard Java. We may achieve this by manually checking against a command string for each command type, and using existing tokenization classes like `ArgumentTokenizer` and `ArgumentMultimap`. + +While this would incur less overhead in initial development time, more explicit coding is required - it is neither quick to write nor scalable to tons of commands. This is especially important as autocomplete was developed in parallel with other new features being added to Jobby, which would require constant changes to the autocomplete rules. + +##### Alternative 2: Using a Graph-based Approach + +A graph based approach, e.g., having a tree structure to define constraints and dependencies, may be more efficient than the current solution (which has to check against _all_ known rules every single time). + +However, it will consume even more development time to implement and model the rules as a graph. Since the current implementation involves one set with a list of constraints, multiple sets can be combined by simply concatenation of both the items and the constraints. + ### Adding Organization #### Implementation @@ -449,6 +654,33 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli (For all use cases below, the **System** is `Jobby` and the **Actor** is the `user`, unless specified otherwise) +**Use case: Inputting commands with autocomplete** + +**MSS** + +1. User inputs a command partially. +2. Jobby shows a list of possible completions that matches the partial command. +3. User selects a completion from the list. +4. Jobby updates the user input with the selected completion. +5. User repeats from step 1 until the command is complete. + + Use case ends. + +**Extensions** + +* 2a1. Jobby does not have any suggestions to list for the partial command. + + Use case resumes at step 5. + +* 3a. User dismisses the list of suggestions. + + Use case resumes at step 5. + +* 1a. User requests to undo the last completion. + * 1a1. Jobby undoes the last completion, if any. + + Use case resumes at step 2. + **Use case: Add an application** @@ -646,9 +878,7 @@ testers are expected to do more *exploratory* testing. 1. Resize the window to an optimum size. Move the window to a different location. Close the window. 1. Re-launch the app by double-clicking the jar file.
- Expected: The most recent window size and location is retained. // TODO: Check if it is valid. - -1. _{ more test cases …​ }_ + Expected: The most recent window size and location is retained. ### Resetting to default data for Jobby @@ -733,11 +963,20 @@ testers are expected to do more *exploratory* testing. ### Saving data 1. Dealing with missing/corrupted data files - - 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_ - -1. _{ more test cases …​ }_ - + 1. Prerequisite: None. + 2. Test case: Delete half of a contact in the json data file.
+ Expected: An empty list of contacts and applications are displayed on startup. + 3. Test case: Delete the data file in Jobby's home folder.
+ Expected: The sample list of contacts and applications is displayed on startup. + +2. Modifying the list of contacts and job applications + 1. Prerequisite: Having existing contacts and applications when editing or deleting data. + 2. Test case: Adding a new contact/job application and closing the application.
+ Expected: The new contact/job application is displayed when the application starts up again. + 3. Test case: Editing an existing contact/job application
+ Expected: The edits are saved and is correctly displayed when the application starts up again. + 4. Test case: Deletes an existing contact/job application
+ Expected: The contact/job application is not displayed when the application starts up again. -------------------------------------------------------------------------------------------------------------------- @@ -904,11 +1143,17 @@ Additionally, a huge amount of time was spent creating test cases and modifying ### Autocompletion -To improve user experience, we wanted to incorporate an autocomplete feature which allows users to know which flags could be used for a certain command. This reduced the reliance on the User Guide and would help new users familiarize themselves with Jobby. +To improve user experience, we wanted to incorporate support for command autocompletion, which allows users to know which parameters and values could be used for a certain command. This reduced the reliance on the User Guide and would help new users familiarize themselves with Jobby. + +Additionally, the addition of autocompletion allows us to use full-length flags (e.g., `--description`), yet allowing the user to simply type `-dc ` to obtain the full flag, removing the need to memorize multiple 1-, 2-letter abbreviations. This involved: -* Creating an entire class to encapsulate this feature. -* Modify the parser to aid in autocompletion. -* Modifying JavaFX to incorporate autocompletion. +* Creating multiple classes to better organize and provide autocompletion, +* Modifying the parser, tokenizer, flag syntax, etc., to aid in autocompletion, and +* Modifying JavaFX elements and intercepting the appropriate keystroke events to incorporate autocompletion. + +The end-to-end process of parsing the user text and determining what are plausible inputs is not trivial - we need to correctly decide which parameters and values are suggestable values based on command rules, such as "only one of `--name` allowed". + +Additionally, despite the complex implementation, the autocompletion package has a comprehensive ~80% test coverage, with expected behaviors clearly documented within the tests themselves to guard against unexpected changes. -This was extremely challenging as including a proper autocompletion in JavaFX was not simple and straightforward. +For more details, refer to the [Command Autocompletion Internals](#command-autocompletion-internals). diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 43a26730ac0..f0f4312ce96 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -70,11 +70,11 @@ title: User Guide ### Code blocks for entering commands -   denotes a command or a part of a command that can be entered in Jobby. For example, `add --org --name Woogle` is a command. `add` is also part of a command. +   denotes a command or a part of a command that can be entered in Jobby. For example, `add --org --name Woogle`{:.language-sh} is a command. `add` is also part of a command. ### Small information pills -| Component | Description | +| Component | Description | |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | :trophy: Learning outcomes | The learning outcome of the section. | | Beginner
Intermediate
Expert | The difficulty level of the section, with Beginner for new users, Intermediate for users who have completed the tutorial, and Expert for users who have completed and used the features in the User Guide. | @@ -147,11 +147,11 @@ Solid! Now it's time to get started with Jobby! ### Adding your first Organization -Let's say you are interested to applying to **Google** as your internship destination, and you found their email **google@gmail.com**. +Let's say you are interested to apply to **Google** as your internship destination, and you found their email **google@gmail.com**. (This is not their real email, of course) -You can use [`add --org`](#adding-organizations---add---org) command here to add Google into your organization: -1. Type `add --org --name Google --id google_id --email google@gmail.com` into the command box +You can use [`add --org`{:.language-sh}](#adding-organizations---add---org) to add the Google organization in Jobby: +1. Type `add --org --name Google --id google_id --email google@gmail.com`{:.language-sh} into the command box 2. Press **ENTER** ![Adding Organization](images/ug-images/org-added.png) @@ -163,39 +163,39 @@ You have successfully added **Google**, with the email **google@gmail.com** into In a job fair, you managed to meet a **Google** internship recruiter, **Josh Mao**, and he provided you with his number **91219121**. -Here is how you can use [`add --rec`](#adding-recruiters---add---rec) command to track the Recruiter data in Jobby: -1. Type `add --rec --name Josh Mao --oid google_id --phone 91219121` into the command box +Here is how you can use [`add --rec`{:.language-sh}](#adding-recruiters---add---rec) to record the recruiter in Jobby: +1. Type `add --rec --name Josh Mao --oid google_id --phone 91219121`{:.language-sh} into the command box 2. Press **ENTER** ![Adding Recruiter](images/ug-images/rec-added.png) -You have successfully added **Josh Mao**, who is a **recruiter** from Google, whose number is **91219121**. +You have successfully added **Josh Mao** - a **recruiter** from Google with the phone number **91219121**. ### Adding your first Application After preparing your resume, you are ready to apply to **Google** as an intern for their **Software Engineer** role! And you know that the application deadline is on the **22-11-2023**. -Here is how you can use [`apply`](#applying-to-organizations---apply) command to track your application in Jobby: -1. Type `apply google_id --title Software Engineer --by 22-11-2023` into the command box +Here is how you can use [`apply`](#applying-to-organizations---apply) to track your application in Jobby: +1. Type `apply google_id --title Software Engineer --by 22-11-2023`{:.language-sh} into the command box 2. Press **ENTER** ![Adding Application](images/ug-images/app-added.png) You have successfully added your job application to **Google**! -**Congratulations!** You have run through the basics of Jobby. We hope that this tutorial has given you an understanding of the -basic workflow of Jobby. However, there are still many features that we have yet introduced. Please refer to the [Using Jobby Section](#using-jobby) to understand -the command structure of Jobby, or visit [Features Section](#features) to see the full capabilities of Jobby! +**Congratulations!** You have run through the basics of Jobby. We hope that this tutorial has given you an understanding of a basic workflow in Jobby. +However, there are still many features that we have yet to introduce. Please refer to the [Using Jobby](#using-jobby) section to understand how to interpret +command structures and formats, or visit the [Features](#features) section to see the full capabilities of Jobby! -------------------------------------------------------------------------------------------------------------------- ## Using Jobby -This section explains the details of how we can interact with Jobby. +This section explains how we can understand and interact with Jobby via commands. If you're looking for the list of available commands, check out the [Features](#features) section instead. -### Command Structure +### Understanding the Command Structure :trophy: How to understand and write Jobby commands Beginner @@ -203,15 +203,15 @@ In Jobby, we write commands in the command box at the top of Jobby's window. Commands are made up of a few parts: The **command**, **parameter names** and **input values**. -A command like "`edit google --name Google SG --id google-sg`" would refer to: +A command like "`edit google --name Google SG --id google-sg`{:.language-sh}" would refer to: * the **command** `edit`, * with a **command value** `google`, -* with a **parameter** `--name`, +* with a **parameter** `--name`{:.language-sh}, * which has the **parameter value** `Google SG`, -* with a **parameter** `--id`, +* with a **parameter** `--id`{:.language-sh}, * which has the **parameter value** `google-sg`. -Parameters may be in any order, whose names are of the form `-a` or `--abc123`, and must be surrounded by whitespace. +Parameters may be in any order, whose names are of the form `-a` or `--abc123`{:.language-sh}, and must be surrounded by whitespace. Any extra parameters and values to commands that don't accept them will either be ignored or throw an error. @@ -227,17 +227,17 @@ Any extra parameters and values to commands that don't accept them will either b
-### Command Explanations +### Reading Command Formats -:trophy: How to interpret this guide's command explanations Beginner +:trophy: How to interpret Jobby-formatted command explanations Beginner -Throughout this guide, you will find symbols and placeholders used to describe a command format. They are: +Throughout this guide and within Jobby itself, you will find symbols and placeholders used to describe a command format. They are: * **Words in `UPPER_CASE`** * The parts where you should be typing your parameter values. - * e.g., `--name NAME` means inputting names along the lines of `--name Alice`. + * e.g., `--name NAME`{:.language-sh} means inputting names along the lines of `--name Alice`{:.language-sh}. * **Terms separated by `/` or `|`** @@ -245,23 +245,30 @@ Throughout this guide, you will find symbols and placeholders used to describe a * These may be included in the parameter names or value description. - * e.g., `--a/--b` means either `--a` or `--b` but not `--a --b`. + * e.g., `--a / --b`{:.language-sh} means either `--a`{:.language-sh} or `--b`{:.language-sh} but not `--a --b`{:.language-sh}. * **Terms surrounded by `[` and `]`** * An optional parameter or option that may be omitted. - * e.g., `[--id ID]` means you may omit setting an ID for the command. + * e.g., `[--id ID]`{:.language-sh} means you may omit setting an ID for the command. * **Terms ending with `...`** * The parameter is multivalued. - * e.g., `[--tag TAG]...` means `--tag` and its value can be repeated from 0 to any number of times. + * e.g., `[--tag TAG]...`{:.language-sh} means `--tag`{:.language-sh} and its value can be repeated from 0 to any number of times. +* **Terms surrounded by `<` and `>`** + * A high level description of the parameter or option. -### Command Autocomplete + * e.g., if you see something like `< add some text here >`, it means you should replace it with your own text. + +Parameters may have certain value format restrictions - Jobby will let you know if you do not meet a requirement when you input your command. Optionally, you may also refer to their details in [Appendix A](#appendix-a--acceptable-values-for-parameters) later. + + +### Autocompleting Commands :trophy: How to use Jobby's command autocompletion Beginner @@ -288,10 +295,10 @@ If suggestions were hidden or aren't shown when they should, press **TAB** to pr * Expert Autocomplete checks for fuzzy matches - it sorts by the best *subsequence* prefix match first. - * For example, you can type `-nm` to get the autocompletion result of `--name`. + * For example, you can type `-nm` to get the autocompletion result of `--name`{:.language-sh}. * This allows you to quickly choose between parameter names with similar prefixes, e.g., by typing - `-dsp` to select `--description` instead of `--descending`. + `-dsp` to select `--description`{:.language-sh} instead of `--descending`{:.language-sh}. @@ -314,7 +321,7 @@ If suggestions were hidden or aren't shown when they should, press **TAB** to pr The `add` command allows you to create contacts to track details about the organizations and recruiters related to your job application process. To learn more about creating each type of contact, check out the sections below. -#### Adding organizations - `add --org` +#### Adding organizations - `add --org`{:.language-sh} :trophy: How to add organization contacts into Jobby Beginner @@ -331,20 +338,20 @@ Adds an organization contact with the details given to the command. | Command | Reason | |------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------| -| `add --org --name J&J` | Adding an organization **J&J**. | -| `add --org --name Google --id g-sg --phone 98765432 ` | Adding an organization **Google** with other flags. | -| `add --org --name Examinations NUS --phone 65166269 --email examinations@nus.edu.sg --url https://luminus.nus.edu.sg/` | Adding an organization **Examination NUS** with other flags. | +| `add --org --name J&J`{:.language-sh} | Adding an organization **J&J**. | +| `add --org --name Google --id g-sg --phone 98765432 `{:.language-sh} | Adding an organization **Google** with other flags. | +| `add --org --name Examinations NUS --phone 65166269 --email examinations@nus.edu.sg --url https://luminus.nus.edu.sg/`{:.language-sh} | Adding an organization **Examination NUS** with other flags. | ##### Invalid examples | Command | Reason | |-------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------| -| `add --org --name` | `--name` field used but not specified. | -| `add --org --name Google --phone 1231*&&@` | Optional field (in this case `--phone`) was not following the [accepted parameters](#appendix-a-acceptable-values-for-parameters). | +| `add --org --name`{:.language-sh} | `--name`{:.language-sh} field used but not specified. | +| `add --org --name Google --phone 1231*&&@`{:.language-sh} | Optional field (in this case `--phone`{:.language-sh}) was not following the [accepted parameters](#appendix-a-acceptable-values-for-parameters). | -#### Adding recruiters - `add --rec` +#### Adding recruiters - `add --rec`{:.language-sh} :trophy: How to add recruiter contacts into Jobby Beginner @@ -355,11 +362,11 @@ add --rec --name NAME [-id ID] [--oid ORG_ID] [--phone NUMBER] [--email EMAIL] [ Adds a recruiter contact with the details given to the command. * If an `ID` is not specified, one will be automatically generated. -* To link a Recruiter to an Organization in the contacts list, make sure you include `--oid` and pass in the `ID` of the Organization you want to link to. +* To link a Recruiter to an Organization in the contacts list, make sure you include `--oid`{:.language-sh} and pass in the `ID` of the Organization you want to link to. * If you wish to know more about the requirements for each parameter, check out the [given appendix](#appendix-a-acceptable-values-for-parameters). ##### Sample demonstration -* If you execute the command: `add --rec --name Ryan Koh --oid job_seeker_plus`, you should see a new Recruiter being added to the bottom of the contacts list. +* If you execute the command: `add --rec --name Ryan Koh --oid job_seeker_plus`{:.language-sh}, you should see a new Recruiter being added to the bottom of the contacts list. * The newly added contact will have a special label _from organization (job\_seeker\_plus)_ to indicate that the Recruiter is associated to the Organization with that particular `ID`. @@ -371,22 +378,23 @@ Adds a recruiter contact with the details given to the command. | Command | Reason | |-------|----------| -| `add --rec --name John Doe` | Adds a recruiter that is not associated to any organization. | -| `add --rec --name John Doe --tag friendly --tag woogle` | Adds a recruiter with two tags - friendly and woogle. | -| `add --rec --name John Doe --oid job_seeker_plus` | Adds a recruiter that is associated to an organization (if it exists in the address book) with the id **job_seeker_plus**. | -| `add --rec --name John Doe --id johndoe_123 --oid job_seeker_plus --number 912832192 --email johndoe@nus.edu.sg --url example.com --address 21 Kent Ridge Rd --tag network` | Adds a recruiter with all the possible fields. | +| `add --rec --name John Doe`{:.language-sh} | Adds a recruiter that is not associated to any organization. | +| `add --rec --name John Doe --tag friendly --tag woogle`{:.language-sh} | Adds a recruiter with two tags - friendly and woogle. | +| `add --rec --name John Doe --oid job_seeker_plus`{:.language-sh} | Adds a recruiter that is associated to an organization (if it exists in the address book) with the id **job_seeker_plus**. | +| `add --rec --name John Doe --id johndoe_123 --oid job_seeker_plus --number 912832192 --email johndoe@nus.edu.sg --url example.com --address 21 Kent Ridge Rd --tag network`{:.language-sh} | Adds a recruiter with all the possible fields. | ##### Invalid examples | Command | Reason | |---------|--------| -| `add --rec` | Missing a name. | -| `add --rec --name John Doe --phone` | Optional fields (in this case `--phone`) were used but not specified. | -| `add --rec --name John Doe --oid bogus-org` | Given that no organization with the id "bogus-org" exists in the address book. | +| `add --rec`{:.language-sh} | Missing a name. | +| `add --rec --name John Doe --phone`{:.language-sh} | Optional fields (in this case `--phone`{:.language-sh}) were used but not specified. | +| `add --rec --name John Doe --oid bogus-org`{:.language-sh} | Given that no organization with the id "bogus-org" exists in the address book. | ### Editing contacts - `edit` -
Organization Recruiter

+
Organization Recruiter
+ :trophy: How to edit organization or recruiter info in Jobby Intermediate
:information_source: Assumes that you have read the `add` command documentation for contacts.
@@ -402,15 +410,15 @@ Edits the given contact according to the parameters given. | Command | Reason | |-----------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------| -| `edit google --phone 91292951` | Change phone number of organization with **ID** google to **91292951**. | -| `edit 1 --name Jane Street` | Change name of contact at index 1 to **Jane Street**. | -| `edit 1 --name Google --phone 91241412 --email google@gmail.sg` | Changes the name, phone number and email of the contact at index 1 to `Google`, `91241412` and `google@gmail.sg` respectively. | +| `edit google --phone 91292951`{:.language-sh} | Change phone number of organization with **ID** google to **91292951**. | +| `edit 1 --name Jane Street`{:.language-sh} | Change name of contact at index 1 to **Jane Street**. | +| `edit 1 --name Google --phone 91241412 --email google@gmail.sg`{:.language-sh} | Changes the name, phone number and email of the contact at index 1 to `Google`, `91241412` and `google@gmail.sg` respectively. | ##### Invalid examples | Command | Reason | |-----------------------------------------|-------------------------------------------------------------------------------------| -| `edit google --phone 8124!@#$` | `--phone` has an [invalid parameter](#appendix-a-acceptable-values-for-parameters) | +| `edit google --phone 8124!@#$`{:.language-sh} | `--phone`{:.language-sh} has an [invalid parameter](#appendix-a-acceptable-values-for-parameters) | ### Applying to organizations - `apply`
Job Application
@@ -429,18 +437,18 @@ Applies to the given organization by creating a job application associated with | Command | Reason | |----------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------| -| `apply 1 --title SWE` | Apply to the **organization** at index 1, for the title of **SWE**. | -| `apply google --title Unit Tester --by 12-12-2023` | Apply to the **organization** with ID of *google** for title of **Unit Tester** by **12-12-2023**. | +| `apply 1 --title SWE`{:.language-sh} | Apply to the **organization** at index 1, for the title of **SWE**. | +| `apply google --title Unit Tester --by 12-12-2023`{:.language-sh} | Apply to the **organization** with ID of *google** for title of **Unit Tester** by **12-12-2023**. | ##### Invalid examples | Command | Reason | |---------------------------------------|-----------------------------------------------------| -| `apply 0 --title SWE` | Invalid index as index starts at 1. | -| `apply 1 --title` | Invalid as `--title` is declared but not specified. | -| `apply 1 --title SWE --by 31-31-2023` | Invalid date for deadline. | +| `apply 0 --title SWE`{:.language-sh} | Invalid index as index starts at 1. | +| `apply 1 --title`{:.language-sh} | Invalid as `--title`{:.language-sh} is declared but not specified. | +| `apply 1 --title SWE --by 31-31-2023`{:.language-sh} | Invalid date for deadline. | -### Editing job applications - `edit --application` +### Editing job applications - `edit --application`{:.language-sh}
Job Application
:trophy: Able to edit job applications associated with an organization in Jobby Intermediate
@@ -459,16 +467,16 @@ Edits the given job application according to the parameters given. | Command | Reason | |--------------------------------------------|-----------------------------------------------------------------| -| `edit --application 1 --title SRE` | Change the title of the job application at index 1 to **SRE**. | -| `edit --application 1 --status pending` | Change the status of job application at index 1 to **pending**. | +| `edit --application 1 --title SRE`{:.language-sh} | Change the title of the job application at index 1 to **SRE**. | +| `edit --application 1 --status pending`{:.language-sh} | Change the status of job application at index 1 to **pending**. | ##### Invalid examples | Command | Reason | |----------------------------------------------|---------------------------------------| -| `edit --application 0 --title SRE` | Invalid index. | -| `edit --application 1` | None of the fields to edit are given. | -| `edit --application 1 --by 31-31-2023` | The date is invalid. | +| `edit --application 0 --title SRE`{:.language-sh} | Invalid index. | +| `edit --application 1`{:.language-sh} | None of the fields to edit are given. | +| `edit --application 1 --by 31-31-2023`{:.language-sh} | The date is invalid. | ### Deleting data - `delete` @@ -487,7 +495,7 @@ The `delete` command allows you to delete contacts and job applications if they delete INDEX/ID [--recursive] ``` Deletes the contact at the given `INDEX` or `ID`. -* `--recursive` flag deletes the associated recruiter contacts and internship applications if the contact to delete is an organization. +* `--recursive`{:.language-sh} flag deletes the associated recruiter contacts and internship applications if the contact to delete is an organization. * If you wish to know more about the requirements for each parameter, check out the [given appendix](#appendix-a-acceptable-values-for-parameters). ##### Valid examples @@ -496,7 +504,7 @@ Deletes the contact at the given `INDEX` or `ID`. |------------------------|----------------------------------------------------------------------------------------| | `delete 1` | This will delete the contact at index 1. | | `delete josh` | This will delete the contact with the **ID** of **josh**. | -| `delete 1 --recursive` | This will delete a contact and all its associated recruiter contacts and applications. | +| `delete 1 --recursive`{:.language-sh} | This will delete a contact and all its associated recruiter contacts and applications. | ##### Invalid examples @@ -504,7 +512,7 @@ Deletes the contact at the given `INDEX` or `ID`. |------------------------|---------------------------------------------------------------------| | `delete 0` | Invalid index, as index starts from 1. | -#### Deleting job applications - `delete --application` +#### Deleting job applications - `delete --application`{:.language-sh} :trophy: Able to delete job applications in Jobby Intermediate @@ -519,13 +527,13 @@ Deletes the job application at the given `INDEX`. | Command | Reason | |--------------------------|---------------------------------------------------------------------| -| `delete --application 1` | This will delete the application at index 1. | +| `delete --application 1`{:.language-sh} | This will delete the application at index 1. | ##### Invalid examples | Command | Reason | |--------------------------|---------------------------------------------------| -| `delete --application 0` | Invalid index, as index starts from 1. | +| `delete --application 0`{:.language-sh} | Invalid index, as index starts from 1. | ### Listing data - `list` @@ -539,18 +547,18 @@ list [--org / --rec / --toapply] ``` Lists all contacts. If you provide a parameter, the contacts listed will be only those that fit the given parameter. -* Supplying `--org` lists only Organizations while supplying `--rec` lists only Recruiters. Specifying neither will list all contacts. +* Supplying `--org`{:.language-sh} lists only Organizations while supplying `--rec`{:.language-sh} lists only Recruiters. Specifying neither will list all contacts. -* Supplying `--toapply` lists Organizations you have not applied to. +* Supplying `--toapply`{:.language-sh} lists Organizations you have not applied to. ##### Valid examples | Command | Reason | |------------------|-------------------------------------------------------------------| | `list` | List all **contacts**. | -| `list --org` | List all **organization contacts**. | -| `list --rec` | List all **recruiter contacts**. | -| `list --toapply` | List all **organization contacts** that have not been applied to. | +| `list --org`{:.language-sh} | List all **organization contacts**. | +| `list --rec`{:.language-sh} | List all **recruiter contacts**. | +| `list --toapply`{:.language-sh} | List all **organization contacts** that have not been applied to. | ### Searching contacts - `find` @@ -596,44 +604,44 @@ sort --FLAG_TO_SORT [--ascending / --descending] ``` Sorts contacts or job applications for you by the specified flag. -`--FLAG_TO_SORT` represents a parameter of the contact or job application (i.e. `--phone` represents the phone number of a contact). +`--FLAG_TO_SORT`{:.language-sh} represents a parameter of the contact or job application (i.e. `--phone`{:.language-sh} represents the phone number of a contact). ##### Supported primary parameters (only 1 may be provided) ###### Fields for Contacts -* `--address` - Will sort alphabetically. -* `--email` - Will sort alphabetically. -* `--id` - Will sort alphabetically. -* `--name` - Will sort alphabetically. -* `--phone` - Will sort alphabetically. -* `--url` - Will sort alphabetically. +* `--address`{:.language-sh} - Will sort alphabetically. +* `--email`{:.language-sh} - Will sort alphabetically. +* `--id`{:.language-sh} - Will sort alphabetically. +* `--name`{:.language-sh} - Will sort alphabetically. +* `--phone`{:.language-sh} - Will sort alphabetically. +* `--url`{:.language-sh} - Will sort alphabetically. ###### Fields for Job Applications -* `--by` - Will sort chronologically. -* `--stage` - Will sort by stage order. -* `--stale` - Will sort chronologically. -* `--status` - Will sort by status order. -* `--title` - Will sort alphabetically. +* `--by`{:.language-sh} - Will sort chronologically. +* `--stage`{:.language-sh} - Will sort by stage order. +* `--stale`{:.language-sh} - Will sort chronologically. +* `--status`{:.language-sh} - Will sort by status order. +* `--title`{:.language-sh} - Will sort alphabetically. ###### Resetting the sort order -* `--none` - Will reset the sorting order of Contacts and Job Applications. +* `--none`{:.language-sh} - Will reset the sorting order of Contacts and Job Applications. ##### Supported secondary parameters ###### Changing the sort order -* `--ascending` - The specified flag will sort in ascending order. -* `--descending` - The specified flag will sort in descending order. +* `--ascending`{:.language-sh} - The specified flag will sort in ascending order. +* `--descending`{:.language-sh} - The specified flag will sort in descending order. -* If neither `--ascending` or `--descending` are provided, the list will be sorted in ascending order by default. +* If neither `--ascending`{:.language-sh} or `--descending`{:.language-sh} are provided, the list will be sorted in ascending order by default. -* Neither `--ascending` nor `--descending` may be specified if the flag is `--none`. +* Neither `--ascending`{:.language-sh} nor `--descending`{:.language-sh} may be specified if the flag is `--none`{:.language-sh}. * Sorting will work even if no Contacts or Job Applications exist. In that case, nothing will happen. ##### Sample demonstration -* To order your Job Applications by order of earliest deadline, you can use the command `sort --by`. +* To order your Job Applications by order of earliest deadline, you can use the command `sort --by`{:.language-sh}. * In the Application Details section of Jobby, you should see your Job Applications now ordered by most urgent deadline.
@@ -644,19 +652,19 @@ Sorts contacts or job applications for you by the specified flag. | Command | Reason | |-----------------------------|------------------------------------------------------------------------------------------------------------| -| `sort --title --ascending` | Sort **job applications** by title, in ascending alphabetical order. | -| `sort --url` | Sort **contacts** by url, in the default order - ascending alphabetical. | -| `sort --stale --descending` | Sort **job applications** by last updated time, in reverse chronological order, from most recent to least. | -| `sort --none` | Reset the sorting order of **contacts** and **job applications**. | +| `sort --title --ascending`{:.language-sh} | Sort **job applications** by title, in ascending alphabetical order. | +| `sort --url`{:.language-sh} | Sort **contacts** by url, in the default order - ascending alphabetical. | +| `sort --stale --descending`{:.language-sh} | Sort **job applications** by last updated time, in reverse chronological order, from most recent to least. | +| `sort --none`{:.language-sh} | Reset the sorting order of **contacts** and **job applications**. | ##### Invalid examples | Command | Reason | |----------------------------|---------------------------------------------| | `sort` | No field provided. | -| `sort --org` | Invalid field. | -| `sort --none --descending` | `--none` and `--descending` both specified. | -| `sort --title --name` | More than 1 field specified. | +| `sort --org`{:.language-sh} | Invalid field. | +| `sort --none --descending`{:.language-sh} | `--none`{:.language-sh} and `--descending`{:.language-sh} both specified. | +| `sort --title --name`{:.language-sh} | More than 1 field specified. | ### Reminding about deadlines - `remind` @@ -672,7 +680,7 @@ remind --earliest / --latest Reminds you of upcoming deadlines for job applications. ##### Sample demonstration -* To see your application deadlines from the earliest to latest, use the command `remind --earliest`. +* To see your application deadlines from the earliest to latest, use the command `remind --earliest`{:.language-sh}. ![Remind Earliest](images/starter-guide/remind-earliest.jpg) @@ -680,8 +688,8 @@ Reminds you of upcoming deadlines for job applications. | Command | Reason | |---------------------|--------------------------------------------------------------------------------------| -| `remind --earliest` | List the application deadlines in order of urgency, from earliest to latest. | -| `remind --latest` | List the application deadlines in order of reverse urgency, from latest to earliest. | +| `remind --earliest`{:.language-sh} | List the application deadlines in order of urgency, from earliest to latest. | +| `remind --latest`{:.language-sh} | List the application deadlines in order of reverse urgency, from latest to earliest. | ##### Invalid examples @@ -707,10 +715,9 @@ Shows a message explaining how to access the help page. ### Clearing all data - `clear`
Organization Recruiter Job Application
+:trophy: How to clear all contacts and job applications in Jobby Intermediate
:warning: The deletion of all data is permanent and there is no way to undo it. -:trophy: How to clear all contacts and job applications in Jobby Intermediate - ##### Format ```sh clear @@ -730,6 +737,17 @@ exit Exits the program. +### Saving the data + +Jobby's data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually. + +### Editing the data file + +Jobby's data are saved automatically as a JSON file `[JAR file location]/data/jobby.json`. Advanced users are welcome to update data directly by editing that data file. + +
+:warning: **Caution:** If your changes to the data file makes its format invalid, Jobby will discard all data and start with an empty data file at the next run. Hence, it is recommended to take a backup of the file before editing it. +
-------------------------------------------------------------------------------------------------------------------- @@ -739,13 +757,13 @@ Exits the program. | Action | Format, Examples | |----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **Add Organization** | `add --org --name NAME [--id ID] [--phone NUMBER] [--email EMAIL] [--url URL] [--address ADDRESS] [--tag TAG]...`
e.g., `add --org --name NUS --phone 0123456789 --email example@nus.edu.sg --url https://www.nus.edu.sg/` | -| **Add Recruiter** | `add --rec --name NAME [--id ID] [--oid ORG_ID] [--phone NUMBER] [--email EMAIL] [--url URL] [--address ADDRESS] [--tag TAG]...`
e.g., `add --rec --name John Doe --oid paypal-sg` | -| **Delete Contact** | `delete INDEX/ID [--recursive]`
e.g., `delete 3`, `delete id-55tg` | -| **Edit Contact** | `edit INDEX/ID [--name NAME] [--id ID] [--phone PHONE] [--email EMAIL] [--url URL] [--address ADDRESS] [--tag TAG]...` | +| **Add Organization** | `add --org --name NAME [--id ID] [--phone NUMBER] [--email EMAIL] [--url URL] [--address ADDRESS] [--tag TAG]...`{:.language-sh}
e.g., `add --org --name NUS --phone 0123456789 --email example@nus.edu.sg --url https://www.nus.edu.sg/`{:.language-sh} | +| **Add Recruiter** | `add --rec --name NAME [--id ID] [--oid ORG_ID] [--phone NUMBER] [--email EMAIL] [--url URL] [--address ADDRESS] [--tag TAG]...`{:.language-sh}
e.g., `add --rec --name John Doe --oid paypal-sg`{:.language-sh} | +| **Delete Contact** | `delete INDEX/ID [--recursive]`{:.language-sh}
e.g., `delete 3`, `delete id-55tg` | +| **Edit Contact** | `edit INDEX/ID [--name NAME] [--id ID] [--phone PHONE] [--email EMAIL] [--url URL] [--address ADDRESS] [--tag TAG]...`{:.language-sh} | | **Find** | `find KEYWORD [MORE_KEYWORDS]`
e.g., `find James Jake` | -| **List** | `list [--org/--rec/--toapply]` | -| **Sort Contacts** | `sort --address/--email/--id/--name/--phone/--url [--ascending/--descending]` | +| **List** | `list [--org / --rec / --toapply]`{:.language-sh} | +| **Sort Contacts** | `sort --address / --email / --id / --name / --phone / --url [--ascending / --descending]`{:.language-sh} | ### Commands for Handling Job Applications @@ -754,10 +772,10 @@ Exits the program. | Action | Format, Examples | |------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **Delete Application** | `delete --application INDEX`
e.g., `delete --application 2` | -| **Edit Application** | `edit --application INDEX [--title TITLE] [--description DESCRIPTION] [--by DEADLINE] [--status STATUS] [--stage STAGE]`
e.g., `edit --application 2 --title Analyst` | -| **Apply** | `apply INDEX/ID --title TITLE [--description DESCRIPTION] [--by DEADLINE] [--stage STAGE] [--status STATUS]` | -| **Sort Applications** | `sort --by/--stage/--stale/--status/--title [--ascending/--descending]` | +| **Delete Application** | `delete --application INDEX`{:.language-sh}
e.g., `delete --application 2`{:.language-sh} | +| **Edit Application** | `edit --application INDEX [--title TITLE] [--description DESCRIPTION] [--by DEADLINE] [--status STATUS] [--stage STAGE]`{:.language-sh}
e.g., `edit --application 2 --title Analyst`{:.language-sh} | +| **Apply** | `apply INDEX/ID --title TITLE [--description DESCRIPTION] [--by DEADLINE] [--stage STAGE] [--status STATUS]`{:.language-sh} | +| **Sort Applications** | `sort --by / --stage / --stale / --status / --title [--ascending / --descending]`{:.language-sh} | ### Other Commands @@ -772,13 +790,14 @@ Exits the program. ## Glossary -| Term | Definition | -|------|------------| -| **Top Level Domain** | A Top Level Domain (TLD) is the part of the website address where it comes after the last dot (i.e. ".com", ".org", ".net") and before the first slash. (E.g. www.example.**com**/path). | -| **Whitespace** | In the context of this application, a whitespace is any number of spaces or tabs that is in the input. | -| **Contact** | A contact in Jobby is can be an **organization** or a **recruiter**. | -| **Substring** | A substring is a contiguous sequence of characters within a string.
e.g. "pp" is a substring of "apple", "mac" is a substring of "macDonald" and "intimacy" | - +| Term | Definition | +|----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **Index** | An index is a number that is used to identify a contact or job application in a list.

(e.g. `2` would be the index of the contact labelled **2.** in the contacts list). | +| **Whitespace** | In the context of this application, a whitespace is any number of spaces that is in the input. | +| **Contact** | A contact in Jobby can be an Organization or a Recruiter. | +| **Substring** | A substring is a contiguous sequence of characters within a string

(e.g. "pp" is a substring of "apple", "mac" is a substring of "macDonald" and "intimacy"). | +| **Subsequence** | A subsequence is a sequence obtainable from another sequence by deleting some or no elements without changing the order of the remaining elements

(e.g. "abc", "1b2", "123" are all subsequences of "a1b2c3"). | +| **Top Level Domain** | A Top Level Domain (TLD) is the part of the website address where it comes after the last dot (i.e. ".com", ".org", ".net") and before the first slash

(e.g. www.example.**com**/path). | ## Appendices @@ -786,20 +805,20 @@ Exits the program. | Parameter | Used by | Requirements | Examples | |-----------|---------|--------------|----------| -| `INDEX` | [`edit`](#editing-contacts---edit)
[`apply`](#applying-to-organizations---apply)
[`edit --application`](#editing-job-applications---edit---application)
[`delete`](#deleting-contacts---delete)
[`delete --application`](#deleting-job-applications---delete---application) | A valid index can accept any positive integer up to the number of items displayed in the contact or job application list where applicable. | `1`
`10` | -| `NAME` | [`add --org`](#adding-organizations---add---org)
[`add --rec`](#adding-recruiters---add---rec)
[`edit`](#editing-contacts---edit) | A valid name can accept any non-empty value. | `Ryan Koh`
`小明` | -| `ID` | [`add --org`](#adding-organizations---add---org)
[`add --rec`](#adding-recruiters---add---rec)
[`edit`](#editing-contacts---edit)
[`apply`](#applying-to-organizations---apply)
[`delete`](#deleting-contacts---delete) | A valid ID has to start with a letter.

It can consist of alphanumeric and basic symbols (i.e. `a-z`, `A-Z`, `0-9`, `-`, `_`) | `woogle123`
`ryan_soc-rec` | -| `NUMBER` | [`add --org`](#adding-organizations---add---org)
[`add --rec`](#adding-recruiters---add---rec)
[`edit`](#editing-contacts---edit) | A valid phone number can consist of only numbers with no whitespace.

It must be at least 3 digits. | `999`
`91824137` | -| `EMAIL` | [`add --org`](#adding-organizations---add---org)
[`add --rec`](#adding-recruiters---add---rec)
[`edit`](#editing-contacts---edit) | A valid email should be in the form of `local-part@domain` where the `local-part` and `domain` must be separated by a single **@**.

The `local-part` can consist of any character except whitespace.

The `domain` name can comprise of one or more labels separated by periods, and each label can include any character except whitespace. The last `domain` label must be a minimum of two characters long. | `ryankoh@nus`
`ryan-koh@nus.edu.sg` | -| `URL` | [`add --org`](#adding-organizations---add---org)
[`add --rec`](#adding-recruiters---add---rec)
[`edit`](#editing-contacts---edit) | A valid url should include a part in the form of `domain.tld` where the `domain` and the `tld` (top level domain) must be separated by a period. | `example.com`
`example.more.com`
`https://example.com`
`example.com/more` | -| `ADDRESS`| [`add --org`](#adding-organizations---add---org)
[`add --rec`](#adding-recruiters---add---rec)
[`edit`](#editing-contacts---edit) | A valid address can accept any non-empty value.

For a contact, it designates its physical address. | `21 Lower Kent Ridge Rd` | -| `TAG` | [`add --org`](#adding-organizations---add---org)
[`add --rec`](#adding-recruiters---add---rec)
[`edit`](#editing-contacts---edit) | A valid tag can consist of only alphanumeric characters. | `internship`
`network`
`parttime`
`jobPortal` | -| `ORG_ID` | [`add --rec`](#adding-recruiters---add---rec) | A valid organization ID is subject to the same requirements as the ID parameter.

It must belong to an Organization contact in the address book. | `woogle123`
`meta_sg-1` | -| `TITLE` | [`apply`](#applying-to-organizations---apply)
[`edit --application`](#editing-job-applications---edit---application) | A valid title can accept multiple words separated with spaces, as long as the characters are alphanumeric. | `Software Engineer`
`Level 3 Engineer` | -| `DESCRIPTION` | [`apply`](#applying-to-organizations---apply)
[`edit --application`](#editing-job-applications---edit---application) | A valid description can accept any non-empty value. | `Senior Role`
`Hourly rate: $25` | -| `DEADLINE` | [`apply`](#applying-to-organizations---apply)
[`edit --application`](#editing-job-applications---edit---application) | A valid deadline should be a date in the form of `DD-MM-YYYY`.

The day (`DD`) and month (`MM`) can be either single or double digits. | `09-02-2022`
`9-2-2022`
`19-11-2022` | -| `STAGE` | [`apply`](#applying-to-organizations---apply)
[`edit --application`](#editing-job-applications---edit---application) | A valid job application stage can accept only one of the three values: `resume`, `online assessment`, `interview`.

The values are ranked in the order shown. | `resume`
`online assessment`
`interview` | -| `STATUS` | [`apply`](#applying-to-organizations---apply)
[`edit --application`](#editing-job-applications---edit---application) | A valid job application status can accept only one of the four values: `pending`, `offered`, `accepted`, `turned down`.

The values are ranked in the order shown. | `pending`
`offered`
`accepted`
`turned down` | +| `INDEX` | [`edit`](#editing-contacts---edit)

[`apply`](#applying-to-organizations---apply)

[`edit --application`{:.language-sh}](#editing-job-applications---edit---application)

[`delete`](#deleting-contacts---delete)

[`delete --application`{:.language-sh}](#deleting-job-applications---delete---application) | A valid index can accept any positive integer up to the number of items displayed in the contact or job application list where applicable. | `1`
`10` | +| `NAME` | [`add --org`{:.language-sh}](#adding-organizations---add---org)

[`add --rec`{:.language-sh}](#adding-recruiters---add---rec)

[`edit`](#editing-contacts---edit) | A valid name can accept any non-empty value. | `Ryan Koh`
`小明` | +| `ID` | [`add --org`{:.language-sh}](#adding-organizations---add---org)

[`add --rec`{:.language-sh}](#adding-recruiters---add---rec)

[`edit`](#editing-contacts---edit)

[`apply`](#applying-to-organizations---apply)

[`delete`](#deleting-contacts---delete) | A valid ID has to start with a letter.

It can consist of alphanumeric and basic symbols (i.e. `a-z`, `A-Z`, `0-9`, `-`, `_`) | `woogle123`
`ryan_soc-rec` | +| `NUMBER` | [`add --org`{:.language-sh}](#adding-organizations---add---org)

[`add --rec`{:.language-sh}](#adding-recruiters---add---rec)

[`edit`](#editing-contacts---edit) | A valid phone number can consist of only numbers with no whitespace.

It must be at least 3 digits. | `999`
`91824137` | +| `EMAIL` | [`add --org`{:.language-sh}](#adding-organizations---add---org)

[`add --rec`{:.language-sh}](#adding-recruiters---add---rec)

[`edit`](#editing-contacts---edit) | A valid email should be in the form of `local-part@domain` where the `local-part` and `domain` must be separated by a single **@**.

The `local-part` can consist of any character except whitespace.

The `domain` name can comprise of one or more labels separated by periods, and each label can include any character except whitespace. The last `domain` label must be a minimum of two characters long. | `ryankoh@nus`
`ryan-koh@nus.edu.sg` | +| `URL` | [`add --org`{:.language-sh}](#adding-organizations---add---org)

[`add --rec`{:.language-sh}](#adding-recruiters---add---rec)

[`edit`](#editing-contacts---edit) | A valid url should include a part in the form of `domain.tld` where the `domain` and the `tld` (top level domain) must be separated by a period. | `example.com`
`example.more.com`
`https://example.com`
`example.com/more` | +| `ADDRESS`| [`add --org`{:.language-sh}](#adding-organizations---add---org)

[`add --rec`{:.language-sh}](#adding-recruiters---add---rec)

[`edit`](#editing-contacts---edit) | A valid address can accept any non-empty value.

For a contact, it designates its physical address. | `21 Lower Kent Ridge Rd` | +| `TAG` | [`add --org`{:.language-sh}](#adding-organizations---add---org)

[`add --rec`{:.language-sh}](#adding-recruiters---add---rec)

[`edit`](#editing-contacts---edit) | A valid tag can consist of only alphanumeric characters. | `internship`
`network`
`parttime`
`jobPortal` | +| `ORG_ID` | [`add --rec`{:.language-sh}](#adding-recruiters---add---rec) | A valid organization ID is subject to the same requirements as the ID parameter.

It must belong to an Organization contact in the address book. | `woogle123`
`meta_sg-1` | +| `TITLE` | [`apply`](#applying-to-organizations---apply)

[`edit --application`{:.language-sh}](#editing-job-applications---edit---application) | A valid title can accept multiple words separated with spaces, as long as the characters are alphanumeric. | `Software Engineer`
`Level 3 Engineer` | +| `DESCRIPTION` | [`apply`](#applying-to-organizations---apply)

[`edit --application`{:.language-sh}](#editing-job-applications---edit---application) | A valid description can accept any non-empty value. | `Senior Role`
`Hourly rate: $25` | +| `DEADLINE` | [`apply`](#applying-to-organizations---apply)

[`edit --application`{:.language-sh}](#editing-job-applications---edit---application) | A valid deadline should be a date in the form of `DD-MM-YYYY`.

The day (`DD`) and month (`MM`) can be either single or double digits. | `09-02-2022`
`9-2-2022`
`19-11-2022` | +| `STAGE` | [`apply`](#applying-to-organizations---apply)

[`edit --application`{:.language-sh}](#editing-job-applications---edit---application) | A valid job application stage can accept only one of the three values: `resume`, `online assessment`, `interview`.

The values are ranked in the order shown. | `resume`
`online assessment`
`interview` | +| `STATUS` | [`apply`](#applying-to-organizations---apply)

[`edit --application`{:.language-sh}](#editing-job-applications---edit---application) | A valid job application status can accept only one of the four values: `pending`, `offered`, `accepted`, `turned down`.

The values are ranked in the order shown. | `pending`
`offered`
`accepted`
`turned down` | | `KEYWORD` | [`find`](#searching-contacts---find) | A valid keyword is a single word that can accept any non-empty value. | `software`
`Ryan` | @@ -829,6 +848,6 @@ Exits the program. 1. **When using multiple screens**, if you move the application to a secondary screen, and later switch to using only the primary screen, the GUI will open off-screen. The remedy is to delete the _preferences.json_ file created by the application before running the application again. -2. **When requesting to sort applications after a call to `list --rec`**, the command will succeed but display nothing, since no organizations are currently listed, and so no linked applications will display. The remedy is to call `list` before sorting applications and calling the sort command once more. +2. **When requesting to sort applications after a call to `list --rec`{:.language-sh}**, the command will succeed but display nothing, since no organizations are currently listed, and so no linked applications will display. The remedy is to call `list` before sorting applications and calling the sort command once more. -3. Parameter names use either the `-` or `--` prefix, but **all commands as of the current version only use the `--` prefix.** The `-` prefix is currently unused, but in future updates it may become relevant. +3. Parameter names use either the `-` or `--` prefix, but **all commands as of the current version only use the `--` prefix.** While the `-` prefix is currently unused, it is reserved (so user input cannot take that format), and it will be relevant in future updates. diff --git a/docs/_sass/minima/_layout.scss b/docs/_sass/minima/_layout.scss index 0052216d00f..7e3ffb77e6c 100644 --- a/docs/_sass/minima/_layout.scss +++ b/docs/_sass/minima/_layout.scss @@ -370,6 +370,8 @@ page-break-before: always !important; } - + tr { + page-break-inside: avoid; + } } diff --git a/docs/_sass/minima/custom-styles.scss b/docs/_sass/minima/custom-styles.scss index 43f754305e7..1da9573ec20 100644 --- a/docs/_sass/minima/custom-styles.scss +++ b/docs/_sass/minima/custom-styles.scss @@ -56,6 +56,7 @@ img.emoji { } // Syntax highlighting term overrides +// - Multiline .language-sh, .language-bash, .language-shell { .highlight code { .nb { @@ -68,6 +69,13 @@ img.emoji { } } } +// - Inline +code.language-plaintext, code.language-sh, code.language-bash, code.language-shell { + .nt { + /* do not wrap --flags */ + white-space: nowrap; + } +} // Pill styles .pill { @@ -83,6 +91,8 @@ img.emoji { font-size: 75%; vertical-align: text-bottom; + display: inline-block; + .pill { /* so nesting pills will look the same */ font-size: 100%; @@ -139,10 +149,8 @@ img.emoji { border-color: #e8e6e5; color: #444444; - padding: 4px 12px; padding-right: 2px; margin: 4px 2px; - display: inline-block; &.jobby-data-class:not(:first-child) { margin-left: 0; diff --git a/docs/diagrams/AutocompleteClasses.puml b/docs/diagrams/AutocompleteClasses.puml new file mode 100644 index 00000000000..dfed450f38b --- /dev/null +++ b/docs/diagrams/AutocompleteClasses.puml @@ -0,0 +1,61 @@ +@startuml +!include style.puml +skinparam arrowThickness 1.2 +skinparam arrowColor LOGIC_COLOR_T4 +skinparam classBackgroundColor LOGIC_COLOR + +skinparam class { + 'workaround to render generics properly without breaking the rest + BorderColor LOGIC_COLOR + BorderThickness 0 + + StereotypeFontColor LOGIC_COLOR_T2 + StereotypeFontSize 14 +} + +'hidden boxes +class " " as HiddenOutside1 <> +class " " as HiddenOutside2 <> +skinparam class { + BorderColor<> #FFFFFF + BackgroundColor<> #FFFFFF + StereotypeFontColor<> #FFFFFF + StereotypeFontSize<> 1 +} + +'packages +package Autocomplete as AutocompletePackage <> { + class AutocompleteGenerator + class AutocompleteSupplier + + class "AutocompleteItemSet" as AutocompleteItemSet + class "<>\nAutocompleteConstraint" as AutocompleteConstraint + + class "<>\nFlagValueSupplier" as FlagValueSupplier + class PartitionedCommand +} + +package Model as ModelPackage { +} +package "Parser classes" <> { + class Flag +} + +'relationships +HiddenOutside1 .down.> AutocompleteGenerator +HiddenOutside2 .right.> AutocompleteSupplier + +AutocompleteGenerator -down-> "1" AutocompleteSupplier : uses > + +AutocompleteSupplier --> "1" AutocompleteItemSet +AutocompleteSupplier --> "*" FlagValueSupplier +AutocompleteSupplier ..> Flag + +AutocompleteItemSet --> "*" AutocompleteConstraint : contains > + +AutocompleteGenerator ..> PartitionedCommand : creates > +FlagValueSupplier .right.> PartitionedCommand : uses > + +FlagValueSupplier ..down.> ModelPackage : uses > +PartitionedCommand ..down.> Flag +@enduml diff --git a/docs/diagrams/LogicClassDiagram.puml b/docs/diagrams/LogicClassDiagram.puml index a57720890ee..920760fde92 100644 --- a/docs/diagrams/LogicClassDiagram.puml +++ b/docs/diagrams/LogicClassDiagram.puml @@ -6,7 +6,7 @@ skinparam classBackgroundColor LOGIC_COLOR package Logic as LogicPackage { -Class AddressBookParser +Class AppParser Class XYZCommand Class CommandResult Class "{abstract}\nCommand" as Command @@ -27,8 +27,8 @@ Class HiddenOutside #FFFFFF HiddenOutside ..> Logic LogicManager .right.|> Logic -LogicManager -right->"1" AddressBookParser -AddressBookParser ..> XYZCommand : creates > +LogicManager -right->"1" AppParser +AppParser ..> XYZCommand : creates > XYZCommand -up-|> Command LogicManager .left.> Command : executes > diff --git a/docs/diagrams/style.puml b/docs/diagrams/style.puml index f7d7347ae84..7770580f0b7 100644 --- a/docs/diagrams/style.puml +++ b/docs/diagrams/style.puml @@ -31,6 +31,12 @@ !define STORAGE_COLOR_T3 #806600 !define STORAGE_COLOR_T2 #544400 +!define AUTOCOMPLETE_COLOR #3333C4 +!define AUTOCOMPLETE_COLOR_T1 #C8C8FA +!define AUTOCOMPLETE_COLOR_T2 #6A6ADC +!define AUTOCOMPLETE_COLOR_T3 #1616B0 +!define AUTOCOMPLETE_COLOR_T4 #101086 + !define USER_COLOR #000000 skinparam Package { diff --git a/docs/images/AutocompleteClasses.png b/docs/images/AutocompleteClasses.png new file mode 100644 index 00000000000..28787acc40c Binary files /dev/null and b/docs/images/AutocompleteClasses.png differ diff --git a/docs/images/LogicClassDiagram.png b/docs/images/LogicClassDiagram.png index e3b784310fe..d27e6627eb1 100644 Binary files a/docs/images/LogicClassDiagram.png and b/docs/images/LogicClassDiagram.png differ diff --git a/docs/index.md b/docs/index.md index 6cc225a49e5..16bbf079408 100644 --- a/docs/index.md +++ b/docs/index.md @@ -20,4 +20,4 @@ title: Jobby **Acknowledgements** -* Libraries used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5) +Refer to the [Developer Guide's Acknowledgements section](DeveloperGuide.html#acknowledgements). diff --git a/docs/team/wxwern.md b/docs/team/wxwern.md index 3b06e43a731..24a0d84732a 100644 --- a/docs/team/wxwern.md +++ b/docs/team/wxwern.md @@ -7,103 +7,64 @@ title: Wern's Project Portfolio Page ### Project: Jobby -Jobby is a desktop application used for tracking job applications. +Jobby is a desktop application used for managing your job applications and associated organization and recruiter contacts. Given below are my contributions to the project. -* **New Feature**: +* **New Feature**: Command Autocompletion ([PR #63](https://github.com/AY2324S1-CS2103T-W08-3/tp/pull/63)) - * **Command Autocompletion** - - * This allows users to autocomplete their commands, just like command terminals or programming IDEs, such as by pressing **TAB**. + * This allows users to autocomplete their commands, just like command terminals or programming IDEs, such as by pressing **TAB**, and even undo when you **BACKSPACE**. * Like an IDE, it does a _subsequence_ match, so typing `-dsp` then **TAB** can select `--description`, allowing for fast disambiguation from another similar term like `--descending`. - * As a bonus, it also supports undoing with **BACKSPACE**. It keeps a complete undo history, so you can do multiple undos for the same command as long if you did not move your text cursor from the end point. - - * **Rationale:** - - * When developing Jobby, we started having too many command parameters with clashing prefixes, so it no longer make sense to offer single letter parameter names. - - * Memorizing multi-letter abbreviations for a bunch of parameter is more difficult than a full name. - - * However, a full parameter name takes much longer to type, which means it's no longer optimized for fast typists. - - * Hence, autocompletion was implemented to resolve all of these concerns. - - * **Implementation:** The internal implementation is written completely from scratch. This allows it to: - - * specifically parse our custom command structure, and - - * dynamically determine what should or should not be suggested next based on a given set of rules, or available data in the app. - - * **UI:** The autocompletion UI is adapted from [@floralvikings's AutoCompleteTextBox.java](https://gist.github.com/floralvikings/10290131) with significant enhancements. These include: + * **Rationale:** It allows for faster command input, and reduces command syntax memorization. - * overhauling the implementation in modern Java syntax and JavaFX method calls, + * **Implementation:** The internal implementation is written completely from scratch to support our custom formats - more information available in the Developer Guide. - * modified the implementation idea to support for our custom `Stream`-based autocompletion result suppliers, - - * integrating it directly within FXML, - - * improved the UI to support adding indicators for invoking the best (first-in-list) autocomplete result, - - * added support for auto-highlighting only the postfix term that is suggested for improved glancability, - - * added support for external parties to invoke autocompletion (e.g., via preferred key events or UI buttons), and - - * added support for undoing autocompleted results (and similarly for external parties to invoke undo). + * **UI:** The autocompletion UI is adapted from [@floralvikings's AutoCompleteTextBox.java](https://gist.github.com/floralvikings/10290131). The reference text box only has a barebones context menu, but significant enhancements has been made to the styling and behavior to improve readability and UX (like partial term highlighting and undo support), which can be seen when using Jobby. * **Code contributed**: [RepoSense link](https://nus-cs2103-ay2324s1.github.io/tp-dashboard/?search=AY2324S1-CS2103T-W08-3&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2023-09-22&tabOpen=true&tabType=authorship&tabAuthor=wxwern&tabRepo=AY2324S1-CS2103T-W08-3%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~other~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false&authorshipIsIgnoredFilesChecked=false) * **Project management**: - * To be added... + * Configuring the Issue Tracker Tags and Milestones for the project. + * Setting up GitHub Actions for the project, including Java CI, CodeCov, GitHub Pages, PR Checks. + * Managed releases [v1.2 and v1.3](https://github.com/AY2324S1-CS2103T-W08-3/tp/releases). + * Styling the website for optimal readability and print formatting, including: -* **Enhancements to existing features**: + * Styling headers with improved spacing, typography and color for increased readability. - * Revamped the parameter syntax to use a prefix of `--param`. + * Tweaking the page-break rules for different elements, such as preventing page breaks on crucial boxes or enforcing page breaks immediately after certain headers. - * This allows for improved autocompletion UX as compared to `param/`, since we can immediately determine if the user intends to type it based on the first character. + * Styling custom unified UG elements, like the following: + * :trophy: How to perform a task :information_source: An info pill :warning: A warning pill :warning: A danger pill + * Organization Recruiter Job Application + * Beginner Intermediate Expert

- * It is also much less likely to clash with an existing user input. +* **Enhancements to existing features**: + * Revamped the parameter syntax to use a prefix of `--param`. + * This allows for improved autocompletion UX as compared to `param/`, since we can immediately determine if the user intends to type a parameter based on the first character. + * It is also much less likely to clash with an existing user input.

* Swapped out random ID generation with an implementation to derive IDs from an input name. - * This allows for improved UX when editing details that require an ID, combined with autocomplete integration. - - * Previously, it was implemented by another team member by generating random RFC 4122 UUIDs instead. - - * Now, random IDs are derived from the name, e.g., `google-sg-a8b3fe` from an input of `Google SG`. + * e.g., `google-sg-a8b3fe` can be derived from an input of `Google SG`.

* **Documentation**: * User Guide: - - * Added a simpler command syntax introduction. - - * Improved explanation of command symbols used in the guide. - + * Added a structured command syntax introduction, and instructions to interpret command formats. * Added usage guides for command autocompletion. - - * Styling the website for improved overall glancability and support for fully-automated print formatting, including: - - * Styling headers with improved spacing, typography and color for increased readability. - - * Tweaking the page-break rules for different elements, such as preventing page breaks on crucial boxes or enforcing page breaks immediately after certain headers. - - * Styling custom unified UG elements for readability, like the following: - * :trophy: How to perform a task :information_source: An info message pill - * :warning: A warning message pill :warning: A danger message pill - * Beginner Intermediate Expert - * Organization Recruiter Job Application - + * Styling the website for improved overall readability and automated print formatting (see above in Project Management).

* Developer Guide: - - * Added a quick explanation of how "Parser classes" may obtain the properties of our custom `Flag`s (like `--name`) from a command via `ArgumentMultimap` and `ArgumentTokenizer`. - - * Added a high-level end-to-end explanation of Jobby's internal autocomplete implementation and interactions. + * Integrated explanations of how "Autocomplete classes" work in the context of the `Logic` package. + * Updated how `AppParser` (formerly `AddressBookParser`) operates in the context of our app, since we now dynamically look up details and also support autocompletion. + * Added a complete high-level explanation of Jobby's internal autocomplete implementation. + * Added use cases for autocompletion.

* **Community**: - * To be added... + * Detailed PR Reviews (e.g., [#32](https://github.com/AY2324S1-CS2103T-W08-3/tp/pull/32), [#34](https://github.com/AY2324S1-CS2103T-W08-3/tp/pull/34), [#39](https://github.com/AY2324S1-CS2103T-W08-3/tp/pull/39), [#69](https://github.com/AY2324S1-CS2103T-W08-3/tp/pull/69), [#183](https://github.com/AY2324S1-CS2103T-W08-3/tp/pull/183)) + * Forum contributions (e.g., [#30](https://github.com/nus-cs2103-AY2324S1/forum/issues/30), [#103](https://github.com/nus-cs2103-AY2324S1/forum/issues/103)) + * Reported bugs and suggestions for other teams (e.g., during PE-D)
diff --git a/src/main/java/seedu/address/logic/autocomplete/AutocompleteGenerator.java b/src/main/java/seedu/address/logic/autocomplete/AutocompleteGenerator.java index d7f32a6b431..5db6a0a6e06 100644 --- a/src/main/java/seedu/address/logic/autocomplete/AutocompleteGenerator.java +++ b/src/main/java/seedu/address/logic/autocomplete/AutocompleteGenerator.java @@ -150,14 +150,14 @@ private static Optional> getPossibleValues( ) { Optional flagString = command.getLastConfirmedFlagString(); if (flagString.isEmpty()) { - return supplier.getValidValues(null, command, model); + return supplier.getValidValuesForFlag(null, command, model); } Optional targetFlag = Flag.findMatch( flagString.get(), supplier.getAllPossibleFlags().toArray(Flag[]::new) ); - return targetFlag.flatMap(f -> supplier.getValidValues(f, command, model)); + return targetFlag.flatMap(f -> supplier.getValidValuesForFlag(f, command, model)); } } diff --git a/src/main/java/seedu/address/logic/autocomplete/AutocompleteSupplier.java b/src/main/java/seedu/address/logic/autocomplete/AutocompleteSupplier.java index b35f68974e8..1c259b387d6 100644 --- a/src/main/java/seedu/address/logic/autocomplete/AutocompleteSupplier.java +++ b/src/main/java/seedu/address/logic/autocomplete/AutocompleteSupplier.java @@ -112,7 +112,7 @@ public Set getOtherPossibleFlagsAsideFromFlagsPresent(Set flagsPrese * @param currentCommand The current command structure. This should not be null. * @param model The model to be supplied for generation. This may be null if the model is unavailable. */ - public Optional> getValidValues(Flag flag, PartitionedCommand currentCommand, Model model) { + public Optional> getValidValuesForFlag(Flag flag, PartitionedCommand currentCommand, Model model) { try { return Optional.ofNullable( this.values.getOrDefault(flag, (c, m) -> Stream.empty()) diff --git a/src/test/java/seedu/address/logic/autocomplete/AutocompleteSupplierTest.java b/src/test/java/seedu/address/logic/autocomplete/AutocompleteSupplierTest.java index c4a41af0b34..26e95d3bae7 100644 --- a/src/test/java/seedu/address/logic/autocomplete/AutocompleteSupplierTest.java +++ b/src/test/java/seedu/address/logic/autocomplete/AutocompleteSupplierTest.java @@ -130,19 +130,19 @@ public void getValidValues() { var emptyCommand = new PartitionedCommand(""); // Should use the lambda's values - assertEquals(LIST_A, supplier.getValidValues(FLAG_A, emptyCommand, null) + assertEquals(LIST_A, supplier.getValidValuesForFlag(FLAG_A, emptyCommand, null) .get().collect(Collectors.toList())); - assertEquals(LIST_B, supplier.getValidValues(FLAG_B, emptyCommand, null) + assertEquals(LIST_B, supplier.getValidValuesForFlag(FLAG_B, emptyCommand, null) .get().collect(Collectors.toList())); - assertEquals(LIST_C, supplier.getValidValues(FLAG_C, emptyCommand, null) + assertEquals(LIST_C, supplier.getValidValuesForFlag(FLAG_C, emptyCommand, null) .get().collect(Collectors.toList())); - assertEquals(LIST_EMPTY, supplier.getValidValues(FLAG_D, emptyCommand, null) + assertEquals(LIST_EMPTY, supplier.getValidValuesForFlag(FLAG_D, emptyCommand, null) .get().collect(Collectors.toList())); - assertEquals(LIST_EMPTY, supplier.getValidValues(FLAG_E, emptyCommand, null) + assertEquals(LIST_EMPTY, supplier.getValidValuesForFlag(FLAG_E, emptyCommand, null) .get().collect(Collectors.toList())); // NPEs should be caught if the lambda does not handle it - assertEquals(LIST_EMPTY, supplier.getValidValues(FLAG_F, emptyCommand, null) + assertEquals(LIST_EMPTY, supplier.getValidValuesForFlag(FLAG_F, emptyCommand, null) .get().collect(Collectors.toList())); }