Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added pid filtering searchbox and selection counter in snapshot download popup #5627

Merged
merged 12 commits into from
Jan 7, 2025
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*******************************************************************************
* Copyright (c) 2025 Eurotech and/or its affiliates and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Eurotech
*******************************************************************************/

package org.eclipse.kura.web.client.ui.settings;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add copyright header

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can already put 2025 at this point.


public enum PartialSnapshotCheckboxStatus {

ALL_VISIBLE_ALL_SELECTED,
ALL_VISIBLE_PARTIAL_SELECTED,
PARTIAL_VISIBLE_ALL_SELECTED,
PARTIAL_VISIBLE_PARTIAL_SELECTED;

public static PartialSnapshotCheckboxStatus fromVisibleAndSelectedStatus(boolean allVisible, boolean allSelected) {
if (allVisible) {
if (allSelected) {
return PartialSnapshotCheckboxStatus.ALL_VISIBLE_ALL_SELECTED;
} else {
return PartialSnapshotCheckboxStatus.ALL_VISIBLE_PARTIAL_SELECTED;
}
} else {
if (allSelected) {
return PartialSnapshotCheckboxStatus.PARTIAL_VISIBLE_ALL_SELECTED;
} else {
return PartialSnapshotCheckboxStatus.PARTIAL_VISIBLE_PARTIAL_SELECTED;
}
}
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2024 Eurotech and/or its affiliates and others
* Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand All @@ -26,14 +26,17 @@
import org.gwtbootstrap3.client.ui.CheckBox;
import org.gwtbootstrap3.client.ui.FormLabel;
import org.gwtbootstrap3.client.ui.Modal;
import org.gwtbootstrap3.client.ui.TextBox;
import org.gwtbootstrap3.client.ui.html.Paragraph;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
Expand All @@ -51,6 +54,12 @@ interface SnapshotDownloadModalUiBinder extends UiBinder<Widget, SnapshotDownloa
@UiField
Paragraph formatModalHint;
@UiField
Label searchBoxSeparatorSmall;
@UiField
TextBox pidSearch;
@UiField
Label searchBoxSeparatorBig;
@UiField
ScrollPanel pidSelectionScrollPanel;
@UiField
Anchor selectOrRemoveAllAnchor;
Expand All @@ -64,8 +73,9 @@ interface SnapshotDownloadModalUiBinder extends UiBinder<Widget, SnapshotDownloa
Button cancelButton;
@UiField
FormLabel noPidSelectedError;
@UiField
Label selectedPidCounter;

boolean areAllPidsSelected = true;
VerticalPanel pidPanel = new VerticalPanel();

HandlerRegistration anchorClickHandler;
Expand All @@ -76,9 +86,13 @@ public SnapshotDownloadModal() {

initWidget(uiBinder.createAndBindUi(this));

this.pidSearch.setVisible(false);
this.pidSelectionScrollPanel.setVisible(false);
this.selectOrRemoveAllAnchor.setVisible(false);
this.noPidSelectedError.setVisible(false);
this.selectedPidCounter.setVisible(false);
this.searchBoxSeparatorSmall.setVisible(false);
this.searchBoxSeparatorBig.setVisible(false);

this.cancelButton.addClickHandler(this::onCancelClick);

Expand All @@ -95,19 +109,29 @@ public void show(Consumer<SnapshotDownloadOptions> consumer) {
public void show(Consumer<SnapshotDownloadOptions> consumer, List<String> availablePids) {
this.snapshotDownloadConsumer = consumer;
this.noPidSelectedError.setVisible(false);
this.searchBoxSeparatorSmall.setVisible(true);
this.searchBoxSeparatorBig.setVisible(true);
this.modal.setTitle(MSGS.deviceSnapshotDownloadModalTitle());
this.downloadModalDescription.setText(MSGS.deviceSnapshotDownloadModalHint());
initPidSearch();
initSnapshotPidList(availablePids);
initSnapshotSelectAllAnchor();
initSnapshotScrollPanel();
initSnapshotDownloadButtons();
initSelectedPidCounter();
this.modal.show();
}

/*
* Snapshot Download Inits
*/

private void initPidSearch() {
this.pidSearch.clear();
this.pidSearch.setVisible(true);
this.pidSearch.addKeyUpHandler(this::onSearchBoxEvent);
}

private void initSnapshotPidList(List<String> snapshotConfigs) {

this.pidPanel.clear();
Expand All @@ -125,9 +149,8 @@ private void initSnapshotSelectAllAnchor() {
if (this.anchorClickHandler != null) {
this.anchorClickHandler.removeHandler();
}
this.areAllPidsSelected = true;
this.selectOrRemoveAllAnchor.setText(MSGS.removeAllAnchorText());
this.anchorClickHandler = this.selectOrRemoveAllAnchor.addClickHandler(this::selectOrRemoveAllSelection);
this.anchorClickHandler = this.selectOrRemoveAllAnchor.addClickHandler(this::onSelectOrRemoveAllSelection);
this.selectOrRemoveAllAnchor.setVisible(true);
}

Expand Down Expand Up @@ -162,6 +185,11 @@ private void initSnapshotDownloadButtons() {
});
}

private void initSelectedPidCounter() {
updateSelectedPidsCounter();
this.selectedPidCounter.setVisible(true);
}

/*
* Wiregraph Snapshot Download Inits
*/
Expand All @@ -180,16 +208,36 @@ private void initWiregraphDownloadButtons() {
}

/*
* Utils
* OnEvents Methods
*/

private void onSearchBoxEvent(KeyUpEvent event) {
TextBox searchBox = (TextBox) event.getSource();
String searchedPid = searchBox.getValue();

if (searchedPid == null || searchedPid.isEmpty() || searchedPid.equals("")) {
this.pidPanel.iterator().forEachRemaining(widget -> widget.setVisible(true));
} else {
this.pidPanel.iterator().forEachRemaining(widget -> {
CheckBox box = (CheckBox) widget;
box.setVisible(box.getText().toLowerCase().contains(searchedPid.toLowerCase()));
});
}

if (this.noPidSelectedError.isVisible()) {
this.noPidSelectedError.setVisible(false);
}

updateSelectOrRemoveAllText(checkPidsCheckboxStates());
}

sfiorani marked this conversation as resolved.
Show resolved Hide resolved
private void onCheckboxClick(ClickEvent handler) {
if (noPidSelectedError.isVisible()) {
noPidSelectedError.setVisible(false);
}

checkAllPidsSelected();
updateSelectOrRemoveAllText();
updateSelectOrRemoveAllText(checkPidsCheckboxStates());
updateSelectedPidsCounter();

}

Expand All @@ -199,6 +247,41 @@ private void onCancelClick(ClickEvent handler) {
this.noPidSelectedError.setVisible(false);
}

private void onSelectOrRemoveAllSelection(ClickEvent handler) {
PartialSnapshotCheckboxStatus state = checkPidsCheckboxStates();
switch (state) {
case ALL_VISIBLE_ALL_SELECTED:
case PARTIAL_VISIBLE_ALL_SELECTED: {
pidPanel.iterator().forEachRemaining(widget -> {
if (widget.isVisible()) {
((CheckBox) widget).setValue(false);
}
});
break;
}

case ALL_VISIBLE_PARTIAL_SELECTED:
case PARTIAL_VISIBLE_PARTIAL_SELECTED:
pidPanel.iterator().forEachRemaining(widget -> {
if (widget.isVisible()) {
((CheckBox) widget).setValue(true);
}
});
break;
}

updateSelectOrRemoveAllText(checkPidsCheckboxStates());
updateSelectedPidsCounter();

if (this.noPidSelectedError.isVisible()) {
this.noPidSelectedError.setVisible(false);
}
}

/*
* Utils
*/

private Optional<List<String>> getSelectedPids() {
List<String> selectedPids = new ArrayList<>();
this.pidPanel.iterator().forEachRemaining(pid -> {
Expand All @@ -212,12 +295,6 @@ private Optional<List<String>> getSelectedPids() {
return selectedPids.isEmpty() ? Optional.empty() : Optional.of(selectedPids);
}

private void selectOrRemoveAllSelection(ClickEvent handler) {
pidPanel.iterator().forEachRemaining(widget -> ((CheckBox) widget).setValue(!this.areAllPidsSelected));
this.areAllPidsSelected = !this.areAllPidsSelected;
updateSelectOrRemoveAllText();
}

private boolean isOnePidSelected() {
boolean result = false;
Iterator<Widget> pidPanelIterator = this.pidPanel.iterator();
Expand All @@ -232,23 +309,45 @@ private boolean isOnePidSelected() {
return result;
}

private void checkAllPidsSelected() {
private PartialSnapshotCheckboxStatus checkPidsCheckboxStates() {
boolean areAllVisible = true;
boolean areAllSelected = true;
Iterator<Widget> pidPanelIterator = this.pidPanel.iterator();
while (pidPanelIterator.hasNext()) {
if (!((CheckBox) pidPanelIterator.next()).getValue().booleanValue()) {

for (Widget widget : pidPanel) {
if (!widget.isVisible()) {
areAllVisible = false;
break;
}
}

for (Widget widget : pidPanel) {
if (widget.isVisible() && !((CheckBox) widget).getValue().booleanValue()) {
areAllSelected = false;
break;
}
}
this.areAllPidsSelected = areAllSelected;

return PartialSnapshotCheckboxStatus.fromVisibleAndSelectedStatus(areAllVisible, areAllSelected);
}

private void updateSelectOrRemoveAllText() {
if (this.areAllPidsSelected) {
private void updateSelectOrRemoveAllText(PartialSnapshotCheckboxStatus state) {

switch (state) {
case ALL_VISIBLE_ALL_SELECTED:
this.selectOrRemoveAllAnchor.setText(MSGS.removeAllAnchorText());
} else {
break;

case ALL_VISIBLE_PARTIAL_SELECTED:
this.selectOrRemoveAllAnchor.setText(MSGS.selectAllAnchorText());
break;

case PARTIAL_VISIBLE_ALL_SELECTED:
this.selectOrRemoveAllAnchor.setText(MSGS.removeAllVisibleAnchorText());
break;

case PARTIAL_VISIBLE_PARTIAL_SELECTED:
this.selectOrRemoveAllAnchor.setText(MSGS.selectAllVisibleAnchorText());
break;
}
}

Expand All @@ -258,4 +357,20 @@ private void resetScrollPanel() {
this.noPidSelectedError.setVisible(false);
}

private void updateSelectedPidsCounter() {

int selectedPids = 0;

Iterator<Widget> pidPanelIterator = this.pidPanel.iterator();
while (pidPanelIterator.hasNext()) {
if (((CheckBox) pidPanelIterator.next()).getValue().booleanValue()) {
selectedPids++;
}
}

StringBuilder counterTextBuilder = new StringBuilder("PIDs Selected ").append(selectedPids).append("/")
.append(this.pidPanel.getWidgetCount());

this.selectedPidCounter.setText(counterTextBuilder.toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<!--

Copyright (c) 2024 Eurotech and/or its affiliates and others
Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others

This program and the accompanying materials are made
available under the terms of the Eclipse Public License 2.0
Expand All @@ -24,10 +24,34 @@

<ui:style>
.channel-name-validation-label {
padding-top: 10px;
color: red;
font-size: 0.35cm;
font-weight: normal;
padding-top: 10px;
color: red;
font-size: 0.35cm;
font-weight: normal;
}
.small-spacing {
padding-bottom: 10px;
}
.big-spacing {
padding-bottom: 20px;
}

.text-button {
background: none;
border: none;
color: blue;
text-decoration: underline;
cursor: pointer;
float: left;
}

.right-label {
margin-left: auto;
float: right;
font-weight: bold;
}
.horizontal-panel {
width: 100%;
}
</ui:style>

Expand All @@ -38,12 +62,19 @@
<b:FormGroup>
<b.html:Paragraph ui:field="downloadModalDescription" />
<b.html:Paragraph ui:field="formatModalHint" text="{msgs.formatDownloadHint}" />
<g:Label ui:field="searchBoxSeparatorSmall" addStyleNames="{style.small-spacing}"/>
<b:TextBox placeholder="{msgs.snapshotDownloadSearchBoxPlaceholder}"
ui:field="pidSearch" addStyleNames="services-search" />
<g:Label ui:field="searchBoxSeparatorBig" addStyleNames="{style.big-spacing}"/>
<g:ScrollPanel ui:field="pidSelectionScrollPanel"></g:ScrollPanel>
<b:FormLabel addStyleNames="{style.channel-name-validation-label}" ui:field="noPidSelectedError" text="{msgs.downloadSnapshotError}" />
</b:FormGroup>
</b:FieldSet>
</g:FormPanel>
<b:Anchor ui:field="selectOrRemoveAllAnchor" />
<g:HorizontalPanel addStyleNames="{style.horizontal-panel}" >
<b:Anchor ui:field="selectOrRemoveAllAnchor" />
<g:Label ui:field="selectedPidCounter" addStyleNames="{style.right-label}" />
</g:HorizontalPanel>
</b:ModalBody>
<b:ModalFooter>
<b:Button addStyleNames="fa" type="PRIMARY" ui:field= "cancelButton" text="{msgs.cancelButton}" />
Expand Down
Loading
Loading