This is an automated email from the ASF dual-hosted git repository.
bbovenzi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 6a5b22df0e Replaced bootstrap-typeahead with jquery-ui (#40744)
6a5b22df0e is described below
commit 6a5b22df0e2f399afc8e952165fd005b81101e08
Author: SAI GANESH S <[email protected]>
AuthorDate: Tue Nov 5 22:19:36 2024 +0530
Replaced bootstrap-typeahead with jquery-ui (#40744)
* Replaced Bootstrap-typeahead with jquery-ui for typeahead functionality
for searching other timezones, present at the navbar.
* Replace bootstrap-typeahead with jquery-ui in dags.js
* Removed bootstrap3-typeahead package
* Added custom css for typeahead
* Fixed linting issues in dags.js
* fixed linting issue in main.css
---
airflow/www/package.json | 2 +-
airflow/www/static/css/main.css | 18 +++++++
airflow/www/static/js/dags.js | 79 +++++++++++++++++++---------
airflow/www/static/js/main.js | 91 +++++++++++++++++++++++----------
airflow/www/templates/airflow/main.html | 4 +-
airflow/www/webpack.config.js | 9 +++-
airflow/www/yarn.lock | 19 ++++---
7 files changed, 159 insertions(+), 63 deletions(-)
diff --git a/airflow/www/package.json b/airflow/www/package.json
index 79991b3bb9..638e782139 100644
--- a/airflow/www/package.json
+++ b/airflow/www/package.json
@@ -109,7 +109,6 @@
"@visx/shape": "^2.12.2",
"ansi_up": "^6.0.2",
"axios": "^1.7.4",
- "bootstrap-3-typeahead": "^4.0.2",
"camelcase-keys": "^7.0.0",
"chakra-react-select": "^4.0.0",
"codemirror": "^5.59.1",
@@ -124,6 +123,7 @@
"eonasdan-bootstrap-datetimepicker": "^4.17.47",
"framer-motion": "^6.0.0",
"jquery": ">=3.5.0",
+ "jquery-ui": "1.13.3",
"jshint": "^2.13.4",
"json-to-pretty-yaml": "^1.2.2",
"lodash": "^4.17.21",
diff --git a/airflow/www/static/css/main.css b/airflow/www/static/css/main.css
index 0a2810c52e..9d9ed1e9fc 100644
--- a/airflow/www/static/css/main.css
+++ b/airflow/www/static/css/main.css
@@ -288,10 +288,28 @@ label[for="timezone-other"],
font-weight: normal;
}
+#timezone-menu {
+ overflow-x: hidden;
+}
+
#timezone-menu ul.typeahead.dropdown-menu {
max-height: 200px;
overflow-y: auto;
overflow-x: hidden;
+ border: none;
+ left: 0 !important;
+}
+
+#timezone-menu .dropdown-item {
+ padding: 3px 20px;
+}
+
+.ui-menu .ui-menu-item a.ui-state-focus,
+.ui-menu .ui-menu-item a.ui-state-active {
+ border: 1px solid white;
+ border-left: 1px solid #ccc;
+ background: #f6f6f6;
+ color: #454545;
}
/* depending on the version of FAB in use, we may have a style conflict */
diff --git a/airflow/www/static/js/dags.js b/airflow/www/static/js/dags.js
index 9228ca630b..66ea124487 100644
--- a/airflow/www/static/js/dags.js
+++ b/airflow/www/static/js/dags.js
@@ -116,31 +116,60 @@ $.each($("[id^=toggle]"), function toggleId() {
});
});
-$(".typeahead").typeahead({
- source(query, callback) {
- return $.ajax(autocompleteUrl, {
- data: {
- query: encodeURIComponent(query),
- status: statusFilter,
- },
- success: callback,
- });
- },
- displayText(value) {
- return value.dag_display_name || value.name;
- },
- autoSelect: false,
- afterSelect(value) {
- const query = new URLSearchParams(window.location.search);
- query.set("search", value.name);
- if (value.type === "owner") {
- window.location = `${DAGS_INDEX}?${query}`;
- }
- if (value.type === "dag") {
- window.location = `${gridUrl.replace("__DAG_ID__",
value.name)}?${query}`;
- }
- },
-});
+// eslint-disable-next-line no-underscore-dangle
+$(".typeahead")
+ .autocomplete({
+ autoFocus: true,
+ source: (request, response) => {
+ $.ajax({
+ url: autocompleteUrl,
+ data: {
+ query: encodeURIComponent(request.term),
+ status: statusFilter,
+ },
+ success: (data) => {
+ response(data);
+ },
+ });
+ },
+ focus: (event) => {
+ // Prevents value from being inserted on focus
+ event.preventDefault();
+ },
+ select: (_, ui) => {
+ const value = ui.item;
+ const query = new URLSearchParams(window.location.search);
+ query.set("search", value.name);
+ if (value.type === "owner") {
+ window.location = `${DAGS_INDEX}?${query}`;
+ }
+ if (value.type === "dag") {
+ window.location = `${gridUrl.replace(
+ "__DAG_ID__",
+ value.name
+ )}?${query}`;
+ }
+ },
+ appendTo: "#search_form > div",
+ })
+ .data("ui-autocomplete")._renderMenu = function (ul, items) {
+ ul.addClass("typeahead dropdown-menu");
+ $.each(items, function (_, item) {
+ // eslint-disable-next-line no-underscore-dangle
+ this._renderItemData(ul, item);
+ });
+};
+
+// eslint-disable-next-line no-underscore-dangle
+$.ui.autocomplete.prototype._renderItem = function (ul, item) {
+ return $("<li>")
+ .append(
+ $("<a>")
+ .addClass("dropdown-item")
+ .text(item.dag_display_name || item.name)
+ )
+ .appendTo(ul);
+};
$("#search_form").on("reset", () => {
const query = new URLSearchParams(window.location.search);
diff --git a/airflow/www/static/js/main.js b/airflow/www/static/js/main.js
index 95861ea6c1..c60827c7a3 100644
--- a/airflow/www/static/js/main.js
+++ b/airflow/www/static/js/main.js
@@ -180,35 +180,70 @@ function initializeUITimezone() {
$("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 <form>
- setTimeout(() => {
- document.activeElement.blur();
- // Bug in typeahed, it thinks it's still shown!
- this.shown = false;
- this.focused = false;
- }, 1);
- },
+ // Prepare the data source
+ const timezoneData = moment.tz.names().map((tzName) => {
+ const category = tzName.split("/", 1)[0];
+ return { category, label: tzName.replace("_", " "), value: tzName };
});
+
+ // Create a custom filter function to include categories
+ function filterByCategory(array, term) {
+ const matcher = new RegExp($.ui.autocomplete.escapeRegex(term), "i");
+ return $.grep(
+ array,
+ (item) => matcher.test(item.label) || matcher.test(item.category)
+ );
+ }
+
+ // Initialize jQuery UI Autocomplete
+ // eslint-disable-next-line no-underscore-dangle
+ $("#timezone-other")
+ .autocomplete({
+ source: (request, response) => {
+ const results = filterByCategory(timezoneData, request.term);
+ response(results);
+ },
+ appendTo: "#timezone-menu > li:nth-child(6) > form",
+ focus: (event, ui) => {
+ // Prevent the value from being inserted on focus
+ event.preventDefault();
+ $(this).val(ui.item.label);
+ },
+ select: (event, ui) => {
+ // Clear it for next time we open the pop-up
+ $(this).val("");
+
+ setManualTimezone(ui.item.value);
+ changeDisplayedTimezone(ui.item.value);
+
+ return false;
+ },
+ })
+ .data("ui-autocomplete")._renderItem = function (ul, item) {
+ const $li = $("<li>");
+ $li.append(
+ `<a class='dropdown-item' href='#' role='option'>${item.label}</a>`
+ );
+ return $li.appendTo(ul);
+ };
+
+ // Custom rendering function to include category headers
+ // eslint-disable-next-line no-underscore-dangle
+ $.ui.autocomplete.prototype._renderMenu = function (ul, items) {
+ let currentCategory = "";
+ ul.addClass("typeahead dropdown-menu");
+ ul.attr("role", "listbox");
+ $.each(items, (index, item) => {
+ if (item.category !== currentCategory) {
+ ul.append(
+ `<li class='ui-autocomplete-category
dropdown-header'>${item.category}</li>`
+ );
+ currentCategory = item.category;
+ }
+ // eslint-disable-next-line no-underscore-dangle
+ this._renderItemData(ul, item);
+ });
+ };
}
function filterOpSelected(ele) {
diff --git a/airflow/www/templates/airflow/main.html
b/airflow/www/templates/airflow/main.html
index 008418d7e5..3842d3602d 100644
--- a/airflow/www/templates/airflow/main.html
+++ b/airflow/www/templates/airflow/main.html
@@ -46,6 +46,7 @@
<link rel="stylesheet" type="text/css" href="{{ url_for_asset('main.css')
}}">
<link rel="stylesheet" type="text/css" href="{{
url_for_asset('loadingDots.css') }}">
<link rel="stylesheet" type="text/css" href="{{
url_for_asset('bootstrap-datetimepicker.min.css') }}">
+ <link rel="stylesheet" type="text/css" href="{{
url_for_asset('jquery-ui.min.css') }}">
<style type="text/css">
{% for state, state_color in state_color_mapping.items() %}
span.{{state}} {
@@ -133,9 +134,10 @@
$('time[title]').tooltip();
</script>
<script src="{{ url_for_asset('moment.js') }}"></script>
+ <script src="{{ url_for_asset('jquery-ui.min.js') }}"></script>
<script src="{{ url_for_asset('main.js') }}"></script>
<script src="{{ url_for_asset('bootstrap-datetimepicker.min.js')
}}"></script>
- <script src="{{ url_for_asset('bootstrap3-typeahead.min.js') }}"></script>
+
<script src="{{ url_for_asset('toggleTheme.js') }}"></script>
{% if analytics_tool is defined and analytics_tool %}
diff --git a/airflow/www/webpack.config.js b/airflow/www/webpack.config.js
index 633d9a6810..9d5800f783 100644
--- a/airflow/www/webpack.config.js
+++ b/airflow/www/webpack.config.js
@@ -211,12 +211,17 @@ const config = {
to: "d3-tip.js",
flatten: true,
},
+
{
- from: "node_modules/bootstrap-3-typeahead/*min.*",
+ from:
"node_modules/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css",
flatten: true,
},
{
- from:
"node_modules/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css",
+ from: "node_modules/jquery-ui/dist/jquery-ui.min.js",
+ flatten: true,
+ },
+ {
+ from: "node_modules/jquery-ui/dist/themes/base/jquery-ui.min.css",
flatten: true,
},
{
diff --git a/airflow/www/yarn.lock b/airflow/www/yarn.lock
index c8b9aaef5b..d1a8d93cdf 100644
--- a/airflow/www/yarn.lock
+++ b/airflow/www/yarn.lock
@@ -4441,11 +4441,6 @@ boolbase@^1.0.0:
resolved
"https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
-bootstrap-3-typeahead@^4.0.2:
- version "4.0.2"
- resolved
"https://registry.yarnpkg.com/bootstrap-3-typeahead/-/bootstrap-3-typeahead-4.0.2.tgz#cb1c969044856862096fc8c71cc21b3acbb50412"
- integrity sha1-yxyWkESFaGIJb8jHHMIbOsu1BBI=
-
bootstrap@^3.3:
version "3.4.1"
resolved
"https://registry.yarnpkg.com/bootstrap/-/bootstrap-3.4.1.tgz#c3a347d419e289ad11f4033e3c4132b87c081d72"
@@ -7991,11 +7986,23 @@ jest@^27.3.1:
import-local "^3.0.2"
jest-cli "^27.3.1"
-jquery@>=3.5.0, jquery@^3.5.1:
[email protected]:
+ version "1.13.3"
+ resolved
"https://registry.yarnpkg.com/jquery-ui/-/jquery-ui-1.13.3.tgz#d9f5292b2857fa1f2fdbbe8f2e66081664eb9bc5"
+ integrity
sha512-D2YJfswSJRh/B8M/zCowDpNFfwsDmtfnMPwjJTyvl+CBqzpYwQ+gFYIbUUlzijy/Qvoy30H1YhoSui4MNYpRwA==
+ dependencies:
+ jquery ">=1.8.0 <4.0.0"
+
+jquery@>=1.7, jquery@>=3.5.0, jquery@^3.5.1:
version "3.6.0"
resolved
"https://registry.yarnpkg.com/jquery/-/jquery-3.6.0.tgz#c72a09f15c1bdce142f49dbf1170bdf8adac2470"
integrity
sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==
+"jquery@>=1.8.0 <4.0.0":
+ version "3.7.1"
+ resolved
"https://registry.yarnpkg.com/jquery/-/jquery-3.7.1.tgz#083ef98927c9a6a74d05a6af02806566d16274de"
+ integrity
sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==
+
js-levenshtein@^1.1.6:
version "1.1.6"
resolved
"https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d"