修复Action history 为空的问题
Some checks failed
Mark & close stale issues / stale (push) Has been cancelled
Vulnerability Scan / trivy-scan (1.0) (push) Has been cancelled
Vulnerability Scan / trivy-scan (master) (push) Has been cancelled
CodeQL Advanced / Analyze (java-kotlin) (push) Has been cancelled
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
Some checks failed
Mark & close stale issues / stale (push) Has been cancelled
Vulnerability Scan / trivy-scan (1.0) (push) Has been cancelled
Vulnerability Scan / trivy-scan (master) (push) Has been cancelled
CodeQL Advanced / Analyze (java-kotlin) (push) Has been cancelled
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
This commit is contained in:
@@ -52,6 +52,8 @@ public final class TargetActionsHistory extends Grid<TargetActionsHistory.Action
|
||||
public TargetActionsHistory(final HawkbitMgmtClient hawkbitClient, TargetView.TargetActionsHistoryLayout.ActionStepsGrid actionStepsGrid) {
|
||||
this.hawkbitClient = hawkbitClient;
|
||||
setWidthFull();
|
||||
setMinHeight("200px");
|
||||
setAllRowsVisible(true);
|
||||
addColumn(new ComponentRenderer<>(ActionStatusEntry::getStatusIcon)).setHeader(STATUS).setAutoWidth(true).setFlexGrow(0);
|
||||
addColumn(ActionStatusEntry::getDistributionSetName).setHeader("Distribution Set").setAutoWidth(true);
|
||||
addColumn(Utils.localDateTimeRenderer(ActionStatusEntry::getLastModifiedAt))
|
||||
@@ -73,25 +75,60 @@ public final class TargetActionsHistory extends Grid<TargetActionsHistory.Action
|
||||
this.actionStepsGrid.setTarget(target);
|
||||
}
|
||||
|
||||
private List<ActionStatusEntry> fetchActions() {
|
||||
return hawkbitClient.getTargetRestApi().getActionHistory(target.getControllerId(), null, 0, 30, null)
|
||||
.getBody()
|
||||
.getContent()
|
||||
.stream()
|
||||
.map(action -> new ActionStatusEntry(action, () -> setItems(fetchActions())))
|
||||
.filter(value -> value.action != null)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttach(AttachEvent attachEvent) {
|
||||
List<ActionStatusEntry> actionStatusEntries = fetchActions();
|
||||
setItems(actionStatusEntries);
|
||||
actionStatusEntries.stream().findFirst().ifPresentOrElse(e -> {
|
||||
// select first action in the list by default
|
||||
public void loadData() {
|
||||
if (target == null) return;
|
||||
List<ActionStatusEntry> items;
|
||||
try {
|
||||
items = fetchActions();
|
||||
} catch (Exception e) {
|
||||
log.error("loadData: failed to fetch actions for target {}", target.getControllerId(), e);
|
||||
setItems(List.of());
|
||||
actionStepsGrid.setActionId(null);
|
||||
return;
|
||||
}
|
||||
log.info("loadData: {} action entries for target {}", items.size(), target.getControllerId());
|
||||
setItems(items);
|
||||
items.stream().findFirst().ifPresentOrElse(e -> {
|
||||
asSingleSelect().setValue(e);
|
||||
actionStepsGrid.setActionId(e.action.getId());
|
||||
}, () -> actionStepsGrid.setActionId(null));
|
||||
}, () -> {
|
||||
log.warn("loadData: no action entries to display");
|
||||
actionStepsGrid.setActionId(null);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from parent's onAttach or tab-selection listener.
|
||||
* Only triggers if a target has been set.
|
||||
*/
|
||||
public void loadIfReady() {
|
||||
if (target != null) {
|
||||
loadData();
|
||||
}
|
||||
}
|
||||
|
||||
private List<ActionStatusEntry> fetchActions() {
|
||||
final var response = hawkbitClient.getTargetRestApi().getActionHistory(target.getControllerId(), null, 0, 30, null);
|
||||
log.info("fetchActions: controllerId={}, httpStatus={}, body={}",
|
||||
target.getControllerId(),
|
||||
response.getStatusCode(),
|
||||
response.getBody() != null ? "present (" + response.getBody().getContent().size() + " actions)" : "NULL");
|
||||
if (response.getBody() == null) {
|
||||
return List.of();
|
||||
}
|
||||
return response.getBody()
|
||||
.getContent()
|
||||
.stream()
|
||||
.map(action -> {
|
||||
try {
|
||||
return new ActionStatusEntry(action, () -> setItems(fetchActions()));
|
||||
} catch (Exception e) {
|
||||
log.error("fetchActions: failed to create ActionStatusEntry for action id={}", action.getId(), e);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(value -> value != null && value.action != null)
|
||||
.toList();
|
||||
}
|
||||
|
||||
protected class ActionStatusEntry {
|
||||
@@ -101,20 +138,35 @@ public final class TargetActionsHistory extends Grid<TargetActionsHistory.Action
|
||||
MgmtDistributionSet distributionSet;
|
||||
|
||||
public ActionStatusEntry(final MgmtAction mgmtAction, final Runnable onUpdate) {
|
||||
this.action = hawkbitClient.getActionRestApi().getAction(mgmtAction.getId()).getBody();
|
||||
log.info("ActionStatusEntry: fetching action id={}", mgmtAction.getId());
|
||||
final var actionResp = hawkbitClient.getActionRestApi().getAction(mgmtAction.getId());
|
||||
log.info("ActionStatusEntry: getAction(id={}) -> status={}, body={}",
|
||||
mgmtAction.getId(),
|
||||
actionResp.getStatusCode(),
|
||||
actionResp.getBody() != null ? "present" : "NULL");
|
||||
this.action = actionResp.getBody();
|
||||
this.onUpdate = onUpdate;
|
||||
if (action == null) {
|
||||
log.error("Unable to fetch the action with id : {}", mgmtAction.getId());
|
||||
return;
|
||||
}
|
||||
log.info("ActionStatusEntry: action id={} loaded, links={}",
|
||||
action.getId(),
|
||||
action.getLinks().stream().map(l -> l.getRel().value()).toList());
|
||||
this.action.getLink("distributionset").ifPresent(link -> {
|
||||
log.info("ActionStatusEntry: found distributionset link, href={}", link.getHref());
|
||||
try {
|
||||
Long dsId = Long.parseLong(link.getHref().substring(link.getHref().lastIndexOf("/") + 1));
|
||||
this.distributionSet = hawkbitClient.getDistributionSetRestApi().getDistributionSet(dsId).getBody();
|
||||
log.info("ActionStatusEntry: distributionSet loaded, name={}",
|
||||
this.distributionSet != null ? this.distributionSet.getName() : "NULL");
|
||||
} catch (NumberFormatException e) {
|
||||
log.error("Error parsing distribution set ID", e);
|
||||
}
|
||||
});
|
||||
if (this.action.getLink("distributionset").isEmpty()) {
|
||||
log.warn("ActionStatusEntry: NO distributionset link found for action id={}", action.getId());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isActive() {
|
||||
|
||||
@@ -127,6 +127,9 @@ public class DistributionSetView extends TableView<MgmtDistributionSet, Long> {
|
||||
|
||||
private final TextField name = Utils.textField("Name");
|
||||
|
||||
private static final java.util.regex.Pattern RSQL_OP =
|
||||
java.util.regex.Pattern.compile("==|!=|=like=|=unlike=|=gt=|=ge=|=lt=|=le=|=in=|=out=");
|
||||
|
||||
private DistributionSetRawFilter() {
|
||||
name.setPlaceholder("<rsql filter>");
|
||||
}
|
||||
@@ -138,13 +141,25 @@ public class DistributionSetView extends TableView<MgmtDistributionSet, Long> {
|
||||
|
||||
@Override
|
||||
public String filter() {
|
||||
return name.getOptionalValue().orElse(null);
|
||||
return name.getOptionalValue().map(raw -> {
|
||||
if (RSQL_OP.matcher(raw).find()) {
|
||||
return raw;
|
||||
}
|
||||
// plain text: wrap as wildcard search on name and version
|
||||
return "(name==*" + encodeRsqlValue(raw) + "*,version==*" + encodeRsqlValue(raw) + "*)";
|
||||
}).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFilter(String filter) {
|
||||
name.setValue(filter);
|
||||
}
|
||||
|
||||
private static String encodeRsqlValue(String value) {
|
||||
return value.replace("\\", "\\\\")
|
||||
.replace("*", "\\*")
|
||||
.replace("\"", "\\\"");
|
||||
}
|
||||
}
|
||||
|
||||
private static class DistributionSetFilter implements Filter.Rsql {
|
||||
|
||||
@@ -50,6 +50,7 @@ import com.vaadin.flow.component.orderedlayout.FlexComponent;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.component.select.Select;
|
||||
import com.vaadin.flow.component.tabs.Tab;
|
||||
import com.vaadin.flow.component.tabs.TabSheet;
|
||||
import com.vaadin.flow.component.textfield.TextArea;
|
||||
import com.vaadin.flow.component.textfield.TextField;
|
||||
@@ -330,9 +331,24 @@ public final class TargetView extends TableView<TargetView.TargetWithDs, String>
|
||||
return List.of(layout);
|
||||
}
|
||||
|
||||
private static final java.util.regex.Pattern RSQL_OP =
|
||||
java.util.regex.Pattern.compile("==|!=|=like=|=unlike=|=gt=|=ge=|=lt=|=le=|=in=|=out=");
|
||||
|
||||
@Override
|
||||
public String filter() {
|
||||
return textFilter.getOptionalValue().orElse(null);
|
||||
return textFilter.getOptionalValue().map(raw -> {
|
||||
if (RSQL_OP.matcher(raw).find()) {
|
||||
return raw;
|
||||
}
|
||||
// plain text: wrap as wildcard search on controllerId and name
|
||||
return "(controllerid==*" + encodeRsqlValue(raw) + "*,name==*" + encodeRsqlValue(raw) + "*)";
|
||||
}).orElse(null);
|
||||
}
|
||||
|
||||
private static String encodeRsqlValue(String value) {
|
||||
return value.replace("\\", "\\\\")
|
||||
.replace("*", "\\*")
|
||||
.replace("\"", "\\\"");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -352,9 +368,11 @@ public final class TargetView extends TableView<TargetView.TargetWithDs, String>
|
||||
private final TargetTags targetTags;
|
||||
private final TargetMetadata targetMetadata;
|
||||
private final TargetActionsHistoryLayout targetActionsHistoryLayout;
|
||||
private final TabSheet tabSheet;
|
||||
private final Tab actionHistoryTab;
|
||||
|
||||
private TargetDetailedView(final HawkbitMgmtClient hawkbitClient) {
|
||||
final TabSheet tabSheet = new TabSheet();
|
||||
tabSheet = new TabSheet();
|
||||
tabSheet.setWidthFull();
|
||||
targetId = new Span();
|
||||
targetDetails = new TargetDetails(hawkbitClient);
|
||||
@@ -369,8 +387,16 @@ public final class TargetView extends TableView<TargetView.TargetWithDs, String>
|
||||
tabSheet.add("Assigned / Installed", targetAssignedInstalled);
|
||||
tabSheet.add("Tags", targetTags);
|
||||
tabSheet.add("Metadata", targetMetadata);
|
||||
tabSheet.add("Action History", targetActionsHistoryLayout);
|
||||
actionHistoryTab = tabSheet.add("Action History", targetActionsHistoryLayout);
|
||||
add(tabSheet);
|
||||
|
||||
// Load action history data when the tab becomes visible.
|
||||
// onAttach handles the first time; this listener handles subsequent tab switches.
|
||||
tabSheet.addSelectedChangeListener(e -> {
|
||||
if (e.getSelectedTab() == actionHistoryTab) {
|
||||
targetActionsHistoryLayout.refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setItem(final MgmtTarget target) {
|
||||
@@ -685,6 +711,16 @@ public final class TargetView extends TableView<TargetView.TargetWithDs, String>
|
||||
targetActionsHistory.setItem(target);
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
targetActionsHistory.loadData();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttach(AttachEvent attachEvent) {
|
||||
super.onAttach(attachEvent);
|
||||
targetActionsHistory.loadIfReady();
|
||||
}
|
||||
|
||||
public static class ActionStepsGrid extends Grid<ActionStepsGrid.ActionStepEntry> {
|
||||
|
||||
@Serial
|
||||
@@ -715,11 +751,6 @@ public final class TargetView extends TableView<TargetView.TargetWithDs, String>
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttach(AttachEvent attachEvent) {
|
||||
setItems(fetchActionSteps());
|
||||
}
|
||||
|
||||
public void setActionId(Long id) {
|
||||
actionId = id;
|
||||
setItems(fetchActionSteps());
|
||||
|
||||
Reference in New Issue
Block a user