<pe:kanban id="kanban"
widgetVar="kanbanWidget"
value="#{kanbanRightClickController.columns}"
draggable="true"
addItemButton="true"
style="height:420px"
bindContextMenu="contextMenu">
<p:ajax event="itemRightClick" listener="#{kanbanRightClickController.onItemRightClick}" />
<p:ajax event="itemAdd" listener="#{kanbanRightClickController.onItemAdd}" update="kanban growl" />
</pe:kanban>
<p:contextMenu id="contextMenu" widgetVar="contextMenu" targetFilter=".kanban-item">
<p:menuitem value="Edit Task"
icon="pi pi-pencil"
update="dialogContent"
oncomplete="PF('taskDialog').show()" />
<p:divider />
<p:menuitem value="View History"
icon="pi pi-clock"
update="historyContent"
oncomplete="PF('historyDialog').show()" />
<p:menuitem value="Delete Task"
icon="pi pi-trash"
styleClass="text-red-600"
onclick="PF('confirmDelete').show()" />
</p:contextMenu>
<p:confirmDialog id="confirmDeleteDialog" widgetVar="confirmDelete"
showEffect="fade" hideEffect="fade"
message="Are you sure you want to delete this task?"
header="Delete Task" icon="pi pi-exclamation-triangle"
closeOnEscape="true" width="400">
<p:commandButton value="Delete"
styleClass="ui-button-danger mr-2"
actionListener="#{kanbanRightClickController.deleteSelectedItem}"
process="@this"
update="@(.ui-kanban) growl"
oncomplete="PF('confirmDelete').hide()"
icon="pi pi-check" />
<p:commandButton value="Cancel"
onclick="PF('confirmDelete').hide()"
type="button"
styleClass="ui-button-secondary"
icon="pi pi-times" />
</p:confirmDialog>
<p:dialog header="Task Details" widgetVar="taskDialog"
modal="true" responsive="true" width="400"
showEffect="fade" hideEffect="fade"
closeOnEscape="true">
<h:panelGroup id="dialogContent" layout="block" styleClass="ui-fluid">
<h:panelGroup rendered="#{not empty kanbanRightClickController.selectedItem}">
<div class="field mb-3">
<p:outputLabel for="title" value="Title" styleClass="font-bold block mb-1" />
<p:inputText id="title" value="#{kanbanRightClickController.selectedItem.title}" readonly="true" />
</div>
<div class="field mb-3">
<p:outputLabel for="desc" value="Description" styleClass="font-bold block mb-1" />
<p:inputTextarea id="desc" value="#{kanbanRightClickController.selectedItem.description}" rows="3" readonly="true" />
</div>
</h:panelGroup>
<h:panelGroup rendered="#{empty kanbanRightClickController.selectedItem}">
<p>Right-click on a task and select "Edit Task" to see its details here.</p>
</h:panelGroup>
</h:panelGroup>
</p:dialog>
<p:dialog header="Task History" widgetVar="historyDialog"
modal="true" responsive="true" width="400"
showEffect="fade" hideEffect="fade"
closeOnEscape="true">
<h:panelGroup id="historyContent" layout="block" styleClass="ui-fluid">
<h:panelGroup rendered="#{not empty kanbanRightClickController.selectedItem}">
<p>Activity history for <strong>#{kanbanRightClickController.selectedItem.title}</strong>:</p>
<ul>
<li>Created - Jan 15, 2026</li>
<li>Moved to #{kanbanRightClickController.selectedColumnId} - Jan 20, 2026</li>
<li>Milestone updated - Feb 01, 2026</li>
</ul>
</h:panelGroup>
<h:panelGroup rendered="#{empty kanbanRightClickController.selectedItem}">
<p>Right-click on a task and select "View History" to see its activity timeline.</p>
</h:panelGroup>
</h:panelGroup>
</p:dialog>
@Named
@ViewScoped
public class KanbanRightClickController implements Serializable {
private static final long serialVersionUID = 1L;
private List<KanbanColumn> columns;
private KanbanItem selectedItem;
private String selectedColumnId;
@PostConstruct
public void init() {
columns = new ArrayList<>();
KanbanColumn todo = new KanbanColumn("todo", "To Do");
todo.setCssClass("kanban-todo");
todo.getItems().addAll(List.of(
new KanbanItem("task-1", "Design new landing page", "Create wireframes and mockups for the new product landing page"),
new KanbanItem("task-2", "Research competitor features", "Analyze top 3 competitor products and summarize feature differences"),
new KanbanItem("task-3", "Write unit tests", "Increase code coverage to 80% for the payment module")));
columns.add(todo);
KanbanColumn inprogress = new KanbanColumn("inprogress", "In Progress");
inprogress.setCssClass("kanban-inprogress");
inprogress.getItems().addAll(List.of(
new KanbanItem("task-4", "Implement OAuth integration", "Add Google and GitHub OAuth providers"),
new KanbanItem("task-5", "API rate limiting", "Implement rate limiter for public API endpoints")));
columns.add(inprogress);
KanbanColumn done = new KanbanColumn("done", "Done");
done.setCssClass("kanban-done");
done.getItems().addAll(List.of(
new KanbanItem("task-6", "Setup CI/CD pipeline", "Configure GitHub Actions for automated builds and deployment"),
new KanbanItem("task-7", "Database migration script", "Write migration scripts for schema updates")));
columns.add(done);
}
public List<KanbanColumn> getColumns() {
return columns;
}
public KanbanItem getSelectedItem() {
return selectedItem;
}
public String getSelectedColumnId() {
return selectedColumnId;
}
public void onItemRightClick(final KanbanItemRightClickEvent event) {
String itemId = event.getItemId();
String columnId = event.getColumnId();
for (KanbanColumn col : columns) {
if (col.getId().equals(columnId)) {
for (KanbanItem item : col.getItems()) {
if (item.getId().equals(itemId)) {
this.selectedItem = item;
this.selectedColumnId = columnId;
break;
}
}
}
}
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_INFO,
"Right-clicked",
"Item: " + (selectedItem != null ? selectedItem.getTitle() : itemId) + ", Column: " + columnId));
}
public void onItemAdd(final KanbanAddEvent event) {
String columnId = event.getColumnId();
for (KanbanColumn column : columns) {
if (column.getId().equals(columnId)) {
int count = column.getItems().size() + 1;
column.addItem(new KanbanItem(columnId + "-new-" + count, "New Task " + count,
"Click to edit this task"));
break;
}
}
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, "Item Added",
"New item added to column " + columnId);
FacesContext.getCurrentInstance().addMessage(null, message);
}
public void deleteSelectedItem() {
if (selectedItem != null) {
for (KanbanColumn col : columns) {
col.getItems().removeIf(item -> item.getId().equals(selectedItem.getId()));
}
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, "Item Deleted",
"Deleted task: " + selectedItem.getTitle());
FacesContext.getCurrentInstance().addMessage(null, message);
selectedItem = null;
selectedColumnId = null;
}
}
}