Skip to content

Commit

Permalink
Update Interactive mode to render different user interfaces based on …
Browse files Browse the repository at this point in the history
…the environment it's running in (#182)

When running `ie interactive` on azure, Interactive mode will render a
simplified user interface that mimics entering the commands with a
prompt and displaying the output.
  • Loading branch information
vmarcella authored Mar 7, 2024
1 parent efbff20 commit 0aca4d9
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 37 deletions.
17 changes: 16 additions & 1 deletion internal/engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package engine

import (
"fmt"
"strings"

"github.com/Azure/InnovationEngine/internal/az"
"github.com/Azure/InnovationEngine/internal/engine/environments"
Expand Down Expand Up @@ -78,7 +79,21 @@ func (e *Engine) InteractWithScenario(scenario *Scenario) error {
}

program = tea.NewProgram(model, tea.WithAltScreen(), tea.WithMouseCellMotion())
_, err = program.Run()

var finalModel tea.Model
var ok bool
finalModel, err = program.Run()

model, ok = finalModel.(InteractiveModeModel)

if environments.EnvironmentsAzure == e.Configuration.Environment {
if !ok {
return fmt.Errorf("failed to cast tea.Model to InteractiveModeModel")
}

logging.GlobalLogger.Info("Writing session output to stdout")
fmt.Println(strings.Join(model.commandLines, "\n"))
}

switch e.Configuration.Environment {
case environments.EnvironmentsAzure, environments.EnvironmentsOCD:
Expand Down
2 changes: 1 addition & 1 deletion internal/engine/environments/azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func ReportAzureStatus(status AzureDeploymentStatus, environment string) {
} else {
// We add these strings to the output so that the portal can find and parse
// the JSON status.
ocdStatus := fmt.Sprintf("ie_us%sie_ue\n", statusJson)
ocdStatus := fmt.Sprintf("ie_us%sie_ue", statusJson)
fmt.Println(ui.OcdStatusUpdateStyle.Render(ocdStatus))
}
}
Expand Down
84 changes: 50 additions & 34 deletions internal/engine/interactive.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package engine

import (
"fmt"
"strings"
"time"

"github.com/Azure/InnovationEngine/internal/az"
Expand Down Expand Up @@ -41,9 +42,10 @@ type CodeBlockState struct {
}

type interactiveModeComponents struct {
paginator paginator.Model
stepViewport viewport.Model
outputViewport viewport.Model
paginator paginator.Model
stepViewport viewport.Model
outputViewport viewport.Model
azureCLIViewport viewport.Model
}

type InteractiveModeModel struct {
Expand All @@ -62,6 +64,7 @@ type InteractiveModeModel struct {
scenarioCompleted bool
components interactiveModeComponents
ready bool
commandLines []string
}

// Initialize the intractive mode model
Expand Down Expand Up @@ -91,11 +94,13 @@ func initializeComponents(model InteractiveModeModel, width, height int) interac

stepViewport := viewport.New(width, 4)
outputViewport := viewport.New(width, 2)
azureCLIViewport := viewport.New(width, height)

components := interactiveModeComponents{
paginator: p,
stepViewport: stepViewport,
outputViewport: outputViewport,
paginator: p,
stepViewport: stepViewport,
outputViewport: outputViewport,
azureCLIViewport: azureCLIViewport,
}

components.updateViewportHeight(height)
Expand Down Expand Up @@ -207,6 +212,7 @@ func (components *interactiveModeComponents) updateViewportHeight(terminalHeight

components.stepViewport.Height = stepViewportHeight
components.outputViewport.Height = outputViewportHeight
components.azureCLIViewport.Height = terminalHeight - 1
}

// Updates the intractive mode model
Expand All @@ -225,6 +231,7 @@ func (model InteractiveModeModel) Update(message tea.Msg) (tea.Model, tea.Cmd) {
} else {
model.components.stepViewport.Width = message.Width
model.components.outputViewport.Width = message.Width
model.components.azureCLIViewport.Width = message.Width
model.components.updateViewportHeight(message.Height)
}

Expand Down Expand Up @@ -255,10 +262,18 @@ func (model InteractiveModeModel) Update(message tea.Msg) (tea.Model, tea.Cmd) {
model.resourceGroupName = tmpResourceGroup
}
}
model.commandLines = append(model.commandLines, codeBlockState.StdOut)

// Increment the codeblock and update the viewport content.
model.currentCodeBlock++

if model.currentCodeBlock < len(model.codeBlockState) {
nextCommand := model.codeBlockState[model.currentCodeBlock].CodeBlock.Content
nextLanguage := model.codeBlockState[model.currentCodeBlock].CodeBlock.Language

model.commandLines = append(model.commandLines, ui.CommandPrompt(nextLanguage)+nextCommand)
}

// Only increment the step for azure if the step name has changed.
nextCodeBlockState := model.codeBlockState[model.currentCodeBlock]

Expand Down Expand Up @@ -301,6 +316,7 @@ func (model InteractiveModeModel) Update(message tea.Msg) (tea.Model, tea.Cmd) {
codeBlockState.Success = false

model.codeBlockState[step] = codeBlockState
model.commandLines = append(model.commandLines, codeBlockState.StdErr)

// Report the error
model.executingCommand = false
Expand Down Expand Up @@ -381,6 +397,8 @@ func (model InteractiveModeModel) Update(message tea.Msg) (tea.Model, tea.Cmd) {
model.components.outputViewport.SetContent(block.StdErr)
}

model.components.azureCLIViewport.SetContent(strings.Join(model.commandLines, "\n"))

// Update all the viewports and append resulting commands.
var command tea.Cmd

Expand All @@ -392,6 +410,9 @@ func (model InteractiveModeModel) Update(message tea.Msg) (tea.Model, tea.Cmd) {
model.components.outputViewport, command = model.components.outputViewport.Update(message)
commands = append(commands, command)

model.components.azureCLIViewport, command = model.components.azureCLIViewport.Update(message)
commands = append(commands, command)

return model, tea.Batch(commands...)
}

Expand Down Expand Up @@ -419,44 +440,33 @@ func (model InteractiveModeModel) helpView() string {

// Renders the interactive mode model.
func (model InteractiveModeModel) View() string {
// When running in the portal, we only want to show the Azure CLI viewport
// which mimics a command line interface during execution.
if model.environment == "azure" {
return model.components.azureCLIViewport.View()
}

scenarioTitle := ui.ScenarioTitleStyle.Width(model.width).
Align(lipgloss.Center).
Render(model.scenarioTitle)
var stepTitle string
var stepView string
var stepSection string
stepTitle = ui.StepTitleStyle.Render(

border := lipgloss.NewStyle().
Width(model.components.stepViewport.Width - 2).
Border(lipgloss.NormalBorder())

stepTitle := ui.StepTitleStyle.Render(
fmt.Sprintf(
"Step %d - %s",
model.currentCodeBlock+1,
model.codeBlockState[model.currentCodeBlock].StepName,
),
)
stepView := border.Render(model.components.stepViewport.View())
stepSection := fmt.Sprintf("%s\n%s\n\n", stepTitle, stepView)

border := lipgloss.NewStyle().
Width(model.components.stepViewport.Width - 2)
// Border(lipgloss.NormalBorder())

stepView = border.Render(model.components.stepViewport.View())

if model.environment != "azure" {
stepSection = fmt.Sprintf("%s\n%s\n\n", stepTitle, stepView)
} else {
stepSection = fmt.Sprintf("%s\n%s\n", stepTitle, stepView)
}

var outputTitle string
var outputView string
var outputSection string
if model.environment != "azure" {
outputTitle = ui.StepTitleStyle.Render("Output")
outputView = border.Render(model.components.outputViewport.View())
outputSection = fmt.Sprintf("%s\n%s\n\n", outputTitle, outputView)
} else {
outputTitle = ""
outputView = ""
outputSection = ""
}
outputTitle := ui.StepTitleStyle.Render("Output")
outputView := border.Render(model.components.outputViewport.View())
outputSection := fmt.Sprintf("%s\n%s\n\n", outputTitle, outputView)

paginator := lipgloss.NewStyle().
Width(model.width).
Expand Down Expand Up @@ -532,6 +542,11 @@ func NewInteractiveModeModel(
azureStatus.AddStep(fmt.Sprintf("%d. %s", stepNumber+1, step.Name), azureCodeBlocks)
}

language := codeBlockState[0].CodeBlock.Language
commandLines := []string{
ui.CommandPrompt(language) + codeBlockState[0].CodeBlock.Content,
}

return InteractiveModeModel{
scenarioTitle: title,
commands: InteractiveModeCommands{
Expand Down Expand Up @@ -562,5 +577,6 @@ func NewInteractiveModeModel(
environment: engine.Configuration.Environment,
scenarioCompleted: false,
ready: false,
commandLines: commandLines,
}, nil
}
11 changes: 10 additions & 1 deletion internal/ui/text.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,18 @@ var (
b.Left = "┤"
return InteractiveModeStepTitleStyle.Copy().BorderStyle(b)
}().Foreground(lipgloss.Color("#fff"))

promptTextStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#6CB6FF"))
promptDollarStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#32CD32"))
)

// Command prompt for interactive environments
func CommandPrompt(language string) string {
promptText := promptTextStyle.Render(language)
promptDollar := promptDollarStyle.Render("$")
return promptText + ":" + promptDollar + " "
}

// Indents a multi-line command to be nested under the first line of the
// command.
func IndentMultiLineCommand(content string, indentation int) string {
Expand All @@ -56,7 +66,6 @@ func IndentMultiLineCommand(content string, indentation int) string {
} else if strings.TrimSpace(lines[i]) != "" {
lines[i] = strings.Repeat(" ", indentation) + lines[i]
}

}
return strings.Join(lines, "\n")
}
Expand Down

0 comments on commit 0aca4d9

Please sign in to comment.