github.com/zppinho/prow@v0.0.0-20240510014325-1738badeb017/cmd/deck/static/common/rerun.ts (about)

     1  import {copyToClipboard, icon, showAlert, showToast} from "./common";
     2  import {relativeURL} from "./urls";
     3  
     4  export function createRerunProwJobIcon(modal: HTMLElement, parentEl: Element, prowjob: string, showRerunButton: boolean, csrfToken: string): HTMLElement {
     5    const LATEST_JOB = 'latest';
     6    const ORIGINAL_JOB = 'original';
     7    const inrepoconfigURL = 'https://docs.prow.k8s.io/docs/inrepoconfig/';
     8    const i = icon.create("refresh", "Show instructions for rerunning this job");
     9  
    10    const closeModal = (): void => {
    11      modal.style.display = "none";
    12      // Resets modal content. If removed, elements will be concatenated, causing duplicates.
    13      parentEl.classList.remove('rerun-content', 'abort-content');
    14      parentEl.innerHTML = '';
    15    };
    16    window.onkeydown = (event: any) => {
    17      if (event.key === "Escape") {
    18        closeModal();
    19      }
    20    };
    21    window.onclick = (event: any) => {
    22      if (event.target === modal) {
    23        closeModal();
    24      }
    25    };
    26    const getJobURL = (mode: string): string => {
    27      return `${location.protocol}//${location.host}/rerun?mode=${mode}&prowjob=${prowjob}`;
    28    };
    29    let commandURL = getJobURL(ORIGINAL_JOB);
    30    const getCommandDescription = (mode: string): string => {
    31      return `The command is for the ${mode} configuration. Admin permissions are required to rerun via kubectl.`;
    32    };
    33    const getCommand = (url: string): string => {
    34      return `kubectl create -f "${url}"`;
    35    };
    36  
    37    // we actually want to know whether the "access-token-session" cookie exists, but we can't always
    38    // access it from the frontend. "github_login" should be set whenever "access-token-session" is
    39    i.onclick = () => {
    40      modal.style.display = "block";
    41      // Add the styles for rerun modal
    42      parentEl.classList.add('rerun-content');
    43  
    44      parentEl.innerHTML = `
    45        <h2 class="rerunModal-title">Rerun ProwJob</h2>
    46        <p class="rerunModal-description">
    47          Below you can choose to rerun this ProwJob with either the original or latest configuration.
    48          <br><br>
    49          Note: Rerunning a ProwJob will create a new instance of a ProwJob. Any ProwJobs already running will not be interrupted.
    50          <a href="${inrepoconfigURL}" target="_blank">
    51            Inrepoconfig
    52            <i class='rerunModal-openOut material-icons state triggered' style='color: gray'>open_in_new</i>
    53          </a>
    54          is currently not supported with the latest configuration option.
    55        </p>
    56        <div class="rerunModal-radioButtonGroup">
    57          <div class="rerunModal-radioButtonRow">
    58            <label class="rerunModal-radioLabel mdl-radio mdl-js-radio mdl-js-ripple-effect" for="rerunOriginalOption">
    59              <input type="radio" id="rerunOriginalOption" class="rerunOriginalOption mdl-radio__button" name="rerunOptions" checked>
    60              <span class="mdl-radio__label">Original Configuration</span>
    61            </label>
    62            (<a href="${getJobURL(ORIGINAL_JOB)}" target="_blank">View YAML
    63            <i class="rerunModal-openOut material-icons state triggered" style="color: gray">open_in_new</i>
    64            </a>)
    65          </div>
    66          <div class="rerunModal-radioButtonRow">
    67            <label class="rerunModal-radioLabel mdl-radio mdl-js-radio mdl-js-ripple-effect" for="rerunLatestOption">
    68              <input type="radio" id="rerunLatestOption" class="rerunLatestOption mdl-radio__button" name="rerunOptions">
    69              <span class="mdl-radio__label">Latest Configuration</span>
    70            </label>
    71            (<a href="${getJobURL(LATEST_JOB)}" target="_blank">View YAML
    72            <i class="rerunModal-openOut material-icons state triggered" style="color: gray">open_in_new</i>
    73            </a>)
    74          </div>
    75        </div>
    76        <div class="rerunModal-accordion">
    77          <button class="rerunModal-accordionButton">
    78            <i class="rerunModal-expandIcon material-icons state triggered" style="color: gray">expand_more</i>
    79            kubectl command
    80          </button>
    81          <div class="rerunModal-accordionPanel">
    82            <div class="accordion-panel-content">
    83              <p class="rerunModal-commandDescription">${getCommandDescription(LATEST_JOB)}</p>
    84              <div class="rerunModal-commandContent">
    85                <div class="rerunModal-command">${getCommand(commandURL)}</div>
    86                <a class="rerunModal-copyButton mdl-button mdl-js-button mdl-button--icon">
    87                  <i class="material-icons state triggered" style="color: gray">content_copy</i>
    88                </a>
    89              </div>
    90            </div>
    91          </div>
    92        </div>
    93      `;
    94  
    95      const latestOption = parentEl.querySelector('.rerunLatestOption');
    96      const command = parentEl.querySelector('.rerunModal-command');
    97      const commandDescription = parentEl.querySelector('.rerunModal-commandDescription');
    98      latestOption.addEventListener('click', () => {
    99        commandURL = getJobURL(LATEST_JOB);
   100        commandDescription.innerHTML = getCommandDescription(LATEST_JOB);
   101        command.innerHTML = getCommand(commandURL);
   102      });
   103      const originalOption = parentEl.querySelector('.rerunOriginalOption');
   104      originalOption.addEventListener('click', () => {
   105        commandURL = getJobURL(ORIGINAL_JOB);
   106        commandDescription.innerHTML = getCommandDescription(ORIGINAL_JOB);
   107        command.innerHTML = getCommand(commandURL);
   108      });
   109      const copyButton = parentEl.querySelector('.rerunModal-copyButton');
   110      copyButton.addEventListener('click', () => {
   111        copyToClipboard(getCommand(commandURL));
   112        showToast("Copied to clipboard");
   113      });
   114      const accordion = parentEl.querySelector('.rerunModal-accordionButton');
   115      const accordionPanel = parentEl.querySelector('.rerunModal-accordionPanel');
   116      const expandIcon = parentEl.querySelector('.rerunModal-expandIcon');
   117      accordion.addEventListener('click', () => {
   118        if (!accordionPanel.classList.contains('rerunModal-accordionPanel--expanded')) {
   119          accordionPanel.classList.add('rerunModal-accordionPanel--expanded');
   120          expandIcon.classList.add('rerunModal-expandIcon--expanded');
   121        } else {
   122          accordionPanel.classList.remove('rerunModal-accordionPanel--expanded');
   123          expandIcon.classList.remove('rerunModal-expandIcon--expanded');
   124        }
   125      });
   126  
   127      if (showRerunButton) {
   128        const runButton = document.createElement('a');
   129        runButton.innerHTML = "<button class='mdl-button mdl-js-button mdl-button--raised mdl-button--colored'>Rerun</button>";
   130        runButton.onclick = async () => {
   131          gtag("event", "rerun", {
   132            event_category: "engagement",
   133            transport_type: "beacon",
   134          });
   135          try {
   136            const result = await fetch(commandURL, {
   137              headers: {
   138                "Content-type": "application/x-www-form-urlencoded; charset=UTF-8",
   139                "X-CSRF-Token": csrfToken,
   140              },
   141              method: 'post',
   142            });
   143            if (result.status === 401) {
   144              window.location.href = `${window.location.origin  }/github-login?dest=${relativeURL({rerun: "gh_redirect"})}`;
   145            }
   146            const data = await result.text();
   147            if (result.status >= 400) {
   148              showAlert(data);
   149            } else {
   150              showToast(data);
   151            }
   152          } catch (e) {
   153            showAlert(`Could not send request to rerun job: ${e}`);
   154          }
   155        };
   156        parentEl.appendChild(runButton);
   157      }
   158    };
   159  
   160    return i;
   161  }