Skip to content

Commit

Permalink
CDPD-68772: [editor] Move the SQL Syntax Dropdown from mako to js to …
Browse files Browse the repository at this point in the history
…get rid of inline script (#3653)

No code changes other than linting and some small clean-up.

(cherry picked from commit b6b2ecc)
(cherry picked from commit 273e39e0c106e74828691887209dce1c1d6b983b)
Change-Id: Ie0c07a005df31ab5ee015deb3e7a734c753435c7
(cherry picked from commit 6372faf1d50990464f42cf0c47fc78edb3064ea6)
  • Loading branch information
JohanAhlen authored and Athithyaa Selvam committed Apr 17, 2024
1 parent 220f138 commit 08d2e44
Show file tree
Hide file tree
Showing 6 changed files with 253 additions and 135 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ko.syntaxDropdown.js should match snapshot 1`] = `
"<html><head></head><body><div id=\\"sqlSyntaxDropdown\\" data-bind=\\"component: { name: 'sql-syntax-dropdown', params: $data }\\">
<div class=\\"hue-syntax-drop-down\\" data-bind=\\"
style: {
'left': left() + 'px',
'top': top() + 'px'
},
component: {
name: 'hue-drop-down',
params: {
value: selected,
entries: expected,
foreachVisible: false,
searchable: false,
showOnInit: true,
menuOnly: true
}
}
\\" style=\\"left: 10px; top: 20px;\\">
<!-- ko if: !menuOnly && (!dropDownVisible() || !searchable) --><!-- /ko -->
<!-- ko if: !menuOnly && (dropDownVisible() && searchable) --><!-- /ko -->
<div class=\\"hue-drop-down-container open\\" data-bind=\\"css: { 'open' : dropDownVisible, 'hue-drop-down-fixed': fixedPosition, 'hue-drop-down-container-searchable': searchable }, dropDownKeyUp: { onEsc: onEsc, onEnter: onEnter, dropDownVisible: dropDownVisible }\\">
<div style=\\"overflow-y: auto;\\" class=\\"dropdown-menu\\" data-bind=\\"visible: filteredEntries().length > 0\\">
<!-- ko if: foreachVisible --><!-- /ko -->
<!-- ko ifnot: foreachVisible -->
<ul class=\\"hue-inner-drop-down\\" data-bind=\\"foreach: filteredEntries\\">
<!-- ko if: typeof $data.divider !== 'undefined' && $data.divider --><!-- /ko -->
<!-- ko if: typeof $data.divider === 'undefined' || !$data.divider -->
<li><a href=\\"javascript:void(0)\\" data-bind=\\"text: $data &amp;&amp; typeof $data[$parent.labelAttribute] !== 'undefined' ? $data[$parent.labelAttribute] : $data, click: function () { let previous = $parent.value(); $parent.value($data); $parent.onSelect($data, previous); }\\">foo</a></li>
<!-- /ko -->
<!-- ko if: typeof $data.divider !== 'undefined' && $data.divider -->
<li class=\\"divider\\"></li>
<!-- /ko -->
<!-- ko if: typeof $data.divider === 'undefined' || !$data.divider --><!-- /ko -->
<!-- ko if: typeof $data.divider !== 'undefined' && $data.divider --><!-- /ko -->
<!-- ko if: typeof $data.divider === 'undefined' || !$data.divider -->
<li><a href=\\"javascript:void(0)\\" data-bind=\\"text: $data &amp;&amp; typeof $data[$parent.labelAttribute] !== 'undefined' ? $data[$parent.labelAttribute] : $data, click: function () { let previous = $parent.value(); $parent.value($data); $parent.onSelect($data, previous); }\\">Ignore this type of error</a></li>
<!-- /ko -->
</ul>
<!-- /ko -->
</div>
</div>
</div>
</div></body></html>"
`;
exports[`ko.syntaxDropdown.js should render component on show event 1`] = `"<html><head></head><body><div id=\\"sqlSyntaxDropdown\\" data-bind=\\"component: { name: 'sql-syntax-dropdown', params: $data }\\"></div></body></html>"`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// Licensed to Cloudera, Inc. under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. Cloudera, Inc. 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.

import * as ko from 'knockout';
import $ from 'jquery';

import 'ko/components/ko.dropDown';
import componentUtils from 'ko/components/componentUtils';
import DisposableComponent from 'ko/components/DisposableComponent';
import huePubSub from 'utils/huePubSub';
import I18n from 'utils/i18n';
import { hueLocalStorage } from 'utils/storageUtils';

export const SYNTAX_DROPDOWN_COMPONENT = 'sql-syntax-dropdown';
export const SYNTAX_DROPDOWN_ID = 'sqlSyntaxDropdown';
export const SHOW_EVENT = 'sql.syntax.dropdown.show';
export const SHOWN_EVENT = 'sql.syntax.dropdown.shown';
export const HIDE_EVENT = 'sql.syntax.dropdown.hide';

// prettier-ignore
const TEMPLATE = `
<div class="hue-syntax-drop-down" data-bind="
style: {
'left': left() + 'px',
'top': top() + 'px'
},
component: {
name: 'hue-drop-down',
params: {
value: selected,
entries: expected,
foreachVisible: false,
searchable: false,
showOnInit: true,
menuOnly: true
}
}
"></div>
`;

const hideSyntaxDropdown = () => {
const $sqlSyntaxDropdown = $(`#${SYNTAX_DROPDOWN_ID}`);
if ($sqlSyntaxDropdown.length) {
ko.cleanNode($sqlSyntaxDropdown[0]);
$sqlSyntaxDropdown.remove();
$(document).off('click', hideOnClickOutside);
}
};

