Skip to content
Snippets Groups Projects
Commit f2e7c75d authored by srosse's avatar srosse
Browse files

OO-3955: add group filter to the coach view in participant folder

parent 690534fa
No related branches found
No related tags found
No related merge requests found
Showing
with 151 additions and 39 deletions
......@@ -219,24 +219,28 @@ public abstract class AbstractFlexiTableRenderer extends DefaultComponentRendere
protected void renderHeaderSearch(Renderer renderer, StringOutput sb, FlexiTableElementImpl ftE, URLBuilder ubu, Translator translator,
RenderResult renderResult, String[] args) {
if(ftE.isSearchEnabled()) {
if(ftE.isSearchEnabled() || ftE.getExtendedFilterButton() != null) {
Form theForm = ftE.getRootForm();
String dispatchId = ftE.getFormDispatchId();
boolean searchInput = ftE.getSearchElement() != null;
sb.append("<div class='o_table_search input-group o_noprint'>");
renderFormItem(renderer, sb, ftE.getSearchElement(), ubu, translator, renderResult, args);
sb.append("<div class='input-group-btn'>");
// reset quick search
String id = ftE.getSearchElement().getFormDispatchId();
sb.append("<a href=\"javascript:jQuery('#").append(id).append("').val('');")
.append(FormJSHelper.getXHRFnCallFor(theForm, dispatchId, 1, true, true, true,
new NameValuePair("reset-search", "true")))
.append("\" class='btn o_reset_quick_search'><i class='o_icon o_icon_remove_filters'> </i></a>");
renderFormItem(renderer, sb, ftE.getSearchButton(), ubu, translator, renderResult, args);
if(ftE.getExtendedSearchButton() != null) {
renderFormItem(renderer, sb, ftE.getExtendedSearchButton(), ubu, translator, renderResult, args);
if(searchInput) {
renderFormItem(renderer, sb, ftE.getSearchElement(), ubu, translator, renderResult, args);
sb.append("<div class='input-group-btn'>");
// reset quick search
String id = ftE.getSearchElement().getFormDispatchId();
sb.append("<a href=\"javascript:jQuery('#").append(id).append("').val('');")
.append(FormJSHelper.getXHRFnCallFor(theForm, dispatchId, 1, true, true, true,
new NameValuePair("reset-search", "true")))
.append("\" class='btn o_reset_quick_search'><i class='o_icon o_icon_remove_filters'> </i></a>");
renderFormItem(renderer, sb, ftE.getSearchButton(), ubu, translator, renderResult, args);
if(ftE.getExtendedSearchButton() != null) {
renderFormItem(renderer, sb, ftE.getExtendedSearchButton(), ubu, translator, renderResult, args);
}
}
StringBuilder filterIndication = new StringBuilder();
if(ftE.getExtendedFilterButton() != null) {
ftE.getSelectedExtendedFilters().forEach(filter -> {
......@@ -246,10 +250,10 @@ public abstract class AbstractFlexiTableRenderer extends DefaultComponentRendere
renderFormItem(renderer, sb, ftE.getExtendedFilterButton(), ubu, translator, renderResult, args);
}
sb.append("</div>");
sb.append("</div>", searchInput);// close the div input-group-btn
sb.append("</div>");
if(filterIndication.length() > 0) {
sb.append("<div class='o_table_tools_indications'>").append(filterIndication)
sb.append("<div class='o_table_tools_indications").append("_filter_only", !searchInput).append("'>").append(filterIndication)
// remove filter
.append("<a href=\"javascript:")
.append(FormJSHelper.getXHRFnCallFor(theForm, dispatchId, 1, true, true, true,
......
......@@ -81,7 +81,13 @@ public class ExtendedFilterController extends FormBasicController {
Object uobject = link.getUserObject();
if(uobject instanceof FlexiTableFilter) {
FlexiTableFilter filter = (FlexiTableFilter)uobject;
filter.setSelected(!filter.isSelected());
if(filter.isShowAll()) {
for(FlexiTableFilter f:filters) {
f.setSelected(false);
}
} else {
filter.setSelected(!filter.isSelected());
}
}
}
fireEvent(ureq, Event.DONE_EVENT);
......
......@@ -612,7 +612,7 @@ public class FlexiTableElementImpl extends FormItemImpl implements FlexiTableEle
extendedFilterButton.setElementCssClass("o_sel_flexi_extendedsearch");
} else {
extendedFilterButton = null;
extendedFilters = null;
this.extendedFilters = null;
}
}
......
<ul class="list-unstyled">
<ul class="o_dropdown list-unstyled">
#foreach($filter in $filters)
#if($filter.filter.filter == "oo-spacer-xx")
<li class='divider'></li>
#else
<li>#if($filter.selected)<i class="o_icon o_icon_check"> </i> #end$r.render($filter.componentName)</li>
#end
#end
</ul>
\ No newline at end of file
......@@ -63,7 +63,9 @@ import org.olat.course.nodes.pf.ui.PFRunController;
import org.olat.course.run.environment.CourseEnvironment;
import org.olat.course.run.userview.UserCourseEnvironment;
import org.olat.group.BusinessGroup;
import org.olat.group.BusinessGroupRef;
import org.olat.group.BusinessGroupService;
import org.olat.group.manager.BusinessGroupRelationDAO;
import org.olat.repository.RepositoryEntry;
import org.olat.repository.RepositoryEntryRelationType;
import org.olat.repository.RepositoryService;
......@@ -96,6 +98,8 @@ public class PFManager {
@Autowired
private RepositoryService repositoryService;
@Autowired
private BusinessGroupRelationDAO businessGroupRelationDao;
@Autowired
private RepositoryEntryRelationDAO repositoryEntryRelationDao;
@Autowired
private UserManager userManager;
......@@ -559,18 +563,28 @@ public class PFManager {
/**
* Gets the participants for different group or course coaches as TableModel.
*
* @param id the identity
* @param pfNode
* @param userPropertyHandlers
* @param locale
* @param courseEnv
* @param admin
* @return the participants
* @param id The identity of the user who searches
* @param pfNode The course element
* @param userPropertyHandlers The list of properties to hold
* @param locale The locale
* @param courseEnv The course environment
* @param admin If the user is an administrator
* @return the participants The list of dropbox
*/
public List<DropBoxRow> getParticipants (Identity id, PFCourseNode pfNode, List<UserPropertyHandler> userPropertyHandlers,
public List<DropBoxRow> getParticipants(Identity id, PFCourseNode pfNode, List<UserPropertyHandler> userPropertyHandlers,
Locale locale, CourseEnvironment courseEnv, boolean admin) {
List<Identity> identityList = getParticipants(id, courseEnv, admin);
return getParticipants(pfNode, userPropertyHandlers, locale, identityList, courseEnv);
}
public List<DropBoxRow> getParticipants(List<BusinessGroupRef> businessGroupRefs, PFCourseNode pfNode, List<UserPropertyHandler> userPropertyHandlers,
Locale locale, CourseEnvironment courseEnv) {
List<Identity> identityList = businessGroupRelationDao.getMembers(businessGroupRefs, GroupRoles.participant.name());
return getParticipants(pfNode, userPropertyHandlers, locale, identityList, courseEnv);
}
private List<DropBoxRow> getParticipants(PFCourseNode pfNode, List<UserPropertyHandler> userPropertyHandlers,
Locale locale, List<Identity> identityList, CourseEnvironment courseEnv) {
Set<Identity> duplicates = new HashSet<>();
List<DropBoxRow> participants = new ArrayList<>(identityList.size());
......
......@@ -34,6 +34,7 @@ import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.form.flexible.FormItem;
import org.olat.core.gui.components.form.flexible.FormItemContainer;
import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement;
import org.olat.core.gui.components.form.flexible.elements.FlexiTableFilter;
import org.olat.core.gui.components.form.flexible.elements.FlexiTableSortOptions;
import org.olat.core.gui.components.form.flexible.elements.FormLink;
import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
......@@ -43,6 +44,7 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFle
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnModel;
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableSearchEvent;
import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
......@@ -57,6 +59,7 @@ import org.olat.core.gui.media.MediaResource;
import org.olat.core.id.Identity;
import org.olat.core.id.Roles;
import org.olat.core.id.UserConstants;
import org.olat.core.util.StringHelper;
import org.olat.core.util.resource.OresHelper;
import org.olat.course.nodes.PFCourseNode;
import org.olat.course.nodes.pf.manager.FileSystemExport;
......@@ -65,6 +68,10 @@ import org.olat.course.nodes.pf.manager.PFView;
import org.olat.course.nodes.pf.ui.DropBoxTableModel.DropBoxCols;
import org.olat.course.run.environment.CourseEnvironment;
import org.olat.course.run.userview.UserCourseEnvironment;
import org.olat.course.run.userview.UserCourseEnvironmentImpl;
import org.olat.group.BusinessGroup;
import org.olat.group.BusinessGroupRef;
import org.olat.group.model.BusinessGroupRefImpl;
import org.olat.resource.OLATResource;
import org.olat.user.HomePageConfig;
import org.olat.user.HomePageDisplayController;
......@@ -108,9 +115,9 @@ public class PFCoachController extends FormBasicController implements Controller
@Autowired
private UserManager userManager;
@Autowired
private BaseSecurityModule securityModule;
@Autowired
private BaseSecurity securityManager;
@Autowired
private BaseSecurityModule securityModule;
public PFCoachController(UserRequest ureq, WindowControl wControl, PFCourseNode sfNode,
UserCourseEnvironment userCourseEnv, PFView pfView) {
......@@ -193,6 +200,8 @@ public class PFCoachController extends FormBasicController implements Controller
} else if ("firstName".equals(se.getCommand()) || "lastName".equals(se.getCommand())) {
doOpenHomePage(ureq, currentObject.getIdentity());
}
} else if(event instanceof FlexiTableSearchEvent) {
loadModel(true);
}
}
}
......@@ -270,10 +279,10 @@ public class PFCoachController extends FormBasicController implements Controller
dropboxTable.setSelectAllEnable(true);
dropboxTable.setExportEnabled(true);
dropboxTable.setSortSettings(options);
initFilters();
dropboxTable.setAndLoadPersistedPreferences(ureq, "participant-folder_coach_" + pfView.name());
dropboxTable.setEmtpyTableMessageKey("table.empty");
FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
buttonGroupLayout.setElementCssClass("o_button_group");
......@@ -283,8 +292,45 @@ public class PFCoachController extends FormBasicController implements Controller
uploadAllLink = uifactory.addFormLink("upload.link", buttonGroupLayout, Link.BUTTON);
}
private void initFilters() {
List<FlexiTableFilter> groupFilters = new ArrayList<>();
List<BusinessGroup> coachedGroups = null;
if(userCourseEnv.isAdmin()) {
coachedGroups = courseEnv.getCourseGroupManager().getAllBusinessGroups();
} else if(userCourseEnv instanceof UserCourseEnvironmentImpl) {
UserCourseEnvironmentImpl uce = (UserCourseEnvironmentImpl)userCourseEnv;
coachedGroups = uce.getCoachedGroups();
}
if(coachedGroups != null) {
for(BusinessGroup coachedGroup:coachedGroups) {
String groupName = StringHelper.escapeHtml(coachedGroup.getName());
groupFilters.add(new FlexiTableFilter(groupName, coachedGroup.getKey().toString(), "o_icon o_icon_group"));
}
}
if(!groupFilters.isEmpty()) {
groupFilters.add(FlexiTableFilter.SPACER);
groupFilters.add(new FlexiTableFilter(translate("show.all"), "", true));
dropboxTable.setExtendedFilterButton(translate("filter.groups"), groupFilters);
}
}
private void loadModel(boolean full) {
List<DropBoxRow> rows = pfManager.getParticipants(getIdentity(), pfNode, userPropertyHandlers, getLocale(), courseEnv, userCourseEnv.isAdmin());
List<FlexiTableFilter> extendedFilters = dropboxTable.getSelectedExtendedFilters();
List<DropBoxRow> rows;
if(extendedFilters == null || extendedFilters.isEmpty() || extendedFilters.get(0).isShowAll()) {
rows = pfManager.getParticipants(getIdentity(), pfNode, userPropertyHandlers, getLocale(), courseEnv, userCourseEnv.isAdmin());
} else {
List<BusinessGroupRef> businessGroups = new ArrayList<>(extendedFilters.size());
for(FlexiTableFilter extendedFilter:extendedFilters) {
if(StringHelper.isLong(extendedFilter.getFilter())) {
businessGroups.add(new BusinessGroupRefImpl(Long.parseLong(extendedFilter.getFilter())));
}
}
rows = pfManager.getParticipants(businessGroups, pfNode, userPropertyHandlers, getLocale(), courseEnv);
}
tableModel.setObjects(rows);
dropboxTable.reset(full, full, true);
flc.contextPut("hasParticipants", tableModel.getRowCount() > 0);
......
......@@ -10,6 +10,7 @@ limit.count=Anzahl der einstellbaren Dokumente einschr\u00E4nken
limit.count.info=Sie k\u00F6nnen nur insgesamt {0} Dokumente einstellen.
limit.count.coach.info=Sobald die max. Anzahl Dokumente erreicht ist, k\u00F6nnen die Teilnehmer nicht mehr Verschieben, Kopieren, Zippen oder Entzippen.
file.count=Limite
filter.groups=Gruppen
alter.file=L\u00F6schen und \u00DCberschreiben von Dokumenten erlauben
time.frame=Zeitfenster f\u00FCr Abgabe festlegen
date.start=von
......@@ -53,3 +54,4 @@ preview.limit=Dokumentenlimite aktiviert
preview.timeframe=Zeitfenster
preview.info=Ein Beispiel finden Sie untenstehend:
preview.header=Konfiguration f\u00FCr den simulierten Benutzer
show.all=Alle anzeigen
......@@ -10,6 +10,7 @@ limit.count=Limit number of uploadable documents
limit.count.info=You may only upload or create {0} files total.
limit.count.coach.info=As soon as the maximum number of files is reached, participants cannot move, copy, zip or unzip anymore.
file.count=Limit
filter.groups=Groups
alter.file=Enable overwrite/delete of uploaded documents
time.frame=Limit upload to time interval
date.start=from
......@@ -52,4 +53,5 @@ preview.return=Coach Returnbox enabled
preview.limit=Filelimit active
preview.timeframe=Time interval
preview.info=An example is shown below:
preview.header=Configuration folder for simulated user
\ No newline at end of file
preview.header=Configuration folder for simulated user
show.all=Show all
\ No newline at end of file
......@@ -321,6 +321,30 @@ public class BusinessGroupRelationDAO {
return members.getResultList();
}
public List<Identity> getMembers(List<? extends BusinessGroupRef> groups, String... roles) {
if(groups == null || groups.isEmpty()) return Collections.emptyList();
StringBuilder sb = new StringBuilder();
sb.append("select ident from businessgroup as bgroup ")
.append(" inner join bgroup.baseGroup as baseGroup")
.append(" inner join baseGroup.members as membership")
.append(" inner join membership.identity as ident")
.append(" inner join fetch ident.user as identUser")
.append(" where bgroup.key in (:businessGroupKeys) and membership.role in (:roles)");
List<String> roleList = GroupRoles.toList(roles);
List<Long> groupKeys = new ArrayList<>(groups.size());
for(BusinessGroupRef group:groups) {
groupKeys.add(group.getKey());
}
return dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Identity.class)
.setParameter("businessGroupKeys", groupKeys)
.setParameter("roles", roleList)
.getResultList();
}
public List<Long> getMemberKeys(List<? extends BusinessGroupRef> groups, String... roles) {
if(groups == null || groups.isEmpty()) return Collections.emptyList();
......
......@@ -141,7 +141,7 @@ a.o_orderby, a.o_orderby:hover {
margin-left: 6px;
}
.o_table_tools_indications {
.o_table_tools_indications, .o_table_tools_indications_filter_only {
margin-left: 10px;
padding-top:3px;
font-size:80%;
......
......@@ -117,6 +117,16 @@ ul.o_dropdown {
background-color: $dropdown-link-hover-bg;
}
}
> li > i.o_icon_check {
display: inline-block;
padding-left: 14px;
}
> li > i.o_icon_check + a {
display: inline-block;
padding-left: 5px;
}
}
/* SCORM module */
......
This diff is collapsed.
This diff is collapsed.
source diff could not be displayed: it is too large. Options to address this: view the blob.
This diff is collapsed.
This diff is collapsed.
source diff could not be displayed: it is too large. Options to address this: view the blob.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment