Skip to content

Commit

Permalink
Merge branch 'master' into feat/gnoxchange
Browse files Browse the repository at this point in the history
  • Loading branch information
matijamarjanovic authored Feb 25, 2025
2 parents 8aee81a + c433aa0 commit 8ae2242
Show file tree
Hide file tree
Showing 9 changed files with 450 additions and 25 deletions.
16 changes: 0 additions & 16 deletions docs/concepts/testnets.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,22 +63,6 @@ Test5 was launched in November 2024.
- **Versioning strategy**:
- Test5 is to be release-based, following releases of the Gno tech stack.


## Staging

Staging is a testnet that is reset once every 60 minutes.

- **Persistence of state:**
- State is fully discarded
- **Timeliness of code:**
- With every reset, the latest commit of the Gno tech stack is applied, including
the demo packages and realms
- **Intended purpose**
- Demoing, single-use code in a staging environment, testing automation which
uploads code to the chain, etc.
- **Versioning strategy**:
- Staging is reset every 60 minutes to match the latest monorepo commit

## TestX

These testnets are deprecated and currently serve as archives of previous progress.
Expand Down
4 changes: 2 additions & 2 deletions docs/reference/gno-js-client/gno-provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Same as [`tm2-js-client` `WSProvider`](../tm2-js-client/Provider/ws-provider.md)
#### Usage

```ts
new GnoWSProvider('ws://staging.gno.land:26657/ws');
new GnoWSProvider('ws://gno.land:443/ws');
// provider with WS connection is created
```

