merge main into feature/client-side-search

This commit is contained in:
Natalia Cholewa 2025-12-19 23:43:39 +01:00
commit 96eb19d74c
18 changed files with 528 additions and 138 deletions

View file

@ -4,7 +4,6 @@ package client.scenes;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale;
import client.exception.UpdateException; import client.exception.UpdateException;
import client.scenes.recipe.IngredientListCtrl; import client.scenes.recipe.IngredientListCtrl;
@ -23,7 +22,6 @@ import commons.ws.Topics;
import commons.ws.messages.Message; import commons.ws.messages.Message;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Alert; import javafx.scene.control.Alert;
import javafx.scene.control.Button; import javafx.scene.control.Button;
@ -48,18 +46,6 @@ public class FoodpalApplicationCtrl implements LocaleAware {
public VBox detailsScreen; public VBox detailsScreen;
public HBox editableTitleArea; public HBox editableTitleArea;
// all of these aren't used with only my part of the code
// everything in the top bar ===
@FXML
private Button flagEnButton; //already here for advanced stuff
@FXML
private Button flagNlButton; //already here for advanced stuff
@FXML
private Button flagPlButton; //already here for advanced stuff
// everything in the left lane // everything in the left lane
@FXML @FXML
public Label recipesLabel; public Label recipesLabel;
@ -113,6 +99,23 @@ public class FoodpalApplicationCtrl implements LocaleAware {
initializeWebSocket(); initializeWebSocket();
} }
private void initRecipeList() {
// Show recipe name in the list
recipeList.setCellFactory(list -> new ListCell<>() {
@Override
protected void updateItem(Recipe item, boolean empty) {
super.updateItem(item, empty);
setText(empty || item == null ? "" : item.getName());
}
});
// When your selection changes, update details in the panel
recipeList.getSelectionModel().selectedItemProperty().addListener(
(obs, oldRecipe, newRecipe) -> {
showRecipeDetails(newRecipe);
updateFavouriteButton(newRecipe);
}
);
}
@Inject @Inject
void setSearchBarCtrl(SearchBarCtrl searchBarCtrl) { void setSearchBarCtrl(SearchBarCtrl searchBarCtrl) {
@ -165,11 +168,7 @@ public class FoodpalApplicationCtrl implements LocaleAware {
}); });
}); });
} }
private void initStepsIngredientsList() {
@Override
public void initializeComponents() {
config = configService.getConfig();
// TODO Reduce code duplication??
// Initialize callback for ingredient list updates // Initialize callback for ingredient list updates
this.ingredientListCtrl.setUpdateCallback(newList -> { this.ingredientListCtrl.setUpdateCallback(newList -> {
Recipe selectedRecipe = recipeList.getSelectionModel().getSelectedItem(); Recipe selectedRecipe = recipeList.getSelectionModel().getSelectedItem();
@ -199,21 +198,12 @@ public class FoodpalApplicationCtrl implements LocaleAware {
throw new UpdateException("Unable to update recipe to server for " + selectedRecipe); throw new UpdateException("Unable to update recipe to server for " + selectedRecipe);
} }
}); });
// Show recipe name in the list }
recipeList.setCellFactory(list -> new ListCell<>() { @Override
@Override public void initializeComponents() {
protected void updateItem(Recipe item, boolean empty) { config = configService.getConfig();
super.updateItem(item, empty); initStepsIngredientsList();
setText(empty || item == null ? "" : item.getName()); initRecipeList();
}
});
// When your selection changes, update details in the panel
recipeList.getSelectionModel().selectedItemProperty().addListener(
(obs, oldRecipe, newRecipe) -> {
showRecipeDetails(newRecipe);
updateFavouriteButton(newRecipe);
}
);
// Double-click to go to detail screen // Double-click to go to detail screen
recipeList.setOnMouseClicked(event -> { recipeList.setOnMouseClicked(event -> {
@ -222,7 +212,6 @@ public class FoodpalApplicationCtrl implements LocaleAware {
openSelectedRecipe(); openSelectedRecipe();
} }
}); });
this.initializeSearchBar(); this.initializeSearchBar();
refresh(); refresh();
updateFavouriteButton(recipeList.getSelectionModel().getSelectedItem()); updateFavouriteButton(recipeList.getSelectionModel().getSelectedItem());
@ -247,13 +236,6 @@ public class FoodpalApplicationCtrl implements LocaleAware {
printRecipeButton.setText(getLocaleString("menu.button.print")); printRecipeButton.setText(getLocaleString("menu.button.print"));
recipesLabel.setText(getLocaleString("menu.label.recipes")); recipesLabel.setText(getLocaleString("menu.label.recipes"));
// TODO propagate ResourceBundle lang changes to nested controller
// ingredientsLabel.setText(getLocaleString("menu.label.ingredients"));
// preparationLabel.setText(getLocaleString("menu.label.preparation"));
// addIngredientButton.setText(getLocaleString("menu.button.add.ingredient"));
// addPreparationStepButton.setText(getLocaleString("menu.button.add.step"));
} }
@Override @Override
@ -378,15 +360,6 @@ public class FoodpalApplicationCtrl implements LocaleAware {
editableTitleArea.getChildren().add(edit); editableTitleArea.getChildren().add(edit);
edit.requestFocus(); edit.requestFocus();
} }
// Language buttons
@FXML
private void switchLocale(ActionEvent event) {
Button button = (Button)event.getSource();
String lang = (String)button.getUserData();
localeManager.setLocale(Locale.of(lang));
}
@FXML @FXML
private void makePrintable() { private void makePrintable() {
System.out.println("Recipe printed"); System.out.println("Recipe printed");

View file

@ -0,0 +1,100 @@
package client.scenes;
import client.utils.LocaleAware;
import client.utils.LocaleManager;
import com.google.inject.Inject;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.util.StringConverter;
import java.io.InputStream;
import java.util.Locale;
/**
* The language selection menu controller.
* This needs to implement {@link LocaleAware LocaleAware} so that the
* <code>getLocaleString(String)</code> function is available.
*/
public class LangSelectMenuCtrl implements LocaleAware {
public ComboBox<String> langSelectMenu;
private final LocaleManager manager;
@Inject
public LangSelectMenuCtrl(LocaleManager manager) {
this.manager = manager;
}
/**
* Switches the locale of the application depending on which button the user selects in the list.
* @param event The action event triggered by the user.
*/
@FXML
private void switchLocale(ActionEvent event) {
String lang = langSelectMenu.getSelectionModel().getSelectedItem();
manager.setLocale(Locale.of(lang));
}
@Override
public void initializeComponents() {
langSelectMenu.getItems().setAll("en", "pl", "nl");
langSelectMenu.setConverter(new StringConverter<String>() {
@Override
public String toString(String s) {
if (s == null) {
return "";
}
return getLocaleString("lang." + s + ".display");
}
@Override
public String fromString(String s) {
return s;
}
});
langSelectMenu.setCellFactory(list -> new ListCell<>() {
@Override
protected void updateItem(String item, boolean empty) {
final int IMAGE_HEIGHT = 32;
final int HBOX_SPACING = 10;
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
setGraphic(null);
return;
}
InputStream imageStream = getClass().getResourceAsStream("/flag_" + item + ".png");
if (imageStream == null) {
setGraphic(new HBox(new Label(getLocaleString("lang." + item + ".display"))));
return;
}
Image img = new Image(imageStream);
ImageView imageView = new ImageView(img);
imageView.setFitHeight(IMAGE_HEIGHT);
imageView.setFitWidth(IMAGE_HEIGHT);
setGraphic(
new HBox(
HBOX_SPACING,
imageView,
new Label(getLocaleString("lang." + item + ".display"))
)
);
}
});
}
@Override
public void updateText() {
// doesn't do anything; the text doesn't need to be updated.
}
@Override
public LocaleManager getLocaleManager() {
return manager;
}
}

View file

@ -0,0 +1,67 @@
package client.utils;
import commons.Recipe;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class PrintExportService {
/**
* Builds the String with all the recipe data in a human-readable format and returns said string.
* @param recipe - Recipe Object that needs to be converted
* @return - String Result that is the converted recipe object
*/
public static String buildRecipeText(Recipe recipe){
String result = "Title: " + recipe.getName() + "\nRecipe ID: " + recipe.getId() + "\n" +
"Ingredients: "; //Starts the string with name and recipe ID
for(int i =0; i<recipe.getIngredients().size();i++){ // For loop adding ingredients one by one
result += recipe.getIngredients().get(i) + ", ";
}
result += "\nSteps:\n";
for(int i =0; i<recipe.getPreparationSteps().size();i++){ // Preparation Steps separated by new lines
result += (i+1) + ": " + recipe.getPreparationSteps().get(i) + "\n";
}
return result;
}
/**
* Method that checks if the directory path of the selected directory is valid and throws and error.
* if not valid
* @param path - Path to directory
*/
public static void validateFolder(Path path){
if (path == null) { //Null path value
throw new IllegalArgumentException("Path is empty");
}
if(!Files.exists(path)){ //If Folder doesn't exist
throw new IllegalArgumentException("Folder does not exist");
}
if(!Files.isDirectory(path)){ // If folder is not directory
throw new IllegalArgumentException("Given path is not a folder");
}
}
/**
* Method that exports a plain-text String of recipe data, into a newly created file from
* a selected directory provided as a path to the method and names said file based on the
* nameOfFile param.
* @param recipeData - String containing recipe data that will be written to file
* @param dirFilePath - Path to Folder
* @param nameOfFile - Name of file to be created
*/
public static void exportToFile(String recipeData, Path dirFilePath, String nameOfFile){
validateFolder(dirFilePath); //runs validate Folder method to check if Directory path is valid
Path filePath = dirFilePath.resolve(nameOfFile); //Creates a file with name provided in directory and stores path in PATH object
try {
Files.writeString(filePath, recipeData); // Writes the recipe data into the File.
}
catch (IOException e){
System.err.println("An error occurred while writing to the file");
}
}
}

View file

@ -15,6 +15,7 @@
<?import javafx.scene.layout.VBox?> <?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<?import javafx.scene.control.ComboBox?>
<BorderPane prefHeight="800.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/25" xmlns:fx="http://javafx.com/fxml/1" fx:controller="client.scenes.FoodpalApplicationCtrl"> <BorderPane prefHeight="800.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/25" xmlns:fx="http://javafx.com/fxml/1" fx:controller="client.scenes.FoodpalApplicationCtrl">
<!-- TOP BAR --> <!-- TOP BAR -->
@ -23,58 +24,12 @@
<padding> <padding>
<Insets bottom="10" left="10" right="10" top="10" /> <Insets bottom="10" left="10" right="10" top="10" />
</padding> </padding>
<GridPane> <Label prefHeight="56.0" prefWidth="158.0" text="FoodPal">
<columnConstraints> <font>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="198.0" minWidth="10.0" prefWidth="130.0" /> <Font name="System Bold" size="29.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="95.0" minWidth="2.0" prefWidth="70.0" /> </font>
</columnConstraints> </Label>
<rowConstraints> </HBox>
<RowConstraints maxHeight="54.0" minHeight="10.0" prefHeight="54.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="25.0" minHeight="6.0" prefHeight="6.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label prefHeight="56.0" prefWidth="158.0" text="FoodPal">
<font>
<Font name="System Bold" size="29.0" />
</font>
</Label>
<ButtonBar prefHeight="40.0" prefWidth="200.0" GridPane.rowIndex="2">
<buttons>
<ToolBar prefHeight="35.0" prefWidth="123.0">
<items>
<Button fx:id="flagEnButton" minWidth="33.0" onAction="#switchLocale" userData="en" prefHeight="25.0" prefWidth="33.0" text="EN" />
<Button fx:id="flagNlButton" onAction="#switchLocale" userData="nl" text="NL" />
<Button fx:id="flagPlButton" onAction="#switchLocale" userData="pl" text="PL" />
</items>
</ToolBar>
</buttons>
</ButtonBar>
</children>
</GridPane>
<Pane HBox.hgrow="ALWAYS" />
<HBox spacing="5" />
<GridPane prefHeight="90.0" prefWidth="114.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="315.0" minWidth="10.0" prefWidth="32.1666259765625" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="315.0" minWidth="10.0" prefWidth="24.8333740234375" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="173.0" minWidth="10.0" prefWidth="28.6666259765625" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="95.0" minWidth="10.0" prefWidth="34.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Button fx:id="refreshButton" onAction="#refresh" prefHeight="25.0" prefWidth="34.0" text="⟳" GridPane.columnIndex="3" GridPane.rowIndex="2" />
</children>
</GridPane>
</HBox>
</top> </top>
<!-- LEFT: RECIPE LIST --> <!-- LEFT: RECIPE LIST -->
@ -83,7 +38,8 @@
<padding> <padding>
<Insets bottom="10" left="10" right="10" top="10" /> <Insets bottom="10" left="10" right="10" top="10" />
</padding> </padding>
<fx:include source="LangSelect.fxml" />
<Button fx:id="refreshButton" onAction="#refresh" prefHeight="25.0" prefWidth="34.0" text="⟳" GridPane.columnIndex="3" GridPane.rowIndex="2" />
<Label fx:id="recipesLabel" text="Recipes"> <Label fx:id="recipesLabel" text="Recipes">
<font> <font>
<Font name="System Bold" size="15.0" /> <Font name="System Bold" size="15.0" />

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<ComboBox
fx:id="langSelectMenu"
xmlns="http://javafx.com/javafx/25"
xmlns:fx="http://javafx.com/fxml/1"
onAction="#switchLocale"
fx:controller="client.scenes.LangSelectMenuCtrl"
>
</ComboBox>

Binary file not shown.

After

Width:  |  Height:  |  Size: 995 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

View file

@ -24,3 +24,7 @@ menu.button.remove.step=Remove Step
menu.button.edit=Edit menu.button.edit=Edit
menu.button.clone=Clone menu.button.clone=Clone
menu.button.print=Print recipe menu.button.print=Print recipe
lang.en.display=English
lang.nl.display=Dutch
lang.pl.display=Polish

View file

@ -25,4 +25,7 @@ menu.button.edit=Edit
menu.button.clone=Clone menu.button.clone=Clone
menu.button.print=Print recipe menu.button.print=Print recipe
menu.search=Search... menu.search=Search...
lang.en.display=English
lang.nl.display=Nederlands
lang.pl.display=Polski

View file

@ -25,4 +25,7 @@ menu.button.edit=Bewerken
menu.button.clone=Dupliceren menu.button.clone=Dupliceren
menu.button.print=Recept afdrukken menu.button.print=Recept afdrukken
menu.search=Zoeken... menu.search=Zoeken...
lang.en.display=English
lang.nl.display=Nederlands
lang.pl.display=Polski

View file

@ -25,4 +25,7 @@ menu.button.edit=Edytuj
menu.button.clone=Duplikuj menu.button.clone=Duplikuj
menu.button.print=Drukuj przepis menu.button.print=Drukuj przepis
menu.search=Szukaj... menu.search=Szukaj...
lang.en.display=English
lang.nl.display=Nederlands
lang.pl.display=Polski

View file

@ -0,0 +1,70 @@
package client.scenes;
import client.utils.PrintExportService;
import client.utils.ServerUtils;
import commons.Recipe;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
public class PrintExportTest {
static ServerUtils dv = new ServerUtils();
@BeforeEach
public void setup(){
Assumptions.assumeTrue(dv.isServerAvailable(), "Server not available");
}
@Test
public void buildRecipeTextTest(){
List<String> ingredients = new ArrayList<>();
ingredients.add("Banana");
ingredients.add("Bread");
final long testRecipeId = 1234L;
List<String> preparationSteps = new ArrayList<>();
preparationSteps.add("Mix Ingredients");
preparationSteps.add("Heat in Oven");
Recipe recipe1 = new Recipe(testRecipeId, "Banana Bread", ingredients, preparationSteps);
assertEquals("""
Title: Banana Bread
Recipe ID: 1234
Ingredients: Banana, Bread,\s
Steps:
1: Mix Ingredients
2: Heat in Oven
""", PrintExportService.buildRecipeText(recipe1));
}
@TempDir
Path tempDir;
@Test
public void validateFolderWithValidFolderTest(){
assertDoesNotThrow(() -> PrintExportService.validateFolder(tempDir));
}
@Test
public void validateFolderWithNullPathTest(){
IllegalArgumentException i = assertThrows(IllegalArgumentException.class,
()->PrintExportService.validateFolder(null));
assertEquals("Path is empty", i.getMessage());
}
@Test
public void validateFolderWithFilePathTest() throws IOException {
Path filePath = Files.createFile(tempDir.resolve("TestFile"));
IllegalArgumentException i = assertThrows(IllegalArgumentException.class,
()->PrintExportService.validateFolder(filePath));
assertEquals("Given path is not a folder", i.getMessage());
}
}

View file

@ -50,6 +50,10 @@ public class Ingredient {
+ carbsPer100g * KCAL_PER_GRAM_CARBS + carbsPer100g * KCAL_PER_GRAM_CARBS
+ fatPer100g * KCAL_PER_GRAM_FAT; + fatPer100g * KCAL_PER_GRAM_FAT;
} }
public void setId(long id) {
this.id = id;
}
} }

