Feat v0.7.9 workflow independence (#63)
All checks were successful
CI/CD / detect-changes (push) Successful in 20s
CI/CD / test-runners (push) Has been skipped
CI/CD / e2e-smoke (push) Has been skipped
CI/CD / test-frontend (push) Successful in 25s
CI/CD / test-sqlite (push) Successful in 2m51s
CI/CD / test-go-pg (push) Successful in 3m0s
CI/CD / build-and-deploy (push) Successful in 1m26s
All checks were successful
CI/CD / detect-changes (push) Successful in 20s
CI/CD / test-runners (push) Has been skipped
CI/CD / e2e-smoke (push) Has been skipped
CI/CD / test-frontend (push) Successful in 25s
CI/CD / test-sqlite (push) Successful in 2m51s
CI/CD / test-go-pg (push) Successful in 3m0s
CI/CD / build-and-deploy (push) Successful in 1m26s
Co-authored-by: Jeffrey Smith <jasafpro@gmail.com> Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit was merged in pull request #63.
This commit is contained in:
@@ -25,6 +25,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"armature/config"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
@@ -631,18 +632,20 @@ func (e *Engine) RenderLogin() gin.HandlerFunc {
|
||||
|
||||
// WorkflowPageData is passed to the workflow.html template via PageData.Data.
|
||||
type WorkflowPageData struct {
|
||||
ChannelID string
|
||||
ChannelTitle string
|
||||
ChannelDescription string
|
||||
SessionID string
|
||||
SessionName string
|
||||
StageMode string // custom | form_only | form_chat | review
|
||||
StageName string
|
||||
FormTemplateJSON string // typed form template JSON (empty if custom)
|
||||
TotalStages int
|
||||
CurrentStage int
|
||||
SurfacePkgID string
|
||||
BrandingJSON string
|
||||
EntryToken string
|
||||
WorkflowTitle string
|
||||
WorkflowDescription string
|
||||
SessionID string
|
||||
SessionName string
|
||||
StageMode string // form | review | delegated | automated
|
||||
StageName string
|
||||
FormTemplateJSON string // typed form template JSON (empty if delegated)
|
||||
TotalStages int
|
||||
CurrentStage int
|
||||
SurfacePkgID string
|
||||
BrandingJSON string
|
||||
InstanceID string // workflow instance ID (used for API calls)
|
||||
Status string // pending | active | completed | cancelled | stale
|
||||
}
|
||||
|
||||
// WorkflowLandingPageData is passed to workflow-landing.html.
|
||||
@@ -660,49 +663,106 @@ type WorkflowLandingPageData struct {
|
||||
PersonaName string
|
||||
PersonaIcon string
|
||||
StageCount int
|
||||
FirstStageMode string // custom | form_only | form_chat
|
||||
FirstStageMode string // form | review | delegated | automated
|
||||
ResumeURL string // non-empty if visitor has an active session
|
||||
}
|
||||
|
||||
// RenderWorkflow renders the workflow entry page for anonymous session visitors.
|
||||
// RenderWorkflow renders the workflow execution page for a running instance.
|
||||
// Route: /w/:id — :id is either an instance ID or a public entry token.
|
||||
// The middleware (AuthOrSession) has already created/resumed the session.
|
||||
func (e *Engine) RenderWorkflow() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// :id is the public entry token (from /w/:id)
|
||||
channelID := c.Param("id")
|
||||
ctx := c.Request.Context()
|
||||
routeID := c.Param("id")
|
||||
sessionID := c.GetString("session_id")
|
||||
|
||||
var title, description string
|
||||
if title == "" {
|
||||
title = "Workflow"
|
||||
}
|
||||
|
||||
// Load session display name
|
||||
sessionName := "Visitor"
|
||||
|
||||
// Load workflow stage info for form rendering
|
||||
var stageMode, stageName, formTplJSON, surfacePkgID, brandingJSON string
|
||||
var totalStages, currentStage int
|
||||
stageMode = "custom" // default
|
||||
|
||||
instanceName, _, _ := e.loadBranding()
|
||||
|
||||
// Try to load instance — the route param may be an instance ID
|
||||
// or an entry token. Also check the ?token= query param.
|
||||
var inst *models.WorkflowInstance
|
||||
if e.stores.Workflows != nil {
|
||||
// First try: query param token (from landing page redirect)
|
||||
if qToken := c.Query("token"); qToken != "" {
|
||||
inst, _ = e.stores.Workflows.GetInstanceByToken(ctx, qToken)
|
||||
}
|
||||
// Second try: route param as entry token
|
||||
if inst == nil {
|
||||
inst, _ = e.stores.Workflows.GetInstanceByToken(ctx, routeID)
|
||||
}
|
||||
// Third try: route param as instance ID
|
||||
if inst == nil {
|
||||
inst, _ = e.stores.Workflows.GetInstance(ctx, routeID)
|
||||
}
|
||||
}
|
||||
|
||||
if inst == nil {
|
||||
c.String(http.StatusNotFound, "Workflow instance not found")
|
||||
return
|
||||
}
|
||||
|
||||
// Load workflow definition for title, description, branding
|
||||
title, description := "Workflow", ""
|
||||
var brandingJSON string
|
||||
wf, _ := e.stores.Workflows.GetByID(ctx, inst.WorkflowID)
|
||||
if wf != nil {
|
||||
title = wf.Name
|
||||
description = wf.Description
|
||||
if len(wf.Branding) > 0 {
|
||||
brandingJSON = string(wf.Branding)
|
||||
}
|
||||
}
|
||||
|
||||
// Load stages to resolve current stage info
|
||||
var stageMode, stageName, formTplJSON, surfacePkgID string
|
||||
var totalStages, currentStage int
|
||||
stageMode = "form" // default
|
||||
|
||||
stages, _ := e.stores.Workflows.ListStages(ctx, inst.WorkflowID)
|
||||
totalStages = len(stages)
|
||||
for i, s := range stages {
|
||||
if s.ID == inst.CurrentStage || s.Name == inst.CurrentStage {
|
||||
currentStage = i
|
||||
stageName = s.Name
|
||||
stageMode = s.StageMode
|
||||
if stageMode == "" {
|
||||
stageMode = "form"
|
||||
}
|
||||
if len(s.FormTemplate) > 0 && string(s.FormTemplate) != "null" {
|
||||
formTplJSON = string(s.FormTemplate)
|
||||
}
|
||||
if s.SurfacePkgID != nil {
|
||||
surfacePkgID = *s.SurfacePkgID
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve the actual entry token from the instance (used by JS API calls)
|
||||
entryToken := ""
|
||||
if inst.EntryToken != nil {
|
||||
entryToken = *inst.EntryToken
|
||||
}
|
||||
|
||||
e.Render(c, "workflow.html", PageData{
|
||||
Surface: "workflow",
|
||||
InstanceName: instanceName,
|
||||
Data: WorkflowPageData{
|
||||
ChannelID: channelID,
|
||||
ChannelTitle: title,
|
||||
ChannelDescription: description,
|
||||
SessionID: sessionID,
|
||||
SessionName: sessionName,
|
||||
StageMode: stageMode,
|
||||
StageName: stageName,
|
||||
FormTemplateJSON: formTplJSON,
|
||||
TotalStages: totalStages,
|
||||
CurrentStage: currentStage,
|
||||
SurfacePkgID: surfacePkgID,
|
||||
BrandingJSON: brandingJSON,
|
||||
EntryToken: entryToken,
|
||||
WorkflowTitle: title,
|
||||
WorkflowDescription: description,
|
||||
SessionID: sessionID,
|
||||
SessionName: sessionName,
|
||||
StageMode: stageMode,
|
||||
StageName: stageName,
|
||||
FormTemplateJSON: formTplJSON,
|
||||
TotalStages: totalStages,
|
||||
CurrentStage: currentStage,
|
||||
SurfacePkgID: surfacePkgID,
|
||||
BrandingJSON: brandingJSON,
|
||||
InstanceID: inst.ID,
|
||||
Status: inst.Status,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user