Added server side columns sorting on the Process Scheduler table

For easier usage of large tables in the Table_API_p.html page.
pull/186/head
luccioman 6 years ago
parent bb51555830
commit 2bdd71de60

@ -63,9 +63,9 @@ To see a list of all APIs, please visit the <a href="http://www.yacy-websuche.de
<span id="resCounter" style="display: inline;"> <span id="resCounter" style="display: inline;">
#(navigation)# #(navigation)#
:: ::
#(left)#<img src="env/grafics/navdl.gif" alt="no previous page" />::<a href="Table_API_p.html?startRecord=#[startRecord]#&amp;maximumRecords=#[maximumRecords]#&amp;inline=#(inline)#false::true#(/inline)#&amp;filter=#[filter]#&amp;query=#[query]#" target="_self"><img src="env/grafics/navsl.gif" alt="previous page" /></a>#(/left)# #(left)#<img src="env/grafics/navdl.gif" alt="no previous page" />::<a href="Table_API_p.html?startRecord=#[startRecord]#&amp;maximumRecords=#[maximumRecords]#&amp;inline=#(inline)#false::true#(/inline)#&amp;filter=#[filter]#&amp;query=#[query]#&amp;sort=#[sort]#" target="_self"><img src="env/grafics/navsl.gif" alt="previous page" /></a>#(/left)#
#[startRecord]#-#[to]# of #[of]# #[startRecord]#-#[to]# of #[of]#
#(right)#<img src="env/grafics/navdr.gif" alt="no next page" />::<a href="Table_API_p.html?startRecord=#[startRecord]#&amp;maximumRecords=#[maximumRecords]#&amp;inline=#(inline)#false::true#(/inline)#&amp;filter=#[filter]#&amp;query=#[query]#" target="_self"><img src="env/grafics/navsr.gif" alt="next page" /></a>#(/right)# #(right)#<img src="env/grafics/navdr.gif" alt="no next page" />::<a href="Table_API_p.html?startRecord=#[startRecord]#&amp;maximumRecords=#[maximumRecords]#&amp;inline=#(inline)#false::true#(/inline)#&amp;filter=#[filter]#&amp;query=#[query]#&amp;sort=#[sort]#" target="_self"><img src="env/grafics/navsr.gif" alt="next page" /></a>#(/right)#
<img src="env/grafics/nave.gif" alt="" /> <img src="env/grafics/nave.gif" alt="" />
#(/navigation)# #(/navigation)#
@ -73,23 +73,43 @@ To see a list of all APIs, please visit the <a href="http://www.yacy-websuche.de
<input type="hidden" name="maximumRecords" value="#[maximumRecords]#" /> <input type="hidden" name="maximumRecords" value="#[maximumRecords]#" />
<input type="hidden" name="inline" value="#(inline)#false::true#(/inline)#" /> <input type="hidden" name="inline" value="#(inline)#false::true#(/inline)#" />
<input type="hidden" name="filter" value="#[filter]#" /> <input type="hidden" name="filter" value="#[filter]#" />
<input type="hidden" name="sort" value="#[sort]#" />
<input type="text" name="query" value="#[query]#" onchange="resetStartRecord()" style="font-size:16px;float:left;border:0px;height:20px;background-image:url('env/grafics/find.gif');background-repeat:no-repeat;background-position:right top;"/> <input type="text" name="query" value="#[query]#" onchange="resetStartRecord()" style="font-size:16px;float:left;border:0px;height:20px;background-image:url('env/grafics/find.gif');background-repeat:no-repeat;background-position:right top;"/>
</span> </span>
<br/> <br/>
<div style="clear:both;"> <div style="clear:both;">
<table class="sortable" style="border:0px; padding:2px; border-spacing:1px"> <table style="border:0px; padding:2px; border-spacing:1px" role="grid">
<tr class="TableHeader" valign="bottom"> <tr class="TableHeader" valign="bottom">
<th class="sorttable_nosort"><input type="checkbox" id="allswitch" onclick="checkAll(this.form.id, this.checked);" /></th> <th class="sorttable_nosort"><input type="checkbox" id="allswitch" onclick="checkAll(this.form.id, this.checked);" /></th>
<th>Type</th> <th #(sortedByType)#::aria-sort="#(asc)#descending::ascending#(/asc)#"#(/sortedByType)#>
<th style="width: 100%;">Comment</th> <a class="sortTableLink" href="Table_API_p.html?startRecord=#[startRecord]#&amp;maximumRecords=#[maximumRecords]#&amp;sort=#(nextSortTypeDesc)#::-#(/nextSortTypeDesc)#type&amp;inline=#(inline)#false::true#(/inline)#&amp;filter=#[filter]#&amp;query=#[query]#" target="_self" title="Sort by #(nextSortTypeDesc)#ascending::descending#(/nextSortTypeDesc)# types">Type</a>
<th>Call<br/>Count</th> #(sortedByType)#::<span class="glyphicon glyphicon-chevron-#(asc)#down::up#(/asc)#"></span>#(/sortedByType)#
<th>Recording<br/>Date</th> </th>
<th>Last&nbsp;Exec<br/>Date</th> <th style="width: 100%;" #(sortedByComment)#::aria-sort="#(asc)#descending::ascending#(/asc)#"#(/sortedByComment)#>
<th>Next&nbsp;Exec<br/>Date#(hasEditableNextExecDate)#:: <button type="submit" name="submitNextExecDates" class="btn btn-default btn-xs" title="Apply edited next execution dates"> <a class="sortTableLink" href="Table_API_p.html?startRecord=#[startRecord]#&amp;maximumRecords=#[maximumRecords]#&amp;sort=#(nextSortCommentDesc)#::-#(/nextSortCommentDesc)#comment&amp;inline=#(inline)#false::true#(/inline)#&amp;filter=#[filter]#&amp;query=#[query]#" target="_self" title="Sort by #(nextSortCommentDesc)#ascending::descending#(/nextSortCommentDesc)# comments">Comment</a>
#(sortedByComment)#::<span class="glyphicon glyphicon-chevron-#(asc)#down::up#(/asc)#"></span>#(/sortedByComment)#
</th>
<th #(sortedByApiCallCount)#::aria-sort="#(asc)#descending::ascending#(/asc)#"#(/sortedByApiCallCount)#>
<a class="sortTableLink" href="Table_API_p.html?startRecord=#[startRecord]#&amp;maximumRecords=#[maximumRecords]#&amp;sort=#(nextSortApiCallCountDesc)#::-#(/nextSortApiCallCountDesc)#apicall_count&amp;inline=#(inline)#false::true#(/inline)#&amp;filter=#[filter]#&amp;query=#[query]#" target="_self" title="Sort by #(nextSortApiCallCountDesc)#ascending::descending#(/nextSortApiCallCountDesc)# call counts">Call Count</a>
#(sortedByApiCallCount)#::<span class="glyphicon glyphicon-chevron-#(asc)#down::up#(/asc)#"></span>#(/sortedByApiCallCount)#
</th>
<th #(sortedByDateRecording)#::aria-sort="#(asc)#descending::ascending#(/asc)#"#(/sortedByDateRecording)#>
<a class="sortTableLink" href="Table_API_p.html?startRecord=#[startRecord]#&amp;maximumRecords=#[maximumRecords]#&amp;sort=#(nextSortDateRecordingDesc)#::-#(/nextSortDateRecordingDesc)#date_recording&amp;inline=#(inline)#false::true#(/inline)#&amp;filter=#[filter]#&amp;query=#[query]#" target="_self" title="Sort by #(nextSortDateRecordingDesc)#ascending::descending#(/nextSortDateRecordingDesc)# recording dates">Recording&nbsp;Date</a>
#(sortedByDateRecording)#::<span class="glyphicon glyphicon-chevron-#(asc)#down::up#(/asc)#"></span>#(/sortedByDateRecording)#
</th>
<th #(sortedByDateLastExec)#::aria-sort="#(asc)#descending::ascending#(/asc)#"#(/sortedByDateLastExec)#>
<a class="sortTableLink" href="Table_API_p.html?startRecord=#[startRecord]#&amp;maximumRecords=#[maximumRecords]#&amp;sort=#(nextSortDateLastExecDesc)#::-#(/nextSortDateLastExecDesc)#date_last_exec&amp;inline=#(inline)#false::true#(/inline)#&amp;filter=#[filter]#&amp;query=#[query]#" target="_self" title="Sort by #(nextSortDateLastExecDesc)#ascending::descending#(/nextSortDateLastExecDesc)# last execution dates">Last&nbsp;Exec&nbsp;Date</a>
#(sortedByDateLastExec)#::<span class="glyphicon glyphicon-chevron-#(asc)#down::up#(/asc)#"></span>#(/sortedByDateLastExec)#
</th>
<th #(sortedByDateNextExec)#::aria-sort="#(asc)#descending::ascending#(/asc)#"#(/sortedByDateNextExec)#>
<a class="sortTableLink" href="Table_API_p.html?startRecord=#[startRecord]#&amp;maximumRecords=#[maximumRecords]#&amp;sort=#(nextSortDateNextExecDesc)#::-#(/nextSortDateNextExecDesc)#date_next_exec&amp;inline=#(inline)#false::true#(/inline)#&amp;filter=#[filter]#&amp;query=#[query]#" target="_self" title="Sort by #(nextSortDateNextExecDesc)#ascending::descending#(/nextSortDateNextExecDesc)# last execution dates">Next&nbsp;Exec&nbsp;Date</a>
#(sortedByDateNextExec)#::<span class="glyphicon glyphicon-chevron-#(asc)#down::up#(/asc)#"></span>#(/sortedByDateNextExec)#
#(hasEditableNextExecDate)#:: <button type="submit" name="submitNextExecDates" class="btn btn-default btn-xs" title="Apply edited next execution dates">
<span class="glyphicon glyphicon-ok"></span> <span class="glyphicon glyphicon-ok"></span>
<span> Apply</span> <span> Apply</span>
</button>#(/hasEditableNextExecDate)# </button>
#(/hasEditableNextExecDate)#
</th> </th>
<th class="sorttable_nosort">Event Trigger</th> <th class="sorttable_nosort">Event Trigger</th>
<th class="sorttable_nosort">Scheduler</th> <th class="sorttable_nosort">Scheduler</th>

