Use autofocus on username input field instead of the password field, Fill missing cells on incorrect cell count in table views
This commit is contained in:
parent
8612251448
commit
a0e712827d
5 changed files with 130 additions and 75 deletions
|
@ -1,5 +1,9 @@
|
||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
## 2.1.4 - 2019/11/08
|
||||||
|
* Use autofocus on username input field instead of the password field
|
||||||
|
* Fill missing cells on incorrect cell count in table views when only partial data is available
|
||||||
|
|
||||||
## 2.1.3 - 2019/08/08
|
## 2.1.3 - 2019/08/08
|
||||||
* Fixed false rendering of forms
|
* Fixed false rendering of forms
|
||||||
* Fixed channel tree view showing the wrong virtual server after selection
|
* Fixed channel tree view showing the wrong virtual server after selection
|
||||||
|
|
11
README.md
11
README.md
|
@ -3,8 +3,8 @@ ts3web is a free and open-source web interface for TeamSpeak 3 instances.
|
||||||
|
|
||||||
The minimalistic approach of this application is intentional.
|
The minimalistic approach of this application is intentional.
|
||||||
|
|
||||||
* Docker images available on https://hub.docker.com/r/varakh/ts3web
|
* Docker images available on [https://hub.docker.com/r/varakh/ts3web](https://hub.docker.com/r/varakh/ts3web)
|
||||||
* Sources are hosted on https://gitlab.com/varakh/ts3web
|
* Sources are hosted on [https://gitlab.com/varakh/ts3web](https://gitlab.com/varakh/ts3web)
|
||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
Features which are currently not supported:
|
Features which are currently not supported:
|
||||||
|
@ -52,7 +52,7 @@ IP for this example setup.
|
||||||
the `env` file referenced in the example `docker-compose`.
|
the `env` file referenced in the example `docker-compose`.
|
||||||
|
|
||||||
```
|
```
|
||||||
version: '2'
|
version: '2.1'
|
||||||
networks:
|
networks:
|
||||||
teamspeak:
|
teamspeak:
|
||||||
external: false
|
external: false
|
||||||
|
@ -86,6 +86,11 @@ services:
|
||||||
restart: always
|
restart: always
|
||||||
networks:
|
networks:
|
||||||
- teamspeak
|
- teamspeak
|
||||||
|
healthcheck:
|
||||||
|
test: "nc -z localhost 80"
|
||||||
|
interval: 1s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 5
|
||||||
```
|
```
|
||||||
|
|
||||||
Now execute `docker-compose up -d` to start those containers. If you like to update, do `docker-compose down`,
|
Now execute `docker-compose up -d` to start those containers. If you like to update, do `docker-compose down`,
|
||||||
|
|
|
@ -75,7 +75,6 @@ http {
|
||||||
# Enable checking the existence of precompressed files.
|
# Enable checking the existence of precompressed files.
|
||||||
#gzip_static on;
|
#gzip_static on;
|
||||||
|
|
||||||
|
|
||||||
# Specifies the main log format.
|
# Specifies the main log format.
|
||||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
'$status $body_bytes_sent "$http_referer" '
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
|
|
|
@ -24,14 +24,14 @@
|
||||||
<input type="text" id="username" name="username" class="form-control form-control-sm"
|
<input type="text" id="username" name="username" class="form-control form-control-sm"
|
||||||
placeholder="{{ getenv('teamspeak_user') }}"
|
placeholder="{{ getenv('teamspeak_user') }}"
|
||||||
value="{{ getenv('teamspeak_user') }}"
|
value="{{ getenv('teamspeak_user') }}"
|
||||||
required>
|
autofocus required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="password" class="sr-only">{% trans %}login.form.password{% endtrans %}</label>
|
<label for="password" class="sr-only">{% trans %}login.form.password{% endtrans %}</label>
|
||||||
<input type="password" id="password" name="password"
|
<input type="password" id="password" name="password"
|
||||||
class="form-control form-control-sm"
|
class="form-control form-control-sm"
|
||||||
placeholder="{% trans %}login.form.password.placeholder{% endtrans %}" autofocus required>
|
placeholder="{% trans %}login.form.password.placeholder{% endtrans %}" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|
|
@ -1,10 +1,50 @@
|
||||||
|
<!-- determine if keys are missing and add empty values for them -->
|
||||||
|
{% set allKeys = [] %}
|
||||||
|
{% for arr in data %}
|
||||||
|
{% for key in arr|keys %}
|
||||||
|
{% if key not in allKeys %}
|
||||||
|
{% set allKeys = allKeys|merge([key]) %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% set workData = [] %}
|
||||||
|
{% for arr in data %}
|
||||||
|
{% set missing = [] %}
|
||||||
|
|
||||||
|
{% for ix,key in allKeys %}
|
||||||
|
{% if key not in arr|keys %}
|
||||||
|
{% set missing = missing|merge({(key) : null}) %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if missing is not null %}
|
||||||
|
{% set manipulatedArr = arr %}
|
||||||
|
{% set manipulatedArr = manipulatedArr|merge(missing) %}
|
||||||
|
|
||||||
|
{% set correctOrdered = [] %}
|
||||||
|
{% for key in allKeys %}
|
||||||
|
{% for k,v in manipulatedArr %}
|
||||||
|
{% if k == key %}
|
||||||
|
{% set correctOrdered = correctOrdered|merge({(k):v}) %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% set workData = workData|merge([correctOrdered]) %}
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
{% set workData = workData|merge([arr]) %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-sm small sortable-bootstrap table-striped table-bordered" data-sortable>
|
<table class="table table-sm small sortable-bootstrap table-striped table-bordered" data-sortable>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<!-- determine if to hide entire column header -->
|
<!-- determine if to hide entire column header -->
|
||||||
{% set added = [] %}
|
{% set added = [] %}
|
||||||
{% for arr in data %}
|
{% for arr in workData %}
|
||||||
{% set added = arr|keys %}
|
{% set added = arr|keys %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
@ -22,95 +62,102 @@
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
||||||
{% for arr in data %}
|
{% for arr in workData %}
|
||||||
|
|
||||||
<!-- determine if row should be hidden -->
|
<!-- determine if row should be hidden -->
|
||||||
{% set show = true %}
|
{% set show = true %}
|
||||||
{% for hidden in hiddenDependingOnAttribute %}
|
{% for hidden in hiddenDependingOnAttribute %}
|
||||||
{% if hidden.key in arr|keys and attribute(arr, hidden.key) in hidden.values %}
|
{% if hidden.key in arr|keys and attribute(arr, hidden.key) in hidden.values %}
|
||||||
{% set show = false %}
|
{% set show = false %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% if show == true %}
|
{% if show == true %}
|
||||||
<tr>
|
<tr>
|
||||||
{% for key, value in arr %}
|
{% for key, value in arr %}
|
||||||
{% set value = value %}
|
{% set value = value %}
|
||||||
|
|
||||||
<!-- apply filters to item -->
|
<!-- apply filters to item -->
|
||||||
{% for filter in filters %}
|
{% for filter in filters %}
|
||||||
{% if filter.key == key %}
|
{% if filter.key == key %}
|
||||||
|
{% if value is not empty %}
|
||||||
{% set value = value|apply_filter(filter.apply)|raw %}
|
{% set value = value|apply_filter(filter.apply)|raw %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
<!-- determine if to hide entire column cell -->
|
|
||||||
{% set showColumn = true %}
|
|
||||||
{% if key in hiddenColumns %}
|
|
||||||
{% set showColumn = false %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
{% if showColumn %}
|
<!-- determine if to hide entire column cell -->
|
||||||
<td>
|
{% set showColumn = true %}
|
||||||
{% set item = value %}
|
{% if key in hiddenColumns %}
|
||||||
|
{% set showColumn = false %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<!-- determine if cell should -->
|
{% if showColumn %}
|
||||||
{% set editable = null %}
|
<td>
|
||||||
{% for attr in attributesEditable %}
|
{% set item = value %}
|
||||||
{% if attr.key == key %}
|
|
||||||
{% set editable = attr %}
|
<!-- determine if cell should -->
|
||||||
|
{% set editable = null %}
|
||||||
|
{% for attr in attributesEditable %}
|
||||||
|
{% if attr.key == key %}
|
||||||
|
{% set editable = attr %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<!-- cell is editable, generate a form -->
|
||||||
|
{% if editable is not empty %}
|
||||||
|
{% include 'form_inline.twig' with {'editable': editable} %}
|
||||||
|
<!-- cell is static or a link-->
|
||||||
|
{% else %}
|
||||||
|
{% for link in links %}
|
||||||
|
{% if link.key == key %}
|
||||||
|
{% if link.uri_param is not empty %}
|
||||||
|
{% for searchingKey, searchingValue in arr %}
|
||||||
|
{% if searchingKey == link.uri_param %}
|
||||||
|
{% set item = "<a href=\"#{link.uri}\/#{searchingValue}\">#{value}</a>" %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
{% set item = "<a href=\"#{link.uri}\/#{value}\">#{value}</a>" %}
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<!-- cell is editable, generate a form -->
|
{% if item is empty %}
|
||||||
{% if editable is not empty %}
|
|
||||||
{% include 'form_inline.twig' with {'editable': editable} %}
|
|
||||||
<!-- cell is static or a link-->
|
|
||||||
{% else %}
|
{% else %}
|
||||||
{% for link in links %}
|
|
||||||
{% if link.key == key %}
|
|
||||||
{% if link.uri_param is not empty %}
|
|
||||||
{% for searchingKey, searchingValue in arr %}
|
|
||||||
{% if searchingKey == link.uri_param %}
|
|
||||||
{% set item = "<a href=\"#{link.uri}\/#{searchingValue}\">#{value}</a>" %}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
{% set item = "<a href=\"#{link.uri}\/#{value}\">#{value}</a>" %}
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{{ item|raw }}
|
{{ item|raw }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
{% endif %}
|
||||||
{% endif %}
|
</td>
|
||||||
{% endfor %}
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
<!-- generate additional columns as links, maybe apply filters -->
|
<!-- generate additional columns as links, maybe apply filters -->
|
||||||
{% for link in additional_links %}
|
{% for link in additional_links %}
|
||||||
<td>
|
<td>
|
||||||
{% set item = "<a href=\"#{link.uri}\">#{link.label}" %}
|
{% set item = "<a href=\"#{link.uri}\">#{link.label}" %}
|
||||||
|
|
||||||
{% if link.uri_param is not empty %}
|
{% if link.uri_param is not empty %}
|
||||||
{% for searchingKey, searchingValue in arr %}
|
{% for searchingKey, searchingValue in arr %}
|
||||||
{% if searchingKey == link.uri_param %}
|
{% if searchingKey == link.uri_param %}
|
||||||
{% set shownValue = searchingValue %}
|
{% set shownValue = searchingValue %}
|
||||||
|
|
||||||
{% if link.apply is not empty %}
|
{% if link.apply is not empty %}
|
||||||
|
{% if shownValue is not empty %}
|
||||||
{% set shownValue = shownValue|apply_filter(link.apply)|raw %}
|
{% set shownValue = shownValue|apply_filter(link.apply)|raw %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% set item = "<a href=\"#{link.uri}\/#{shownValue}\">#{link.label}</a>" %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{{ item|raw }}
|
{% set item = "<a href=\"#{link.uri}\/#{shownValue}\">#{link.label}</a>" %}
|
||||||
</td>
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
{% endif %}
|
||||||
{% endif %}
|
|
||||||
|
{{ item|raw }}
|
||||||
|
</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
Reference in a new issue