diff --git a/.gitignore b/.gitignore
index a1b1f0d3a7..8b796207f5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -71,5 +71,3 @@ out/
monitoring/prometheus/prometheus_db/*
!monitoring/prometheus/prometheus_db/.gitkeep
monitoring/grafana/grafana_db/grafana.db
-monitoring/prometheus/django/*
-!monitoring/prometheus/django/.gitkeep
diff --git a/apps/challenges/aws_utils.py b/apps/challenges/aws_utils.py
index acc1e8181f..d9fae7905c 100644
--- a/apps/challenges/aws_utils.py
+++ b/apps/challenges/aws_utils.py
@@ -1146,7 +1146,10 @@ def restart_workers(queryset):
count = 0
failures = []
for challenge in queryset:
- if challenge.is_docker_based:
+ if (
+ challenge.is_docker_based
+ and not challenge.is_static_dataset_code_upload
+ ):
response = "Sorry. This feature is not available for code upload/docker based challenges."
failures.append(
{"message": response, "challenge_pk": challenge.pk}
diff --git a/apps/challenges/serializers.py b/apps/challenges/serializers.py
index 6e28744f12..4fa6a24bee 100644
--- a/apps/challenges/serializers.py
+++ b/apps/challenges/serializers.py
@@ -103,6 +103,7 @@ class Meta:
"allowed_submission_file_types",
"default_submission_meta_attributes",
"allowed_email_ids",
+ "is_submission_public",
)
diff --git a/apps/jobs/views.py b/apps/jobs/views.py
index 11eb837268..29b4850da0 100644
--- a/apps/jobs/views.py
+++ b/apps/jobs/views.py
@@ -486,18 +486,6 @@ def change_submission_data_and_visibility(
if serializer.is_valid():
serializer.save()
response_data = serializer.data
- if (
- request.FILES.get("submission_input_file")
- and challenge.is_static_dataset_code_upload
- ):
- message = {
- "challenge_pk": challenge_pk,
- "phase_pk": challenge_phase_pk,
- "submission_pk": submission_pk,
- "is_static_dataset_code_upload_submission": False,
- }
- # publish message in the queue
- publish_submission_message(message)
return Response(response_data, status=status.HTTP_200_OK)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@@ -1260,9 +1248,38 @@ def update_submission(request, challenge_pk):
if request.method == "PATCH":
submission_pk = request.data.get("submission")
+ submission = get_submission_model(submission_pk)
+ # Update submission_input_file for is_static_dataset_code_upload submission evaluation
+ if (
+ request.FILES.get("submission_input_file")
+ and submission.challenge_phase.challenge.is_static_dataset_code_upload
+ ):
+ serializer = SubmissionSerializer(
+ submission,
+ data=request.data,
+ context={
+ "request": request,
+ },
+ partial=True,
+ )
+ if serializer.is_valid():
+ serializer.save()
+ message = {
+ "challenge_pk": challenge_pk,
+ "phase_pk": submission.challenge_phase.pk,
+ "submission_pk": submission_pk,
+ "is_static_dataset_code_upload_submission": False,
+ }
+ # publish message in the queue
+ publish_submission_message(message)
+ response_data = serializer.data
+ return Response(response_data, status=status.HTTP_200_OK)
+ else:
+ return Response(
+ serializer.errors, status=status.HTTP_400_BAD_REQUEST
+ )
submission_status = request.data.get("submission_status", "").lower()
job_name = request.data.get("job_name", "").lower()
- submission = get_submission_model(submission_pk)
jobs = submission.job_name
if job_name:
jobs.append(job_name)
diff --git a/docker-compose-staging.yml b/docker-compose-staging.yml
index 27583d886f..4789017ebd 100644
--- a/docker-compose-staging.yml
+++ b/docker-compose-staging.yml
@@ -49,7 +49,6 @@ services:
NODE_ENV: staging
ports:
- '80:80'
- - '443:443'
volumes:
- /code/node_modules
- /code/bower_components
@@ -69,6 +68,7 @@ services:
NODE_ENV: staging
ports:
- "9999:80"
+ - "443:443"
volumes:
- /code/node_modules
logging:
@@ -94,3 +94,61 @@ services:
build:
context: ./
dockerfile: docker/prod/code-upload-worker/Dockerfile
+
+ prometheus:
+ hostname: prometheus
+ image: prom/prometheus:latest
+ user: "1000"
+ volumes:
+ - ./monitoring/prometheus/prometheus_staging.yml:/etc/prometheus/prometheus.yml
+ - ./monitoring/prometheus/prometheus_db:/var/lib/prometheus
+ - ./monitoring/prometheus/prometheus_db:/prometheus
+ - ./monitoring/prometheus/prometheus_db:/etc/prometheus
+ command:
+ - '--config.file=/etc/prometheus/prometheus.yml'
+ - '--web.external-url=http://localhost:9090/prometheus'
+ ports:
+ - '9090:9090'
+
+ grafana:
+ hostname: grafana
+ image: grafana/grafana:latest
+ user: "1000"
+ env_file:
+ - docker/prod/docker_staging.env
+ volumes:
+ - ./monitoring/grafana/grafana_db:/var/lib/grafana
+ depends_on:
+ - prometheus
+ ports:
+ - '3000:3000'
+
+ statsd-exporter:
+ hostname: statsd
+ image: prom/statsd-exporter:latest
+ command:
+ - '--log.level=info'
+ - '--web.telemetry-path=/statsd/metrics'
+ ports:
+ - '9125:9125'
+ - '9102:9102'
+
+ node_exporter:
+ hostname: node_exporter
+ image: prom/node-exporter
+ ports:
+ - '9100:9100'
+
+ nginx-ingress:
+ image: ${AWS_ACCOUNT_ID}.dkr.ecr.us-east-1.amazonaws.com/evalai-staging-nginx-ingress:${COMMIT_ID}
+ build:
+ context: ./
+ dockerfile: docker/prod/nginx-ingress/Dockerfile
+ args:
+ MONITORING_ENV: staging
+ depends_on:
+ - prometheus
+ - grafana
+ ports:
+ - '80:80'
+ - '443:443'
diff --git a/docker-compose.yml b/docker-compose.yml
index df65f130f1..b3d7cab852 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -23,6 +23,7 @@ services:
depends_on:
- db
- sqs
+ - statsd-exporter
volumes:
- .:/code
@@ -75,7 +76,6 @@ services:
- ./monitoring/prometheus/prometheus_db:/etc/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- restart: unless-stopped
ports:
- '9090:9090'
@@ -90,3 +90,19 @@ services:
- prometheus
ports:
- '3000:3000'
+
+ statsd-exporter:
+ hostname: statsd
+ image: prom/statsd-exporter:latest
+ command:
+ - '--log.level=info'
+ - '--web.telemetry-path=/statsd/metrics'
+ ports:
+ - '9125:9125'
+ - '9102:9102'
+
+ node_exporter:
+ hostname: node_exporter
+ image: prom/node-exporter
+ ports:
+ - '9100:9100'
diff --git a/docker/dev/django/uwsgi.ini b/docker/dev/django/uwsgi.ini
index 6b38f6805c..3e79d7accc 100644
--- a/docker/dev/django/uwsgi.ini
+++ b/docker/dev/django/uwsgi.ini
@@ -8,4 +8,3 @@ vaccum = true
python-autoreload = 1
buffer-size=32768
chmod-socket = 777
-lazy-apps = true
diff --git a/docker/dev/docker.env b/docker/dev/docker.env
index 51b5a31a3d..9352952bcf 100644
--- a/docker/dev/docker.env
+++ b/docker/dev/docker.env
@@ -36,4 +36,5 @@ SERVICE_DNS=localhost
GF_SECURITY_ADMIN_USER=admin
GF_SECURITY_ADMIN_PASSWORD=password
-prometheus_multiproc_dir=/code/monitoring/prometheus/django
+STATSD_ENDPOINT=statsd
+STATSD_PORT=9125
diff --git a/docker/prod/docker_staging.env b/docker/prod/docker_staging.env
index 1a5273bbff..e561b8a2be 100644
--- a/docker/prod/docker_staging.env
+++ b/docker/prod/docker_staging.env
@@ -55,3 +55,11 @@ EKS_NODEGROUP_ROLE_ARN=x
SLACK_WEB_HOOK_URL=x
ENVIRONMENT=staging
SERVICE_DNS=x
+
+GF_SECURITY_ADMIN_USER=x
+GF_SECURITY_ADMIN_PASSWORD=x
+GF_SERVER_ROOT_URL=http://localhost:3000/grafana
+GF_SERVER_SERVE_FROM_SUB_PATH=true
+
+STATSD_ENDPOINT=statsd
+STATSD_PORT=9125
diff --git a/docker/prod/nginx-ingress/Dockerfile b/docker/prod/nginx-ingress/Dockerfile
new file mode 100644
index 0000000000..0137e342f1
--- /dev/null
+++ b/docker/prod/nginx-ingress/Dockerfile
@@ -0,0 +1,4 @@
+FROM nginx:1.13-alpine
+ARG MONITORING_ENV
+COPY docker/prod/nginx-ingress/nginx_${MONITORING_ENV}.conf /etc/nginx/conf.d/default.conf
+COPY /ssl /etc/ssl
diff --git a/docker/prod/nginx-ingress/nginx_staging.conf b/docker/prod/nginx-ingress/nginx_staging.conf
new file mode 100644
index 0000000000..b8e31a57ec
--- /dev/null
+++ b/docker/prod/nginx-ingress/nginx_staging.conf
@@ -0,0 +1,47 @@
+upstream prometheus {
+ server prometheus:9090 fail_timeout=0;
+}
+
+upstream grafana {
+ server grafana:3000 fail_timeout=0;
+}
+
+server {
+ server_name monitoring-staging.eval.ai;
+ listen 80;
+ return 301 https://monitoring-staging.eval.ai$request_uri;
+}
+
+server {
+ server_name monitoring-staging.eval.ai;
+ listen 443 ssl;
+ location / {
+ root /usr/share/nginx/html;
+ index index.html index.htm;
+ }
+
+ ssl on;
+ ssl_certificate /etc/ssl/eval_ai.crt;
+ ssl_certificate_key /etc/ssl/eval_ai.key;
+ ssl_prefer_server_ciphers on;
+ # enables all versions of TLS, but not SSLv2 or 3 which are weak and now deprecated.
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+
+ access_log /var/log/nginx/access.log;
+ error_log /var/log/nginx/error.log;
+
+ location /prometheus {
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header Host $host;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_pass https://prometheus;
+ }
+
+ location /grafana {
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header Host $host;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_pass https://grafana;
+ }
+
+}
diff --git a/docker/prod/nodejs/nginx_staging.conf b/docker/prod/nodejs/nginx_staging.conf
index b9af1864d4..8e7cdd02ce 100644
--- a/docker/prod/nodejs/nginx_staging.conf
+++ b/docker/prod/nodejs/nginx_staging.conf
@@ -2,6 +2,14 @@ upstream django_app {
server django:8000 fail_timeout=0;
}
+upstream statsd_exporter {
+ server statsd:9102 fail_timeout=0;
+}
+
+upstream node_exporter {
+ server node_exporter:9100 fail_timeout=0;
+}
+
server {
server_name staging-evalai.cloudcv.org evalai-staging.cloudcv.org;
listen 80;
@@ -53,6 +61,20 @@ server {
proxy_pass http://django_app;
}
+ location /statsd {
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header Host $host;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_pass http://statsd_exporter;
+ }
+
+ location /node_exporter {
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header Host $host;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_pass http://node_exporter/metrics;
+ }
+
ssl on;
ssl_certificate /etc/ssl/eval_ai.crt;
ssl_certificate_key /etc/ssl/eval_ai.key;
diff --git a/docker/prod/nodejs_v2/nginx_staging.conf b/docker/prod/nodejs_v2/nginx_staging.conf
index 633655c2dc..74214c17a1 100644
--- a/docker/prod/nodejs_v2/nginx_staging.conf
+++ b/docker/prod/nodejs_v2/nginx_staging.conf
@@ -2,14 +2,22 @@ upstream django_app {
server django:8000 fail_timeout=0;
}
+upstream statsd_exporter {
+ server statsd:9102 fail_timeout=0;
+}
+
+upstream node_exporter {
+ server node_exporter:9100 fail_timeout=0;
+}
+
server {
- server_name beta-staging.eval.ai;
+ server_name staging.eval.ai;
listen 80;
- return 301 https://beta-staging.eval.ai$request_uri;
+ return 301 https://staging.eval.ai$request_uri;
}
server {
- server_name beta-staging.eval.ai;
+ server_name staging.eval.ai;
listen 443 ssl;
location / {
root /usr/share/nginx/html;
@@ -17,11 +25,21 @@ server {
try_files $uri $uri/ /index.html =404;
}
+ client_max_body_size 200M;
+ gzip on;
+ gzip_http_version 1.1;
+ gzip_disable "MSIE [1-6]\.";
+ gzip_min_length 256;
+ gzip_vary on;
+ gzip_proxied expired no-cache no-store private auth;
+ gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
+ gzip_comp_level 9;
+
ssl on;
ssl_certificate /etc/ssl/eval_ai.crt;
ssl_certificate_key /etc/ssl/eval_ai.key;
ssl_prefer_server_ciphers on;
- #enables all versions of TLS, but not SSLv2 or 3 which are weak and now deprecated.
+ # enables all versions of TLS, but not SSLv2 or 3 which are weak and now deprecated.
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
access_log /var/log/nginx/access.log;
@@ -33,4 +51,18 @@ server {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://django_app;
}
+
+ location /statsd {
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header Host $host;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_pass http://statsd_exporter;
+ }
+
+ location /node_exporter {
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header Host $host;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_pass http://node_exporter/metrics;
+ }
}
diff --git a/docs/source/faq(developers).md b/docs/source/faq(developers).md
index e3d006a4ce..b3c597d205 100644
--- a/docs/source/faq(developers).md
+++ b/docs/source/faq(developers).md
@@ -258,3 +258,12 @@ rm -rf bower_components
npm install
bower install
```
+
+#### Q. While trying to build EvalAI from the master branch and run the command docker-compose up:
+
+```
+ERROR: Service 'celery' failed to build: pull access denied for evalai_django, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
+```
+
+Please make sure to clone EvalAI in its default directory with name evalai. This happens because the parent directory changes the name of docker images.
+For instance, the image evalai_django gets renamed to evalai_dev_django if your directory is renamed to EvalAI_dev.
diff --git a/evalai/urls.py b/evalai/urls.py
index 8f94b949a2..9e09a5811d 100644
--- a/evalai/urls.py
+++ b/evalai/urls.py
@@ -92,7 +92,6 @@
schema_view.with_ui("redoc", cache_timeout=0),
name="schema-redoc",
),
- url(r"^api/prometheus/", include("django_prometheus.urls")),
]
# DJANGO-SPAGHETTI-AND-MEATBALLS URLs available during development only.
diff --git a/frontend_v2/src/app/app.component.html b/frontend_v2/src/app/app.component.html
index 6be740b4ca..dd80668e1f 100644
--- a/frontend_v2/src/app/app.component.html
+++ b/frontend_v2/src/app/app.component.html
@@ -1,11 +1,11 @@
+ (currentRoutePath == '/' || currentRoutePath == '/auth/login' || currentRoutePath == '/auth/signup')
+ ? '' : (currentRoutePath == '/about' || currentRoutePath == '/contact' || currentRoutePath == '/our-team' ||
+ currentRoutePath == '/get-involved' || currentRoutePath == '/privacy-policy')
+ ? 'page-wrap' : 'page-wrap-challenge'
+ " >
diff --git a/frontend_v2/src/app/components/challenge/challengeleaderboard/challengeleaderboard.component.ts b/frontend_v2/src/app/components/challenge/challengeleaderboard/challengeleaderboard.component.ts
index 7bc11aea02..8b8d1edbc2 100644
--- a/frontend_v2/src/app/components/challenge/challengeleaderboard/challengeleaderboard.component.ts
+++ b/frontend_v2/src/app/components/challenge/challengeleaderboard/challengeleaderboard.component.ts
@@ -343,6 +343,19 @@ export class ChallengeleaderboardComponent implements OnInit, AfterViewInit, OnD
phaseSplitSelected(phaseSplit) {
const SELF = this;
SELF.selectedPhaseSplit = phaseSplit;
+
+ const API_PATH = SELF.endpointsService.particularChallengePhaseSplitUrl(this.selectedPhaseSplit['id']);
+ SELF.apiService.getUrl(API_PATH).subscribe(
+ (data) => {
+ SELF.leaderboardPrecisionValue = data.leaderboard_decimal_precision;
+ SELF.setLeaderboardPrecisionValue = `1.${ SELF.leaderboardPrecisionValue }-${ SELF.leaderboardPrecisionValue }`;
+ },
+ (err) => {
+ SELF.globalService.handleApiError(err);
+ },
+ () => {}
+ );
+
if (SELF.selectedPhaseSplit && SELF.router.url.endsWith('leaderboard/' + phaseSplit['id'])) {
SELF.fetchLeaderboard(SELF.selectedPhaseSplit['id']);
SELF.showLeaderboardByLatest = SELF.selectedPhaseSplit.show_leaderboard_by_latest_submission;
@@ -620,7 +633,7 @@ export class ChallengeleaderboardComponent implements OnInit, AfterViewInit, OnD
SELF.apiService.patchUrl(API_PATH, BODY).subscribe(
(data) => {
this.minusDisabled = SELF.leaderboardPrecisionValue === 0 ? true : false;
- this.plusDisabled = SELF.leaderboardPrecisionValue === 5 ? true : false;
+ this.plusDisabled = SELF.leaderboardPrecisionValue === 20 ? true : false;
},
(err) => {
SELF.globalService.handleApiError(err, true);
diff --git a/frontend_v2/src/app/components/challenge/challengephases/editphasemodal/editphasemodal.component.html b/frontend_v2/src/app/components/challenge/challengephases/editphasemodal/editphasemodal.component.html
index 6af6dac21a..924da573c7 100644
--- a/frontend_v2/src/app/components/challenge/challengephases/editphasemodal/editphasemodal.component.html
+++ b/frontend_v2/src/app/components/challenge/challengephases/editphasemodal/editphasemodal.component.html
@@ -76,6 +76,7 @@
+
Submissions/day
@@ -134,6 +135,43 @@
>
+
+
+
diff --git a/frontend_v2/src/app/components/challenge/challengephases/editphasemodal/editphasemodal.component.ts b/frontend_v2/src/app/components/challenge/challengephases/editphasemodal/editphasemodal.component.ts
index 043db1c87c..b74a9fab77 100644
--- a/frontend_v2/src/app/components/challenge/challengephases/editphasemodal/editphasemodal.component.ts
+++ b/frontend_v2/src/app/components/challenge/challengephases/editphasemodal/editphasemodal.component.ts
@@ -27,6 +27,11 @@ export class EditphasemodalComponent implements OnInit {
* Challenge phase name
*/
name = '';
+
+ /**
+ * Challenge phase allowed submission file types
+ */
+ allowedSubmissionFileTypes = '';
/**
* Challenge phase description
@@ -58,6 +63,11 @@ export class EditphasemodalComponent implements OnInit {
*/
maxSubmissions: number;
+ /**
+ * Challenge phase max concurrent submissions allowed
+ */
+ maxConcurrentSubmissionsAllowed: number;
+
/**
* If editor error message
*/
@@ -141,7 +151,9 @@ export class EditphasemodalComponent implements OnInit {
* Constructor.
* @param globalService GlobalService Injection.
*/
- constructor(private globalService: GlobalService) {}
+ constructor(
+ private globalService: GlobalService,
+ ) {}
ngOnInit() {
if (this.params) {
@@ -172,6 +184,12 @@ export class EditphasemodalComponent implements OnInit {
if (this.params['maxSubmissions']) {
this.maxSubmissions = this.params['maxSubmissions'];
}
+ if (this.params['maxConcurrentSubmissionsAllowed']) {
+ this.maxConcurrentSubmissionsAllowed = this.params['maxConcurrentSubmissionsAllowed'];
+ }
+ if (this.params['allowedSubmissionFileTypes']) {
+ this.allowedSubmissionFileTypes = this.params['allowedSubmissionFileTypes'];
+ }
if (this.params['confirm']) {
this.confirm = this.params['confirm'];
}
diff --git a/frontend_v2/src/app/components/challenge/challengesettings/challengesettings.component.html b/frontend_v2/src/app/components/challenge/challengesettings/challengesettings.component.html
index d69aa6a310..796a9092f8 100644
--- a/frontend_v2/src/app/components/challenge/challengesettings/challengesettings.component.html
+++ b/frontend_v2/src/app/components/challenge/challengesettings/challengesettings.component.html
@@ -106,16 +106,41 @@
Challenge Settings
+
+
+
+
+
+
+
+ Is Public
+
+
+
+
+
+ Submission Visibility
+
+
+
+
+
+
+
diff --git a/frontend_v2/src/app/components/challenge/challengesettings/challengesettings.component.scss b/frontend_v2/src/app/components/challenge/challengesettings/challengesettings.component.scss
index 0de5a6dbb1..543e84f175 100644
--- a/frontend_v2/src/app/components/challenge/challengesettings/challengesettings.component.scss
+++ b/frontend_v2/src/app/components/challenge/challengesettings/challengesettings.component.scss
@@ -13,6 +13,14 @@
}
}
+.phase-card {
+ width:50vw;
+}
+
+.phase-button {
+ margin-left: 25px;
+}
+
@include screen-medium {
.settings-section {
padding: 10px 20px !important;
diff --git a/frontend_v2/src/app/components/challenge/challengesettings/challengesettings.component.ts b/frontend_v2/src/app/components/challenge/challengesettings/challengesettings.component.ts
index 924a462226..96265fcc37 100644
--- a/frontend_v2/src/app/components/challenge/challengesettings/challengesettings.component.ts
+++ b/frontend_v2/src/app/components/challenge/challengesettings/challengesettings.component.ts
@@ -89,13 +89,44 @@ export class ChallengesettingsComponent implements OnInit, OnDestroy {
* Email error message
*/
message: string;
+
+ /**
+ * If the submission is public
+ */
+ isSubmissionPublic : boolean = false;
+
+ /**
+ * If the phase is public
+ */
+ isPhasePublic : boolean = false;
+
+ /**
+ * If leaderboard is public
+ */
+ isLeaderboardPublic : boolean = false;
+
+ /**
+ * phase visibility state and it's icon
+ */
+ phaseVisibility = {
+ state: 'Private',
+ icon: 'fa fa-toggle-off',
+ };
+
+ /**
+ * submission visibility state and it's icon
+ */
+ submissionVisibility = {
+ state: 'Private',
+ icon: 'fa fa-toggle-off',
+ };
/**
* publish challenge state and it's icon
*/
publishChallenge = {
state: 'Not Published',
- icon: 'fa fa-eye-slash red-text',
+ icon: 'fa fa-toggle-off',
};
/**
@@ -188,49 +219,180 @@ export class ChallengesettingsComponent implements OnInit, OnDestroy {
const SELF = this;
return (phase) => {
SELF.selectedPhase = phase;
+ SELF.isPhasePublic = SELF.selectedPhase['is_public'];
+ SELF.isSubmissionPublic = SELF.selectedPhase['is_submission_public'];
+ SELF.isLeaderboardPublic = SELF.selectedPhase['leaderboard_public'];
+ if (SELF.isPhasePublic) {
+ SELF.phaseVisibility.state = 'Public';
+ SELF.phaseVisibility.icon = 'fa fa-toggle-on green-text';
+ }
+ else {
+ SELF.phaseVisibility.state = 'Private';
+ SELF.phaseVisibility.icon = 'fa fa-toggle-off grey-text text-darken-1';
+ }
+ if (SELF.isSubmissionPublic) {
+ SELF.submissionVisibility.state = 'Public';
+ SELF.submissionVisibility.icon = 'fa fa-toggle-on green-text';
+ }
+ else {
+ SELF.submissionVisibility.state = 'Private';
+ SELF.submissionVisibility.icon = 'fa fa-toggle-off grey-text text-darken-1';
+ }
+ };
+ }
- SELF.apiCall = (params) => {
- const FORM_DATA: FormData = new FormData();
- for (const key in params) {
- if (params[key]) {
- FORM_DATA.append(key, params[key]);
- }
+ editPhaseDetails() {
+ const SELF = this;
+ SELF.apiCall = (params) => {
+ const FORM_DATA: FormData = new FormData();
+ for (const key in params) {
+ if (params[key]) {
+ FORM_DATA.append(key, params[key]);
}
+ }
+ SELF.apiService
+ .patchFileUrl(
+ SELF.endpointsService.updateChallengePhaseDetailsURL(SELF.challenge.id, SELF.selectedPhase['id']),
+ FORM_DATA
+ )
+ .subscribe(
+ (data) => {
+ SELF.selectedPhase = data;
+ SELF.challengeService.fetchPhases(SELF.challenge['id']);
+ SELF.challengeService.changePhaseSelected(true);
+ SELF.selectedPhase = false;
+ SELF.globalService.showToast('success', 'The challenge phase details are successfully updated!');
+ },
+ (err) => {
+ SELF.globalService.showToast('error', err);
+ },
+ () => {this.logger.info('PHASE-UPDATE-FINISHED')}
+ );
+ };
+
+ const PARAMS = {
+ title: 'Edit Challenge Phase Details',
+ name: SELF.selectedPhase['name'],
+ label: 'description',
+ description: SELF.selectedPhase['description'],
+ startDate: SELF.selectedPhase['start_date'],
+ endDate: SELF.selectedPhase['end_date'],
+ maxSubmissionsPerDay: SELF.selectedPhase['max_submissions_per_day'],
+ maxSubmissionsPerMonth: SELF.selectedPhase['max_submissions_per_month'],
+ maxSubmissions: SELF.selectedPhase['max_submissions'],
+ maxConcurrentSubmissionsAllowed: SELF.selectedPhase['max_concurrent_submissions_allowed'],
+ allowedSubmissionFileTypes: SELF.selectedPhase['allowed_submission_file_types'],
+ confirm: 'Submit',
+ deny: 'Cancel',
+ confirmCallback: SELF.apiCall,
+ };
+ SELF.globalService.showEditPhaseModal(PARAMS);
+}
+
+ /**
+ * Phase Visibility toggle function
+ */
+ togglePhaseVisibility() {
+ const SELF = this;
+ let togglePhaseVisibilityState, isPublic;
+ if (SELF.phaseVisibility.state === 'Public') {
+ togglePhaseVisibilityState = 'private';
+ isPublic = false;
+ SELF.phaseVisibility.state = 'Private';
+ SELF.phaseVisibility.icon = 'fa fa-toggle-off';
+ } else {
+ togglePhaseVisibilityState = 'public';
+ isPublic = true;
+ SELF.phaseVisibility.state = 'Public';
+ SELF.phaseVisibility.icon = 'fa fa-toggle-on green-text';
+ }
+ const BODY: FormData = new FormData();
+ BODY.append("is_public", isPublic);
+ SELF.apiService
+ .patchFileUrl(
+ SELF.endpointsService.updateChallengePhaseDetailsURL(SELF.selectedPhase['challenge'], SELF.selectedPhase['id']),
+ BODY
+ )
+ .subscribe(
+ (data) => {
+ SELF.challengeService.fetchPhases(SELF.selectedPhase['challenge']);
+ SELF.challengeService.changePhaseSelected(true);
+ SELF.selectedPhase = false;
+ SELF.globalService.showToast(
+ 'success',
+ 'The phase was successfully made ' + togglePhaseVisibilityState,
+ 5
+ );
+ },
+ (err) => {
+ SELF.globalService.handleApiError(err, true);
+ SELF.globalService.showToast('error', err);
+ if (isPublic) {
+ SELF.phaseVisibility.state = 'Private';
+ SELF.phaseVisibility.icon = 'fa fa-toggle-off';
+ } else {
+ SELF.phaseVisibility.state = 'Public';
+ SELF.phaseVisibility.icon = 'fa fa-toggle-on green-text';
+ }
+ },
+ () => this.logger.info('PHASE-VISIBILITY-UPDATE-FINISHED')
+ );
+ }
+
+ /**
+ * Submission Visibility toggle function
+ */
+ toggleSubmissionVisibility() {
+ const SELF = this;
+ if(SELF.isLeaderboardPublic == true) {
+ let toggleSubmissionVisibilityState, isSubmissionPublic;
+ if (SELF.submissionVisibility.state === 'Public') {
+ toggleSubmissionVisibilityState = 'private';
+ isSubmissionPublic = false;
+ SELF.submissionVisibility.state = 'Private';
+ SELF.submissionVisibility.icon = 'fa fa-toggle-off';
+ } else {
+ toggleSubmissionVisibilityState = 'public';
+ isSubmissionPublic = true;
+ SELF.submissionVisibility.state = 'Public';
+ SELF.submissionVisibility.icon = 'fa fa-toggle-on green-text';
+ }
+ const BODY: FormData = new FormData();
+ BODY.append("is_submission_public", isSubmissionPublic);
SELF.apiService
- .patchFileUrl(
- SELF.endpointsService.updateChallengePhaseDetailsURL(SELF.challenge.id, SELF.selectedPhase['id']),
- FORM_DATA
- )
+ .patchFileUrl(
+ SELF.endpointsService.updateChallengePhaseDetailsURL(SELF.selectedPhase['challenge'], SELF.selectedPhase['id']),
+ BODY
+ )
.subscribe(
(data) => {
- SELF.selectedPhase = data;
- SELF.challengeService.fetchPhases(SELF.challenge['id']);
- SELF.globalService.showToast('success', 'The challenge phase details are successfully updated!');
+ SELF.challengeService.fetchPhases(SELF.selectedPhase['challenge']);
+ SELF.challengeService.changePhaseSelected(true);
+ SELF.selectedPhase = false;
+ SELF.globalService.showToast(
+ 'success',
+ 'The submissions were successfully made ' + toggleSubmissionVisibilityState,
+ 5
+ );
},
(err) => {
+ SELF.globalService.handleApiError(err, true);
SELF.globalService.showToast('error', err);
+ if (isSubmissionPublic) {
+ SELF.submissionVisibility.state = 'Private';
+ SELF.submissionVisibility.icon = 'fa fa-toggle-off';
+ } else {
+ SELF.submissionVisibility.state = 'Public';
+ SELF.submissionVisibility.icon = 'fa fa-toggle-on green-text';
+ }
},
- () => {this.logger.info('PHASE-UPDATE-FINISHED')}
+ () => this.logger.info('SUBMISSION-VISIBILITY-UPDATE-FINISHED')
);
- };
-
- const PARAMS = {
- title: 'Edit Challenge Phase Details',
- name: SELF.selectedPhase['name'],
- label: 'description',
- description: SELF.selectedPhase['description'],
- startDate: SELF.selectedPhase['start_date'],
- endDate: SELF.selectedPhase['end_date'],
- maxSubmissionsPerDay: SELF.selectedPhase['max_submissions_per_day'],
- maxSubmissionsPerMonth: SELF.selectedPhase['max_submissions_per_month'],
- maxSubmissions: SELF.selectedPhase['max_submissions'],
- confirm: 'Submit',
- deny: 'Cancel',
- confirmCallback: SELF.apiCall,
- };
- SELF.globalService.showEditPhaseModal(PARAMS);
- };
- }
+ }
+ else {
+ SELF.globalService.showToast('error', "Leaderboard is private, please make the leaderbaord public");
+ }
+ }
/**
* Remove banned email chip
diff --git a/frontend_v2/src/app/components/challenge/challengesubmissions/challengesubmissions.component.html b/frontend_v2/src/app/components/challenge/challengesubmissions/challengesubmissions.component.html
index 5b61795a72..e633b57a7b 100644
--- a/frontend_v2/src/app/components/challenge/challengesubmissions/challengesubmissions.component.html
+++ b/frontend_v2/src/app/components/challenge/challengesubmissions/challengesubmissions.component.html
@@ -139,7 +139,7 @@
My Submissions
Show on leaderboard
diff --git a/frontend_v2/src/app/components/challenge/challengesubmit/challengesubmit.component.html b/frontend_v2/src/app/components/challenge/challengesubmit/challengesubmit.component.html
index 458ae03599..5d3e6b3e0b 100644
--- a/frontend_v2/src/app/components/challenge/challengesubmit/challengesubmit.component.html
+++ b/frontend_v2/src/app/components/challenge/challengesubmit/challengesubmit.component.html
@@ -83,6 +83,7 @@ Submission Guidelines
+
Submission limits
@@ -154,13 +155,14 @@ Submission Guidelines
-
+
+
-
+
@@ -210,265 +212,10 @@ Make Submission
-
-
Submission instructions
-
- - Install evalai-cli
- $ pip install evalai{{ cliVersion }}
-
-
- - Add your EvalAI account token to evalai-cli
- $ evalai set_token {{authToken}}
-
-
- - Make Submission
- $ evalai challenge {{challengeId}} phase {{phaseId}} submit --file <submission_file_path> --large
-
-
- -
-
Use --private
or --public
flag in the submission
- command to make the submission private or public respectively.
-
-
- - For more commands, please refer to evalai-cli documentation.
-
-
-
-
-
-
-
-
-
- {{ selectedPhaseSubmissions.maxExceededMessage }}
-
-
-
-
-
@@ -501,6 +248,268 @@
Make Submission
+
+
+
+
Submission instructions
+
+ - Install evalai-cli
+ $ pip install evalai{{ cliVersion }}
+
+
+ - Add your EvalAI account token to evalai-cli
+ $ evalai set_token {{authToken}}
+
+
+ - Make Submission
+ $ evalai challenge {{challengeId}} phase {{phaseId}} submit --file <submission_file_path> --large
+
+
+ -
+
Use --private
or --public
flag in the submission
+ command to make the submission private or public respectively.
+
+
+ - For more commands, please refer to evalai-cli documentation.
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ selectedPhaseSubmissions.maxExceededMessage }}
+
+
+
+
+
diff --git a/frontend_v2/src/app/components/challenge/challengesubmit/challengesubmit.component.scss b/frontend_v2/src/app/components/challenge/challengesubmit/challengesubmit.component.scss
index 57e9e0d982..25f420ea7d 100644
--- a/frontend_v2/src/app/components/challenge/challengesubmit/challengesubmit.component.scss
+++ b/frontend_v2/src/app/components/challenge/challengesubmit/challengesubmit.component.scss
@@ -5,6 +5,12 @@
padding: 10px 30px;
}
+.ev-challenge-view {
+ margin-top: 0px;
+ padding-top: 30px;
+ margin-bottom: 20px;
+}
+
.row .row-lr-margin {
margin-bottom: 20px;
}
@@ -56,7 +62,7 @@ th {
padding-right: 36px;
}
ul {
- padding-left: 70px;
+ padding-left: 60px;
}
}
@@ -134,3 +140,8 @@ th {
flex-direction: row;
align-items: center;
}
+
+.cli-card-container {
+ margin: 14.5px 0px;
+ padding: 0px 0px 0px 70px;
+}
diff --git a/frontend_v2/src/app/components/challenge/challengesubmit/challengesubmit.component.ts b/frontend_v2/src/app/components/challenge/challengesubmit/challengesubmit.component.ts
index 6a5746b031..4acf2e5af9 100644
--- a/frontend_v2/src/app/components/challenge/challengesubmit/challengesubmit.component.ts
+++ b/frontend_v2/src/app/components/challenge/challengesubmit/challengesubmit.component.ts
@@ -44,15 +44,20 @@ export class ChallengesubmitComponent implements OnInit {
isLoggedIn = false;
/**
- * Is submittion submitted
+ * Is submission submitted
*/
isSubmitted = false;
/**
- * Is submittion submitted
+ * Is submission submitted
*/
isPublicSubmission:boolean = true;
+ /**
+ * Is submission allowed by host
+ */
+ isLeaderboardPublic:boolean = false;
+
/**
* Challenge object
*/
@@ -467,6 +472,7 @@ export class ChallengesubmitComponent implements OnInit {
const SELF = this;
return (phase) => {
SELF.selectedPhase = phase;
+ SELF.isLeaderboardPublic = phase['leaderboard_public'];
if (SELF.challenge['id'] && phase['id']) {
SELF.getMetaDataDetails(SELF.challenge['id'], phase['id']);
SELF.fetchRemainingSubmissions(SELF.challenge['id'], phase['id']);
diff --git a/frontend_v2/src/app/components/nav/header-static/header-static.component.html b/frontend_v2/src/app/components/nav/header-static/header-static.component.html
index c48a1dc74f..8c619e3ce2 100644
--- a/frontend_v2/src/app/components/nav/header-static/header-static.component.html
+++ b/frontend_v2/src/app/components/nav/header-static/header-static.component.html
@@ -9,7 +9,8 @@
/>
- All Challenges
+ All Challenges
diff --git a/frontend_v2/src/app/components/nav/header-static/header-static.component.ts b/frontend_v2/src/app/components/nav/header-static/header-static.component.ts
index e3f45c0dfd..5d53f335b0 100644
--- a/frontend_v2/src/app/components/nav/header-static/header-static.component.ts
+++ b/frontend_v2/src/app/components/nav/header-static/header-static.component.ts
@@ -11,6 +11,7 @@ import {
} from '@angular/core';
import { GlobalService } from '../../../services/global.service';
import { AuthService } from '../../../services/auth.service';
+import { filter } from "rxjs/internal/operators";
import { RouterModule, Router, ActivatedRoute, NavigationEnd } from '@angular/router';
import { DOCUMENT } from '@angular/common';
import { ApiService } from '../../../services/api.service';
@@ -62,6 +63,16 @@ export class HeaderStaticComponent implements OnInit, OnDestroy {
*/
isLoggedIn: any = false;
+ /**
+ * Current name of tab which needs to be active
+ */
+ tabHighlight: string = "allChallenges";
+
+ /**
+ * Returns true if the string is not a number
+ */
+ isChallengeComponent : boolean = false;
+
/**
* Inner width
*/
@@ -88,7 +99,7 @@ export class HeaderStaticComponent implements OnInit, OnDestroy {
private apiService: ApiService,
@Inject(DOCUMENT) private document: Document
) {
- this.authState = authService.authState;
+ this.authState = authService.authState;
}
/**
@@ -107,6 +118,27 @@ export class HeaderStaticComponent implements OnInit, OnDestroy {
ngOnInit() {
this.updateElements();
this.checkInnerWidth();
+
+ this.router.events
+ .pipe(filter(event => event instanceof NavigationEnd))
+ .subscribe((event) => {
+ if(event) {
+ if(this.router.url.split('/')[length] == "all") {
+ this.tabHighlight = "allChallenges";
+ this.globalService.changeTabActiveStatus("allChallenges");
+ }
+ else if(this.router.url.split('/')[1] == "profile") {
+ this.tabHighlight = "profile";
+ this.globalService.changeTabActiveStatus("profile");
+ }
+ }
+ });
+ this.isChallengeComponent = isNaN(parseInt(this.router.url.split('/')[length]));
+
+ this.globalService.nameTabHighlight.subscribe((tabHighlight) => {
+ this.tabHighlight = tabHighlight;
+ });
+
this.authServiceSubscription = this.authService.change.subscribe((authState) => {
this.authState = authState;
if (this.authService.isLoggedIn()) {
diff --git a/frontend_v2/src/app/components/publiclists/challengelist/challengecard/challengecard.component.scss b/frontend_v2/src/app/components/publiclists/challengelist/challengecard/challengecard.component.scss
index a427c2f91c..dee9eec866 100644
--- a/frontend_v2/src/app/components/publiclists/challengelist/challengecard/challengecard.component.scss
+++ b/frontend_v2/src/app/components/publiclists/challengelist/challengecard/challengecard.component.scss
@@ -5,7 +5,7 @@
}
.bg-img {
- width: 100%;
+ object-fit: cover;
height: 100%;
margin: auto;
}
diff --git a/frontend_v2/src/app/components/publiclists/challengelist/challengelist.component.ts b/frontend_v2/src/app/components/publiclists/challengelist/challengelist.component.ts
index 4584fc91d2..329c033ae8 100644
--- a/frontend_v2/src/app/components/publiclists/challengelist/challengelist.component.ts
+++ b/frontend_v2/src/app/components/publiclists/challengelist/challengelist.component.ts
@@ -231,8 +231,10 @@ export class ChallengelistComponent implements OnInit {
*/
@HostListener('window:scroll', [])
onWindowScroll(): void {
- const RECT = this.document.getElementById('ongoing-challenges').getBoundingClientRect();
- this.isScrollbtnVisible = RECT.top < 0;
+ if(this.document.getElementById('ongoing-challenges')) {
+ const RECT = this.document.getElementById('ongoing-challenges').getBoundingClientRect();
+ this.isScrollbtnVisible = RECT.top < 0;
+ }
}
/**
diff --git a/frontend_v2/src/app/components/template-challenge-create/template-challenge-create.component.html b/frontend_v2/src/app/components/template-challenge-create/template-challenge-create.component.html
index 0e7bb212cf..860294ec62 100644
--- a/frontend_v2/src/app/components/template-challenge-create/template-challenge-create.component.html
+++ b/frontend_v2/src/app/components/template-challenge-create/template-challenge-create.component.html
@@ -5,9 +5,7 @@
-
- Create Challenge
-
+ Create Challenge
-
Challenge Phases
+
Challenge Phases
-
+
Name for Phase {{phase['id']}}
+
diff --git a/frontend_v2/src/app/components/template-challenge-create/template-challenge-create.component.scss b/frontend_v2/src/app/components/template-challenge-create/template-challenge-create.component.scss
index 8c41306b58..5bc6db6909 100644
--- a/frontend_v2/src/app/components/template-challenge-create/template-challenge-create.component.scss
+++ b/frontend_v2/src/app/components/template-challenge-create/template-challenge-create.component.scss
@@ -13,6 +13,14 @@
}
}
+.challenge-phase {
+ margin-top: 2rem;
+}
+
+::-webkit-calendar-picker-indicator:hover{
+ cursor:pointer;
+}
+
@media only screen and (max-width: $med-screen) {
.web-container {
width: 100%;
@@ -43,7 +51,7 @@ p {
}
.web-container {
- width: calc(100vw - 223px);
+ width: calc(100% - 223px);
float: right;
padding-top: 70px;
overflow-x: hidden;
diff --git a/frontend_v2/src/app/components/utility/selectphase/selectphase.component.ts b/frontend_v2/src/app/components/utility/selectphase/selectphase.component.ts
index e24b401af4..6abdfe0c55 100644
--- a/frontend_v2/src/app/components/utility/selectphase/selectphase.component.ts
+++ b/frontend_v2/src/app/components/utility/selectphase/selectphase.component.ts
@@ -46,6 +46,11 @@ export class SelectphaseComponent implements OnInit, OnChanges {
*/
phaseVisibility = false;
+ /**
+ * If phase selected
+ */
+ isPhaseSelected : boolean = false;
+
/**
* Currently selected phase
*/
@@ -86,7 +91,15 @@ export class SelectphaseComponent implements OnInit, OnChanges {
* Component on changes detected in Input.
* @param change changes detected
*/
- ngOnChanges(change) {}
+ ngOnChanges(change) {
+ this.challengeService.isPhaseSelected.subscribe((isPhaseSelected) => {
+ this.isPhaseSelected = isPhaseSelected;
+ });
+ if(this.isPhaseSelected == true) {
+ this.challengeService.changePhaseSelected(false);
+ this.phaseName = '';
+ }
+ }
/**
* Select a particular phase.
diff --git a/frontend_v2/src/app/components/utility/side-bar/side-bar.component.html b/frontend_v2/src/app/components/utility/side-bar/side-bar.component.html
index 577e5af12b..e00acdb49f 100644
--- a/frontend_v2/src/app/components/utility/side-bar/side-bar.component.html
+++ b/frontend_v2/src/app/components/utility/side-bar/side-bar.component.html
@@ -3,25 +3,29 @@
-
-
+
-
-
+
-
-
+
-
-
+
diff --git a/frontend_v2/src/app/components/utility/side-bar/side-bar.component.scss b/frontend_v2/src/app/components/utility/side-bar/side-bar.component.scss
index c5952ab61f..8d6b256471 100644
--- a/frontend_v2/src/app/components/utility/side-bar/side-bar.component.scss
+++ b/frontend_v2/src/app/components/utility/side-bar/side-bar.component.scss
@@ -36,6 +36,7 @@
border-right: 1px solid transparent;
&:hover {
color: $highlight;
+ border-right: 1px solid $highlight;
}
&.side-active-link {
color: $med-black;
diff --git a/frontend_v2/src/app/components/utility/side-bar/side-bar.component.ts b/frontend_v2/src/app/components/utility/side-bar/side-bar.component.ts
index 8c531c3c72..943212da8a 100644
--- a/frontend_v2/src/app/components/utility/side-bar/side-bar.component.ts
+++ b/frontend_v2/src/app/components/utility/side-bar/side-bar.component.ts
@@ -1,4 +1,7 @@
import { Component, OnInit } from '@angular/core';
+import { Router, NavigationEnd } from '@angular/router';
+import { filter } from "rxjs/internal/operators";
+import { GlobalService } from '../../../services/global.service';
@Component({
selector: 'app-side-bar',
@@ -6,7 +9,58 @@ import { Component, OnInit } from '@angular/core';
styleUrls: ['./side-bar.component.scss'],
})
export class SideBarComponent implements OnInit {
- constructor() {}
- ngOnInit() {}
+ /**
+ * Current name of tab which needs to be active
+ */
+ tabHighlight: string = "allChallenges";
+
+ /**
+ * Returns true if the string is not a number
+ */
+ isChallengeComponent : boolean = false;
+
+ /**
+ * Constructor
+ * @param globalService GlobalService Injection.
+ * @param router Router
+ */
+ constructor(
+ private globalService: GlobalService,
+ private router: Router
+ ) { }
+
+ ngOnInit() {
+ this.globalService.nameTabHighlight.subscribe((tabHighlight) => {
+ this.tabHighlight = tabHighlight;
+ });
+
+ this.router.events
+ .pipe(filter(event => event instanceof NavigationEnd))
+ .subscribe((event) => {
+ if(event) {
+ if(this.router.url.split('/')[2] == "me") {
+ this.tabHighlight = "hostedChallenges";
+ this.globalService.changeTabActiveStatus("hostedChallenges");
+ }
+ else if(this.router.url.split('/')[2] == "hosts") {
+ this.tabHighlight = "createChallenge";
+ this.globalService.changeTabActiveStatus("createChallenge");
+ }
+ else if(this.router.url.split('/')[2] == "participants") {
+ this.tabHighlight = "myParticipantTeams";
+ this.globalService.changeTabActiveStatus("myParticipantTeams");
+ }
+ else if(this.router.url.split('/')[2] == "participated") {
+ this.tabHighlight = "participatedChallenges";
+ this.globalService.changeTabActiveStatus("participatedChallenges");
+ }
+ else if(this.router.url.split('/')[2] == "all") {
+ this.tabHighlight = "allChallenges";
+ this.globalService.changeTabActiveStatus("allChallenges");
+ }
+ this.isChallengeComponent = isNaN(parseInt(this.router.url.split('/')[length]));
+ }
+ });
+ }
}
diff --git a/frontend_v2/src/app/components/utility/toast/toast.component.scss b/frontend_v2/src/app/components/utility/toast/toast.component.scss
index c72f49e24d..3daf1c35bd 100644
--- a/frontend_v2/src/app/components/utility/toast/toast.component.scss
+++ b/frontend_v2/src/app/components/utility/toast/toast.component.scss
@@ -4,6 +4,7 @@
.toast-container {
visibility: hidden;
word-wrap: break-word;
+ z-index: 1;
display: inline-block;
color: #fff;
text-align: center;
diff --git a/frontend_v2/src/app/services/challenge.service.ts b/frontend_v2/src/app/services/challenge.service.ts
index 3e78be9cf6..942b3317b8 100644
--- a/frontend_v2/src/app/services/challenge.service.ts
+++ b/frontend_v2/src/app/services/challenge.service.ts
@@ -33,6 +33,8 @@ export class ChallengeService {
currentHostTeam = this.hostTeamSource.asObservable();
private challengeHostSource = new BehaviorSubject(false);
isChallengeHost = this.challengeHostSource.asObservable();
+ private phaseSelected = new BehaviorSubject(false);
+ isPhaseSelected = this.phaseSelected.asObservable();
private challengePublishSource = new BehaviorSubject(this.defaultPublishChallenge);
currentChallengePublishState = this.challengePublishSource.asObservable();
@@ -66,6 +68,14 @@ export class ChallengeService {
this.challengeHostSource.next(isChallengeHost);
}
+ /**
+ * Update the status for selectPhase component after details are updated
+ * @param selectedPhase new updated phase details status
+ */
+ changePhaseSelected(selectedPhase: boolean) {
+ this.phaseSelected.next(selectedPhase);
+ }
+
/**
* Update challenge publish state and icon for current challenge.
* @param publishChallenge new challenge publish status and icon.
diff --git a/frontend_v2/src/app/services/global.service.ts b/frontend_v2/src/app/services/global.service.ts
index 099ba2ca9f..f5c52f768c 100644
--- a/frontend_v2/src/app/services/global.service.ts
+++ b/frontend_v2/src/app/services/global.service.ts
@@ -75,6 +75,8 @@ export class GlobalService {
editPhaseModalParams = this.editPhasemodalSource.asObservable();
private termsAndConditionsSource = new BehaviorSubject(this.termsAndConditionsModalDefault);
termsAndConditionsModalParams = this.termsAndConditionsSource.asObservable();
+ private tabHighlight = new BehaviorSubject(" ");
+ nameTabHighlight = this.tabHighlight.asObservable();
@Output() toast: EventEmitter