@ -44,6 +44,7 @@ import net.yacy.data.TransactionManager;
import net.yacy.data.WorkTables; import net.yacy.data.WorkTables;
import net.yacy.kelondro.blob.Tables; import net.yacy.kelondro.blob.Tables;
import net.yacy.kelondro.blob.Tables.Row; import net.yacy.kelondro.blob.Tables.Row;
import net.yacy.kelondro.blob.Tables.SortDirection;
import net.yacy.search.Switchboard; import net.yacy.search.Switchboard;
import net.yacy.search.SwitchboardConstants; import net.yacy.search.SwitchboardConstants;
import net.yacy.search.query.QueryParams; import net.yacy.search.query.QueryParams;
@ -87,6 +88,21 @@ public class Table_API_p {
typefilter = Pattern.compile(post.get("filter", ".*")); typefilter = Pattern.compile(post.get("filter", ".*"));
} }
/* Applying JSON API convention for the sort parameter format (http://jsonapi.org/format/#fetching-sorting) */
String sortParam = WorkTables.TABLE_API_COL_DATE_RECORDING;
if(post != null) {
sortParam = post.get("sort", WorkTables.TABLE_API_COL_DATE_RECORDING).trim();
}
final SortDirection sortDir;
final String sortColumn;
if(sortParam.startsWith("-")) {
sortColumn = sortParam.substring(1);
sortDir = SortDirection.DESC;
} else {
sortColumn = sortParam;
sortDir = SortDirection.ASC;
}
// process scheduler and event input actions // process scheduler and event input actions
boolean scheduleeventaction = false; // flag if schedule info of row changes boolean scheduleeventaction = false; // flag if schedule info of row changes
String current_pk = ""; // pk of changed schedule data row String current_pk = ""; // pk of changed schedule data row
@ -311,6 +327,8 @@ public class Table_API_p {
prop.put(TransactionManager.TRANSACTION_TOKEN_PARAM, nextTransactionToken); prop.put(TransactionManager.TRANSACTION_TOKEN_PARAM, nextTransactionToken);
prop.put("showtable_" + TransactionManager.TRANSACTION_TOKEN_PARAM, nextTransactionToken); prop.put("showtable_" + TransactionManager.TRANSACTION_TOKEN_PARAM, nextTransactionToken);
final Date now = new Date();
// insert rows // insert rows
final List<Tables.Row> table = new ArrayList<Tables.Row>(maximumRecords); final List<Tables.Row> table = new ArrayList<Tables.Row>(maximumRecords);
int count = 0; int count = 0;
@ -319,7 +337,22 @@ public class Table_API_p {
try { try {
tablesize = sb.tables.size(WorkTables.TABLE_API_NAME); tablesize = sb.tables.size(WorkTables.TABLE_API_NAME);
final Iterator<Tables.Row> plainIterator = sb.tables.iterator(WorkTables.TABLE_API_NAME); final Iterator<Tables.Row> plainIterator = sb.tables.iterator(WorkTables.TABLE_API_NAME);
final Iterator<Tables.Row> mapIterator = Tables.orderBy(plainIterator, -1, WorkTables.TABLE_API_COL_DATE_RECORDING).iterator(); final Iterator<Tables.Row> mapIterator;
if(sortColumn.isEmpty()) {
mapIterator = plainIterator;
} else {
if (WorkTables.TABLE_API_COL_APICALL_COUNT.equals(sortColumn)
|| WorkTables.TABLE_API_COL_APICALL_SCHEDULE_TIME.equals(sortColumn)) {
mapIterator = Tables.orderByInt(plainIterator, sortColumn, 0, sortDir).iterator();
} else if (WorkTables.TABLE_API_COL_DATE.equals(sortColumn)
|| WorkTables.TABLE_API_COL_DATE_RECORDING.equals(sortColumn)
|| WorkTables.TABLE_API_COL_DATE_LAST_EXEC.equals(sortColumn)
|| WorkTables.TABLE_API_COL_DATE_NEXT_EXEC.equals(sortColumn)) {
mapIterator = Tables.orderByDate(plainIterator, sortColumn, now, sortDir).iterator();
} else {
mapIterator = Tables.orderByString(plainIterator, sortColumn, "", sortDir).iterator();
}
}
Tables.Row r; Tables.Row r;
boolean dark = true; boolean dark = true;
boolean scheduledactions = false; boolean scheduledactions = false;
@ -380,7 +413,6 @@ public class Table_API_p {
// then work on the list // then work on the list
for (final Tables.Row row : table) { for (final Tables.Row row : table) {
final String rowPKStr = UTF8.String(row.getPK()); final String rowPKStr = UTF8.String(row.getPK());
final Date now = new Date();
final Date date = row.containsKey(WorkTables.TABLE_API_COL_DATE) ? row.get(WorkTables.TABLE_API_COL_DATE, now) : null; final Date date = row.containsKey(WorkTables.TABLE_API_COL_DATE) ? row.get(WorkTables.TABLE_API_COL_DATE, now) : null;
final Date date_recording = row.get(WorkTables.TABLE_API_COL_DATE_RECORDING, date); final Date date_recording = row.get(WorkTables.TABLE_API_COL_DATE_RECORDING, date);
final Date date_last_exec = row.get(WorkTables.TABLE_API_COL_DATE_LAST_EXEC, date); final Date date_last_exec = row.get(WorkTables.TABLE_API_COL_DATE_LAST_EXEC, date);
@ -536,6 +568,10 @@ public class Table_API_p {
prop.put("showtable_inline", (inline) ? 1 : 0); prop.put("showtable_inline", (inline) ? 1 : 0);
prop.put("showtable_filter", typefilter.pattern()); prop.put("showtable_filter", typefilter.pattern());
prop.put("showtable_query", queryParam); prop.put("showtable_query", queryParam);
prop.put("showtable_sort", sortParam);
putTableSortProperties(prop, sortDir, sortColumn);
if (filteredSize > maximumRecords) { if (filteredSize > maximumRecords) {
prop.put("showtable_navigation", 1); prop.put("showtable_navigation", 1);
prop.put("showtable_navigation_startRecord", startRecord); prop.put("showtable_navigation_startRecord", startRecord);
@ -547,6 +583,7 @@ public class Table_API_p {
prop.put("showtable_navigation_left_inline", (inline) ? 1 : 0); prop.put("showtable_navigation_left_inline", (inline) ? 1 : 0);
prop.put("showtable_navigation_left_filter", typefilter.pattern()); prop.put("showtable_navigation_left_filter", typefilter.pattern());
prop.put("showtable_navigation_left_query", queryParam); prop.put("showtable_navigation_left_query", queryParam);
prop.put("showtable_navigation_left_sort", sortParam);
prop.put("showtable_navigation_left", startRecord == 0 ? 0 : 1); prop.put("showtable_navigation_left", startRecord == 0 ? 0 : 1);
prop.put("showtable_navigation_filter", typefilter.pattern()); prop.put("showtable_navigation_filter", typefilter.pattern());
prop.put("showtable_navigation_right", startRecord + maximumRecords >= filteredSize ? 0 : 1); prop.put("showtable_navigation_right", startRecord + maximumRecords >= filteredSize ? 0 : 1);
@ -555,6 +592,7 @@ public class Table_API_p {
prop.put("showtable_navigation_right_inline", (inline) ? 1 : 0); prop.put("showtable_navigation_right_inline", (inline) ? 1 : 0);
prop.put("showtable_navigation_right_filter", typefilter.pattern()); prop.put("showtable_navigation_right_filter", typefilter.pattern());
prop.put("showtable_navigation_right_query", queryParam); prop.put("showtable_navigation_right_query", queryParam);
prop.put("showtable_navigation_right_sort", sortParam);
} else { } else {
prop.put("showtable_navigation", 0); prop.put("showtable_navigation", 0);
} }
@ -562,4 +600,47 @@ public class Table_API_p {
// return rewrite properties // return rewrite properties
return prop; return prop;
} }
/**
* Fill the serverObjects instance with table columns sort properties.
*
* @param prop
* the serverObjects instance to fill. Must not be null.
* @param sortDir
* the current sort direction
* @param sortColumn
* the current sort column
*/
private static void putTableSortProperties(final serverObjects prop, final SortDirection sortDir,
final String sortColumn) {
boolean sortedByAsc = WorkTables.TABLE_API_COL_TYPE.equals(sortColumn) && sortDir == SortDirection.ASC;
prop.put("showtable_sortedByType", WorkTables.TABLE_API_COL_TYPE.equals(sortColumn));
prop.put("showtable_sortedByType_asc", sortedByAsc);
prop.put("showtable_nextSortTypeDesc", sortedByAsc);
sortedByAsc = WorkTables.TABLE_API_COL_COMMENT.equals(sortColumn) && sortDir == SortDirection.ASC;
prop.put("showtable_sortedByComment", WorkTables.TABLE_API_COL_COMMENT.equals(sortColumn));
prop.put("showtable_sortedByComment_asc", sortedByAsc);
prop.put("showtable_nextSortCommentDesc", sortedByAsc);
sortedByAsc = WorkTables.TABLE_API_COL_APICALL_COUNT.equals(sortColumn) && sortDir == SortDirection.ASC;
prop.put("showtable_sortedByApiCallCount", WorkTables.TABLE_API_COL_APICALL_COUNT.equals(sortColumn));
prop.put("showtable_sortedByApiCallCount_asc", sortedByAsc);
prop.put("showtable_nextSortApiCallCountDesc", sortedByAsc);
sortedByAsc = WorkTables.TABLE_API_COL_DATE_RECORDING.equals(sortColumn) && sortDir == SortDirection.ASC;
prop.put("showtable_sortedByDateRecording", WorkTables.TABLE_API_COL_DATE_RECORDING.equals(sortColumn));
prop.put("showtable_sortedByDateRecording_asc", sortedByAsc);
prop.put("showtable_nextSortDateRecordingDesc", sortedByAsc);
sortedByAsc = WorkTables.TABLE_API_COL_DATE_LAST_EXEC.equals(sortColumn) && sortDir == SortDirection.ASC;
prop.put("showtable_sortedByDateLastExec", WorkTables.TABLE_API_COL_DATE_LAST_EXEC.equals(sortColumn));
prop.put("showtable_sortedByDateLastExec_asc", sortedByAsc);
prop.put("showtable_nextSortDateLastExecDesc", sortedByAsc);
sortedByAsc = WorkTables.TABLE_API_COL_DATE_NEXT_EXEC.equals(sortColumn) && sortDir == SortDirection.ASC;
prop.put("showtable_sortedByDateNextExec", WorkTables.TABLE_API_COL_DATE_NEXT_EXEC.equals(sortColumn));
prop.put("showtable_sortedByDateNextExec_asc", sortedByAsc);
prop.put("showtable_nextSortDateNextExecDesc", sortedByAsc);
}
} }

@ -15,7 +15,7 @@
## "global classes" ## ## "global classes" ##
# i.e. ".strong"; ".left"; ".error"; # i.e. ".strong"; ".left"; ".error";
############################################### ###############################################
## "privat classes" ## ## "private classes" ##
# all HTML-elements with a specific class # all HTML-elements with a specific class
# i.e. "div.content"; "span.left"; # i.e. "div.content"; "span.left";
# and # and
@ -607,6 +607,12 @@ a.thumblink {
overflow: hidden; overflow: hidden;
} }
/* Link in a table header that triggers server-side table sorting */
a.sortTableLink, a.sortTableLink:link, a.sortTableLink:visited, a.sortTableLink:hover {
text-decoration: none;
color: white;
}
/*---------- /*----------
<em> <em>
*/ */

@ -3294,13 +3294,12 @@ to a scheduler for a periodic execution.==einem Scheduler für periodische Ausf
"next page"=="Keine nächste Seite" "next page"=="Keine nächste Seite"
"previous page"=="Keine vorherige Seite" "previous page"=="Keine vorherige Seite"
of #[of]#== von #[of]# of #[of]#== von #[of]#
>Date==>Datum
>Type==>Typ >Type==>Typ
>Comment==>Kommentar >Comment==>Kommentar
Call<br/>Count<==Aufruf<br/>Zähler< Call Count<==Aufruf Zähler<
Recording<==Aufzeichnungs< Recording&nbsp;Date==Aufzeichnungs&nbsp;Datum
Last&nbsp;Exec==Letzte&nbsp;Ausführung Last&nbsp;Exec&nbsp;Date==Letzte&nbsp;Ausführung&nbsp;Datum
Next&nbsp;Exec==Nächste&nbsp;Ausführung Next&nbsp;Exec&nbsp;Date==Nächste&nbsp;Ausführung&nbsp;Datum
#>URL<==>URL< #>URL<==>URL<
>Event Trigger<==>Ereignis Auslöser< >Event Trigger<==>Ereignis Auslöser<
"clone"=="Ereignis klonen" "clone"=="Ereignis klonen"

@ -1215,7 +1215,7 @@ YaCy Supporters<==Sostenitori di YaCy<
"next page"=="pagina successiva" "next page"=="pagina successiva"
"previous page"=="pagina precedente" "previous page"=="pagina precedente"
# of #[of]#== su #[of]# # of #[of]#== su #[of]#
>Date==>Data &nbsp;Date==&nbsp;Data
>URL<==>URL< >URL<==>URL<
"clone"=="clona" "clone"=="clona"
>Scheduler<==>Schedulatore< >Scheduler<==>Schedulatore<

@ -8765,9 +8765,6 @@
<trans-unit id="1449865e" xml:space="preserve" approved="no" translate="yes"> <trans-unit id="1449865e" xml:space="preserve" approved="no" translate="yes">
<source> of #[of]#</source> <source> of #[of]#</source>
</trans-unit> </trans-unit>
<trans-unit id="38a150c" xml:space="preserve" approved="no" translate="yes">
<source>&gt;Date</source>
</trans-unit>
<trans-unit id="391b498" xml:space="preserve" approved="no" translate="yes"> <trans-unit id="391b498" xml:space="preserve" approved="no" translate="yes">
<source>&gt;Type</source> <source>&gt;Type</source>
</trans-unit> </trans-unit>
@ -8775,16 +8772,16 @@
<source>&gt;Comment</source> <source>&gt;Comment</source>
</trans-unit> </trans-unit>
<trans-unit id="c2a0ac2a" xml:space="preserve" approved="no" translate="yes"> <trans-unit id="c2a0ac2a" xml:space="preserve" approved="no" translate="yes">
<source>Call&lt;br/&gt;Count&lt;</source> <source>Call Count&lt;</source>
</trans-unit> </trans-unit>
<trans-unit id="a2a91c8b" xml:space="preserve" approved="no" translate="yes"> <trans-unit id="a2a91c8b" xml:space="preserve" approved="no" translate="yes">
<source>Recording&lt;</source> <source>Recording&amp;nbsp;Date</source>
</trans-unit> </trans-unit>
<trans-unit id="9c5940cb" xml:space="preserve" approved="no" translate="yes"> <trans-unit id="9c5940cb" xml:space="preserve" approved="no" translate="yes">
<source>Last&amp;nbsp;Exec</source> <source>Last&amp;nbsp;Exec&amp;nbsp;Date</source>
</trans-unit> </trans-unit>
<trans-unit id="409928e8" xml:space="preserve" approved="no" translate="yes"> <trans-unit id="409928e8" xml:space="preserve" approved="no" translate="yes">
<source>Next&amp;nbsp;Exec</source> <source>Next&amp;nbsp;Exec&amp;nbsp;Date</source>
</trans-unit> </trans-unit>
<trans-unit id="2ef20848" xml:space="preserve" approved="no" translate="yes"> <trans-unit id="2ef20848" xml:space="preserve" approved="no" translate="yes">
<source>&gt;Event Trigger&lt;</source> <source>&gt;Event Trigger&lt;</source>

@ -3444,13 +3444,12 @@ to a scheduler for a periodic execution.==в планировщик для пе
"next page"=="следующая страница" "next page"=="следующая страница"
"previous page"=="предыдущая страница" "previous page"=="предыдущая страница"
of #[of]#== по #[of]# of #[of]#== по #[of]#
>Date==>Дата
>Type==>Тип >Type==>Тип
>Comment==>Комментарий >Comment==>Комментарий
Call<br/>Count<==Количество<br/>вызовов< Call Count<==Количество вызовов<
Recording<==Запись< Recording&nbsp;Date==Запись&nbsp;Дата
Last&nbsp;Exec==Дата&nbsp;последнего запуска Last&nbsp;Exec&nbsp;Date==Дата&nbsp;последнего запуска&nbsp;Дата
Next&nbsp;Exec==Дата&nbsp;следующего запуска Next&nbsp;Exec&nbsp;Date==Дата&nbsp;следующего запуска&nbsp;Дата
#>URL<==>URL-адрес< #>URL<==>URL-адрес<
>Event Trigger<==>Триггер событий< >Event Trigger<==>Триггер событий<
"clone"=="клонировать" "clone"=="клонировать"

@ -2993,10 +2993,10 @@ to a scheduler for a periodic execution.==для періодичного сам
of #[of]#== з #[of]# of #[of]#== з #[of]#
>Type==>Тип >Type==>Тип
>Comment==>Примітка >Comment==>Примітка
Call<br/>Count<==Виклики< Call Count<==Виклики<
>Recording<br/>Date<==>Дата<br/>запису< >Recording&nbsp;Date<==>Дата&nbsp;запису<
>Last&nbsp;Exec<br/>Date<==>Останній<br/>запуск< >Last&nbsp;Exec&nbsp;Date<==>Останній&nbsp;запуск<
>Next&nbsp;Exec<br/>Date<==>Наступний<br/>запуск< >Next&nbsp;Exec&nbsp;Date<==>Наступний&nbsp;запуск<
>Scheduler<==>Планувальник< >Scheduler<==>Планувальник<
>no repetition<==>без повторення< >no repetition<==>без повторення<
>activate scheduler<==>з плануванням< >activate scheduler<==>з плануванням<

@ -3307,13 +3307,12 @@ to a scheduler for a periodic execution.==或者用于周期执行一系列动
"next page"=="下一页" "next page"=="下一页"
"previous page"=="上一页" "previous page"=="上一页"
of #[of]#== 共 #[of]# of #[of]#== 共 #[of]#
>Date==>日期
>Type==>类型 >Type==>类型
>Comment==>注释 >Comment==>注释
Call<br/>Count<==调用<br/>次数< Call Count<==调用 次数<
Recording<==正在记录< Recording&nbsp;Date==正在记录&nbsp;日期
Last&nbsp;Exec==上次&nbsp;执行 Last&nbsp;Exec&nbsp;Date==上次&nbsp;执行&nbsp;日期
Next&nbsp;Exec==下次&nbsp;执行 Next&nbsp;Exec&nbsp;Date==下次&nbsp;执行&nbsp;日期
>Scheduler<==>定时器< >Scheduler<==>定时器<
#>URL<==>URL #>URL<==>URL
>no repetition<==>无安排< >no repetition<==>无安排<

@ -33,6 +33,7 @@ import java.text.ParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -40,7 +41,6 @@ import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -481,20 +481,138 @@ public class Tables implements Iterable<String> {
return new OrderedRowIterator(table, wherePattern, up); return new OrderedRowIterator(table, wherePattern, up);
} }
public static Collection<Row> orderBy(final Iterator<Row> rowIterator, int maxcount, final String sortColumn) { /**
final TreeMap<String, Row> sortTree = new TreeMap<String, Row>(); * @param rowIterator
Row row; * an open iterator on a table. Must not be null.
byte[] r; * @param sortColumn
while ((maxcount < 0 || maxcount-- > 0) && rowIterator.hasNext()) { * the name of the column to use for sorting.
row = rowIterator.next(); * @return all the rows of the table sorted in ascending order on the given
r = row.get(sortColumn); * column name
if (r == null) { */
sortTree.put("0000" + UTF8.String(row.pk), row); public static Collection<Row> orderBy(final Iterator<Row> rowIterator, final String sortColumn) {
} else { return orderByString(rowIterator, sortColumn, "", SortDirection.ASC);
sortTree.put(UTF8.String(r) + UTF8.String(row.pk), row); }
/**
* @param rowIterator
* an open iterator on a table. Must not be null.
* @param sortColumn
* the name of the column to use for sorting.
* @param defaultValue
* the default value to use when the column value is null.
* @param sortDir
* the sorting direction. When null, {@link SortDirection#ASC} is applied.
* @return all the rows of the table sorted on the given column name
*/
public static Collection<Row> orderByInt(final Iterator<Row> rowIterator, final String sortColumn,
final int defaultValue, final SortDirection sortDir) {
/* Compare first on the given column */
Comparator<Row> comparator = Comparator.<Row>comparingInt(row -> row.get(sortColumn, defaultValue));
/*
* Then in case of equality, compare on the primary key. Ensure also that
* eventual null rows do not make the process fail.
*/
comparator = Comparator.nullsFirst(comparator.thenComparing(row -> UTF8.String(row.pk)));
if (sortDir == SortDirection.DESC) {
comparator = comparator.reversed();
}
return orderBy(rowIterator, comparator);
}
/**
* @param rowIterator
* an open iterator on a table. Must not be null.
* @param sortColumn
* the name of the column to use for sorting.
* @param defaultValue
* the default value to use when the column value is null.
* @param sortDir
* the sorting direction. When null, {@link SortDirection#ASC} is applied.
* @return all the rows of the table sorted on the given column name
*/
public static Collection<Row> orderByLong(final Iterator<Row> rowIterator, final String sortColumn,
final long defaultValue, final SortDirection sortDir) {
/* Compare first on the given column */
Comparator<Row> comparator = Comparator.<Row>comparingLong(row -> row.get(sortColumn, defaultValue));
/*
* Then in case of equality, compare on the primary key. Ensure also that
* eventual null rows do not make the process fail.
*/
comparator = Comparator.nullsFirst(comparator.thenComparing(row -> UTF8.String(row.pk)));
if (sortDir == SortDirection.DESC) {
comparator = comparator.reversed();
}
return orderBy(rowIterator, comparator);
}
/**
* @param rowIterator
* an open iterator on a table. Must not be null.
* @param sortColumn
* the name of the column to use for sorting.
* @param defaultValue
* the default value to use when the column value is null.
* @param sortDir
* the sorting direction. When null, {@link SortDirection#ASC} is applied.
* @return all the rows of the table sorted on the given column name
*/
public static Collection<Row> orderByString(final Iterator<Row> rowIterator, final String sortColumn,
final String defaultValue, final SortDirection sortDir) {
/* Compare first on the given column */
Comparator<Row> comparator = Comparator
.nullsFirst(Comparator.<Row, String>comparing(row -> row.get(sortColumn, defaultValue)));
/*
* Then in case of equality, compare on the primary key. Ensure also that
* eventual null rows do not make the process fail.
*/
comparator = Comparator.nullsFirst(comparator.thenComparing(row -> UTF8.String(row.pk)));
if (sortDir == SortDirection.DESC) {
comparator = comparator.reversed();
}
return orderBy(rowIterator, comparator);
}
/**
* @param rowIterator
* an open iterator on a table. Must not be null.
* @param sortColumn
* the name of the column to use for sorting.
* @param defaultValue
* the default value to use when the column value is null.
* @param sortDir
* the sorting direction. When null, {@link SortDirection#ASC} is applied.
* @return all the rows of the table sorted on the given column name
*/
public static Collection<Row> orderByDate(final Iterator<Row> rowIterator, final String sortColumn,
final Date defaultValue, final SortDirection sortDir) {
/* Compare first on the given column */
Comparator<Row> comparator = Comparator
.nullsFirst(Comparator.<Row, Date>comparing(row -> row.get(sortColumn, defaultValue)));
/*
* Then in case of equality, compare on the primary key. Ensure also that
* eventual null rows do not make the process fail.
*/
comparator = Comparator.nullsFirst(comparator.thenComparing(row -> UTF8.String(row.pk)));
if (sortDir == SortDirection.DESC) {
comparator = comparator.reversed();
} }
return orderBy(rowIterator, comparator);
}
/**
* @param rowIterator
* an open iterator on a table. Must not be null.
* @param comparator
* the eventual comparator to use.
* @return all the rows of the table sorted using the given comparator, or
* sorted on rows natural order when comparator is null.
*/
public static Collection<Row> orderBy(final Iterator<Row> rowIterator, final Comparator<Row> comparator) {
final TreeSet<Row> sortTree = new TreeSet<Row>(comparator);
while (rowIterator.hasNext()) {
sortTree.add(rowIterator.next());
} }
return sortTree.values(); return sortTree;
} }
public ArrayList<String> columns(final String table) throws IOException { public ArrayList<String> columns(final String table) throws IOException {
@ -502,6 +620,14 @@ public class Tables implements Iterable<String> {
return heap.columns(); return heap.columns();
} }
/** Sort direction for ordering rows */
public enum SortDirection {
/** Ascending order */
ASC,
/** Descending order */
DESC
}
public class HeapRowIterator extends LookAheadIterator<Row> implements Iterator<Row> { public class HeapRowIterator extends LookAheadIterator<Row> implements Iterator<Row> {
private final String whereColumn; private final String whereColumn;

@ -188,6 +188,7 @@ import net.yacy.http.YaCyHttpServer;
import net.yacy.kelondro.blob.ArrayStack; import net.yacy.kelondro.blob.ArrayStack;
import net.yacy.kelondro.blob.BEncodedHeap; import net.yacy.kelondro.blob.BEncodedHeap;
import net.yacy.kelondro.blob.Tables; import net.yacy.kelondro.blob.Tables;
import net.yacy.kelondro.blob.Tables.SortDirection;
import net.yacy.kelondro.data.meta.URIMetadataNode; import net.yacy.kelondro.data.meta.URIMetadataNode;
import net.yacy.kelondro.data.word.Word; import net.yacy.kelondro.data.word.Word;
import net.yacy.kelondro.logging.GuiHandler; import net.yacy.kelondro.logging.GuiHandler;
@ -2495,7 +2496,7 @@ public final class Switchboard extends serverSwitch {
final Date now = new Date(); final Date now = new Date();
try { try {
final Iterator<Tables.Row> plainIterator = this.tables.iterator(WorkTables.TABLE_API_NAME); final Iterator<Tables.Row> plainIterator = this.tables.iterator(WorkTables.TABLE_API_NAME);
final Iterator<Tables.Row> mapIterator = Tables.orderBy(plainIterator, -1, WorkTables.TABLE_API_COL_DATE_LAST_EXEC).iterator(); final Iterator<Tables.Row> mapIterator = Tables.orderByDate(plainIterator, WorkTables.TABLE_API_COL_DATE_LAST_EXEC, null, SortDirection.ASC).iterator();
while (mapIterator.hasNext()) { while (mapIterator.hasNext()) {
row = mapIterator.next(); row = mapIterator.next();
if (row == null) continue; if (row == null) continue;

Loading…
Cancel
Save