Changeset 5954


Ignore:
Timestamp:
01/26/15 15:12:46 (9 years ago)
Author:
emanuel.dima@uni-tuebingen.de
Message:
  1. alpha14: collections view stable sorting, better filtering; upfront diagnostic messages for search
Location:
SRUAggregator/trunk
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • SRUAggregator/trunk/aggregator_development.yml

    r5919 r5954  
    44
    55  AGGREGATOR_FILE_PATH: /Users/edima/fcsAggregatorCorpora.json
    6   SCAN_MAX_DEPTH: 3
    7   SCAN_TASK_INITIAL_DELAY: 12
    8   SCAN_TASK_INTERVAL: 24
     6  SCAN_MAX_DEPTH: 2
     7  SCAN_TASK_INITIAL_DELAY: 6
     8  SCAN_TASK_INTERVAL: 12
    99  SCAN_TASK_TIME_UNIT: HOURS
    1010
     
    1313
    1414
    15   ENDPOINTS_SCAN_TIMEOUT_MS: 10000
     15  ENDPOINTS_SCAN_TIMEOUT_MS: 60000
    1616  ENDPOINTS_SEARCH_TIMEOUT_MS: 10000
    1717  EXECUTOR_SHUTDOWN_TIMEOUT_MS: 100
  • SRUAggregator/trunk/pom.xml

    r5931 r5954  
    88        <groupId>eu.clarin.sru.fcs</groupId>
    99        <artifactId>Aggregator2</artifactId>
    10         <version>2.0.0-alpha-12</version>
     10        <version>2.0.0-alpha-14</version>
    1111        <name>FCS Aggregator</name>
    1212
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/app/Aggregator.java

    r5931 r5954  
    8686 * @author edima
    8787 *
    88  * TODO: fix ordering of corpora in corpora view
    89  *
    90  * TODO: corpora search should not indicate the ones that don't match
     88 * TODO: support new spec-compatible centres, see Oliver's mail
     89 * (use SRUClient's extraResponseData POJOs)
     90 *
     91 * TODO: version page: credits, open source, see vcr/version page
     92 *
     93 * TODO: statistics page linked from version page
     94 *
     95 * TODO: add diagnostics messages to statistics page
     96 *
     97 * TODO: disable popups easily
     98 *
     99 * TODO: Fix activeSearch memory leak (gc searches older than...)
     100 *
     101 * TODO: Use weblicht with results
     102 *
     103 * TODO: Export to personal workspace as csv, excel, tcf, plain text
     104 *
     105 * TODO: Download to personal workspace as csv, excel, tcf, plain text
     106 *
     107 * TODO: websockets
     108 *
     109 * TODO: atomic replace of cached corpora (file)
     110 *
     111 * TODO: show multiple hits on the same result in multiple rows, linked visually
     112 *
     113 * TODO: zoom into the results from a corpus, allow functionality only for
     114 * the view (search for next set of results)
     115 *
     116 * TODO: optimise page load
     117 *
     118 * TODO: test it in IE, other browsers
    91119 *
    92120 * TODO: tri-state for parent collections; search + message implications
    93  *
    94  * TODO: version page: credits, open source, see vcr/version page
    95  *
    96  * TODO: statistics page liked from version page
    97  *
    98  * TODO: 1. support new spec-compatible centres, see Oliver's mail
    99  * (use SRUClient's extraResponseData POJOs)
    100  *
    101  * TODO: 2. zoom into the results from a corpus, allow functionality only for
    102  * the view (search for next set of results)
    103  *
    104  * TODO: disable popups easily
    105  *
    106  * TODO: Fix activeSearch memory leak (gc searches older than...)
    107  *
    108  * TODO: Use weblicht with results
    109  *
    110  * TODO: Export to personal workspace as csv, excel, tcf, plain text
    111  *
    112  * TODO: Download to personal workspace as csv, excel, tcf, plain text
    113  *
    114  * TODO: websockets
    115  *
    116  * TODO: atomic replace of cached corpora (file)
    117  *
    118  * TODO: show multiple hits on the same result in multiple rows, linked visually
    119  *
    120  * TODO: optimise page load
    121121 *
    122122 * TODO: improve help page text
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/rest/RestService.java

    r5931 r5954  
    107107        }
    108108
    109         @GET
    110         @Path("diagnostics")
    111         public Response getDiagnostics() throws IOException {
    112                 Map<String, Diagnostic> diagnostics = Aggregator.getInstance().getCorpora().getEndpointDiagnostics();
    113                 return Response.ok(toJson(diagnostics)).build();
    114         }
    115 
    116109        @POST
    117110        @Path("search")
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/scan/Corpora.java

    r5900 r5954  
    44import java.util.ArrayList;
    55import java.util.Collections;
    6 import java.util.HashMap;
    76import java.util.HashSet;
    87import java.util.List;
    9 import java.util.Map;
    108import java.util.Set;
    119import org.slf4j.LoggerFactory;
     
    2321
    2422        @JsonProperty
    25         private Map<String, Diagnostic> endpointDiagnostics = Collections.synchronizedMap(new HashMap<String, Diagnostic>());
    26         @JsonProperty
    2723        private List<Institution> institutions = Collections.synchronizedList(new ArrayList<Institution>());
    2824        @JsonProperty
     
    3531        public List<Corpus> getCorpora() {
    3632                return Collections.unmodifiableList(corpora);
    37         }
    38 
    39         public Map<String, Diagnostic> getEndpointDiagnostics() {
    40                 return Collections.unmodifiableMap(endpointDiagnostics);
    4133        }
    4234
     
    5547                }
    5648                return true;
    57         }
    58 
    59         public void addEndpointDiagnostic(String endpoint, Diagnostic diagnostic) {
    60                 endpointDiagnostics.put(endpoint, diagnostic);
    6149        }
    6250
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/scan/Diagnostic.java

    r5900 r5954  
    66public class Diagnostic {
    77
    8         private String uri;
    9         private String context;
    10         private String message;
    11         private String diagnostic;
     8        private String reqEndpointUrl, reqContext;
     9        private String dgnUri, dgnMessage, dgnDiagnostic;
    1210
    13         public Diagnostic(String uri, String context, String message, String diagnostic) {
    14                 this.uri = uri;
    15                 this.context = context;
    16                 this.message = message;
    17                 this.diagnostic = diagnostic;
     11        public Diagnostic(String reqEndpointUrl, String reqContext, String dgnUri, String dgnMessage, String dgnDiagnostic) {
     12                this.reqEndpointUrl = reqEndpointUrl;
     13                this.reqContext = reqContext;
     14                this.dgnUri = dgnUri;
     15                this.dgnMessage = dgnMessage;
     16                this.dgnDiagnostic = dgnDiagnostic;
    1817        }
    1918
     
    2120        }
    2221
    23         public String getUri() {
    24                 return uri;
     22        public String getDgnDiagnostic() {
     23                return dgnDiagnostic;
    2524        }
    2625
    27         public String getContext() {
    28                 return context;
     26        public String getDgnMessage() {
     27                return dgnMessage;
    2928        }
    3029
    31         public String getMessage() {
    32                 return message;
     30        public String getDgnUri() {
     31                return dgnUri;
    3332        }
    3433
    35         public String getDiagnostic() {
    36                 return diagnostic;
     34        public String getReqContext() {
     35                return reqContext;
    3736        }
    3837
    39         public void setUri(String uri) {
    40                 this.uri = uri;
     38        public String getReqEndpointUrl() {
     39                return reqEndpointUrl;
    4140        }
    4241
    43         public void setMessage(String message) {
    44                 this.message = message;
     42        public void setDgnDiagnostic(String dgnDiagnostic) {
     43                this.dgnDiagnostic = dgnDiagnostic;
    4544        }
    4645
    47         public void setContext(String context) {
    48                 this.context = context;
     46        public void setDgnMessage(String dgnMessage) {
     47                this.dgnMessage = dgnMessage;
    4948        }
    5049
    51         public void setDiagnostic(String diagnostic) {
    52                 this.diagnostic = diagnostic;
     50        public void setDgnUri(String dgnUri) {
     51                this.dgnUri = dgnUri;
     52        }
     53
     54        public void setReqContext(String reqContext) {
     55                this.reqContext = reqContext;
     56        }
     57
     58        public void setReqEndpointUrl(String reqEndpointUrl) {
     59                this.reqEndpointUrl = reqEndpointUrl;
    5360        }
    5461
     
    5663        public int hashCode() {
    5764                https://primes.utm.edu/lists/small/1000.txt
    58                 return uri.hashCode() * 967 + context.hashCode() * 797
    59                                 + message.hashCode() * 1669 + diagnostic.hashCode();
     65                return reqEndpointUrl.hashCode() * 967 + reqContext.hashCode() * 797
     66                                + dgnUri.hashCode() * 1669 + dgnMessage.hashCode() * 31
     67                                + dgnDiagnostic.hashCode();
    6068        }
    6169
     
    6674                }
    6775                Diagnostic d = (Diagnostic) obj;
    68                 return uri.equals(d.uri) && message.equals(d.message)
    69                                 && context.equals(d.context) && diagnostic.equals(d.diagnostic);
     76                return reqEndpointUrl.equals(d.reqEndpointUrl)
     77                                && reqContext.equals(d.reqContext)
     78                                && dgnUri.equals(d.dgnUri)
     79                                && dgnMessage.equals(d.dgnMessage)
     80                                && dgnDiagnostic.equals(d.dgnDiagnostic);
    7081        }
    7182}
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/scan/ScanCrawler.java

    r5901 r5954  
    77import eu.clarin.sru.client.SRUScanResponse;
    88import eu.clarin.sru.client.SRUTerm;
    9 import eu.clarin.sru.client.SRUVersion;
    10 import eu.clarin.sru.fcs.aggregator.app.Aggregator;
    119import eu.clarin.sru.fcs.aggregator.client.ThrottledClient;
    1210import eu.clarin.sru.fcs.aggregator.util.SRUCQL;
     
    137135                                if (response != null && response.hasDiagnostics()) {
    138136                                        for (SRUDiagnostic d : response.getDiagnostics()) {
    139                                                 String context = SRUCQL.SCAN_RESOURCE_PARAMETER + "=" + normalizeHandle(parentCorpus);
    140                                                 Diagnostic diag = new Diagnostic(d.getURI(), context, d.getMessage(), d.getDetails());
    141                                                 corpora.addEndpointDiagnostic(endpointUrl, diag);
    142                                                 log.info("Diagnostic: {}: {}: {}", d.getURI(), context, d.getMessage(), d.getDetails());
     137                                                SRUScanRequest request = response.getRequest();
     138
     139                                                String handle = SRUCQL.SCAN_RESOURCE_PARAMETER + "=" + normalizeHandle(parentCorpus);
     140                                                Diagnostic diag = new Diagnostic(request.getBaseURI().toString(), handle,
     141                                                                d.getURI(), d.getMessage(), d.getDetails());
     142                                                statistics.addEndpointDiagnostic(institution, endpointUrl, diag);
     143                                                log.info("Diagnostic: {} {}: {} {} {}", diag.getReqEndpointUrl(), diag.getReqContext(),
     144                                                                diag.getDgnUri(), diag.getDgnMessage(), diag.getDgnDiagnostic());
    143145                                        }
    144146                                }
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/scan/Statistics.java

    r5894 r5954  
    1919                List<Long> executionTimes = Collections.synchronizedList(new ArrayList<Long>());
    2020
     21                @JsonProperty
     22                List<Diagnostic> diagnostics = Collections.synchronizedList(new ArrayList<Diagnostic>());
    2123                @JsonProperty
    2224                Map<String, Integer> errors = Collections.synchronizedMap(new HashMap<String, Integer>());
     
    7880        }
    7981
     82        public void addEndpointDiagnostic(Institution institution, String endpoint, Diagnostic diag) {
     83                EndpointStats stats = getEndpointStats(institution, endpoint);
     84                stats.diagnostics.add(diag);
     85        }
     86
    8087        public void addErrorDatapoint(Institution institution, String endpoint, SRUClientException error) {
    8188                EndpointStats stats = getEndpointStats(institution, endpoint);
  • SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/search/Result.java

    r5931 r5954  
    22
    33import eu.clarin.sru.client.SRUClientException;
     4import eu.clarin.sru.client.SRUDiagnostic;
    45import eu.clarin.sru.client.SRURecord;
     6import eu.clarin.sru.client.SRUSearchRetrieveRequest;
    57import eu.clarin.sru.fcs.aggregator.scan.Corpus;
    68import eu.clarin.sru.client.SRUSearchRetrieveResponse;
     
    1214import eu.clarin.sru.client.fcs.DataViewHits;
    1315import eu.clarin.sru.client.fcs.Resource;
     16import eu.clarin.sru.fcs.aggregator.scan.Diagnostic;
    1417import java.util.ArrayList;
     18import java.util.Collections;
    1519import java.util.List;
    1620import org.w3c.dom.Node;
     
    3236        private List<Kwic> kwics = new ArrayList<Kwic>();
    3337        private SRUClientException exception;
     38        private List<Diagnostic> diagnostics = new ArrayList<Diagnostic>();
    3439
    3540        public List<Kwic> getKwics() {
     
    4449                        setResponse(response);
    4550                }
     51                if (response != null && response.hasDiagnostics()) {
     52                        setDiagnostics(response);
     53                }
    4654        }
    4755
    48         public void setResponse(SRUSearchRetrieveResponse response) {
     56        void setResponse(SRUSearchRetrieveResponse response) {
    4957                for (SRURecord record : response.getRecords()) {
    5058                        if (record.isRecordSchema(ClarinFCSRecordData.RECORD_SCHEMA)) {
     
    6169                                log.info("Unsupported schema: {0}", record.getRecordSchema());
    6270                        }
     71                }
     72        }
     73
     74        void setDiagnostics(SRUSearchRetrieveResponse response) {
     75                for (SRUDiagnostic d : response.getDiagnostics()) {
     76                        SRUSearchRetrieveRequest srurequest = response.getRequest();
     77                        diagnostics.add(new Diagnostic(srurequest.getBaseURI().toString(),
     78                                        srurequest.getQuery(),
     79                                        d.getURI(), d.getMessage(), d.getDetails()));
    6380                }
    6481        }
     
    111128        }
    112129
     130        public List<Diagnostic> getDiagnostics() {
     131                return Collections.unmodifiableList(diagnostics);
     132        }
     133
    113134        public int getStartRecord() {
    114135                return request.getStartRecord();
     
    126147                return request.getSearchString();
    127148        }
    128 
    129149}
  • SRUAggregator/trunk/src/main/resources/assets/index.html

    r5931 r5954  
    4646                                                <a title="about" id="aboutlink" href="about">
    4747                                                <span class="glyphicon glyphicon-info-sign"></span>
    48                                                 <span>VERSION 2.0.0.α12</span>
     48                                                <span>VERSION 2.0.0.α14</span>
    4949                                        </a>
    5050                                </div>
     
    7070        <script src="lib/jquery.min.js"></script>
    7171        <script src="lib/react-with-addons.js"></script>
     72        <script src="lib/react-router.min.js"></script>
    7273        <script src="lib/bootstrap.min.js"></script>
    7374        <script src="js/components.js"></script>
  • SRUAggregator/trunk/src/main/resources/assets/js/corpora.js

    r5931 r5954  
    2525
    2626        handleChange: function(event) {
    27                 this.setState({query: event.target.value});
    28                 this.props.search(event.target.value);
     27                var query = event.target.value;
     28                this.setState({query: query});
     29
     30                if (query.length === 0 || 2 <= query.length) {
     31                        this.props.search(query);
     32                }
    2933                event.stopPropagation();
    3034        },
     
    5155        },
    5256
    53         toggleSelection: function (corpus) {
     57        toggleSelection: function (corpus, e) {
    5458                var s = !corpus.selected;
    5559                this.props.corpora.recurseCorpus(corpus, function(c) { c.selected = s; });
    5660                this.props.corpora.update();
     61                this.stop(e);
    5762        },
    5863
     
    7681                };
    7782
    78                 this.props.corpora.recurse(function(corpus) { corpus.subCorpora.sort(sortFn); });
    79                 this.props.corpora.corpora.sort(sortFn);
    80 
    8183                query = query.toLowerCase();
    82                 var querytokens = query.split(" ");
    8384                if (!query) {
    8485                        this.props.corpora.recurse(function(corpus) {corpus.priority = 1; });
     
    9394
    9495                // find priority for each corpus
     96                var querytokens = query.split(" ").filter(function(x){ return x.length > 0; });
    9597                this.props.corpora.recurse(function(corpus){
    9698                        var title = corpus.title ? corpus.title : corpus.displayName;
     
    121123                }.bind(this));
    122124
    123                 // ensure root corpora have nonnull priority
    124                 this.props.corpora.recurse(function(corpus){
    125                         if (corpus.subCorpora) {
    126                                 corpus.subCorpora.forEach(function(subcorpus){
    127                                         if (subcorpus.priority > 0 && corpus.priority === 0)
    128                                                 corpus.priority ++;
    129                                 });
     125                // ensure parents of visible corpora are also visible; maximum depth = 3
     126                var isVisibleFn = function(corpus){ return corpus.priority > 0; };
     127                var parentBooster = function(corpus){
     128                        if (corpus.priority <= 0 && corpus.subCorpora) {
     129                                if (corpus.subCorpora.some(isVisibleFn)) {
     130                                        corpus.priority = 0.5;
     131                                }
    130132                        }
    131                 });
     133                };
     134                for (var i = 3; i > 0; i --) {
     135                        this.props.corpora.recurse(parentBooster);
     136                }
    132137
    133138                this.props.corpora.recurse(function(corpus) { corpus.subCorpora.sort(sortFn); });
     
    136141                // display
    137142                this.props.corpora.update();
    138                 // console.log("corpus search done", query);
     143        },
     144
     145        stop: function(e) {
     146                e.stopPropagation();
    139147        },
    140148
     
    167175                                                        React.createElement("span", {className: "glyphicon glyphicon-plus", 'aria-hidden': "true"}),
    168176                                               
    169                                                 corpus.expanded ? " Collapse ":" Expand ", " ", corpus.subCorpora.length, " subcollections"
     177                                                corpus.expanded ? " Collapse ":" Expand ", " (", corpus.subCorpora.length, " subcollections)"
    170178                                        )
    171179                                );
     
    179187        },
    180188
     189        renderFilteredMessage: function() {
     190                var total = 0;
     191                var visible = 0;
     192                this.props.corpora.recurse(function(corpus){
     193                        if (corpus.visible) {
     194                                total ++;
     195                                if (corpus.priority > 0) {
     196                                        visible++;
     197                                }
     198                        }
     199                });
     200                if (visible === total) {
     201                        return false;
     202                }
     203                return  React.createElement("div", null, " Showing ", visible, " out of ", total, " (sub)collections. ");
     204        },
     205
    181206        renderCorpus: function(level, minmaxp, corpus) {
    182                 if (!corpus.visible) {
     207                if (!corpus.visible || corpus.priority <= 0) {
    183208                        return false;
    184209                }
     
    187212                var corpusContainerClass = "corpus-container "+(corpus.priority>0?"":"dimmed");
    188213
    189                 var hue = 80 * corpus.priority / minmaxp[1];
    190                 if (corpus.priority > 0) { hue += 40; }
     214                var hue = 120 * corpus.priority / minmaxp[1];
    191215                var color = minmaxp[0] === minmaxp[1] ? 'transparent' : 'hsl('+hue+', 50%, 50%)';
    192                 var priorityStyle = {paddingBottom: 4, paddingLeft: 2, borderBottom: '2px solid '+color };
    193                 var expansive = corpus.expanded ? {}
     216                var priorityStyle = {paddingBottom: 4, paddingLeft: 2, borderBottom: '3px solid '+color };
     217                var expansive = corpus.expanded ? {overflow:'hidden'}
    194218                        : {whiteSpace:'nowrap', overflow:'hidden', textOverflow: 'ellipsis'};
    195219                var title = corpus.title || corpus.displayName;
     
    204228                                                        React.createElement("div", {style: indent},
    205229                                                                React.createElement("h3", {style: expansive},
    206                                                                          corpus.landingPage ? React.createElement("a", {href: corpus.landingPage}, title): title
     230                                                                        title,
     231                                                                         corpus.landingPage ?
     232                                                                                React.createElement("a", {href: corpus.landingPage, onClick: this.stop},
     233                                                                                        React.createElement("span", {style: {fontSize:12}}, " – Homepage "), React.createElement("i", {className: "fa fa-home"})
     234                                                                                ): false
    207235                                                                ),
    208236
    209                                                                 React.createElement("p", {style: expansive}, corpus.description)
    210                                                         ),
    211                                                         this.renderExpansion(corpus)
     237
     238                                                                React.createElement("p", {style: expansive}, corpus.description),
     239                                                                this.renderExpansion(corpus)
     240                                                        )
    212241                                                ),
    213242                                                React.createElement("div", {className: "col-sm-3 vcenter"},
     
    234263                                                ),
    235264                                                React.createElement("div", {className: "float-right inline"},
    236                                                         React.createElement("div", {className: "inline", style: { marginRight: 20}},
    237                                                                 React.createElement(SearchCorpusBox, {search: this.searchCorpus})
    238                                                         ),
    239265                                                        React.createElement("button", {className: "btn btn-default", style: { marginRight: 10}, onClick: this.selectAll.bind(this,true)},
    240266                                                                " Select all"),
    241267                                                        React.createElement("button", {className: "btn btn-default", style: { marginRight: 20}, onClick: this.selectAll.bind(this,false)},
    242268                                                                " Deselect all")
     269                                                ),
     270                                                React.createElement("div", {className: "float-right inline"},
     271                                                        React.createElement("div", {className: "inline", style: { marginRight: 20}},
     272                                                                React.createElement(SearchCorpusBox, {search: this.searchCorpus}),
     273                                                                this.renderFilteredMessage()
     274                                                        )
    243275                                                )
    244276                                        ),
     277                                       
    245278                                        this.props.corpora.corpora.map(this.renderCorpus.bind(this, 0, minmaxp))
    246279                                );
  • SRUAggregator/trunk/src/main/resources/assets/js/corpora.jsx

    r5931 r5954  
    2525
    2626        handleChange: function(event) {
    27                 this.setState({query: event.target.value});
    28                 this.props.search(event.target.value);
     27                var query = event.target.value;
     28                this.setState({query: query});
     29
     30                if (query.length === 0 || 2 <= query.length) {
     31                        this.props.search(query);
     32                }
    2933                event.stopPropagation();
    3034        },
     
    5155        },
    5256
    53         toggleSelection: function (corpus) {
     57        toggleSelection: function (corpus, e) {
    5458                var s = !corpus.selected;
    5559                this.props.corpora.recurseCorpus(corpus, function(c) { c.selected = s; });
    5660                this.props.corpora.update();
     61                this.stop(e);
    5762        },
    5863
     
    7681                };
    7782
    78                 this.props.corpora.recurse(function(corpus) { corpus.subCorpora.sort(sortFn); });
    79                 this.props.corpora.corpora.sort(sortFn);
    80 
    8183                query = query.toLowerCase();
    82                 var querytokens = query.split(" ");
    8384                if (!query) {
    8485                        this.props.corpora.recurse(function(corpus) {corpus.priority = 1; });
     
    9394
    9495                // find priority for each corpus
     96                var querytokens = query.split(" ").filter(function(x){ return x.length > 0; });
    9597                this.props.corpora.recurse(function(corpus){
    9698                        var title = corpus.title ? corpus.title : corpus.displayName;
     
    121123                }.bind(this));
    122124
    123                 // ensure root corpora have nonnull priority
    124                 this.props.corpora.recurse(function(corpus){
    125                         if (corpus.subCorpora) {
    126                                 corpus.subCorpora.forEach(function(subcorpus){
    127                                         if (subcorpus.priority > 0 && corpus.priority === 0)
    128                                                 corpus.priority ++;
    129                                 });
     125                // ensure parents of visible corpora are also visible; maximum depth = 3
     126                var isVisibleFn = function(corpus){ return corpus.priority > 0; };
     127                var parentBooster = function(corpus){
     128                        if (corpus.priority <= 0 && corpus.subCorpora) {
     129                                if (corpus.subCorpora.some(isVisibleFn)) {
     130                                        corpus.priority = 0.5;
     131                                }
    130132                        }
    131                 });
     133                };
     134                for (var i = 3; i > 0; i --) {
     135                        this.props.corpora.recurse(parentBooster);
     136                }
    132137
    133138                this.props.corpora.recurse(function(corpus) { corpus.subCorpora.sort(sortFn); });
     
    136141                // display
    137142                this.props.corpora.update();
    138                 // console.log("corpus search done", query);
     143        },
     144
     145        stop: function(e) {
     146                e.stopPropagation();
    139147        },
    140148
     
    167175                                                        <span className="glyphicon glyphicon-plus" aria-hidden="true"/>
    168176                                                }
    169                                                 {corpus.expanded ? " Collapse ":" Expand "} {corpus.subCorpora.length} subcollections
     177                                                {corpus.expanded ? " Collapse ":" Expand "} ({corpus.subCorpora.length} subcollections)
    170178                                        </a>
    171179                                </div>;
     
    179187        },
    180188
     189        renderFilteredMessage: function() {
     190                var total = 0;
     191                var visible = 0;
     192                this.props.corpora.recurse(function(corpus){
     193                        if (corpus.visible) {
     194                                total ++;
     195                                if (corpus.priority > 0) {
     196                                        visible++;
     197                                }
     198                        }
     199                });
     200                if (visible === total) {
     201                        return false;
     202                }
     203                return  <div> Showing {visible} out of {total} (sub)collections. </div>;
     204        },
     205
    181206        renderCorpus: function(level, minmaxp, corpus) {
    182                 if (!corpus.visible) {
     207                if (!corpus.visible || corpus.priority <= 0) {
    183208                        return false;
    184209                }
     
    187212                var corpusContainerClass = "corpus-container "+(corpus.priority>0?"":"dimmed");
    188213
    189                 var hue = 80 * corpus.priority / minmaxp[1];
    190                 if (corpus.priority > 0) { hue += 40; }
     214                var hue = 120 * corpus.priority / minmaxp[1];
    191215                var color = minmaxp[0] === minmaxp[1] ? 'transparent' : 'hsl('+hue+', 50%, 50%)';
    192                 var priorityStyle = {paddingBottom: 4, paddingLeft: 2, borderBottom: '2px solid '+color };
    193                 var expansive = corpus.expanded ? {}
     216                var priorityStyle = {paddingBottom: 4, paddingLeft: 2, borderBottom: '3px solid '+color };
     217                var expansive = corpus.expanded ? {overflow:'hidden'}
    194218                        : {whiteSpace:'nowrap', overflow:'hidden', textOverflow: 'ellipsis'};
    195219                var title = corpus.title || corpus.displayName;
     
    203227                                                <div className="col-sm-8 vcenter">
    204228                                                        <div style={indent}>
    205                                                                 <h3 style={expansive}>
    206                                                                         { corpus.landingPage ? <a href={corpus.landingPage}>{title}</a>: title }
     229                                                                <h3 style={expansive}>
     230                                                                        {title}
     231                                                                        { corpus.landingPage ?
     232                                                                                <a href={corpus.landingPage} onClick={this.stop}>
     233                                                                                        <span style={{fontSize:12}}> – Homepage </span><i className="fa fa-home"/>
     234                                                                                </a>: false}
    207235                                                                </h3>
    208236
     237
    209238                                                                <p style={expansive}>{corpus.description}</p>
     239                                                                {this.renderExpansion(corpus)}
    210240                                                        </div>
    211                                                         {this.renderExpansion(corpus)}
    212241                                                </div>
    213242                                                <div className="col-sm-3 vcenter">
     
    234263                                                </div>
    235264                                                <div className="float-right inline">
    236                                                         <div className="inline" style={{ marginRight: 20 }} >
    237                                                                 <SearchCorpusBox search={this.searchCorpus}/>
    238                                                         </div>
    239265                                                        <button className="btn btn-default" style={{ marginRight: 10 }} onClick={this.selectAll.bind(this,true)}>
    240266                                                                {" Select all"}</button>
     
    242268                                                                {" Deselect all"}</button>
    243269                                                </div>
     270                                                <div className="float-right inline">
     271                                                        <div className="inline" style={{ marginRight: 20 }} >
     272                                                                <SearchCorpusBox search={this.searchCorpus}/>
     273                                                                {this.renderFilteredMessage()}
     274                                                        </div>
     275                                                </div>
    244276                                        </div>
     277                                       
    245278                                        {this.props.corpora.corpora.map(this.renderCorpus.bind(this, 0, minmaxp))}
    246279                                </div>;
  • SRUAggregator/trunk/src/main/resources/assets/js/main.js

    r5919 r5954  
    105105                                React.createElement("div", {className: "container"},
    106106                                        React.createElement("div", {className: "beta-tag"},
    107                                                 React.createElement("span", null, "BETA")
     107                                                React.createElement("span", null, "ALPHA")
    108108                                        )
    109109                                ),
     
    270270
    271271React.render(React.createElement(Main, null), document.getElementById('reactMain') );
     272
    272273})();
  • SRUAggregator/trunk/src/main/resources/assets/js/main.jsx

    r5919 r5954  
    105105                                <div className="container">
    106106                                        <div className="beta-tag">
    107                                                 <span>BETA</span>
     107                                                <span>ALPHA</span>
    108108                                        </div>
    109109                                </div>
     
    270270
    271271React.render(<Main />, document.getElementById('reactMain') );
     272
    272273})();
  • SRUAggregator/trunk/src/main/resources/assets/js/search.js

    r5931 r5954  
    6565                corpus.expanded = false; // not expanded in the corpus view
    6666                corpus.priority = 1; // priority in corpus view
    67                 corpus.index = index;
     67                corpus.index = index; // original order, used for stable sort
    6868        });
    6969}
     
    7979Corpora.prototype.recurseCorpora = function(corpora, fn) {
    8080        var recfn = function(corpus, index){
    81                 if (false === fn(corpus)) {
     81                if (false === fn(corpus, index)) {
    8282                        // no recursion
    8383                } else {
     
    284284
    285285        stop: function(e) {
    286                 e.preventDefault();
    287286                e.stopPropagation();
    288287        },
     
    296295                                endRecord: corpusHit.endRecord,
    297296                                exception: corpusHit.exception,
     297                                diagnostics: corpusHit.diagnostics,
    298298                                searchString: corpusHit.searchString,
    299299                                kwics: corpusHit.kwics.filter(function(kwic){
     
    379379                                                                React.createElement("span", {className: "input-group-addon nobkg"}, "and show up to"),
    380380                                                                React.createElement("div", {className: "input-group-btn"},
    381                                                                         React.createElement("input", {type: "number", className: "form-control input", min: "10", max: "250", step: "5",
    382                                                                                 style: {width:54},
     381                                                                        React.createElement("input", {type: "number", className: "form-control input", min: "10", max: "250",
     382                                                                                style: {width:60},
    383383                                                                                onChange: this.setNumberOfResults, value: this.state.numberOfResults,
    384384                                                                                onKeyPress: this.stop})
     
    556556
    557557        renderRowLanguage: function(hit) {
    558                 return React.createElement("span", {style: {fontFace:"Courier",color:"black"}}, hit.language, " ") ;
     558                return false; //<span style={{fontFace:"Courier",color:"black"}}>{hit.language} </span> ;
    559559        },
    560560
     
    619619        },
    620620
     621        renderDiagnostics: function(corpusHit) {
     622                if (!corpusHit.diagnostics || corpusHit.diagnostics.length === 0) {
     623                        return false;
     624                }
     625
     626                return corpusHit.diagnostics.map(function(d) {
     627                        return  React.createElement("div", {className: "alert alert-danger", role: "alert"},
     628                                                d.dgnMessage, ": ", d.dgnDiagnostic
     629                                        );
     630                });
     631        },
     632
    621633        renderPanelBody: function(corpusHit) {
    622                 var fulllength = {width:"100%"};               
     634                var fulllength = {width:"100%"};
    623635                if (this.state.displayKwic) {
    624                         return  React.createElement("table", {className: "table table-condensed table-hover", style: fulllength},
    625                                                 React.createElement("tbody", null, corpusHit.kwics.map(this.renderRowsAsKwic))
     636                        return  React.createElement("div", null,
     637                                                this.renderDiagnostics(corpusHit),
     638                                                React.createElement("table", {className: "table table-condensed table-hover", style: fulllength},
     639                                                        React.createElement("tbody", null, corpusHit.kwics.map(this.renderRowsAsKwic))
     640                                                )
    626641                                        );
    627642                } else {
    628                         return  React.createElement("div", null, corpusHit.kwics.map(this.renderRowsAsHits));
     643                        return  React.createElement("div", null,
     644                                                this.renderDiagnostics(corpusHit),
     645                                                corpusHit.kwics.map(this.renderRowsAsHits)
     646                                        );
    629647                }
    630648        },
    631649
    632650        renderResultPanels: function(corpusHit) {
    633                 if (corpusHit.kwics.length === 0) {
     651                if (corpusHit.kwics.length === 0 &&
     652                        corpusHit.diagnostics.length === 0) {
    634653                        return false;
    635654                }
  • SRUAggregator/trunk/src/main/resources/assets/js/search.jsx

    r5931 r5954  
    6565                corpus.expanded = false; // not expanded in the corpus view
    6666                corpus.priority = 1; // priority in corpus view
    67                 corpus.index = index;
     67                corpus.index = index; // original order, used for stable sort
    6868        });
    6969}
     
    7979Corpora.prototype.recurseCorpora = function(corpora, fn) {
    8080        var recfn = function(corpus, index){
    81                 if (false === fn(corpus)) {
     81                if (false === fn(corpus, index)) {
    8282                        // no recursion
    8383                } else {
     
    284284
    285285        stop: function(e) {
    286                 e.preventDefault();
    287286                e.stopPropagation();
    288287        },
     
    296295                                endRecord: corpusHit.endRecord,
    297296                                exception: corpusHit.exception,
     297                                diagnostics: corpusHit.diagnostics,
    298298                                searchString: corpusHit.searchString,
    299299                                kwics: corpusHit.kwics.filter(function(kwic){
     
    379379                                                                <span className="input-group-addon nobkg">and show up to</span>
    380380                                                                <div className="input-group-btn">
    381                                                                         <input type="number" className="form-control input" min="10" max="250" step="5"
    382                                                                                 style={{width:54}}
     381                                                                        <input type="number" className="form-control input" min="10" max="250"
     382                                                                                style={{width:60}}
    383383                                                                                onChange={this.setNumberOfResults} value={this.state.numberOfResults}
    384384                                                                                onKeyPress={this.stop}/>
     
    556556
    557557        renderRowLanguage: function(hit) {
    558                 return <span style={{fontFace:"Courier",color:"black"}}>{hit.language} </span> ;
     558                return false; //<span style={{fontFace:"Courier",color:"black"}}>{hit.language} </span> ;
    559559        },
    560560
     
    619619        },
    620620
     621        renderDiagnostics: function(corpusHit) {
     622                if (!corpusHit.diagnostics || corpusHit.diagnostics.length === 0) {
     623                        return false;
     624                }
     625
     626                return corpusHit.diagnostics.map(function(d) {
     627                        return  <div className="alert alert-danger" role="alert">
     628                                                {d.dgnMessage}{": "}{d.dgnDiagnostic}
     629                                        </div>;
     630                });
     631        },
     632
    621633        renderPanelBody: function(corpusHit) {
    622                 var fulllength = {width:"100%"};               
     634                var fulllength = {width:"100%"};
    623635                if (this.state.displayKwic) {
    624                         return  <table className="table table-condensed table-hover" style={fulllength}>
    625                                                 <tbody>{corpusHit.kwics.map(this.renderRowsAsKwic)}</tbody>
    626                                         </table>;
     636                        return  <div>
     637                                                {this.renderDiagnostics(corpusHit)}
     638                                                <table className="table table-condensed table-hover" style={fulllength}>
     639                                                        <tbody>{corpusHit.kwics.map(this.renderRowsAsKwic)}</tbody>
     640                                                </table>
     641                                        </div>;
    627642                } else {
    628                         return  <div>{corpusHit.kwics.map(this.renderRowsAsHits)}</div>;
     643                        return  <div>
     644                                                {this.renderDiagnostics(corpusHit)}
     645                                                {corpusHit.kwics.map(this.renderRowsAsHits)}
     646                                        </div>;
    629647                }
    630648        },
    631649
    632650        renderResultPanels: function(corpusHit) {
    633                 if (corpusHit.kwics.length === 0) {
     651                if (corpusHit.kwics.length === 0 &&
     652                        corpusHit.diagnostics.length === 0) {
    634653                        return false;
    635654                }
Note: See TracChangeset for help on using the changeset viewer.