/*! * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* global $, moment, Airflow, window, localStorage, document, hostName, csrfToken, CustomEvent */ import { dateTimeAttrFormat, formatTimezone, isoDateToTimeEl, setDisplayedTimezone, TimezoneEvent, } from "./datetime_utils"; window.isoDateToTimeEl = isoDateToTimeEl; /* We pull moment in via a webpack entrypoint rather than import so that we don't put it in more than a single .js file. This "exports" it to be globally available. */ window.moment = Airflow.moment; function displayTime() { const now = moment(); $("#clock") .attr("datetime", now.format(dateTimeAttrFormat)) .html(`${now.format("HH:mm")} ${formatTimezone(now)}`); } function changeDisplayedTimezone(tz) { localStorage.setItem("selected-timezone", tz); // dispatch an event that React can listen for const event = new CustomEvent(TimezoneEvent, { detail: tz, }); document.dispatchEvent(event); setDisplayedTimezone(tz); displayTime(); $("body").trigger({ type: "airflow.timezone-change", timezone: tz, }); } const el = document.createElement("span"); export function escapeHtml(text) { el.textContent = text; return el.innerHTML; } window.escapeHtml = escapeHtml; export function convertSecsToHumanReadable(seconds) { let processedSeconds = seconds; const oriSeconds = seconds; const floatingPart = oriSeconds - Math.floor(oriSeconds); processedSeconds = Math.floor(processedSeconds); const secondsPerHour = 60 * 60; const secondsPerMinute = 60; const hours = Math.floor(processedSeconds / secondsPerHour); processedSeconds -= hours * secondsPerHour; const minutes = Math.floor(processedSeconds / secondsPerMinute); processedSeconds -= minutes * secondsPerMinute; let readableFormat = ""; if (hours > 0) { readableFormat += `${hours}Hours `; } if (minutes > 0) { readableFormat += `${minutes}Min `; } if (processedSeconds + floatingPart > 0) { if (Math.floor(oriSeconds) === oriSeconds) { readableFormat += `${processedSeconds}Sec`; } else { processedSeconds += floatingPart; readableFormat += `${processedSeconds.toFixed(3)}Sec`; } } return readableFormat; } window.convertSecsToHumanReadable = convertSecsToHumanReadable; function postAsForm(url, parameters) { const form = $("
"); form.attr("method", "POST"); form.attr("action", url); $.each(parameters || {}, (key, value) => { const field = $(""); field.attr("type", "hidden"); field.attr("name", key); field.attr("value", value); form.append(field); }); const field = $(""); field.attr("type", "hidden"); field.attr("name", "csrf_token"); field.attr("value", csrfToken); form.append(field); // The form needs to be a part of the document in order for us to be able // to submit it. $(document.body).append(form); form.submit(); } window.postAsForm = postAsForm; function initializeUITimezone() { const local = moment.tz.guess(); const selectedTz = localStorage.getItem("selected-timezone"); const manualTz = localStorage.getItem("chosen-timezone"); function setManualTimezone(tz) { localStorage.setItem("chosen-timezone", tz); if (tz === local && tz === Airflow.serverTimezone) { $("#timezone-manual").hide(); return; } $("#timezone-manual a").data("timezone", tz).text(formatTimezone(tz)); $("#timezone-manual").show(); } if (manualTz) { setManualTimezone(manualTz); } changeDisplayedTimezone(selectedTz || Airflow.defaultUITimezone); if (Airflow.serverTimezone !== "UTC") { $("#timezone-server a").html( `${formatTimezone( Airflow.serverTimezone )} Server` ); $("#timezone-server").show(); } if (Airflow.serverTimezone !== local) { $("#timezone-local a") .attr("data-timezone", local) .html( `${formatTimezone(local)} Local` ); } else { $("#timezone-local").hide(); } $("a[data-timezone]").click((evt) => { changeDisplayedTimezone($(evt.currentTarget).data("timezone")); }); $("#timezone-other").typeahead({ source: $( moment.tz.names().map((tzName) => { const category = tzName.split("/", 1)[0]; return { category, name: tzName.replace("_", " "), tzName }; }) ), showHintOnFocus: "all", showCategoryHeader: true, items: "all", afterSelect(data) { // Clear it for next time we open the pop-up this.$element.val(""); setManualTimezone(data.tzName); changeDisplayedTimezone(data.tzName); // We need to delay the close event to not be in the form handler, // otherwise bootstrap ignores it, thinking it's caused by interaction on // the