opf/openproject

View on GitHub
frontend/src/stimulus/controllers/dynamic/storages/open-project-storage-modal.controller.ts

Summary

Maintainability
A
3 hrs
Test Coverage
/*
 * -- copyright
 * OpenProject is an open source project management software.
 * Copyright (C) 2023 the OpenProject GmbH
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version 3.
 *
 * OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
 * Copyright (C) 2006-2013 Jean-Philippe Lang
 * Copyright (C) 2010-2013 the ChiliProject Team
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * See COPYRIGHT and LICENSE files for more details.
 * ++
 */

import { Controller } from '@hotwired/stimulus';
import { renderStreamMessage } from '@hotwired/turbo';
import { xCircleIconData, toDOMString } from '@openproject/octicons-angular';

export default class OpenProjectStorageModalController extends Controller<HTMLDialogElement> {
  static values = {
    projectStorageOpenUrl: String,
    redirectUrl: String,
  };

  loadingInterval:number;
  timeoutInterval:number;
  networkErrorHappened:boolean;
  projectStorageOpenUrlValue:string;
  redirectUrlValue:string;

  connect() {
    this.element.showModal();
    this.loadingInterval = 0;
    this.networkErrorHappened = false;
    this.load();
    this.timeoutInterval = window.setTimeout(
      () => {
        clearInterval(this.loadingInterval);
        this.setTimeoutMessage();
      },
      120000,
    );
    this.element.addEventListener('close', () => { this.disconnect(); });
    this.element.addEventListener('cancel', () => { this.disconnect(); });
  }

  disconnect() {
    clearInterval(this.loadingInterval);
    clearInterval(this.timeoutInterval);
  }

  load() {
    this.loadingInterval = window.setTimeout(
      async () => {
        try {
          const response = await fetch(
            this.projectStorageOpenUrlValue,
            {
              headers: {
                Accept: 'text/vnd.turbo-stream.html',
              },
            },
          );
          if (response.status === 200) {
            const streamActionHTML = await response.text();
            renderStreamMessage(streamActionHTML);
            setTimeout(
              () => { window.location.href = this.redirectUrlValue; },
              2000,
            );
          } else {
            if (this.networkErrorHappened === true) {
              this.setNetworkErrorHappened(false);
            }
            this.load();
          }
        } catch (error:unknown) {
          console.error('Error: ', error);
          if (this.networkErrorHappened === false) {
            this.setNetworkErrorHappened(true);
          }
          setTimeout(() => this.load(), 3000);
        }
      },
      3000,
    );
  }

  private setNetworkErrorHappened(value:boolean) {
    const waitingSubtitle = document.getElementById('waiting_subtitle');
    if (waitingSubtitle) {
      waitingSubtitle.innerText = I18n.t(
        `js.open_project_storage_modal.waiting_subtitle.network_${value ? 'off' : 'on'}`,
      );
    }
    this.networkErrorHappened = value;
  }

  private setTimeoutMessage() {
    const waitingLogo = document.getElementById('waiting_logo');
    const waitingTitle = document.getElementById('waiting_title');
    const waitingSubtitle = document.getElementById('waiting_subtitle');
    if (waitingLogo) {
      waitingLogo.innerHTML = toDOMString(
        xCircleIconData,
        'medium',
        {
          'aria-hidden': 'true',
          class: 'octicon octicon-x-circle-icon color-fg-danger',
        },
      );
    }
    if (waitingTitle) {
      waitingTitle.innerText = I18n.t(
        'js.open_project_storage_modal.waiting_title.timeout',
      );
    }
    if (waitingSubtitle) {
      waitingSubtitle.innerHTML = I18n.t(
        'js.open_project_storage_modal.waiting_subtitle.timeout',
      );
    }
  }
}