Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [1.1.0 - 2026-05-06]
## [1.1.0 - 2026-05-07]
### Added
- Dockerfile
- Single Spa
Expand Down Expand Up @@ -145,6 +145,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Filter boolean form fields for creation rules
- Cohort definition in a query
- Query Details
- Rename overview headers

### Removed
- Application Form
Expand Down
103 changes: 55 additions & 48 deletions src/components/BridgeheadOverview.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<template>
<div class="table-container">
<button v-if="bridgeheads.length > numberBridgeheadShown" title="left" @click="scrollBridgehead('left')"
<button v-if="bridgeheads.length > numberBridgeheadShown" title="left"
@click="scrollBridgehead('left')"
class="btn btn-primary bridgehead-arrow">
<i class="bi bi-caret-left-fill"></i>
</button>
Expand All @@ -9,19 +10,20 @@
<tr v-for="(header, index) in headers" :key="index">
<!-- Header in the first column -->
<td class="header-cell">{{ header }}</td>
<td v-if="header === Header.SITES" class="header-summary-cell" style="border-top: 1px solid #dddddd">
<td v-if="header === Header.SITES" class="header-summary-cell"
style="border-top: 1px solid #dddddd">
{{ bridgeheads.length }}
</td>
<td v-else-if="header === 'Votum'" class="header-summary-cell status-cell">{{ getVotumStatus()[0] }}
<td v-else-if="header === Header.VOTUM" class="header-summary-cell status-cell">
{{ getVotumStatus()[0] }}
<div class="exist-small green"></div>
/ {{ getVotumStatus()[1] }}
<div class="exist-small red"></div>
</td>
<td v-else-if="THeader.isHeaderOfHeaderType(header, Header.TEILER)" class="header-summary-cell status-cell">{{
fetchQueryStatus(THeader.extractProjectType(header))[0]
}}
<td v-else-if="header === Header.TEILER" class="header-summary-cell status-cell">
{{ fetchQueryStatusAll()[0] }}
<div class="exist-small green"></div>
/ {{ fetchQueryStatus(THeader.extractProjectType(header))[1] }}
/ {{ fetchQueryStatusAll()[1] }}
<div class="exist-small red"></div>
</td>
<td v-if="header === DATASHIELD_STATUS_HEADER " class="header-summary-cell status-cell">
Expand All @@ -30,12 +32,14 @@
/ {{ getDatashieldStatus()[1] }}
<div class="exist-small red"></div>
</td>
<td v-else-if="header === 'User Access'" class="header-summary-cell status-cell">{{ getBridgeheadStatus()[0] }}
<td v-else-if="header === Header.USER_ACCESS" class="header-summary-cell status-cell">
{{ getBridgeheadStatus()[0] }}
<div class="exist-small green"></div>
/ {{ getBridgeheadStatus()[1] }}
<div class="exist-small red"></div>
</td>
<td v-else-if="header === Header.APPLICANT_RESULTS_ACCEPTANCE" class="header-summary-cell status-cell">
<td v-else-if="header === Header.APPLICANT_RESULTS_ACCEPTANCE"
class="header-summary-cell status-cell">
{{ getCreatorStatus()[0] }}
<div class="exist-small green"></div>
/ {{ getCreatorStatus()[1] }}
Expand All @@ -53,7 +57,8 @@
{{ bridgehead.humanReadable }}
</div>
<div v-else-if="header === Header.VOTUM">
<div v-if="existsVotums.length > 0 && existsVotums[bridgeheadIndex]" class="states-circle-container">
<div v-if="existsVotums.length > 0 && existsVotums[bridgeheadIndex]"
class="states-circle-container">
<div class="state_circle green"></div>
<DownloadButton
:context="fetchContext(bridgehead)"
Expand All @@ -79,25 +84,35 @@
<div class="state_circle red"></div>
</div>
</div>
<div v-else-if="THeader.isHeaderOfHeaderType(header, Header.TEILER)" class="states-circle-container">
<div class="state_circle"
:class="fetchQueryState(bridgehead, THeader.extractProjectType(header))?.toLowerCase()"
data-toggle="tooltip"
data-placement="top"
:title="fetchQueryState(bridgehead, THeader.extractProjectType(header)) ?? undefined"/>
<div v-else-if="header === Header.TEILER" class="states-circle-container">
<template
v-for="(group) in getMergedQueryStates(bridgehead, getAllProjectTypes(project))"
:key="i">
<div
class="state_circle"
:class="group.state.toLowerCase()"
data-toggle="tooltip"
data-placement="top"
:title="group.types.join(', ')"
/>
</template>
</div>
<div v-else-if="header === Header.USER_ACCESS" class="states-circle-container">
<div class="state_circle" :class="bridgehead?.state?.toLowerCase()" data-toggle="tooltip"
<div class="state_circle" :class="bridgehead?.state?.toLowerCase()"
data-toggle="tooltip"
data-placement="top" :title="bridgehead?.state ?? undefined"/>
</div>
<div v-else-if="header === Header.APPLICANT_RESULTS_ACCEPTANCE" class="states-circle-container">
<div class="state_circle" :class="getCreatorStatusForBridgehead(bridgehead)?.toLowerCase()"
<div v-else-if="header === Header.APPLICANT_RESULTS_ACCEPTANCE"
class="states-circle-container">
<div class="state_circle"
:class="getCreatorStatusForBridgehead(bridgehead)?.toLowerCase()"
data-toggle="tooltip" data-placement="top"
:title="getCreatorStatusForBridgehead(bridgehead) ?? undefined"/>
</div>
<div v-else-if="header === 'DataSHIELD Status'">
<div v-if="dataShieldStatusArray[bridgeheadIndex]" class="states-circle-container">
<div class="state_circle" :class="dataShieldStatusArray[bridgeheadIndex]?.project_status?.toLowerCase()"
<div class="state_circle"
:class="dataShieldStatusArray[bridgeheadIndex]?.project_status?.toLowerCase()"
data-toggle="tooltip" data-placement="top"
:title="dataShieldStatusArray[bridgeheadIndex]?.project_status">
</div>
Expand All @@ -110,7 +125,8 @@
</tr>
</tbody>
</table>
<button v-if="bridgeheads.length > numberBridgeheadShown" title="right" @click="scrollBridgehead('right')"
<button v-if="bridgeheads.length > numberBridgeheadShown" title="right"
@click="scrollBridgehead('right')"
class="btn btn-primary bridgehead-arrow">
<i class="bi bi-caret-right-fill"></i>
</button>
Expand All @@ -124,7 +140,7 @@ import {
Bridgehead,
DataShieldProjectStatus,
getAllProjectTypes,
getQueryState,
getMergedQueryStates,
hasProjectType,
Module,
Project,
Expand All @@ -137,11 +153,10 @@ import {
import DownloadButton from "@/components/DownloadButton.vue";
import '@/assets/styles/state-circle.css'
import {PropType, watch} from "vue";
import {BridgeheadOverviewHeader, MultiHeader} from "@/services/BridgeheadOverviewHeaders";
import {BridgeheadOverviewHeader} from "@/services/BridgeheadOverviewHeaders";

@Options({
name: "BridgeheadOverview",
methods: {fetchQueryState: getQueryState},
computed: {
BridgeheadOverview() {
return BridgeheadOverview
Expand Down Expand Up @@ -191,8 +206,8 @@ export default class BridgeheadOverview extends Vue {
DATASHIELD_STATUS_HEADER = 'DataSHIELD Status';

Header = BridgeheadOverviewHeader;
THeader = MultiHeader;
fetchQueryState = getQueryState;
getMergedQueryStates = getMergedQueryStates;
getAllProjectTypes = getAllProjectTypes;

headers: string[] = [];

Expand All @@ -219,18 +234,24 @@ export default class BridgeheadOverview extends Vue {
}

buildHeaders(): void {
this.headers = []; // reset headers
this.headers = [];
Object.values(this.Header).forEach(header => {
if (header === this.Header.TEILER) {
getAllProjectTypes(this.project).forEach(pt => {
this.headers.push(MultiHeader.build(pt, BridgeheadOverviewHeader.TEILER));
});
} else {
this.headers.push(header);
}
// TEILER is now always a single header — no per-type expansion
this.headers.push(header);
});
}

fetchQueryStatusAll(): number[] {
if (!this.bridgeheads) return [0, 0];
const types = getAllProjectTypes(this.project);
const executions = this.bridgeheads
.flatMap(b => b.executions ?? [])
.filter(e => types.includes(e.projectType));
const finished = executions.filter(e => e.queryState === 'FINISHED').length;
const notFinished = executions.length - finished;
return [finished, notFinished];
}

async updateBridgeheadExtraInfo() {
this.existsVotums = await this.fetchExistsVotums();
this.buildHeaders();
Expand Down Expand Up @@ -319,20 +340,6 @@ export default class BridgeheadOverview extends Vue {
return [withData.length, withoutData.length]
}

fetchQueryStatus(projectType: ProjectType | undefined): number[] {
if (!this.bridgeheads || projectType === undefined) return [0, 0];

// Flatten all executions and filter by projectType
const executions = this.bridgeheads
.flatMap(b => b.executions ?? [])
.filter(e => e.projectType === projectType);

const isFinished = executions.filter(e => e.queryState === 'FINISHED');
const notFinished = executions.filter(e => e.queryState !== 'FINISHED');

return [isFinished.length, notFinished.length];
}

getCreatorStatus(): number[] {
if (this.project?.creatorState === UserProjectState.ACCEPTED && this.project?.resultsUrl) {
return [1, 0];
Expand Down
8 changes: 2 additions & 6 deletions src/components/ProjectDashboard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<tr>
<th scope="col">Request ID</th>
<th scope="col">Title</th>
<th scope="col">Author</th>
<th scope="col">Applicant</th>
<th scope="col">Created on</th>
<th scope="col" style="display: flex;justify-content: space-between;align-items: baseline">
<span>Status</span><span class="filter">
Expand Down Expand Up @@ -263,7 +263,7 @@ thead > tr > th {
}
.main-menu {
width: 100%;
height: 62.4px;
height: 62px;
background-color: rgba(0,72,156,.95);
display: flex;
padding-left: 60%;
Expand Down Expand Up @@ -291,10 +291,6 @@ thead > tr > th {
align-items: center;
}

.notification-button:hover {
color: black !important;
}

.table-box {
margin: 3% 2% 5% 2%;
}
Expand Down
Loading
Loading