Skip to content

Commit

Permalink
wip: sort workflows
Browse files Browse the repository at this point in the history
  • Loading branch information
katallaxie authored Aug 27, 2024
1 parent d30fd83 commit 998f6a9
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 89 deletions.
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ func (s *WebSrv) Start(ctx context.Context, ready server.ReadyFunc, run server.R
workflows.Get("/:id", handlers.ShowWorkflow())
workflows.Post("/:id/steps", handlers.CreateWorkflowStep())
workflows.Delete("/:id/steps/:step_id", handlers.DeleteWorkflowStep())
workflows.Put("/:id/steps", handlers.UpdateWorkflowSteps())

// Templates ...
templates := app.Group("/templates")
Expand Down
33 changes: 32 additions & 1 deletion internal/adapters/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package db
import (
"context"

"github.com/google/uuid"
"github.com/zeiss/fiber-htmx/components/tables"
seed "github.com/zeiss/gorm-seed"
"github.com/zeiss/service-lens/internal/models"
Expand Down Expand Up @@ -152,7 +153,13 @@ func (r *readTxImpl) GetTotalNumberOfWorkloads(ctx context.Context, total *int64

// GetWorkflow is a method that returns a workflow by ID
func (r *readTxImpl) GetWorkflow(ctx context.Context, workflow *models.Workflow) error {
return r.conn.Preload(clause.Associations).First(workflow, workflow.ID).Error
return r.conn.
Preload(clause.Associations).
Preload("Transitions").
Preload("Transitions.CurrentState").
Preload("Transitions.NextState").
First(workflow, workflow.ID).
Error
}

// GetDesignComment is a method that returns a design comment by ID
Expand Down Expand Up @@ -432,3 +439,27 @@ func (rw *writeTxImpl) DeleteWorkflowState(ctx context.Context, state *models.Wo

return rw.conn.Delete(&workflow.Transitions[currentTransition], workflow.Transitions[currentTransition].ID).Error
}

// UpdateWorkflowTransitions is a method that updates workflow transitions
func (rw *writeTxImpl) UpdateWorkflowTransitions(ctx context.Context, workflowId uuid.UUID, transitions []int) error {
workflow := models.Workflow{}

err := rw.conn.Preload(clause.Associations).First(&workflow, workflowId).Error
if err != nil {
return err
}

for i := len(transitions) - 1; i >= 0; i-- {
for j := range workflow.Transitions {
if workflow.Transitions[j].CurrentStateID == transitions[i] {
if len(transitions)-1 == i {
workflow.Transitions[j].NextStateID = 0
} else {
workflow.Transitions[j].NextStateID = transitions[i+1]
}
}
}
}

return rw.conn.Session(&gorm.Session{FullSaveAssociations: true}).Save(&workflow.Transitions).Error
}
7 changes: 7 additions & 0 deletions internal/adapters/handlers/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -515,3 +515,10 @@ func (a *handlers) DeleteWorkflowStep() fiber.Handler {
return workflows.NewStepController(a.store)
})
}

// UpdateWorkflowSteps ...
func (a *handlers) UpdateWorkflowSteps() fiber.Handler {
return htmx.NewHxControllerHandler(func() htmx.Controller {
return workflows.NewStepController(a.store)
})
}
4 changes: 0 additions & 4 deletions internal/components/page.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ func Page(props PageProps, children ...htmx.Node) htmx.Node {
htmx.Attribute("src", "https://unpkg.com/[email protected]"),
htmx.CrossOrigin("anonymous"),
),
htmx.Script(
htmx.Attribute("src", "https://cdn.jsdelivr.net/npm/@alpinejs/[email protected]/dist/cdn.min.js"),
htmx.Attribute("defer", ""),
),
htmx.Script(
htmx.Attribute("src", "https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"),
htmx.Attribute("defer", ""),
Expand Down
9 changes: 7 additions & 2 deletions internal/components/workflows/workflows-step.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,14 @@ func WorkflowStep(props WorkflowStepProps, children ...htmx.Node) htmx.Node {
return cards.CardBordered(
cards.CardProps{
ClassNames: htmx.ClassNames{
tailwind.M2: true,
tailwind.CursorPointer: true,
},
},
htmx.Input(
htmx.Type("hidden"),
htmx.Name("step"),
htmx.Value(conv.String(props.State.ID)),
),
cards.Body(
cards.BodyProps{},
cards.Title(
Expand All @@ -40,7 +45,7 @@ func WorkflowStep(props WorkflowStepProps, children ...htmx.Node) htmx.Node {
buttons.ButtonProps{},
htmx.HxDelete(fmt.Sprintf(utils.DeleteWorkflowStepUrlFormat, conv.String(props.WorkflowID), props.State.ID)),
htmx.HxConfirm("Are you sure you want to delete this step?"),
htmx.HxTarget("closest li"),
htmx.HxTarget("closest .card"),
htmx.HxSwap("outerHTML swap:1s"),
htmx.Text("Delete"),
),
Expand Down
130 changes: 55 additions & 75 deletions internal/controllers/workflows/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@ package workflows

import (
"context"
"fmt"

htmx "github.com/zeiss/fiber-htmx"
"github.com/zeiss/fiber-htmx/components/alerts"
"github.com/zeiss/fiber-htmx/components/alpine"
"github.com/zeiss/fiber-htmx/components/buttons"
"github.com/zeiss/fiber-htmx/components/cards"
"github.com/zeiss/fiber-htmx/components/loading"
"github.com/zeiss/fiber-htmx/components/tailwind"
seed "github.com/zeiss/gorm-seed"
"github.com/zeiss/service-lens/internal/components"
"github.com/zeiss/service-lens/internal/components/workflows"
"github.com/zeiss/service-lens/internal/models"
"github.com/zeiss/service-lens/internal/ports"
"github.com/zeiss/service-lens/internal/utils"
)

// WorkflowShowControllerImpl ...
Expand Down Expand Up @@ -66,7 +69,11 @@ func (p *WorkflowShowControllerImpl) Get() error {
Path: p.Path(),
User: p.Session().User,
Development: p.IsDevelopment(),
Head: []htmx.Node{},
Head: []htmx.Node{
htmx.Script(
htmx.Src("https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"),
),
},
},
func() htmx.Node {
return htmx.Fragment(
Expand Down Expand Up @@ -129,13 +136,41 @@ func (p *WorkflowShowControllerImpl) Get() error {
),
),
),

cards.CardBordered(
cards.CardProps{
ClassNames: htmx.ClassNames{
tailwind.M2: true,
},
},
// Todo: Move this script to a separate file
htmx.Script(htmx.Raw(`
htmx.onLoad(function(content) {
var sortables = content.querySelectorAll(".sortable");
for (var i = 0; i < sortables.length; i++) {
var sortable = sortables[i];
var sortableInstance = new Sortable(sortable, {
animation: 150,
ghostClass: 'blue-background-class',
filter: ".htmx-indicator",
onMove: function (evt) {
return evt.related.className.indexOf('htmx-indicator') === -1;
},
onEnd: function (evt) {
this.option("disabled", true);
}
});
sortable.addEventListener("htmx:afterSwap", function() {
sortableInstance.option("disabled", false);
});
}
})
`)),
alpine.XData(`{
}`),
cards.Body(
cards.BodyProps{},
Expand All @@ -152,87 +187,32 @@ func (p *WorkflowShowControllerImpl) Get() error {
htmx.Text("Add Step"),
),
),
htmx.Ul(
htmx.FormElement(
htmx.ClassNames{
"sortable": true,
},
htmx.HxPut(fmt.Sprintf(utils.UpdateWorkflowStepUrlFormat, p.workflow.ID)),
htmx.HxTrigger("end"),
htmx.HxSwap("none"),
htmx.ID("steps"),
htmx.Attribute("x-sort", ""),
loading.Spinner(
loading.SpinnerProps{
ClassNames: htmx.ClassNames{
"htmx-indicator": true,
},
},
),
htmx.Group(
htmx.ForEach(p.workflow.States, func(state models.WorkflowState, idx int) htmx.Node {
return htmx.Li(
htmx.ClassNames{
tailwind.My2: true,
htmx.ForEach(p.workflow.GetTransitions(), func(transition models.WorkflowTransition, idx int) htmx.Node {
return workflows.WorkflowStep(
workflows.WorkflowStepProps{
State: transition.CurrentState,
WorkflowID: p.workflow.ID,
},
htmx.Attribute("x-sort:item", ""),
workflows.WorkflowStep(
workflows.WorkflowStepProps{
State: state,
WorkflowID: p.workflow.ID,
},
),
)
})...,
),
),
// cards.Title(
// cards.TitleProps{},
// htmx.Text("Steps"),
// htmx.Div(
// htmx.ClassNames{
// "flex": true,
// "flex-col": true,
// "py-2": true,
// },
// ),

// htmx.Ul(
// htmx.Attribute("x-sort", ""),
// htmx.Li(
// htmx.Attribute("x-sort:item", ""),
// cards.CardBordered(
// cards.CardProps{},
// htmx.Attribute("x-sort:item", ""),
// cards.Body(
// cards.BodyProps{},
// htmx.Text("This is an example state."),
// ),
// ),
// ),
// htmx.Li(
// htmx.Attribute("x-sort:item", ""),
// cards.CardBordered(
// cards.CardProps{},
// htmx.Attribute("x-sort:item", ""),
// cards.Body(
// cards.BodyProps{
// ClassNames: htmx.ClassNames{
// tailwind.Flex: true,
// tailwind.JustifyBetween: true,
// tailwind.FlexRow: true,
// tailwind.ItemsCenter: true,
// },
// },
// htmx.Text("This is an example state."),
// buttons.Button(
// buttons.ButtonProps{},
// icons.EllipsisHorizontalOutline(
// icons.IconProps{},
// ),
// ),
// ),
// ),
// ),
// htmx.Li(
// htmx.Attribute("x-sort:item", ""),
// cards.CardBordered(
// cards.CardProps{},
// htmx.Attribute("x-sort:item", ""),
// cards.Body(
// cards.BodyProps{},
// htmx.Text("This is an example state."),
// ),
// ),
// ),
// ),
// ),
),
),
)
Expand Down
31 changes: 24 additions & 7 deletions internal/controllers/workflows/steps.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package workflows
import (
"context"

"github.com/zeiss/fiber-htmx/components/tailwind"
"github.com/zeiss/service-lens/internal/components/workflows"
"github.com/zeiss/service-lens/internal/models"
"github.com/zeiss/service-lens/internal/ports"
Expand Down Expand Up @@ -41,6 +40,28 @@ func (l *StepControllerImpl) Delete() error {
})
}

// Put ...
func (l *StepControllerImpl) Put() error {
var params struct {
WorkflowID uuid.UUID `json:"workflow_id" params:"id"`
Steps []int `json:"steps" form:"step"`
}

err := l.BindParams(&params)
if err != nil {
return err
}

err = l.BindBody(&params)
if err != nil {
return err
}

return l.store.ReadWriteTx(l.Context(), func(ctx context.Context, tx ports.ReadWriteTx) error {
return tx.UpdateWorkflowTransitions(ctx, params.WorkflowID, params.Steps)
})
}

// Post ...
func (l *StepControllerImpl) Post() error {
var params struct {
Expand Down Expand Up @@ -74,17 +95,13 @@ func (l *StepControllerImpl) Post() error {

return l.Render(
htmx.Fragment(
htmx.Li(
htmx.ClassNames{
tailwind.My2: true,
},
htmx.Attribute("x-sort:item", ""),
htmx.Div(
htmx.ID("steps"),
htmx.HxSwapOob("beforeend"),
workflows.WorkflowStep(
workflows.WorkflowStepProps{
State: state,
WorkflowID: state.WorkflowID,
WorkflowID: params.WorkflowID,
},
),
),
Expand Down
14 changes: 14 additions & 0 deletions internal/models/workflow.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package models

import (
"sort"
"time"

"github.com/google/uuid"
Expand Down Expand Up @@ -35,6 +36,15 @@ type Workflow struct {
DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"`
}

// GetSortedStates returns the states sorted by transitions.
func (w Workflow) GetTransitions() []WorkflowTransition {
sort.Slice(w.Transitions, func(i, j int) bool {
return w.Transitions[i].NextStateID == w.Transitions[j].CurrentStateID
})

return w.Transitions
}

// WorkflowState is the model for the workflow_state table
type WorkflowState struct {
// ID is the primary key of the workflow status
Expand All @@ -61,8 +71,12 @@ type WorkflowTransition struct {
WorkflowID uuid.UUID `json:"workflow_id" gorm:"type:uuid;not null"`
// CurrentStateID is the foreign key of the current state
CurrentStateID int `json:"current_state_id" gorm:"type:bigint;not null"`
// CurrentState is the current state of the transition
CurrentState WorkflowState `json:"current_state" gorm:"foreignKey:CurrentStateID;references:ID"`
// NextStateID is the foreign key of the next state
NextStateID int `json:"next_state_id" gorm:"type:bigint"`
// NextState is the next state of the transition
NextState WorkflowState `json:"next_state" gorm:"foreignKey:NextStateID;references:ID"`
// CreatedAt is the created at field
CreatedAt time.Time `json:"created_at"`
// UpdatedAt is the updated at field
Expand Down
2 changes: 2 additions & 0 deletions internal/ports/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ type Handlers interface {
DesignReactions() fiber.Handler
// CreateWorkflowStep ...
CreateWorkflowStep() fiber.Handler
// UpdateWorkflowSteps ...
UpdateWorkflowSteps() fiber.Handler
// DeleteWorkflowStep ...
DeleteWorkflowStep() fiber.Handler
}
Loading

0 comments on commit 998f6a9

Please sign in to comment.