Skip to content

Commit 8674095

Browse files
committed
working towards new atom interface
1 parent 64bd41f commit 8674095

8 files changed

Lines changed: 112 additions & 95 deletions

File tree

tsunami/app/defaultclient.go

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"io/fs"
99
"net/http"
1010

11-
"github.com/wavetermdev/waveterm/tsunami/util"
1211
"github.com/wavetermdev/waveterm/tsunami/vdom"
1312
)
1413

@@ -42,31 +41,31 @@ func SendAsyncInitiation() error {
4241
return defaultClient.SendAsyncInitiation()
4342
}
4443

45-
func GetSharedAtom[T any](name string) T {
46-
rawVal := defaultClient.GetAtomVal("$shared." + name)
47-
return util.GetTypedAtomValue[T](rawVal, "$shared."+name)
44+
func ConfigAtom[T any](name string, defaultValue T) Atom[T] {
45+
fullName := "$config." + name
46+
// Set the default value if not already set
47+
if defaultClient.GetAtomVal(fullName) == nil {
48+
defaultClient.SetAtomVal(fullName, defaultValue)
49+
}
50+
return Atom[T]{name: fullName, client: defaultClient}
4851
}
4952

50-
func SetSharedAtom[T any](name string, val T) {
51-
defaultClient.SetAtomVal("$shared."+name, val)
53+
func DataAtom[T any](name string, defaultValue T) Atom[T] {
54+
fullName := "$data." + name
55+
// Set the default value if not already set
56+
if defaultClient.GetAtomVal(fullName) == nil {
57+
defaultClient.SetAtomVal(fullName, defaultValue)
58+
}
59+
return Atom[T]{name: fullName, client: defaultClient}
5260
}
5361

54-
func GetConfig[T any](name string) T {
55-
rawVal := defaultClient.GetAtomVal("$config." + name)
56-
return util.GetTypedAtomValue[T](rawVal, "$config."+name)
57-
}
58-
59-
func SetConfig[T any](name string, val T) {
60-
defaultClient.SetAtomVal("$config."+name, val)
61-
}
62-
63-
func GetData[T any](name string) T {
64-
rawVal := defaultClient.GetAtomVal("$data." + name)
65-
return util.GetTypedAtomValue[T](rawVal, "$data."+name)
66-
}
67-
68-
func SetData[T any](name string, val T) {
69-
defaultClient.SetAtomVal("$data."+name, val)
62+
func SharedAtom[T any](name string, defaultValue T) Atom[T] {
63+
fullName := "$shared." + name
64+
// Set the default value if not already set
65+
if defaultClient.GetAtomVal(fullName) == nil {
66+
defaultClient.SetAtomVal(fullName, defaultValue)
67+
}
68+
return Atom[T]{name: fullName, client: defaultClient}
7069
}
7170

7271
// HandleDynFunc registers a dynamic HTTP handler function with the internal http.ServeMux.

tsunami/app/tsunamiapp.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,3 +306,27 @@ func (c *clientImpl) HandleDynFunc(pattern string, fn func(http.ResponseWriter,
306306
}
307307
c.UrlHandlerMux.HandleFunc(pattern, fn)
308308
}
309+
310+
// Atom[T] represents a typed atom implementation
311+
type Atom[T any] struct {
312+
name string
313+
client *clientImpl
314+
}
315+
316+
// AtomName implements the vdom.Atom interface
317+
func (a Atom[T]) AtomName() string {
318+
return a.name
319+
}
320+
321+
// Get returns the current value of the atom
322+
func (a Atom[T]) Get() T {
323+
val := a.client.GetAtomVal(a.name)
324+
return util.GetTypedAtomValue[T](val, a.name)
325+
}
326+
327+
// Set updates the atom's value
328+
func (a Atom[T]) Set(newVal T) {
329+
a.client.SetAtomVal(a.name, newVal)
330+
}
331+
332+

tsunami/demo/cpuchart/app.go

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,23 @@ import (
1010
"github.com/wavetermdev/waveterm/tsunami/vdom"
1111
)
1212

13-
// Use func init() to set atom defaults
14-
func init() {
15-
// Set default configuration
16-
app.SetConfig("dataPointCount", 60)
17-
18-
// Initialize with empty data points to maintain consistent chart size
19-
dataPointCount := 60 // Default value for initialization
20-
initialData := make([]CPUDataPoint, dataPointCount)
21-
for i := range initialData {
22-
initialData[i] = CPUDataPoint{
23-
Time: 0,
24-
CPUUsage: nil, // Use nil to represent empty slots
25-
Timestamp: "",
13+
// Global atoms for config and data
14+
var (
15+
dataPointCountAtom = app.ConfigAtom("dataPointCount", 60)
16+
cpuDataAtom = app.DataAtom("cpuData", func() []CPUDataPoint {
17+
// Initialize with empty data points to maintain consistent chart size
18+
dataPointCount := 60 // Default value for initialization
19+
initialData := make([]CPUDataPoint, dataPointCount)
20+
for i := range initialData {
21+
initialData[i] = CPUDataPoint{
22+
Time: 0,
23+
CPUUsage: nil, // Use nil to represent empty slots
24+
Timestamp: "",
25+
}
2626
}
27-
}
28-
app.SetData("cpuData", initialData)
29-
}
27+
return initialData
28+
}())
29+
)
3030

3131
type CPUDataPoint struct {
3232
Time int64 `json:"time"` // Unix timestamp in seconds
@@ -145,9 +145,9 @@ var App = app.DefineComponent("App",
145145
func(ctx context.Context, _ struct{}) any {
146146
vdom.UseSetAppTitle(ctx, "CPU Usage Monitor")
147147

148-
// Global state
149-
cpuData, setCpuData, setCpuDataFn := vdom.UseData[[]CPUDataPoint](ctx, "cpuData")
150-
dataPointCount, _, _ := vdom.UseConfig[int](ctx, "dataPointCount")
148+
// Global state using atoms
149+
cpuData, setCpuData, setCpuDataFn := vdom.UseAtom[[]CPUDataPoint](ctx, cpuDataAtom)
150+
dataPointCount, _, _ := vdom.UseAtom[int](ctx, dataPointCountAtom)
151151

152152
// Local state for forcing re-renders
153153
_, _, setTickerFn := vdom.UseState[int](ctx, 0)
@@ -167,7 +167,7 @@ var App = app.DefineComponent("App",
167167
setCpuDataFn(func(currentData []CPUDataPoint) []CPUDataPoint {
168168
newPoint := generateCPUDataPoint()
169169
// Read current config inside the loop to get live updates
170-
currentDataPointCount := app.GetConfig[int]("dataPointCount")
170+
currentDataPointCount := dataPointCountAtom.Get()
171171

172172
// Ensure we have the right size array
173173
if len(currentData) != currentDataPointCount {
@@ -208,7 +208,7 @@ var App = app.DefineComponent("App",
208208

209209
handleClear := func() {
210210
// Reset with empty data points based on current config
211-
currentDataPointCount := app.GetConfig[int]("dataPointCount")
211+
currentDataPointCount := dataPointCountAtom.Get()
212212
initialData := make([]CPUDataPoint, currentDataPointCount)
213213
for i := range initialData {
214214
initialData[i] = CPUDataPoint{

tsunami/demo/githubaction/app.go

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,17 @@ import (
1616
"github.com/wavetermdev/waveterm/tsunami/vdom"
1717
)
1818

19-
func init() {
20-
app.SetConfig("pollInterval", 5)
21-
app.SetConfig("repository", "wavetermdev/waveterm")
22-
app.SetConfig("workflow", "build-helper.yml")
23-
app.SetConfig("maxWorkflowRuns", 10)
24-
app.SetData("workflowRuns", []WorkflowRun{})
25-
app.SetData("lastError", "")
26-
app.SetData("isLoading", true)
27-
app.SetData("lastRefreshTime", time.Time{})
28-
}
19+
// Global atoms for config and data
20+
var (
21+
pollIntervalAtom = app.ConfigAtom("pollInterval", 5)
22+
repositoryAtom = app.ConfigAtom("repository", "wavetermdev/waveterm")
23+
workflowAtom = app.ConfigAtom("workflow", "build-helper.yml")
24+
maxWorkflowRunsAtom = app.ConfigAtom("maxWorkflowRuns", 10)
25+
workflowRunsAtom = app.DataAtom("workflowRuns", []WorkflowRun{})
26+
lastErrorAtom = app.DataAtom("lastError", "")
27+
isLoadingAtom = app.DataAtom("isLoading", true)
28+
lastRefreshTimeAtom = app.DataAtom("lastRefreshTime", time.Time{})
29+
)
2930

3031
type WorkflowRun struct {
3132
ID int64 `json:"id"`
@@ -223,14 +224,14 @@ var App = app.DefineComponent("App",
223224
func(ctx context.Context, _ struct{}) any {
224225
vdom.UseSetAppTitle(ctx, "GitHub Actions Monitor")
225226

226-
workflowRuns, setWorkflowRuns, _ := vdom.UseData[[]WorkflowRun](ctx, "workflowRuns")
227-
lastError, setLastError, _ := vdom.UseData[string](ctx, "lastError")
228-
isLoading, setIsLoading, _ := vdom.UseData[bool](ctx, "isLoading")
229-
lastRefreshTime, setLastRefreshTime, _ := vdom.UseData[time.Time](ctx, "lastRefreshTime")
230-
pollInterval, _, _ := vdom.UseConfig[int](ctx, "pollInterval")
231-
repository, _, _ := vdom.UseConfig[string](ctx, "repository")
232-
workflow, _, _ := vdom.UseConfig[string](ctx, "workflow")
233-
maxWorkflowRuns, _, _ := vdom.UseConfig[int](ctx, "maxWorkflowRuns")
227+
workflowRuns, setWorkflowRuns, _ := vdom.UseAtom[[]WorkflowRun](ctx, workflowRunsAtom)
228+
lastError, setLastError, _ := vdom.UseAtom[string](ctx, lastErrorAtom)
229+
isLoading, setIsLoading, _ := vdom.UseAtom[bool](ctx, isLoadingAtom)
230+
lastRefreshTime, setLastRefreshTime, _ := vdom.UseAtom[time.Time](ctx, lastRefreshTimeAtom)
231+
pollInterval, _, _ := vdom.UseAtom[int](ctx, pollIntervalAtom)
232+
repository, _, _ := vdom.UseAtom[string](ctx, repositoryAtom)
233+
workflow, _, _ := vdom.UseAtom[string](ctx, workflowAtom)
234+
maxWorkflowRuns, _, _ := vdom.UseAtom[int](ctx, maxWorkflowRunsAtom)
234235

235236
_, _, setTickerFn := vdom.UseState[int](ctx, 0)
236237

@@ -239,7 +240,7 @@ var App = app.DefineComponent("App",
239240
done := make(chan bool)
240241

241242
fetchData := func() {
242-
currentMaxRuns := app.GetConfig[int]("maxWorkflowRuns")
243+
currentMaxRuns := maxWorkflowRunsAtom.Get()
243244
runs, err := fetchWorkflowRuns(repository, workflow, currentMaxRuns)
244245
if err != nil {
245246
log.Printf("Error fetching workflow runs: %v", err)
@@ -279,7 +280,7 @@ var App = app.DefineComponent("App",
279280
handleRefresh := func() {
280281
setIsLoading(true)
281282
go func() {
282-
currentMaxRuns := app.GetConfig[int]("maxWorkflowRuns")
283+
currentMaxRuns := maxWorkflowRunsAtom.Get()
283284
runs, err := fetchWorkflowRuns(repository, workflow, currentMaxRuns)
284285
if err != nil {
285286
log.Printf("Error fetching workflow runs: %v", err)

tsunami/demo/recharts/app.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ import (
99
"github.com/wavetermdev/waveterm/tsunami/vdom"
1010
)
1111

12-
// Use func init() to set atom defaults
13-
func init() {
14-
app.SetData("chartData", generateInitialData())
15-
app.SetConfig("chartType", "line")
16-
app.SetSharedAtom("isAnimating", false)
17-
}
12+
// Global atoms for config and data
13+
var (
14+
chartDataAtom = app.DataAtom("chartData", generateInitialData())
15+
chartTypeAtom = app.ConfigAtom("chartType", "line")
16+
isAnimatingAtom = app.SharedAtom("isAnimating", false)
17+
)
1818

1919
type DataPoint struct {
2020
Time int `json:"time"`
@@ -206,10 +206,10 @@ var App = app.DefineComponent("App",
206206
func(ctx context.Context, _ struct{}) any {
207207
vdom.UseSetAppTitle(ctx, "Recharts Demo")
208208

209-
// Global state
210-
chartData, setChartData, setChartDataFn := vdom.UseData[[]DataPoint](ctx, "chartData")
211-
chartType, setChartType, _ := vdom.UseConfig[string](ctx, "chartType")
212-
isAnimating, setIsAnimating, _ := vdom.UseSharedAtom[bool](ctx, "isAnimating")
209+
// Global state using atoms
210+
chartData, setChartData, setChartDataFn := vdom.UseAtom[[]DataPoint](ctx, chartDataAtom)
211+
chartType, setChartType, _ := vdom.UseAtom[string](ctx, chartTypeAtom)
212+
isAnimating, setIsAnimating, _ := vdom.UseAtom[bool](ctx, isAnimatingAtom)
213213

214214
// Local state for timer
215215
_, _, setTickerFn := vdom.UseState[int](ctx, 0)

tsunami/demo/tsunamiconfig/app.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ import (
1515
"github.com/wavetermdev/waveterm/tsunami/vdom"
1616
)
1717

18+
// Global atoms for config
19+
var (
20+
serverURLAtom = app.ConfigAtom("serverURL", "")
21+
)
22+
1823
type URLInputProps struct {
1924
Value string `json:"value"`
2025
OnChange func(string) `json:"onChange"`
@@ -253,7 +258,7 @@ var App = app.DefineComponent("App",
253258
vdom.UseSetAppTitle(ctx, "Tsunami Config Manager")
254259

255260
// Use UseConfig for the URL input so it persists
256-
urlInput, setURLInput, _ := vdom.UseConfig[string](ctx, "serverURL")
261+
urlInput, setURLInput, _ := vdom.UseAtom[string](ctx, serverURLAtom)
257262
jsonContent, setJSONContent, _ := vdom.UseState(ctx, "")
258263
errorMessage, setErrorMessage, _ := vdom.UseState(ctx, "")
259264
successMessage, setSuccessMessage, _ := vdom.UseState(ctx, "")

tsunami/vdom/vdom.go

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,6 @@ func UseState[T any](ctx context.Context, initialVal T) (T, func(T), func(func(T
182182
return rtnVal, typedSetVal, typedSetFuncVal
183183
}
184184

185-
186185
func useAtom[T any](ctx context.Context, hookName string, atomName string) (T, func(T), func(func(T) T)) {
187186
rc := vdomctx.GetRenderContext(ctx)
188187
if rc == nil {
@@ -207,28 +206,12 @@ func useAtom[T any](ctx context.Context, hookName string, atomName string) (T, f
207206
return atomVal, typedSetVal, typedSetFuncVal
208207
}
209208

210-
// UseSharedAtom provides access to a shared atom state across components.
209+
// UseAtom provides access to atom values using an Atom interface.
211210
// It returns the current atom value, a setter function, and an updater function.
212-
// Setting a new value causes a re-render of any component using this atom.
213-
// This hook must be called within a component context.
214-
func UseSharedAtom[T any](ctx context.Context, atomName string) (T, func(T), func(func(T) T)) {
215-
return useAtom[T](ctx, "UseSharedAtom", "$shared."+atomName)
216-
}
217-
218-
// UseConfig provides access to config values (atom names are global across the app).
219-
// It returns the current config value, a setter function, and an updater function.
220-
// Setting a new value causes a re-render of all components using this config atom.
221-
// This hook must be called within a component context.
222-
func UseConfig[T any](ctx context.Context, atomName string) (T, func(T), func(func(T) T)) {
223-
return useAtom[T](ctx, "UseConfig", "$config."+atomName)
224-
}
225-
226-
// UseData provides access to data values (atom names are global across the app).
227-
// It returns the current data value, a setter function, and an updater function.
228-
// Setting a new value causes a re-render of all components using this data atom.
211+
// Setting a new value causes a re-render of all components using this atom.
229212
// This hook must be called within a component context.
230-
func UseData[T any](ctx context.Context, atomName string) (T, func(T), func(func(T) T)) {
231-
return useAtom[T](ctx, "UseData", "$data."+atomName)
213+
func UseAtom[T any](ctx context.Context, atom Atom) (T, func(T), func(func(T) T)) {
214+
return useAtom[T](ctx, "UseAtom", atom.AtomName())
232215
}
233216

234217
// UseVDomRef provides a reference to a DOM element in the VDOM tree.

tsunami/vdom/vdom_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,8 @@ type VDomRefOperation struct {
126126
Params []any `json:"params,omitempty"`
127127
OutputRef string `json:"outputref,omitempty"`
128128
}
129+
130+
// Atom interface for atom implementations
131+
type Atom interface {
132+
AtomName() string
133+
}

0 commit comments

Comments
 (0)