From da551d3cd6944f8b1aca78edd33d10612c1030e7 Mon Sep 17 00:00:00 2001 From: Tom Bishop Date: Wed, 4 Sep 2024 12:55:29 -0400 Subject: [PATCH] CLDR-14913 Add Download XML button to Survey Tool (#4010) --- tools/cldr-apps/js/src/esm/cldrAnnounce.mjs | 19 +- .../cldr-apps/js/src/esm/cldrGenerateVxml.mjs | 88 +++++ tools/cldr-apps/js/src/esm/cldrText.mjs | 1 + tools/cldr-apps/js/src/esm/cldrVueMap.mjs | 4 +- tools/cldr-apps/js/src/views/GenerateVxml.vue | 75 +++++ tools/cldr-apps/js/src/views/MainMenu.vue | 1 + .../java/org/unicode/cldr/web/DBUtils.java | 7 +- .../unicode/cldr/web/OutputFileManager.java | 245 +++++--------- .../java/org/unicode/cldr/web/STFactory.java | 11 +- .../unicode/cldr/web/VettingViewerQueue.java | 3 +- .../org/unicode/cldr/web/VxmlGenerator.java | 70 ++++ .../java/org/unicode/cldr/web/VxmlQueue.java | 305 ++++++++++++++++++ .../java/org/unicode/cldr/web/XPathTable.java | 5 +- .../unicode/cldr/web/api/GenerateVxml.java | 111 +++++++ 14 files changed, 765 insertions(+), 180 deletions(-) create mode 100644 tools/cldr-apps/js/src/esm/cldrGenerateVxml.mjs create mode 100644 tools/cldr-apps/js/src/views/GenerateVxml.vue create mode 100644 tools/cldr-apps/src/main/java/org/unicode/cldr/web/VxmlGenerator.java create mode 100644 tools/cldr-apps/src/main/java/org/unicode/cldr/web/VxmlQueue.java create mode 100644 tools/cldr-apps/src/main/java/org/unicode/cldr/web/api/GenerateVxml.java diff --git a/tools/cldr-apps/js/src/esm/cldrAnnounce.mjs b/tools/cldr-apps/js/src/esm/cldrAnnounce.mjs index 056611e93aa..52bc0fda4cc 100644 --- a/tools/cldr-apps/js/src/esm/cldrAnnounce.mjs +++ b/tools/cldr-apps/js/src/esm/cldrAnnounce.mjs @@ -6,12 +6,6 @@ import * as cldrAjax from "./cldrAjax.mjs"; import * as cldrSchedule from "./cldrSchedule.mjs"; import * as cldrStatus from "./cldrStatus.mjs"; -/** - * This should be false for production. It can be made true during debugging, which - * may be useful for performance testing. - */ -const DISABLE_ANNOUNCEMENTS = false; - const CLDR_ANNOUNCE_DEBUG = false; const ANNOUNCE_REFRESH_SECONDS = 60; // one minute @@ -38,6 +32,16 @@ const MOST_RECENT_ID_UNKNOWN = -1; // must be less than zero */ let alreadyGotId = MOST_RECENT_ID_UNKNOWN; +/** + * Ordinarily announcements are enabled. They may be temporarily disabled during + * critical operations such as VXML generation, or for debugging. + */ +let announcementsEnabled = true; + +function enableAnnouncements(enable) { + announcementsEnabled = Boolean(enable); +} + /** * Get the number of unread announcements, to display in the main menu * @@ -60,7 +64,7 @@ async function getUnreadCount(setUnreadCount) { * we're only getting the number of unread announcements to display in the main header */ async function refresh(viewCallbackSetData, viewCallbackSetCounts) { - if (DISABLE_ANNOUNCEMENTS) { + if (!announcementsEnabled) { return; } if (viewCallbackSetData) { @@ -185,6 +189,7 @@ export { canAnnounce, canChooseAllOrgs, compose, + enableAnnouncements, getUnreadCount, refresh, resetSchedule, diff --git a/tools/cldr-apps/js/src/esm/cldrGenerateVxml.mjs b/tools/cldr-apps/js/src/esm/cldrGenerateVxml.mjs new file mode 100644 index 00000000000..24f20c3b37a --- /dev/null +++ b/tools/cldr-apps/js/src/esm/cldrGenerateVxml.mjs @@ -0,0 +1,88 @@ +/* + * cldrGenerateVxml: for Survey Tool feature "Generate VXML". The display logic is in GenerateVxml.vue. + */ +import * as cldrAjax from "./cldrAjax.mjs"; +import * as cldrAnnounce from "./cldrAnnounce.mjs"; +import * as cldrNotify from "./cldrNotify.mjs"; +import * as cldrStatus from "./cldrStatus.mjs"; + +const SECONDS_IN_MS = 1000; + +const NORMAL_RETRY = 10 * SECONDS_IN_MS; // "Normal" retry: starting or about to start + +const VXML_URL = "api/vxml"; + +// These must match the back end; used in requests +class LoadingPolicy { + static START = "START"; // start generating vxml + static CONTINUE = "CONTINUE"; // continue generating vxml + static STOP = "STOP"; // stop (cancel) generating vxml +} + +// These must match the back end; used in responses +class Status { + static INIT = "INIT"; // before making a request (back end does not have INIT) + static WAITING = "WAITING"; // waiting on other users/tasks + static PROCESSING = "PROCESSING"; // in progress + static READY = "READY"; // finished successfully + static STOPPED = "STOPPED"; // due to error or cancellation (LoadingPolicy.STOP) +} + +let canGenerate = false; + +let callbackToSetData = null; + +function canGenerateVxml() { + return canGenerate; +} + +function viewMounted(setData) { + callbackToSetData = setData; + const perm = cldrStatus.getPermissions(); + canGenerate = Boolean(perm?.userIsAdmin); +} + +function start() { + // Disable announcements during VXML generation to reduce risk of interference + cldrAnnounce.enableAnnouncements(false); + requestVxml(LoadingPolicy.START); +} + +function fetchStatus() { + if (!canGenerate || "generate_vxml" !== cldrStatus.getCurrentSpecial()) { + canGenerate = false; + } else if (canGenerate) { + requestVxml(LoadingPolicy.CONTINUE); + } +} + +function stop() { + requestVxml(LoadingPolicy.STOP); +} + +function requestVxml(loadingPolicy) { + const args = { loadingPolicy: loadingPolicy }; + const init = cldrAjax.makePostData(args); + cldrAjax + .doFetch(VXML_URL, init) + .then(cldrAjax.handleFetchErrors) + .then((r) => r.json()) + .then(setVxmlData) + .catch((e) => { + cldrNotify.exception(e, "generating VXML"); + }); +} + +function setVxmlData(data) { + if (!callbackToSetData) { + return; + } + callbackToSetData(data); + if (data.status === Status.WAITING || data.status === Status.PROCESSING) { + window.setTimeout(fetchStatus.bind(this), NORMAL_RETRY); + } else if (data.status === Status.READY || data.status === Status.STOPPED) { + cldrAnnounce.enableAnnouncements(true); // restore + } +} + +export { Status, canGenerateVxml, start, stop, viewMounted }; diff --git a/tools/cldr-apps/js/src/esm/cldrText.mjs b/tools/cldr-apps/js/src/esm/cldrText.mjs index 08fdf0535ef..d3991685e86 100644 --- a/tools/cldr-apps/js/src/esm/cldrText.mjs +++ b/tools/cldr-apps/js/src/esm/cldrText.mjs @@ -497,6 +497,7 @@ const strings = { special_forum: "Forum Posts", special_forum_participation: "Forum Participation", special_general: "General Info", + special_generate_vxml: "Generate VXML", special_list_emails: "List Email Addresses", special_list_users: "List Users", special_locales: "Locale List", diff --git a/tools/cldr-apps/js/src/esm/cldrVueMap.mjs b/tools/cldr-apps/js/src/esm/cldrVueMap.mjs index 875d7e8c051..7f396abdc74 100644 --- a/tools/cldr-apps/js/src/esm/cldrVueMap.mjs +++ b/tools/cldr-apps/js/src/esm/cldrVueMap.mjs @@ -1,11 +1,10 @@ -import * as cldrLoad from "./cldrLoad.mjs"; - import AboutPanel from "../views/AboutPanel.vue"; import AnnouncePanel from "../views/AnnouncePanel.vue"; import AddUser from "../views/AddUser.vue"; import AutoImport from "../views/AutoImport.vue"; import DowngradedVotes from "../views/DowngradedVotes.vue"; import GeneralInfo from "../views/GeneralInfo.vue"; +import GenerateVxml from "../views/GenerateVxml.vue"; import LockAccount from "../views/LockAccount.vue"; import LookUp from "../views/LookUp.vue"; import MainMenu from "../views/MainMenu.vue"; @@ -27,6 +26,7 @@ const specialToComponentMap = { auto_import: AutoImport, downgraded: DowngradedVotes, general: GeneralInfo, // see cldrLoad.GENERAL_SPECIAL + generate_vxml: GenerateVxml, lock_account: LockAccount, lookup: LookUp, menu: MainMenu, diff --git a/tools/cldr-apps/js/src/views/GenerateVxml.vue b/tools/cldr-apps/js/src/views/GenerateVxml.vue new file mode 100644 index 00000000000..9f0c060e4e0 --- /dev/null +++ b/tools/cldr-apps/js/src/views/GenerateVxml.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/tools/cldr-apps/js/src/views/MainMenu.vue b/tools/cldr-apps/js/src/views/MainMenu.vue index dc51b6d3b51..1acbb88629a 100644 --- a/tools/cldr-apps/js/src/views/MainMenu.vue +++ b/tools/cldr-apps/js/src/views/MainMenu.vue @@ -2,6 +2,7 @@