Skip to content

Commit 725d725

Browse files
keshxvdayalvschnei
authored andcommitted
Merge pull request #16 from elixir-cloud-aai/keshav-dev
feat(ui): various minor improvements
1 parent 3f957c4 commit 725d725

9 files changed

Lines changed: 442 additions & 407 deletions

File tree

README.md

Lines changed: 223 additions & 326 deletions
Large diffs are not rendered by default.

backend/.tes_instances

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@
33
# Lines starting with # are comments
44

55
# ELIXIR Cloud TES Instances
6-
Funnel/OpenPBS @ ELIXIR-CZ,https://funnel.cloud.e-infra.cz/
7-
Funnel/Slurm @ ELIXIR-FI,https://vm4816.kaj.pouta.csc.fi/
8-
TESK/Kubernetes @ ELIXIR-CZ (Prod),https://tesk-prod.cloud.e-infra.cz/
9-
TESK/Kubernetes @ ELIXIR-CZ (NA),https://tesk-na.cloud.e-infra.cz/
10-
TESK/Kubernetes @ ELIXIR-DE,https://tesk.elixir-cloud.bi.denbi.de/
11-
TESK/Kubernetes @ ELIXIR-GR,https://tesk-eu.hypatia-comp.athenarc.gr/
12-
TESK/OpenShift @ ELIXIR-FI,https://csc-tesk-noauth.rahtiapp.fi/
6+
Funnel/OpenPBS @ ELIXIR-CZ,https://funnel.cloud.e-infra.cz
7+
Poiesis @ ELIXIR-CZ,https://poiesis.dyn.cloud.e-infra.cz/
8+
TESK @ ELIXIR-FI,https://csc-tesk-noauth.rahtiapp.fi
9+
Funnel/Slurm @ ELIXIR-FI,https://fip-86-50-228-254.kaj.poutavm.fi/
10+
Poiesis @ ELIXIR-FI,https://poiesis.rahtiapp.fi/
11+
Test Poiesis @ ELIXIR-FI,https://test-poiesis.rahtiapp.fi/
12+
Funnel/Slurm @ BIH,https://spe4hd.tes.bihealth.org
13+
TESK @ ELIXIR-GR,https://tesk-eu.hypatia-comp.athenarc.gr
1314

14-
# Local Development
15-
Local TES,http://localhost:8080

backend/services/tes_service.py

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -135,13 +135,29 @@ def fetch_tes_status(instance):
135135

136136
def get_service_info(tes_url):
137137
"""Get service info from a TES instance with multiple endpoint attempts"""
138-
try:
138+
try:
139+
tes_url = (tes_url or "").rstrip("/")
140+
credentials = get_instance_credentials("unknown", tes_url)
141+
headers = {
142+
'Accept': 'application/json',
143+
'User-Agent': 'TES-Dashboard/1.0'
144+
}
145+
auth = None
146+
147+
if credentials.get('token'):
148+
headers['Authorization'] = f"Bearer {credentials['token']}"
149+
elif credentials.get('user') and credentials.get('password'):
150+
auth = (credentials['user'], credentials['password'])
151+
139152
endpoints_to_try = [
140153
f"{tes_url}/ga4gh/tes/v1/service-info",
141-
f"{tes_url}/v1/tasks",
154+
f"{tes_url}/v1/service-info",
155+
f"{tes_url}/tasks/v1/service-info",
142156
f"{tes_url}/service-info",
143157
f"{tes_url}/api/service-info",
144158
f"{tes_url}/api/v1/service-info",
159+
f"{tes_url}/v1/tasks",
160+
f"{tes_url}/tasks/v1/tasks",
145161
]
146162

147163
last_error = None
@@ -153,30 +169,51 @@ def get_service_info(tes_url):
153169
response = requests.get(
154170
endpoint,
155171
timeout=10,
156-
headers={
157-
'Accept': 'application/json',
158-
'User-Agent': 'TES-Dashboard/1.0'
159-
},
172+
headers=headers,
173+
auth=auth,
160174
verify=True
161175
)
162176

163177
print(f"📊 Response status: {response.status_code}")
164178

