1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.poc;
35
36 import static com.vaadin.server.Sizeable.Unit.PERCENTAGE;
37
38 import info.magnolia.icons.MagnoliaIcons;
39 import info.magnolia.poc.task.MagnoliaTask;
40 import info.magnolia.poc.task.MagnoliaTaskService;
41 import info.magnolia.poc.task.TaskStatusRenderer;
42 import info.magnolia.ui.vaadin.actionbar.Actionbar;
43 import info.magnolia.ui.vaadin.dialog.BaseDialog;
44 import info.magnolia.ui.vaadin.gwt.client.actionbar.shared.ActionbarItem;
45
46 import java.util.Arrays;
47 import java.util.List;
48
49 import javax.servlet.annotation.WebServlet;
50
51 import org.jsoup.Jsoup;
52 import org.jsoup.safety.Whitelist;
53
54 import com.vaadin.annotations.Theme;
55 import com.vaadin.annotations.Title;
56 import com.vaadin.annotations.VaadinServletConfiguration;
57 import com.vaadin.annotations.Widgetset;
58 import com.vaadin.data.provider.ListDataProvider;
59 import com.vaadin.server.ThemeResource;
60 import com.vaadin.server.VaadinRequest;
61 import com.vaadin.server.VaadinServlet;
62 import com.vaadin.shared.ui.ContentMode;
63 import com.vaadin.ui.Button;
64 import com.vaadin.ui.ComboBox;
65 import com.vaadin.ui.Component;
66 import com.vaadin.ui.CssLayout;
67 import com.vaadin.ui.FormLayout;
68 import com.vaadin.ui.Grid;
69 import com.vaadin.ui.HorizontalLayout;
70 import com.vaadin.ui.Image;
71 import com.vaadin.ui.Label;
72 import com.vaadin.ui.Panel;
73 import com.vaadin.ui.TabSheet;
74 import com.vaadin.ui.TextArea;
75 import com.vaadin.ui.TextField;
76 import com.vaadin.ui.UI;
77 import com.vaadin.ui.VerticalLayout;
78 import com.vaadin.ui.components.grid.ItemClickListener;
79 import com.vaadin.ui.renderers.HtmlRenderer;
80
81 @Theme("poctheme")
82 @Title("Magnolia 6 Resurface")
83 @Widgetset("info.magnolia.poc.Widgetset")
84 public class TasksBrowser extends UI {
85
86 private HorizontalLayout header = new HorizontalLayout();
87 private CssLayout viewPort = new CssLayout();
88 private TabSheet tabSheetComponent;
89
90 @Override
91 protected void init(VaadinRequest request) {
92 header.setStyleName("header");
93 header.setSpacing(false);
94
95
96 CssLayout logoWrapper = createLogoComponent();
97
98
99 CssLayout finderBarContainer = new CssLayout();
100 finderBarContainer.setStyleName("periscope-wrapper");
101
102 Component finderBar = createFinderBar();
103
104 finderBarContainer.addComponent(finderBar);
105
106
107 CssLayout tasksWrapper = new CssLayout();
108 tasksWrapper.setStyleName("tasks-wrapper");
109 Component taskIndicator = createIndicatorComponent("Tasks", "23", "green");
110 tasksWrapper.addComponent(taskIndicator);
111
112
113 CssLayout messageWrapper = new CssLayout();
114 messageWrapper.setStyleName("messages-wrapper");
115 Component messageIndicator = createIndicatorComponent("Messages", "02", "green");
116 messageWrapper.addComponent(messageIndicator);
117
118
119 Component profileWrapper = createProfileComponent();
120 profileWrapper.setStyleName("profile-wrapper");
121
122
123 Component bannerWrapper = createBannerComponent(tasksWrapper);
124 bannerWrapper.setStyleName("banner-wrapper");
125 bannerWrapper.setVisible(false);
126
127 header.addComponents(logoWrapper, finderBarContainer, tasksWrapper, messageWrapper, profileWrapper);
128
129 viewPort.setStyleName("viewport");
130 viewPort.setSizeFull();
131
132 Component tabSheet = createTabSheetComponent();
133 viewPort.addComponents(bannerWrapper, tabSheet);
134
135
136 final VerticalLayout layout = new VerticalLayout();
137 layout.setStyleName("main-wrapper");
138 layout.setSpacing(false);
139 layout.addComponents(header, viewPort);
140 layout.setMargin(false);
141 layout.setExpandRatio(header, 0f);
142 layout.setExpandRatio(viewPort, 1f);
143 layout.setSizeFull();
144
145 setContent(layout);
146 }
147
148 private CssLayout createLogoComponent() {
149 CssLayout logoWrapper = new CssLayout();
150 logoWrapper.setStyleName("logo-wrapper");
151
152 ThemeResource resource = new ThemeResource("img/logo-magnolia.svg");
153
154 Image image = new Image("Magnolia logo", resource);
155 image.addStyleName("header-component");
156 logoWrapper.addComponent(image);
157 return logoWrapper;
158 }
159
160 private HorizontalLayout createProfileComponent() {
161 HorizontalLayout profileWrapper = new HorizontalLayout();
162 profileWrapper.setSpacing(false);
163 profileWrapper.setMargin(false);
164
165 Label avatar = new Label();
166 avatar.setContentMode(ContentMode.HTML);
167 avatar.addStyleName("header-component");
168 avatar.setValue("<span class='indicator number icon-user-role'></span>");
169 profileWrapper.addComponent(avatar);
170
171 Component profileComponent = createHeaderComponent("public-01", "INT");
172 profileWrapper.addComponent(profileComponent);
173 return profileWrapper;
174 }
175
176 private Component createBannerComponent(CssLayout tasksWrapper) {
177 CssLayout bannerWrapper = new CssLayout();
178 bannerWrapper.setWidth(100, Unit.PERCENTAGE);
179 bannerWrapper.setHeight(80, Unit.PIXELS);
180
181 VerticalLayout banner = new VerticalLayout();
182 banner.addStyleNames("banner", "info");
183 banner.setSpacing(false);
184 banner.setMargin(false);
185
186 Label infoLabel = new Label("Info");
187 infoLabel.addStyleName("header");
188
189 Label bodyLabel = new Label("Your license will expire in 15 days. Renew now.");
190 bodyLabel.addStyleName("body");
191
192 Button closeButton = new Button();
193 closeButton.setCaptionAsHtml(true);
194 closeButton.setPrimaryStyleName("icon-close");
195 closeButton.addStyleName("close");
196 closeButton.addClickListener(e -> bannerWrapper.setVisible(false));
197
198 banner.addComponents(infoLabel, bodyLabel, closeButton);
199 bannerWrapper.addComponent(banner);
200
201 tasksWrapper.addLayoutClickListener(e -> {
202 if (!bannerWrapper.isVisible()) {
203 bannerWrapper.setVisible(true);
204 }
205
206 switch (banner.getStyleName()) {
207 case "banner info":
208 banner.removeStyleName("info");
209 banner.addStyleName("warning");
210 infoLabel.setValue("Warning");
211 bodyLabel.setValue("Your license will expire tomorrow. Magnolia will stop functioning if no valid license is found. Renew now.");
212 break;
213 case "banner warning":
214 banner.removeStyleName("warning");
215 banner.addStyleName("error");
216 infoLabel.setValue("Error");
217 bodyLabel.setValue("The multipart stream ended unexpectedly. More.");
218 break;
219 case "banner error":
220 banner.removeStyleName("error");
221 banner.addStyleName("info");
222 infoLabel.setValue("Info");
223 bodyLabel.setValue("Your license will expire in 15 days. Renew now.");
224 break;
225 }
226 });
227
228 return bannerWrapper;
229 }
230
231 private HorizontalLayout createFinderBar() {
232 HorizontalLayout finderBar = new HorizontalLayout();
233 finderBar.addStyleName("header-component");
234 finderBar.setSpacing(false);
235 finderBar.setMargin(false);
236 finderBar.setSizeFull();
237 Button shellButton = new Button();
238 shellButton.addStyleName("btn-shell icon-appslauncher btn-appslauncher");
239 finderBar.addComponent(shellButton);
240 finderBar.setExpandRatio(shellButton, 0f);
241
242 CssLayout searchField = new CssLayout();
243 searchField.setStyleName("search-field");
244 TextField textField = new TextField();
245 textField.addStyleNames("search-textfield", "heading-2");
246 textField.setPlaceholder("Type to find");
247 searchField.addComponent(textField);
248 Label searchIcon = new Label();
249 searchIcon.setStyleName("icon-search");
250 searchField.addComponent(searchIcon);
251
252 finderBar.addComponent(searchField);
253 finderBar.setExpandRatio(searchField, 1f);
254
255
256 Button voiceButton = new Button();
257 voiceButton.addStyleName("btn-shell icon-target-app btn-voice");
258 finderBar.addComponent(voiceButton);
259 finderBar.setExpandRatio(voiceButton, 0f);
260
261 return finderBar;
262 }
263
264 private Component createIndicatorComponent(String label, String value, String status) {
265 return createHeaderComponent(label, value + "<span class='status icon-status-" + status + " color-" + status + "'></span>");
266 }
267
268 private Component createHeaderComponent(String label, String value) {
269
270 VerticalLayout tasksComponent = new VerticalLayout();
271 tasksComponent.setSpacing(false);
272 tasksComponent.setMargin(false);
273 tasksComponent.setStyleName("header-component");
274 Label taskNumber = new Label();
275 taskNumber.addStyleName("indicator heading-2");
276 taskNumber.setValue(value);
277 taskNumber.setContentMode(ContentMode.HTML);
278 Label taskLabel = new Label(label);
279 taskLabel.addStyleNames("text-tiny");
280 tasksComponent.addComponents(taskNumber, taskLabel);
281 tasksComponent.addLayoutClickListener(event -> onTasksCounterClick(event));
282
283 return tasksComponent;
284 }
285
286 private void onTasksCounterClick(Event event) {
287 int number = (int) (Math.random() * 100);
288 ((Label) ((VerticalLayout) event.getComponent()).getComponent(0)).setValue(String.valueOf(number));
289 tabSheetComponent.getTab(0).setCaption("<span style='word-spacing: 7px;'>Tasks | <a href='#'>New " + number + "</a></span>");
290 ((Label) ((HorizontalLayout) ((VerticalLayout) ((HorizontalLayout) ((VerticalLayout) tabSheetComponent.getTab(0).getComponent()).getComponent(0)).getComponent(0)).getComponent(0)).getComponent(0)).setValue("Tasks | <a href='#'>New (" + number + ")</a>");
291 }
292
293 private Component createTabSheetComponent() {
294 tabSheetComponent = new TabSheet();
295 tabSheetComponent.addStyleName("apps");
296 tabSheetComponent.setSizeFull();
297 tabSheetComponent.setTabCaptionsAsHtml(true);
298 tabSheetComponent.addTab(createBrowserAppComponent("Tasks | <a href='#'>New (23)</a>"), "<span style='word-spacing: 7px;'>Tasks | <a href='#'>New 23</a></span>", MagnoliaIcons.SELECT);
299 tabSheetComponent.addTab(createBrowserAppComponent("Tasks | Assigned"), "Assigned");
300 tabSheetComponent.addTab(createBrowserAppComponent("Tasks | Resolved"), "Resolved");
301 tabSheetComponent.addTab(createBrowserAppComponent("Tasks | Failed"), "Failed");
302 tabSheetComponent.addTab(createBrowserAppComponent("Tasks | Scheduled"), "Scheduled");
303 tabSheetComponent.addTab(createBrowserAppComponent("Tasks | All tasks"), "All tasks");
304 tabSheetComponent.setSizeFull();
305 tabSheetComponent.setSelectedTab(1);
306 return tabSheetComponent;
307 }
308
309 private Component createBrowserAppComponent(String label) {
310 VerticalLayout browser = new VerticalLayout();
311 browser.addStyleName("browser");
312 browser.setSizeFull();
313 browser.setMargin(false);
314
315 VerticalLayout workbench = new VerticalLayout();
316 workbench.addStyleName("workbench");
317 workbench.setSizeFull();
318 workbench.setMargin(false);
319 Component toolBar = buildTabNameBar(label);
320 Component contentView = buildContentView();
321 Component statusBar = buildStatusBar();
322 workbench.addComponents(toolBar, contentView, statusBar);
323 workbench.setExpandRatio(toolBar, 0f);
324 workbench.setExpandRatio(contentView, 1f);
325
326 Component actionbar = buildActionBar();
327
328 HorizontalLayout workbenchWrapper = new HorizontalLayout();
329 workbenchWrapper.setSizeFull();
330 workbenchWrapper.addComponents(workbench, actionbar);
331 workbenchWrapper.setExpandRatio(workbench, 1f);
332 workbenchWrapper.setExpandRatio(actionbar, 0f);
333
334
335 browser.addComponents(workbenchWrapper, statusBar);
336 browser.setExpandRatio(workbenchWrapper, 1f);
337 browser.setExpandRatio(statusBar, 0f);
338
339
340 return browser;
341 }
342
343 private Component buildTabNameBar(String label) {
344 HorizontalLayout tabNameBar = new HorizontalLayout();
345 tabNameBar.setWidth(100, PERCENTAGE);
346 tabNameBar.addStyleName("tabNameBar");
347 tabNameBar.setSpacing(true);
348
349 Label tabName = new Label(label, ContentMode.HTML);
350
351 tabNameBar.addComponents(tabName);
352
353 return tabNameBar;
354 }
355
356 private Component buildContentView() {
357 Panel keyboardPanel = new Panel();
358 keyboardPanel.setSizeFull();
359 keyboardPanel.addStyleName("keyboard-panel");
360
361 Grid<MagnoliaTask> grid = new Grid<>();
362
363 grid.setSizeFull();
364 grid.setBodyRowHeight(75);
365
366 grid.addColumn(task -> task.getStatus().name(), new TaskStatusRenderer()).setCaption("New").setExpandRatio(1);
367 grid.addColumn(task -> " <div style='height:59px; padding-top:16px'>" + MagnoliaIcons.WORK_ITEM.getHtml() + "</div> <div style='height:59px; padding-top:16px; padding-left:20px'><span style='line-height:normal; padding-top:16px'>" + Jsoup.clean(task.getName(), Whitelist.simpleText()) + "</span><br/><span style='font-size:12px; line-height:normal; padding-top:8px'>" + Jsoup.clean(task.getDescription(), Whitelist.simpleText()) + "</span></div>", new HtmlRenderer()).setCaption("Task").setExpandRatio(5);
368 grid.addColumn(MagnoliaTask::getStatus).setCaption("Status").setExpandRatio(2);
369 grid.addColumn(MagnoliaTask::getSender).setCaption("Sender").setExpandRatio(2);
370 grid.addColumn(task -> MagnoliaIcons.USER_GROUP.getHtml() + " <span style='height:59px; padding-top:16px; padding-left:8px'>" + Jsoup.clean(task.getSendTo(), Whitelist.simpleText()) + "</span>", new HtmlRenderer()).setCaption("Sent to").setExpandRatio(2);
371 grid.addColumn(MagnoliaTask::getAssigned).setCaption("Assigned").setExpandRatio(2);
372 grid.addColumn(MagnoliaTask::getLastChange).setCaption("Last changed").setExpandRatio(2);
373
374 grid.setSelectionMode(Grid.SelectionMode.MULTI);
375
376 grid.addItemClickListener((ItemClickListener<MagnoliaTask>) event -> {
377 if (event.getSource().getSelectionModel().isSelected(event.getItem())) {
378 event.getSource().getSelectionModel().deselect(event.getItem());
379 } else {
380 event.getSource().getSelectionModel().select(event.getItem());
381 }
382 });
383
384
385
386 MagnoliaTaskService service = MagnoliaTaskService.getInstance();
387 List<MagnoliaTask> magnoliaTasks = service.findAll();
388 grid.setItems(magnoliaTasks);
389
390 keyboardPanel.setContent(grid);
391
392 return keyboardPanel;
393 }
394
395 private Component buildStatusBar() {
396 HorizontalLayout statusBar = new HorizontalLayout();
397 statusBar.addStyleName("statusbar");
398 statusBar.setWidth(100, PERCENTAGE);
399
400 Label label = new Label("Profile images / Directors / Managing directors /");
401 label.setWidth(100, PERCENTAGE);
402
403 statusBar.addComponent(label);
404
405 return statusBar;
406 }
407
408 private Component buildActionBar() {
409 Actionbar actionbar = new Actionbar();
410 actionbar.addSection("main", "Actions");
411 actionbar.addAction(new ActionbarItem("addAction", "Add action", "icon-add-item", "addActions"), "main");
412 actionbar.addAction(new ActionbarItem("deleteAction", "Delete action", "icon-delete", "addActions"), "main");
413 actionbar.addAction(new ActionbarItem("editAction", "Edit action", "icon-edit", "editActions"), "main");
414 CssLayout wrapper = new CssLayout();
415 wrapper.addComponent(actionbar);
416 wrapper.setWidthUndefined();
417 wrapper.setHeight(100, Unit.PERCENTAGE);
418 wrapper.addStyleName("actionbar");
419 return wrapper;
420 }
421
422 private Component createDetailAppWithBaseDialog() {
423 HorizontalLayout detail = new HorizontalLayout();
424 detail.addStyleName("detail basedialog");
425 detail.setSizeFull();
426
427 CssLayout detailView = new CssLayout();
428 detailView.addStyleName("detailview");
429 detailView.setSizeFull();
430 detail.addComponent(detailView);
431
432 BaseDialog baseDialog = new BaseDialog();
433 baseDialog.setCaption("Asset");
434 baseDialog.setDialogDescription("This is description");
435 baseDialog.setDescriptionVisibility(true);
436 baseDialog.setSizeFull();
437
438 baseDialog.setContent(createDetailForm());
439
440 CssLayout footer = new CssLayout();
441 footer.setWidth(100, PERCENTAGE);
442 footer.addComponents(createActions());
443 baseDialog.setFooterToolbar(footer);
444
445 Panel panel = new Panel();
446 panel.setSizeFull();
447 panel.setContent(baseDialog);
448
449 detailView.addComponent(panel);
450
451 return detail;
452 }
453
454 private Component createDetailAppWithVerticalLayout() {
455 VerticalLayout detailLayout = new VerticalLayout();
456 detailLayout.addStyleName("detail");
457 detailLayout.setSizeFull();
458 detailLayout.setMargin(false);
459 detailLayout.setSpacing(false);
460
461 Label title = new Label();
462 title.addStyleName("heading-1 title");
463 title.setValue("Asset");
464
465 CssLayout header = new CssLayout();
466 header.addStyleName("detail-header");
467 header.addComponent(title);
468
469 Component detailForm = createDetailForm();
470 detailForm.addStyleName("detail-content");
471
472 CssLayout footer = new CssLayout();
473 footer.addStyleName("detail-footer");
474 footer.setWidth(100, PERCENTAGE);
475 footer.addComponents(createActions());
476
477 detailLayout.addComponents(header, detailForm, footer);
478 detailLayout.setExpandRatio(header, 0f);
479 detailLayout.setExpandRatio(detailForm, 1f);
480 detailLayout.setExpandRatio(footer, 0f);
481
482 return detailLayout;
483 }
484
485 private Component createDetailForm() {
486 TabSheet tabSheetComponent = new TabSheet();
487 tabSheetComponent.setSizeFull();
488
489 tabSheetComponent.addTab(createTab1(), "Meta Data");
490 tabSheetComponent.addTab(createTab2(), "Article Info");
491 tabSheetComponent.addTab(createTab3(), "Output channels");
492
493 return tabSheetComponent;
494 }
495
496 private FormLayout createTab1() {
497 FormLayout form = new FormLayout();
498 form.setMargin(true);
499 form.setSizeFull();
500
501 TextField textField = new TextField("Asset name");
502
503 TextField textFieldHover = new TextField("File name");
504 textFieldHover.setDescription("This is file name");
505
506 TextField textFieldFocus = new TextField("Location");
507 textFieldFocus.setValue("Basel ");
508
509 form.addComponents(textField,
510 textFieldHover,
511 textFieldFocus);
512
513 form.iterator().forEachRemaining(
514 component -> component.setWidth(100, PERCENTAGE)
515 );
516
517 return form;
518 }
519
520 private FormLayout createTab2() {
521 FormLayout form = new FormLayout();
522 form.setMargin(true);
523 form.setSizeFull();
524
525 TextField disabledTextField = new TextField("Author");
526 disabledTextField.setEnabled(false);
527
528 TextField textFieldValidation = new TextField("Birthday");
529
530 form.addComponents(disabledTextField,
531 textFieldValidation);
532
533 form.iterator().forEachRemaining(
534 component -> component.setWidth(100, PERCENTAGE)
535 );
536
537 return form;
538 }
539
540 private FormLayout createTab3() {
541 FormLayout form = new FormLayout();
542 form.setMargin(true);
543 form.setSizeFull();
544
545 TextField textFieldWithPlaceHolder = new TextField("Title");
546 textFieldWithPlaceHolder.setPlaceholder("Add title here...");
547
548 TextArea expandable = new TextArea("Description");
549 expandable.setRows(1);
550
551 form.addComponents(textFieldWithPlaceHolder,
552 expandable);
553
554 form.iterator().forEachRemaining(
555 component -> component.setWidth(100, PERCENTAGE)
556 );
557
558 return form;
559 }
560
561 private Component[] createActions() {
562 ComboBox<String> languageSelector = new ComboBox<>();
563 ListDataProvider<String> dataProvider = new ListDataProvider<>(Arrays.asList("English", "Việt Nam"));
564 languageSelector.setEmptySelectionAllowed(false);
565 languageSelector.setPlaceholder("Select...");
566 languageSelector.addStyleName("secondary-actions");
567 languageSelector.setDataProvider(dataProvider);
568
569 Button saveButton = new Button("Save changes");
570 saveButton.addStyleName("commit primary-button primary-actions");
571
572 Button downloadButton = new Button("Download");
573 downloadButton.addStyleName("download secondary-button primary-actions");
574
575 Button cancelButton = new Button("Cancel");
576 cancelButton.addStyleName("cancel secondary-button primary-actions");
577
578 return new Component[]{languageSelector, saveButton, downloadButton, cancelButton};
579 }
580
581 @Override
582 public boolean equals(Object obj) {
583 return super.equals(obj);
584 }
585
586 @Override
587 public int hashCode() {
588 return super.hashCode();
589 }
590
591 @WebServlet(value = "/tasksbrowser/*", asyncSupported = true)
592 @VaadinServletConfiguration(productionMode = false, ui = TasksBrowser.class)
593 public static class Servlet extends VaadinServlet {
594 }
595 }