~sircmpwn/sr.ht-dev

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
4 2

[PATCH todo.sr.ht 0/3] Reuse username autocomplete

Details
Message ID
<20190811121203.11370-1-ivan@habunek.com>
DKIM signature
pass
Download raw message
Extract relevant code and reuse it on the tracker access page.

Ivan Habunek (3):
  Extract user autocomplete to enable reuse
  Extract getting recent users
  Add username completion to tracker access page

 todosrht/blueprints/ticket.py          | 16 ++----
 todosrht/blueprints/tracker.py         |  8 +--
 todosrht/templates/autocomplete.js     | 72 ++++++++++++++++++++++++++
 todosrht/templates/ticket.html         | 72 +-------------------------
 todosrht/templates/tracker-access.html | 22 ++++++++
 todosrht/trackers.py                   | 15 ++++++
 6 files changed, 119 insertions(+), 86 deletions(-)
 create mode 100644 todosrht/templates/autocomplete.js
 create mode 100644 todosrht/trackers.py

-- 
2.20.1

[PATCH todo.sr.ht 1/3] Extract user autocomplete to enable reuse

Details
Message ID
<20190811121203.11370-2-ivan@habunek.com>
In-Reply-To
<20190811121203.11370-1-ivan@habunek.com> (view parent)
DKIM signature
pass
Download raw message
Patch: +73 -71
---
 todosrht/templates/autocomplete.js | 72 ++++++++++++++++++++++++++++++
 todosrht/templates/ticket.html     | 72 +-----------------------------
 2 files changed, 73 insertions(+), 71 deletions(-)
 create mode 100644 todosrht/templates/autocomplete.js

diff --git a/todosrht/templates/autocomplete.js b/todosrht/templates/autocomplete.js
new file mode 100644
index 0000000..f16364b
--- /dev/null
+++ b/todosrht/templates/autocomplete.js
@@ -0,0 +1,72 @@
function UserAutoComplete(input, list) {
  this.input = input;
  this.list = list;
  this.lastQuery = input.value;

  // Settings
  this.delay = 250;
  this.minQueryLength = 3;

  this.onLoad = function(event) {
    const response = event.target;
    if (response.status == 200) {
      const data = JSON.parse(response.responseText);

      this.list.innerHTML = '';
      data.results.forEach(function (username) {
        const option = document.createElement('option');
        option.value = username;
        this.list.appendChild(option);
      }.bind(this));
    }
  }.bind(this)

  this.sendRequest = function(query) {
    const search = encodeURIComponent(query);
    const request = new XMLHttpRequest();
    request.onload = this.onLoad;
    request.open("GET", "/usernames/?q=" + search);
    request.send();
  }

  this.search = function() {
    const query = this.input.value
    if (query == "" || query == "~") {
      this.list.innerHTML = "";
      this.lastQuery = "";
      return;
    }

    const notRepeated = query !== this.lastQuery;
    const notTooShort = query.length >= this.minQueryLength;
    if (notRepeated && notTooShort) {
      this.sendRequest(query);
      this.lastQuery = query;
    }
  }.bind(this)

  this.debounce = function(fn, delay) {
    let timeout = null;
    return function() {
      if (timeout) {
        clearTimeout(timeout);
      }
      timeout = setTimeout(fn, delay);
    }
  }

  this.register = function() {
    this.input.addEventListener("input",
        this.debounce(this.search, this.delay));

    // Prevent search being triggered when an user is selected from the datalist
    // 'select' works in Firefox, 'change' works in Chrome
    this.input.addEventListener("select", function(e) {
      this.lastQuery = e.target.value;
    }.bind(this));

    this.input.addEventListener("change", function(e) {
      this.lastQuery = e.target.value;
    }.bind(this));
  }
}
diff --git a/todosrht/templates/ticket.html b/todosrht/templates/ticket.html
index 4abf522..0efdf36 100644
--- a/todosrht/templates/ticket.html
+++ b/todosrht/templates/ticket.html
@@ -395,78 +395,8 @@