165179
if response.status_code == 200:
166180
try:
167-
service_info = response.json()
181+
payload = response.json()
182+
if endpoint.endswith('/v1/tasks'):
183+
print(f"✅ TES API reachable via {endpoint}; building synthetic service info")
184+
return {
185+
'name': f"TES Service @ {tes_url}",
186+
'id': tes_url,
187+
'organization': {
188+
'name': 'Unknown',
189+
'url': tes_url
190+
},
191+
'description': 'TES instance reachable, service-info endpoint not exposed at common paths.',
192+
'type': {
193+
'group': 'ga4gh',
194+
'artifact': 'tes',
195+
'version': 'Unknown'
196+
},
197+
'contactUrl': 'Unknown',
198+
'documentationUrl': 'Unknown',
199+
'storage': ['Unknown'],
200+
'version': payload.get('version', 'Unknown') if isinstance(payload, dict) else 'Unknown',
201+
'message': 'TES endpoint is reachable; service metadata is limited.',
202+
'timestamp': datetime.now(timezone.utc).isoformat()
203+
}
204+
168205
print(f"✅ Successfully got service info from {endpoint}")
169-
return service_info
206+
return payload
170207
except ValueError as json_error:
171208
print(f"⚠️ Invalid JSON response: {json_error}")
172209
last_error = f"Invalid JSON: {json_error}"
173210
continue
174211

175-
elif response.status_code == 403:
212+
elif response.status_code in (401, 403):
176213
print(f"🔒 Endpoint {endpoint} requires authentication")
177214
auth_required = True
178-
last_error = "Authentication required"
179-
break
215+
last_error = "Authentication required or credentials rejected"
216+
continue
180217

181218
else:
182219
print(f"⚠️ Status {response.status_code} from {endpoint}")
Lines changed: 87 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,106 @@
11
[
22
{
3-
"id": "elixir-cz",
4-
"name": "TESK Production",
5-
"url": "https://tesk-prod.cloud.e-infra.cz",
6-
"country": "Czech Republic",
7-
"lat": 49.75,
8-
"lng": 15.5,
9-
"lon": 15.5,
10-
"status": "healthy",
11-
"description": "Primary TESK production instance",
3+
"id": "elixir:cz:1",
4+
"name": "Funnel/OpenPBS @ ELIXIR-CZ",
5+
"url": "https://funnel.cloud.e-infra.cz",
6+
"country": "Czechia",
7+
"lat": 50.0755,
8+
"lng": 14.4378,
9+
"lon": 14.4378,
10+
"status": "online",
11+
"description": "Funnel with OpenPBS backend",
12+
"version": "1.1",
13+
"region": "EU-Central"
14+
},
15+
{
16+
"id": "elixir:cz:2",
17+
"name": "Poiesis @ ELIXIR-CZ",
18+
"url": "https://poiesis.dyn.cloud.e-infra.cz/",
19+
"country": "Czechia",
20+
"lat": 50.0755,
21+
"lng": 14.4378,
22+
"lon": 14.4378,
23+
"status": "online",
24+
"description": "Poiesis TES instance",
25+
"version": "1.1",
1226
"region": "EU-Central"
1327
},
1428
{
15-
"id": "elixir-fi",
16-
"name": "TESK/OpenShift @ ELIXIR-FI",
17-
"url": "https://csc-tesk-noauth.rahtiapp.fi/ga4gh/tes",
29+
"id": "elixir:fi:1",
30+
"name": "TESK @ ELIXIR-FI",
31+
"url": "https://csc-tesk-noauth.rahtiapp.fi",
1832
"country": "Finland",
1933
"lat": 60.1699,
2034
"lng": 24.9384,
2135
"lon": 24.9384,
22-
"status": "healthy",
23-
"description": "OpenShift-based TESK instance",
36+
"status": "online",
37+
"description": "TESK instance at CSC",
38+
"version": "1.0",
2439
"region": "EU-North"
2540
},
2641
{
27-
"id": "elixir-gr",
28-
"name": "TESK/Kubernetes @ ELIXIR-GR",
29-
"url": "https://tesk.c3g.calculquebec.ca",
30-
"country": "Greece",
31-
"lat": 37.9838,
32-
"lng": 23.7275,
33-
"lon": 23.7275,
34-
"status": "healthy",
35-
"description": "Kubernetes-based TESK instance",
36-
"region": "EU-South"
42+
"id": "elixir:fi:2",
43+
"name": "Funnel/Slurm @ ELIXIR-FI",
44+
"url": "https://fip-86-50-228-254.kaj.poutavm.fi/",
45+
"country": "Finland",
46+
"lat": 60.1699,
47+
"lng": 24.9384,
48+
"lon": 24.9384,
49+
"status": "online",
50+
"description": "Funnel with Slurm backend",
51+
"version": "unknown",
52+
"region": "EU-North"
3753
},
3854
{
39-
"id": "funnel-cz",
40-
"name": "Funnel/OpenPBS @ ELIXIR-CZ",
41-
"url": "https://funnel.cloud.e-infra.cz",
42-
"country": "Czech Republic",
43-
"lat": 50.0755,
44-
"lng": 14.4378,
45-
"lon": 14.4378,
46-
"status": "healthy",
47-
"description": "Funnel with OpenPBS backend",
55+
"id": "elixir:fi:3",
56+
"name": "Poiesis @ ELIXIR-FI",
57+
"url": "https://poiesis.rahtiapp.fi/",
58+
"country": "Finland",
59+
"lat": 60.1699,
60+
"lng": 24.9384,
61+
"lon": 24.9384,
62+
"status": "online",
63+
"description": "Poiesis TES instance",
64+
"version": "1.1",
65+
"region": "EU-North"
66+
},
67+
{
68+
"id": "elixir:fi:4",
69+
"name": "Test Poiesis @ ELIXIR-FI",
70+
"url": "https://test-poiesis.rahtiapp.fi/",
71+
"country": "Finland",
72+
"lat": 60.1699,
73+
"lng": 24.9384,
74+
"lon": 24.9384,
75+
"status": "online",
76+
"description": "Test Poiesis instance",
77+
"version": "1.1",
78+
"region": "EU-North"
79+
},
80+
{
81+
"id": "elixir:de:1",
82+
"name": "Funnel/Slurm @ BIH",
83+
"url": "https://spe4hd.tes.bihealth.org",
84+
"country": "Germany",
85+
"lat": 52.52,
86+
"lng": 13.40,
87+
"lon": 13.40,
88+
"status": "online",
89+
"description": "Funnel with Slurm backend",
90+
"version": "1.0",
4891
"region": "EU-Central"
4992
},
5093
{
51-
"id": "local-tes",
52-
"name": "Local TES",
53-
"url": "http://localhost:8080",
54-
"country": "Local",
55-
"lat": 0,
56-
"lng": 0,
57-
"lon": 0,
58-
"status": "unknown",
59-
"description": "Local development TES instance",
60-
"region": "Local"
94+
"id": "elixir:gr:1",
95+
"name": "TESK @ ELIXIR-GR",
96+
"url": "https://tesk-eu.hypatia-comp.athenarc.gr",
97+
"country": "Greece",
98+
"lat": 37.9838,
99+
"lng": 23.7275,
100+
"lon": 23.7275,
101+
"status": "online",
102+
"description": "TESK instance",
103+
"version": "1.0",
104+
"region": "EU-South"
61105
}
62106
]

