Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 55 additions & 19 deletions playground/app/features/keys/components/dialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,18 @@

import reflex as rx

from app.core.variables import ICON_SIZE_MEDIUM, ICON_SIZE_XL, MAX_DIALOG_WIDTH, SIZE_MEDIUM, SPACING_LARGE, SPACING_SMALL, TEXT_SIZE_LABEL
from app.core.variables import (
ICON_SIZE_MEDIUM,
ICON_SIZE_XL,
MAX_DIALOG_WIDTH,
PADDING_MEDIUM,
SIZE_MEDIUM,
SPACING_LARGE,
SPACING_MEDIUM,
SPACING_SMALL,
SPACING_TINY,
TEXT_SIZE_LABEL,
)
from app.features.keys.state import KeysState
from app.shared.components.dialogs import entity_delete_dialog

Expand All @@ -11,23 +22,32 @@ def keys_created_dialog() -> rx.Component:
"""Dialog to display the newly created API key."""
return rx.dialog.root(
rx.dialog.content(
rx.dialog.title(
rx.vstack(
# Header
rx.hstack(
rx.icon("check_check", size=ICON_SIZE_XL, color=rx.color("green", 11)),
"API Key created successfully!",
spacing=SPACING_SMALL,
rx.icon("circle_check", size=ICON_SIZE_XL, color=rx.color("green", 9)),
rx.vstack(
rx.dialog.title("API key created", margin="0"),
spacing=SPACING_TINY,
align="start",
),
spacing=SPACING_MEDIUM,
align="center",
)
),
rx.dialog.description(
"Copy your API key now. You won't be able to see it again!",
color=rx.color("red", 11),
weight="bold",
),
rx.vstack(
width="100%",
),
# Warning
rx.callout(
"Copy your key now, for security reasons you won't be able to see it again.",
icon="triangle_alert",
color_scheme="amber",
variant="surface",
size="1",
width="100%",
),
# Key
rx.vstack(
rx.text(
"Your API Key:",
"Your API key",
size=TEXT_SIZE_LABEL,
weight="bold",
color=rx.color("mauve", 11),
Expand All @@ -42,19 +62,35 @@ def keys_created_dialog() -> rx.Component:
spacing=SPACING_SMALL,
width="100%",
),
rx.dialog.close(
# Footer
rx.hstack(
rx.dialog.close(
rx.button(
"Done",
on_click=KeysState.clear_created_key,
variant="soft",
color_scheme="gray",
size=SIZE_MEDIUM,
),
),
rx.button(
rx.icon("check", size=ICON_SIZE_MEDIUM),
"I've copied the key",
on_click=KeysState.clear_created_key,
rx.icon("copy", size=ICON_SIZE_MEDIUM),
"Copy API key",
on_click=[
rx.set_clipboard(KeysState.created_key),
rx.toast.success("API key copied to clipboard", position="bottom-right"),
],
size=SIZE_MEDIUM,
width="100%",
),
spacing=SPACING_MEDIUM,
justify="end",
width="100%",
),
spacing=SPACING_LARGE,
width="100%",
),
max_width=MAX_DIALOG_WIDTH,
padding=PADDING_MEDIUM,
),
open=KeysState.is_created_dialog_open,
on_open_change=KeysState.handle_created_dialog_change,
Expand Down
14 changes: 14 additions & 0 deletions playground/app/features/keys/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,23 @@ def keys(self) -> list[Key]:
"""Get keys list with correct typing for Reflex."""
return self.entities

def _default_expiry_date(self) -> str:
"""Default expiry date: today + 1 year, capped at the configured maximum if any."""
default = dt.datetime.now() + dt.timedelta(days=365)
if configuration.settings.auth_key_max_expiration_days is not None:
max_date = dt.datetime.now() + dt.timedelta(days=configuration.settings.auth_key_max_expiration_days - 1)
default = min(default, max_date)
return default.strftime("%Y-%m-%d")

@rx.event
async def load_entities(self):
"""Load entities."""
if not self.is_authenticated or not self.api_key:
return

if not self.entity_to_create.expires:
self.entity_to_create.expires = self._default_expiry_date()

self.entities_loading = True
yield

Expand Down Expand Up @@ -193,6 +204,9 @@ async def create_entity(self):
self.created_key = data.get("key", "")
self.is_created_dialog_open = True

# Reset the create form, keeping the default 1-year expiry
self.entity_to_create = Key(expires=self._default_expiry_date())

yield rx.toast.success("Key created successfully", position="bottom-right")
async for _ in self.load_entities():
yield
Expand Down
Loading