Expand All @@ -35,7 +35,7 @@ Same as [`tm2-js-client` `JSONRPCProvider`](../tm2-js-client/Provider/json-rpc-p
#### Usage

```ts
new GnoJSONRPCProvider('http://staging.gno.land:36657');
new GnoJSONRPCProvider('https://gno.land:443');
// provider is created
```

Expand Down
1 change: 0 additions & 1 deletion docs/reference/network-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ id: network-config
|-------------|----------------------------------|---------------|
| Portal Loop | https://rpc.gno.land:443 | `portal-loop` |
| Test5 | https://rpc.test5.gno.land:443 | `test5` |
| Staging | https://rpc.staging.gno.land:443 | `staging` |

### WebSocket endpoints
All networks follow the same pattern for websocket connections:
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/tm2-js-client/Provider/json-rpc-provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ Creates a new instance of the JSON-RPC Provider
#### Usage

```ts
new JSONRPCProvider('http://staging.gno.land:36657');
new JSONRPCProvider('https://gno.land:443');
// provider is created
```
10 changes: 5 additions & 5 deletions docs/reference/tm2-js-client/Provider/ws-provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Creates a new instance of the WebSocket Provider
#### Usage

```ts
new WSProvider('ws://staging.gno.land:26657/ws');
new WSProvider('ws://gno.land:443/ws');
// provider with WS connection is created
```

Expand All @@ -30,7 +30,7 @@ with the WS provider
#### Usage

```ts
const wsProvider = new WSProvider('ws://staging.gno.land:26657/ws');
const wsProvider = new WSProvider('ws://gno.land:443/ws');

wsProvider.closeConnection();
// WS connection is now closed
Expand All @@ -52,7 +52,7 @@ Returns **Promise<RPCResponse<Result\>>**
```ts
const request: RPCRequest = // ...

const wsProvider = new WSProvider('ws://staging.gno.land:26657/ws');
const wsProvider = new WSProvider('ws://gno.land:443/ws');

wsProvider.sendRequest<Result>(request);
// request is sent over the open WS connection
Expand All @@ -73,7 +73,7 @@ Returns **Result**
```ts
const response: RPCResponse = // ...

const wsProvider = new WSProvider('ws://staging.gno.land:26657/ws');
const wsProvider = new WSProvider('ws://gno.land:443/ws');

wsProvider.parseResponse<Result>(response);
// response is parsed
Expand All @@ -88,7 +88,7 @@ Returns **Promise<null\>**
#### Usage

```ts
const wsProvider = new WSProvider('ws://staging.gno.land:26657/ws');
const wsProvider = new WSProvider('ws://gno.land:443/ws');

await wsProvider.waitForOpenConnection()
// status of the connection is: CONNECTED
Expand Down
1 change: 1 addition & 0 deletions examples/gno.land/p/jeronimoalbi/pager/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module gno.land/p/jeronimoalbi/pager
204 changes: 204 additions & 0 deletions examples/gno.land/p/jeronimoalbi/pager/pager.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
// Package pager provides pagination functionality through a generic pager implementation.
//
// Example usage:
//
// import (
// "strconv"
// "strings"
//
// "gno.land/p/jeronimoalbi/pager"
// )
//
// func Render(path string) string {
// // Define the items to paginate
// items := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
//
// // Create a pager that paginates 4 items at a time
// p, err := pager.New(path, len(items), pager.WithPageSize(4))
// if err != nil {
// panic(err)
// }
//
// // Render items for the current page
// var output strings.Builder
// p.Iterate(func(i int) bool {
// output.WriteString("- " + strconv.Itoa(items[i]) + "\n")
// return false
// })
//
// // Render page picker
// if p.HasPages() {
// output.WriteString("\n" + pager.Picker(p))
// }
//
// return output.String()
// }
package pager

import (
"errors"
"math"
"net/url"
"strconv"
"strings"
)

var ErrInvalidPageNumber = errors.New("invalid page number")

// PagerIterFn defines a callback to iterate page items.
type PagerIterFn func(index int) (stop bool)

// New creates a new pager.
func New(rawURL string, totalItems int, options ...PagerOption) (Pager, error) {
u, err := url.Parse(rawURL)
if err != nil {
return Pager{}, err
}

p := Pager{
query: u.RawQuery,
pageQueryParam: DefaultPageQueryParam,
pageSize: DefaultPageSize,
page: 1,
totalItems: totalItems,
}
for _, apply := range options {
apply(&p)
}

p.pageCount = int(math.Ceil(float64(p.totalItems) / float64(p.pageSize)))

rawPage := u.Query().Get(p.pageQueryParam)
if rawPage != "" {
p.page, _ = strconv.Atoi(rawPage)
if p.page == 0 || p.page > p.pageCount {
return Pager{}, ErrInvalidPageNumber
}
}

return p, nil
}

// MustNew creates a new pager or panics if there is an error.
func MustNew(rawURL string, totalItems int, options ...PagerOption) Pager {
p, err := New(rawURL, totalItems, options...)
if err != nil {
panic(err)
}
return p
}

// Pager allows paging items.
type Pager struct {
query, pageQueryParam string
pageSize, page, pageCount, totalItems int
}

// TotalItems returns the total number of items to paginate.
func (p Pager) TotalItems() int {
return p.totalItems
}

// PageSize returns the size of each page.
func (p Pager) PageSize() int {
return p.pageSize
}

// Page returns the current page number.
func (p Pager) Page() int {
return p.page
}

// PageCount returns the number pages.
func (p Pager) PageCount() int {
return p.pageCount
}

// Offset returns the index of the first page item.
func (p Pager) Offset() int {
return (p.page - 1) * p.pageSize
}

// HasPages checks if pager has more than one page.
func (p Pager) HasPages() bool {
return p.pageCount > 1
}

// GetPageURI returns the URI for a page.
// An empty string is returned when page doesn't exist.
func (p Pager) GetPageURI(page int) string {
if page < 1 || page > p.PageCount() {
return ""
}

values, _ := url.ParseQuery(p.query)
values.Set(p.pageQueryParam, strconv.Itoa(page))
return "?" + values.Encode()
}

// PrevPageURI returns the URI path to the previous page.
// An empty string is returned when current page is the first page.
func (p Pager) PrevPageURI() string {
if p.page == 1 || !p.HasPages() {
return ""
}
return p.GetPageURI(p.page - 1)
}

// NextPageURI returns the URI path to the next page.
// An empty string is returned when current page is the last page.
func (p Pager) NextPageURI() string {
if p.page == p.pageCount {
// Current page is the last page
return ""
}
return p.GetPageURI(p.page + 1)
}

// Iterate allows iterating page items.
func (p Pager) Iterate(fn PagerIterFn) bool {
if p.totalItems == 0 {
return true
}

start := p.Offset()
end := start + p.PageSize()
if end > p.totalItems {
end = p.totalItems
}

for i := start; i < end; i++ {
if fn(i) {
return true
}
}
return false
}

// TODO: Support different types of pickers (ex. with clickable page numbers)

// Picker returns a string with the pager as Markdown.
// An empty string is returned when the pager has no pages.
func Picker(p Pager) string {
if !p.HasPages() {
return ""
}

var out strings.Builder

if s := p.PrevPageURI(); s != "" {
out.WriteString("[«](" + s + ") | ")
} else {
out.WriteString("\\- | ")
}

out.WriteString("page " + strconv.Itoa(p.Page()) + " of " + strconv.Itoa(p.PageCount()))

if s := p.NextPageURI(); s != "" {
out.WriteString(" | [»](" + s + ")")
} else {
out.WriteString(" | \\-")
}

return out.String()
}
33 changes: 33 additions & 0 deletions examples/gno.land/p/jeronimoalbi/pager/pager_options.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package pager

import "strings"

const (
DefaultPageSize = 50
DefaultPageQueryParam = "page"
)

// PagerOption configures the pager.
type PagerOption func(*Pager)

// WithPageSize assigns a page size to a pager.
func WithPageSize(size int) PagerOption {
return func(p *Pager) {
if size < 1 {
p.pageSize = DefaultPageSize
} else {
p.pageSize = size
}
}
}

// WithPageQueryParam assigns the name of the URL query param for the page value.
func WithPageQueryParam(name string) PagerOption {
return func(p *Pager) {
name = strings.TrimSpace(name)
if name == "" {
name = DefaultPageQueryParam
}
p.pageQueryParam = name
}
}
Loading

0 comments on commit 8ae2242

Please sign in to comment.