Add Show Widget for library actions with Overview charts from last run output.
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"codeberg.org/SquidSE/ClusterCanvas/service/internal/auth"
|
||||
"codeberg.org/SquidSE/ClusterCanvas/service/internal/runner/widgetparse"
|
||||
"codeberg.org/SquidSE/ClusterCanvas/service/internal/settings"
|
||||
)
|
||||
|
||||
@@ -126,10 +127,7 @@ func ResolveItem(item settings.NodeActionItem, library []settings.Action) (Resol
|
||||
}
|
||||
for _, action := range library {
|
||||
if action.ID == item.LibraryActionID {
|
||||
env := action.Env
|
||||
if env == nil {
|
||||
env = []settings.ActionEnvVar{}
|
||||
}
|
||||
env := mergeActionEnv(action.Env, item.Env)
|
||||
return ResolvedAction{
|
||||
Name: action.Name,
|
||||
Description: action.Description,
|
||||
@@ -170,6 +168,36 @@ func ResolveItem(item settings.NodeActionItem, library []settings.Action) (Resol
|
||||
}
|
||||
}
|
||||
|
||||
// mergeActionEnv returns library env with item overrides (item wins on name clash).
|
||||
func mergeActionEnv(
|
||||
libraryEnv []settings.ActionEnvVar,
|
||||
itemEnv []settings.ActionEnvVar,
|
||||
) []settings.ActionEnvVar {
|
||||
merged := make([]settings.ActionEnvVar, 0, len(libraryEnv)+len(itemEnv))
|
||||
indexByName := map[string]int{}
|
||||
for _, envVar := range libraryEnv {
|
||||
name := strings.TrimSpace(envVar.Name)
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
indexByName[name] = len(merged)
|
||||
merged = append(merged, settings.ActionEnvVar{Name: name, Value: envVar.Value})
|
||||
}
|
||||
for _, envVar := range itemEnv {
|
||||
name := strings.TrimSpace(envVar.Name)
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
if index, exists := indexByName[name]; exists {
|
||||
merged[index].Value = envVar.Value
|
||||
continue
|
||||
}
|
||||
indexByName[name] = len(merged)
|
||||
merged = append(merged, settings.ActionEnvVar{Name: name, Value: envVar.Value})
|
||||
}
|
||||
return merged
|
||||
}
|
||||
|
||||
// WrapShellWithSudo prepends "sudo -n " when requiresSudo is true.
|
||||
func WrapShellWithSudo(command string, requiresSudo bool) string {
|
||||
if !requiresSudo {
|
||||
@@ -390,6 +418,17 @@ func (executor *Executor) runItems(
|
||||
itemResult.VariableValue = captured
|
||||
}
|
||||
results = append(results, itemResult)
|
||||
|
||||
if item.Source == settings.ActionItemSourceLibrary {
|
||||
_ = persistWidgetSnapshot(
|
||||
executor.ConfigDir,
|
||||
group,
|
||||
item,
|
||||
libraryStore.Actions,
|
||||
itemResult,
|
||||
envMap,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
finishedAt := time.Now().UTC()
|
||||
@@ -447,3 +486,68 @@ func (executor *Executor) loadNodeCredentials(nodeID string) (settings.Node, str
|
||||
}
|
||||
return settings.Node{}, "", "", fmt.Errorf("node private key not found")
|
||||
}
|
||||
|
||||
func persistWidgetSnapshot(
|
||||
configDir string,
|
||||
group settings.NodeActionGroup,
|
||||
item settings.NodeActionItem,
|
||||
library []settings.Action,
|
||||
itemResult settings.ActionItemRunResult,
|
||||
envMap map[string]string,
|
||||
) error {
|
||||
var libraryAction *settings.Action
|
||||
for index := range library {
|
||||
if library[index].ID == item.LibraryActionID {
|
||||
libraryAction = &library[index]
|
||||
break
|
||||
}
|
||||
}
|
||||
if libraryAction == nil || !libraryAction.ShowWidget {
|
||||
return nil
|
||||
}
|
||||
widgetType := libraryAction.WidgetType
|
||||
if widgetType == settings.ActionWidgetTypeNone {
|
||||
widgetType = settings.ActionWidgetTypeRaw
|
||||
}
|
||||
|
||||
title := strings.TrimSpace(item.WidgetLabel)
|
||||
if title == "" {
|
||||
title = libraryAction.Name
|
||||
if mount := strings.TrimSpace(envMap["MOUNT"]); mount != "" && widgetType == settings.ActionWidgetTypeDisk {
|
||||
title = fmt.Sprintf("%s (%s)", libraryAction.Name, mount)
|
||||
}
|
||||
}
|
||||
|
||||
snapshot := settings.ActionWidgetSnapshot{
|
||||
NodeID: group.NodeID,
|
||||
ItemID: item.ID,
|
||||
GroupID: group.ID,
|
||||
LibraryActionID: item.LibraryActionID,
|
||||
WidgetType: widgetType,
|
||||
Title: title,
|
||||
UpdatedAt: itemResult.FinishedAt,
|
||||
ExitCode: itemResult.ExitCode,
|
||||
Error: itemResult.Error,
|
||||
RawStdout: itemResult.Stdout,
|
||||
}
|
||||
|
||||
if itemResult.Skipped {
|
||||
snapshot.Error = itemResult.SkipReason
|
||||
return settings.UpsertActionWidgetSnapshot(configDir, snapshot)
|
||||
}
|
||||
|
||||
mountHint := strings.TrimSpace(envMap["MOUNT"])
|
||||
if itemResult.ExitCode == 0 && itemResult.Error == "" {
|
||||
memory, disk, parseErr := widgetparse.ParseStdout(widgetType, itemResult.Stdout, mountHint)
|
||||
if parseErr != nil {
|
||||
snapshot.Error = parseErr.Error()
|
||||
} else {
|
||||
snapshot.Memory = memory
|
||||
snapshot.Disk = disk
|
||||
}
|
||||
} else if snapshot.Error == "" && itemResult.ExitCode != 0 {
|
||||
snapshot.Error = fmt.Sprintf("exit code %d", itemResult.ExitCode)
|
||||
}
|
||||
|
||||
return settings.UpsertActionWidgetSnapshot(configDir, snapshot)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user