Rozdělané fulltextové vyhledávání
parent
b1818546c0
commit
02311ae5dd
@ -0,0 +1,71 @@
|
|||||||
|
package info.bukova.isspst.data;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Type;
|
||||||
|
import org.hibernate.search.annotations.Analyze;
|
||||||
|
import org.hibernate.search.annotations.Field;
|
||||||
|
import org.hibernate.search.annotations.Index;
|
||||||
|
import org.hibernate.search.annotations.Indexed;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "FILE_METAINFO")
|
||||||
|
@Indexed
|
||||||
|
public class FileMetainfo extends BaseData {
|
||||||
|
|
||||||
|
@Column(name = "FILE_NAME")
|
||||||
|
private String fileName;
|
||||||
|
@Column(name = "PATH_IN_FILESYSTEM")
|
||||||
|
private String pathInFilesystem;
|
||||||
|
@Column(name = "MODULE_ID")
|
||||||
|
private String moduleId;
|
||||||
|
@Column(name = "RECORD_ID")
|
||||||
|
private int recordId;
|
||||||
|
@Column(name = "CONTENT")
|
||||||
|
@Type(type = "text")
|
||||||
|
@Field(index = Index.YES, analyze = Analyze.YES)
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
public String getFileName() {
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileName(String fileName) {
|
||||||
|
this.fileName = fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPathInFilesystem() {
|
||||||
|
return pathInFilesystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPathInFilesystem(String pathInFilesystem) {
|
||||||
|
this.pathInFilesystem = pathInFilesystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModuleId() {
|
||||||
|
return moduleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModuleId(String moduleId) {
|
||||||
|
this.moduleId = moduleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRecordId() {
|
||||||
|
return recordId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRecordId(int recordId) {
|
||||||
|
this.recordId = recordId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(String content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package info.bukova.isspst.services;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface FullTextService {
|
||||||
|
|
||||||
|
public void reindex();
|
||||||
|
public List<?> search(Class<?> entityClass, String[] fields, String word);
|
||||||
|
public List<?> globalSearch(String word);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,143 @@
|
|||||||
|
package info.bukova.isspst.services;
|
||||||
|
|
||||||
|
import info.bukova.isspst.dao.QueryDao;
|
||||||
|
import info.bukova.isspst.data.BaseData;
|
||||||
|
import info.bukova.isspst.data.User;
|
||||||
|
import info.bukova.isspst.sort.ReflectionTools;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.lucene.search.Query;
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.search.FullTextSession;
|
||||||
|
import org.hibernate.search.Search;
|
||||||
|
import org.hibernate.search.annotations.IndexedEmbedded;
|
||||||
|
import org.hibernate.search.query.dsl.QueryBuilder;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
public class FullTextServiceImpl implements FullTextService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private QueryDao queryDao;
|
||||||
|
private List<Class<?>> classesForSearch;
|
||||||
|
private Map<Class<?>, String[]> fields;
|
||||||
|
private List<Class<?>> nestedClasses;
|
||||||
|
|
||||||
|
public FullTextServiceImpl() {
|
||||||
|
nestedClasses = new ArrayList<Class<?>>();
|
||||||
|
nestedClasses.add(User.class);
|
||||||
|
nestedClasses.add(BaseData.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void reindex() {
|
||||||
|
Logger logger = LoggerFactory.getLogger(FullTextServiceImpl.class);
|
||||||
|
logger.info("Indexing database for fulltext search");
|
||||||
|
FullTextSession ftSession = Search.getFullTextSession(queryDao.getSession());
|
||||||
|
try {
|
||||||
|
ftSession.createIndexer().startAndWait();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
logger.error("Cannot index database");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public List<?> search(Class<?> entityClass, String[] fields, String word) {
|
||||||
|
FullTextSession session = Search.getFullTextSession(queryDao.getSession());
|
||||||
|
QueryBuilder qb = session.getSearchFactory().buildQueryBuilder().forEntity(entityClass).get();
|
||||||
|
|
||||||
|
Query luceneQuery = qb.keyword().onFields(fields).matching(word).createQuery();
|
||||||
|
org.hibernate.Query hiberQuery = session.createFullTextQuery(luceneQuery, entityClass);
|
||||||
|
|
||||||
|
return hiberQuery.list();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public List<?> globalSearch(String word) {
|
||||||
|
List<Object> result = new ArrayList<Object>();
|
||||||
|
|
||||||
|
for (Class<?> clazz : classesForSearch()) {
|
||||||
|
result.addAll(search(clazz, fields.get(clazz), word));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Object o : result) {
|
||||||
|
BaseData data = (BaseData) o;
|
||||||
|
Hibernate.initialize(data.getModifiedBy());
|
||||||
|
Hibernate.initialize(data.getOwnedBy());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Class<?>> classesForSearch() {
|
||||||
|
if (classesForSearch != null) {
|
||||||
|
return classesForSearch;
|
||||||
|
}
|
||||||
|
|
||||||
|
classesForSearch = new ArrayList<Class<?>>();
|
||||||
|
fields = new HashMap<Class<?>, String[]>();
|
||||||
|
FullTextSession session = Search.getFullTextSession(queryDao.getSession());
|
||||||
|
|
||||||
|
for (Class<?> clazz : session.getSearchFactory().getIndexedTypes()) {
|
||||||
|
if (nestedClasses.contains(clazz)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
classesForSearch.add(clazz);
|
||||||
|
fields.put(clazz, fields(clazz, ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
return classesForSearch;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] fields(Class<?> clazz, String prefix) {
|
||||||
|
List<String> res = new ArrayList<String>();
|
||||||
|
|
||||||
|
for (Field field : ReflectionTools.getFields(clazz)) {
|
||||||
|
for (Annotation a : field.getDeclaredAnnotations()) {
|
||||||
|
if (a instanceof org.hibernate.search.annotations.Field) {
|
||||||
|
res.add(prefix + field.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a instanceof IndexedEmbedded) {
|
||||||
|
Class<?> fieldClass;
|
||||||
|
|
||||||
|
fieldClass = field.getType();
|
||||||
|
if (fieldClass.isAssignableFrom(List.class)) {
|
||||||
|
ParameterizedType type = (ParameterizedType) field.getGenericType();
|
||||||
|
Type[] types = type.getActualTypeArguments();
|
||||||
|
if (types.length == 1) {
|
||||||
|
fieldClass = (Class<?>)types[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
classesForSearch.remove(fieldClass);
|
||||||
|
fields.remove(fieldClass);
|
||||||
|
nestedClasses.add(fieldClass);
|
||||||
|
|
||||||
|
String nestedPrefix = prefix + field.getName() + ".";
|
||||||
|
res.addAll(Arrays.asList(fields(fieldClass, nestedPrefix)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String resArray[] = new String[res.size()];
|
||||||
|
resArray = res.toArray(resArray);
|
||||||
|
return resArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package info.bukova.isspst.ui.search;
|
||||||
|
|
||||||
|
import info.bukova.isspst.EntityUrlResolver;
|
||||||
|
import info.bukova.isspst.data.BaseData;
|
||||||
|
|
||||||
|
public abstract class AbstractResultTransformer implements ResultTransformer {
|
||||||
|
|
||||||
|
protected EntityUrlResolver urlResolver;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SearchResult transformObject(Object object) {
|
||||||
|
BaseData data = (BaseData)object;
|
||||||
|
SearchResult result = new SearchResult();
|
||||||
|
|
||||||
|
result.setCreated(data.getCreated());
|
||||||
|
result.setModified(data.getModified());
|
||||||
|
result.setOwnedBy(data.getOwnedBy());
|
||||||
|
result.setModifiedBy(data.getModifiedBy());
|
||||||
|
|
||||||
|
if (urlResolver != null) {
|
||||||
|
result.setUrl(urlResolver.entityUrl(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
transform(object, result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void transform(Object object, SearchResult result);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUrlResolver(EntityUrlResolver resolver) {
|
||||||
|
this.urlResolver = resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package info.bukova.isspst.ui.search;
|
||||||
|
|
||||||
|
|
||||||
|
public class CommonResultTransformer extends AbstractResultTransformer implements ResultTransformer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void transform(Object object, SearchResult result) {
|
||||||
|
result.setRecordName("Neznámá entita");
|
||||||
|
result.setDescription(object.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package info.bukova.isspst.ui.search;
|
||||||
|
|
||||||
|
import info.bukova.isspst.data.Order;
|
||||||
|
|
||||||
|
public class OrderResultTransformer extends AbstractResultTransformer implements ResultTransformer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void transform(Object object, SearchResult result) {
|
||||||
|
Order order = (Order)object;
|
||||||
|
result.setRecordName("Objednávka: " + order.getNumser());
|
||||||
|
result.setDescription(order.getDescription() + ", dodavatel: " + order.getSuplier().getCompany());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package info.bukova.isspst.ui.search;
|
||||||
|
|
||||||
|
import info.bukova.isspst.data.Requirement;
|
||||||
|
|
||||||
|
public class RequirementResultTransformer extends AbstractResultTransformer implements ResultTransformer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void transform(Object object, SearchResult result) {
|
||||||
|
Requirement req = (Requirement)object;
|
||||||
|
result.setRecordName("Požadavek na nákup/službu: " + req.getNumser());
|
||||||
|
result.setDescription(req.getDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package info.bukova.isspst.ui.search;
|
||||||
|
|
||||||
|
import info.bukova.isspst.EntityUrlResolver;
|
||||||
|
|
||||||
|
public interface ResultTransformer {
|
||||||
|
|
||||||
|
public SearchResult transformObject(Object object);
|
||||||
|
public void setUrlResolver(EntityUrlResolver resolver);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
package info.bukova.isspst.ui.search;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.zkoss.bind.annotation.Command;
|
||||||
|
import org.zkoss.bind.annotation.NotifyChange;
|
||||||
|
import org.zkoss.zk.ui.select.annotation.WireVariable;
|
||||||
|
|
||||||
|
import info.bukova.isspst.UrlResolverHolder;
|
||||||
|
import info.bukova.isspst.data.BaseData;
|
||||||
|
import info.bukova.isspst.data.Requirement;
|
||||||
|
import info.bukova.isspst.data.TripRequirement;
|
||||||
|
import info.bukova.isspst.services.FullTextService;
|
||||||
|
|
||||||
|
public class SearchForm {
|
||||||
|
|
||||||
|
@WireVariable
|
||||||
|
private FullTextService fulltextService;
|
||||||
|
@WireVariable
|
||||||
|
private UrlResolverHolder urlResolverHolder;
|
||||||
|
private List<SearchResult> results;
|
||||||
|
|
||||||
|
private String keyWord;
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command
|
||||||
|
@NotifyChange("results")
|
||||||
|
public void doSearch() {
|
||||||
|
if (keyWord == null || keyWord.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//String[] fields = {"items.textItem", "description"};
|
||||||
|
List<?> result = fulltextService.globalSearch(keyWord);
|
||||||
|
//List<?> result = fulltextService.search(Requirement.class, fields, keyWord);
|
||||||
|
|
||||||
|
SearchListTransformer srt = new SearchListTransformer(urlResolverHolder);
|
||||||
|
results = srt.transform(result);
|
||||||
|
|
||||||
|
System.out.println(result.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKeyWord() {
|
||||||
|
return keyWord;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyWord(String keyWord) {
|
||||||
|
this.keyWord = keyWord;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SearchResult> getResults() {
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package info.bukova.isspst.ui.search;
|
||||||
|
|
||||||
|
import info.bukova.isspst.UrlResolverHolder;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SearchListTransformer {
|
||||||
|
|
||||||
|
private UrlResolverHolder urlResolverHolder;
|
||||||
|
|
||||||
|
public SearchListTransformer() {
|
||||||
|
urlResolverHolder = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public SearchListTransformer(UrlResolverHolder urlResolverHolder) {
|
||||||
|
super();
|
||||||
|
this.urlResolverHolder = urlResolverHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public List<SearchResult> transform(List<?> source) {
|
||||||
|
List<SearchResult> ret = new ArrayList<SearchResult>();
|
||||||
|
|
||||||
|
for (int i = 0; i < source.size(); i++) {
|
||||||
|
ResultTransformer transformer = TransformerFactory.transformerFor(source.get(i));
|
||||||
|
if (urlResolverHolder != null) {
|
||||||
|
transformer.setUrlResolver(urlResolverHolder.resolverFor(source.get(i).getClass()));
|
||||||
|
}
|
||||||
|
ret.add(transformer.transformObject(source.get(i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
package info.bukova.isspst.ui.search;
|
||||||
|
|
||||||
|
import info.bukova.isspst.data.User;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class SearchResult {
|
||||||
|
|
||||||
|
private String recordName;
|
||||||
|
private String description;
|
||||||
|
private String url;
|
||||||
|
private Date created;
|
||||||
|
private Date modified;
|
||||||
|
private User ownedBy;
|
||||||
|
private User modifiedBy;
|
||||||
|
|
||||||
|
public String getRecordName() {
|
||||||
|
return recordName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRecordName(String recordName) {
|
||||||
|
this.recordName = recordName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreated() {
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreated(Date created) {
|
||||||
|
this.created = created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getModified() {
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModified(Date modified) {
|
||||||
|
this.modified = modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getOwnedBy() {
|
||||||
|
return ownedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOwnedBy(User ownedBy) {
|
||||||
|
this.ownedBy = ownedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getModifiedBy() {
|
||||||
|
return modifiedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModifiedBy(User modifiedBy) {
|
||||||
|
this.modifiedBy = modifiedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package info.bukova.isspst.ui.search;
|
||||||
|
|
||||||
|
import info.bukova.isspst.data.Order;
|
||||||
|
import info.bukova.isspst.data.Requirement;
|
||||||
|
import info.bukova.isspst.data.TripBill;
|
||||||
|
import info.bukova.isspst.data.TripRequirement;
|
||||||
|
|
||||||
|
public class TransformerFactory {
|
||||||
|
|
||||||
|
public static ResultTransformer transformerFor(Object object) {
|
||||||
|
if (object instanceof TripBill) {
|
||||||
|
return new TripBillTransformer();
|
||||||
|
}
|
||||||
|
if (object instanceof TripRequirement) {
|
||||||
|
return new TripRequirementTransformer();
|
||||||
|
}
|
||||||
|
if (object instanceof Requirement) {
|
||||||
|
return new RequirementResultTransformer();
|
||||||
|
}
|
||||||
|
if (object instanceof Order) {
|
||||||
|
return new OrderResultTransformer();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CommonResultTransformer();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package info.bukova.isspst.ui.search;
|
||||||
|
|
||||||
|
import info.bukova.isspst.data.TripBill;
|
||||||
|
|
||||||
|
public class TripBillTransformer extends AbstractResultTransformer implements ResultTransformer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void transform(Object object, SearchResult result) {
|
||||||
|
TripBill tb = (TripBill)object;
|
||||||
|
result.setRecordName("Vyúčtování služební cesty: " + tb.getRequirement().getNumser());
|
||||||
|
result.setDescription("Z " + tb.getRequirement().getFrom() + " do " + tb.getRequirement().getTo() + " - " + tb.getRequirement().getDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package info.bukova.isspst.ui.search;
|
||||||
|
|
||||||
|
import info.bukova.isspst.data.TripRequirement;
|
||||||
|
|
||||||
|
public class TripRequirementTransformer extends AbstractResultTransformer implements ResultTransformer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void transform(Object object, SearchResult result) {
|
||||||
|
TripRequirement tr = (TripRequirement)object;
|
||||||
|
result.setRecordName("Žádost o služební cestu: " + tr.getNumser());
|
||||||
|
result.setDescription("Z " + tr.getFrom() + " do " + tr.getTo() + " - " + tr.getDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
<?page title="Search" contentType="text/html;charset=UTF-8"?>
|
||||||
|
<zk>
|
||||||
|
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
|
||||||
|
|
||||||
|
<window title="Search" border="normal" closable="true"
|
||||||
|
apply="org.zkoss.bind.BindComposer"
|
||||||
|
viewModel="@id('vm') @init('info.bukova.isspst.ui.search.SearchForm')"
|
||||||
|
vflex="1">
|
||||||
|
|
||||||
|
<vbox width="100%"
|
||||||
|
vflex="1">
|
||||||
|
<hbox>
|
||||||
|
<textbox value="@bind(vm.keyWord)" />
|
||||||
|
<button label="Hledat" onClick="@command('doSearch')" />
|
||||||
|
</hbox>
|
||||||
|
<panel hflex="1" vflex="1">
|
||||||
|
<panelchildren style="overflow:auto;">
|
||||||
|
<vbox children="@load(vm.results)" width="100%">
|
||||||
|
<template name="children">
|
||||||
|
<vbox width="100%">
|
||||||
|
<separator bar="true" width="100%"/>
|
||||||
|
<label value="@load(each.recordName)" style="font-weight: bold; font-size:14px;"/>
|
||||||
|
<label value="@load(each.description)"/>
|
||||||
|
<hbox>
|
||||||
|
<label value="Vytvořeno: "/>
|
||||||
|
<label value="@load(each.created)"/>
|
||||||
|
</hbox>
|
||||||
|
<hbox>
|
||||||
|
<label value="Vytvořil: "/>
|
||||||
|
<label value="@load(each.ownedBy)"/>
|
||||||
|
</hbox>
|
||||||
|
<hbox>
|
||||||
|
<label value="Změněno: "/>
|
||||||
|
<label value="@load(each.modified)"/>
|
||||||
|
</hbox>
|
||||||
|
<hbox>
|
||||||
|
<label value="Změnil: "/>
|
||||||
|
<label value="@load(each.modifiedBy)"/>
|
||||||
|
</hbox>
|
||||||
|
<a href="@load(each.url)" label="@load(each.url)"/>
|
||||||
|
</vbox>
|
||||||
|
</template>
|
||||||
|
</vbox>
|
||||||
|
</panelchildren>
|
||||||
|
</panel>
|
||||||
|
</vbox>
|
||||||
|
|
||||||
|
</window>
|
||||||
|
</zk>
|
Loading…
Reference in New Issue