{% block scripts %}
<script type="text/javascript">
function UserAutoComplete(input, list) {
  this.input = input;
  this.list = list;
  this.lastQuery = input.value;

  // Settings
  this.delay = 250;
  this.minQueryLength = 3;

  this.onLoad = function(event) {
    const response = event.target;
    if (response.status == 200) {
      const data = JSON.parse(response.responseText);

      this.list.innerHTML = '';
      data.results.forEach(function (username) {
        const option = document.createElement('option');
        option.value = username;
        this.list.appendChild(option);
      }.bind(this));
    }
  }.bind(this)

  this.sendRequest = function(query) {
    const search = encodeURIComponent(query);
    const request = new XMLHttpRequest();
    request.onload = this.onLoad;
    request.open("GET", "/usernames/?q=" + search);
    request.send();
  }

  this.search = function() {
    const query = this.input.value
    if (query == "" || query == "~") {
      this.list.innerHTML = "";
      this.lastQuery = "";
      return;
    }

    const notRepeated = query !== this.lastQuery;
    const notTooShort = query.length >= this.minQueryLength;
    if (notRepeated && notTooShort) {
      this.sendRequest(query);
      this.lastQuery = query;
    }
  }.bind(this)

  this.debounce = function(fn, delay) {
    let timeout = null;
    return function() {
      if (timeout) {
        clearTimeout(timeout);
      }
      timeout = setTimeout(fn, delay);
    }
  }

  this.register = function() {
    this.input.addEventListener("input",
        this.debounce(this.search, this.delay));

    // Prevent search being triggered when an user is selected from the datalist
    // 'select' works in Firefox, 'change' works in Chrome
    this.input.addEventListener("select", function(e) {
      this.lastQuery = e.target.value;
    }.bind(this));

    this.input.addEventListener("change", function(e) {
      this.lastQuery = e.target.value;
    }.bind(this));
  }
}
{% include "autocomplete.js" %}

