diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 00000000000..72241dfbcd5 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,23 @@ +changelog: + categories: + - title: 'šŸš€ Features' + labels: + - 'feature' + - 'enhancement' + - title: 'šŸ› Bug Fixes' + labels: + - 'fix' + - 'bugfix' + - 'bug' + - title: 'šŸ“¦ Dependencies' + label: 'dependencies' + - title: āš ļø Changes + labels: + - 'deprecated' + - title: šŸ“„ Documentation + labels: + - 'docs' + - 'documentation' + exclude: + labels: + - 'skip-changelog' diff --git a/AxonIvyPortal/PortalKitTestHelper/pom.xml b/AxonIvyPortal/PortalKitTestHelper/pom.xml index 92f67094eef..9b1856defa9 100644 --- a/AxonIvyPortal/PortalKitTestHelper/pom.xml +++ b/AxonIvyPortal/PortalKitTestHelper/pom.xml @@ -7,8 +7,8 @@ 9.1.0.0-SNAPSHOT iar - 12.0.0 - 12.0.0 + 12.0.1 + 12.0.0-SNAPSHOT UTF-8 diff --git a/AxonIvyPortal/portal-components/pom.xml b/AxonIvyPortal/portal-components/pom.xml index 21011bc121d..7f1813bde05 100644 --- a/AxonIvyPortal/portal-components/pom.xml +++ b/AxonIvyPortal/portal-components/pom.xml @@ -16,8 +16,8 @@ - 12.0.0 - 12.0.0 + 12.0.1 + 12.0.0-SNAPSHOT UTF-8 diff --git a/AxonIvyPortal/portal-migration/pom.xml b/AxonIvyPortal/portal-migration/pom.xml index a0353fc56c4..fab872d578f 100644 --- a/AxonIvyPortal/portal-migration/pom.xml +++ b/AxonIvyPortal/portal-migration/pom.xml @@ -6,8 +6,8 @@ 9.4.0 iar - 12.0.0 - 12.0.0 + 12.0.1 + 12.0.0-SNAPSHOT diff --git a/AxonIvyPortal/portal-selenium-test/customized_pom.xml b/AxonIvyPortal/portal-selenium-test/customized_pom.xml index 70d06c19157..09309492b2a 100644 --- a/AxonIvyPortal/portal-selenium-test/customized_pom.xml +++ b/AxonIvyPortal/portal-selenium-test/customized_pom.xml @@ -6,8 +6,8 @@ 9.1.0.0-SNAPSHOT iar - 12.0.0 - 12.0.0 + 12.0.0-SNAPSHOT + 12.0.1 UTF-8 @@ -20,7 +20,7 @@ com.axonivy.ivy.webtest web-tester - 10.0.0 + 11.3.0 test diff --git a/AxonIvyPortal/portal-selenium-test/document_screenshot_pom.xml b/AxonIvyPortal/portal-selenium-test/document_screenshot_pom.xml index 64fdb25fbfd..09bffcb6333 100644 --- a/AxonIvyPortal/portal-selenium-test/document_screenshot_pom.xml +++ b/AxonIvyPortal/portal-selenium-test/document_screenshot_pom.xml @@ -6,8 +6,8 @@ 9.1.0.0-SNAPSHOT pom - 12.0.0 - 12.0.0 + 12.0.0-SNAPSHOT + 12.0.1 UTF-8 @@ -30,7 +30,7 @@ com.axonivy.ivy.webtest web-tester - 10.0.0 + 11.3.0 test diff --git a/AxonIvyPortal/portal-selenium-test/pom.xml b/AxonIvyPortal/portal-selenium-test/pom.xml index 0d9279096db..9b533775639 100644 --- a/AxonIvyPortal/portal-selenium-test/pom.xml +++ b/AxonIvyPortal/portal-selenium-test/pom.xml @@ -7,15 +7,15 @@ 9.1.0.0-SNAPSHOT iar - 12.0.0 - 12.0.0 + 12.0.1 + 12.0.0-SNAPSHOT UTF-8 com.axonivy.ivy.webtest web-tester - 10.0.0 + 11.3.0 test diff --git a/AxonIvyPortal/portal-selenium-test/resources/css/document-screenshot.css b/AxonIvyPortal/portal-selenium-test/resources/css/document-screenshot.css index a6e51bbe0a8..015f547d564 100644 --- a/AxonIvyPortal/portal-selenium-test/resources/css/document-screenshot.css +++ b/AxonIvyPortal/portal-selenium-test/resources/css/document-screenshot.css @@ -1,3 +1,12 @@ +/*****CSS FOR DECORATE SCREENSHOT***** + THIS scrollbar-width is used to prevent + the gap on the right side when selenide taking screenshot + it only happens on Linux environment. +*/ +html { + scrollbar-width: none; +} + /*****CSS FOR DECORATE SCREENSHOT******/ .marker { position: absolute; diff --git a/AxonIvyPortal/portal-selenium-test/resources/js/document-screenshot.js b/AxonIvyPortal/portal-selenium-test/resources/js/document-screenshot.js index 8e9b4caacee..72d33cbad1f 100644 --- a/AxonIvyPortal/portal-selenium-test/resources/js/document-screenshot.js +++ b/AxonIvyPortal/portal-selenium-test/resources/js/document-screenshot.js @@ -34,25 +34,6 @@ function createRedThickOutlineWithOffset($element) { } /***IMPLEMENTATION TO DECORATE PAGES - WHICH ARE CALLED IN SELENIUM****/ -function highlightDashboardWidget() { - createRedMediumOutline($("#task-widget")); - createRedMediumOutline($("#process-widget")); -} - -function highlightAndNumberingDashboardSections() { - var processWidget = $("#process-widget"); - createRedMediumOutline(processWidget); - appendStepAnnotation(processWidget, "1", 0 , processWidget.width()/2); - var taskWidget = $("#task-widget"); - createRedMediumOutline(taskWidget); - appendStepAnnotation(taskWidget, "2", 0, taskWidget.width()/2); -} - -function numberingTaskFilter() { - var taskOrder = jQuery("#task-widget\\:compact-task-widget-sort-menu"); - appendStepAnnotation(taskOrder, 2, -15,100) -} - function highlightTopBar() { var topMenu = $("#top-menu"); var searchIcon = topMenu.find("li.topbar-item.search-item"); @@ -61,6 +42,8 @@ function highlightTopBar() { $(themeSwitchIcon).addClass("red-topbottom-medium-border"); var chatItem = topMenu.find("li.topbar-item.chat-item"); $(chatItem).addClass("red-topbottom-medium-border"); + var notificationIcon = $("#open-notifications-panel")[0].parentElement; + $(notificationIcon).addClass("red-topbottom-medium-border"); var userNameItem = topMenu.find("li.topbar-item.user-profile.setting-container"); $(userNameItem).addClass("red-topbottomright-medium-border"); } @@ -82,31 +65,6 @@ function highlightLogo() { createRedMediumOutline($(".portal-home-logo.portal-home-logo-small")); } -function numberingTaskItem() { - var taskPriorityFirstRow = jQuery(".priority-cell:eq(0)"); - appendStepAnnotation(taskPriorityFirstRow, "1", -35, 0); - - var taskNameFirstRow = jQuery(".task-start-info-task-name:eq(0)"); - appendStepAnnotation(taskNameFirstRow, "2", -10, 160); - - var taskIdSecondRow = jQuery(".task-start-info-task-name:eq(1)"); - appendStepAnnotation(taskIdSecondRow, "3", -10, 170); - - var taskDatesThirddRow = jQuery(".task-start-info-content:eq(2)"); - appendStepAnnotation(taskDatesThirddRow, "4", -10, -45); - appendStepAnnotation(taskDatesThirddRow, "5", -10, 120); - - var taskDescriptionFourthRow = jQuery(".task-start-info-task-description:eq(3)"); - appendStepAnnotation(taskDescriptionFourthRow, "6", -10, 175); -} - -function numberingTaskFilterAndSort() { - var taskFilter = $("#task-widget\\:filter-form\\:filter-container"); - appendStepAnnotation(taskFilter, 1, -15, taskFilter.width()/2); - var taskSort = $("#task-widget\\:sort-task-form\\:sort-task-menu"); - appendStepAnnotation(taskSort, 2, -15, taskSort.width()/2); -} - function highlightProcessNavigation() { createRedThickOutlineWithOffset($('.layout-menu .PROCESS')); } @@ -202,72 +160,6 @@ function highlightShowMoreNoteLink() { createRedMediumOutline($('a.js-note-show-more-link')); } -function highlightCustomCaseList() { - var caseHeader = $("[id$='case-widget:widget-column-header']"); - createRedMediumOutline(caseHeader); - appendStepAnnotation(caseHeader, "1", -15, caseHeader.width()/2); - - var action = $(".case-header-container.case-header-data:eq(1)"); - createRedMediumOutline(action); - appendStepAnnotation(action, "2", -15, caseHeader.width()/2); -} - -function highlightCustomColumnsConfigOnCaseList() { - var customColumnHeader = $(".ui-commandlink.customized-case-header-column:eq(0)"); - createRedMediumOutline(customColumnHeader) - appendStepAnnotation(customColumnHeader, "1", -30, -20); - - var columnsCheckbox = $("[id$=':select-columns-form:columns-checkbox']"); - var customCheckbox = columnsCheckbox.find("td:eq(5)"); - createRedMediumOutline(customCheckbox); - appendStepAnnotation(customCheckbox, "2", -20, customCheckbox.width() - 10); - - var caseHeader = $(".case-info-row.js-case-start-link:eq(6)"); - var customCaseItemCell = caseHeader.find("span.customized-case-header-column:eq(0)"); - createRedMediumOutline(customCaseItemCell); - appendStepAnnotation(customCaseItemCell, "3", -20, - 20); -} - -function highlightCaseCreatorFilter() { - var filterLabel = $("[id$=':creator-filter:filter-open-form:advanced-filter-command']"); - createRedMediumOutline(filterLabel); - appendStepAnnotation(filterLabel, "1", -25, -30); - - var removeFilterCommand = $("[id$=':creator-filter:filter-open-form:advanced-filter-remove-command']"); - createRedMediumOutline(removeFilterCommand); - appendStepAnnotation(removeFilterCommand, "2", -25, removeFilterCommand.width()); - - var updateCommand = $("[id$=':creator-filter:filter-input-form:update-command']"); - createRedMediumOutline(updateCommand); - appendStepAnnotation(updateCommand, "3", -2, -40) -} - -function highlightEditSwitchProcessButton() { - var editSwitchCommand = $("[id$='process-widget:user-process-action-form:editing-switch-command']"); - createRedMediumOutline(editSwitchCommand); - appendStepAnnotation(editSwitchCommand, "1", -45, editSwitchCommand.width()/2); -} - -function highlightEditStepUserProcess(isDeleteProcess) { - var userProcessList = $("[id$='process-widget:edit-process-item-form:order-list-items']"); - var userProcessItem = userProcessList.find("li.ui-orderlist-item.ui-sortable-handle:eq(0)"); - if (isDeleteProcess) { - var processDeleteLink = userProcessItem.find("[id$=':process-delete-link']"); - createRedMediumOutline(processDeleteLink); - appendStepAnnotation(processDeleteLink, "2", -40, processDeleteLink.width()/2); - } else { - appendStepAnnotation(userProcessItem, "2", 4, userProcessItem.width()/2); - } - - var processSaveLink = $("[id$='process-widget:user-process-action-form:save-process-command']"); - createRedMediumOutline(processSaveLink); - appendStepAnnotation(processSaveLink, "3", -40, -20); -} - -function highlightSortUserProcess() { - createRedMediumOutline($("[id$=':user-process-action-form:name-sort-command']")); -} - function highlightProcessMoreInformationLink() { var displayingProcessItem = $(".js-process-start-list-item").filter(function() { if($(this).css('display') != 'none') @@ -280,47 +172,6 @@ function highlightProcessMoreInformationLink() { } // Task -function highlightCustomTaskList() { - var caseHeader = $("[id$='task-widget:task-widget-sub-header']"); - createRedMediumOutline(caseHeader); - appendStepAnnotation(caseHeader, "1", -15, caseHeader.width()/2); - - var action = $(".full-mode.task-start-list-item.js-task-start-list-item:eq(2)"); - createRedMediumOutline(action); - appendStepAnnotation(action, "2", -15, caseHeader.width()/2); -} - -function highlightCustomColumnsConfigOnTaskList() { - var customColumnHeader = $("[id$=':task-custom']")[0]; - createRedMediumOutline($(customColumnHeader)) - appendStepAnnotation($(customColumnHeader), "1", -30, -20); - - var columnsCheckbox = $("[id$='task-columns-configuration:select-columns-form:columns-checkbox']"); - var customCheckbox = columnsCheckbox.find("td:eq(7)"); - createRedMediumOutline(customCheckbox); - appendStepAnnotation(customCheckbox, "2", -20, customCheckbox.width() - 10); - - var taskHeader = $(".task-start-link.js-task-start-link:eq(4)"); - var customTaskItemCell = taskHeader.find(".task-custom-field-cell"); - createRedMediumOutline(customTaskItemCell); - appendStepAnnotation(customTaskItemCell, "3", -20, - 20); -} - - -function highlightTaskStateFilter() { - var filterLabel = $("[id$=':state-filter:filter-open-form:advanced-filter-command']"); - createRedMediumOutline(filterLabel); - appendStepAnnotation(filterLabel, "1", -25, -30); - - var removeFilterCommand = $("[id$=':state-filter:filter-open-form:advanced-filter-remove-command']"); - createRedMediumOutline(removeFilterCommand); - appendStepAnnotation(removeFilterCommand, "2", -25, removeFilterCommand.width()); - - var updateCommand = $("[id$=':state-filter:filter-input-form:update-command']"); - createRedMediumOutline(updateCommand); - appendStepAnnotation(updateCommand, "3", -2, -40) -} - function highlightJoinGroupChatOption() { createRedMediumOutline($('#horizontal-task-action-form\\:chat-group').parent()); } @@ -349,36 +200,10 @@ function scrollToMiddleOfLayoutContent() { window.scrollTo(0, document.body.scrollHeight/2); } -function scrollToMiddleOfLayoutContent2() { - window.scrollTo(0, document.body.scrollHeight/4); -} - function scrollToBottomOfLayoutContent() { window.scrollTo(0, document.body.scrollHeight); } -function highlightCustomTaskDetail() { - var customTop = $('.custom-task-details-panel-top'); - appendStepAnnotation(customTop, 1, -45, customTop.width()/2); - - var customBottom = $('.custom-task-details-panel-bottom'); - appendStepAnnotation(customBottom, 2, -45, customBottom.width()/2); -} - -function highlightCustomTaskDetailWithNewStyle() { - var customPanel1 = $('.custom-task-panel-1'); - appendStepAnnotation(customPanel1, 1, -10, customPanel1.width()/2); - - var customPanel2 = $('.custom-task-panel-2'); - appendStepAnnotation(customPanel2, 2, -10, customPanel2.width()/2); - - var customPanel3 = $('.custom-task-panel-3'); - appendStepAnnotation(customPanel3, 3, -10, customPanel3.width()/2); - - var customPanel4 = $('.custom-task-panel-4'); - appendStepAnnotation(customPanel4, 4, -10, customPanel4.width()/2); -} - function highlightCaseDetailComponents() { var general = $('#case-details-information-panel'); appendStepAnnotation(general, 1, 0, general.width()/2); @@ -423,14 +248,6 @@ function highlightTaskActionItem(taskIndex, actionIndex) { createRedMediumOutline(actionItem); } -function highlightShowAllProcesses() { - createRedThickOutlineWithOffset($('.layout-menu .PROCESS')); -} - -function highlightTaskExportToExcelButton() { - createRedMediumOutline($("[id$=':task-export-to-excel-form']")); -} - function highlightCaseExportToExcelButton() { createRedMediumOutline($("a[id$=':case-export-to-excel']")); } @@ -456,16 +273,6 @@ function highlightCustomWidgetInCaseDetails() { createRedMediumOutline($(".custom-widget-card")); } -function addStepToCustomWidgetTopTaskDetails() { - var topWidget = $(".custom-task-details-panel-top"); - appendStepAnnotation(topWidget, 1, -30, topWidget.width()/2) -} - -function addStepTCustomWidgetTopTaskDetails() { - var bottomWidget = $(".custom-task-details-panel-bottom"); - appendStepAnnotation(bottomWidget, 2, -30, bottomWidget.width()/2) -} - function highlightIFrameWidgetTaskDetails() { createRedMediumOutline($(".custom-widget-card.task-detail-card")); } @@ -482,10 +289,6 @@ function clearHighlightUserName() { clearRedMediumOutline($('#user-settings-menu')); } -function highlightServerInfo() { - createRedMediumOutline($("#server-infor")); -} - function highlightUserExampleNavigation() { createRedThickOutlineWithOffset($('.layout-menu .CUSTOM')); } @@ -558,8 +361,4 @@ function createBlackThinOutline($element) { function createBlackMediumOutline($element) { $element.addClass("black-medium-outline"); -} - -function highlightElement(elementSelector) { - createRedMediumOutline($(elementSelector)); -} +} \ No newline at end of file diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/common/ComplexFilterHelper.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/common/ComplexFilterHelper.java index 8c26728eac8..176cfec0fd5 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/common/ComplexFilterHelper.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/common/ComplexFilterHelper.java @@ -15,6 +15,7 @@ import com.codeborne.selenide.CollectionCondition; import com.codeborne.selenide.Condition; import com.codeborne.selenide.SelenideElement; +import com.codeborne.selenide.WebElementCondition; public class ComplexFilterHelper { protected final static Duration DEFAULT_TIMEOUT = Duration.ofSeconds(45); @@ -219,7 +220,7 @@ private static SelenideElement getValueOfCheckBox(String value) { .$$("li.ui-selectcheckboxmenu-item").filter(text(value)).first().$("div.ui-chkbox-box"); } - protected static Condition getClickableCondition() { + protected static WebElementCondition getClickableCondition() { return and("should be clickable", visible, exist); } diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/document/screenshot/DashboardScreenshotTest.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/document/screenshot/DashboardScreenshotTest.java index 2d673f25df7..bdd8fc0b44f 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/document/screenshot/DashboardScreenshotTest.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/document/screenshot/DashboardScreenshotTest.java @@ -42,7 +42,6 @@ import com.axonivy.portal.selenium.util.ConfigurationJsonUtils; import com.codeborne.selenide.CollectionCondition; import com.codeborne.selenide.Condition; -import com.codeborne.selenide.SelenideElement; import ch.ivy.addon.portalkit.enums.PortalVariable; @@ -354,10 +353,8 @@ public void screenshotTaskByPriorityClientStatisticChartWidget() throws IOExcept NewDashboardDetailsEditPage newDashboard = new NewDashboardDetailsEditPage(); newDashboard.waitPageLoaded(); - SelenideElement clientStatisticWidget = newDashboard.getStatisticWidgetConfigurationDialog(); ScreenshotUtils.capturePageScreenshot(ScreenshotUtils.NEW_DASHBOARD_FOLDER + "edit-statistic-widget"); - ScreenshotUtils.captureElementWithMarginOptionScreenshot(clientStatisticWidget, - ScreenshotUtils.NEW_DASHBOARD_FOLDER + "task-by-priority-statistic-widget-configuration", new ScreenshotMargin(20)); + ScreenshotUtils.capturePageScreenshot(ScreenshotUtils.NEW_DASHBOARD_FOLDER + "task-by-priority-statistic-widget-configuration"); redirectToRelativeLink(PORTAL_HOME_PAGE_URL); homePage = new NewDashboardPage(); ScreenshotUtils.captureElementScreenshot(homePage.waitAndGetClientStatisticChart(0), diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/document/screenshot/HandleErrorPageScreenshotTest.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/document/screenshot/HandleErrorPageScreenshotTest.java index eb9c4195300..1832ffb06bd 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/document/screenshot/HandleErrorPageScreenshotTest.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/document/screenshot/HandleErrorPageScreenshotTest.java @@ -25,7 +25,7 @@ public class HandleErrorPageScreenshotTest extends ScreenshotBaseTest { @Test public void screenshotErrorPages() throws IOException { - ScreenshotUtils.resizeBrowser(new Dimension(1200, 800)); + ScreenshotUtils.resizeBrowser(new Dimension(1280, 720)); redirectToRelativeLink(portalCustomErrorUrl); $("[id$=':test-error-method']").shouldBe(exist, DEFAULT_TIMEOUT).shouldBe(visible, DEFAULT_TIMEOUT).click(); $(".notification-container").shouldBe(appear, DEFAULT_TIMEOUT); diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/document/screenshot/SettingScreenshotTest.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/document/screenshot/SettingScreenshotTest.java index 5dc65eaaaad..072d0743de7 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/document/screenshot/SettingScreenshotTest.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/document/screenshot/SettingScreenshotTest.java @@ -52,6 +52,7 @@ public void screenshotAdminSettings() throws IOException { ScreenshotUtils.captureElementWithMarginOptionScreenshot(adminSettingsPage.getEditSettingDialogOfFirstRow(), ScreenshotUtils.SETTINGS_FOLDER + "edit-global-settings", new ScreenshotMargin(20)); adminSettingsPage.closeEditSettingDialog(); + refreshPage(); adminSettingsPage.openAnnouncementTab(); ScreenshotUtils.captureElementWithMarginOptionScreenshot(adminSettingsPage.getAdminSettingContainer(), diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/AbsencePage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/AbsencePage.java index 0db6b045aa4..97f325a8b2d 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/AbsencePage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/AbsencePage.java @@ -7,7 +7,6 @@ import java.util.List; import java.util.stream.Collectors; -import org.apache.commons.collections4.CollectionUtils; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedConditions; @@ -15,6 +14,7 @@ import com.codeborne.selenide.CollectionCondition; import com.codeborne.selenide.Condition; +import com.codeborne.selenide.ElementsCollection; import com.codeborne.selenide.SelenideElement; import com.codeborne.selenide.WebDriverRunner; @@ -68,14 +68,14 @@ public String getMyDisabledDeputy(int deputyRoleIndex) { } public String getIAMDeputyFor() { - List noteAuthorElements = $$("tbody[id*='substitution-table_data'] > tr > td"); - return noteAuthorElements.stream().map(w -> w.getText()).collect(Collectors.joining()); + ElementsCollection noteAuthorElements = $$("tbody[id*='substitution-table_data'] > tr > td"); + return noteAuthorElements.asFixedIterable().stream().map(w -> w.getText()).collect(Collectors.joining()); } public int indexOfDeputyRole(DeputyRoleType deputyRoleType) { String deputyRoleTypeSelector = ".substitute-table .substition-role-type"; - List elements = $$(deputyRoleTypeSelector); - if (CollectionUtils.isNotEmpty(elements)) { + ElementsCollection elements = $$(deputyRoleTypeSelector); + if (!elements.isEmpty()) { for (int index = 0; index < elements.size(); index++) { SelenideElement element = elements.get(index); String deputyRoleTypeValue = element.getAttribute("deputy-role-type"); diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/CaseDetailsPage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/CaseDetailsPage.java index 9adacb2c1f3..cec20f12a4e 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/CaseDetailsPage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/CaseDetailsPage.java @@ -403,7 +403,7 @@ public String getLatestHistoryContent() { } public boolean isBusinessCaseInformationSectionDisplayed() { - List elements = $$("[id$='business-case-information']"); + ElementsCollection elements = $$("[id$='business-case-information']"); return !elements.isEmpty(); } @@ -653,7 +653,7 @@ public boolean isDownloadCompleted(String statusDialogId) { } public Integer getTaskRowIndex(String taskName) { - List taskNames = $$(".task-name-value"); + ElementsCollection taskNames = $$(".task-name-value"); int taskIndex = IntStream.range(0, taskNames.size()).filter(i -> taskNames.get(i).getText().equals(taskName)) .findFirst().getAsInt(); return taskIndex; @@ -677,7 +677,7 @@ public void clickRelatedTaskActionButton(String taskName) { } public int getTaskRowIndexFromDetailPage(String taskName) { - List taskNames = $$(".task-name-value"); + ElementsCollection taskNames = $$(".task-name-value"); int taskIndex = IntStream.range(0, taskNames.size()).filter(i -> taskNames.get(i).getText().equals(taskName)) .findFirst().getAsInt(); return taskIndex; @@ -761,14 +761,14 @@ public void selectDelegateResponsible(String responsibleName, boolean isRole) { $(By.cssSelector("input[id$='group-activator-select_input']")).click(); $(By.cssSelector("input[id$='group-activator-select_input']")).sendKeys(responsibleName); waitForElementDisplayed(By.cssSelector("span[id$='group-activator-select_panel']"), true); - List foundRoles = $$("span[id$='group-activator-select_panel'] .name-after-avatar"); + ElementsCollection foundRoles = $$("span[id$='group-activator-select_panel'] .name-after-avatar"); foundRoles.get(0).click(); } else { waitForElementDisplayed(By.cssSelector("input[id$='user-activator-select_input']"), true); $(By.cssSelector("input[id$='user-activator-select_input']")).click(); $(By.cssSelector("input[id$='user-activator-select_input']")).sendKeys(responsibleName); waitForElementDisplayed(By.cssSelector("span[id$='user-activator-select_panel']"), true); - List foundUsers = $$("span[id$='user-activator-select_panel'] .name-after-avatar"); + ElementsCollection foundUsers = $$("span[id$='user-activator-select_panel'] .name-after-avatar"); foundUsers.get(0).click(); } waitForElementClickableThenClick($(By.cssSelector("button[id$='proceed-task-delegate-command']"))); @@ -897,7 +897,7 @@ public boolean isRelatedCaseListColumnExist(String columnClass) { } public boolean isRelatedCaseListColumnNotExist(String columnClass) { - List columns = $$(".related-cases-container th." + columnClass); + ElementsCollection columns = $$(".related-cases-container th." + columnClass); return !columns.isEmpty() && !columns.get(0).isDisplayed(); } @@ -992,14 +992,13 @@ public TaskDetailsPage openTasksOfCasePage(String taskName) { } public boolean hasDoneTask() { - List doneTasks = $$(DONE_TASKS_SELECTOR); - return CollectionUtils.isNotEmpty(doneTasks); + ElementsCollection doneTasks = $$(DONE_TASKS_SELECTOR); + return !doneTasks.isEmpty(); } public List getCaseNoteAuthors() { - List noteAuthorElements = - $$("span.history-fullname").shouldBe(CollectionCondition.sizeGreaterThanOrEqual(0), DEFAULT_TIMEOUT); - return noteAuthorElements.stream().map(w -> w.getText()).collect(Collectors.toList()); + ElementsCollection noteAuthorElements = $$("span.history-fullname").shouldBe(CollectionCondition.sizeGreaterThanOrEqual(0), DEFAULT_TIMEOUT); + return noteAuthorElements.asFixedIterable().stream().map(w -> w.getText()).collect(Collectors.toList()); } public void clickBackButton() { diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/ChatPage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/ChatPage.java index d266508dda6..73c767afbc6 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/ChatPage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/ChatPage.java @@ -15,7 +15,6 @@ import com.axonivy.portal.selenium.common.WaitHelper; import com.codeborne.selenide.Condition; import com.codeborne.selenide.ElementsCollection; -import com.codeborne.selenide.SelenideElement; import ch.ivyteam.ivy.project.portal.test.Responsible; @@ -84,7 +83,7 @@ public int refreshAndCountGroupChat() { refresh(); getChat(); waitForElementDisplayed(By.id("chat-form:group-chat-container"), true); - List chatGroups = findElementById("chat-form:group-chat-container").findAll(".js-group-card-name"); + ElementsCollection chatGroups = findElementById("chat-form:group-chat-container").findAll(".js-group-card-name"); return chatGroups.size(); } diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/DashboardConfigurationPage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/DashboardConfigurationPage.java index 7dd61c03998..3872980e27d 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/DashboardConfigurationPage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/DashboardConfigurationPage.java @@ -9,11 +9,14 @@ import org.openqa.selenium.Keys; import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Action; +import org.openqa.selenium.interactions.Actions; import com.axonivy.portal.selenium.common.FileHelper; import com.codeborne.selenide.Condition; import com.codeborne.selenide.DragAndDropOptions; import com.codeborne.selenide.SelenideElement; +import com.codeborne.selenide.WebDriverRunner; public class DashboardConfigurationPage extends TemplatePage { @@ -349,8 +352,14 @@ public void reorderPrivateDashboard(String fromDashboardName, String toDashboard } private void dragAndDropTo(SelenideElement toRow, SelenideElement fromRow) { - var targetCssSelector = String.format("[id$='%s']", toRow.getAttribute("id")); - fromRow.dragAndDropTo(targetCssSelector, DragAndDropOptions.usingActions()); + SelenideElement targetCssSelector = $("[id$='"+ toRow.getAttribute("id") + "']"); + Actions builder = new Actions(WebDriverRunner.getWebDriver()); + Action dragAndDrop = builder.clickAndHold(fromRow).pause(500) + .moveToElement(targetCssSelector, 50, 20).pause(500).release(targetCssSelector) + .pause(500) + .build(); + dragAndDrop.perform(); + } public void reorderPublicDashboard(String fromDashboardName, String toDashboardName) { diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/DashboardNewsWidgetPage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/DashboardNewsWidgetPage.java index ad434100d7b..12f29d99200 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/DashboardNewsWidgetPage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/DashboardNewsWidgetPage.java @@ -9,6 +9,7 @@ import com.codeborne.selenide.Condition; import com.codeborne.selenide.ElementsCollection; import com.codeborne.selenide.SelenideElement; +import com.codeborne.selenide.WebElementCondition; public class DashboardNewsWidgetPage extends TemplatePage { @@ -111,7 +112,7 @@ public void publishNews() { manageNewsDialogShouldBe(disappear); } - private SelenideElement manageNewsDialogShouldBe(Condition expectCondition) { + private SelenideElement manageNewsDialogShouldBe(WebElementCondition expectCondition) { return $("[id$=':manage-news-dialog']").shouldBe(expectCondition, DEFAULT_TIMEOUT); } diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/LeaveRequestIFramePage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/LeaveRequestIFramePage.java index e7c926d65a9..72b6ac6bedd 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/LeaveRequestIFramePage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/LeaveRequestIFramePage.java @@ -3,7 +3,6 @@ import static com.codeborne.selenide.Selenide.$; import static com.codeborne.selenide.Selenide.$$; -import java.util.List; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; @@ -13,7 +12,7 @@ import com.codeborne.selenide.CollectionCondition; import com.codeborne.selenide.Condition; -import com.codeborne.selenide.SelenideElement; +import com.codeborne.selenide.ElementsCollection; public class LeaveRequestIFramePage extends TaskTemplateIFramePage { @@ -46,8 +45,8 @@ public String clickSubmitAndGetValidationMsg() { } public String getValidationMsg() { - List messages = $$("span.ui-messages-error-summary"); - return StringUtils.join(messages.stream().map(WebElement::getText).collect(Collectors.toList()), ","); + ElementsCollection messages = $$("span.ui-messages-error-summary"); + return StringUtils.join(messages.asFixedIterable().stream().map(WebElement::getText).collect(Collectors.toList()), ","); } public void enterLeaveRequestInformation(String leaveType, String from, String to, String approver, diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/LeaveRequestPage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/LeaveRequestPage.java index 0f937187335..52d7d8eead2 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/LeaveRequestPage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/LeaveRequestPage.java @@ -3,7 +3,6 @@ import static com.codeborne.selenide.Selenide.$; import static com.codeborne.selenide.Selenide.$$; -import java.util.List; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; @@ -13,7 +12,7 @@ import com.codeborne.selenide.CollectionCondition; import com.codeborne.selenide.Condition; -import com.codeborne.selenide.SelenideElement; +import com.codeborne.selenide.ElementsCollection; public class LeaveRequestPage extends TaskTemplateIFramePage { @@ -58,8 +57,8 @@ private void clickSubmitAndWaitValidationSummary(int numberOfErrors) { } public String getValidationMsg() { - List messages = $$("span.ui-messages-error-summary"); - return StringUtils.join(messages.stream().map(WebElement::getText).collect(Collectors.toList()), ","); + ElementsCollection messages = $$("span.ui-messages-error-summary"); + return StringUtils.join(messages.asFixedIterable().stream().map(WebElement::getText).collect(Collectors.toList()), ","); } public void enterLeaveRequestInformation(String leaveType, String from, String to, String approver, diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/NewDashboardPage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/NewDashboardPage.java index 977c1937081..aa73b4029ce 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/NewDashboardPage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/NewDashboardPage.java @@ -6,8 +6,6 @@ import static com.codeborne.selenide.Selenide.$; import static com.codeborne.selenide.Selenide.$$; -import java.util.List; - import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.Keys; @@ -971,7 +969,7 @@ public void markAsRead(WebElement notificationsPanel, int expectedBadge) { } public int findNumberOfNotificationsItem(WebElement notificationsPanel) { - List item = $$(".ui-datascroller-item"); + ElementsCollection item = $$(".ui-datascroller-item"); return item.size(); } diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/NoteHistoryPage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/NoteHistoryPage.java index 1de8b1da85b..ab1840ee09e 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/NoteHistoryPage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/NoteHistoryPage.java @@ -10,7 +10,7 @@ import org.openqa.selenium.WebElement; import com.codeborne.selenide.CollectionCondition; -import com.codeborne.selenide.SelenideElement; +import com.codeborne.selenide.ElementsCollection; import com.codeborne.selenide.WebDriverRunner; public class NoteHistoryPage extends TemplatePage { @@ -60,9 +60,9 @@ public String getCaseId() { } public List getNoteAuthors() { - List noteAuthorElements = $$("td.note-history-fullname-column .name-after-avatar") + ElementsCollection noteAuthorElements = $$("td.note-history-fullname-column .name-after-avatar") .shouldBe(CollectionCondition.sizeGreaterThanOrEqual(0), DEFAULT_TIMEOUT); - return noteAuthorElements.stream().map(w -> w.getText()).collect(Collectors.toList()); + return noteAuthorElements.asFixedIterable().stream().map(w -> w.getText()).collect(Collectors.toList()); } public void clickOnCheckboxShowSystemNotes() { diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/ProcessEditWidgetNewDashBoardPage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/ProcessEditWidgetNewDashBoardPage.java index bb62e2f8b61..61f018e1247 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/ProcessEditWidgetNewDashBoardPage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/ProcessEditWidgetNewDashBoardPage.java @@ -435,7 +435,7 @@ public void save() { public void dragAndDropProcess(int fromIndex, int toIndex) { SelenideElement processList = $("ul.ui-widget-content"); processList.shouldBe(Condition.appear, DEFAULT_TIMEOUT); - List findAll = processList.findAll("li.ui-orderlist-item"); + ElementsCollection findAll = processList.findAll("li.ui-orderlist-item"); if (findAll.size() > toIndex) { SelenideElement fromElement = findAll.get(fromIndex) .$(".process-start-list-item").shouldBe(clickable(), DEFAULT_TIMEOUT); diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/ProcessWidgetPage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/ProcessWidgetPage.java index 3d2ef4de049..2ad9b1bc935 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/ProcessWidgetPage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/ProcessWidgetPage.java @@ -5,9 +5,6 @@ import static com.codeborne.selenide.Selenide.$; import static com.codeborne.selenide.Selenide.$$; -import java.util.List; - -import org.apache.commons.collections4.CollectionUtils; import org.openqa.selenium.By; import org.openqa.selenium.Keys; import org.openqa.selenium.WebElement; @@ -15,6 +12,7 @@ import com.axonivy.portal.selenium.common.FileHelper; import com.axonivy.portal.selenium.common.WaitHelper; import com.codeborne.selenide.Condition; +import com.codeborne.selenide.ElementsCollection; import com.codeborne.selenide.SelenideElement; public class ProcessWidgetPage extends TemplatePage { @@ -207,8 +205,8 @@ public void selectViewMode(String viewMode) { waitForElementDisplayed(By.cssSelector("[id$='process-widget:process-view-mode:view-mode-selection']"), true); SelenideElement viewModeElement = findElementByCssSelector("[id$='process-widget:process-view-mode:view-mode-selection']"); - List webElements = viewModeElement.$$(By.cssSelector("span.ui-button-text.ui-c")); - if (CollectionUtils.isNotEmpty(webElements)) { + ElementsCollection webElements = viewModeElement.$$(By.cssSelector("span.ui-button-text.ui-c")); + if (!webElements.isEmpty()) { for (SelenideElement webElement : webElements) { if (webElement.getText().equalsIgnoreCase(viewMode)) { waitForElementClickableThenClick(webElement); @@ -236,7 +234,7 @@ public void enterSearchKeyword(String keyword) { public SelenideElement getStartImageProcess(String processName, SelenideElement processListElement) { SelenideElement startProcessItemElement = null; - List processItems = processListElement.$$(".js-process-start-list-item"); + ElementsCollection processItems = processListElement.$$(".js-process-start-list-item"); for (SelenideElement process : processItems) { SelenideElement processNameElement = process.$(".js-process-start-list-item-name"); if (processNameElement.isDisplayed() && processName.equalsIgnoreCase(processNameElement.getText())) { @@ -256,7 +254,7 @@ public SelenideElement getProcess(String processName) { } public boolean isImageModeActivated() { - List findElements = $$(By.cssSelector("[id$=':image-process-container']")); + ElementsCollection findElements = $$(By.cssSelector("[id$=':image-process-container']")); return !findElements.isEmpty(); } @@ -270,13 +268,13 @@ public boolean isNoProcessFound() { public boolean isProcessGroupDisplay(String processGroupCharacter) { if (isImageModeActivated()) { - List webElements = $$(".js-grid-process-index-group"); - return webElements.stream().anyMatch(processItem -> processItem.isDisplayed() + ElementsCollection webElements = $$(".js-grid-process-index-group"); + return webElements.asFixedIterable().stream().anyMatch(processItem -> processItem.isDisplayed() && processItem.getAttribute("class").endsWith(processGroupCharacter)); } - List indexGroup = + ElementsCollection indexGroup = $$(By.xpath("//legend[@class='ui-fieldset-legend ui-corner-all ui-state-default']")); - return indexGroup.stream().anyMatch(item -> processGroupCharacter.equals(item.getText())); + return indexGroup.asFixedIterable().stream().anyMatch(item -> processGroupCharacter.equals(item.getText())); } public String getCurrentViewMode() { @@ -374,7 +372,7 @@ public void clickProcessMoreActionMenu(String processName) { public SelenideElement getProcessItem(String processName) { SelenideElement processItemElement = null; - List processItems = $$(".js-process-start-list-item"); + ElementsCollection processItems = $$(".js-process-start-list-item"); for (SelenideElement process : processItems) { processItemElement = process.$(".js-process-start-list-item-name"); if (processItemElement.getText().equalsIgnoreCase(processName)) { @@ -408,7 +406,7 @@ public void deleteGridProcess(String processName) { public SelenideElement getProcessItemForm(String processName) { SelenideElement processItemElement = null; - List processItems = $$(".js-process-start-list-item form"); + ElementsCollection processItems = $$(".js-process-start-list-item form"); for (SelenideElement process : processItems) { processItemElement = process.$(".js-process-start-list-item-name"); if (processItemElement.getText().equalsIgnoreCase(processName)) { diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/ReorderDashboardPage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/ReorderDashboardPage.java index cf3328c8774..18ceebb1e07 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/ReorderDashboardPage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/ReorderDashboardPage.java @@ -4,12 +4,13 @@ import static com.codeborne.selenide.Condition.disappear; import static com.codeborne.selenide.Selenide.$; -import com.codeborne.selenide.DragAndDropOptions; +import org.openqa.selenium.interactions.Action; +import org.openqa.selenium.interactions.Actions; + import com.codeborne.selenide.SelenideElement; +import com.codeborne.selenide.WebDriverRunner; public class ReorderDashboardPage extends TemplatePage { - private static final String ID_SELECTOR_PATTERN = "[id$='%s']"; - @Override protected String getLoadedLocator() { return "i.dashboard-icon-drag-drop"; @@ -28,8 +29,14 @@ public void reorderPrivateDashboard(String fromDashboardName, String toDashboard } private void dragAndDropTo(SelenideElement toRow, SelenideElement fromRow) { - var targetCssSelector = String.format(ID_SELECTOR_PATTERN, toRow.getAttribute("id")); - fromRow.dragAndDropTo(targetCssSelector, DragAndDropOptions.usingActions()); + SelenideElement targetCssSelector = $("[id$='" + toRow.getAttribute("id") + "']"); + Actions builder = new Actions(WebDriverRunner.getWebDriver()); + Action dragAndDrop = builder.clickAndHold(fromRow).pause(500) + .moveToElement(targetCssSelector, 50, 20).pause(500).release(targetCssSelector) + .pause(500) + .build(); + dragAndDrop.perform(); + } public void reorderPublicDashboard(String fromDashboardName, String toDashboardName) { diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/RoleManagementPage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/RoleManagementPage.java index 8419510fdd5..ed2c3bc2d02 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/RoleManagementPage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/RoleManagementPage.java @@ -146,7 +146,7 @@ public SelenideElement findActionForRoleByName(String roleName, String actionId) .shouldBe(Condition.appear, DEFAULT_TIMEOUT); } - private List getRolesOnTheTreeTable() { + private ElementsCollection getRolesOnTheTreeTable() { return getRoleTreeTable().$$(By.cssSelector("tbody tr.role")); } diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/SearchResultPage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/SearchResultPage.java index 7918279aef7..ecba3dca487 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/SearchResultPage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/SearchResultPage.java @@ -8,6 +8,7 @@ import org.openqa.selenium.By; +import com.codeborne.selenide.ElementsCollection; import com.codeborne.selenide.SelenideElement; public class SearchResultPage extends TemplatePage { @@ -63,7 +64,7 @@ public String getCaseResult(int index) { public int countCase() { waitCaseWidgetLoaded(); - List caseItems = $$("li[class='ui-datascroller-item']"); + ElementsCollection caseItems = $$("li[class='ui-datascroller-item']"); return caseItems.size(); } diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TaskDetailsPage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TaskDetailsPage.java index 42d1fa683cf..30860893e9d 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TaskDetailsPage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TaskDetailsPage.java @@ -299,15 +299,15 @@ public String getTaskUuid() { public List getTaskNoteHasAuthors() { ScreenshotUtils.resizeBrowser(new Dimension(2560, 1600)); $("th.task-document-author").shouldBe(appear); - List noteAuthorElements = + ElementsCollection noteAuthorElements = $$("td.task-document-author .name-after-avatar").shouldBe(CollectionCondition.sizeGreaterThanOrEqual(1)); - return noteAuthorElements.stream().map(w -> w.getText()).collect(Collectors.toList()); + return noteAuthorElements.asFixedIterable().stream().map(w -> w.getText()).collect(Collectors.toList()); } public List getTaskNoteAuthors() { - List noteAuthorElements = $$("td.task-document-author .name-after-avatar") + ElementsCollection noteAuthorElements = $$("td.task-document-author .name-after-avatar") .shouldBe(CollectionCondition.sizeGreaterThanOrEqual(0), DEFAULT_TIMEOUT); - return noteAuthorElements.stream().map(w -> w.getText()).collect(Collectors.toList()); + return noteAuthorElements.asFixedIterable().stream().map(w -> w.getText()).collect(Collectors.toList()); } public void clickBackButton() { diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TaskIFrameTemplatePage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TaskIFrameTemplatePage.java index ece5b31220d..208d9023cbb 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TaskIFrameTemplatePage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TaskIFrameTemplatePage.java @@ -5,7 +5,6 @@ import static com.codeborne.selenide.Selenide.$; import static com.codeborne.selenide.Selenide.$$; -import java.util.List; import java.util.stream.IntStream; import org.openqa.selenium.By; @@ -16,6 +15,7 @@ import com.axonivy.portal.selenium.common.WaitHelper; import com.codeborne.selenide.CollectionCondition; import com.codeborne.selenide.Condition; +import com.codeborne.selenide.ElementsCollection; import com.codeborne.selenide.SelenideElement; import com.codeborne.selenide.WebDriverRunner; @@ -173,7 +173,7 @@ public TaskDetailsPage openRelatedTaskInList(String taskName) { } public Integer getTaskRowIndex(String taskName) { - List taskNames = $$(".task-name-value"); + ElementsCollection taskNames = $$(".task-name-value"); int taskIndex = IntStream.range(0, taskNames.size()).filter(i -> taskNames.get(i).getText().equals(taskName)) .findFirst().getAsInt(); return taskIndex; diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TaskTemplatePage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TaskTemplatePage.java index c1468a1e32b..b5b1443f124 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TaskTemplatePage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TaskTemplatePage.java @@ -5,7 +5,6 @@ import static com.codeborne.selenide.Selenide.$; import static com.codeborne.selenide.Selenide.$$; -import java.util.List; import java.util.stream.IntStream; import org.openqa.selenium.By; @@ -15,6 +14,7 @@ import com.axonivy.portal.selenium.common.NavigationHelper; import com.axonivy.portal.selenium.common.WaitHelper; import com.codeborne.selenide.CollectionCondition; +import com.codeborne.selenide.ElementsCollection; import com.codeborne.selenide.SelenideElement; public class TaskTemplatePage extends TemplatePage { @@ -169,7 +169,7 @@ public TaskDetailsPage openRelatedTaskInList(String taskName) { } public Integer getTaskRowIndex(String taskName) { - List taskNames = $$(".task-name-value"); + ElementsCollection taskNames = $$(".task-name-value"); int taskIndex = IntStream.range(0, taskNames.size()).filter(i -> taskNames.get(i).getText().equals(taskName)) .findFirst().getAsInt(); return taskIndex; diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TaskWidgetPage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TaskWidgetPage.java index ce14cbdf225..7bd71fcecd0 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TaskWidgetPage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TaskWidgetPage.java @@ -322,7 +322,7 @@ public void clickOnTaskStatesAndApply(List states) { "table[id$=':filter-input-form:state-selection'] div.ui-chkbox-box span.ui-chkbox-icon.ui-icon-blank")) .size() == labelList.size(); }); - List checkBoxList = getStateFilterPanel() + ElementsCollection checkBoxList = getStateFilterPanel() .$$(By.cssSelector("table[id$=':filter-input-form:state-selection'] div.ui-chkbox-box.ui-state-default")); statesSelectedIndex.forEach(index -> { waitForElementClickableThenClick(checkBoxList.get(index)); @@ -540,7 +540,7 @@ public void confimDestruction() { public boolean isTaskDelegateOptionDisable(String taskName) { int index = 1; - List taskElements = $$("span[id$=':task-item:task-name-component:task-name']"); + ElementsCollection taskElements = $$("span[id$=':task-item:task-name-component:task-name']"); for (int i = 0; i < taskElements.size(); i++) { if (taskElements.get(i).getText().equals(taskName)) { index = i; @@ -590,7 +590,7 @@ public String getFilterValue(String filterId) { } public String getResponsibleOfTaskAt(int index) { - List responsibles = $$(".responsible-cell .name-after-avatar"); + ElementsCollection responsibles = $$(".responsible-cell .name-after-avatar"); return responsibles.get(index).getText(); } @@ -637,7 +637,7 @@ public boolean isTaskStateOpen(int index) { } public boolean isCategoryColumnDisplayed() { - List taskCategoryCells = $$("span[id$=':task-category-cell']"); + ElementsCollection taskCategoryCells = $$("span[id$=':task-category-cell']"); for (SelenideElement categoryCell : taskCategoryCells) { if (categoryCell.isDisplayed()) { return true; @@ -694,7 +694,7 @@ public void selectDelegateResponsible(String responsibleName, boolean isRole) { responsibleElement.click(); responsibleElement.sendKeys(responsibleName); waitForElementDisplayed(By.cssSelector("span[id$='group-activator-select_panel']"), true); - List foundRoles = $$("span[id$='group-activator-select_panel'] .gravatar"); + ElementsCollection foundRoles = $$("span[id$='group-activator-select_panel'] .gravatar"); waitForElementClickableThenClick(foundRoles.get(0)); } else { waitForElementDisplayed(By.cssSelector("input[id$='user-activator-select_input']"), true); @@ -702,7 +702,7 @@ public void selectDelegateResponsible(String responsibleName, boolean isRole) { responsibleElement.click(); responsibleElement.sendKeys(responsibleName); waitForElementDisplayed(By.cssSelector("span[id$='user-activator-select_panel']"), true); - List foundUsers = $$("span[id$='user-activator-select_panel'] .name-after-avatar"); + ElementsCollection foundUsers = $$("span[id$='user-activator-select_panel'] .name-after-avatar"); waitForElementClickableThenClick(foundUsers.get(0)); } waitForElementClickableThenClick(By.cssSelector("button[id$='proceed-task-delegate-command']")); diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TemplatePage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TemplatePage.java index 74f2da36859..4038d8afe67 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TemplatePage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TemplatePage.java @@ -34,6 +34,7 @@ import com.codeborne.selenide.SelenideElement; import com.codeborne.selenide.WebDriverConditions; import com.codeborne.selenide.WebDriverRunner; +import com.codeborne.selenide.WebElementCondition; import com.codeborne.selenide.conditions.Not; public abstract class TemplatePage extends AbstractPage { @@ -60,11 +61,11 @@ public void assertPageTitle(String titleExpect) { webdriver().shouldHave(WebDriverConditions.title(titleExpect)); } - protected Condition getClickableCondition() { + protected WebElementCondition getClickableCondition() { return and("should be clickable", visible, exist); } - protected Condition clickable() { + protected WebElementCondition clickable() { return and("should be clickable", visible, enabled); } @@ -182,7 +183,7 @@ public void waitForElementPresent(By element, boolean expected) { if (expected) { $(element).shouldBe(exist, DEFAULT_TIMEOUT); } else { - $(element).shouldBe(Not.exist, DEFAULT_TIMEOUT); + $(element).shouldNotBe(exist, DEFAULT_TIMEOUT); } } diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TopMenuTaskWidgetPage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TopMenuTaskWidgetPage.java index a7938f9ab88..df3ad0336fe 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TopMenuTaskWidgetPage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/TopMenuTaskWidgetPage.java @@ -253,7 +253,7 @@ public void selectDelegateResponsible(String responsibleName, boolean isRole) { responsibleElement.click(); responsibleElement.sendKeys(responsibleName); waitForElementDisplayed(By.cssSelector("span[id$='group-activator-select_panel']"), true); - List foundRoles = $$("span[id$='group-activator-select_panel'] .gravatar"); + ElementsCollection foundRoles = $$("span[id$='group-activator-select_panel'] .gravatar"); waitForElementClickableThenClick(foundRoles.get(0)); } else { waitForElementDisplayed(By.cssSelector("input[id$='user-activator-select_input']"), true); @@ -261,7 +261,7 @@ public void selectDelegateResponsible(String responsibleName, boolean isRole) { responsibleElement.click(); responsibleElement.sendKeys(responsibleName); waitForElementDisplayed(By.cssSelector("span[id$='user-activator-select_panel']"), true); - List foundUsers = $$("span[id$='user-activator-select_panel'] .name-after-avatar"); + ElementsCollection foundUsers = $$("span[id$='user-activator-select_panel'] .name-after-avatar"); waitForElementClickableThenClick(foundUsers.get(0)); } waitForElementClickableThenClick(By.cssSelector("button[id$='proceed-task-delegate-command']")); diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/WelcomeEditWidgetNewDashboardPage.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/WelcomeEditWidgetNewDashboardPage.java index 83752848f17..e9264f20900 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/WelcomeEditWidgetNewDashboardPage.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/page/WelcomeEditWidgetNewDashboardPage.java @@ -34,9 +34,10 @@ public void inputWelcomeTexts(List welcomeTexts) { ElementsCollection welcomeTextInputs = configDialog.findAll(".js-welcome-text-input"); welcomeTextInputs.asDynamicIterable().forEach(elem -> { elem.clear(); - elem.sendKeys(welcomeTexts.stream().filter(text -> welcomeTexts.indexOf(text) == welcomeTextInputs.indexOf(elem)) - .findFirst().orElse("")); }); + for (int i = 0; i < welcomeTexts.size(); i++) { + $("input[id$='welcome-text-list:" + i + ":welcome-text-input']").sendKeys(welcomeTexts.get(i)); + } } public void selectTextSize(String value) { diff --git a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/test/dashboard/DashboardRestoreConfigurationTest.java b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/test/dashboard/DashboardRestoreConfigurationTest.java index 9d96eb6cc86..f1306a51c60 100644 --- a/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/test/dashboard/DashboardRestoreConfigurationTest.java +++ b/AxonIvyPortal/portal-selenium-test/src_test/com/axonivy/portal/selenium/test/dashboard/DashboardRestoreConfigurationTest.java @@ -16,6 +16,7 @@ import com.axonivy.portal.selenium.page.NewDashboardPage; import com.codeborne.selenide.CollectionCondition; import com.codeborne.selenide.Condition; +import com.codeborne.selenide.WebElementsCondition; import ch.ivy.addon.portalkit.enums.PortalVariable; @@ -84,7 +85,7 @@ public void testCannotRestoreDashboardWhenTemplateNotFound() { restoreButton.shouldHave(Condition.cssClass("ui-state-disabled")); } - private void verifyEditingDashboardContent(String dashboardName, CollectionCondition collectionCondition) { + private void verifyEditingDashboardContent(String dashboardName, WebElementsCondition collectionCondition) { NewDashboardDetailsEditPage newDashboardDetailsEditPage = new NewDashboardDetailsEditPage(); newDashboardDetailsEditPage.getTitleByIndex(0).shouldBe(Condition.exactText(dashboardName)); newDashboardDetailsEditPage.getWidgets().shouldBe(collectionCondition); diff --git a/AxonIvyPortal/portal/pom.xml b/AxonIvyPortal/portal/pom.xml index 48de35cf4df..5c7f9309e22 100644 --- a/AxonIvyPortal/portal/pom.xml +++ b/AxonIvyPortal/portal/pom.xml @@ -17,8 +17,8 @@ - 12.0.0 - 12.0.0 + 12.0.1 + 12.0.0-SNAPSHOT UTF-8 diff --git a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardWidgetUtils.java b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardWidgetUtils.java index cae74c02430..d397f4915a8 100644 --- a/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardWidgetUtils.java +++ b/AxonIvyPortal/portal/src/ch/ivy/addon/portalkit/util/DashboardWidgetUtils.java @@ -533,6 +533,7 @@ public static void loadProcessesOfWidget(ProcessDashboardWidget widget) { private static void loadProcessByPath(SingleProcessDashboardWidget processWidget) { String processPath = processWidget.getProcessPath(); if (processPath == null || processWidget.getProcess() != null) { + processWidget.setEmptyProcessMessage(Ivy.cms().co("/ch.ivy.addon.portalkit.ui.jsf/dashboard/processes/noProcessSelected")); return; } diff --git a/AxonIvyPortal/portal/src_hd/ch/ivy/addon/portal/generic/dashboard/component/ProcessWidget/ProcessWidget.xhtml b/AxonIvyPortal/portal/src_hd/ch/ivy/addon/portal/generic/dashboard/component/ProcessWidget/ProcessWidget.xhtml index faf16da47d9..dd976d8bdb6 100644 --- a/AxonIvyPortal/portal/src_hd/ch/ivy/addon/portal/generic/dashboard/component/ProcessWidget/ProcessWidget.xhtml +++ b/AxonIvyPortal/portal/src_hd/ch/ivy/addon/portal/generic/dashboard/component/ProcessWidget/ProcessWidget.xhtml @@ -120,7 +120,7 @@ - - +
diff --git a/AxonIvyPortal/portal/src_hd/ch/ivy/addon/portal/generic/dashboard/component/ProcessWidgetConfiguration/ProcessWidgetConfiguration.xhtml b/AxonIvyPortal/portal/src_hd/ch/ivy/addon/portal/generic/dashboard/component/ProcessWidgetConfiguration/ProcessWidgetConfiguration.xhtml index 9330fe95d3c..ba590a7a91d 100644 --- a/AxonIvyPortal/portal/src_hd/ch/ivy/addon/portal/generic/dashboard/component/ProcessWidgetConfiguration/ProcessWidgetConfiguration.xhtml +++ b/AxonIvyPortal/portal/src_hd/ch/ivy/addon/portal/generic/dashboard/component/ProcessWidgetConfiguration/ProcessWidgetConfiguration.xhtml @@ -241,7 +241,7 @@ -
+

#{ivy.cms.co('/ch.ivy.addon.portalkit.ui.jsf/dashboard/preview')}

- +
diff --git a/AxonIvyPortal/portal/webContent/layouts/restricted/IFrameTaskTemplate.xhtml b/AxonIvyPortal/portal/webContent/layouts/restricted/IFrameTaskTemplate.xhtml index eb85ed0512f..c9cda06739d 100644 --- a/AxonIvyPortal/portal/webContent/layouts/restricted/IFrameTaskTemplate.xhtml +++ b/AxonIvyPortal/portal/webContent/layouts/restricted/IFrameTaskTemplate.xhtml @@ -9,69 +9,87 @@ - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - + **Task Details:** + - taskName: (String) Custom text for the task name. + - taskIcon: (String) Icon for the task, using Streamline or Awesome font (e.g., `si si-arrow-right`). + - isHideTaskName: (Boolean) Hides the task name when true. Default is false. + + **Case Information:** + - caseId: (String) ID of the case to be displayed in the case information dialog. + - isHideCaseInfo: (Boolean) Hides the `Show Information` button when true. Default is false. + + **Process Steps:** + - currentProcessStep: (Number/String) Current step in the process, either as an index or step name. + - processSteps: (Array/String) List of process steps (e.g., `["Create Investment Request", "Approve Investment Request"]`) + or JSON (e.g., `#{portalComponentUtilsBean.convertToJSON(data.steps)}`). + - isShowAllSteps: (Boolean) Displays all steps on large screens when true. Default is false. + - processChainDirection: (String) Orientation of the process chain, either `VERTICAL` or `HORIZONTAL` (default). + - processChainShape: (String) Shape of the process chain, either `LINE` or `CIRCLE` (default). + + **Task Actions:** + - isHideTaskAction: (Boolean) Hides the task action button when true. Default is false. + - isWorkingOnATask: (Boolean) Indicates if a task is currently being worked on, useful for displaying a warning when leaving the page. Default is true. + + **Miscellaneous:** + - announcementInvisible: (Boolean) Makes the announcement invisible when true. Default is false. + - isCardFrame: (Boolean) Displays content of the IFrame inside a card-style container when true. + - viewName: (String) Defines a custom breadcrumb view. Possible values: + `HOME, PROCESS, TASK, TASK_DETAIL, CASE_DETAIL, CASE, TECHNICAL_CASE, RELATED_TASK, USER_PROFILE, + ABSENCES_MANAGEMENT, DASHBOARD_CONFIGURATION, EDIT_DASHBOARD_DETAILS, PROCESS_VIEWER, PORTAL_MANAGEMENT, NOTIFICATION`. + + --> + + + - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AxonIvyPortal/portal/webContent/resources/css/dashboard.css b/AxonIvyPortal/portal/webContent/resources/css/dashboard.css index 8b220fff9e3..c790e6bc76f 100644 --- a/AxonIvyPortal/portal/webContent/resources/css/dashboard.css +++ b/AxonIvyPortal/portal/webContent/resources/css/dashboard.css @@ -1096,6 +1096,7 @@ body .ui-widget.new-widget-dialog__introduction { align-content: center; width: 100%; height: 90%; + display: grid; } .process-dashboard-widget__empty-process.empty-message-container { @@ -1170,9 +1171,9 @@ body .ui-widget.new-widget-dialog__introduction { } .process-grid-item__action--combined { - padding: 20px; - padding-bottom: 0; + padding: 8px; float: right; + height: 10% } .process-widget--combined { diff --git a/AxonIvyPortal/portal/webContent/resources/css/module.css b/AxonIvyPortal/portal/webContent/resources/css/module.css index a3e2c97ac94..986b50e6874 100644 --- a/AxonIvyPortal/portal/webContent/resources/css/module.css +++ b/AxonIvyPortal/portal/webContent/resources/css/module.css @@ -656,7 +656,7 @@ span.case-details-document-add-link, span.task-details-document-add-link { box-sizing: content-box; text-align: left; color: var(--text-color); - width: 87%; + min-width: 160px; } .case-detail-header { @@ -1912,19 +1912,28 @@ _:-ms-input-placeholder, :root a.compact-task-start-link { display: grid; } +.options-panel.ui-overlaypanel .ui-overlaypanel-content, +.ui-overlaypanel .ui-overlaypanel-content{ + padding: 1rem 0 !important; +} + .options-panel .option-item { display: inline-flex; flex-direction: row; align-items: center; clear: both; float: left; - padding: 10px 18px 10px 0px; + padding: 10px 18px 10px 10px; margin: 0; width: 160px; box-sizing: content-box; color: var(--text-color); } + .options-panel .option-item:hover .option-item-label { + text-decoration: underline; +} + .options-panel .option-item.color-destroy, .action-steps-panel .action-step-item.color-destroy, .ui-menu-list .ui-menuitem > .ui-menuitem-link.color-destroy > span { color: var(--ivy-tertinary-color-red-medium) !important; } diff --git a/Documentation/portal-guide/source/portal-developer-guide/iframe/index.rst b/Documentation/portal-guide/source/portal-developer-guide/iframe/index.rst index 6a4196590f6..8a03edbc6e0 100644 --- a/Documentation/portal-guide/source/portal-developer-guide/iframe/index.rst +++ b/Documentation/portal-guide/source/portal-developer-guide/iframe/index.rst @@ -11,7 +11,11 @@ your HTML dialog independent of the **Portal**. It is rendered automatically in .. _iframe-usage: -Templates to use with IFrame: frame-10 templates (Provided by core, uses Freya theme). This template fully supports responsiveness. +Templates to Use with IFrame +============================ + +Use the ``frame-10`` templates (provided by the core and using the Freya theme). +These templates fully support responsive designs. How To Use ========== @@ -21,54 +25,90 @@ How To Use Follow these steps to use the IFrame approach: -#. Your HTML User Dialog has to be independent of the **Portal**. You can use - the ``frame-_x_`` template in designer, or your own template. **Portal** will - render it automatically in an IFrame. - -#. If you don't want to use the default configuration, apply one of the following three - levels to open your task(s) in an IFrame: - - - Task level: in Task custom fields, set the ``embedInFrame`` field to - - - ``true``: start inside IFrame - - ``false``: not start inside IFrame - - Don't set if you want to use case or engine level - - |task-embedInFrame| - - - Case level: in Case custom fields, set the ``embedInFrame`` String field to - - - ``true``: start inside IFrame - - ``false``: not start inside IFrame - - Don't set if you want to use engine level - - |case-embedInFrame| - - - Engine level: - - - The **Portal Administrator** can define globally that all of the tasks - running on the engine are started inside IFrames by using the - ``Portal.EmbedInFrame`` Portal setting. refer to - :ref:`update-portal-settings` +#. **HTML Dialog Independence** + + Ensure your HTML User Dialog is independent of the **Portal**. You can use the ``frame-_x_`` + template in the designer or your own custom template. **Portal** will automatically render it in an IFrame. + +#. **Configuration Levels** + If you want custom behavior, configure at one of the following levels to open your tasks in an IFrame: + + - **Task Level**: Set the ``embedInFrame`` field in Task custom fields to: + + - ``true``: Start inside IFrame. + - ``false``: Do not start inside IFrame. + - Leave unset to use case or engine-level configuration. + + |task-embedInFrame| + + - **Case Level**: Set the ``embedInFrame`` String field in Case custom fields to: + + - ``true``: Start inside IFrame. + - ``false``: Do not start inside IFrame. + - Leave unset to use engine-level configuration. + + |case-embedInFrame| + + - **Engine Level**: + + The **Portal Administrator** can globally configure all tasks to start inside IFrames by setting the ``Portal.EmbedInFrame`` value in the Portal settings. + Refer to :ref:`update-portal-settings`. .. _iframe-configure-template: -Configure template +Configure Template ================== -**Portal** supports some configurations for templates like: +The **Portal** allows configuration of templates with the following options: -#. Name and icon of the working task. +#. Name and icon for the working task. +#. Process chain configuration. + (See: :ref:`components-portal-components-process-chain`). +#. Show/hide case details and other actions. -#. Configuration of :ref:`components-portal-components-process-chain`. -#. Show/hide case details and other actions. +Template Parameters +------------------- + +The following parameters are available for this template: + +**Task Details** + +- ``taskName``: Custom text for the task name. +- ``taskIcon``: Icon for the task, using Streamline or Awesome font. +- ``isHideTaskName``: Hides the task name when true. + +**Case Information** + +- ``caseId``: ID of the case to be displayed in the case information dialog. +- ``isHideCaseInfo``: Hides the ``Show Information`` button when true. + +**Process Steps** -|task-name-template| +- ``currentProcessStep``: Current step in the process, either as an index or step name. +- ``processSteps``: List of process steps or JSON. +- ``isShowAllSteps``: Displays all steps on large screens when true. +- ``processChainDirection``: Orientation of the process chain, either ``VERTICAL`` or ``HORIZONTAL``. +- ``processChainShape``: Shape of the process chain, either ``LINE`` or ``CIRCLE``. -You could configure UI in either of these two ways: +**Task Actions** -#. Using the component IFrameTaskConfig (recommended) +- ``isHideTaskAction``: Hides the task action button when true. +- ``isWorkingOnATask``: Indicates if a task is currently being worked on, + useful for displaying a warning when leaving the page. + +**Miscellaneous** + +- ``announcementInvisible``: Makes the announcement invisible. +- ``isCardFrame``: Displays content of the IFrame inside a card-style container. +- ``viewName``: Defines a custom breadcrumb view. + +Configuration Methods +--------------------- + +You can configure the UI in one of two ways: + +#. **Using ``IFrameTaskConfig`` Component** (Recommended) .. code-block:: xml @@ -96,13 +136,13 @@ You could configure UI in either of these two ways: -#. Using Javascript +#. **Using JavaScript** .. code-block:: xml - ... + ... ... -Configure Task name -------------------- +Configure Task Details +---------------------- +You can customize task details, such as the task name and icon. -By default, **Portal** uses the name of the working task. +**Parameters:** + - ``taskName``: Custom text for the task name. + - ``taskIcon``: Using Streamline or Awesome font (e.g., `si si-arrow-right`). + - ``isHideTaskName``: Set to ``true`` to hide the task name. Default is ``false``. -Options for ``Task name`` +**Example:** -.. csv-table:: - :file: documents/available_task_options.csv - :widths: 20 50 - :header-rows: 1 - :class: longtable +.. code-block:: xml -Example using IFrameTaskConfig: + + + ... + + ... + + + + +Configure Case Information +-------------------------- +Customize how case details are displayed and whether to show the "Show Information" button. + +**Parameters:** + - ``caseId``: The ID of the case to display in the information dialog. + - ``isHideCaseInfo``: Set to ``true`` to hide the "Show Information" button. + Default is ``false``. + +**Example:** .. code-block:: xml ... - + ... + + + +Configure Task Actions +---------------------- +Control the visibility and behavior of task-related buttons and actions. + +**Parameters:** + - ``isHideTaskAction``: Set to ``true`` to hide the task action button. + Default is ``false``. + - ``isWorkingOnATask``: Indicates if the task is active. + Useful for displaying a warning when leaving the page. Default is ``true``. + +**Example:** + +.. code-block:: xml + + + + ... + + ... + + + + +Configure Miscellaneous Options +------------------------------- +Additional settings can influence the layout and visibility of elements. + +**Parameters:** + - ``announcementInvisible``: Set to ``true`` to hide announcements. + Default is ``false``. + - ``isCardFrame``: Set to ``true`` to display the IFrame + content inside a card-style container. + - ``viewName``: Custom breadcrumb view. Possible values are: + ``HOME, PROCESS, TASK, TASK_DETAIL, CASE_DETAIL, CASE, TECHNICAL_CASE, RELATED_TASK, + USER_PROFILE, ABSENCES_MANAGEMENT, DASHBOARD_CONFIGURATION, EDIT_DASHBOARD_DETAILS, + PROCESS_VIEWER, PORTAL_MANAGEMENT, NOTIFICATION``. + +**Example:** + +.. code-block:: xml + + + + ... + ... diff --git a/Documentation/portal-guide/source/portal-user-guide/admin-settings/index.rst b/Documentation/portal-guide/source/portal-user-guide/admin-settings/index.rst index b1df12f1140..bd4bfc13470 100644 --- a/Documentation/portal-guide/source/portal-user-guide/admin-settings/index.rst +++ b/Documentation/portal-guide/source/portal-user-guide/admin-settings/index.rst @@ -39,7 +39,7 @@ HowTo: Add a Third Party Application #. Enter its URL in :guilabel:`Link`, e.g. http://www.google.com. -#. Click on :guilabel:`Ok`. +#. Click on :guilabel:`Save`. .. _update-portal-settings: diff --git a/Documentation/portal-guide/source/portal-user-guide/portal-header/index.rst b/Documentation/portal-guide/source/portal-user-guide/portal-header/index.rst index 38461f38ba9..f6f49433eef 100644 --- a/Documentation/portal-guide/source/portal-user-guide/portal-header/index.rst +++ b/Documentation/portal-guide/source/portal-user-guide/portal-header/index.rst @@ -101,7 +101,7 @@ HowTo: Set substitute .. note:: - Grant either permission :bdg-warning:`šŸ”‘UserCreateOwnSubstitute ` or :bdg-ref-warning:`šŸ”‘UserCreateSubstitute ` + Grant either permission :bdg-ref-warning:`šŸ”‘UserCreateOwnSubstitute ` or :bdg-ref-warning:`šŸ”‘UserCreateSubstitute ` to allow a user to create their own substitute definitions or create substitute definitions for all users, respectively. Change Password @@ -113,7 +113,7 @@ The menu entry :guilabel:`Change password` allows you to set a new password. .. note:: - Grant permission: :bdg-ref-warning:`šŸ”‘UserSetOwnPassword` to allow a user to change their password. + Grant permission: :bdg-warning:`šŸ”‘UserSetOwnPassword` to allow a user to change their password. Configure permissions in the :dev-url:`Engine Cockpit `. In the security area, open PersonalPermissions -> PersonalSecurityPermissions -> UserSetOwnPassword. diff --git a/Showcase/InternalSupport/pom.xml b/Showcase/InternalSupport/pom.xml index 5e0578b75af..6a74a3701a5 100644 --- a/Showcase/InternalSupport/pom.xml +++ b/Showcase/InternalSupport/pom.xml @@ -6,8 +6,8 @@ 9.1.0.0-SNAPSHOT iar - 12.0.0 - 12.0.0 + 12.0.0-SNAPSHOT + 12.0.1 UTF-8 diff --git a/Showcase/portal-components-examples/pom.xml b/Showcase/portal-components-examples/pom.xml index ac732b8129c..076878621ed 100644 --- a/Showcase/portal-components-examples/pom.xml +++ b/Showcase/portal-components-examples/pom.xml @@ -17,8 +17,8 @@ - 12.0.0 - 12.0.0 + 12.0.1 + 12.0.0-SNAPSHOT UTF-8 diff --git a/Showcase/portal-developer-examples/pom.xml b/Showcase/portal-developer-examples/pom.xml index 6b8f7129f2b..470188c062f 100644 --- a/Showcase/portal-developer-examples/pom.xml +++ b/Showcase/portal-developer-examples/pom.xml @@ -17,8 +17,8 @@ - 12.0.0 - 12.0.0 + 12.0.1 + 12.0.0-SNAPSHOT UTF-8 diff --git a/Showcase/portal-user-examples/pom.xml b/Showcase/portal-user-examples/pom.xml index 1933081090c..20e8b2c6f51 100644 --- a/Showcase/portal-user-examples/pom.xml +++ b/Showcase/portal-user-examples/pom.xml @@ -17,8 +17,8 @@ - 12.0.0 - 12.0.0 + 12.0.1 + 12.0.0-SNAPSHOT UTF-8