github.com/GoogleCloudPlatform/deploystack@v1.12.8/tui/page.go (about)

     1  // Copyright 2023 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package tui
    16  
    17  import (
    18  	"os"
    19  	"strings"
    20  
    21  	"github.com/charmbracelet/bubbles/spinner"
    22  	tea "github.com/charmbracelet/bubbletea"
    23  )
    24  
    25  type dynamicPage struct {
    26  	queue            *Queue
    27  	spinner          spinner.Model
    28  	spinnerLabel     string
    29  	key              string
    30  	value            string
    31  	err              error
    32  	state            string
    33  	content          []component
    34  	preProcessor     tea.Cmd
    35  	postProcessor    func(string, *Queue) tea.Cmd
    36  	preViewFunc      func(*Queue)
    37  	showProgress     bool
    38  	omitFromSettings bool
    39  	querySlowText    string
    40  }
    41  
    42  func (p *dynamicPage) getKey() string {
    43  	return p.key
    44  }
    45  
    46  func (p *dynamicPage) setValue(s string) {
    47  	p.value = s
    48  }
    49  
    50  func (p *dynamicPage) getValue() string {
    51  	return p.value
    52  }
    53  
    54  func (p *dynamicPage) clear() {
    55  	p.value = ""
    56  }
    57  
    58  func (p *dynamicPage) clearContent() {
    59  	p.content = []component{}
    60  }
    61  
    62  func (p *dynamicPage) addPostProcessor(f func(string, *Queue) tea.Cmd) {
    63  	p.postProcessor = f
    64  }
    65  
    66  func (p *dynamicPage) addPreProcessor(f tea.Cmd) {
    67  	p.preProcessor = f
    68  }
    69  
    70  func (p *dynamicPage) addQueue(q *Queue) {
    71  	p.queue = q
    72  }
    73  
    74  func (p *dynamicPage) addContent(s ...string) {
    75  	for _, v := range s {
    76  		p.content = append(p.content, textBlock(v))
    77  	}
    78  }
    79  
    80  func (p *dynamicPage) addPreView(f func(*Queue)) {
    81  	p.preViewFunc = f
    82  }
    83  
    84  type page struct {
    85  	dynamicPage
    86  }
    87  
    88  func newPage(key string, content []component) page {
    89  	p := page{}
    90  	p.key = key
    91  	p.content = content
    92  	p.showProgress = true
    93  	return p
    94  }
    95  
    96  func (p page) Init() tea.Cmd {
    97  	return p.preProcessor
    98  }
    99  
   100  func (p page) View() string {
   101  	if p.preViewFunc != nil {
   102  		p.preViewFunc(p.queue)
   103  	}
   104  	doc := strings.Builder{}
   105  	doc.WriteString(p.queue.header.render())
   106  	if p.showProgress {
   107  		doc.WriteString(drawProgress(p.queue.calcPercent()))
   108  		doc.WriteString("\n\n")
   109  	}
   110  
   111  	for _, v := range p.content {
   112  		doc.WriteString(bodyStyle.Render(v.render()))
   113  		doc.WriteString("\n")
   114  	}
   115  
   116  	doc.WriteString("\n")
   117  	doc.WriteString(bodyStyle.Render(promptStyle.Render(" Press the Enter Key to continue ")))
   118  
   119  	test := docStyle.Render(doc.String())
   120  
   121  	return test
   122  }
   123  
   124  // TODO: a test for this is pretty straight forward
   125  func (p page) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
   126  	switch msg.(type) {
   127  	case successMsg:
   128  		return p.queue.next()
   129  	case tea.KeyMsg:
   130  		switch msg.(tea.KeyMsg).String() {
   131  
   132  		case "alt+b", "ctrl+b":
   133  			return p.queue.prev()
   134  		case "ctrl+c", "q":
   135  			if p.queue.Get("halted") != nil {
   136  				os.Exit(1)
   137  			}
   138  			return p.queue.exitPage()
   139  		case "enter":
   140  			if p.postProcessor != nil {
   141  				if p.state != "querying" {
   142  					p.state = "querying"
   143  					p.err = nil
   144  					return p, p.postProcessor(p.value, p.queue)
   145  				}
   146  
   147  				return p, nil
   148  			}
   149  
   150  			return p.queue.next()
   151  		}
   152  
   153  	}
   154  	return p, nil
   155  }