Spaces:
Sleeping
Sleeping
Ahmad Shallouf
commited on
Commit
•
1bc149f
1
Parent(s):
8482e72
initialize
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .DS_Store +0 -0
- CompUGE-Frontend.iml +9 -0
- Dockerfile +22 -0
- README.md +27 -11
- angular.json +127 -0
- docker-compose.yaml +9 -0
- package-lock.json +0 -0
- package.json +42 -0
- src/.DS_Store +0 -0
- src/app/app.component.css +0 -0
- src/app/app.component.html +6 -0
- src/app/app.component.spec.ts +29 -0
- src/app/app.component.ts +20 -0
- src/app/app.config.ts +15 -0
- src/app/app.routes.ts +21 -0
- src/app/components/body/about/about.component.css +0 -0
- src/app/components/body/about/about.component.html +154 -0
- src/app/components/body/about/about.component.spec.ts +23 -0
- src/app/components/body/about/about.component.ts +30 -0
- src/app/components/body/body.component.css +114 -0
- src/app/components/body/body.component.html +87 -0
- src/app/components/body/body.component.spec.ts +23 -0
- src/app/components/body/body.component.ts +56 -0
- src/app/components/body/dashboard/dashboard.component.css +0 -0
- src/app/components/body/dashboard/dashboard.component.html +1 -0
- src/app/components/body/dashboard/dashboard.component.spec.ts +23 -0
- src/app/components/body/dashboard/dashboard.component.ts +12 -0
- src/app/components/body/datasets/dataset/dataset.component.css +0 -0
- src/app/components/body/datasets/dataset/dataset.component.html +48 -0
- src/app/components/body/datasets/dataset/dataset.component.spec.ts +23 -0
- src/app/components/body/datasets/dataset/dataset.component.ts +56 -0
- src/app/components/body/datasets/datasets.component.css +0 -0
- src/app/components/body/datasets/datasets.component.html +7 -0
- src/app/components/body/datasets/datasets.component.spec.ts +23 -0
- src/app/components/body/datasets/datasets.component.ts +34 -0
- src/app/components/body/leaderboards/leaderboard/leaderboard.component.css +0 -0
- src/app/components/body/leaderboards/leaderboard/leaderboard.component.html +84 -0
- src/app/components/body/leaderboards/leaderboard/leaderboard.component.spec.ts +23 -0
- src/app/components/body/leaderboards/leaderboard/leaderboard.component.ts +85 -0
- src/app/components/body/leaderboards/leaderboards.component.css +0 -0
- src/app/components/body/leaderboards/leaderboards.component.html +28 -0
- src/app/components/body/leaderboards/leaderboards.component.spec.ts +23 -0
- src/app/components/body/leaderboards/leaderboards.component.ts +57 -0
- src/app/components/body/submissions/submissions.component.css +0 -0
- src/app/components/body/submissions/submissions.component.html +90 -0
- src/app/components/body/submissions/submissions.component.spec.ts +23 -0
- src/app/components/body/submissions/submissions.component.ts +99 -0
- src/app/components/body/submitting/submitting.component.css +0 -0
- src/app/components/body/submitting/submitting.component.html +87 -0
- src/app/components/body/submitting/submitting.component.spec.ts +23 -0
.DS_Store
ADDED
Binary file (6.15 kB). View file
|
|
CompUGE-Frontend.iml
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<module type="WEB_MODULE" version="4">
|
3 |
+
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
4 |
+
<exclude-output />
|
5 |
+
<content url="file://$MODULE_DIR$" />
|
6 |
+
<orderEntry type="inheritedJdk" />
|
7 |
+
<orderEntry type="sourceFolder" forTests="false" />
|
8 |
+
</component>
|
9 |
+
</module>
|
Dockerfile
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM node:lts
|
2 |
+
|
3 |
+
# Set the working directory
|
4 |
+
WORKDIR /usr/src/app
|
5 |
+
|
6 |
+
# Install Angular CLI globally
|
7 |
+
RUN npm install -g @angular/cli
|
8 |
+
|
9 |
+
# Copy package.json and package-lock.json first to leverage Docker cache
|
10 |
+
COPY package*.json ./
|
11 |
+
|
12 |
+
# Install dependencies
|
13 |
+
RUN npm install
|
14 |
+
|
15 |
+
# Copy the rest of the application code
|
16 |
+
COPY . .
|
17 |
+
|
18 |
+
# Expose port
|
19 |
+
EXPOSE 4200
|
20 |
+
|
21 |
+
# Set entrypoint for different environments
|
22 |
+
ENTRYPOINT bash -c "ng serve --host 0.0.0.0 --port 4200 --configuration=production --disable-host-check;"
|
README.md
CHANGED
@@ -1,11 +1,27 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# CompugeFrontend
|
2 |
+
|
3 |
+
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.3.4.
|
4 |
+
|
5 |
+
## Development server
|
6 |
+
|
7 |
+
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
|
8 |
+
|
9 |
+
## Code scaffolding
|
10 |
+
|
11 |
+
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
12 |
+
|
13 |
+
## Build
|
14 |
+
|
15 |
+
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
|
16 |
+
|
17 |
+
## Running unit tests
|
18 |
+
|
19 |
+
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
20 |
+
|
21 |
+
## Running end-to-end tests
|
22 |
+
|
23 |
+
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
|
24 |
+
|
25 |
+
## Further help
|
26 |
+
|
27 |
+
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
angular.json
ADDED
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
3 |
+
"version": 1,
|
4 |
+
"newProjectRoot": "projects",
|
5 |
+
"projects": {
|
6 |
+
"compuge-frontend": {
|
7 |
+
"projectType": "application",
|
8 |
+
"schematics": {},
|
9 |
+
"root": "",
|
10 |
+
"sourceRoot": "src",
|
11 |
+
"prefix": "app",
|
12 |
+
"architect": {
|
13 |
+
"build": {
|
14 |
+
"builder": "@angular-devkit/build-angular:application",
|
15 |
+
"options": {
|
16 |
+
"outputPath": "dist/compuge-frontend",
|
17 |
+
"index": "src/index.html",
|
18 |
+
"browser": "src/main.ts",
|
19 |
+
"polyfills": [
|
20 |
+
"zone.js"
|
21 |
+
],
|
22 |
+
"tsConfig": "tsconfig.app.json",
|
23 |
+
"assets": [
|
24 |
+
"src/favicon.ico",
|
25 |
+
"src/assets"
|
26 |
+
],
|
27 |
+
"styles": [
|
28 |
+
"@angular/material/prebuilt-themes/deeppurple-amber.css",
|
29 |
+
"src/styles.css"
|
30 |
+
],
|
31 |
+
"scripts": []
|
32 |
+
},
|
33 |
+
"configurations": {
|
34 |
+
"production": {
|
35 |
+
"budgets": [
|
36 |
+
{
|
37 |
+
"type": "initial",
|
38 |
+
"maximumWarning": "500kb",
|
39 |
+
"maximumError": "1mb"
|
40 |
+
},
|
41 |
+
{
|
42 |
+
"type": "anyComponentStyle",
|
43 |
+
"maximumWarning": "2kb",
|
44 |
+
"maximumError": "4kb"
|
45 |
+
}
|
46 |
+
],
|
47 |
+
"outputHashing": "all",
|
48 |
+
"fileReplacements": [
|
49 |
+
{
|
50 |
+
"replace": "src/environments/environment.ts",
|
51 |
+
"with": "src/environments/environment.prod.ts"
|
52 |
+
}
|
53 |
+
]
|
54 |
+
},
|
55 |
+
"docker": {
|
56 |
+
"budgets": [
|
57 |
+
{
|
58 |
+
"type": "initial",
|
59 |
+
"maximumWarning": "500kb",
|
60 |
+
"maximumError": "1mb"
|
61 |
+
},
|
62 |
+
{
|
63 |
+
"type": "anyComponentStyle",
|
64 |
+
"maximumWarning": "2kb",
|
65 |
+
"maximumError": "4kb"
|
66 |
+
}
|
67 |
+
],
|
68 |
+
"outputHashing": "all",
|
69 |
+
"fileReplacements": [
|
70 |
+
{
|
71 |
+
"replace": "src/environments/environment.ts",
|
72 |
+
"with": "src/environments/environment.docker.ts"
|
73 |
+
}
|
74 |
+
]
|
75 |
+
},
|
76 |
+
"development": {
|
77 |
+
"optimization": false,
|
78 |
+
"extractLicenses": false,
|
79 |
+
"sourceMap": true
|
80 |
+
}
|
81 |
+
},
|
82 |
+
"defaultConfiguration": "production"
|
83 |
+
},
|
84 |
+
"serve": {
|
85 |
+
"builder": "@angular-devkit/build-angular:dev-server",
|
86 |
+
"configurations": {
|
87 |
+
"production": {
|
88 |
+
"buildTarget": "compuge-frontend:build:production"
|
89 |
+
},
|
90 |
+
"docker": {
|
91 |
+
"buildTarget": "compuge-frontend:build:docker"
|
92 |
+
},
|
93 |
+
"development": {
|
94 |
+
"buildTarget": "compuge-frontend:build:development"
|
95 |
+
}
|
96 |
+
},
|
97 |
+
"defaultConfiguration": "development"
|
98 |
+
},
|
99 |
+
"extract-i18n": {
|
100 |
+
"builder": "@angular-devkit/build-angular:extract-i18n",
|
101 |
+
"options": {
|
102 |
+
"buildTarget": "compuge-frontend:build"
|
103 |
+
}
|
104 |
+
},
|
105 |
+
"test": {
|
106 |
+
"builder": "@angular-devkit/build-angular:karma",
|
107 |
+
"options": {
|
108 |
+
"polyfills": [
|
109 |
+
"zone.js",
|
110 |
+
"zone.js/testing"
|
111 |
+
],
|
112 |
+
"tsConfig": "tsconfig.spec.json",
|
113 |
+
"assets": [
|
114 |
+
"src/favicon.ico",
|
115 |
+
"src/assets"
|
116 |
+
],
|
117 |
+
"styles": [
|
118 |
+
"@angular/material/prebuilt-themes/deeppurple-amber.css",
|
119 |
+
"src/styles.css"
|
120 |
+
],
|
121 |
+
"scripts": []
|
122 |
+
}
|
123 |
+
}
|
124 |
+
}
|
125 |
+
}
|
126 |
+
}
|
127 |
+
}
|
docker-compose.yaml
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
version: '3.7'
|
2 |
+
services:
|
3 |
+
frontend:
|
4 |
+
build:
|
5 |
+
context: .
|
6 |
+
args:
|
7 |
+
PROFILE: production
|
8 |
+
ports:
|
9 |
+
- '4200:4200' # Port mapping
|
package-lock.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
package.json
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "compuge-frontend",
|
3 |
+
"version": "0.0.0",
|
4 |
+
"scripts": {
|
5 |
+
"ng": "ng",
|
6 |
+
"start": "ng serve",
|
7 |
+
"build": "ng build",
|
8 |
+
"watch": "ng build --watch --configuration development",
|
9 |
+
"test": "ng test"
|
10 |
+
},
|
11 |
+
"private": true,
|
12 |
+
"dependencies": {
|
13 |
+
"@angular/animations": "^17.3.4",
|
14 |
+
"@angular/cdk": "^17.3.4",
|
15 |
+
"@angular/common": "^17.3.4",
|
16 |
+
"@angular/compiler": "^17.3.4",
|
17 |
+
"@angular/core": "^17.3.4",
|
18 |
+
"@angular/flex-layout": "^15.0.0-beta.42",
|
19 |
+
"@angular/forms": "^17.3.4",
|
20 |
+
"@angular/material": "^17.3.4",
|
21 |
+
"@angular/platform-browser": "^17.3.4",
|
22 |
+
"@angular/platform-browser-dynamic": "^17.3.4",
|
23 |
+
"@angular/router": "^17.3.4",
|
24 |
+
"rxjs": "~7.8.0",
|
25 |
+
"rxjs-compat": "^6.6.7",
|
26 |
+
"tslib": "^2.3.0",
|
27 |
+
"zone.js": "~0.14.3"
|
28 |
+
},
|
29 |
+
"devDependencies": {
|
30 |
+
"@angular-devkit/build-angular": "^17.3.4",
|
31 |
+
"@angular/cli": "^17.3.4",
|
32 |
+
"@angular/compiler-cli": "^17.3.4",
|
33 |
+
"@types/jasmine": "~5.1.0",
|
34 |
+
"jasmine-core": "~5.1.0",
|
35 |
+
"karma": "~6.4.0",
|
36 |
+
"karma-chrome-launcher": "~3.2.0",
|
37 |
+
"karma-coverage": "~2.2.0",
|
38 |
+
"karma-jasmine": "~5.1.0",
|
39 |
+
"karma-jasmine-html-reporter": "~2.1.0",
|
40 |
+
"typescript": "~5.4.2"
|
41 |
+
}
|
42 |
+
}
|
src/.DS_Store
ADDED
Binary file (6.15 kB). View file
|
|
src/app/app.component.css
ADDED
File without changes
|
src/app/app.component.html
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class='container' style="width: 100%;">
|
2 |
+
<app-header></app-header>
|
3 |
+
<br>
|
4 |
+
|
5 |
+
<router-outlet></router-outlet>
|
6 |
+
</div>
|
src/app/app.component.spec.ts
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { TestBed } from '@angular/core/testing';
|
2 |
+
import { AppComponent } from './app.component';
|
3 |
+
|
4 |
+
describe('AppComponent', () => {
|
5 |
+
beforeEach(async () => {
|
6 |
+
await TestBed.configureTestingModule({
|
7 |
+
imports: [AppComponent],
|
8 |
+
}).compileComponents();
|
9 |
+
});
|
10 |
+
|
11 |
+
it('should create the app', () => {
|
12 |
+
const fixture = TestBed.createComponent(AppComponent);
|
13 |
+
const app = fixture.componentInstance;
|
14 |
+
expect(app).toBeTruthy();
|
15 |
+
});
|
16 |
+
|
17 |
+
it(`should have the 'compuge-frontend' title`, () => {
|
18 |
+
const fixture = TestBed.createComponent(AppComponent);
|
19 |
+
const app = fixture.componentInstance;
|
20 |
+
expect(app.title).toEqual('compuge-frontend');
|
21 |
+
});
|
22 |
+
|
23 |
+
it('should render title', () => {
|
24 |
+
const fixture = TestBed.createComponent(AppComponent);
|
25 |
+
fixture.detectChanges();
|
26 |
+
const compiled = fixture.nativeElement as HTMLElement;
|
27 |
+
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, compuge-frontend');
|
28 |
+
});
|
29 |
+
});
|
src/app/app.component.ts
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Component } from '@angular/core';
|
2 |
+
import { RouterOutlet } from '@angular/router';
|
3 |
+
import {HeaderComponent} from "./components/header/header.component";
|
4 |
+
|
5 |
+
@Component({
|
6 |
+
selector: 'app-root',
|
7 |
+
standalone: true,
|
8 |
+
imports: [
|
9 |
+
RouterOutlet,
|
10 |
+
|
11 |
+
HeaderComponent],
|
12 |
+
templateUrl: './app.component.html',
|
13 |
+
styleUrl: './app.component.css'
|
14 |
+
})
|
15 |
+
export class AppComponent {
|
16 |
+
|
17 |
+
constructor(
|
18 |
+
) {
|
19 |
+
}
|
20 |
+
}
|
src/app/app.config.ts
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ApplicationConfig } from '@angular/core';
|
2 |
+
import {provideRouter, withComponentInputBinding} from '@angular/router';
|
3 |
+
|
4 |
+
import { routes } from './app.routes';
|
5 |
+
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
|
6 |
+
import {provideHttpClient, withFetch} from "@angular/common/http";
|
7 |
+
|
8 |
+
export const appConfig: ApplicationConfig = {
|
9 |
+
providers: [
|
10 |
+
provideRouter(routes, withComponentInputBinding()),
|
11 |
+
provideAnimationsAsync(),
|
12 |
+
provideAnimationsAsync(),
|
13 |
+
provideHttpClient(withFetch())
|
14 |
+
]
|
15 |
+
};
|
src/app/app.routes.ts
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import {Routes} from '@angular/router';
|
2 |
+
import {BodyComponent} from "./components/body/body.component";
|
3 |
+
import {TasksComponent} from "./components/body/tasks/tasks.component";
|
4 |
+
import {LeaderboardsComponent} from "./components/body/leaderboards/leaderboards.component";
|
5 |
+
import {SubmissionsComponent} from "./components/body/submissions/submissions.component";
|
6 |
+
import {DatasetsComponent} from "./components/body/datasets/datasets.component";
|
7 |
+
import {AboutComponent} from "./components/body/about/about.component";
|
8 |
+
import {TaskComponent} from "./components/body/tasks/task/task.component";
|
9 |
+
import {SubmittingComponent} from "./components/body/submitting/submitting.component";
|
10 |
+
|
11 |
+
export const routes: Routes = [
|
12 |
+
{path: '', component : BodyComponent},
|
13 |
+
{path: 'tasks', component: TasksComponent},
|
14 |
+
{path: 'tasks/:task', component: TaskComponent},
|
15 |
+
{path: 'submissions', component: SubmissionsComponent},
|
16 |
+
{path: 'submitting', component: SubmittingComponent},
|
17 |
+
{path: 'datasets', component: DatasetsComponent},
|
18 |
+
{path: 'about', component: AboutComponent},
|
19 |
+
{path: 'leaderboards', component: LeaderboardsComponent},
|
20 |
+
{path: 'leaderboards/:task', component: LeaderboardsComponent},
|
21 |
+
];
|
src/app/components/body/about/about.component.css
ADDED
File without changes
|
src/app/components/body/about/about.component.html
ADDED
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<mat-card>
|
2 |
+
|
3 |
+
<mat-card-content *ngIf="whatAbout === 'general'">
|
4 |
+
<br>
|
5 |
+
<p>
|
6 |
+
This System was built in the process of the research conducted by the Author Ahmad Shallouf for his Master Thesis
|
7 |
+
at the University of Hamburg.
|
8 |
+
<br>
|
9 |
+
The purpose of this system is to provide a Benchmark for the 4 main tasks of Comparative Question Answering in the
|
10 |
+
English Language.
|
11 |
+
<br>
|
12 |
+
The system is built using the Angular Framework for the Frontend and FastAPI Framework for the Backend with a
|
13 |
+
PostgreSQL Database.
|
14 |
+
</p>
|
15 |
+
<br>
|
16 |
+
<h3>Contact Information: </h3>
|
17 |
+
<table class="borderless table">
|
18 |
+
<tr>
|
19 |
+
<td>Name:</td>
|
20 |
+
<td>Ahmad Shallouf</td>
|
21 |
+
</tr>
|
22 |
+
<tr>
|
23 |
+
<td>Position:</td>
|
24 |
+
<td>Master Student</td>
|
25 |
+
</tr>
|
26 |
+
<tr>
|
27 |
+
<td>Email:</td>
|
28 |
+
<td>{{ '7shallou@informatik.uni-hamburg.de' }}</td>
|
29 |
+
</tr>
|
30 |
+
<tr>
|
31 |
+
<td>Phone:</td>
|
32 |
+
<td>+49 1762405080</td>
|
33 |
+
</tr>
|
34 |
+
</table>
|
35 |
+
|
36 |
+
</mat-card-content>
|
37 |
+
|
38 |
+
<mat-card-content *ngIf="whatAbout === 'Question Identification'">
|
39 |
+
<div style="display: flex;">
|
40 |
+
<div style="flex: 1; padding-right: 3%; text-align: justify;">
|
41 |
+
<p style="font-size: 18px">
|
42 |
+
The comparative question identification task involves detecting and classifying questions that aim to compare
|
43 |
+
entities, such as products or services. This task is important for applications like review summarization,
|
44 |
+
recommendation systems, and opinion mining. Researchers have developed methods involving natural language
|
45 |
+
processing techniques to accurately identify and categorize comparative questions from user-generated content.
|
46 |
+
These methods often require syntactic and semantic analysis to understand the nuances and patterns in language
|
47 |
+
that indicate comparisons.
|
48 |
+
<br><br>
|
49 |
+
Recent advancements in this field include the use of machine learning models and neural networks to improve
|
50 |
+
the accuracy of identifying comparative questions. These models are trained on large datasets to recognize
|
51 |
+
both explicit and implicit comparisons. Challenges in this area include handling context-dependent comparisons
|
52 |
+
and refining algorithms to better capture the intent behind complex linguistic structures. This work enhances
|
53 |
+
applications by providing deeper insights into user preferences and opinions through effective comparison
|
54 |
+
detection.
|
55 |
+
</p>
|
56 |
+
<div>
|
57 |
+
<br><br>
|
58 |
+
<h3>References</h3>
|
59 |
+
<ul>
|
60 |
+
<li><a href="https://aclanthology.org/P10-1067/" target="_blank">Li et al., 2010</a></li>
|
61 |
+
<li><a href="https://dl.acm.org/doi/10.1145/3336191.3371848" target="_blank">Bondarenko et al., 2020a</a>
|
62 |
+
</li>
|
63 |
+
<li><a href="https://dl.acm.org/doi/10.1145/3488560.3498534" target="_blank">Bondarenko et al., 2022a</a>
|
64 |
+
</li>
|
65 |
+
<li><a href="https://aclanthology.org/2022.lrec-1.402/" target="_blank">Beloucif et al., 2022</a></li>
|
66 |
+
<li><a href="https://aclanthology.org/2022.coling-1.138/" target="_blank">Sen et al., 2022</a></li>
|
67 |
+
</ul>
|
68 |
+
</div>
|
69 |
+
</div>
|
70 |
+
<div style="flex: 1; display: flex; align-items: center; justify-content: center;">
|
71 |
+
<!--- this image is in assets and is called cqi_explainer.svg --->
|
72 |
+
<img src="assets/cqi_explainer.svg" alt="Image Unavailable" style="max-width: 100%; height: auto; padding: 5%">
|
73 |
+
</div>
|
74 |
+
</div>
|
75 |
+
</mat-card-content>
|
76 |
+
|
77 |
+
|
78 |
+
<mat-card-content *ngIf="whatAbout === 'Object and Aspect Identification'">
|
79 |
+
<div style="display: flex;">
|
80 |
+
<div style="flex: 1; padding: 20px;">
|
81 |
+
<p>
|
82 |
+
Object and Aspect Labeling is a sequence tagging task aimed at identifying entities such as objects, aspects, and predicates in comparative questions.
|
83 |
+
<br><br>
|
84 |
+
There are at least three different datasets for this task. The dataset by Li et al. focuses on extracting objects of comparison but is not publicly available. The other two datasets, by Beloucif et al. and Bondarenko et al., have different annotation schemas and tags. Another dataset by Chekalina et al. includes labeled affirmative sentences.<br>
|
85 |
+
</p>
|
86 |
+
<div>
|
87 |
+
<br><br>
|
88 |
+
<h3>References</h3>
|
89 |
+
<ul>
|
90 |
+
<li><a href="https://aclanthology.org/P10-1067/" target="_blank">Li et al., 2010</a></li>
|
91 |
+
<li><a href="https://dl.acm.org/doi/10.1145/3488560.3498534" target="_blank">Bondarenko et al., 2022a</a></li>
|
92 |
+
<li><a href="https://aclanthology.org/2022.lrec-1.402/" target="_blank">Beloucif et al., 2022</a></li>
|
93 |
+
<li><a href="https://aclanthology.org/2021.eacl-demos.36/" target="_blank">Chekalina et al., 2021</a></li>
|
94 |
+
</ul>
|
95 |
+
</div>
|
96 |
+
</div>
|
97 |
+
<div style="flex: 1; display: flex; align-items: center; justify-content: center;">
|
98 |
+
<img src="assets/oai_explainer.svg" alt="Image Unavailable" style="max-width: 100%; height: auto; padding: 5%">
|
99 |
+
</div>
|
100 |
+
</div>
|
101 |
+
</mat-card-content>
|
102 |
+
|
103 |
+
|
104 |
+
<mat-card-content *ngIf="whatAbout === 'Stance Classification'">
|
105 |
+
<div style="display: flex;">
|
106 |
+
<div style="flex: 1; padding: 20px;">
|
107 |
+
<p>
|
108 |
+
Stance classification is one of the crucial subtasks of the whole pipeline, as we select relevant arguments and detect, in favor of which object the choice is made thanks to the class assigned at this step.
|
109 |
+
<br><br>
|
110 |
+
There is a dataset published by Panchenko et al. along with the baseline classifier, which is outperformed by Ma et al. Bondarenko et al. also introduces datasets and tests them on several models. However, their text excerpts are quite large and are not consistent with the argumentative sentences for our task.
|
111 |
+
</p>
|
112 |
+
<div>
|
113 |
+
<br><br>
|
114 |
+
<h3>References</h3>
|
115 |
+
<ul>
|
116 |
+
<li><a href="https://aclanthology.org/W19-4516/" target="_blank">Panchenko et al., 2019</a></li>
|
117 |
+
<li><a href="https://aclanthology.org/2020.acl-main.512/" target="_blank">Ma et al., 2020</a></li>
|
118 |
+
<li><a href="https://dl.acm.org/doi/10.1145/3488560.3498534" target="_blank">Bondarenko et al., 2022a</a></li>
|
119 |
+
</ul>
|
120 |
+
</div>
|
121 |
+
</div>
|
122 |
+
<div style="flex: 1; display: flex; align-items: center; justify-content: center;">
|
123 |
+
<img src="assets/sc_explainer.svg" alt="Image Unavailable" style="max-width: 100%; height: auto; padding: 5%">
|
124 |
+
</div>
|
125 |
+
</div>
|
126 |
+
</mat-card-content>
|
127 |
+
|
128 |
+
|
129 |
+
<mat-card-content *ngIf="whatAbout === 'Summary Generation'">
|
130 |
+
<div style="display: flex;">
|
131 |
+
<div style="flex: 1; padding: 20px;">
|
132 |
+
<p>
|
133 |
+
Comparative Summary Generation is a relatively recent and less widespread task.
|
134 |
+
<br> <br>
|
135 |
+
To the best of our knowledge, only two papers introduce datasets and baseline approaches. Chekalina et al. (2021) presents comparative questions with their best answers from Yahoo! Answers and tests several unsupervised approaches, including CTRL and template-based answers. Yu et al. (2023) pre-trains LLMs for comparative reasoning using prompts and introduces a dataset called “Diffen” that works with summarizing arguments for an object pair, though it is not publicly available.<br>
|
136 |
+
</p>
|
137 |
+
<div>
|
138 |
+
<br>
|
139 |
+
<br>
|
140 |
+
<h3>References</h3>
|
141 |
+
<ul>
|
142 |
+
<li><a href="https://arxiv.org/abs/2305.14457" target="_blank">Yu et al., 2023</a></li>
|
143 |
+
<li><a href="https://arxiv.org/abs/1909.05858" target="_blank">Keskar et al., 2019</a></li>
|
144 |
+
<li><a href="https://aclanthology.org/2021.eacl-demos.36/" target="_blank">Chekalina et al., 2021</a></li>
|
145 |
+
</ul>
|
146 |
+
</div>
|
147 |
+
</div>
|
148 |
+
<div style="flex: 1; display: flex; align-items: center; justify-content: center;">
|
149 |
+
<img src="assets/sg_explainer.svg" alt="Image Unavailable" style="max-width: 100%; height: auto; padding: 5%">
|
150 |
+
</div>
|
151 |
+
</div>
|
152 |
+
</mat-card-content>
|
153 |
+
|
154 |
+
</mat-card>
|
src/app/components/body/about/about.component.spec.ts
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
2 |
+
|
3 |
+
import { AboutComponent } from './about.component';
|
4 |
+
|
5 |
+
describe('AboutComponent', () => {
|
6 |
+
let component: AboutComponent;
|
7 |
+
let fixture: ComponentFixture<AboutComponent>;
|
8 |
+
|
9 |
+
beforeEach(async () => {
|
10 |
+
await TestBed.configureTestingModule({
|
11 |
+
imports: [AboutComponent]
|
12 |
+
})
|
13 |
+
.compileComponents();
|
14 |
+
|
15 |
+
fixture = TestBed.createComponent(AboutComponent);
|
16 |
+
component = fixture.componentInstance;
|
17 |
+
fixture.detectChanges();
|
18 |
+
});
|
19 |
+
|
20 |
+
it('should create', () => {
|
21 |
+
expect(component).toBeTruthy();
|
22 |
+
});
|
23 |
+
});
|
src/app/components/body/about/about.component.ts
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import {Component, Input, OnInit} from '@angular/core';
|
2 |
+
import {MatCard, MatCardContent} from "@angular/material/card";
|
3 |
+
import {NgIf} from "@angular/common";
|
4 |
+
|
5 |
+
@Component({
|
6 |
+
selector: 'app-about',
|
7 |
+
standalone: true,
|
8 |
+
imports: [
|
9 |
+
MatCard,
|
10 |
+
MatCardContent,
|
11 |
+
NgIf
|
12 |
+
],
|
13 |
+
templateUrl: './about.component.html',
|
14 |
+
styleUrl: './about.component.css'
|
15 |
+
})
|
16 |
+
export class AboutComponent implements OnInit{
|
17 |
+
|
18 |
+
@Input()
|
19 |
+
whatAbout = 'general';
|
20 |
+
|
21 |
+
constructor() { }
|
22 |
+
|
23 |
+
ngOnInit() {
|
24 |
+
if (this.whatAbout === undefined) {
|
25 |
+
this.whatAbout = 'general';
|
26 |
+
}
|
27 |
+
}
|
28 |
+
|
29 |
+
|
30 |
+
}
|
src/app/components/body/body.component.css
ADDED
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.container {
|
2 |
+
display: flex;
|
3 |
+
justify-content: center;
|
4 |
+
align-items: center;
|
5 |
+
box-sizing: border-box;
|
6 |
+
}
|
7 |
+
|
8 |
+
mat-card {
|
9 |
+
width: 100%;
|
10 |
+
text-align: justify;
|
11 |
+
}
|
12 |
+
|
13 |
+
mat-card-header {
|
14 |
+
display: flex;
|
15 |
+
justify-content: center;
|
16 |
+
}
|
17 |
+
|
18 |
+
mat-card-title {
|
19 |
+
width: 100%;
|
20 |
+
text-align: center;
|
21 |
+
}
|
22 |
+
|
23 |
+
.section-content {
|
24 |
+
margin-top: 20px;
|
25 |
+
}
|
26 |
+
|
27 |
+
.example-question {
|
28 |
+
display: flex;
|
29 |
+
justify-content: center;
|
30 |
+
gap: 10px;
|
31 |
+
margin: 10px 0;
|
32 |
+
}
|
33 |
+
|
34 |
+
.example-question img {
|
35 |
+
width: 400px;
|
36 |
+
height: auto;
|
37 |
+
border-radius: 4px;
|
38 |
+
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
39 |
+
}
|
40 |
+
|
41 |
+
.response-images {
|
42 |
+
display: flex;
|
43 |
+
flex-direction: column;
|
44 |
+
align-items: center;
|
45 |
+
}
|
46 |
+
|
47 |
+
.response-images img {
|
48 |
+
margin-top: 10px;
|
49 |
+
width: 800px;
|
50 |
+
height: auto;
|
51 |
+
border-radius: 4px;
|
52 |
+
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
53 |
+
}
|
54 |
+
|
55 |
+
.task-buttons {
|
56 |
+
display: grid;
|
57 |
+
grid-template-columns: 1fr 1fr;
|
58 |
+
gap: 10px;
|
59 |
+
margin: 20px 0;
|
60 |
+
}
|
61 |
+
|
62 |
+
.task-buttons button {
|
63 |
+
height: 80px;
|
64 |
+
}
|
65 |
+
|
66 |
+
.submit-button {
|
67 |
+
width: 100%;
|
68 |
+
height: 80px;
|
69 |
+
margin-top: 20px;
|
70 |
+
}
|
71 |
+
|
72 |
+
.nav-buttons {
|
73 |
+
display: flex;
|
74 |
+
justify-content: center;
|
75 |
+
gap: 10px;
|
76 |
+
}
|
77 |
+
|
78 |
+
.nav-buttons button {
|
79 |
+
width: 100%;
|
80 |
+
height: 80px;
|
81 |
+
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
82 |
+
}
|
83 |
+
|
84 |
+
.image-grid {
|
85 |
+
display: grid;
|
86 |
+
grid-template-columns: 25% 50% 25%;
|
87 |
+
gap: 5px;
|
88 |
+
}
|
89 |
+
|
90 |
+
.image1 {
|
91 |
+
grid-column: 1;
|
92 |
+
grid-row: span 2; /* This spans the first image across two rows */
|
93 |
+
}
|
94 |
+
|
95 |
+
.image2 {
|
96 |
+
grid-column: 2;
|
97 |
+
grid-row: 1 / 2; /* This places the second image in the first row of the second column */
|
98 |
+
}
|
99 |
+
|
100 |
+
.image3 {
|
101 |
+
grid-column: 2;
|
102 |
+
grid-row: 2 / 3; /* This places the third image in the second row of the second column */
|
103 |
+
}
|
104 |
+
|
105 |
+
.image4 {
|
106 |
+
grid-column: 3;
|
107 |
+
grid-row: span 2; /* This spans the fourth image across two rows */
|
108 |
+
}
|
109 |
+
|
110 |
+
.image-grid-item img {
|
111 |
+
width: 100%;
|
112 |
+
height: 100%;
|
113 |
+
object-fit: cover;
|
114 |
+
}
|
src/app/components/body/body.component.html
ADDED
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="container">
|
2 |
+
<mat-card>
|
3 |
+
<mat-card-header>
|
4 |
+
<mat-card-title>
|
5 |
+
<h1>Welcome to CompUGE</h1>
|
6 |
+
</mat-card-title>
|
7 |
+
</mat-card-header>
|
8 |
+
<mat-card-content>
|
9 |
+
<section>
|
10 |
+
<h2>What is Comparative Question Answering?</h2>
|
11 |
+
<p>Comparative question answering (CQA) is a specialized field within natural language processing (NLP) focused
|
12 |
+
on generating responses to questions that require comparing two or more entities across specific attributes or
|
13 |
+
dimensions. This involves identifying the entities and attributes in the query, retrieving relevant
|
14 |
+
information from various sources, and synthesizing this data into a coherent comparison. CQA systems are
|
15 |
+
particularly useful in domains such as e-commerce, healthcare, education, and technology, where users seek
|
16 |
+
detailed comparisons to make informed decisions. These systems face challenges such as handling ambiguous
|
17 |
+
queries, understanding context, ensuring data quality, and developing robust evaluation metrics to assess the
|
18 |
+
accuracy and relevance of the comparisons generated.</p>
|
19 |
+
<section>
|
20 |
+
<br><br>
|
21 |
+
<h2>What is CompUGE?</h2>
|
22 |
+
<p>
|
23 |
+
CompUGE is an acronym for Comparative Understanding and Generation Evaluation, a platform designed to
|
24 |
+
facilitate research and development in the field of comparative question answering (CQA). The platform
|
25 |
+
provides access to benchmark datasets, evaluation metrics, leaderboards, and submission guidelines for
|
26 |
+
researchers and practitioners working on CQA systems. By offering a centralized hub for sharing resources
|
27 |
+
and comparing performance across different models, CompUGE aims to advance the state of the art in CQA and
|
28 |
+
foster collaboration within the research community.
|
29 |
+
</p>
|
30 |
+
</section>
|
31 |
+
|
32 |
+
<p>
|
33 |
+
Here's an example of a comparative question being processes by the
|
34 |
+
<a href="https://cam-v2.ltdemos.informatik.uni-hamburg.de">CAM 2.0 System</a>
|
35 |
+
introduced in the paper
|
36 |
+
<a href="https://aclanthology.org/2024.lrec-main.238">"CAM 2.0: End-to-End Open Domain Comparative Question
|
37 |
+
Answering System"</a>
|
38 |
+
by our team and accepted at
|
39 |
+
<a href="https://lrec-coling-2024.org">LREC-Coling 2024</a>.
|
40 |
+
</p>
|
41 |
+
<div class="section-content">
|
42 |
+
<mat-expansion-panel>
|
43 |
+
<mat-expansion-panel-header>
|
44 |
+
<mat-panel-title>
|
45 |
+
<h2 style="text-align: center; margin-top: 15px">What is better: Harry Potter or Lord of the Rings?</h2>
|
46 |
+
</mat-panel-title>
|
47 |
+
</mat-expansion-panel-header>
|
48 |
+
|
49 |
+
<div class="image-grid">
|
50 |
+
<div class="image-grid-item image1">
|
51 |
+
<img src="assets/hp.jpg" alt="Image 1">
|
52 |
+
</div>
|
53 |
+
<div class="image-grid-item image2">
|
54 |
+
<img src="assets/cam_response1.jpg" alt="Image 2">
|
55 |
+
</div>
|
56 |
+
<div class="image-grid-item image3">
|
57 |
+
<img src="assets/cam_response2.jpg" alt="Image 3">
|
58 |
+
</div>
|
59 |
+
<div class="image-grid-item image4">
|
60 |
+
<img src="assets/lotr.jpg" alt="Image 4">
|
61 |
+
</div>
|
62 |
+
</div>
|
63 |
+
|
64 |
+
</mat-expansion-panel>
|
65 |
+
</div>
|
66 |
+
</section>
|
67 |
+
|
68 |
+
<div class="task-buttons">
|
69 |
+
<button
|
70 |
+
*ngFor="let task of (tasks | async)"
|
71 |
+
mat-raised-button color="primary"
|
72 |
+
routerLink="/tasks/{{ task.name }}"
|
73 |
+
>{{ task.name }}
|
74 |
+
</button>
|
75 |
+
</div>
|
76 |
+
|
77 |
+
<nav class="nav-buttons">
|
78 |
+
<button mat-button routerLink="/leaderboards">Leaderboards</button>
|
79 |
+
<button mat-button routerLink="/datasets">Datasets</button>
|
80 |
+
<button mat-button routerLink="/submissions">Submissions List</button>
|
81 |
+
</nav>
|
82 |
+
|
83 |
+
<button mat-raised-button color="accent" class="submit-button">Submit a Model</button>
|
84 |
+
|
85 |
+
</mat-card-content>
|
86 |
+
</mat-card>
|
87 |
+
</div>
|
src/app/components/body/body.component.spec.ts
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
2 |
+
|
3 |
+
import { BodyComponent } from './body.component';
|
4 |
+
|
5 |
+
describe('BodyComponent', () => {
|
6 |
+
let component: BodyComponent;
|
7 |
+
let fixture: ComponentFixture<BodyComponent>;
|
8 |
+
|
9 |
+
beforeEach(async () => {
|
10 |
+
await TestBed.configureTestingModule({
|
11 |
+
imports: [BodyComponent]
|
12 |
+
})
|
13 |
+
.compileComponents();
|
14 |
+
|
15 |
+
fixture = TestBed.createComponent(BodyComponent);
|
16 |
+
component = fixture.componentInstance;
|
17 |
+
fixture.detectChanges();
|
18 |
+
});
|
19 |
+
|
20 |
+
it('should create', () => {
|
21 |
+
expect(component).toBeTruthy();
|
22 |
+
});
|
23 |
+
});
|
src/app/components/body/body.component.ts
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Component } from '@angular/core';
|
2 |
+
import {MatTab, MatTabGroup} from "@angular/material/tabs";
|
3 |
+
import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from "@angular/material/card";
|
4 |
+
import {LeaderboardsComponent} from "./leaderboards/leaderboards.component";
|
5 |
+
import {AboutComponent} from "./about/about.component";
|
6 |
+
|
7 |
+
import {SubmissionsComponent} from "./submissions/submissions.component";
|
8 |
+
import {DashboardComponent} from "./dashboard/dashboard.component";
|
9 |
+
import {TasksComponent} from "./tasks/tasks.component";
|
10 |
+
import {DatasetsComponent} from "./datasets/datasets.component";
|
11 |
+
import {MatButton} from "@angular/material/button";
|
12 |
+
import {AppStateService} from "../../state_management/services/app-state.service";
|
13 |
+
import {map} from "rxjs";
|
14 |
+
import {AsyncPipe, NgForOf, NgOptimizedImage} from "@angular/common";
|
15 |
+
import {RouterLink} from "@angular/router";
|
16 |
+
import {MatExpansionPanel, MatExpansionPanelHeader, MatExpansionPanelTitle} from "@angular/material/expansion";
|
17 |
+
|
18 |
+
@Component({
|
19 |
+
selector: 'app-body',
|
20 |
+
standalone: true,
|
21 |
+
imports: [
|
22 |
+
MatTabGroup,
|
23 |
+
MatTab,
|
24 |
+
MatCard,
|
25 |
+
LeaderboardsComponent,
|
26 |
+
AboutComponent,
|
27 |
+
SubmissionsComponent,
|
28 |
+
DashboardComponent,
|
29 |
+
TasksComponent,
|
30 |
+
DatasetsComponent,
|
31 |
+
MatCardContent,
|
32 |
+
MatCardTitle,
|
33 |
+
MatCardHeader,
|
34 |
+
MatButton,
|
35 |
+
AsyncPipe,
|
36 |
+
NgForOf,
|
37 |
+
NgOptimizedImage,
|
38 |
+
RouterLink,
|
39 |
+
MatExpansionPanel,
|
40 |
+
MatExpansionPanelTitle,
|
41 |
+
MatExpansionPanelHeader
|
42 |
+
],
|
43 |
+
templateUrl: './body.component.html',
|
44 |
+
styleUrl: './body.component.css'
|
45 |
+
})
|
46 |
+
export class BodyComponent {
|
47 |
+
|
48 |
+
tasks = this.stateService.state$.pipe(
|
49 |
+
map(state => state.tasks)
|
50 |
+
);
|
51 |
+
|
52 |
+
constructor(
|
53 |
+
private stateService: AppStateService
|
54 |
+
) { }
|
55 |
+
|
56 |
+
}
|
src/app/components/body/dashboard/dashboard.component.css
ADDED
File without changes
|
src/app/components/body/dashboard/dashboard.component.html
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
<p>dashboard works!</p>
|
src/app/components/body/dashboard/dashboard.component.spec.ts
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
2 |
+
|
3 |
+
import { DashboardComponent } from './dashboard.component';
|
4 |
+
|
5 |
+
describe('DashboardComponent', () => {
|
6 |
+
let component: DashboardComponent;
|
7 |
+
let fixture: ComponentFixture<DashboardComponent>;
|
8 |
+
|
9 |
+
beforeEach(async () => {
|
10 |
+
await TestBed.configureTestingModule({
|
11 |
+
imports: [DashboardComponent]
|
12 |
+
})
|
13 |
+
.compileComponents();
|
14 |
+
|
15 |
+
fixture = TestBed.createComponent(DashboardComponent);
|
16 |
+
component = fixture.componentInstance;
|
17 |
+
fixture.detectChanges();
|
18 |
+
});
|
19 |
+
|
20 |
+
it('should create', () => {
|
21 |
+
expect(component).toBeTruthy();
|
22 |
+
});
|
23 |
+
});
|
src/app/components/body/dashboard/dashboard.component.ts
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Component } from '@angular/core';
|
2 |
+
|
3 |
+
@Component({
|
4 |
+
selector: 'app-dashboard',
|
5 |
+
standalone: true,
|
6 |
+
imports: [],
|
7 |
+
templateUrl: './dashboard.component.html',
|
8 |
+
styleUrl: './dashboard.component.css'
|
9 |
+
})
|
10 |
+
export class DashboardComponent {
|
11 |
+
|
12 |
+
}
|
src/app/components/body/datasets/dataset/dataset.component.css
ADDED
File without changes
|
src/app/components/body/datasets/dataset/dataset.component.html
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<mat-expansion-panel>
|
2 |
+
<mat-expansion-panel-header>
|
3 |
+
<mat-panel-title>
|
4 |
+
<h2 style="margin-top: 15px">{{ datasetModel.name }} ({{ datasetModel.task }})</h2>
|
5 |
+
</mat-panel-title>
|
6 |
+
</mat-expansion-panel-header>
|
7 |
+
<p>{{ datasetModel.description }}</p>
|
8 |
+
<p>
|
9 |
+
This dataset was introduced in the following paper:
|
10 |
+
<a href="{{datasetModel.paper_link}}" target="_blank">{{ datasetModel.paper }}</a>
|
11 |
+
</p>
|
12 |
+
|
13 |
+
<button mat-raised-button (click)="goToUrl(datasetModel.link)" style="width: 99%; margin: 0.5%">Link to the
|
14 |
+
Dataset
|
15 |
+
</button>
|
16 |
+
|
17 |
+
<!-- Training Data Button -->
|
18 |
+
<button *ngIf="datasetModel.train"
|
19 |
+
mat-raised-button
|
20 |
+
[ngStyle]="{
|
21 |
+
'width': !datasetModel.val ? '49.5%' : '33%'
|
22 |
+
}"
|
23 |
+
style="margin-left: 0.3%; margin-right: 0.1%"
|
24 |
+
(click)="downloadData(datasetModel.train, 'train')">
|
25 |
+
Download Training Data
|
26 |
+
</button>
|
27 |
+
|
28 |
+
<!-- Validation Data Button -->
|
29 |
+
<button *ngIf="datasetModel.val"
|
30 |
+
mat-raised-button
|
31 |
+
[ngStyle]="{
|
32 |
+
'width': !datasetModel.train ? '49.5%' : '33%'
|
33 |
+
}"
|
34 |
+
style="margin: 0.1%"
|
35 |
+
(click)="downloadData(datasetModel.val, 'validation')">
|
36 |
+
Download Validation Data
|
37 |
+
</button>
|
38 |
+
|
39 |
+
<!-- Testing Data Button (always present) -->
|
40 |
+
<button mat-raised-button
|
41 |
+
[ngStyle]="{
|
42 |
+
'width': !datasetModel.train && !datasetModel.val ? '99%' : (!datasetModel.train || !datasetModel.val) ? '49.5%' : '33%'
|
43 |
+
}"
|
44 |
+
style="margin-right: 0.3%; margin-left: 0.1%"
|
45 |
+
(click)="downloadData(datasetModel.test, 'test')">
|
46 |
+
Download Testing Data
|
47 |
+
</button>
|
48 |
+
</mat-expansion-panel>
|
src/app/components/body/datasets/dataset/dataset.component.spec.ts
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
2 |
+
|
3 |
+
import { DatasetComponent } from './dataset.component';
|
4 |
+
|
5 |
+
describe('DatasetComponent', () => {
|
6 |
+
let component: DatasetComponent;
|
7 |
+
let fixture: ComponentFixture<DatasetComponent>;
|
8 |
+
|
9 |
+
beforeEach(async () => {
|
10 |
+
await TestBed.configureTestingModule({
|
11 |
+
imports: [DatasetComponent]
|
12 |
+
})
|
13 |
+
.compileComponents();
|
14 |
+
|
15 |
+
fixture = TestBed.createComponent(DatasetComponent);
|
16 |
+
component = fixture.componentInstance;
|
17 |
+
fixture.detectChanges();
|
18 |
+
});
|
19 |
+
|
20 |
+
it('should create', () => {
|
21 |
+
expect(component).toBeTruthy();
|
22 |
+
});
|
23 |
+
});
|
src/app/components/body/datasets/dataset/dataset.component.ts
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import {Component, Input} from '@angular/core';
|
2 |
+
import {MatCard, MatCardContent} from "@angular/material/card";
|
3 |
+
import {MatButton} from "@angular/material/button";
|
4 |
+
import {MatExpansionPanel, MatExpansionPanelHeader, MatExpansionPanelTitle} from "@angular/material/expansion";
|
5 |
+
import {DatasetModel} from "../../../../state_management/models/dataset.model";
|
6 |
+
import {NgIf, NgStyle} from "@angular/common";
|
7 |
+
|
8 |
+
@Component({
|
9 |
+
selector: 'app-dataset',
|
10 |
+
standalone: true,
|
11 |
+
imports: [
|
12 |
+
MatCard,
|
13 |
+
MatCardContent,
|
14 |
+
MatButton,
|
15 |
+
MatExpansionPanel,
|
16 |
+
MatExpansionPanelHeader,
|
17 |
+
MatExpansionPanelTitle,
|
18 |
+
NgIf,
|
19 |
+
NgStyle
|
20 |
+
],
|
21 |
+
templateUrl: './dataset.component.html',
|
22 |
+
styleUrl: './dataset.component.css'
|
23 |
+
})
|
24 |
+
export class DatasetComponent {
|
25 |
+
|
26 |
+
@Input()
|
27 |
+
public datasetModel: DatasetModel = {
|
28 |
+
task: '',
|
29 |
+
name: '',
|
30 |
+
description: '',
|
31 |
+
link: '',
|
32 |
+
paper: '',
|
33 |
+
paper_link: '',
|
34 |
+
train: [],
|
35 |
+
test: [],
|
36 |
+
val: []
|
37 |
+
};
|
38 |
+
|
39 |
+
getTextDownloadURL(data: string[]) {
|
40 |
+
return window.URL.createObjectURL(new Blob(data, {type: 'text/plain'}));
|
41 |
+
}
|
42 |
+
|
43 |
+
downloadData(data: string[], name: string) {
|
44 |
+
const url = this.getTextDownloadURL(data);
|
45 |
+
const a = document.createElement('a');
|
46 |
+
a.href = url;
|
47 |
+
a.download = this.datasetModel.task + '-' + this.datasetModel.name + '-' + name + '.csv';
|
48 |
+
document.body.appendChild(a);
|
49 |
+
a.click();
|
50 |
+
window.URL.revokeObjectURL(url);
|
51 |
+
}
|
52 |
+
|
53 |
+
goToUrl(url: string) {
|
54 |
+
window.open(url, '_blank');
|
55 |
+
}
|
56 |
+
}
|
src/app/components/body/datasets/datasets.component.css
ADDED
File without changes
|
src/app/components/body/datasets/datasets.component.html
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div style="margin-bottom: 10px" *ngFor="let i of datasets | async">
|
2 |
+
<app-dataset
|
3 |
+
[datasetModel]="i">
|
4 |
+
</app-dataset>
|
5 |
+
</div>
|
6 |
+
<br>
|
7 |
+
|
src/app/components/body/datasets/datasets.component.spec.ts
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
2 |
+
|
3 |
+
import { DatasetsComponent } from './datasets.component';
|
4 |
+
|
5 |
+
describe('DatasetsComponent', () => {
|
6 |
+
let component: DatasetsComponent;
|
7 |
+
let fixture: ComponentFixture<DatasetsComponent>;
|
8 |
+
|
9 |
+
beforeEach(async () => {
|
10 |
+
await TestBed.configureTestingModule({
|
11 |
+
imports: [DatasetsComponent]
|
12 |
+
})
|
13 |
+
.compileComponents();
|
14 |
+
|
15 |
+
fixture = TestBed.createComponent(DatasetsComponent);
|
16 |
+
component = fixture.componentInstance;
|
17 |
+
fixture.detectChanges();
|
18 |
+
});
|
19 |
+
|
20 |
+
it('should create', () => {
|
21 |
+
expect(component).toBeTruthy();
|
22 |
+
});
|
23 |
+
});
|
src/app/components/body/datasets/datasets.component.ts
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import {Component, Input, OnInit} from '@angular/core';
|
2 |
+
import {AppStateService} from "../../../state_management/services/app-state.service";
|
3 |
+
import {DatasetComponent} from "./dataset/dataset.component";
|
4 |
+
import {AsyncPipe, NgForOf} from "@angular/common";
|
5 |
+
import {map, Observable} from "rxjs";
|
6 |
+
|
7 |
+
@Component({
|
8 |
+
selector: 'app-datasets',
|
9 |
+
standalone: true,
|
10 |
+
imports: [
|
11 |
+
DatasetComponent,
|
12 |
+
NgForOf,
|
13 |
+
AsyncPipe
|
14 |
+
],
|
15 |
+
templateUrl: './datasets.component.html',
|
16 |
+
styleUrl: './datasets.component.css'
|
17 |
+
})
|
18 |
+
export class DatasetsComponent implements OnInit {
|
19 |
+
|
20 |
+
@Input() datasets!: Observable<any[]>;
|
21 |
+
|
22 |
+
constructor(
|
23 |
+
private appState: AppStateService,
|
24 |
+
) {}
|
25 |
+
|
26 |
+
ngOnInit(): void {
|
27 |
+
if (!this.datasets) {
|
28 |
+
this.datasets = this.appState.state$.pipe(
|
29 |
+
map(state => state.datasets)
|
30 |
+
);
|
31 |
+
}
|
32 |
+
}
|
33 |
+
|
34 |
+
}
|
src/app/components/body/leaderboards/leaderboard/leaderboard.component.css
ADDED
File without changes
|
src/app/components/body/leaderboards/leaderboard/leaderboard.component.html
ADDED
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<mat-card>
|
2 |
+
<button mat-raised-button color="primary" (click)="refresh()">Refresh Leaderboard</button>
|
3 |
+
<table mat-table [dataSource]=dataSource>
|
4 |
+
|
5 |
+
<ng-container matColumnDef="model">
|
6 |
+
<mat-header-cell
|
7 |
+
*matHeaderCellDef
|
8 |
+
>
|
9 |
+
Model
|
10 |
+
</mat-header-cell>
|
11 |
+
<mat-cell *matCellDef="let entry">
|
12 |
+
<a *ngIf="entry.is_public" [href]="entry.link" target="_blank"> {{ entry.model }}</a>
|
13 |
+
<span *ngIf="entry.isPublic">{{ entry.model }}</span>
|
14 |
+
</mat-cell>
|
15 |
+
</ng-container>
|
16 |
+
|
17 |
+
<ng-container matColumnDef="team">
|
18 |
+
<mat-header-cell
|
19 |
+
*matHeaderCellDef
|
20 |
+
>
|
21 |
+
Team
|
22 |
+
</mat-header-cell>
|
23 |
+
<mat-cell *matCellDef="let entry">
|
24 |
+
<a *ngIf="entry.is_public" [href]="'mailto:' + entry.email" target="_blank"> {{ entry.team }}</a>
|
25 |
+
<span *ngIf="!entry.is_public">{{ entry.team }}</span>
|
26 |
+
</mat-cell>
|
27 |
+
</ng-container>
|
28 |
+
|
29 |
+
<ng-container matColumnDef="predictions">
|
30 |
+
<mat-header-cell
|
31 |
+
*matHeaderCellDef
|
32 |
+
>
|
33 |
+
Predictions
|
34 |
+
</mat-header-cell>
|
35 |
+
<mat-cell *matCellDef="let entry">
|
36 |
+
<a *ngIf="entry.is_public" [href]="getTextDownloadURL(entry.predictions)" target="_blank" download="{{entry.model + '-predictions.txt'}}">Download</a>
|
37 |
+
<span *ngIf="!entry.is_public">Private</span>
|
38 |
+
</mat-cell>
|
39 |
+
</ng-container>
|
40 |
+
|
41 |
+
<ng-container matColumnDef="accuracy">
|
42 |
+
<mat-header-cell
|
43 |
+
*matHeaderCellDef
|
44 |
+
>
|
45 |
+
Accuracy
|
46 |
+
</mat-header-cell>
|
47 |
+
<mat-cell *matCellDef="let entry">{{ entry.accuracy | number: '1.2-2' }}</mat-cell>
|
48 |
+
</ng-container>
|
49 |
+
|
50 |
+
<ng-container matColumnDef="precision">
|
51 |
+
<mat-header-cell
|
52 |
+
*matHeaderCellDef
|
53 |
+
>
|
54 |
+
Precision
|
55 |
+
</mat-header-cell>
|
56 |
+
<mat-cell *matCellDef="let entry">{{ entry.precision | number: '1.2-2' }}</mat-cell>
|
57 |
+
</ng-container>
|
58 |
+
|
59 |
+
<ng-container matColumnDef="recall">
|
60 |
+
<mat-header-cell
|
61 |
+
*matHeaderCellDef
|
62 |
+
>
|
63 |
+
Recall
|
64 |
+
</mat-header-cell>
|
65 |
+
<mat-cell *matCellDef="let entry">{{ entry.recall | number: '1.2-2'}}</mat-cell>
|
66 |
+
</ng-container>
|
67 |
+
|
68 |
+
<ng-container matColumnDef="f1">
|
69 |
+
<mat-header-cell
|
70 |
+
*matHeaderCellDef
|
71 |
+
>
|
72 |
+
F1
|
73 |
+
</mat-header-cell>
|
74 |
+
<mat-cell *matCellDef="let entry">{{ entry.f1_score | number: '1.2-2' }}</mat-cell>
|
75 |
+
</ng-container>
|
76 |
+
|
77 |
+
|
78 |
+
|
79 |
+
<mat-header-row
|
80 |
+
*matHeaderRowDef="displayedColumns; sticky: true"
|
81 |
+
></mat-header-row>
|
82 |
+
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
|
83 |
+
</table>
|
84 |
+
</mat-card>
|
src/app/components/body/leaderboards/leaderboard/leaderboard.component.spec.ts
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
2 |
+
|
3 |
+
import { LeaderboardsComponent} from "../leaderboards.component";
|
4 |
+
|
5 |
+
describe('LeaderboardComponent', () => {
|
6 |
+
let component: LeaderboardComponent;
|
7 |
+
let fixture: ComponentFixture<LeaderboardComponent>;
|
8 |
+
|
9 |
+
beforeEach(async () => {
|
10 |
+
await TestBed.configureTestingModule({
|
11 |
+
imports: [LeaderboardComponent]
|
12 |
+
})
|
13 |
+
.compileComponents();
|
14 |
+
|
15 |
+
fixture = TestBed.createComponent(LeaderboardComponent);
|
16 |
+
component = fixture.componentInstance;
|
17 |
+
fixture.detectChanges();
|
18 |
+
});
|
19 |
+
|
20 |
+
it('should create', () => {
|
21 |
+
expect(component).toBeTruthy();
|
22 |
+
});
|
23 |
+
});
|
src/app/components/body/leaderboards/leaderboard/leaderboard.component.ts
ADDED
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import {Component, Input, OnInit} from '@angular/core';
|
2 |
+
import {MatCard} from "@angular/material/card";
|
3 |
+
import {
|
4 |
+
MatCell,
|
5 |
+
MatCellDef, MatColumnDef,
|
6 |
+
MatHeaderCell,
|
7 |
+
MatHeaderCellDef, MatHeaderRow, MatHeaderRowDef, MatRow, MatRowDef,
|
8 |
+
MatTable,
|
9 |
+
MatTableDataSource
|
10 |
+
} from "@angular/material/table";
|
11 |
+
import {LeaderboardEntry} from "../../../../state_management/models/leaderboard-entry.model";
|
12 |
+
import {MatButton} from "@angular/material/button";
|
13 |
+
import {AppStateService} from "../../../../state_management/services/app-state.service";
|
14 |
+
import {map} from "rxjs";
|
15 |
+
import {DecimalPipe, NgIf} from "@angular/common";
|
16 |
+
|
17 |
+
@Component({
|
18 |
+
selector: 'app-leaderboard',
|
19 |
+
standalone: true,
|
20 |
+
imports: [
|
21 |
+
MatCard,
|
22 |
+
MatTable,
|
23 |
+
MatHeaderCell,
|
24 |
+
MatHeaderCellDef,
|
25 |
+
MatCell,
|
26 |
+
MatCellDef,
|
27 |
+
MatColumnDef,
|
28 |
+
MatHeaderRow,
|
29 |
+
MatHeaderRowDef,
|
30 |
+
MatRow,
|
31 |
+
MatRowDef,
|
32 |
+
MatButton,
|
33 |
+
NgIf,
|
34 |
+
DecimalPipe
|
35 |
+
],
|
36 |
+
templateUrl: './leaderboard.component.html',
|
37 |
+
styleUrl: './leaderboard.component.css'
|
38 |
+
})
|
39 |
+
export class LeaderboardComponent implements OnInit {
|
40 |
+
|
41 |
+
displayedColumns: string[] = [
|
42 |
+
'model',
|
43 |
+
'team',
|
44 |
+
'predictions',
|
45 |
+
'accuracy',
|
46 |
+
'precision',
|
47 |
+
'recall',
|
48 |
+
'f1'
|
49 |
+
];
|
50 |
+
|
51 |
+
@Input()
|
52 |
+
task : string = 'Question Identification';
|
53 |
+
|
54 |
+
@Input()
|
55 |
+
dataset : string = "CIFAR10";
|
56 |
+
|
57 |
+
dataSource = new MatTableDataSource<LeaderboardEntry>();
|
58 |
+
leaderboards = this.stateService.state$.pipe(map(state => state.leaderboards));
|
59 |
+
|
60 |
+
|
61 |
+
constructor(private stateService: AppStateService) {
|
62 |
+
|
63 |
+
}
|
64 |
+
|
65 |
+
ngOnInit() {
|
66 |
+
this.leaderboards.subscribe(
|
67 |
+
data => {
|
68 |
+
// choose only entries where task == this.task and dataset == this.dataset.
|
69 |
+
// assign the data to the dataSource
|
70 |
+
this.dataSource.data = data.filter(
|
71 |
+
entry => (entry.task == this.task && entry.dataset == this.dataset)
|
72 |
+
)
|
73 |
+
}
|
74 |
+
);
|
75 |
+
this.stateService.updateLeaderboards();
|
76 |
+
}
|
77 |
+
|
78 |
+
getTextDownloadURL(prediction: string) {
|
79 |
+
return window.URL.createObjectURL(new Blob([prediction], {type: 'text/plain'}));
|
80 |
+
}
|
81 |
+
|
82 |
+
refresh() {
|
83 |
+
this.stateService.updateLeaderboards();
|
84 |
+
}
|
85 |
+
}
|
src/app/components/body/leaderboards/leaderboards.component.css
ADDED
File without changes
|
src/app/components/body/leaderboards/leaderboards.component.html
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div>
|
2 |
+
<mat-card>
|
3 |
+
|
4 |
+
<!--
|
5 |
+
make a header with the task name, if the task is not '', align the text to the center
|
6 |
+
-->
|
7 |
+
<br>
|
8 |
+
<h1 *ngIf="task && showTask" style="text-align: center">
|
9 |
+
{{task}} Leaderboards
|
10 |
+
</h1>
|
11 |
+
|
12 |
+
<mat-tab-group>
|
13 |
+
<mat-tab
|
14 |
+
*ngFor="let dataset of datasets | async"
|
15 |
+
[label]="this.task? dataset.name : dataset.name + '(' + dataset.task + ')'"
|
16 |
+
>
|
17 |
+
<br>
|
18 |
+
<p>{{dataset.description}}</p>
|
19 |
+
<br>
|
20 |
+
<app-leaderboard
|
21 |
+
[task]="task"
|
22 |
+
[dataset]="dataset.name"
|
23 |
+
>
|
24 |
+
</app-leaderboard>
|
25 |
+
</mat-tab>
|
26 |
+
</mat-tab-group>
|
27 |
+
</mat-card>
|
28 |
+
</div>
|
src/app/components/body/leaderboards/leaderboards.component.spec.ts
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
2 |
+
|
3 |
+
import { LeaderboardsComponent } from './leaderboards.component';
|
4 |
+
|
5 |
+
describe('LeaderboardsComponent', () => {
|
6 |
+
let component: LeaderboardsComponent;
|
7 |
+
let fixture: ComponentFixture<LeaderboardsComponent>;
|
8 |
+
|
9 |
+
beforeEach(async () => {
|
10 |
+
await TestBed.configureTestingModule({
|
11 |
+
imports: [LeaderboardsComponent]
|
12 |
+
})
|
13 |
+
.compileComponents();
|
14 |
+
|
15 |
+
fixture = TestBed.createComponent(LeaderboardsComponent);
|
16 |
+
component = fixture.componentInstance;
|
17 |
+
fixture.detectChanges();
|
18 |
+
});
|
19 |
+
|
20 |
+
it('should create', () => {
|
21 |
+
expect(component).toBeTruthy();
|
22 |
+
});
|
23 |
+
});
|
src/app/components/body/leaderboards/leaderboards.component.ts
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core';
|
2 |
+
import {MatCard, MatCardHeader} from "@angular/material/card";
|
3 |
+
import {MatTab, MatTabGroup} from "@angular/material/tabs";
|
4 |
+
import {LeaderboardComponent} from "./leaderboard/leaderboard.component";
|
5 |
+
import {AppStateService} from "../../../state_management/services/app-state.service";
|
6 |
+
import {filter, map} from "rxjs";
|
7 |
+
import {AsyncPipe, NgForOf, NgIf} from "@angular/common";
|
8 |
+
|
9 |
+
@Component({
|
10 |
+
selector: 'app-leaderboards',
|
11 |
+
standalone: true,
|
12 |
+
imports: [
|
13 |
+
MatCard,
|
14 |
+
MatCardHeader,
|
15 |
+
MatTabGroup,
|
16 |
+
MatTab,
|
17 |
+
LeaderboardComponent,
|
18 |
+
AsyncPipe,
|
19 |
+
NgForOf,
|
20 |
+
NgIf
|
21 |
+
],
|
22 |
+
templateUrl: './leaderboards.component.html',
|
23 |
+
styleUrl: './leaderboards.component.css'
|
24 |
+
})
|
25 |
+
export class LeaderboardsComponent implements OnChanges {
|
26 |
+
|
27 |
+
@Input()
|
28 |
+
task: string = '';
|
29 |
+
|
30 |
+
@Input()
|
31 |
+
showTask: boolean = true;
|
32 |
+
|
33 |
+
datasets: any;
|
34 |
+
|
35 |
+
constructor(
|
36 |
+
private stateService: AppStateService
|
37 |
+
) {
|
38 |
+
this.updateDatasets();
|
39 |
+
}
|
40 |
+
|
41 |
+
ngOnChanges(changes: SimpleChanges): void {
|
42 |
+
if (changes['task']) {
|
43 |
+
this.updateDatasets();
|
44 |
+
}
|
45 |
+
}
|
46 |
+
|
47 |
+
private updateDatasets() {
|
48 |
+
this.datasets = this.stateService.state$.pipe(
|
49 |
+
map(state =>
|
50 |
+
state.datasets.filter(dataset =>
|
51 |
+
dataset.task === this.task || !this.task
|
52 |
+
)
|
53 |
+
),
|
54 |
+
);
|
55 |
+
}
|
56 |
+
|
57 |
+
}
|
src/app/components/body/submissions/submissions.component.css
ADDED
File without changes
|
src/app/components/body/submissions/submissions.component.html
ADDED
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!---
|
2 |
+
This component is used to display a list of submissions for all users, and allows a new submission to be made.
|
3 |
+
-->
|
4 |
+
|
5 |
+
<mat-card>
|
6 |
+
<mat-card-content>
|
7 |
+
<button mat-raised-button color="primary" style="width: 100%" (click)="refresh()">Refresh Submissions</button>
|
8 |
+
</mat-card-content>
|
9 |
+
|
10 |
+
<table mat-table [dataSource]=dataSource>
|
11 |
+
|
12 |
+
<ng-container matColumnDef="team">
|
13 |
+
<mat-header-cell
|
14 |
+
*matHeaderCellDef
|
15 |
+
>
|
16 |
+
Team
|
17 |
+
</mat-header-cell>
|
18 |
+
<mat-cell *matCellDef="let entry">
|
19 |
+
<a *ngIf="entry.is_public" [href]="'mailto:' + entry.email" target="_blank"> {{ entry.team }}</a>
|
20 |
+
<span *ngIf="!entry.is_public">{{ entry.team }}</span>
|
21 |
+
</mat-cell>
|
22 |
+
</ng-container>
|
23 |
+
|
24 |
+
<ng-container matColumnDef="task">
|
25 |
+
<mat-header-cell
|
26 |
+
*matHeaderCellDef
|
27 |
+
>
|
28 |
+
Task
|
29 |
+
</mat-header-cell>
|
30 |
+
<mat-cell *matCellDef="let entry">{{ entry.task }}</mat-cell>
|
31 |
+
</ng-container>
|
32 |
+
|
33 |
+
<ng-container matColumnDef="dataset">
|
34 |
+
<mat-header-cell
|
35 |
+
*matHeaderCellDef
|
36 |
+
>
|
37 |
+
Dataset
|
38 |
+
</mat-header-cell>
|
39 |
+
<mat-cell *matCellDef="let entry">{{ entry.dataset }}</mat-cell>
|
40 |
+
</ng-container>
|
41 |
+
|
42 |
+
<ng-container matColumnDef="model">
|
43 |
+
<mat-header-cell
|
44 |
+
*matHeaderCellDef
|
45 |
+
>
|
46 |
+
Model
|
47 |
+
</mat-header-cell>
|
48 |
+
<mat-cell *matCellDef="let entry">
|
49 |
+
<a *ngIf="entry.is_public" [href]="entry.link" target="_blank"> {{ entry.model }}</a>
|
50 |
+
<span *ngIf="entry.isPublic">{{ entry.model }}</span>
|
51 |
+
</mat-cell>
|
52 |
+
</ng-container>
|
53 |
+
|
54 |
+
<ng-container matColumnDef="predictions">
|
55 |
+
<mat-header-cell
|
56 |
+
*matHeaderCellDef
|
57 |
+
>
|
58 |
+
Predictions
|
59 |
+
</mat-header-cell>
|
60 |
+
<mat-cell *matCellDef="let entry">
|
61 |
+
<a *ngIf="entry.is_public" [href]="getTextDownloadURL(entry.predictions)" target="_blank" download="{{entry.model + '-predictions.txt'}}">Download</a>
|
62 |
+
<span *ngIf="!entry.is_public">Private</span>
|
63 |
+
</mat-cell>
|
64 |
+
</ng-container>
|
65 |
+
|
66 |
+
<ng-container matColumnDef="status">
|
67 |
+
<mat-header-cell
|
68 |
+
*matHeaderCellDef
|
69 |
+
>
|
70 |
+
Status
|
71 |
+
</mat-header-cell>
|
72 |
+
<mat-cell *matCellDef="let entry">{{ entry.status }}</mat-cell>
|
73 |
+
</ng-container>
|
74 |
+
|
75 |
+
<ng-container matColumnDef="time">
|
76 |
+
<mat-header-cell
|
77 |
+
*matHeaderCellDef
|
78 |
+
>
|
79 |
+
Time
|
80 |
+
</mat-header-cell>
|
81 |
+
<mat-cell *matCellDef="let entry">{{ entry.time }}</mat-cell>
|
82 |
+
</ng-container>
|
83 |
+
|
84 |
+
|
85 |
+
<mat-header-row
|
86 |
+
*matHeaderRowDef="displayedColumns; sticky: true"
|
87 |
+
></mat-header-row>
|
88 |
+
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
|
89 |
+
</table>
|
90 |
+
</mat-card>
|
src/app/components/body/submissions/submissions.component.spec.ts
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
2 |
+
|
3 |
+
import { SubmissionsComponent } from './submissions.component';
|
4 |
+
|
5 |
+
describe('SubmissionsComponent', () => {
|
6 |
+
let component: SubmissionsComponent;
|
7 |
+
let fixture: ComponentFixture<SubmissionsComponent>;
|
8 |
+
|
9 |
+
beforeEach(async () => {
|
10 |
+
await TestBed.configureTestingModule({
|
11 |
+
imports: [SubmissionsComponent]
|
12 |
+
})
|
13 |
+
.compileComponents();
|
14 |
+
|
15 |
+
fixture = TestBed.createComponent(SubmissionsComponent);
|
16 |
+
component = fixture.componentInstance;
|
17 |
+
fixture.detectChanges();
|
18 |
+
});
|
19 |
+
|
20 |
+
it('should create', () => {
|
21 |
+
expect(component).toBeTruthy();
|
22 |
+
});
|
23 |
+
});
|
src/app/components/body/submissions/submissions.component.ts
ADDED
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import {Component, Input, OnInit} from '@angular/core';
|
2 |
+
import {MatCard, MatCardActions, MatCardContent} from "@angular/material/card";
|
3 |
+
import {MatFormField, MatLabel} from "@angular/material/form-field";
|
4 |
+
import {MatInput} from "@angular/material/input";
|
5 |
+
import {MatButton} from "@angular/material/button";
|
6 |
+
import {NgIf} from "@angular/common";
|
7 |
+
import {MatOption} from "@angular/material/autocomplete";
|
8 |
+
import {MatSelect} from "@angular/material/select";
|
9 |
+
import {FormsModule} from "@angular/forms";
|
10 |
+
import {AppStateService} from "../../../state_management/services/app-state.service";
|
11 |
+
import {map} from "rxjs";
|
12 |
+
import {
|
13 |
+
MatCell,
|
14 |
+
MatCellDef,
|
15 |
+
MatColumnDef,
|
16 |
+
MatHeaderCell, MatHeaderCellDef,
|
17 |
+
MatHeaderRow,
|
18 |
+
MatHeaderRowDef,
|
19 |
+
MatRow, MatRowDef, MatTable, MatTableDataSource
|
20 |
+
} from "@angular/material/table";
|
21 |
+
import {LeaderboardEntry} from "../../../state_management/models/leaderboard-entry.model";
|
22 |
+
import {SubmissionEntry} from "../../../state_management/models/submission-entry.model";
|
23 |
+
import {MatTab, MatTabGroup} from "@angular/material/tabs";
|
24 |
+
|
25 |
+
@Component({
|
26 |
+
selector: 'app-submissions',
|
27 |
+
standalone: true,
|
28 |
+
imports: [
|
29 |
+
MatCard,
|
30 |
+
MatCardContent,
|
31 |
+
MatFormField,
|
32 |
+
MatInput,
|
33 |
+
MatButton,
|
34 |
+
MatCardActions,
|
35 |
+
MatLabel,
|
36 |
+
NgIf,
|
37 |
+
MatOption,
|
38 |
+
MatSelect,
|
39 |
+
FormsModule,
|
40 |
+
MatCell,
|
41 |
+
MatCellDef,
|
42 |
+
MatColumnDef,
|
43 |
+
MatHeaderCell,
|
44 |
+
MatHeaderRow,
|
45 |
+
MatHeaderRowDef,
|
46 |
+
MatRow,
|
47 |
+
MatRowDef,
|
48 |
+
MatTable,
|
49 |
+
MatHeaderCellDef,
|
50 |
+
MatTabGroup,
|
51 |
+
MatTab
|
52 |
+
],
|
53 |
+
templateUrl: './submissions.component.html',
|
54 |
+
styleUrl: './submissions.component.css'
|
55 |
+
})
|
56 |
+
export class SubmissionsComponent implements OnInit {
|
57 |
+
|
58 |
+
displayedColumns: string[] = [
|
59 |
+
'team',
|
60 |
+
'model',
|
61 |
+
'task',
|
62 |
+
'dataset',
|
63 |
+
'status',
|
64 |
+
'predictions',
|
65 |
+
'time',
|
66 |
+
];
|
67 |
+
|
68 |
+
@Input()
|
69 |
+
task: string = '';
|
70 |
+
|
71 |
+
constructor(private state: AppStateService) {
|
72 |
+
}
|
73 |
+
|
74 |
+
submissions = this.state.state$.pipe(
|
75 |
+
map(
|
76 |
+
state =>
|
77 |
+
state.submissions.filter(
|
78 |
+
submission =>
|
79 |
+
(submission.task == this.task || this.task == undefined)))
|
80 |
+
);
|
81 |
+
|
82 |
+
dataSource = new MatTableDataSource<SubmissionEntry>();
|
83 |
+
|
84 |
+
ngOnInit() {
|
85 |
+
this.submissions.subscribe(
|
86 |
+
data => {
|
87 |
+
this.dataSource.data = data;
|
88 |
+
}
|
89 |
+
)
|
90 |
+
}
|
91 |
+
|
92 |
+
getTextDownloadURL(prediction: string) {
|
93 |
+
return window.URL.createObjectURL(new Blob([prediction], {type: 'text/plain'}));
|
94 |
+
}
|
95 |
+
|
96 |
+
refresh() {
|
97 |
+
this.state.updateSubmissions();
|
98 |
+
}
|
99 |
+
}
|
src/app/components/body/submitting/submitting.component.css
ADDED
File without changes
|
src/app/components/body/submitting/submitting.component.html
ADDED
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!----
|
2 |
+
This component is for submitting a model for evaluation.
|
3 |
+
It is a form that takes in the model name, the model file, and the model's description.
|
4 |
+
---->
|
5 |
+
<mat-card>
|
6 |
+
<form [formGroup]="form" (ngSubmit)="onSubmit()">
|
7 |
+
|
8 |
+
<mat-card-content>
|
9 |
+
<mat-form-field appearance="outline" style="width: 100%">
|
10 |
+
<mat-label>Team Name</mat-label>
|
11 |
+
<input matInput formControlName="teamName" placeholder="Team Name" type="text">
|
12 |
+
</mat-form-field>
|
13 |
+
</mat-card-content>
|
14 |
+
|
15 |
+
|
16 |
+
<mat-card-content>
|
17 |
+
<mat-form-field appearance="outline" style="width: 100%">
|
18 |
+
<mat-label>Contact Email</mat-label>
|
19 |
+
<input matInput formControlName="teamName" placeholder="Contact Email" type="text" email>
|
20 |
+
</mat-form-field>
|
21 |
+
</mat-card-content>
|
22 |
+
|
23 |
+
<mat-card-content>
|
24 |
+
<mat-form-field appearance="outline" style="width: 100%">
|
25 |
+
<mat-label>Model Name</mat-label>
|
26 |
+
<input matInput formControlName="modelName" placeholder="Model Name" type="text">
|
27 |
+
</mat-form-field>
|
28 |
+
</mat-card-content>
|
29 |
+
|
30 |
+
<mat-card-content>
|
31 |
+
<mat-form-field appearance="outline" style="width: 100%">
|
32 |
+
<mat-label>Model Link</mat-label>
|
33 |
+
<input formControlName="modelLink" matInput placeholder="Model Link" type="text">
|
34 |
+
</mat-form-field>
|
35 |
+
</mat-card-content>
|
36 |
+
|
37 |
+
<mat-card-content>
|
38 |
+
<mat-form-field appearance="outline" style="width: 100%">
|
39 |
+
<mat-label>Task</mat-label>
|
40 |
+
<mat-select formControlName="task">
|
41 |
+
@for (task of tasks | async; track task) {
|
42 |
+
<mat-option [value]="task.name">{{ task.name }}</mat-option>
|
43 |
+
}
|
44 |
+
</mat-select>
|
45 |
+
</mat-form-field>
|
46 |
+
</mat-card-content>
|
47 |
+
|
48 |
+
<mat-card-content>
|
49 |
+
<mat-form-field appearance="outline" style="width: 100%">
|
50 |
+
<mat-label>Dataset</mat-label>
|
51 |
+
<mat-select formControlName="dataset">
|
52 |
+
@for (dataset of datasets|async; track dataset) {
|
53 |
+
<mat-option [value]="dataset.name">{{ dataset.name }} ({{dataset.task}})</mat-option>
|
54 |
+
}
|
55 |
+
</mat-select>
|
56 |
+
</mat-form-field>
|
57 |
+
</mat-card-content>
|
58 |
+
|
59 |
+
<mat-card-actions>
|
60 |
+
<button type="button" style="width: 100%" mat-raised-button (click)="predsFileInput.click()">Upload Model
|
61 |
+
Predictions {{ chosenFileName != '' ? ' - ' + chosenFileName : '' }}
|
62 |
+
</button>
|
63 |
+
<input hidden type="file" #predsFileInput formControlName="file" required (change)="onFileSelected($event)"/>
|
64 |
+
</mat-card-actions>
|
65 |
+
|
66 |
+
<br>
|
67 |
+
|
68 |
+
<mat-card-content>
|
69 |
+
<mat-form-field appearance="outline" style="width: 100%">
|
70 |
+
<mat-label>Make Predictions Public</mat-label>
|
71 |
+
<mat-select formControlName="isPublic" required>
|
72 |
+
<mat-option value="true">Yes</mat-option>
|
73 |
+
<mat-option value="false">No</mat-option>
|
74 |
+
</mat-select>
|
75 |
+
</mat-form-field>
|
76 |
+
</mat-card-content>
|
77 |
+
|
78 |
+
<mat-card-actions>
|
79 |
+
<button type="submit" mat-raised-button style="width: 100%" color="primary">
|
80 |
+
Submit
|
81 |
+
<label *ngIf="message != ''"> - {{ message }}</label>
|
82 |
+
</button>
|
83 |
+
</mat-card-actions>
|
84 |
+
|
85 |
+
</form>
|
86 |
+
|
87 |
+
</mat-card>
|
src/app/components/body/submitting/submitting.component.spec.ts
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
2 |
+
|
3 |
+
import { SubmittingComponent } from './submitting.component';
|
4 |
+
|
5 |
+
describe('SubmittingComponent', () => {
|
6 |
+
let component: SubmittingComponent;
|
7 |
+
let fixture: ComponentFixture<SubmittingComponent>;
|
8 |
+
|
9 |
+
beforeEach(async () => {
|
10 |
+
await TestBed.configureTestingModule({
|
11 |
+
imports: [SubmittingComponent]
|
12 |
+
})
|
13 |
+
.compileComponents();
|
14 |
+
|
15 |
+
fixture = TestBed.createComponent(SubmittingComponent);
|
16 |
+
component = fixture.componentInstance;
|
17 |
+
fixture.detectChanges();
|
18 |
+
});
|
19 |
+
|
20 |
+
it('should create', () => {
|
21 |
+
expect(component).toBeTruthy();
|
22 |
+
});
|
23 |
+
});
|