Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Documentation #183

Merged
merged 8 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,45 @@

Team allocation decision support system as used in the iPraktikum.

A more detailed documentation can be found at [https://ls1intum.github.io/tease](https://ls1intum.github.io/tease).

## Usage

### Starting TEASE Client and Server

To start the TEASE application, follow the steps below:

#### Option A: Using Remote Docker Images
#### Option A: Using Remote Docker Images

Ensure that the docker-compose.yml file is in the directory, then run:

```
docker compose up
```

#### Option B: Using Local Repository

If you want to build the images locally from the repository, run:

```
docker compose up --build
```

### Access TEASE
Once the application is running, open `http://localhost/tease` in your browser.

Once the application is running, open `http://localhost/tease` in your browser.

![Dashboard](docs/Dashboard.jpeg)

You can either import the example student data or specify a different file. If running together with [PROMPT](https://github.com/ls1intum/prompt) and previously logged in, student data can be directly imported.
You can either import the example student data or specify a different file. If running together with [PROMPT](https://github.com/ls1intum/prompt) and previously logged in, student data can be directly imported.

Constraints can be created for team size, skills, gender, nationality, device ownership, and language. After applying constraints, students will be automatically assigned to their highest project team preference while fulfilling all set constraints.

When used with PROMPT, constraints, allocations, and locked students can be synchronized in real-time between multiple clients.

The result can be exported as a CSV file or directly to PROMPT to continue the workflow there. Additionally, the team cards can be exported as images.

## Development
## Development

TEASE consists of a client and a server. The client is built with Angular, while the server utilizes Spring Boot with Java and functions as a STOMP WebSocket Broker.

Expand Down
2 changes: 1 addition & 1 deletion client/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export class AppComponent implements OverlayServiceHost, OnInit, OnDestroy {
if (!studentId) return;

if (!projectId) {
this.allocationsService.removeStudentFromProjects(studentId);
this.allocationsService.removeStudentFromAllocations(studentId);
return;
}

Expand Down
18 changes: 17 additions & 1 deletion client/src/app/shared/data/allocations.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ export class AllocationsService {
this.moveStudentToProjectAtPosition(studentId, projectId);
}

/**
* Moves a student to a specified project at a given position relative to a sibling.
* If no siblings is provided, the student is added to the end of the project.
*
* @param {string} studentId - The ID of the student to move.
* @param {string} projectId - The ID of the project to which the student will be moved.
* @param {string} [siblingId] - The ID of the sibling student. If provided, the student will be placed next to this sibling. If not found or not provided, the student is added to the end.
* @returns {void}
*/
moveStudentToProjectAtPosition(studentId: string, projectId: string, siblingId?: string): void {
const allocations = this.getAllocationsWithoutStudent(studentId);
const allocation = this.getAllocationForProjectId(projectId);
Expand All @@ -71,6 +80,13 @@ export class AllocationsService {
this.setAllocations(allocations);
}

/**
* Retrieves all allocations and filters out the specified student from each allocation.
*
* @private
* @param {string} studentId - The ID of the student to be removed from the allocations.
* @returns {Allocation[]} - An array of allocations with the specified student removed.
*/
private getAllocationsWithoutStudent(studentId: string): Allocation[] {
const allocations = this.getAllocations();
allocations.forEach(allocation => {
Expand All @@ -79,7 +95,7 @@ export class AllocationsService {
return allocations;
}

removeStudentFromProjects(studentId: string): void {
removeStudentFromAllocations(studentId: string): void {
const allocations = this.getAllocations();
allocations.forEach(allocation => {
allocation.students = allocation.students.filter(id => id !== studentId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ export class ConstraintBuilderService {
private lockedConstraintsService: LockedConstraintsService
) {}

/**
* Creates a list of constraints for the linear program based on the provided students, projects, custom constraints, and locks.
* The constraints generated follow the format:
* `x[numericalId of student]y[numericalId of project] + x[numericalId of student]y[numericalId of project] + ... <= [threshold]`.
*
* @param {Student[]} students - An array of `Student` objects for whom the constraints are being generated.
* @param {string[]} projectIds - An array of project IDs that the students can be assigned to.
* @param {ConstraintWrapper[]} constraintWrappers - An array of custom constraints that need to be applied.
* @param {StudentIdToProjectIdMapping} locks - A mapping of locked student-to-project assignments.
* @returns {string[]} - An array of constraint strings, each following the specified format.
*/
createConstraints(
students: Student[],
projectIds: string[],
Expand Down
34 changes: 34 additions & 0 deletions client/src/app/shared/matching/matching.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@ export class MatchingService {
private toastsService: ToastsService
) {}

/**
* Asynchronously matches students to projects based on the given constraints.
* Solves a linear program to determine the allocations.
* If an error occurs during the solving process, a toast message is shown.
* The constraints generated follow the format:
* `x[numericalId of student]y[numericalId of project] + x[numericalId of student]y[numericalId of project] + ... <= [threshold]`.
*
* @param {string[]} constraints - An array of constraint strings, each following the specified format to apply in the linear program.
* @returns {Promise<Allocation[]>} - A promise that resolves to an array of `Allocation` objects.
* Returns `null` if no feasible solution is found.
*
* @see id-mapping.service.ts for the mapping of numerical IDs to project and student IDs.
*/
async getAllocations(constraints: string[]): Promise<Allocation[]> {
try {
const startTime = Date.now();
Expand Down Expand Up @@ -42,6 +55,19 @@ export class MatchingService {
});
}

/**
* Transforms the given solution into an array of allocations.
* This method first checks if the solution is feasible. If not, it returns `null`.
* Then, it removes specified properties from the solution object.
* Finally, it converts the remaining solution data into an array of `Allocation` objects.
*
* @private
* @param {Solve} solution - The solution object that contains the result of a linear program.
* The object is expected to have keys representing variable names,
* which can be split into `studentId` and `projectId`.
* @returns {Allocation[]} - An array of `Allocation` objects if the solution is feasible,
* or `null` if the solution is not feasible.
*/
private transformSolutionToAllocations(solution: Solve): Allocation[] {
if (!solution.feasible) return null;

Expand All @@ -68,6 +94,14 @@ export class MatchingService {
return { studentId: this.getId(split[0].slice(1)), projectId: this.getId(split[1]) };
}

/**
* Retrieves the original student or project ID corresponding to a given numerical ID.
*
* @private
* @param {string} value - The numerical ID that needs to be mapped to its corresponding student or project ID.
* @returns {string} - The original student or project ID.
* @throws {Error} If the mapping for the provided numerical ID is undefined.
*/
private getId(value: string): string {
const key = this.constraintMappingService.getId(value);
if (!key) throw new Error(`Key for value "${value}" is undefined`);
Expand Down
Binary file added docs/ConstraintBuilder.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/ConstraintSummary.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/Statistics.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions docs/_config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
plugins:
- jekyll-relative-links
relative_links:
enabled: true
collections: true
include:
- index.md
Loading