Files
2026-06-18 23:33:27 +01:00

250 lines
7.2 KiB
Go

package executor
import (
"fmt"
config "github.com/OliveTin/OliveTin/internal/config"
"github.com/OliveTin/OliveTin/internal/entities"
)
type DashboardNavigationTarget struct {
Title string
EntityType string
EntityKey string
Path string
}
func (target DashboardNavigationTarget) key() string {
return target.Title + "\x00" + target.EntityType + "\x00" + target.EntityKey
}
func (b *ActionBinding) IsOnConfiguredDashboard() bool {
for _, dashboard := range b.OnDashboards {
if dashboard.Title != "Actions" {
return true
}
}
return false
}
type dashboardTargetIndex struct {
byTitle map[string][]DashboardNavigationTarget
byTitleEntityKey map[string]map[string][]DashboardNavigationTarget
}
func buildDashboardTargetIndex(cfg *config.Config) *dashboardTargetIndex {
index := &dashboardTargetIndex{
byTitle: make(map[string][]DashboardNavigationTarget),
byTitleEntityKey: make(map[string]map[string][]DashboardNavigationTarget),
}
for _, dashboard := range cfg.Dashboards {
walkDashboardContents(dashboard.Contents, dashboard.Title, index)
}
return index
}
func walkDashboardContents(contents []*config.DashboardComponent, rootDashboardTitle string, index *dashboardTargetIndex) {
for _, component := range contents {
walkDashboardComponent(component, rootDashboardTitle, index)
}
}
func walkDashboardComponent(component *config.DashboardComponent, rootDashboardTitle string, index *dashboardTargetIndex) {
if component.Type == "fieldset" && component.Entity != "" {
walkEntityFieldset(component, rootDashboardTitle, component.Entity, index)
return
}
recordActionTarget(component, rootDashboardTitle, "", "", index)
if len(component.Contents) > 0 {
walkDashboardContents(component.Contents, rootDashboardTitle, index)
}
}
func walkEntityFieldset(fieldset *config.DashboardComponent, rootDashboardTitle, entityType string, index *dashboardTargetIndex) {
for _, component := range fieldset.Contents {
if component.Type == "directory" {
walkEntityDirectory(component, entityType, index)
continue
}
recordActionTargetForAllEntities(component, rootDashboardTitle, entityType, index)
if len(component.Contents) > 0 {
walkEntityFieldsetContents(component.Contents, rootDashboardTitle, entityType, index)
}
}
}
func walkEntityFieldsetContents(contents []*config.DashboardComponent, rootDashboardTitle, entityType string, index *dashboardTargetIndex) {
for _, component := range contents {
if component.Type == "directory" {
walkEntityDirectory(component, entityType, index)
continue
}
recordActionTargetForAllEntities(component, rootDashboardTitle, entityType, index)
if len(component.Contents) > 0 {
walkEntityFieldsetContents(component.Contents, rootDashboardTitle, entityType, index)
}
}
}
func walkEntityDirectory(directory *config.DashboardComponent, entityType string, index *dashboardTargetIndex) {
for _, entity := range entities.GetEntityInstancesOrdered(entityType) {
for _, component := range directory.Contents {
recordActionTarget(component, directory.Title, entityType, entity.UniqueKey, index)
}
}
}
func recordActionTargetForAllEntities(component *config.DashboardComponent, rootDashboardTitle, entityType string, index *dashboardTargetIndex) {
actionTitle := actionTitleFromComponent(component)
if actionTitle == "" {
return
}
target := dashboardNavigationTarget(rootDashboardTitle, "", "")
for _, entity := range entities.GetEntityInstancesOrdered(entityType) {
addEntityTarget(index, actionTitle, entity.UniqueKey, target)
}
}
func recordActionTarget(component *config.DashboardComponent, dashboardTitle, entityType, entityKey string, index *dashboardTargetIndex) {
actionTitle := actionTitleFromComponent(component)
if actionTitle == "" {
return
}
target := dashboardNavigationTarget(dashboardTitle, entityType, entityKey)
if entityType != "" && entityKey != "" {
addEntityTarget(index, actionTitle, entityKey, target)
return
}
addTitleTarget(index, actionTitle, target)
}
func actionTitleFromComponent(component *config.DashboardComponent) string {
if title := inlineActionTitle(component); title != "" {
return title
}
if component.Type == "link" || component.Type == "" {
return component.Title
}
return ""
}
func inlineActionTitle(component *config.DashboardComponent) string {
if component.InlineAction == nil {
return ""
}
if component.Title != "" {
return component.Title
}
return component.InlineAction.Title
}
func dashboardNavigationTarget(title, entityType, entityKey string) DashboardNavigationTarget {
return DashboardNavigationTarget{
Title: title,
EntityType: entityType,
EntityKey: entityKey,
Path: dashboardNavigationPath(title, entityType, entityKey),
}
}
func dashboardNavigationPath(title, entityType, entityKey string) string {
if title == "Actions" {
return "/"
}
if entityType != "" && entityKey != "" {
return fmt.Sprintf("/dashboards/%s/%s/%s", title, entityType, entityKey)
}
return fmt.Sprintf("/dashboards/%s", title)
}
func addTitleTarget(index *dashboardTargetIndex, actionTitle string, target DashboardNavigationTarget) {
index.byTitle[actionTitle] = appendUniqueTarget(index.byTitle[actionTitle], target)
}
func addEntityTarget(index *dashboardTargetIndex, actionTitle, entityKey string, target DashboardNavigationTarget) {
if index.byTitleEntityKey[actionTitle] == nil {
index.byTitleEntityKey[actionTitle] = make(map[string][]DashboardNavigationTarget)
}
entityTargets := index.byTitleEntityKey[actionTitle][entityKey]
index.byTitleEntityKey[actionTitle][entityKey] = appendUniqueTarget(entityTargets, target)
}
func appendUniqueTarget(targets []DashboardNavigationTarget, target DashboardNavigationTarget) []DashboardNavigationTarget {
for _, existing := range targets {
if existing.key() == target.key() {
return targets
}
}
return append(targets, target)
}
func (index *dashboardTargetIndex) targetsForAction(actionTitle string) []DashboardNavigationTarget {
return dedupeTargets(index.byTitle[actionTitle])
}
func (index *dashboardTargetIndex) targetsForEntityAction(actionTitle, entityKey string) []DashboardNavigationTarget {
targets := make([]DashboardNavigationTarget, 0)
targets = append(targets, index.byTitle[actionTitle]...)
if entityTargets, ok := index.byTitleEntityKey[actionTitle]; ok {
targets = append(targets, entityTargets[entityKey]...)
}
return dedupeTargets(targets)
}
func dedupeTargets(targets []DashboardNavigationTarget) []DashboardNavigationTarget {
if len(targets) == 0 {
return nil
}
seen := make(map[string]bool, len(targets))
result := make([]DashboardNavigationTarget, 0, len(targets))
for _, target := range targets {
key := target.key()
if seen[key] {
continue
}
seen[key] = true
result = append(result, target)
}
return result
}
func resolveOnDashboards(index *dashboardTargetIndex, actionTitle, entityKey string) []DashboardNavigationTarget {
var targets []DashboardNavigationTarget
if entityKey == "" {
targets = index.targetsForAction(actionTitle)
} else {
targets = index.targetsForEntityAction(actionTitle, entityKey)
}
if len(targets) == 0 {
return []DashboardNavigationTarget{dashboardNavigationTarget("Actions", "", "")}
}
return targets
}