-
Notifications
You must be signed in to change notification settings - Fork 328
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
116 additions
and
172 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,60 +1,49 @@ | ||
# Wizard | ||
# Create a multi-step #wizard using #form cards. | ||
# --- | ||
from h2o_wave import Q, ui, main, app, cypress, Cypress | ||
import uvicorn | ||
from starlette.applications import Starlette | ||
from starlette.routing import Mount, WebSocketRoute | ||
from starlette.staticfiles import StaticFiles | ||
from starlette.websockets import WebSocketDisconnect | ||
from h2o_wavelite import wave_serve, ui, Q | ||
from h2o_wavelite_web import web_directory | ||
|
||
|
||
@app('/demo') | ||
async def serve(q: Q): | ||
if not q.client.initialized: # First visit, create an empty form card for our wizard | ||
q.page['wizard'] = ui.form_card(box='1 1 2 4', items=[]) | ||
# Paint our UI on the first page visit. | ||
if not q.client.initialized: | ||
# Create a local state. | ||
q.client.count = 0 | ||
# Add a "card" with a text and a button | ||
q.page['hello'] = ui.form_card(box='1 1 2 2', items=[ | ||
ui.text_xl('Hello world'), | ||
ui.button(name='counter', label=f'Current count: {q.client.count}'), | ||
]) | ||
q.client.initialized = True | ||
|
||
wizard = q.page['wizard'] # Get a reference to the wizard form | ||
if q.args.step1: | ||
wizard.items = [ | ||
ui.text_xl('Wizard - Step 1'), | ||
ui.text('What is your name?', name='text'), | ||
ui.textbox(name='nickname', label='My name is...', value='Gandalf'), | ||
ui.buttons([ui.button(name='step2', label='Next', primary=True)]), | ||
] | ||
elif q.args.step2: | ||
q.client.nickname = q.args.nickname | ||
wizard.items = [ | ||
ui.text_xl('Wizard - Step 2'), | ||
ui.text(f'Hi {q.args.nickname}! How do you feel right now?', name='text'), | ||
ui.textbox(name='feeling', label='I feel...', value='magical'), | ||
ui.buttons([ui.button(name='step3', label='Next', primary=True)]), | ||
] | ||
elif q.args.step3: | ||
wizard.items = [ | ||
ui.text_xl('Wizard - Done'), | ||
ui.text( | ||
f'What a coincidence, {q.client.nickname}! I feel {q.args.feeling} too!', | ||
name='text', | ||
), | ||
ui.buttons([ui.button(name='step1', label='Try Again', primary=True)]), | ||
] | ||
else: | ||
wizard.items = [ | ||
ui.text_xl('Wizard Example'), | ||
ui.text("Let's have a conversation, shall we?"), | ||
ui.buttons([ui.button(name='step1', label='Of course!', primary=True)]), | ||
] | ||
# Handle counter button click. | ||
if q.args.counter: | ||
# Increment the counter. | ||
q.client.count += 1 | ||
# Update the counter button. | ||
q.page['hello'].items[1].button.label = f'Current count: {q.client.count}' | ||
|
||
# Send the UI changes to the browser. | ||
await q.page.save() | ||
|
||
|
||
@cypress('Walk through the wizard') | ||
def try_walk_through(cy: Cypress): | ||
cy.visit('/demo') | ||
cy.locate('step1').click() | ||
cy.locate('text').should('contain.text', 'What is your name?') | ||
cy.locate('nickname').clear().type('Fred') | ||
cy.locate('step2').click() | ||
cy.locate('text').should('contain.text', 'Hi Fred! How do you feel right now?') | ||
cy.locate('feeling').clear().type('quirky') | ||
cy.locate('step3').click() | ||
cy.locate('text').should( | ||
'contain.text', 'What a coincidence, Fred! I feel quirky too!' | ||
) | ||
async def socket(ws): | ||
try: | ||
await ws.accept() | ||
await wave_serve(serve, ws.send_text, ws.receive_text) | ||
await ws.close() | ||
except WebSocketDisconnect: | ||
print('Client disconnected') | ||
|
||
|
||
startlette_app = Starlette(routes=[ | ||
WebSocketRoute('/_s/', socket), | ||
Mount("/", app=StaticFiles(directory=web_directory, html=True), name="/") | ||
]) | ||
|
||
if __name__ == '__main__': | ||
uvicorn.run(startlette_app, host='0.0.0.0', port=5000) | ||
|
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 |
---|---|---|
@@ -1,59 +1,89 @@ | ||
H2O Wave | ||
======== | ||
# H2O Wavelite | ||
|
||
H2O Wave is a lightweight software stack for programming interactive web applications | ||
entirely in Python (no HTML/Javascript/CSS required). | ||
H2O Wavelite is a lighter version of [H2O Wave](https://wave.h2o.ai/), capable of seamless integration into popular existing python web frameworks like Django, Flask, FastAPI, Starlette etc. | ||
|
||
It is designed to make it fast, fun and easy to build low-latency, realtime, | ||
collaborative, web-based applications. It ships batteries-included with | ||
a suite of form and data visualization components for rapidly prototyping | ||
analytical and decision-support applications. | ||
The integration consists of 2 steps: | ||
|
||
Wave's components work in conjunction with the Wave relay server that facilitates | ||
realtime state synchronization between Python and web browsers. | ||
* Serve Wavelite's static web dir at the route of your choice. | ||
* Set up a WebSocket connection and hook `wave_serve` callback function to control the UI. | ||
|
||
Installing | ||
---------- | ||
Done. You can render UI elements with nothing but Python. Wavelite aims to be as simplistic as possible and only provides: | ||
|
||
Install and update using conda | ||
* A simple way to render your UI. | ||
* A simple way of getting the UI inputs (like button clicks, dropdown values etc.) | ||
* Minimal state management. | ||
|
||
```bash | ||
conda config --append channels conda-forge | ||
conda install -c h2oai h2o-wave | ||
``` | ||
Nothing more, nothing less. | ||
|
||
Hello world | ||
----------- | ||
## Installation | ||
|
||
`hello.py`: | ||
---------- | ||
|
||
```bash | ||
from h2o_wave import site, ui | ||
|
||
# Access the web page at http://localhost:10101/demo | ||
page = site['/demo'] | ||
|
||
# Add some content. | ||
page['example'] = ui.markdown_card( | ||
box='1 1 2 2', | ||
title='Hello World!', | ||
content='And now for something completely different.', | ||
) | ||
|
||
# Save the page | ||
page.save() | ||
pip install "h2o-wavelite[web]" | ||
``` | ||
|
||
Run `hello.py`: | ||
## Starlette Hello world | ||
|
||
```py | ||
import uvicorn | ||
from starlette.applications import Starlette | ||
from starlette.routing import Mount, WebSocketRoute | ||
from starlette.staticfiles import StaticFiles | ||
from starlette.websockets import WebSocketDisconnect | ||
from h2o_wavelite import wave_serve, ui, Q | ||
from h2o_wavelite_web import web_directory | ||
|
||
|
||
# Wavelite callback function. | ||
async def serve(q: Q): | ||
# Paint our UI on the first page visit. | ||
if not q.client.initialized: | ||
# Create a local state. | ||
q.client.count = 0 | ||
# Add a "card" with a text and a button | ||
q.page['hello'] = ui.form_card(box='1 1 2 2', items=[ | ||
ui.text_xl('Hello world'), | ||
ui.button(name='counter', label=f'Current count: {q.client.count}'), | ||
]) | ||
q.client.initialized = True | ||
|
||
# Handle counter button click. | ||
if q.args.counter: | ||
# Increment the counter. | ||
q.client.count += 1 | ||
# Update the counter button. | ||
q.page['hello'].items[1].button.label = f'Current count: {q.client.count}' | ||
|
||
# Send the UI changes to the browser. | ||
await q.page.save() | ||
|
||
|
||
# Starlette boilerplate. | ||
async def socket(ws): | ||
try: | ||
await ws.accept() | ||
await wave_serve(serve, ws.send_text, ws.receive_text) | ||
await ws.close() | ||
except WebSocketDisconnect: | ||
print('Client disconnected') | ||
|
||
|
||
startlette_app = Starlette(routes=[ | ||
# Register a websocket. | ||
WebSocketRoute('/_s/', socket), | ||
# Serve static assets. | ||
Mount("/", app=StaticFiles(directory=web_directory, html=True), name="/") | ||
]) | ||
|
||
if __name__ == '__main__': | ||
uvicorn.run(startlette_app, host='0.0.0.0', port=5000) | ||
|
||
```bash | ||
python hello.py | ||
``` | ||
|
||
Links | ||
----- | ||
## Links | ||
|
||
- Website: [https://wave.h2o.ai/](https://wave.h2o.ai/) | ||
- Releases: [https://pypi.org/project/h2o-wave/](https://pypi.org/project/h2o-wave/) | ||
- Code: [https://github.com/h2oai/wave](https://github.com/h2oai/wave) | ||
- Issue tracker: [https://github.com/h2oai/wave/issues](https://github.com/h2oai/wave/issues) | ||
* Website: [https://wave.h2o.ai/](https://wave.h2o.ai/) | ||
* Releases: [https://pypi.org/project/h2o-wave/](https://pypi.org/project/h2o-wave/) | ||
* Code: [https://github.com/h2oai/wave](https://github.com/h2oai/wave) | ||
* Issue tracker: [https://github.com/h2oai/wave/issues](https://github.com/h2oai/wave/issues) |
This file was deleted.
Oops, something went wrong.
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 |
---|---|---|
@@ -1,13 +1 @@ | ||
Create apps 10x quicker, without Javascript, HTML, or CSS. | ||
|
||
[Documentation](https://nitro.h2o.ai) | [Source](https://github.com/h2oai/nitro) | ||
|
||
Integrates with [Django](https://www.djangoproject.com/) | ||
, [Flask](https://flask.palletsprojects.com/), [Starlette](https://www.starlette.io/) | ||
, [Tornado](https://www.tornadoweb.org/), [Uvicorn](https://www.uvicorn.org/) and other popular frameworks. Can be | ||
integrated into your existing applications. | ||
|
||
|
||
|
||
|
||
|
||
Web assets for H2O Wavelite. |