Skip to content

Commit

Permalink
Merge branch 'release-3.x.x' into TASK-4846
Browse files Browse the repository at this point in the history
  • Loading branch information
jmjuanes authored Nov 4, 2024
2 parents f1c4e35 + a27300d commit f4e6bbb
Show file tree
Hide file tree
Showing 15 changed files with 677 additions and 568 deletions.
4 changes: 2 additions & 2 deletions src/webcomponents/commons/forms/data-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -807,15 +807,15 @@ export default class DataForm extends LitElement {
}

return html`
<div class="${hasErrorMessages ? "text-danger" : nothing}">
<div>
<div data-testid="${this.config.test?.active ? `${this.config.test.prefix || "test"}-${element.field}` : nothing}">
${contentHtml}
</div>
${helpMessage && helpMode !== "block" ? html`
<div class="form-text">${helpMessage}</div>
` : nothing}
${hasErrorMessages ? html`
<div class="d-flex mt-2 text-body-secondary">
<div class="d-flex mt-2 text-danger">
<div class="me-2">
<i class="${this._getErrorIcon(element)}"></i>
</div>
Expand Down
3 changes: 1 addition & 2 deletions src/webcomponents/commons/forms/select-field-filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,6 @@ export default class SelectFieldFilter extends LitElement {
.select-field-filter .select2-results__options {
max-height: 600px !important;
}
.select-field-filter .select2-results__option--selected {
background-color: #fff !important;
color: #000 !important;
Expand All @@ -379,7 +378,7 @@ export default class SelectFieldFilter extends LitElement {
render() {
return html`
${this.renderStyle()}
<div class="input-group mb-1 select-field-filter">
<div class="input-group select-field-filter">
<select
class="form-select"
id="${this._prefix}"
Expand Down
2 changes: 1 addition & 1 deletion src/webcomponents/commons/layouts/custom-navbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ export default class CustomNavBar extends LitElement {
<div class="navbar-brand d-flex justify-content-center align-items-center me-n1" style="height: 2.5rem;">
<!-- Application logo provided -->
${this.app?.logo ? html`
<img class="d-inline-block" src="${this.app?.logo}" alt="App logo">
<img class="d-inline-block" src="${this.app?.logo}" alt="App logo" style="height:1.3em;">
` : nothing}
<!-- No application logo provided -->
${!this.app?.logo && this.app?.name ? html`
Expand Down
26 changes: 16 additions & 10 deletions src/webcomponents/commons/modal/modal-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,17 @@ export default class ModalUtils {

static create(self, id, config) {
// Parse modal parameters, all of them must start with prefix 'modal'
const modalWidth = config.display?.modalWidth || "768px";
const modalSize = config.display?.modalSize || "";
const modalTitle = config.display?.modalTitle || "";
const modalTitleHeader = config.display?.modalTitleHeader || "h4";
const modalTitleClassName = config.display?.modalTitleClassName || "";
const modalTitleStyle = config.display?.modalTitleStyle || "";
const btnsVisible = config.display?.modalbtnsVisible;
const modalDraggable = config.display?.modalDraggable || false;
const modalCyDataName = config.display?.modalCyDataName || "";
const modalWidth = config.display?.modalWidth ?? "768px";
const modalSize = config.display?.modalSize ?? "";
const modalTitle = config.display?.modalTitle ?? "";
const modalTitleHeader = config.display?.modalTitleHeader ?? "h4";
const modalTitleClassName = config.display?.modalTitleClassName ?? "";
const modalTitleStyle = config.display?.modalTitleStyle ?? "";
const btnsVisible = config.display?.modalbtnsVisible ?? false;
const btnCancelVisible = config.display?.btnCancelVisible ?? true;
const btnSaveVisible = config.display?.btnSaveVisible ?? true;
const modalDraggable = config.display?.modalDraggable ?? false;
const modalCyDataName = config.display?.modalCyDataName ?? "";

return html`
<div
Expand All @@ -38,7 +40,7 @@ export default class ModalUtils {
aria-hidden="true"
data-cy="${modalCyDataName}"
>
<div class="modal-dialog ${modalSize}" style="width: ${modalWidth}">
<div class="modal-dialog ${modalSize}" style="width: ${modalSize ? "": modalWidth}">
<div class="modal-content">
<div class="modal-header">
${ModalUtils.#getTitleHeader(modalTitleHeader, modalTitle, "modal-title " + modalTitleClassName, modalTitleStyle)}
Expand All @@ -53,6 +55,7 @@ export default class ModalUtils {
</div>
${btnsVisible? html`
<div class="modal-footer">
${btnCancelVisible ? html`
<button
type="button"
class="btn btn-light"
Expand All @@ -61,6 +64,8 @@ export default class ModalUtils {
>
${config?.display?.cancelButtonText || "Cancel"}
</button>
` : nothing}
${btnSaveVisible ? html`
<button
type="button"
class="btn btn-primary"
Expand All @@ -69,6 +74,7 @@ export default class ModalUtils {
>
${config?.display?.okButtonText || "Save"}
</button>
` : nothing}
</div>
`: nothing}
</div>
Expand Down
27 changes: 7 additions & 20 deletions src/webcomponents/commons/opencga-browser-filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import {LitElement, html, nothing} from "lit";
import {LitElement, html} from "lit";
import UtilsNew from "../../core/utils-new.js";
import LitUtils from "./utils/lit-utils.js";
import "./filters/catalog-search-autocomplete.js";
Expand All @@ -34,7 +34,7 @@ export default class OpencgaBrowserFilter extends LitElement {
constructor() {
super();

this._init();
this.#init();

}
createRenderRoot() {
Expand Down Expand Up @@ -67,15 +67,9 @@ export default class OpencgaBrowserFilter extends LitElement {
};
}

_init() {
#init() {
this._prefix = UtilsNew.randomString(8);

this.annotationFilterConfig = {
class: "small",
buttonClass: "btn-sm",
inputClass: "input-sm"
};

this.query = {};
this.preparedQuery = {};
this.searchButton = true;
Expand Down Expand Up @@ -112,12 +106,6 @@ export default class OpencgaBrowserFilter extends LitElement {
};
}

connectedCallback() {
super.connectedCallback();

this.preparedQuery = {...this.query}; // propagates here the iva-app query object
}

firstUpdated(changedProperties) {
super.firstUpdated(changedProperties);

Expand All @@ -141,17 +129,18 @@ export default class OpencgaBrowserFilter extends LitElement {

queryObserver() {
this.preparedQuery = this.query || {};
this.requestUpdate();
}

onFilterChange(key, value) {
if (value && value !== "") {
this.preparedQuery = {...this.preparedQuery, ...{[key]: value}};
this.preparedQuery[key] = value;
} else {
delete this.preparedQuery[key];
this.preparedQuery = {...this.preparedQuery};
}
this.preparedQuery = {...this.preparedQuery};
this.notifyQuery(this.preparedQuery);
// Note 20241015 Vero: I believe this.requestUpdate() is not needed, but removing it requires further investigation
// (see variant-browser-filter.js, onFilterChange())
this.requestUpdate();
}

Expand All @@ -163,7 +152,6 @@ export default class OpencgaBrowserFilter extends LitElement {
}
this.preparedQuery = {...this.preparedQuery};
this.notifyQuery(this.preparedQuery);
this.requestUpdate();
}

notifyQuery(query) {
Expand Down Expand Up @@ -289,7 +277,6 @@ export default class OpencgaBrowserFilter extends LitElement {
.opencgaSession="${this.opencgaSession}"
.opencgaClient="${this.opencgaSession.opencgaClient}"
.resource="${this.resource}"
.config="${this.annotationFilterConfig}"
.selectedVariablesText="${this.preparedQuery.annotation}"
@annotationChange="${this.onAnnotationChange}">
</opencga-annotation-filter-modal>
Expand Down
89 changes: 53 additions & 36 deletions src/webcomponents/job/job-monitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ export class JobMonitor extends LitElement {
#init() {
this.JOBS_TYPES = {
ALL: {
title: "All",
jobsTypes: [],
title: "Latest",
jobsTypes: ["PENDING", "QUEUED", "RUNNING", "DONE", "ERROR", "ABORTED"],
},
RUNNING: {
title: "Running",
Expand All @@ -59,9 +59,9 @@ export class JobMonitor extends LitElement {
},
};
this._interval = -1;
this._jobs = [];
this._addedJobs= new Set(); // Used for displaying the NEW label in each new job
this._updatedJobsCount = 0; // To store the number of changes (new jobs, state changes)
this._jobs = null;
this._latestJobs = []; // To store the latest updated jobs
this._updatedJobs= new Set(); // Used for displaying the NEW label in each new job
this._visibleJobsType = "ALL"; // Current visible jobs types (one of JOB_TYPES)
this._config = this.getDefaultConfig();
}
Expand All @@ -74,9 +74,9 @@ export class JobMonitor extends LitElement {

update(changedProperties) {
if (changedProperties.has("opencgaSession")) {
this._jobs = [];
this._updatedJobsCount = 0;
this._addedJobs = new Set();
this._jobs = null;
this._latestJobs = [];
this._updatedJobs = new Set();
this._visibleJobsType = "ALL";
}
if (changedProperties.has("config")) {
Expand Down Expand Up @@ -111,22 +111,28 @@ export class JobMonitor extends LitElement {
}

fetchLastJobs() {
this.opencgaSession.opencgaClient.jobs()
.search({
study: this.opencgaSession.study.fqn,
internalStatus: "PENDING,QUEUED,RUNNING,DONE,ERROR,ABORTED",
limit: this._config.limit || 10,
sort: "creationDate",
include: "id,internal.status,tool,creationDate",
order: -1,
})
.then(response => {
const newJobsList = response?.responses?.[0]?.results || [];
// generate the list of job types to fetch. Note that if the visible jobs type is "ALL",
// we will prevent requesting for the same job types multiple times
const jobsTypesToFetch = Array.from(new Set(["ALL", this._visibleJobsType]));
const jobsPromises = jobsTypesToFetch.map(jobType => {
return this.opencgaSession.opencgaClient.jobs()
.search({
study: this.opencgaSession.study.fqn,
internalStatus: this.JOBS_TYPES[jobType].jobsTypes.join(","),
limit: this._config.limit || 10,
sort: "creationDate",
include: "id,internal.status,tool,creationDate",
order: -1,
});
});
Promise.all(jobsPromises)
.then(responses => {
const newJobsList = responses[0]?.responses?.[0]?.results || [];
// 1. Process the list of new jobs returned by OpenCGA
// Note: we check if the previous list of jobs is not empty, to prevent marking all jobs as new jobs
if (this._jobs.length > 0) {
if (this._latestJobs?.length > 0) {
newJobsList.forEach(job => {
const oldJob = this._jobs.find(j => j.id === job.id);
const oldJob = this._latestJobs.find(j => j.id === job.id);
if (oldJob) {
const statusId = job?.internal?.status?.id || "-";
const oldStatusId = oldJob?.internal?.status?.id || "-";
Expand All @@ -135,20 +141,20 @@ export class JobMonitor extends LitElement {
NotificationUtils.dispatch(this, NotificationUtils.NOTIFY_INFO, {
message: `The job <b>${job?.id}</b> has now status ${statusId}.`,
});
this._updatedJobsCount = this._updatedJobsCount + 1;
}
} else {
// This is a new job, so we display an info notification to the user
NotificationUtils.dispatch(this, NotificationUtils.NOTIFY_INFO, {
message: `The job <b>${job?.id}</b> has been added.`,
});
this._updatedJobsCount = this._updatedJobsCount + 1;
this._addedJobs.add(job.id);
this._updatedJobs.add(job.id);
}
});
}
// 2. Save the new jobs list
this._jobs = newJobsList;
this._latestJobs = newJobsList;
// 3. save the visible jobs list
this._jobs = responses[1]?.responses?.[0]?.results || newJobsList;
this.requestUpdate();
})
.catch(response => {
Expand All @@ -162,12 +168,16 @@ export class JobMonitor extends LitElement {

onRefresh(event) {
event.stopPropagation();
this._jobs = null;
this.fetchLastJobs();
this.requestUpdate();
}

onJobTypeChange(event, newJobType) {
event.stopPropagation();
this._jobs = null;
this._visibleJobsType = newJobType;
this.fetchLastJobs();
this.requestUpdate();
}

Expand All @@ -180,20 +190,17 @@ export class JobMonitor extends LitElement {
}

renderVisibleJobsList() {
// Get the list of visible jobs with the selected type
const visibleJobs = this._jobs.filter(job => {
return this._visibleJobsType === "ALL" || this.JOBS_TYPES[this._visibleJobsType].jobsTypes.includes(job?.internal?.status?.id);
});
if (visibleJobs.length > 0) {
return visibleJobs.map(job => html`
// Display jobs list
if (this._jobs && this._jobs.length > 0) {
return this._jobs.map(job => html`
<li>
<a href="${this.getJobUrl(job.id)}" class="dropdown-item border-top">
<div class="d-flex align-items-center overflow-hidden">
<div class="flex-shrink-0 fs-2 rocket-${job?.internal?.status?.id ?? job?.internal?.status?.name ?? "default"}">
<i class="text-secondary fas fa-rocket"></i>
</div>
<div class="flex-grow-1 ms-3">
${this._addedJobs.has(job?.id) ? html`
${this._updatedJobs.has(job?.id) ? html`
<span class="badge bg-primary rounded-pill">NEW</span>
` : nothing}
<div class="mt-0 text-truncate" style="max-width:275px">
Expand All @@ -212,11 +219,21 @@ export class JobMonitor extends LitElement {
</a>
</li>
`);
} else if (this._jobs && this._jobs.length === 0) {
return html`
<li>
<div class="d-flex flex-column justify-content-center align-items-center py-3 gap-1">
<i class="fas fa-tasks"></i>
<div class="fw-bold small">No jobs on this category</div>
</div>
</li>
`;
} else {
return html`
<li>
<div class="pt-2 pb-1 text-center fw-bold border-top">
No jobs on this category.
<div class="d-flex flex-column justify-content-center align-items-center py-3 gap-1">
<i class="fas fa-sync-alt anim-rotate"></i>
<div class="fw-bold small">Loading jobs...</div>
</div>
</li>
`;
Expand All @@ -231,9 +248,9 @@ export class JobMonitor extends LitElement {
<div class="dropdown-button-icon">
<i class="fas fa-rocket"></i>
</div>
${this._updatedJobsCount > 0 ? html`
${this._updatedJobs.size > 0 ? html`
<span class="position-absolute top-0 start-100 mt-1 translate-middle badge bg-danger rounded-pill">
${this._updatedJobsCount}
${this._updatedJobs.size}
</span>
` : nothing}
</a>
Expand Down
Loading

0 comments on commit f4e6bbb

Please sign in to comment.