browsermain

package
v0.0.0-...-fd1ce1a Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 30, 2023 License: Apache-2.0 Imports: 28 Imported by: 0

README

This package is the entry point to Tempest's browser UI. This document describes the high-level architecture.

The architecture is heavily inspired by Elm. In particular:

  • There is a central Model type that defines the state of the application.
  • There is a Model.View() method which returns an HTML rendering of the app based on the state, using go-vdom.
  • message.go defines message types that represent various events the UI state should respond to. Each message type has an ApplyTo() method that transforms the model. These messages are sent on a channel from within event handlers, and there is a loop that continuously receives from the channel, applies the message, and re-renders the UI. ApplyTo() must never block, as this could causes the UI to hang. It should always just update the model as it needs and spawn a goroutine for any side effects.

We use Cap'n Proto rpc over a websocket to communicate with the server.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Main

func Main()

Types

type ClearGrains

type ClearGrains struct{}

func (ClearGrains) Update

func (ClearGrains) Update(m *Model) Cmd

type ClearPackages

type ClearPackages struct{}

func (ClearPackages) Update

func (ClearPackages) Update(m *Model) Cmd

type CloseGrain

type CloseGrain struct {
	ID types.GrainID
}

func (CloseGrain) Update

func (msg CloseGrain) Update(m *Model) Cmd

type Cmd

type Cmd = func(context.Context, func(Msg))

type EditEmailLogin

type EditEmailLogin struct {
	NewValue string
}

func (EditEmailLogin) Update

func (msg EditEmailLogin) Update(m *Model) Cmd

type EditEmailToken

type EditEmailToken struct {
	NewValue string
}

func (EditEmailToken) Update

func (msg EditEmailToken) Update(m *Model) Cmd

type Focus

type Focus int
const (
	FocusGrainList Focus = iota
	FocusApps
	FocusOpenGrain
	FocusShareGrain
	FocusLoadShared

	InitialFocus = FocusGrainList
)

func (Focus) HasGrain

func (f Focus) HasGrain() bool

HasGrain returns whether or not the focus should display the current grain's iframe.

type Grain

type Grain struct {
	Title        string
	SessionToken string
	Subdomain    string
	Controller   external.UiView_Controller
}

type HaveSharingToken

type HaveSharingToken struct {
	GrainID types.GrainID
	Token   string
}

func (HaveSharingToken) Update

func (msg HaveSharingToken) Update(m *Model) Cmd

type LoginForm

type LoginForm struct {
	TokenSent  bool   // Whether we've already sent a token:
	EmailInput string // The email the user has entered
	TokenInput string // The token the user has entered
}

Model for the email login form

func (LoginForm) View

func (lf LoginForm) View(l10n intl.L10N, ms tea.MessageSender[Model]) vdom.VNode

type LoginSessionResult

type LoginSessionResult struct {
	Result orerr.OrErr[Sessions]
}

func (LoginSessionResult) Update

func (msg LoginSessionResult) Update(m *Model) Cmd

type Model

type Model struct {
	L10N intl.L10N

	ServerAddr   ServerAddr
	CurrentFocus Focus
	FocusedGrain types.GrainID // ID for the currently focused grain

	// Errors to display to the user. As the UI evolves, we will
	// probably want more out of this, but YAGNI.
	Errors []error

	Grains     map[types.GrainID]Grain
	OpenGrains map[types.GrainID]OpenGrain
	Packages   map[types.ID[external.Package]]external.Package

	// Keeps track of the order we need to display grain iframes in.
	// Grain iframes must never change order or be detached from the
	// DOM, or they will reload the page within them, losing state.
	// So we keep them in a stable order, rendering empty slots
	// as dummyNode, and hiding everything but the active grain
	// with CSS (display: none).
	GrainDomOrder poolslice.PoolSlice[types.GrainID]

	API           external.ExternalApi
	LoginSessions maybe.Maybe[orerr.OrErr[Sessions]]

	LoginForm LoginForm
}

func (*Model) FocusGrain

func (m *Model) FocusGrain(grainID types.GrainID)

func (Model) View

func (m Model) View(ms tea.MessageSender[Model]) vdom.VNode

type Msg

type Msg = tea.Message[Model]
type Navigate struct {
	// Path & fragment parts of the new URL:
	Path, Fragment string
}

The URL has changed. We never send this one explicitly from UI code; instead we set up an event listener for the "hashchange" event in our main function. All of our URLs start with #, so this covers everything.

func (msg Navigate) Update(m *Model) Cmd

type NewAppPkgFile

type NewAppPkgFile struct {
	Name   string
	Size   int
	Reader streams.ReadableStreamDefaultReader
}

The user has selected an spk file to upload & install

func (NewAppPkgFile) Update

func (msg NewAppPkgFile) Update(m *Model) Cmd

type NewError

type NewError struct {
	Err error
}

func (NewError) Update

func (msg NewError) Update(m *Model) Cmd

type OpenGrain

type OpenGrain struct {
	DomIndex     int
	SharingToken string
}

type RemoveGrain

type RemoveGrain struct {
	ID types.GrainID
}

func (RemoveGrain) Update

func (msg RemoveGrain) Update(m *Model) Cmd

type RemovePackage

type RemovePackage struct {
	ID types.ID[external.Package]
}

func (RemovePackage) Update

func (msg RemovePackage) Update(m *Model) Cmd

type ServerAddr

type ServerAddr struct {
	Host string
	TLS  bool
}

func (ServerAddr) Root

func (sa ServerAddr) Root() url.URL

func (ServerAddr) Subdomain

func (sa ServerAddr) Subdomain(s string) url.URL

type Sessions

type Sessions struct {
	Visitor external.VisitorSession
	User    external.UserSession
}

type ShareGrain

type ShareGrain struct {
	ID types.GrainID
}

func (ShareGrain) Update

func (msg ShareGrain) Update(m *Model) Cmd

type SpawnGrain

type SpawnGrain struct {
	Index int
	PkgID types.ID[external.Package]
}

func (SpawnGrain) Update

func (msg SpawnGrain) Update(m *Model) Cmd

type SubmitEmailLogin

type SubmitEmailLogin struct {
}

func (SubmitEmailLogin) Update

func (msg SubmitEmailLogin) Update(m *Model) Cmd

type SubmitEmailToken

type SubmitEmailToken struct {
}

func (SubmitEmailToken) Update

func (msg SubmitEmailToken) Update(m *Model) Cmd

type UpsertGrain

type UpsertGrain struct {
	ID    types.GrainID
	Grain Grain
}

func (UpsertGrain) Update

func (msg UpsertGrain) Update(m *Model) Cmd

type UpsertPackage

type UpsertPackage struct {
	ID  types.ID[external.Package]
	Pkg external.Package
}

func (UpsertPackage) Update

func (msg UpsertPackage) Update(m *Model) Cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL