Skip to content

Commit fa0ad5b

Browse files
authored
Add the possibility to define a task description template #94 (#238)
* Update Task livetable to have the same filter excluding 'Template' pages as Kanban, Task Dependencies and Gantt * Added TaskTemplateList page * Changed how title works for Template tasks * Added Create Template button * Formatting * Exclude templates from task panel * Add functional tests for Gantt functionality #159 * Move TaskManagerTemplate to Template space * Formatting * Added task template section to admin section * Fix TaskTemplateProvider Template * Fix merge * Add tests * Fix templates on XWiki >14.10 * Re-export TaskManagerTemplate * Fix some merge conflict * Change template check in the sheet * Add the possibility to define a task description template #94 * Update since version
1 parent 593c85f commit fa0ad5b

File tree

25 files changed

+739
-224
lines changed

25 files changed

+739
-224
lines changed

application-task-default/src/main/java/com/xwiki/task/internal/DefaultTaskManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public Task getTask(int id) throws TaskException
105105
XWikiContext context = contextProvider.get();
106106
String statement = ", BaseObject as taskObj, IntegerProperty as idProp "
107107
+ "WHERE taskObj.name = doc.fullName "
108-
+ "AND doc.fullName != 'TaskManager.TaskManagerTemplate' "
108+
+ "AND doc.space != 'TaskManager.TaskManagerTemplates' "
109109
+ "AND taskObj.className = 'TaskManager.TaskManagerClass' "
110110
+ "AND taskObj.id = idProp.id.id AND idProp.id.name = 'number' "
111111
+ "AND idProp.value = :id";

application-task-default/src/main/java/com/xwiki/task/internal/TaskObjectUpdateEventListener.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.Arrays;
2424
import java.util.Collections;
2525
import java.util.List;
26+
import java.util.stream.Collectors;
2627

