Add filter-posts (unfinished) + UI/UX improvements
This commit is contained in:
parent
ee5eb1af0e
commit
961808d59c
41
css/base.php
41
css/base.php
|
@ -75,6 +75,7 @@ body > .toast-container {
|
|||
*[id*="-item"] { display: none !important }
|
||||
|
||||
.flex { display: flex }
|
||||
.iflex { display: inline-flex }
|
||||
.inline { display: inline-block }
|
||||
.center { margin: auto }
|
||||
.wmax { width: 100vw }
|
||||
|
@ -158,7 +159,7 @@ textarea {
|
|||
}
|
||||
|
||||
br.sep {
|
||||
margin-bottom: 1em;
|
||||
margin-bottom: .7em;
|
||||
}
|
||||
|
||||
hr { color: #0000005e }
|
||||
|
@ -170,7 +171,10 @@ a {
|
|||
main input[type=text],
|
||||
main input[type=password],
|
||||
main textarea {
|
||||
padding: 1em;
|
||||
padding: .7em;
|
||||
border-radius: .5em;
|
||||
border: 1px solid #00000042;
|
||||
box-shadow: 0px 0px .2em #0000002b;
|
||||
}
|
||||
main input[type=number] {
|
||||
padding: .5em 1em;
|
||||
|
@ -179,8 +183,24 @@ main input[type=number] {
|
|||
main select {
|
||||
padding: .5em;
|
||||
}
|
||||
@media (min-width: 650px) {
|
||||
main .input-rows-2 {
|
||||
display: flex;
|
||||
}
|
||||
main .input-rows-2.divide > * {
|
||||
width: 100%;
|
||||
}
|
||||
main .input-rows-2 > .div2 {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
main .input {
|
||||
margin-bottom: 1em;
|
||||
border-bottom: 2px dotted #00000017;
|
||||
padding: .8em .5em;
|
||||
}
|
||||
main .input.last {
|
||||
padding: 1em;
|
||||
padding-top: 1.5em;
|
||||
}
|
||||
|
||||
.software .only {
|
||||
|
@ -294,6 +314,9 @@ table.fields tr.verified td .fa.fa-check::before {
|
|||
#window-instance #tabs .item[data-id="settings"] {
|
||||
border-left: 2px solid #5e5e5e;
|
||||
}
|
||||
#window-instance #tabs .item.selected {
|
||||
border-top: 4px solid #ff7a7a;
|
||||
}
|
||||
#window-instance #tabs .tab-content {
|
||||
padding: 1em;
|
||||
}
|
||||
|
@ -304,7 +327,13 @@ table.fields tr.verified td .fa.fa-check::before {
|
|||
}
|
||||
#window-instance #content #container {
|
||||
margin: 0 auto;
|
||||
max-width: 50em;
|
||||
padding: 1em;
|
||||
width: 100%;
|
||||
}
|
||||
#window-instance #content #container h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
#window-instance #container .card {
|
||||
margin-bottom: 1em;
|
||||
|
@ -313,6 +342,12 @@ table.fields tr.verified td .fa.fa-check::before {
|
|||
#window-instance #filters-all {
|
||||
max-width: 50em;
|
||||
}
|
||||
#window-instance #filters-all .item .btn.mid {
|
||||
margin-right: .5em;
|
||||
margin-bottom: .2em;
|
||||
font-size: .9em;
|
||||
padding: .3em !important;
|
||||
}
|
||||
#window-instance #container #new-accounts .card {
|
||||
width: calc(100vw - 4em);
|
||||
max-width: 30em;
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
<h3>Filters being applied: <button id="btncollapse-filters-all">hide</button></h3>
|
||||
<div id="filters-all"></div>
|
||||
<span id="filters-all-item">
|
||||
<a href="javascript:window.set_hash_argument('filter_id','{id}')">
|
||||
<div class="btn mid card inline" style="margin-right: .5em; margin-bottom: .5em">
|
||||
<i class="fa fa-filter fa-fw"></i>{name}
|
||||
<button class="btn small red"
|
||||
onclick="{view.js}.delete_filter('{id}');event.preventDefault()">
|
||||
<i class="fa fa-close fa-fw"></i>
|
||||
</button>
|
||||
</div>
|
||||
</a>
|
||||
</span>
|
||||
|
||||
<h3>
|
||||
<span id="filter-current-name">*New filter</span>:
|
||||
<button id="btncollapse-filters-current">hide</button>
|
||||
<button class="btn mid green center"
|
||||
onclick="window.del_hash_argument('filter_id');
|
||||
{view.js}.set_current_filter({})"
|
||||
><i class="fa fa-plus fa-fw"></i>
|
||||
New</button>
|
||||
</h3>
|
||||
<div id="filters-current">
|
||||
<div class="card">
|
||||
<div class="input">
|
||||
<input type="hidden" name="preset_id" value="-1"/>
|
||||
<label for="preset_name">Preset name:</label>
|
||||
<input type="text" name="preset_name" placeholder="Preset name" value="Undefined"/>
|
||||
</div>
|
||||
<div class="input">
|
||||
<label for="profile">Post content:</label>
|
||||
<input type="radio" id="post-search-type-simple"
|
||||
name="post_search_type" value="simple" checked
|
||||
/><label for="post-search-type-simple">simple</label>
|
||||
<input type="radio" id="post-search-type-expr"
|
||||
name="post_search_type" value="expr"
|
||||
/><label for="post-search-type-expr">expr</label>
|
||||
<br class="sep"/>
|
||||
<textarea name="profile" placeholder="Input your text here"
|
||||
style="width: 100%; min-width: 24em; min-height: 6em"></textarea>
|
||||
</div>
|
||||
<div class="input">
|
||||
<label for="instances">Instances:</label>
|
||||
<br class="sep"/>
|
||||
<textarea name="instances" placeholder="instance1.org, server2.com, !not-this-one.com"
|
||||
style="width: 100%; min-width: 24em; min-height: 4em"></textarea>
|
||||
</div>
|
||||
<div class="input">
|
||||
<label for="languages">Languages:</label>
|
||||
<br class="sep"/>
|
||||
<textarea name="languages" placeholder="es, en, de"
|
||||
style="width: 100%; min-width: 24em; min-height: 4em"></textarea>
|
||||
</div>
|
||||
<br>
|
||||
<div class="input flex">
|
||||
<button class="btn center"
|
||||
onclick="{view.js}.toggle_filter('{id}')"
|
||||
><i class="fa fa-search fa-fw"></i>
|
||||
{enableOrDisable}</button>
|
||||
<div style="width:1em"></div>
|
||||
<button class="btn center"
|
||||
onclick="{view.js}.save_filter()"
|
||||
><i class="fa fa-save fa-fw"></i>
|
||||
Save filter</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="filter-instance-action"></div>
|
||||
<div id="filter-instance-action-item">
|
||||
<div class="card">
|
||||
<div class="flex">
|
||||
<span class="center"><i class="fa fa-info-circle fa-fw"></i>
|
||||
Action for users matching this filter on <b>{instance}</b>
|
||||
</span>
|
||||
</div>
|
||||
<hr><br>
|
||||
<div class="input">
|
||||
<label for="instance_action_name">What to do:</label>
|
||||
<br class="sep"/>
|
||||
<select name="instance_action_name">
|
||||
<option value="none">None (do nothing)</option>
|
||||
<option value="report">Report</option>
|
||||
<option value="silence">Silence</option>
|
||||
<option value="sensible">Sensible</option>
|
||||
<option value="suspend">Suspend</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="input">
|
||||
<label for="instance_action_explain">Generic explanation to users:</label>
|
||||
<br class="sep"/>
|
||||
<textarea type="text" name="instance_action_explain" style="min-height: 6em" class="w100"
|
||||
placeholder="Generic explanation that will be sent to users when an action is taken..."></textarea>
|
||||
</div>
|
||||
<div class="input">
|
||||
<label for="instance_action_interval">Job interval (in seconds):</label>
|
||||
<input type="number" name="instance_action_interval" placeholder="60"/>
|
||||
</div>
|
||||
<br>
|
||||
<div class="input flex">
|
||||
<button class="btn center" onclick="
|
||||
{view.js}.save_filter_action('{id}')"
|
||||
><i class="fa fa-save fa-fw"></i> Save filter action</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Timeline:
|
||||
<button id="btncollapse-results-box">hide</button>
|
||||
<button onclick="{view.js}.execute()" class="btn mid center">
|
||||
<i class="fa fa-search fa-fw"></i></button>
|
||||
</h3>
|
||||
<div id="results-box">
|
||||
<div id="paging"></div>
|
||||
<div id="paging-item">
|
||||
<button class="btn mid" onclick="
|
||||
{view.js}.execute({prev_page},{items_per_page})"
|
||||
><i class="fa fa-chevron-left fa-fw"></i></button>
|
||||
<button class="btn mid" onclick="
|
||||
{view.js}.execute({next_page},{items_per_page})"
|
||||
><i class="fa fa-chevron-right fa-fw"></i></button>
|
||||
<span>{current_page} / {total_pages} ({total_users} users)</span>
|
||||
</div>
|
||||
<div id="users-all"></div>
|
||||
<div id="users-all-item" data-id="{id}">
|
||||
<div class="card software {software} {silencedClass}">
|
||||
<div class="flex disable-able">
|
||||
<img data-src="{avatar}"/>
|
||||
<div class="w100" style="padding:0 1em">
|
||||
<b style="font-size: 1.1em">{name}</b>
|
||||
<br>
|
||||
<span class="gray">@{acct}</span>
|
||||
<div class="props flex">
|
||||
<span>{statuses}<br><span class="gray">statuses</span></span>
|
||||
<span>{following}<br><span class="gray">following</span></span>
|
||||
<span>{followers}<br><span class="gray">followers</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="only mastodon">{mastodon:fields}</div>
|
||||
<div class="note">{note}</div>
|
||||
<div style="margin-top: 1em; text-align: right;">
|
||||
|
||||
<div style="float:left">
|
||||
|
||||
<button onclick="if ({do.js}.users.trust_user('{acct}'))
|
||||
E.element('.item[data-id="{id}"]').remove()"
|
||||
title="Add this user to the trusted_users list"
|
||||
class="btn mid green"><i class="fa fa-thumbs-up fa-fw"></i>
|
||||
Trust</button>
|
||||
|
||||
<a href="{accountAdminLink}" target="_blank" rel="noreferrer noopener">
|
||||
<button class="btn mid"
|
||||
title="Open this account in the AP application manager"
|
||||
><i class="fa fa-id-card fa-fw"></i>
|
||||
Manage</button>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
<button onclick="if ({do.js}.users.hide_on_filters('{acct}', 86400))
|
||||
E.element('.item[data-id="{id}"]').remove()"
|
||||
title="Hide the selected account for 1 day (24 hours)"
|
||||
class="btn mid"><i class="fa fa-clock-o fa-fw"></i>
|
||||
Hide 1d</button>
|
||||
|
||||
<button onclick="
|
||||
if ('' === '{disabledClass}') {
|
||||
if ({do.js}.users.silence('{id}')) {
|
||||
E.element('.item[data-id="{id}"]').classList.add('silenced');
|
||||
this.querySelector('span').innerText = 'Silenced';
|
||||
this.setAttribute('disabled', 'true');
|
||||
}
|
||||
}"
|
||||
title="Silence this user on the instance"
|
||||
class="btn mid disable-able" {disabledHTML}>
|
||||
<i class="fa fa-volume-mute fa-fw"></i>
|
||||
<span>{silencedText}</span></button>
|
||||
|
||||
<button onclick="if ({do.js}.users.suspend('{id}')) {
|
||||
E.element('.item[data-id="{id}"]').classList.add('suspended');
|
||||
this.querySelector('span').innerText = 'Suspended'}"
|
||||
title="Suspend this user on the instance"
|
||||
class="btn mid red"><i class="fa fa-ban fa-fw"></i>
|
||||
<span>Suspend</span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="paging" class="bottom"></div>
|
||||
</div>
|
||||
<br>
|
|
@ -2,7 +2,7 @@
|
|||
<div id="filters-all"></div>
|
||||
<span id="filters-all-item">
|
||||
<a href="javascript:window.set_hash_argument('filter_id','{id}')">
|
||||
<div class="btn mid card inline" style="margin-right: .5em; margin-bottom: .5em">
|
||||
<div class="btn mid card inline">
|
||||
<i class="fa fa-filter fa-fw"></i>{name}
|
||||
<button class="btn small red"
|
||||
onclick="{view.js}.delete_filter('{id}');event.preventDefault()">
|
||||
|
@ -12,6 +12,7 @@
|
|||
</a>
|
||||
</span>
|
||||
|
||||
<br>
|
||||
<h3>
|
||||
<span id="filter-current-name">*New filter</span>:
|
||||
<button id="btncollapse-filters-current">hide</button>
|
||||
|
@ -41,46 +42,64 @@
|
|||
/><label for="profile-search-type-empty">Empty</label>
|
||||
<br class="sep"/>
|
||||
<textarea name="profile" placeholder="Input your text here"
|
||||
style="width: 100%; min-width: 24em; min-height: 6em"></textarea>
|
||||
style="width: 100%; min-width: 24em; min-height: 4em"></textarea>
|
||||
</div>
|
||||
<div class="input-rows-2 divide">
|
||||
<div class="input">
|
||||
<label for="instances">Instances:</label>
|
||||
<br class="sep"/>
|
||||
<textarea name="instances" placeholder="instance1.org, server2.com"
|
||||
style="width: 100%; min-width: 24em; min-height: 4em"></textarea>
|
||||
<textarea name="instances" placeholder="instance1.org, server2.com, !not-this-one.com"
|
||||
style="width: 100%; min-height: 2em"></textarea>
|
||||
</div>
|
||||
<div class="input">
|
||||
<div class="input div2">
|
||||
<label for="languages">Languages:</label>
|
||||
<br class="sep"/>
|
||||
<textarea name="languages" placeholder="es, en, de"
|
||||
style="width: 100%; min-width: 24em; min-height: 4em"></textarea>
|
||||
style="width: 100%; min-height: 2em"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-rows-2">
|
||||
<div class="input">
|
||||
<label for="user_filter">Account type:</label>
|
||||
<br class="sep"/>
|
||||
<input type="radio" id="user-filter-local"
|
||||
<div class="iflex">
|
||||
<input type="radio" id="user-filter-local"
|
||||
name="user_filter" value="local" checked
|
||||
/><label for="user-filter-local">local</label>
|
||||
<input type="radio" id="user_filter-remote"
|
||||
</div>
|
||||
<div class="iflex">
|
||||
<input type="radio" id="user_filter-remote"
|
||||
name="user_filter" value="remote"
|
||||
/><label for="user_filter-remote">remote</label>
|
||||
</div>
|
||||
<div><br></div>
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>Account stages:</label>
|
||||
<br class="sep"/>
|
||||
<input type="checkbox" id="account-prop-noavatar"
|
||||
<div class="iflex">
|
||||
<input type="checkbox" id="account-prop-noavatar"
|
||||
name="no_avatar" value="1"
|
||||
/><label for="account-prop-noavatar">No avatar</label>
|
||||
<input type="checkbox" id="account-prop-nostatuses"
|
||||
</div>
|
||||
<div class="iflex">
|
||||
<input type="checkbox" id="account-prop-nostatuses"
|
||||
name="no_statuses" value="1"
|
||||
/><label for="account-prop-nostatuses">No statuses</label>
|
||||
<input type="checkbox" id="account-prop-nofollows"
|
||||
</div>
|
||||
<div class="iflex">
|
||||
<input type="checkbox" id="account-prop-nofollows"
|
||||
name="no_follows" value="1"
|
||||
/><label for="account-prop-nofollows">No follows</label>
|
||||
<input type="checkbox" id="account-prop-ismoved"
|
||||
</div>
|
||||
<div class="iflex">
|
||||
<input type="checkbox" id="account-prop-ismoved"
|
||||
name="is_moved" value="1"
|
||||
/><label for="account-prop-ismoved">Has moved elsewhere</label>
|
||||
</div>
|
||||
<div><br></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>Last activity (days):</label>
|
||||
<br class="sep"/>
|
||||
|
@ -106,8 +125,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="input flex">
|
||||
<div class="input last noborder flex">
|
||||
<button class="btn center"
|
||||
onclick="{view.js}.execute()"
|
||||
><i class="fa fa-search fa-fw"></i>
|
||||
|
@ -149,8 +167,7 @@
|
|||
<label for="instance_action_interval">Job interval (in seconds):</label>
|
||||
<input type="number" name="instance_action_interval" placeholder="60"/>
|
||||
</div>
|
||||
<br>
|
||||
<div class="input flex">
|
||||
<div class="input last noborder flex">
|
||||
<button class="btn center" onclick="
|
||||
{view.js}.save_filter_action('{id}')"
|
||||
><i class="fa fa-save fa-fw"></i> Save filter action</button>
|
||||
|
@ -159,6 +176,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<h3>Results:
|
||||
<button id="btncollapse-results-box">hide</button>
|
||||
<button onclick="{view.js}.execute()" class="btn mid center">
|
||||
|
|
|
@ -457,6 +457,44 @@ window.view.instance = {
|
|||
});
|
||||
});
|
||||
},
|
||||
filter_posts: function() {
|
||||
const hargs = get_hash_arguments();
|
||||
E.http_template('instance/filter-posts', function(html) {
|
||||
html = html.replaceAll('{view.js}', 'window.view.instance.do.filter_posts');
|
||||
html = html.replaceAll('{do.js}', 'window.view.instance.do');
|
||||
E.element('#window-instance #container').innerHTML = html;
|
||||
E.elemid('post-search-type-simple').onchange = function(e) {
|
||||
if (e.target.checked) {
|
||||
E.element('#filters-current textarea[name=profile]').setAttribute('placeholder', 'Input your text here');
|
||||
E.element('#filters-current textarea[name=profile]').removeAttribute('disabled');
|
||||
}
|
||||
};
|
||||
E.elemid('post-search-type-expr').onchange = function(e) {
|
||||
if (e.target.checked) {
|
||||
E.element('#filters-current textarea[name=profile]').setAttribute('placeholder',
|
||||
'Input your expression (click on info button for documentation)');
|
||||
E.element('#filters-current textarea[name=profile]').removeAttribute('disabled');
|
||||
}
|
||||
};
|
||||
E.custom.btncollapse_render();
|
||||
http.get('api/v1/config/filters/get?type=posts', {}, function(js) {
|
||||
js = js.sort((a,b) => a.preset_name.localeCompare(b.preset_name));
|
||||
window.vars.post_filters = js;
|
||||
E.template('filters-all', function(TPL) {
|
||||
var html = '';
|
||||
for (var i = 0; i < js.length; i++) {
|
||||
var tpl = TPL;
|
||||
tpl = tpl.replaceAll('{id}', js[i].id);
|
||||
tpl = tpl.replaceAll('{name}', js[i].preset_name);
|
||||
html += tpl;
|
||||
}
|
||||
return html;
|
||||
});
|
||||
if (hargs.filter_id !== undefined)
|
||||
window.view.instance.do.filter_posts.set_current_filter(hargs.filter_id);
|
||||
});
|
||||
});
|
||||
},
|
||||
filter_users: function() {
|
||||
const hargs = get_hash_arguments();
|
||||
E.http_template('instance/filter-users', function(html) {
|
||||
|
@ -472,7 +510,7 @@ window.view.instance = {
|
|||
E.elemid('profile-search-type-expr').onchange = function(e) {
|
||||
if (e.target.checked) {
|
||||
E.element('#filters-current textarea[name=profile]').setAttribute('placeholder',
|
||||
'(words "apple,banana" AND contains "i like apples") OR words "pineapple,strawberry"');
|
||||
'Input your expression (click on info button for documentation)');
|
||||
E.element('#filters-current textarea[name=profile]').removeAttribute('disabled');
|
||||
}
|
||||
};
|
||||
|
@ -508,6 +546,8 @@ window.view.instance = {
|
|||
const hargs = get_hash_arguments();
|
||||
const _empty_content = function() {
|
||||
E.element('#window-instance #container').innerHTML = '';
|
||||
E.elements('#tabs .item').forEach(function(t){t.classList.remove('selected')});
|
||||
E.element(`#tabs *[data-id=${content}]`).classList.add('selected');
|
||||
};
|
||||
if (click) {
|
||||
delete window.hash_argument_nofirechange;
|
||||
|
|
Loading…
Reference in New Issue