const hideOnClickOutside = event => {
const $modal = $('.modal');
if (
$.contains(document, event.target) &&
!$.contains($(`#${SYNTAX_DROPDOWN_ID}`)[0], event.target) &&
($modal[0].length === 0 || !$.contains($modal[0], event.target))
) {
hideSyntaxDropdown();
}
};

class SqlSyntaxDropdownViewModel extends DisposableComponent {
constructor(params) {
super();

this.selected = ko.observable();

const expected = params.data.expected.map(expected => expected.text);
// TODO: Allow suppression of unknown columns etc.
if (params.data.ruleId) {
if (expected.length > 0) {
expected.push({
divider: true
});
}
expected.push({
label: I18n('Ignore this type of error'),
suppressRule: params.data.ruleId.toString() + params.data.text.toLowerCase()
});
}
this.expected = ko.observableArray(expected);

const selectedSub = this.selected.subscribe(newValue => {
if (typeof newValue.suppressRule !== 'undefined') {
const suppressedRules = hueLocalStorage('hue.syntax.checker.suppressedRules') || {};
suppressedRules[newValue.suppressRule] = true;
hueLocalStorage('hue.syntax.checker.suppressedRules', suppressedRules);
huePubSub.publish('editor.refresh.statement.locations', params.editorId);
} else {
params.editor.session.replace(params.range, newValue);
}
hideSyntaxDropdown();
});

this.addDisposalCallback(() => {
selectedSub.dispose();
});

this.left = ko.observable(params.source.left);
this.top = ko.observable(params.source.bottom);

const closeOnEsc = e => {
if (e.keyCode === 27) {
hideSyntaxDropdown();
}
};

$(document).on('keyup', closeOnEsc);

this.addDisposalCallback(() => {
$(document).off('keyup', closeOnEsc);
});

window.setTimeout(() => {
$(document).on('click', hideOnClickOutside);
}, 0);

this.addDisposalCallback(() => {
$(document).off('click', hideOnClickOutside);
});
}
}

componentUtils.registerComponent(SYNTAX_DROPDOWN_COMPONENT, SqlSyntaxDropdownViewModel, TEMPLATE);

huePubSub.subscribe(HIDE_EVENT, hideSyntaxDropdown);
huePubSub.subscribe(SHOW_EVENT, details => {
hideSyntaxDropdown();
const $sqlSyntaxDropdown = $(
`<div id="${SYNTAX_DROPDOWN_ID}" data-bind="component: { name: '${SYNTAX_DROPDOWN_COMPONENT}', params: $data }"></div>`
);
$('body').append($sqlSyntaxDropdown);
ko.applyBindings(details, $sqlSyntaxDropdown[0]);
huePubSub.publish(SHOWN_EVENT);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Licensed to Cloudera, Inc. under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. Cloudera, Inc. 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.

import { SHOW_EVENT, SHOWN_EVENT, SYNTAX_DROPDOWN_ID } from './ko.syntaxDropdown';
import huePubSub from 'utils/huePubSub';

describe('ko.syntaxDropdown.js', () => {
const publishShowEvent = () => {
huePubSub.publish(SHOW_EVENT, {
data: {
text: 'floo',
expected: [{ text: 'foo' }],
ruleId: 123
},
source: {
left: 10,
bottom: 20
}
});
};

it('should render component on show event', async () => {
expect(document.querySelectorAll(`#${SYNTAX_DROPDOWN_ID}`)).toHaveLength(0);

publishShowEvent();

expect(document.querySelectorAll(`#${SYNTAX_DROPDOWN_ID}`)).toHaveLength(1);
expect(window.document.documentElement.outerHTML).toMatchSnapshot();
});

it('should match snapshot', async () => {
const shownPromise = new Promise(resolve => {
huePubSub.subscribeOnce(SHOWN_EVENT, resolve);
});
publishShowEvent();

await shownPromise;

expect(window.document.documentElement.outerHTML).toMatchSnapshot();
});
});
1 change: 1 addition & 0 deletions desktop/core/src/desktop/js/apps/notebook/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import 'ext/jquery.hotkeys';
import 'jquery/plugins/jquery.hdfstree';

import NotebookViewModel from './NotebookViewModel';
import '../editor/components/ko.syntaxDropdown';
import {
ACTIVE_SNIPPET_CONNECTOR_CHANGED_EVENT,
IGNORE_NEXT_UNLOAD_EVENT
Expand Down
132 changes: 0 additions & 132 deletions desktop/core/src/desktop/templates/sql_syntax_dropdown.mako

This file was deleted.

Loading

0 comments on commit 08d2e44

Please sign in to comment.