2728
import javax.inject.Inject;
2829
import javax.inject.Named;
@@ -37,7 +38,7 @@
3738
import org.xwiki.job.JobGroupPath;
3839
import org.xwiki.model.reference.DocumentReference;
3940
import org.xwiki.model.reference.EntityReference;
40-
import org.xwiki.model.reference.LocalDocumentReference;
41+
import org.xwiki.model.reference.SpaceReference;
4142
import org.xwiki.observation.event.Event;
4243
import org.xwiki.user.UserReference;
4344
import org.xwiki.user.UserReferenceResolver;
@@ -61,8 +62,7 @@
6162
@Singleton
6263
public class TaskObjectUpdateEventListener extends AbstractTaskEventListener
6364
{
64-
private static final LocalDocumentReference TEMPLATE_REFERENCE =
65-
new LocalDocumentReference("TaskManager", "TaskManagerTemplate");
65+
private static final List<String> TEMPLATE_SPACE_REFERENCES = List.of("TaskManager", "TaskManagerTemplates");
6666

6767
@Inject
6868
private TaskCounter taskCounter;
@@ -94,11 +94,13 @@ protected void processEvent(XWikiDocument document, XWikiContext context, Event
9494
return;
9595
}
9696

97-
maybeSetTaskNumber(context, taskObj);
98-
99-
if (new LocalDocumentReference(document.getDocumentReference()).equals(TEMPLATE_REFERENCE)) {
97+
if (document.getDocumentReference().getSpaceReferences().stream().map(SpaceReference::getName)
98+
.collect(Collectors.toList()).equals(TEMPLATE_SPACE_REFERENCES)) {
10099
return;
101100
}
101+
102+
maybeSetTaskNumber(context, taskObj);
103+
102104
// If the flag is set, the listener was triggered as a result of a save made by TaskMacroUpdateEventListener
103105
// which updated some task objects. Skip the execution.
104106
if (context.get(TASK_UPDATE_FLAG) != null) {

application-task-default/src/test/java/com/xwiki/task/DefaultTaskManagerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ void getTaskById() throws TaskException, QueryException
158158
{
159159
String queryStatement = ", BaseObject as taskObj, IntegerProperty as idProp "
160160
+ "WHERE taskObj.name = doc.fullName "
161-
+ "AND doc.fullName != 'TaskManager.TaskManagerTemplate' "
161+
+ "AND doc.space != 'TaskManager.TaskManagerTemplates' "
162162
+ "AND taskObj.className = 'TaskManager.TaskManagerClass' "
163163
+ "AND taskObj.id = idProp.id.id AND idProp.id.name = 'number' "
164164
+ "AND idProp.value = :id";

application-task-test/application-task-test-docker/src/test/it/com/xwiki/task/test/ui/AllITs.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,12 @@ class NestedGanttIT extends GanttIT
5757
class NestedNotificationIT extends NotificationIT
5858
{
5959
}
60+
61+
@Nested
62+
@Order(4)
63+
@DisplayName("Task Manager Template Creation")
64+
class NestedTaskTemplatesIT extends TaskTemplatesIT
65+
{
66+
}
67+
6068
}

application-task-test/application-task-test-docker/src/test/it/com/xwiki/task/test/ui/TaskManagerIT.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ void deleteTaskMacro(WikiReference wiki, TestUtils setup) throws Exception
412412
void checkboxMacro(WikiReference wiki, TestUtils setup,
413413
TestLocalReference testLocalReference, TestReference testReference)
414414
{
415+
setup.setCurrentWiki(wiki.getName());
415416
DocumentReference testRef = new DocumentReference(docWithTaskboxes, wiki);
416417
setup.createPage(testRef, "{{checkbox id=\"someId\"}}Hello there{{/checkbox}}");
417418
ViewPageWithTasks viewPageWithTasks = new ViewPageWithTasks();
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* See the NOTICE file distributed with this work for additional
3+
* information regarding copyright ownership.
4+
*
5+
* This is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU Lesser General Public License as
7+
* published by the Free Software Foundation; either version 2.1 of
8+
* the License, or (at your option) any later version.
9+
*
10+
* This software is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this software; if not, write to the Free
17+
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18+
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19+
*/
20+
package com.xwiki.task.test.ui;
21+
22+
import java.util.List;
23+
24+
import org.junit.jupiter.api.BeforeAll;
25+
import org.junit.jupiter.api.Order;
26+
import org.junit.jupiter.api.Test;
27+
import org.openqa.selenium.By;
28+
import org.xwiki.contrib.application.task.test.po.TaskManagerHomePage;
29+
import org.xwiki.contrib.application.task.test.po.TaskManagerInlinePage;
30+
import org.xwiki.contrib.application.task.test.po.TaskTemplateListPage;
31+
import org.xwiki.test.docker.junit5.UITest;
32+
import org.xwiki.test.ui.TestUtils;
33+
import org.xwiki.test.ui.po.CreatePagePage;
34+
35+
import static org.junit.jupiter.api.Assertions.assertEquals;
36+
import static org.junit.jupiter.api.Assertions.assertFalse;
37+
import static org.junit.jupiter.api.Assertions.assertNotNull;
38+
import static org.junit.jupiter.api.Assertions.assertTrue;
39+
40+
/**
41+
* Tests for the Task Manager Template creation.
42+
*
43+
* @version $Id$
44+
* @since 3.10.0
45+
*/
46+
@UITest
47+
public class TaskTemplatesIT
48+
{
49+
private static final String TEST_USERNAME = "TaskTemplatesTestUser";
50+
51+
private static final String TEST_PASSWORD = "pass";
52+
53+
@BeforeAll
54+
void setup(TestUtils setup)
55+
{
56+
setup.createUserAndLogin(TEST_USERNAME, TEST_PASSWORD);
57+
setup.loginAsSuperAdmin();
58+
setup.setGlobalRights(null, "XWiki." + TEST_USERNAME, "edit", false);
59+
}
60+
61+
@Test
62+
@Order(1)
63+
void noEditRights(TestUtils setup)
64+
{
65+
setup.login(TEST_USERNAME, TEST_PASSWORD);
66+
TaskManagerHomePage taskManagerHomePage = TaskManagerHomePage.gotoPage();
67+
taskManagerHomePage.clickTaskTemplateListButton();
68+
assertEquals(setup.getDriver().getCurrentUrl(), TaskTemplateListPage.getURL());
69+
TaskTemplateListPage page = new TaskTemplateListPage();
70+
page.setTemplateName("TestNoEdit");
71+
page.submit();
72+
assertNotNull(setup.getDriver().findElement(By.className("xnotification-error")));
73+
page = TaskTemplateListPage.gotoPage();
74+
assertFalse(page.getListedTemplates().contains("TaskManager.TaskManagerTemplates.TestNoEditTemplateProvider"),
75+
"Expected " + page.getListedTemplates());
76+
}
77+
78+
@Test
79+
@Order(2)
80+
void createTemplate(TestUtils setup)
81+
{
82+
String testTemplate = "Test";
83+
String templateName = "TaskManager.TaskManagerTemplates." + testTemplate + "Template";
84+
String testProperty = "15";
85+
setup.createUserAndLogin("TestUser", "password");
86+
87+
TaskTemplateListPage page = TaskTemplateListPage.gotoPage();
88+
assertFalse(page.getListedTemplates().contains(templateName + "Provider"));
89+
page.setTemplateName(testTemplate);
90+
setup.getDriver().addPageNotYetReloadedMarker();
91+
page.submit();
92+
assertNotNull(setup.getDriver().findElement(By.className("xnotification-done")));
93+
setup.getDriver().waitUntilPageIsReloaded();
94+
// See that the user is redirected to the template page, ignoring the query string, which contains some tokens.
95+
assertEquals(getTemplateSpaceUrl("edit", testTemplate + "Template", setup), setup.getDriver().getCurrentUrl());
96+
97+
TaskManagerInlinePage taskEditPage = new TaskManagerInlinePage();
98+
taskEditPage.setProgress(testProperty);
99+
taskEditPage.clickSaveAndView();
100+
createPageFromTemplate("TestTaskPage", templateName + "Provider");
101+
taskEditPage = new TaskManagerInlinePage();
102+
// See that the right template is applied.
103+
assertEquals(testProperty, taskEditPage.getProgress());
104+
// Also test that the templates don't show up as dependencies.
105+
assertFalse(taskEditPage.getDependencies().contains(templateName));
106+
107+
// Check that the new template is listed.
108+
page = TaskTemplateListPage.gotoPage();
109+
assertTrue(
110+
page.getListedTemplates().contains(getTemplateSpaceUrl("view", testTemplate + "TemplateProvider", setup)),
111+
"Listed templates: " + page.getListedTemplates());
112+
113+
logout(setup);
114+
}
115+
116+
private String getTemplateSpaceUrl(String action, String templateName, TestUtils setup)
117+
{
118+
return setup.getURL(List.of("TaskManager", "TaskManagerTemplates"), templateName, action, "").split("\\?")[0];
119+
}
120+
121+
private void createPageFromTemplate(String title, String template)
122+
{
123+
TaskManagerHomePage taskManagerHomePage = TaskManagerHomePage.gotoPage();
124+
CreatePagePage createPage = taskManagerHomePage.createPage();
125+
126+
createPage.getDocumentPicker().setTitle(title);
127+
createPage.setTemplate(template);
128+
createPage.clickCreate();
129+
}
130+
131+
private void logout(TestUtils setup)
132+
{
133+
setup.setSession(null);
134+
setup.getDriver().navigate().refresh();
135+
}
136+
}

application-task-test/application-task-test-pageobjects/src/main/java/org/xwiki/contrib/application/task/test/po/TaskManagerHomePage.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@ public TaskManagerInlinePage clickAddEntry()
9191
return new TaskManagerInlinePage();
9292
}
9393

94+
/**
95+
* Click the button which leads to the list of task templates, to redirect to the templates page.
96+
*
97+
* @since 3.10.0
98+
*/
99+
public void clickTaskTemplateListButton()
100+
{
101+
getUtil().getDriver().findElement(By.id("task-manager-view-task-template-list")).click();
102+
}
103+
94104
/**
95105
* @return the FAQ livetable element
96106
* @deprecated since 3.10.0, use {@link #getTaskLiveDataTable()} instead.

application-task-test/application-task-test-pageobjects/src/main/java/org/xwiki/contrib/application/task/test/po/TaskManagerInlinePage.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@
1919
*/
2020
package org.xwiki.contrib.application.task.test.po;
2121

22-
import org.openqa.selenium.Keys;
22+
import java.util.List;
23+
import java.util.stream.Collectors;
24+
2325
import org.openqa.selenium.By;
26+
import org.openqa.selenium.Keys;
2427
import org.openqa.selenium.WebElement;
2528
import org.openqa.selenium.support.FindBy;
2629
import org.openqa.selenium.support.ui.Select;
@@ -67,6 +70,8 @@ public class TaskManagerInlinePage extends InlinePage
6770
@FindBy(id = CLASS_PREFIX + "progress")
6871
private WebElement progressElement;
6972

73+
private static final String DEPENDENCIES_ID = "TaskManager.TaskManagerClass_dependencies";
74+
7075
/**
7176
* @param name the name of the Task entry
7277
*/
@@ -159,6 +164,14 @@ public void setStatus(String status)
159164
statusSelect.selectByValue(status);
160165
}
161166

167+
/**
168+
* @return the progress of the task entry
169+
*/
170+
public String getProgress()
171+
{
172+
return this.progressElement.getAttribute("value");
173+
}
174+
162175
/**
163176
* @param progress the progress for the task entry
164177
*/
@@ -180,4 +193,28 @@ public void appendAssignee(String userReference)
180193
WebElement select = getDriver().findElement(By.cssSelector(".selectize-dropdown-content > div"));
181194
select.click();
182195
}
196+
197+
/**
198+
* @return the name of the Task entry
199+
* @since 3.10.0
200+
*/
201+
public List<String> getDependencies()
202+
{
203+
List<WebElement> dependenciesElements = getUtil().getDriver()
204+
.findElements(By.cssSelector("input[name='TaskManager.TaskManagerClass_0_dependencies']:not([value=''])"));
205+
return dependenciesElements.stream().map(element -> assigneeElement.getAttribute("value"))
206+
.collect(Collectors.toList());
207+
}
208+
209+
/**
210+
* @param dependencyPage the page reference of the task to depend on
211+
*/
212+
public void setDependency(String dependencyPage)
213+
{
214+
List<WebElement> dependency = getUtil().getDriver().findElements(
215+
By.cssSelector("input[name='TaskManager.TaskManagerClass_0_dependencies'][value='" + dependencyPage + "']"));
216+
if (!dependency.isEmpty()) {
217+
dependency.get(0).click();
218+
}
219+
}
183220
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* See the NOTICE file distributed with this work for additional
3+
* information regarding copyright ownership.
4+
*
5+
* This is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU Lesser General Public License as
7+
* published by the Free Software Foundation; either version 2.1 of
8+
* the License, or (at your option) any later version.
9+
*
10+
* This software is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this software; if not, write to the Free
17+
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18+
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19+
*/
20+
package org.xwiki.contrib.application.task.test.po;
21+
22+
import java.util.List;
23+
import java.util.stream.Collectors;
24+
25+
import org.openqa.selenium.By;
26+
import org.openqa.selenium.WebElement;
27+
import org.openqa.selenium.support.FindBy;
28+
import org.xwiki.test.ui.po.ViewPage;
29+
30+
/**
31+
* Represents actions that can be done on the TaskManager.TaskTemplateList page.
32+
*
33+
* @version $Id$
34+
* @since 4.0.0
35+
*/
36+
public class TaskTemplateListPage extends ViewPage
37+
{
38+
@FindBy(id = "button-submit-template")
39+
private WebElement submitTemplateButton;
40+
41+
@FindBy(name = "templateName")
42+
private WebElement templateNameField;
43+
44+
@FindBy(className = "xwiki-livedata")
45+
private WebElement livedataElement;
46+
47+
public static String getURL()
48+
{
49+
return getUtil().getURL("TaskManager", "TaskTemplateList");
50+
}
51+
52+
/**
53+
* Opens the home page.
54+
*/
55+
public static TaskTemplateListPage gotoPage()
56+
{
57+
getUtil().gotoPage("TaskManager", "TaskTemplateList");
58+
return new TaskTemplateListPage();
59+
}
60+
61+
public void submit()
62+
{
63+
submitTemplateButton.click();
64+
}
65+
66+
public void setTemplateName(String name)
67+
{
68+
templateNameField.sendKeys(name);
69+
}
70+
71+
/**
72+
* @return a list of urls to /bin/view/..TemplateProvider
73+
*/
74+
public List<String> getListedTemplates()
75+
{
76+
return livedataElement.findElements(
77+
By.cssSelector("a[href*=\"/bin/view/\"][href*=\"TemplateProvider\"]")).stream()
78+
.map(we -> we.getAttribute("href")).collect(Collectors.toList());
79+
}
80+
}

application-task-ui/src/main/resources/TaskManager/Administration.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
{{include reference="TaskManager.AdministrationAddStatus"/}}
4848
== $services.localization.render('TaskManager.adminitration.addSeverity') ==
4949
{{include reference="TaskManager.AdministrationAddSeverity"/}}
50+
== $services.localization.render('TaskManager.adminitration.templateList') ==
51+
{{include reference="TaskManager.TaskTemplateList"/}}
5052
== $services.localization.render('TaskManager.adminitration.incompleteTasks') ==
5153
{{include reference="TaskManager.AdministrationIncompleteTasks"/}}
5254
#end

0 commit comments

Comments
 (0)