-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Evaluation Results Data Explorer (#96)
Using a Google Sheet To View the evaluation results isn't working too well. So we create our own viewer to display the results. Create a connect-rpc service for listing the evaluation results * This is the first step to building a viewer for the evaluation results; we need a service to allow the client app to read the results. * We decided to go with [connect-rpc](https://connectrpc.com/docs/go/getting-started) because this should simplify things by eliminating the need to use grpc and gprc gateway in order to have a service that we can connect to from the browser * Furthermore, hopefully we can use the connect-rpc generated clients even when using WASM * Fix the go_package option in most of the proto files. We seem to be missing a directory "foyle" in the path. This doesn't appear to matter until we start using connect-rpc and then the imports are broken unless we fix the package Refactor our existing go-app to better support multiple pages. Each page might render the right hand side differently. * Add a status bar to display the GOAPP_VERSION; this makes it easier to ensure we have picked up any changes. The app is pretty ugly. I will try to fix the styling in a subsequent PR.
- Loading branch information
Showing
29 changed files
with
1,417 additions
and
124 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package eval | ||
|
||
import ( | ||
"context" | ||
|
||
"connectrpc.com/connect" | ||
"github.com/cockroachdb/pebble" | ||
"github.com/jlewi/foyle/app/pkg/logs" | ||
"github.com/jlewi/foyle/protos/go/foyle/v1alpha1" | ||
"github.com/jlewi/monogo/helpers" | ||
"github.com/pkg/errors" | ||
"google.golang.org/protobuf/proto" | ||
) | ||
|
||
// EvalServer is the server that implements the Eval service interface. | ||
// This is used to make results available to the frontend. | ||
type EvalServer struct{} | ||
|
||
func (s *EvalServer) List( | ||
ctx context.Context, | ||
req *connect.Request[v1alpha1.EvalResultListRequest], | ||
) (*connect.Response[v1alpha1.EvalResultListResponse], error) { | ||
log := logs.FromContext(ctx) | ||
|
||
if req.Msg.GetDatabase() == "" { | ||
err := connect.NewError(connect.CodeInvalidArgument, errors.New("Request is missing database")) | ||
log.Error(err, "Invalid EvalResultListRequest") | ||
return nil, err | ||
} | ||
|
||
db, err := pebble.Open(req.Msg.GetDatabase(), &pebble.Options{}) | ||
if err != nil { | ||
log.Error(err, "Failed to open database") | ||
return nil, connect.NewError(connect.CodeInternal, err) | ||
} | ||
defer helpers.DeferIgnoreError(db.Close) | ||
|
||
iter, err := db.NewIterWithContext(ctx, nil) | ||
if err != nil { | ||
return nil, connect.NewError(connect.CodeInternal, err) | ||
} | ||
defer iter.Close() | ||
|
||
results := &v1alpha1.EvalResultListResponse{ | ||
Items: make([]*v1alpha1.EvalResult, 0, 100), | ||
} | ||
|
||
for iter.First(); iter.Valid(); iter.Next() { | ||
key := iter.Key() | ||
if key == nil { | ||
break | ||
} | ||
|
||
value, err := iter.ValueAndErr() | ||
if err != nil { | ||
log.Error(err, "Failed to read value for key", "key", string(key)) | ||
continue | ||
} | ||
|
||
result := &v1alpha1.EvalResult{} | ||
if err := proto.Unmarshal(value, result); err != nil { | ||
log.Error(err, "Failed to unmarshal value for", "key", string(key)) | ||
continue | ||
} | ||
results.Items = append(results.Items, result) | ||
} | ||
|
||
res := connect.NewResponse(results) | ||
res.Header().Set("Eval-Version", "v1alpha1") | ||
return res, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package logsviewer | ||
|
||
import ( | ||
"github.com/go-logr/zapr" | ||
"github.com/maxence-charriere/go-app/v9/pkg/app" | ||
"github.com/pkg/errors" | ||
"go.uber.org/zap" | ||
) | ||
|
||
type page string | ||
type view string | ||
|
||
const ( | ||
getAction = "/get" | ||
setPage = "/setPage" | ||
|
||
errorView view = "error" | ||
generatedBlockView view = "generatedBlock" | ||
executedBlockView view = "executedBlock" | ||
rawView view = "raw" | ||
|
||
blockLogsView page = "blockLogs" | ||
evalsView page = "evals" | ||
|
||
getErrorState = "/getError" | ||
blockLogState = "/blocklog" | ||
) | ||
|
||
// MainApp is the main window of the application. | ||
// | ||
// The main application consists of a left hand navigation bar and a right hand side component that is the page | ||
// to display. When you click on one of the left hand navigation buttons it fires of an action setPage to change the | ||
// view. The handler for this action loads the appropriate page and sets MainApp.page to the component for that | ||
// page. | ||
type MainApp struct { | ||
app.Compo | ||
// Page keeps track of the page to display in the right hand side. | ||
page app.UI | ||
} | ||
|
||
func (m *MainApp) Render() app.UI { | ||
if m.page == nil { | ||
// TODO(jeremy): Could we keep track of the last view so if we refresh we show the same data? | ||
// One way to do that is to update the URL with query arguments containing the relevant state information. | ||
// Then when we click refresh we could get the information directly from the URL | ||
m.page = &BlockViewer{} | ||
} | ||
return app.Div().Class("main-layout").Body( | ||
app.Div().Class("content").Body( | ||
app.Div().Class("sidebar").Body( | ||
&navigationBar{}, | ||
), | ||
app.Div().Class("page-window").Body( | ||
m.page, | ||
), | ||
), &StatusBar{}, | ||
) | ||
} | ||
|
||
func (m *MainApp) OnMount(ctx app.Context) { | ||
// register to handle the setPage action | ||
ctx.Handle(setPage, m.handleSetPage) | ||
} | ||
|
||
// handleSetPage handles the setPage action. The event will tell us which view to display. | ||
func (m *MainApp) handleSetPage(ctx app.Context, action app.Action) { | ||
log := zapr.NewLogger(zap.L()) | ||
pageValue, ok := action.Value.(page) | ||
if !ok { | ||
log.Error(errors.New("No page provided"), "Invalid action") | ||
return | ||
} | ||
log.Info("Handling set page action", "page", pageValue) | ||
switch pageValue { | ||
case blockLogsView: | ||
if _, ok := m.page.(*BlockViewer); !ok { | ||
log.Info("Setting page to BlockViewer") | ||
m.page = &BlockViewer{} | ||
} | ||
case evalsView: | ||
if _, ok := m.page.(*EvalViewer); !ok { | ||
log.Info("Setting page to EvalViewer") | ||
m.page = &EvalViewer{} | ||
} | ||
} | ||
// We need to call update to trigger a re-render of the component. | ||
m.Update() | ||
} | ||
|
||
// StatusBar at the bottom of the page. Inspired by the vscode/intellij status bar. | ||
// We use this to show useful information like the version number. | ||
type StatusBar struct { | ||
app.Compo | ||
} | ||
|
||
func (s *StatusBar) Render() app.UI { | ||
version := app.Getenv("GOAPP_VERSION") | ||
return app.Div().Class("status-bar").Text("goapp version: " + version) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.