async def layout(request: web.Request): next_url = request.query.get('next_url') or default_redirect error = request.query.get('err') footer = core.Container( 'Invalid credentials', style={'color': 'red', 'padding': '0.5rem'}, identity='login-error' ) if error else UNDEFINED return core.Container([ auth.Login( '/auth/login', method='post', identity='login-form', next_url=next_url, bordered=True, header=core.Html('h2', 'Please sign in'), footer=footer, style={ 'padding': '2rem', } ), ], style={ 'display': 'flex', 'justifyContent': 'center', 'alignItems': 'center', 'width': '100%', 'marginTop': '4rem' })
async def layout(request: web.Request): return core.Container([ core.Container(request.get('dummy', 'foobar'), identity='request-output'), core.Container(identity='cookie-output'), core.Button('Set from cookie', identity='cookie-setter') ])
async def on_click(ctx: BindingContext): await ctx.set_aspect( 'output', children=core.Container([ core.Container('from click', identity='trigger'), core.Input(value=ctx.trigger.value, type='number', identity='store-clicks') ]) )
def test_page_url_conflict(): page_one = Page('one', core.Container()) page_two = Page('two', core.Container(), url='/one') app = Dazzler(__name__) with pytest.raises(PageConflictError) as context: app.add_page(page_one, page_two) assert context.value.args[0] == 'Duplicate page url: two@/one'
async def on_any_click(ctx: BindingContext): await ctx.set_aspect( re.compile(r'output\d'), children=f'clicked from button {ctx.trigger.identity}') output = [] for identity, aspects in ctx.states.items(): for aspect_name, aspect_value in aspects.items(): output.append( core.Container(f'{aspect_name}@{identity}: {aspect_value}', identity=f'{aspect_name}-{identity}-output')) # FIXME Setting the array directly on children trigger # the same identity bug #53 await ctx.set_aspect('state-output', children=core.Container(output))
async def test_page_meta_attributes(start_page, browser): meta = [ { 'name': 'description', 'content': 'test dazzler' }, { 'name': 'custom', 'content': 'customized' }, ] await start_page( Page(name='meta', layout=core.Container('Hello', identity='layout'), meta_tags=meta)) await asyncio.sleep(0.001) meta_tags = await browser.wait_for_elements_by_css_selector('meta') # Meta charset + http-equiv always present (+2) assert len(meta_tags) == 4 for i in range(2, len(meta_tags)): meta_dict = meta[i - 2] meta_tag = meta_tags[i] for k, v in meta_dict.items(): assert meta_tag.get_attribute(k) == v
async def on_concat(ctx: BindingContext): await ctx.set_aspect( 'list-box', concat=[ core.Container(f'concat-{x}', class_name='item concat') for x in range(await ctx.get_aspect('index-input', 'value')) ])
async def layout(request: web.Request): user = request.cookies.get('logged-user') if user: return core.Container([ core.Html('h1', f'Logged in as {user}', identity='login-label'), auth.Logout('/login/logout', identity='logout'), ]) return core.Container([ auth.Login( '/login/login-perform', method='post', identity='login-form', bordered=True, header=core.Html('h3', 'Please login', identity='login-label'), ), ])
def session_app(): app = Dazzler(__name__) app.config.session.duration = 3 app.config.secret_key = uuid.uuid4().hex page = Page(__name__, core.Container( [core.Container(identity='session-output', clicks=1)]), url='/') @page.bind(Trigger('session-output', 'clicks')) async def on_session(ctx: BindingContext): await ctx.set_aspect('session-output', children=ctx.session.session_id) app.add_page(page) return app
async def on_insert(ctx: BindingContext): index = await ctx.get_aspect('index-input', 'value') await ctx.set_aspect('list-box', insert={ 'index': index, 'item': core.Container('inserted', class_name='item insert') })
async def test_session(start_visit, browser, backend): app = Dazzler(__name__) app.config.session.enable = False app.config.session.duration = 3 app.middlewares.append(SessionMiddleware(app, backend=backend(app))) page = Page(__name__, url='/', layout=core.Container([ core.Button('Click', identity='session-click'), core.Container(identity='session-output'), core.Button('Remove session', identity='remove-session'), ])) @page.bind(Trigger('session-click', 'clicks')) async def on_session(ctx: BindingContext): session = ctx.request['session'] clicks = await session.get('clicks') or 0 clicks += 1 await session.set('clicks', clicks) await ctx.set_aspect('session-output', children=f'Clicked {clicks}') @page.bind(Trigger('remove-session', 'clicks')) async def on_remove(ctx: BindingContext): session = ctx.request['session'] await session.delete('clicks') app.add_page(page) await start_visit(app) for i in range(1, 4): await browser.get('http://localhost:8150/') await browser.click('#session-click') await browser.wait_for_text_to_equal('#session-output', f'Clicked {i}') # Delete session item await browser.click('#remove-session') await browser.click('#session-click') await browser.wait_for_text_to_equal('#session-output', 'Clicked 1')
def auth_app(): app = Dazzler(__name__) page = Page('test-auth', core.Container([ core.Html('h2', 'logged-in', identity='header'), core.Container(identity='username-output'), _auth.Logout('/auth/logout', identity='logout') ]), url='/', require_login=True) @page.bind(Trigger('header', 'children')) async def on_username(ctx): user = ctx.request['user'] await ctx.set_aspect('username-output', children=user.username) app.add_page(page) app.config.session.backend = 'Redis' DazzlerAuth(app, DummyAuthenticator()) return app
async def test_package_route(start_page, browser): async def package_route(_): return web.Response(body='<html><head></head><body>' '<div id="content">Package route</div>' '</body></html>', content_type='text/html') await start_page( Page('package', core.Container(), routes=[Route('/package-route', package_route)])) await browser.get('http://localhost:8150/package-route') await browser.wait_for_text_to_equal('#content', 'Package route')
async def test_page_routes(start_page, browser): page = Page('page-routes', core.Container()) # pylint: disable=unused-variable @page.route('/page-route') async def page_route(_): return web.Response(body='<html><head></head><body>' '<div id="content">Page route</div>' '</body></html>', content_type='text/html') await start_page(page) await browser.get('http://localhost:8150/page-routes/page-route') await browser.wait_for_text_to_equal('#content', 'Page route')
async def test_page_requirements_package_override(start_page, browser): # Overriding the package is an optimization if some pages uses big bundles # and others pages are more lightweight, down the line maybe add # on-demand loading of requirements, it's already set up for it. # noinspection PyUnresolvedReferences from tests.components import spec_components as spec # noqa: F401 page = Page(__name__, core.Container('Rendered'), packages=['dazzler_core']) await start_page(page) await browser.wait_for_element_by_css_selector('.dazzler-rendered') scripts = await browser.wait_for_elements_by_css_selector('script') for script in scripts: src = script.get_attribute('src') assert 'dazzler_test' not in src
async def test_auth_from_configs(start_visit, browser): app = Dazzler(__name__) app.config.authentication.enable = True app.config.session.backend = 'Redis' app.config.authentication.authenticator = \ 'tests.test_dazzler_auth:DummyAuthenticator' page = Page(__name__, core.Container('my-page', identity='content'), require_login=True, url='/') app.add_page(page) await start_visit(app) await browser.get('http://localhost:8150/') await proceed_login(browser, 'AgentSmith', 'SuperSecret1') await browser.wait_for_text_to_equal('#content', 'my-page')
""" Page markdown of dazzler Created 2019-08-19 """ from dazzler.components import core, markdown as md from dazzler.system import Page text = ''' # Foo ## Bar [google](http://google.com) ```jsx const Foo = props => <div>{props.text}</div>; ``` ''' page = Page( __name__, core.Container([ md.Markdown(text, identity='markdown'), md.CodeBlock(value=text, language='md') ]))
""" Page progress of dazzler Created 2019-06-26 """ from dazzler.components import core from dazzler.system import Page, Trigger, BindingContext, State page = Page( __name__, core.Container([ core.ProgressBar(identity='progress', minimum=0, high=80, low=20, maximum=100, rounded=True, optimum=21, striped=True, progress_text='percent'), core.Button('add progress', identity='progress-btn'), core.Container(identity='counter') ])) @page.bind(Trigger('progress-btn', 'clicks'), State('progress', 'value')) async def on_meter(ctx: BindingContext): new_value = (ctx.states['progress']['value'] or 0) + 1 await ctx.set_aspect('progress', value=new_value) await ctx.set_aspect('counter', children=new_value)
""" Page get_aspect_error of dazzler Created 2019-06-15 """ from dazzler.components import core from dazzler.system import Page, Trigger, BindingContext from dazzler.errors import GetAspectError page = Page( __name__, core.Container([ core.Button('click error', identity='click-error'), core.Container(identity='error-output') ])) @page.bind(Trigger('click-error', 'clicks')) async def trigger_error(ctx: BindingContext): try: await ctx.get_aspect('invalid', 'error') except GetAspectError as err: await ctx.set_aspect('error-output', children=err.args[0])
""" Page initial_trigger of dazzler Created 2019-06-15 """ from dazzler.components import core from dazzler.system import Page, Trigger, BindingContext, State page = Page( 'initial-trigger', core.Container([ core.Input(value=10, identity='input'), core.Container(identity='output'), core.Input(value=88, identity='state'), core.Container(identity='state-output') ])) @page.bind(Trigger('input', 'value'), State('state', 'value')) async def on_value(context: BindingContext): await context.set_aspect('output', children=f'Input {context.trigger.value}') await context.set_aspect( 'state-output', children=F'State {context.states["state"]["value"]}')
async def layout(_): return core.Container('Layout as function', identity='layout')
from dazzler import Dazzler from dazzler.components import core from dazzler.system import Page app = Dazzler(__name__) for num in ('one', 'two', 'three', 'four'): page = Page( name=num, layout=core.Container(f'Page {num}', identity='content'), title=f'Page {num}', ) app.add_page(page) if __name__ == '__main__': app.start('-v --debug 1'.split())
""" Page icons of dazzler Created 2021-06-13 """ from dazzler.components import core, icons from dazzler.system import Page page = Page( __name__, core.Container([ icons.IconLoader([]), icons.LinearIconPack(), icons.FoundIconPack(), icons.OpenIconicPack(), icons.TypiconsPack(), core.Container(icons.Icon('lnr-home'), ), core.Container(icons.Icon('fi-home')), core.Container(icons.Icon('oi-bug')), core.Container(icons.Icon('typcn-globe')), ]))
async def on_click(context: BindingContext): await context.set_aspect('output', children=core.Container('from binding', id='from-binding'))
from dazzler import Dazzler from dazzler.components import core from dazzler.system import Page, Trigger, BindingContext page = Page(name='page', url='/', layout=core.Container([ core.Button('click', identity='clicker'), core.Container('output', identity='output') ])) app = Dazzler(__name__) app.add_page(page) @page.bind(Trigger('clicker', 'clicks')) async def on_click(context: BindingContext): await context.set_aspect('output', children=core.Container('from binding', id='from-binding')) if __name__ == '__main__': app.start('-v --debug=1 --port=8151'.split())
from dazzler.components import core, extra from dazzler.system import Page, BindingContext page = Page( __name__, core.Container([ extra.TreeView([ 'item12', { 'identifier': 'nest', 'label': 'nest', 'items': [ 'nested1', 'nested2', { 'label': 'subnest', 'identifier': 'subnest', 'items': ['sub1', 'sub2'] } ], } ], identity='treeview'), core.Container(identity='output') ])) @page.bind('selected@treeview') async def on_selected(ctx: BindingContext): await ctx.set_aspect('output', children=ctx.trigger.value)
[1, 2, 3, 4], [1, 'foo', 'bar', 4], [{'arr': [1, 2, 3], 'foo': 'bar'}], [[1, 2, 4], ['foo', 'bar']] ] ) ] for i in range(0, 4)), 2))) page = Page( __name__, core.Container([ core.Store(identity='empty-store'), core.Store(data={'foo': 'bar'}, identity='initial-store'), core.Button('click', identity='click'), core.Container(identity='click-output'), core.Container(identity='initial-output'), core.Button('type-click', identity='type-click'), core.Store(identity='type-store'), core.Container(identity='type-output'), core.Button('get-aspect', identity='get-aspect-click'), core.Container(identity='get-aspect-output') ]) ) @page.bind(Trigger('initial-store', 'data')) async def initial(ctx: BindingContext): await ctx.set_aspect( 'initial-output', children=json.dumps(ctx.trigger.value) )
import asyncio import json from dazzler.components import core from dazzler.system import Page, Trigger, BindingContext, State page = Page( 'binding-tree', core.Container([ core.Button('trigger', identity='trigger'), core.Container([ core.Container([ core.Input(identity=f'output-{i}', type='number') for i in range(1, 3) ]), core.Container([ core.Input(identity=f'value-{i}', type='number') for i in range(1, 11) ]), core.Container('[]', identity='output'), core.Container(identity='done') ]) ])) @page.bind(Trigger('trigger', 'clicks')) async def trigger_click(context: BindingContext): await context.set_aspect('output-1', value=1) # Got to alternate the inputs for the first set to complete and let # frontend to register the state and all, # so as long as this start after and the other delay # is a little higher it should be ok.
import functools from dazzler.components import core from dazzler.system import Page, Trigger, BindingContext page = Page( 'binding-chain', core.Container([ core.Button(x, identity=f'trigger-{x}') for x in range(1, 21) ] + [core.Container(identity='output')]) ) async def update_next(context: BindingContext, num: int = 0): await context.set_aspect( f'trigger-{num+1}', clicks=1, ) @page.bind(Trigger('trigger-20', 'clicks')) async def last_trigger(context: BindingContext): await context.set_aspect('output', children='output generated') for i in range(1, 20): page.bind(Trigger(f'trigger-{i}', 'clicks'))( functools.partial(update_next, num=i) )
from dazzler import Dazzler from dazzler.system import Page from dazzler.components import core app = Dazzler(__name__) app.config.requirements.prefer_external = True app.add_page(Page('index', core.Container('foo'), url='/'))