(function() {
  const input = document.getElementById("assignee-input");
-- 
2.20.1

[PATCH todo.sr.ht 2/3] Extract getting recent users

Details
Message ID
<20190811121203.11370-3-ivan@habunek.com>
In-Reply-To
<20190811121203.11370-1-ivan@habunek.com> (view parent)
DKIM signature
pass
Download raw message
Patch: +19 -12
---
 todosrht/blueprints/ticket.py | 16 ++++------------
 todosrht/trackers.py          | 15 +++++++++++++++
 2 files changed, 19 insertions(+), 12 deletions(-)
 create mode 100644 todosrht/trackers.py

diff --git a/todosrht/blueprints/ticket.py b/todosrht/blueprints/ticket.py
index 2e4f6b5..4e9ea71 100644
--- a/todosrht/blueprints/ticket.py
+++ b/todosrht/blueprints/ticket.py
@@ -8,13 +8,14 @@ from todosrht.access import get_tracker, get_ticket
from todosrht.filters import invalidate_markup_cache
from todosrht.search import find_usernames
from todosrht.tickets import add_comment, mark_seen, assign, unassign
from todosrht.types import Event, EventType
from todosrht.types import Label, Ticket, TicketLabel
from todosrht.trackers import get_recent_users
from todosrht.types import Event, EventType, Label, TicketLabel
from todosrht.types import TicketAccess, TicketResolution
from todosrht.types import TicketSubscription, User
from todosrht.urls import ticket_url
from todosrht.webhooks import TrackerWebhook, TicketWebhook


ticket = Blueprint("ticket", __name__)

def get_ticket_context(ticket, tracker, access):
@@ -28,15 +29,6 @@ def get_ticket_context(ticket, tracker, access):
        ticket_sub = TicketSubscription.query.filter_by(
            ticket=ticket, tracker=None, user=current_user).one_or_none()

    # Find users who recently interacted with this tracker
    recent_user_events = (db.session.query(Event.id, User.username)
        .join(User, User.id == Event.user_id)
        .join(Ticket, Ticket.id == Event.ticket_id)
        .filter(Ticket.tracker_id == tracker.id)
        .order_by(Event.created.desc())
        .limit(20))
    recent_users = {e[1] for e in recent_user_events}

    return {
        "tracker": tracker,
        "ticket": ticket,
@@ -46,7 +38,7 @@ def get_ticket_context(ticket, tracker, access):
        "access": access,
        "tracker_sub": tracker_sub,
        "ticket_sub": ticket_sub,
        "recent_users": recent_users,
        "recent_users": get_recent_users(tracker),
    }

@ticket.route("/<owner>/<name>/<int:ticket_id>")
diff --git a/todosrht/trackers.py b/todosrht/trackers.py
new file mode 100644
index 0000000..5ebdf60
--- /dev/null
+++ b/todosrht/trackers.py
@@ -0,0 +1,15 @@
from srht.database import db
from todosrht.types import Event, Ticket, User


def get_recent_users(tracker, limit=20):
    """Find users who recently interacted with a tracker."""

    recent_user_events = (db.session.query(Event.id, User.username)
        .join(User, User.id == Event.user_id)
        .join(Ticket, Ticket.id == Event.ticket_id)
        .filter(Ticket.tracker_id == tracker.id)
        .order_by(Event.created.desc())
        .limit(20))

    return {e[1] for e in recent_user_events}
-- 
2.20.1

[PATCH todo.sr.ht 3/3] Add username completion to tracker access page

Details
Message ID
<20190811121203.11370-4-ivan@habunek.com>
In-Reply-To
<20190811121203.11370-1-ivan@habunek.com> (view parent)
DKIM signature
pass
Download raw message
Patch: +27 -3
---
 todosrht/blueprints/tracker.py         |  8 +++++---
 todosrht/templates/tracker-access.html | 22 ++++++++++++++++++++++
 2 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/todosrht/blueprints/tracker.py b/todosrht/blueprints/tracker.py
index bd65d8c..cb9ce97 100644
--- a/todosrht/blueprints/tracker.py
+++ b/todosrht/blueprints/tracker.py
@@ -5,10 +5,11 @@ from todosrht.access import get_tracker
from todosrht.search import apply_search
from todosrht.tickets import get_last_seen_times, get_comment_counts
from todosrht.tickets import submit_ticket
from todosrht.types import TicketSubscription, User
from todosrht.trackers import get_recent_users
from todosrht.types import Event, UserAccess
from todosrht.types import Tracker, Ticket, TicketAccess
from todosrht.types import Label, TicketLabel
from todosrht.types import TicketSubscription, User
from todosrht.types import Tracker, Ticket, TicketAccess
from todosrht.urls import tracker_url, ticket_url
from todosrht.webhooks import TrackerWebhook, UserWebhook
from srht.config import cfg
@@ -209,9 +210,10 @@ def settings_details_POST(owner, name):


def render_tracker_access(tracker, **kwargs):
    recent_users = get_recent_users(tracker)
    return render_template("tracker-access.html",
        view="access", tracker=tracker, access_type_list=TicketAccess,
        access_help_map=access_help_map, **kwargs)
        access_help_map=access_help_map, recent_users=recent_users, **kwargs)


@tracker.route("/<owner>/<name>/settings/access")
diff --git a/todosrht/templates/tracker-access.html b/todosrht/templates/tracker-access.html
index 01a0f6c..19cd1ad 100644
--- a/todosrht/templates/tracker-access.html
+++ b/todosrht/templates/tracker-access.html
@@ -109,8 +109,15 @@
          id="username"
          name="username"
          placeholder="~{{ current_user.username }}"
          autocomplete="off"
          list="user-list"
          value="{{username or ""}}"
        />
        <datalist id="user-list">
          {% for u in recent_users %}
            <option value="~{{ u }}" />
          {% endfor %}
        </datalist>
        {{ valid.summary("username") }}
      </div>

@@ -182,3 +189,18 @@
  </div>
</div>
{% endblock %}

{% block scripts %}
<script type="text/javascript">
  {% include "autocomplete.js" %}

  (function() {
    const input = document.getElementById("username");
    const list = document.getElementById("user-list");
    if (input && list) {
      autocomplete = new UserAutoComplete(input, list);
      autocomplete.register();
    }
  })();
</script>
{% endblock %}
-- 
2.20.1
Details
Message ID
<BW79K0MUOZBM.12J31U2UDG8YX@koishi>
In-Reply-To
<20190811121203.11370-1-ivan@habunek.com> (view parent)
DKIM signature
pass
Download raw message
Thanks!

To git.sr.ht:~sircmpwn/todo.sr.ht
   c8ef2f9..e7aab9c  master -> master
 * [new tag]         0.46.7 -> 0.46.7