backend/utils/auth_utils.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,37 @@
22
from config import FUNNEL_SERVER_USER, FUNNEL_SERVER_PASSWORD, TES_TOKEN
33

44
def get_instance_credentials(instance_name, instance_url):
5+
instance_url = (instance_url or '').rstrip('/')
56
default_user = FUNNEL_SERVER_USER
67
default_pass = FUNNEL_SERVER_PASSWORD
78
default_token = TES_TOKEN
89

9-
if 'tesk-prod.cloud.e-infra.cz' in instance_url:
10+
if 'funnel.cloud.e-infra.cz' in instance_url:
1011
return {
11-
'user': os.getenv('TESK_PROD_USER', default_user),
12-
'password': os.getenv('TESK_PROD_PASSWORD', default_pass),
13-
'token': os.getenv('TESK_PROD_TOKEN', default_token)
12+
'user': os.getenv('FUNNEL_CZ_USER', default_user),
13+
'password': os.getenv('FUNNEL_CZ_PASSWORD', default_pass),
14+
'token': None
1415
}
15-
elif 'tesk-na.cloud.e-infra.cz' in instance_url:
16+
17+
elif 'fip-86-50-228-254.kaj.poutavm.fi' in instance_url:
18+
return {
19+
'user': os.getenv('FUNNEL_FI_USER', default_user),
20+
'password': os.getenv('FUNNEL_FI_PASSWORD', default_pass),
21+
'token': None
22+
}
23+
24+
elif 'tesk-eu.hypatia-comp.athenarc.gr' in instance_url:
25+
return {
26+
'user': os.getenv('TESK_GR_USER', default_user),
27+
'password': os.getenv('TESK_GR_PASSWORD', default_pass),
28+
'token': None
29+
}
30+
31+
elif 'spe4hd.tes.bihealth.org' in instance_url:
1632
return {
17-
'user': os.getenv('TESK_NA_USER', default_user),
18-
'password': os.getenv('TESK_NA_PASSWORD', default_pass),
19-
'token': os.getenv('TESK_NA_TOKEN', default_token)
33+
'user': None,
34+
'password': None,
35+
'token': os.getenv('BIHEALTH_TOKEN', default_token)
2036
}
2137
else:
2238
return {

docker-compose.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
services:
2+
tes-dashboard-backend-service:
3+
build:
4+
context: ./backend
5+
dockerfile: Dockerfile
6+
container_name: tes-dashboard-backend
7+
environment:
8+
PORT: 8000
9+
FLASK_ENV: production
10+
FLASK_DEBUG: "false"
11+
ports:
12+
- "8000:8000"
13+
volumes:
14+
- ./backend/uploads:/app/uploads
15+
- ./backend/tes_instance_locations.json:/app/tes_instance_locations.json
16+
- ./backend/.tes_instances:/app/.tes_instances
17+
extra_hosts:
18+
- "spe4hd.tes.bihealth.org:194.94.4.48"
19+
healthcheck:
20+
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/api/health', timeout=5)"]
21+
interval: 30s
22+
timeout: 10s
23+
retries: 3
24+
start_period: 40s
25+
restart: unless-stopped
26+
27+
tes-dashboard-frontend-service:
28+
build:
29+
context: ./frontend
30+
dockerfile: Dockerfile
31+
args:
32+
REACT_APP_API_URL: ""
33+
container_name: tes-dashboard-frontend
34+
depends_on:
35+
tes-dashboard-backend-service:
36+
condition: service_healthy
37+
ports:
38+
- "3000:80"
39+
restart: unless-stopped

frontend/Dockerfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ RUN npm ci --only=production
1313
# Copy source code
1414
COPY . .
1515

16+
# Accept API URL build argument (empty = use nginx proxy)
17+
ARG REACT_APP_API_URL=""
18+
ENV REACT_APP_API_URL=$REACT_APP_API_URL
19+
1620
# Build the application
1721
RUN npm run build
1822

frontend/src/services/api.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import axios from 'axios';
22

33
const getApiBaseUrl = () => {
4-
if (process.env.REACT_APP_API_URL) {
4+
if (process.env.REACT_APP_API_URL !== undefined && process.env.REACT_APP_API_URL !== null) {
55
return process.env.REACT_APP_API_URL;
66
}
77

frontend/src/utils/constants.js

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,12 @@ export const THEME = {
8888
};
8989

9090
export const TES_INSTANCES = [
91-
{ name: 'Funnel/OpenPBS @ ELIXIR-CZ', url: 'https://funnel.cloud.e-infra.cz', id: 'funnel-cz' },
92-
{ name: 'Funnel/Slurm @ ELIXIR-FI', url: 'https://vm4816.kaj.pouta.csc.fi', id: 'funnel-fi' },
93-
{ name: 'TESK/Kubernetes @ ELIXIR-CZ (Prod)', url: 'https://tesk-prod.cloud.e-infra.cz', id: 'elixir-cz-prod' },
94-
{ name: 'TESK/Kubernetes @ ELIXIR-CZ (NA)', url: 'https://tesk-na.cloud.e-infra.cz', id: 'elixir-cz-na' },
95-
{ name: 'TESK/Kubernetes @ ELIXIR-DE', url: 'https://tesk.elixir-cloud.bi.denbi.de', id: 'elixir-de' },
96-
{ name: 'TESK/Kubernetes @ ELIXIR-GR', url: 'https://tesk-eu.hypatia-comp.athenarc.gr', id: 'elixir-gr' },
97-
{ name: 'TESK/OpenShift @ ELIXIR-FI', url: 'https://csc-tesk-noauth.rahtiapp.fi', id: 'elixir-fi' },
98-
{ name: 'TESK North America', url: 'https://tesk-na.cloud.e-infra.cz', id: 'tesk-na' },
99-
{ name: 'Local TES', url: 'http://localhost:8080', id: 'local-tes' }
91+
{ name: 'Funnel/OpenPBS @ ELIXIR-CZ', url: 'https://funnel.cloud.e-infra.cz', id: 'elixir:cz:1' },
92+
{ name: 'Poiesis @ ELIXIR-CZ', url: 'https://poiesis.dyn.cloud.e-infra.cz/', id: 'elixir:cz:2' },
93+
{ name: 'TESK @ ELIXIR-FI', url: 'https://csc-tesk-noauth.rahtiapp.fi', id: 'elixir:fi:1' },
94+
{ name: 'Funnel/Slurm @ ELIXIR-FI', url: 'https://fip-86-50-228-254.kaj.poutavm.fi/', id: 'elixir:fi:2' },
95+
{ name: 'Poiesis @ ELIXIR-FI', url: 'https://poiesis.rahtiapp.fi/', id: 'elixir:fi:3' },
96+
{ name: 'Test Poiesis @ ELIXIR-FI', url: 'https://test-poiesis.rahtiapp.fi/', id: 'elixir:fi:4' },
97+
{ name: 'Funnel/Slurm @ BIH', url: 'https://spe4hd.tes.bihealth.org', id: 'elixir:de:1' },
98+
{ name: 'TESK @ ELIXIR-GR', url: 'https://tesk-eu.hypatia-comp.athenarc.gr', id: 'elixir:gr:1' }
10099
];

0 commit comments

Comments
 (0)