-
Notifications
You must be signed in to change notification settings - Fork 455
feat(gnoweb): change built-in playground and run views into features #5774
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
1c303a9
75baeb3
9f30703
ca89afc
223d59b
38a9c78
d99869d
53f6185
56dbb30
870cc7a
167d64c
9682008
7466039
99dcec3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,22 +1,6 @@ | ||
| package components | ||
|
|
||
| // PlaygroundViewType identifies the playground feature view in | ||
| // layout-level switch cases (see layout_index.go). The data type | ||
| // and view constructor live in the playground feature package. | ||
| const PlaygroundViewType ViewType = "playground-view" | ||
|
|
||
| type PlaygroundData struct { | ||
| // InitialCode is pre-filled code (e.g. from fork) | ||
| InitialCode string | ||
| // ForkFrom is the package path this was forked from | ||
| ForkFrom string | ||
| // Remote is the RPC endpoint | ||
| Remote string | ||
| // ChainId is the current chain ID | ||
| ChainId string | ||
| // Domain is the node domain | ||
| Domain string | ||
| // DefaultFile is the filename that should be focus on first load | ||
| DefaultFile string | ||
| } | ||
|
|
||
| func PlaygroundView(data PlaygroundData) *View { | ||
| return NewTemplateView(PlaygroundViewType, "renderPlayground", data) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,23 +1,6 @@ | ||
| package components | ||
|
|
||
| import "path" | ||
|
|
||
| // RunViewType identifies the run feature view in layout-level switch | ||
| // cases (see layout_index.go). The data type and view constructor live | ||
| // in the run feature package. | ||
| const RunViewType ViewType = "run-view" | ||
|
|
||
| // RunData holds the data for the maketx-run scratchpad view. | ||
| type RunData struct { | ||
| PkgPath string // full path, e.g. "gno.land/r/demo/boards" | ||
| Domain string // e.g. "gno.land" | ||
| Remote string // e.g. "https://rpc.gno.land:443" | ||
| ChainId string // e.g. "portal-loop" | ||
| } | ||
|
|
||
| // PkgAlias returns the last segment of the import path, used as the package alias | ||
| // in the generated template code (e.g. "boards" from "gno.land/r/demo/boards"). | ||
| func (d RunData) PkgAlias() string { | ||
| return path.Base(d.PkgPath) | ||
| } | ||
|
|
||
| func RunView(data RunData) *View { | ||
| return NewTemplateView(RunViewType, "renderRun", data) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| package playground | ||
|
|
||
| import ( | ||
| "html/template" | ||
| "io" | ||
|
|
||
| "github.com/gnolang/gno/gno.land/pkg/gnoweb/components" | ||
| ) | ||
|
|
||
| type playgroundComponent struct { | ||
| tmpl *template.Template | ||
| name string | ||
| data any | ||
| } | ||
|
|
||
| func (c *playgroundComponent) Render(w io.Writer) error { | ||
| return c.tmpl.ExecuteTemplate(w, c.name, c.data) | ||
| } | ||
|
|
||
| // NewPageView wraps the playground template. | ||
| func NewPageView(data PlaygroundData) *components.View { | ||
| return &components.View{ | ||
| Type: components.PlaygroundViewType, | ||
| Component: &playgroundComponent{ | ||
| tmpl: PageTemplate, | ||
| name: "renderPage", | ||
| data: data, | ||
| }, | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| // Package playground implements the gnoweb playground feature. | ||
| // | ||
| // It serves the standalone playground page at /_/play, the fork view | ||
| // (?fork on a package or realm URL — concatenates the source files | ||
| // into the playground), and the JSON API endpoints used by the | ||
| // playground UI (/_/api/eval, /_/api/funcs). | ||
| package playground |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| package playground | ||
|
|
||
| import ( | ||
| "context" | ||
| "log/slog" | ||
|
|
||
| "github.com/gnolang/gno/gnovm/pkg/doc" | ||
| ) | ||
|
|
||
| // ClientAdapter is the subset of the gnoweb chain-client interface that | ||
| // the playground feature consumes. Declared locally so feature/playground | ||
| // does not import the gnoweb package. The signatures match the | ||
| // corresponding methods on gnoweb.ClientAdapter. | ||
| type ClientAdapter interface { | ||
| // ListFiles lists all source files available in a specified package path. | ||
| ListFiles(ctx context.Context, path string) ([]string, error) | ||
|
|
||
| // File fetche the source file from a given package path and filename. | ||
| File(ctx context.Context, path, filename string) ([]byte, error) | ||
|
|
||
| // Doc retrieves the JSON doc suitable for printing from a | ||
| // specified package path. | ||
| Doc(ctx context.Context, path string) (*doc.JSONDocumentation, error) | ||
|
|
||
| // Eval evaluates a Gno expression via vm/qeval query. | ||
| // The data string should be in the format "gno.land/r/pkg.Expression(args)". | ||
| Eval(ctx context.Context, data string) ([]byte, error) | ||
| } | ||
|
|
||
| // Deps gathers the dependencies the playground Handler needs. | ||
| type Deps struct { | ||
| Client ClientAdapter | ||
| Logger *slog.Logger | ||
|
|
||
| // Domain is the chain domain (e.g. "gno.land"). | ||
| Domain string | ||
|
|
||
| // Remote is the RPC endpoint. | ||
| Remote string | ||
|
|
||
| // ChainId is the active chain ID. | ||
| ChainId string | ||
| } | ||
|
|
||
| // Handler owns the playground feature state. | ||
| type Handler struct { | ||
| deps Deps | ||
| limiter *rateLimiter | ||
| } | ||
|
|
||
| // New validates required deps and returns a Handler. | ||
| func New(deps Deps) *Handler { | ||
| if deps.Client == nil { | ||
| panic("playground.New: Client is required") | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Validation is asymmetric here no? Client panics if nil, but empty Domain / Remote / ChainId slide through silently even though they all end up rendered into the page. Not necessarily wrong (maybe empty defaults are legitimate in dev?), just felt inconsistent enough to flag. Either validate them all or drop a one-liner saying empties are intentional.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| } | ||
|
|
||
| if deps.Logger == nil { | ||
| deps.Logger = slog.Default() | ||
| } | ||
|
|
||
| return &Handler{ | ||
| deps: deps, | ||
| limiter: newRateLimiter(evalBurstSize, evalRefillInterval), | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.