Skip to content

Commit

Permalink
more JS cleanup. Package lock rebuild. Working email functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisclark committed Dec 20, 2023
1 parent 4641e4d commit d1b6965
Show file tree
Hide file tree
Showing 10 changed files with 198 additions and 254 deletions.
31 changes: 28 additions & 3 deletions explorer/static/js/src/explorer.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import cookie from 'cookiejs';
import List from 'list.js'

import 'floatthead'
import {getCsrfToken} from "./csrf";
import {toggleFavorite} from "./favorites";


function editorFromTextArea(textarea) {
Expand Down Expand Up @@ -108,9 +110,28 @@ export class ExplorerEditor {
}

formatSql() {
$.post("../format/", {sql: this.editor.getValue() }, function(data) {
this.editor.setValue(data.formatted);
}.bind(this));
let sqlText = this.editor.state.doc.toString();
let editor = this.editor;

$.ajax({
url: "../format/",
type: "POST",
headers: {
'X-CSRFToken': getCsrfToken()
},
data: {
sql: sqlText
},
success: function(data) {
editor.dispatch({
changes: {
from: 0,
to: editor.state.doc.length,
insert: data.formatted
}
})
}.bind(this)
});
}

showRows() {
Expand Down Expand Up @@ -147,6 +168,10 @@ export class ExplorerEditor {
}

bind() {
document.querySelectorAll('.query_favorite_toggle').forEach(function(element) {
element.addEventListener('click', toggleFavorite);
});

$("#show_schema_button").click(this.showSchema);
$("#hide_schema_button").click(this.hideSchema);

Expand Down
21 changes: 13 additions & 8 deletions explorer/static/js/src/favorites.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import $ from 'jquery';
import {getCsrfToken} from "./csrf";

export async function toggleFavorite() {
let queryId = $(this).data('id');
let favoriteUrl = $(this).data('url');
// Assuming this function is bound to an element, 'this' refers to that element
let queryId = this.dataset.id; // or this.getAttribute('data-id');
let favoriteUrl = this.dataset.url; // or this.getAttribute('data-url');

try {
let response = await fetch(favoriteUrl, {
Expand All @@ -17,12 +17,17 @@ export async function toggleFavorite() {

let data = await response.json();
let is_favorite = data.is_favorite;
let selector = '.query_favorite_toggle[data-id=' + queryId + ']';
let selector = `.query_favorite_toggle[data-id='${queryId}']`;
let element = document.querySelector(selector);

if (is_favorite) {
$(selector).removeClass("bi-heart").addClass("bi-heart-fill");
} else {
$(selector).removeClass("bi-heart-fill").addClass("bi-heart");
if (element) {
if (is_favorite) {
element.classList.remove("bi-heart");
element.classList.add("bi-heart-fill");
} else {
element.classList.remove("bi-heart-fill");
element.classList.add("bi-heart");
}
}
} catch (error) {
console.error('Error:', error);
Expand Down
73 changes: 7 additions & 66 deletions explorer/static/js/src/main.js
Original file line number Diff line number Diff line change
@@ -1,76 +1,17 @@
// Import all of Bootstrap's JS
import * as bootstrap from 'bootstrap'; // eslint-disable-line no-unused-vars

import {toggleFavorite} from "./favorites";
import {ExplorerEditor} from "./explorer"
import {setupList} from "./query-list"
import List from 'list.js'
import $ from "jquery";
import {getCsrfToken} from "./csrf";

import {setupQueryList} from "./query-list"
import {setupSchema} from "./schema";
// TODO add back in XLSX export support

const route_initializers = {
explorer_index: function() {
document.querySelectorAll('.query_favorite_toggle').forEach(function(element) {
element.addEventListener('click', toggleFavorite);
});
function SearchFocus() {
const searchElement = document.querySelector('.search');
if (searchElement) {
searchElement.focus();
}
}

let options = {
valueNames: [ 'name' ],
handlers: { 'updated': [SearchFocus] }
};
new List('queries', options);
setupList();
},
query_detail: function() {
document.querySelectorAll('.query_favorite_toggle').forEach(function(element) {
element.addEventListener('click', toggleFavorite);
});
new ExplorerEditor(queryId);
},
query_create: function() {
new ExplorerEditor('new');
},
explorer_playground: function() {
new ExplorerEditor('new');
},
explorer_schema: function() {
function SearchFocus() {
if (!$(window.parent.document.getElementById("schema_frame")).hasClass('no-autofocus')) {
$(".search").focus();
}
}
let options = {
valueNames: [ 'name', 'app' ],
handlers: { 'updated': [SearchFocus] }
};
new List('tables', options);

$('#collapse_all').click(function(){
$('.schema-table').hide();
});
$('#expand_all').click(function(){
$('.schema-table').show();
});
$('.schema-header').click(function(){
$(this).parent().find('.schema-table').toggle();
});
}
explorer_index: setupQueryList,
query_detail: () => new ExplorerEditor(queryId),
query_create: () => new ExplorerEditor('new'),
explorer_playground: () => new ExplorerEditor('new'),
explorer_schema: setupSchema
};

$.ajaxSetup({
beforeSend: function(xhr) {
xhr.setRequestHeader("X-CSRFToken", getCsrfToken());
}
});

document.addEventListener('DOMContentLoaded', function() {
route_initializers[clientRoute]();
});
120 changes: 71 additions & 49 deletions explorer/static/js/src/query-list.js
Original file line number Diff line number Diff line change
@@ -1,68 +1,90 @@
import $ from "jquery";
import List from "list.js";
import {getCsrfToken} from "./csrf";
import {toggleFavorite} from "./favorites";
import * as bootstrap from 'bootstrap'; // eslint-disable-line no-unused-vars

export function setupList() {
var $emailCsv = $('.email-csv');
function searchFocus() {
const searchElement = document.querySelector('.search');
if (searchElement) {
searchElement.focus();
}
}
export function setupQueryList() {

var isValidEmail = function (email) {
return /^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i.test(email);
document.querySelectorAll('.query_favorite_toggle').forEach(function (element) {
element.addEventListener('click', toggleFavorite);
});

let options = {
valueNames: ['name'],
handlers: {'updated': [searchFocus]}
};
new List('queries', options);

$emailCsv.each(function () {
var $this = $(this);
$this.popover({
html: true,
sanitize: false,
trigger: 'manual',
placement: 'left',
content:
'<form class="email-csv-form" action="' + $this.prop('href') + '">' +
'<div class="input-group">' +
'<input type="email" autofocus="true" name="email" class="form-control" placeholder="Email" />' +
'<span class="input-group-btn">' +
'<button type="submit" class="btn btn-primary">Send</button>' +
'</span>' +
'</div>' +
'</form>'
});
});
setUpEmailCsv();
}

$emailCsv.on('click', function (e) {
e.preventDefault();
var $this = $(this);
$emailCsv.not($this).popover('hide');
$this.popover('toggle');
});
function setUpEmailCsv() {
let $emailCsv = $('.email-csv');
let emailModal = new bootstrap.Modal('#emailCsvModal', {});
let curQueryEmailId = null;

$('body').on('submit', '.email-csv-form', function (e) {
e.preventDefault();
var url = this.action;
var $this = $(this);
var email = $this.find('[name=email]').val();
let isValidEmail = function (email) {
return /^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i.test(email);
};

let showEmailSuccess = () => {
const $msgSuccess = $('#email-success-msg');
const $msgAlert = $('#email-error-msg');
$msgSuccess.show();
$msgAlert.hide();
setTimeout(()=>emailModal.hide(), 2000);
}

let showEmailError = (msg) => {
const $msgSuccess = $('#email-success-msg');
const $msgAlert = $('#email-error-msg');
$msgAlert.html(msg);
$msgSuccess.hide();
$msgAlert.show();
}
let handleEmailCsvSubmit = function (e) {
let email = document.querySelector('#emailCsvInput').value;
let url = '/' + curQueryEmailId + '/email_csv?email=' + email;
if (isValidEmail(email)) {
$.ajax({
url: url,
type: 'POST',
headers: {
'X-CSRFToken': getCsrfToken()
},
data: {
email: $this.find('[name=email]').val()
email: email
},
success: function () {
var $el = $this.closest('td');
$el.find('.popover-content').html("Ok! The query results will be emailed to you shortly.");
var closeSoon = function () {
$el.find('.email-csv').popover('hide');
};
setTimeout(closeSoon, 2000);
success: showEmailSuccess,
error: (xhr, status, error) => {
showEmailError(error);
}
});
} else {
$this.tooltip({
title: 'Email is invalid',
trigger: 'manual'
});
$this.tooltip('show');
setTimeout(function () {
$this.tooltip('hide');
}, 3000);
showEmailError('Email is invalid');
}
}

document.querySelectorAll('#btnSubmitCsvEmail').forEach(function(element) {
element.addEventListener('click', handleEmailCsvSubmit);
});

$emailCsv.on('click', function (e) {
e.preventDefault();
curQueryEmailId = $(this).data('query-id');
emailModal.show();
});

const emailModalEl = document.getElementById('emailCsvModal')
emailModalEl.addEventListener('hidden.bs.modal', event => {
$('#email-success-msg').hide();
$('#email-error-msg').hide();
})
}
41 changes: 41 additions & 0 deletions explorer/static/js/src/schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import List from "list.js";

function searchFocus() {
let schemaFrame = window.parent.document.getElementById("schema_frame");
if (!schemaFrame.classList.contains('no-autofocus')) {
document.querySelector(".search").focus();
}
}

export function setupSchema() {

let options = {
valueNames: ['name', 'app'],
handlers: {'updated': [searchFocus]}
};

new List('tables', options);

document.getElementById('collapse_all').addEventListener('click', function () {
document.querySelectorAll('.schema-table').forEach(function (element) {
element.style.display = 'none';
});
});

document.getElementById('expand_all').addEventListener('click', function () {
document.querySelectorAll('.schema-table').forEach(function (element) {
element.style.display = '';
});
});

document.querySelectorAll('.schema-header').forEach(function (header) {
header.addEventListener('click', function () {
let schemaTable = this.parentElement.querySelector('.schema-table');
if (schemaTable.style.display === 'none' || schemaTable.style.display === '') {
schemaTable.style.display = 'block';
} else {
schemaTable.style.display = 'none';
}
});
});
}
7 changes: 2 additions & 5 deletions explorer/templates/explorer/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,16 @@
</li>
<li class="nav-item">
<a class="nav-link{% if not query and view_name == 'explorer_playground' %} active{% endif %}"
href="{% url 'explorer_playground' %}">{% trans "Playground" %}</a>
href="{% url 'explorer_playground' %}"><i class="small me-1 bi-code-square"></i>{% trans "Playground" %}</a>
</li>
{% endif %}
{% if query %}
<li class="nav-item"><a class="nav-link active" href="">{% trans "Query Detail" %}</a></li>
{% endif %}
<li class="nav-item">
<a class="nav-link{% if not query and view_name == 'explorer_logs' %} active{% endif %}"
href="{% url 'explorer_logs' %}">{% trans "Logs" %}</a>
</li>
<li class="nav-item">
<a class="nav-link{% if not query and view_name == 'query_favorites' %} active{% endif %}"
href="{% url 'query_favorites' %}">{% trans "Favorite Queries" %}</a>
href="{% url 'query_favorites' %}"><i class="small me-1 bi-heart"></i>{% trans "Favorites" %}</a>
</li>
</ul>
</header>
Expand Down
4 changes: 2 additions & 2 deletions explorer/templates/explorer/query_favorites.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
{% load i18n %}

{% block sql_explorer_content %}
<h2>{% trans "Favorite Queries" %}</h2>
<div>
<div class="container">
<h2>{% trans "Favorite Queries" %}</h2>
<table class="table table-striped query-list">
<thead>
<tr>
Expand Down
Loading

0 comments on commit d1b6965

Please sign in to comment.