use axum::routing::get;
use full::{
auth::{TestAuthProvider, TestLoginProvider},
ui::test::{TestEntityCreateForm, TestEntityListing, TestEntityUpdateForm},
};
use quokka::{
bundle::Pouch,
state::{
Database, ProvideState, ProvideStateRef, Resources, Scripting, State, Styling, Templating,
},
};
use quokka_admin::{
data::AdminDashboardWidget,
handler::EntityHandler,
service::page_loader::{AdminNavigationGroup, AdminSidebarWidget, NavigationItem},
state::AdminState,
AdminBundle,
};
mod full;
pub const EXAMPLE_SUPER_USER_GROUP: &str = "super_example_user";
#[derive(Clone, State, ProvideState)]
pub struct ExampleState {
templating: Templating,
database: Database,
styling: Styling,
scripting: Scripting,
resources: Resources,
admin_state: AdminState<Self>,
}
struct ExampleBundle;
async fn test_widget() -> String {
String::from("Example widget")
}
async fn time_widget() -> String {
format!(
"Current Server Time: {}",
time::OffsetDateTime::now_local().unwrap_or_else(|_| time::OffsetDateTime::now_utc())
)
}
impl<S> Pouch<S> for ExampleBundle
where
S: ProvideState<Database>,
S: ProvideState<Templating>,
S: ProvideStateRef<AdminState<S>>,
S: State + 'static,
{
fn from_config(_: &quokka::config::Config) -> quokka::Result<Self>
where
Self: Sized,
{
Ok(Self)
}
fn get_router(&mut self, _state: &S) -> axum::Router<S> {
axum::Router::new()
.route("/example/admin/test_widget", get(test_widget))
.route("/example/admin/time_widget", get(time_widget))
}
fn configure_state(&mut self, state: &mut S) -> quokka::Result<()> {
let admin: &mut AdminState<_> = state.provide_mut();
admin.super_admin_group = EXAMPLE_SUPER_USER_GROUP.to_string().into(); admin.add_auth_provider(TestAuthProvider);
admin.add_login_provider(TestLoginProvider);
admin.add_navigation(
AdminNavigationGroup::new("Example").add(
NavigationItem::new("example_page", "Example Page").link("/admin/example/page"),
),
);
admin.add_sidebar_widget(AdminSidebarWidget::htmx("/example/admin/test_widget"));
admin.add_sidebar_widget(AdminSidebarWidget::htmx("/example/admin/time_widget"));
admin.add_dashboard_widget(AdminDashboardWidget::htmx("/example/admin/test_widget"));
admin.add_dashboard_widget(AdminDashboardWidget::htmx("/example/admin/test_widget"));
admin.add_dashboard_widget(AdminDashboardWidget::htmx("/example/admin/test_widget"));
admin.add_dashboard_widget(AdminDashboardWidget::htmx("/example/admin/test_widget"));
admin.register_entity_handler(EntityHandler::<
S,
TestEntityCreateForm,
TestEntityUpdateForm,
TestEntityListing,
>::new("Example"));
Ok(())
}
fn get_migrations(&self) -> Option<sqlx::migrate::Migrator> {
Some(sqlx::migrate::Migrator {
migrations: vec![sqlx::migrate::Migration {
version: 1,
description: "Test migration".into(),
migration_type: sqlx::migrate::MigrationType::Simple,
sql: r#"CREATE TABLE IF NOT EXISTS "test" (
id SERIAL NOT NULL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
age INTEGER NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW())"#
.into(),
checksum: vec![1, 2, 3, 4, 5, 6].into(),
no_tx: true,
}]
.into(),
ignore_missing: true,
locking: true,
no_tx: true,
})
}
}
#[tokio::main]
async fn main() -> quokka::Result<()> {
quokka::Quokka::<ExampleState>::try_default()?
.load::<ExampleBundle>()?
.load::<AdminBundle>()?
.serve()
.await
}