View file

@ -69,7 +69,7 @@ public class RecipeIngredient {
public double amountInBaseUnit() { public double amountInBaseUnit() {
Unit unit = getUnit(); Unit unit = getUnit();
if (unit == null || unit.isFormal() || unit.conversionFactor <= 0) { if (unit == null || !unit.isFormal() || unit.conversionFactor <= 0) {
return 0.0; return 0.0;
} }
return amount * unit.conversionFactor; return amount * unit.conversionFactor;

View file

@ -1,4 +1,95 @@
package commons; package commons;
//should i do it or wait for lines for next week
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
public class RecipeIngredientTest { public class RecipeIngredientTest {
private RecipeIngredient gram;
private RecipeIngredient kilogram;
private RecipeIngredient milliliter;
private RecipeIngredient liter;
private RecipeIngredient teaspoon;
private RecipeIngredient tablespoon;
private RecipeIngredient cup;
private RecipeIngredient piece;
private RecipeIngredient pinch;
private RecipeIngredient handful;
private RecipeIngredient toTaste;
private RecipeIngredient invalid;
@BeforeEach
void setup(){
Recipe recipe = new Recipe();
Ingredient ingredient = new Ingredient();
gram = new RecipeIngredient(recipe,ingredient,1,"GRAM");
kilogram = new RecipeIngredient(recipe,ingredient,1,"KILOGRAM");
milliliter = new RecipeIngredient(recipe,ingredient,1,"MILLILITER");
liter = new RecipeIngredient(recipe,ingredient,1,"LITER");
teaspoon = new RecipeIngredient(recipe,ingredient,1,"TEASPOON");
tablespoon = new RecipeIngredient(recipe,ingredient,1,"TABLESPOON");
cup = new RecipeIngredient(recipe,ingredient,1,"CUP");
piece = new RecipeIngredient(recipe,ingredient,1,"PIECE");
pinch = new RecipeIngredient(recipe,ingredient,1,"PINCH");
handful = new RecipeIngredient(recipe,ingredient,1,"HANDFUL");
toTaste = new RecipeIngredient(recipe,ingredient,1,"TO_TASTE");
invalid = new RecipeIngredient(recipe,ingredient,1,"INVALID");
}
@Test
void getFormalUnitTest(){
assertEquals(Unit.GRAM, gram.getUnit());
assertEquals(Unit.KILOGRAM, kilogram.getUnit());
assertEquals(Unit.MILLILITER, milliliter.getUnit());
assertEquals(Unit.LITER, liter.getUnit());
assertEquals(Unit.TEASPOON, teaspoon.getUnit());
assertEquals(Unit.TABLESPOON, tablespoon.getUnit());
assertEquals(Unit.CUP, cup.getUnit());
assertEquals(Unit.PIECE, piece.getUnit());
}
@Test
void getInformalUnitTest(){
assertEquals(Unit.PINCH, pinch.getUnit());
assertEquals(Unit.HANDFUL, handful.getUnit());
assertEquals(Unit.TO_TASTE, toTaste.getUnit());
}
@Test
void getUnknownUnitTest(){
assertNull(invalid.getUnit());
}
@Test
void convertFormalToBaseUnit(){
assertEquals(1000, kilogram.amountInBaseUnit());
assertEquals(1,milliliter.amountInBaseUnit());
assertEquals(1000.0,liter.amountInBaseUnit());
assertEquals(15.0,tablespoon.amountInBaseUnit());
assertEquals(5,teaspoon.amountInBaseUnit());
assertEquals(240.0,cup.amountInBaseUnit());
assertEquals(1.0,piece.amountInBaseUnit());
}
@Test
void convertInformalToBaseUnit(){
assertEquals(0,pinch.amountInBaseUnit());
assertEquals(0,handful.amountInBaseUnit());
assertEquals(0, toTaste.amountInBaseUnit());
}
@Test
void convertUnknownToBaseUnit(){
assertEquals(0,invalid.amountInBaseUnit());
}
} }

View file

@ -1,33 +1,134 @@
# Week 6 meeting agenda # Week 6 meeting agenda
| Key | Value | | Key | Value |
| ------------ |-----------------------------------------------------------------------------------------| | ------------ |--------------------------------------------------------------------------------------------------|
| Date | Dec 18th | | Date | Dec 18th |
| Time | 14:45 | | Time | 14:45 |
| Location | Hall D | | Location | Hall D |
| Chair | Rithvik Sriram | | Chair | Rithvik Sriram |
| Minute Taker | Mei Chang van der Werff | | Minute Taker | Mei Chang van der Werff |
| Attendees | Mei Chang van der Werff, Natalia Cholewa, Rithvik Sriram, Aysegul Aydinlik, Steven Liu | | Attendees | Mei Chang van der Werff, Natalia Cholewa, Rithvik Sriram, Aysegul Aydinlik, Steven Liu (online) |
## Table of contents ## Table of contents
1. (1 min) Introduction by chair * (Steven joins the meeting online)
2. (1 min) Any additions to the agenda?
3. (1-2 min) TA announcements?
4. (1 min) Go over TA feedback given
5. (33 min) **Meeting content**
1. (5 min) Week 6 progress in terms of completion
- How far are we in terms of completion?
2. (5 min) Progress check in terms of feature/issue completion
- What have we completed/going to complete this week?
3. (3 min) Small Showcase of the product
4. (20 min) **Sprint planning week 7-8** 1. (1 min) Introduction by chair
- What needs to be done? > Meeting starts at **14:46**
- Handle Backend-Server code delegation ---
- How do we do it?
- Who does it? 2. (1 min) Any additions to the agenda?
5. (2 min) Designate teams. > Tomorrow is the deadline for technology, it's best to go over the requirements real quick. \
6. (1 min) Who is the next chair and minute taker? > To prevent failing this assignment like the previous 2
---
3. (1-2 min) TA announcements?
> If there are any questions about my feedback ask them now
4. (1 min) Go over TA feedback given
>*We've made a little summary of our feedback, and had a few questions*
> ### _Time Tracking_:
>- **What exactly is expected from us for the time tracking?** \
>We need to do an estimate of how long a task/issue might take. And after implementing it, you have to upload the actual taken time
>- **Are the Mr and issues time tracking connected?** \
>Yes, but not 100% sure. It's better to double-check it yourself
>
>### _Milestones_:
>- **What was the exact issue, they are too big?** \
>Our understanding of milestones is wrong, the milestones should be kinda our weekly tasks deadline. \
>And when we don't finish a task it should be moved to the next milestone, of the next week.
>
> ### _UserStory (backlog)_:
>- **How should we do this?** \
> You can just put it in the issue description.Don't make it your mr title! \
>A different groups makes the user story a parent issue and make children issues with the actual code, but we can choose what we want
>>For now, we will just put the user Story in the issue description, we will discuss it later if we want to change the method or not
>
>
>### _Commit and MR issues_:
>- Not all commits are related to the Mr
>- Our commits are too big, editing ±20 files are way too many. Try too keep it to 3-5 files max.
>- Also do only client or only server in a commit, don't combine them.
> - `mvn clean verify` before pushing to check whether the pipeline fails or not
---
5. (33 min) Meeting content
* (5 min) Week 6 progress in terms of completion
- How far are we in terms of completion?
>* 4.1 We still need to merge to connection of the print function, the Mr needed some changes but we can do that later. But do Rebase the MR as the branch is behind with A LOT of commits
>* 4.2 We've done the websockets, we only need to merge it
>* 4.3 We've done some backend parts but they are not yet connected to the client side
>* 4.4 The favourite button and message were made this week
>* 4.4 The search bar is currently in prgress on both the client and server side
>* 4.5 We keep this for week 8 or next week if there are not enough tasks
> >Let's focus on just connecting everything next week and after that we can start implementing 4.5
* (5 min) Progress check in terms of feature/issue completion
- What have we completed/going to complete this week?
> **Rithvik**: the backend of the searchbar and favourites is in progress. \
> **Aysegul**: Made the favourite button and some UI elements, sadly enough no penguin icon yet :< \
> **Oskar**: Finished the websocket implementation, however there is a small TODO left. Steven is going to do that. Also connected the config \
> **Mei Chang**: Deleted all the left over example code, made the favourite recipe message(backend), created a test class, made unit use enums and did a small TODO about setters.\
> **Natalia**: Almost finished the search bar (frontend) and improved testing on the client side. Will do some refactoring tomorrow. \
> **Steven**: Forgot to ask. But did make the language buttons a dropdown box, and did some other things
* (3 min) Small Showcase of the product
>We didn't have a lot of time to review and merge our code, so there is not big difference compared to last week. \
> We've shown the language dropdown box
* (20 min) Sprint planning week 7-8
- What needs to be done?
- Handle Backend-Server code delegation
- How do we do it?
- Who does it?
>We didn't really divide the tasks, just the roles. We will distribute tasks on the monday meeting. \
> We did discuss some things general tasks that need to be done
>
> ### Server
> - Testing
> - Refactoring (Oskar)
> - Some backend websocket things
> - Add more endpoints
>
> ### Client
> - Connecting everything to the UI
> - Some frontend websocket things
* (2 min) Designate teams.
>There is not a lot of server code that needs to be done so we're keeping the 2/4 server/client distribution this week.\
> Since there are still 3 people who need their LOC in server they have prioriy
> - Ayse and Oskar will do Server
> - The others will do Client
* (1 min) Who is the next chair and minute taker?
> Mei Chang will be the Chair \
> Aysegul will be the minute taker
---
>### Some Questions
> **What's the criteria of production code in server?**\
> Answer: recommendation to do 50/50 or 60/40 production/test code.
>
> **Can we copy code from the internet?**\
> Answer: Yes, but do put the link of where you got the code from in comments
>
> **For a test I want to change the gitlab UI, is that allowed?**
> **And I need to write a docx file for this, is the team fine with that?**\
> Answer TA: Yes, but make sure it doesn't affect the other teammates \
> Team: Yeah we're fine with that
---
6. (2 min) Questions 6. (2 min) Questions
> #### We haven't yet talked about the technology requirements.
> We might didn't split the ui correctly, there is too much logic in it.\
> Server utils isn't server decorated
>
> **What is business logic?** \
> Something about the fact that not everything should be in the same file, but split across files
---
7. (1 min) Summarize everything 7. (1 min) Summarize everything
8. (1 min) TA remarks >- 3 people still need to do server LOC; Aysegul, Oskar, Mei Chang.
**Max time:** ~40 minutes >- Next week our priority is connecting everything
>- We need to improve our code contribution and planning based on the feedback
---
8. (1 min) TA remarks \
Max time: ~40 minutes
> Ta will look at technology on Tuesday
>
>Meeting ends: **15:18**\
>Actual meeting time: 32 minutes

View file

@ -134,8 +134,7 @@ public class IngredientController {
return ResponseEntity.notFound().build(); return ResponseEntity.notFound().build();
} }
// TODO: Refactor to use setters updated.setId(id);
updated.id = id;
Ingredient savedIngredient = ingredientRepository.save(updated); Ingredient savedIngredient = ingredientRepository.save(updated);
messagingTemplate.convertAndSend(Topics.INGREDIENTS, new CreateIngredientMessage(savedIngredient)); messagingTemplate.convertAndSend(Topics.INGREDIENTS, new CreateIngredientMessage(savedIngredient));