redirects, middleware, Transport, set/capture error status (#4751)
* wip: redirect * redirect example * fix file upload not in a form * wip * deny missing cfgs * wip: add router fallback but it's not working * fix suspense bug after rebuilds that queued work * more cleanup * add test for error codes * add helpful comment * bring back middleware annotation * fix cfg * add server feature * fix doctest * just disable liveview test for now * fix liveview * dont send init * cache more playwright! * add more pkgs to cache
This commit is contained in:
1 parent
8a81475ba8
commit
9243ef4128
35 files changed
+935
-800
No files matched your search
+126
-125
@@ -201,131 +201,6 @@ pub struct ErrorBoundaryProps {
|
||||
children: Element,
|
||||
handle_error: ErrorHandler,
|
||||
}
|
||||
impl ErrorBoundaryProps {
|
||||
/**
|
||||
Create a builder for building `ErrorBoundaryProps`.
|
||||
On the builder, call `.children(...)`(optional), `.handle_error(...)`(optional) to set the values of the fields.
|
||||
Finally, call `.build()` to create the instance of `ErrorBoundaryProps`.
|
||||
*/
|
||||
#[allow(dead_code)]
|
||||
pub fn builder() -> ErrorBoundaryPropsBuilder<((), ())> {
|
||||
ErrorBoundaryPropsBuilder { fields: ((), ()) }
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[doc(hidden)]
|
||||
#[allow(dead_code, non_camel_case_types, non_snake_case)]
|
||||
pub struct ErrorBoundaryPropsBuilder<TypedBuilderFields> {
|
||||
fields: TypedBuilderFields,
|
||||
}
|
||||
impl<TypedBuilderFields> Clone for ErrorBoundaryPropsBuilder<TypedBuilderFields>
|
||||
where
|
||||
TypedBuilderFields: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
fields: self.fields.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Properties for ErrorBoundaryProps {
|
||||
type Builder = ErrorBoundaryPropsBuilder<((), ())>;
|
||||
fn builder() -> Self::Builder {
|
||||
ErrorBoundaryProps::builder()
|
||||
}
|
||||
fn memoize(&mut self, other: &Self) -> bool {
|
||||
*self = other.clone();
|
||||
false
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[allow(dead_code, non_camel_case_types, non_snake_case)]
|
||||
pub trait ErrorBoundaryPropsBuilder_Optional<T> {
|
||||
fn into_value<F: FnOnce() -> T>(self, default: F) -> T;
|
||||
}
|
||||
impl<T> ErrorBoundaryPropsBuilder_Optional<T> for () {
|
||||
fn into_value<F: FnOnce() -> T>(self, default: F) -> T {
|
||||
default()
|
||||
}
|
||||
}
|
||||
impl<T> ErrorBoundaryPropsBuilder_Optional<T> for (T,) {
|
||||
fn into_value<F: FnOnce() -> T>(self, _: F) -> T {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
#[allow(dead_code, non_camel_case_types, missing_docs)]
|
||||
impl<__handle_error> ErrorBoundaryPropsBuilder<((), __handle_error)> {
|
||||
pub fn children(
|
||||
self,
|
||||
children: Element,
|
||||
) -> ErrorBoundaryPropsBuilder<((Element,), __handle_error)> {
|
||||
let children = (children,);
|
||||
let (_, handle_error) = self.fields;
|
||||
ErrorBoundaryPropsBuilder {
|
||||
fields: (children, handle_error),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[allow(dead_code, non_camel_case_types, non_snake_case)]
|
||||
pub enum ErrorBoundaryPropsBuilder_Error_Repeated_field_children {}
|
||||
#[doc(hidden)]
|
||||
#[allow(dead_code, non_camel_case_types, missing_docs)]
|
||||
impl<__handle_error> ErrorBoundaryPropsBuilder<((Element,), __handle_error)> {
|
||||
#[deprecated(note = "Repeated field children")]
|
||||
pub fn children(
|
||||
self,
|
||||
_: ErrorBoundaryPropsBuilder_Error_Repeated_field_children,
|
||||
) -> ErrorBoundaryPropsBuilder<((Element,), __handle_error)> {
|
||||
self
|
||||
}
|
||||
}
|
||||
#[allow(dead_code, non_camel_case_types, missing_docs)]
|
||||
impl<__children> ErrorBoundaryPropsBuilder<(__children, ())> {
|
||||
pub fn handle_error(
|
||||
self,
|
||||
handle_error: impl ::core::convert::Into<ErrorHandler>,
|
||||
) -> ErrorBoundaryPropsBuilder<(__children, (ErrorHandler,))> {
|
||||
let handle_error = (handle_error.into(),);
|
||||
let (children, _) = self.fields;
|
||||
ErrorBoundaryPropsBuilder {
|
||||
fields: (children, handle_error),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[allow(dead_code, non_camel_case_types, non_snake_case)]
|
||||
pub enum ErrorBoundaryPropsBuilder_Error_Repeated_field_handle_error {}
|
||||
#[doc(hidden)]
|
||||
#[allow(dead_code, non_camel_case_types, missing_docs)]
|
||||
impl<__children> ErrorBoundaryPropsBuilder<(__children, (ErrorHandler,))> {
|
||||
#[deprecated(note = "Repeated field handle_error")]
|
||||
pub fn handle_error(
|
||||
self,
|
||||
_: ErrorBoundaryPropsBuilder_Error_Repeated_field_handle_error,
|
||||
) -> ErrorBoundaryPropsBuilder<(__children, (ErrorHandler,))> {
|
||||
self
|
||||
}
|
||||
}
|
||||
#[allow(dead_code, non_camel_case_types, missing_docs)]
|
||||
impl<
|
||||
__handle_error: ErrorBoundaryPropsBuilder_Optional<ErrorHandler>,
|
||||
__children: ErrorBoundaryPropsBuilder_Optional<Element>,
|
||||
> ErrorBoundaryPropsBuilder<(__children, __handle_error)>
|
||||
{
|
||||
pub fn build(self) -> ErrorBoundaryProps {
|
||||
let (children, handle_error) = self.fields;
|
||||
let children = ErrorBoundaryPropsBuilder_Optional::into_value(children, VNode::empty);
|
||||
let handle_error = ErrorBoundaryPropsBuilder_Optional::into_value(handle_error, || {
|
||||
ErrorHandler(Rc::new(default_handler))
|
||||
});
|
||||
ErrorBoundaryProps {
|
||||
children,
|
||||
handle_error,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new error boundary component that catches any errors thrown from child components
|
||||
///
|
||||
@@ -459,3 +334,129 @@ pub fn ErrorBoundary(props: ErrorBoundaryProps) -> Element {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ErrorBoundaryProps {
|
||||
/**
|
||||
Create a builder for building `ErrorBoundaryProps`.
|
||||
On the builder, call `.children(...)`(optional), `.handle_error(...)`(optional) to set the values of the fields.
|
||||
Finally, call `.build()` to create the instance of `ErrorBoundaryProps`.
|
||||
*/
|
||||
#[allow(dead_code)]
|
||||
pub fn builder() -> ErrorBoundaryPropsBuilder<((), ())> {
|
||||
ErrorBoundaryPropsBuilder { fields: ((), ()) }
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[doc(hidden)]
|
||||
#[allow(dead_code, non_camel_case_types, non_snake_case)]
|
||||
pub struct ErrorBoundaryPropsBuilder<TypedBuilderFields> {
|
||||
fields: TypedBuilderFields,
|
||||
}
|
||||
impl<TypedBuilderFields> Clone for ErrorBoundaryPropsBuilder<TypedBuilderFields>
|
||||
where
|
||||
TypedBuilderFields: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
fields: self.fields.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Properties for ErrorBoundaryProps {
|
||||
type Builder = ErrorBoundaryPropsBuilder<((), ())>;
|
||||
fn builder() -> Self::Builder {
|
||||
ErrorBoundaryProps::builder()
|
||||
}
|
||||
fn memoize(&mut self, other: &Self) -> bool {
|
||||
*self = other.clone();
|
||||
false
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[allow(dead_code, non_camel_case_types, non_snake_case)]
|
||||
pub trait ErrorBoundaryPropsBuilder_Optional<T> {
|
||||
fn into_value<F: FnOnce() -> T>(self, default: F) -> T;
|
||||
}
|
||||
impl<T> ErrorBoundaryPropsBuilder_Optional<T> for () {
|
||||
fn into_value<F: FnOnce() -> T>(self, default: F) -> T {
|
||||
default()
|
||||
}
|
||||
}
|
||||
impl<T> ErrorBoundaryPropsBuilder_Optional<T> for (T,) {
|
||||
fn into_value<F: FnOnce() -> T>(self, _: F) -> T {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
#[allow(dead_code, non_camel_case_types, missing_docs)]
|
||||
impl<__handle_error> ErrorBoundaryPropsBuilder<((), __handle_error)> {
|
||||
pub fn children(
|
||||
self,
|
||||
children: Element,
|
||||
) -> ErrorBoundaryPropsBuilder<((Element,), __handle_error)> {
|
||||
let children = (children,);
|
||||
let (_, handle_error) = self.fields;
|
||||
ErrorBoundaryPropsBuilder {
|
||||
fields: (children, handle_error),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[allow(dead_code, non_camel_case_types, non_snake_case)]
|
||||
pub enum ErrorBoundaryPropsBuilder_Error_Repeated_field_children {}
|
||||
#[doc(hidden)]
|
||||
#[allow(dead_code, non_camel_case_types, missing_docs)]
|
||||
impl<__handle_error> ErrorBoundaryPropsBuilder<((Element,), __handle_error)> {
|
||||
#[deprecated(note = "Repeated field children")]
|
||||
pub fn children(
|
||||
self,
|
||||
_: ErrorBoundaryPropsBuilder_Error_Repeated_field_children,
|
||||
) -> ErrorBoundaryPropsBuilder<((Element,), __handle_error)> {
|
||||
self
|
||||
}
|
||||
}
|
||||
#[allow(dead_code, non_camel_case_types, missing_docs)]
|
||||
impl<__children> ErrorBoundaryPropsBuilder<(__children, ())> {
|
||||
pub fn handle_error(
|
||||
self,
|
||||
handle_error: impl ::core::convert::Into<ErrorHandler>,
|
||||
) -> ErrorBoundaryPropsBuilder<(__children, (ErrorHandler,))> {
|
||||
let handle_error = (handle_error.into(),);
|
||||
let (children, _) = self.fields;
|
||||
ErrorBoundaryPropsBuilder {
|
||||
fields: (children, handle_error),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[allow(dead_code, non_camel_case_types, non_snake_case)]
|
||||
pub enum ErrorBoundaryPropsBuilder_Error_Repeated_field_handle_error {}
|
||||
#[doc(hidden)]
|
||||
#[allow(dead_code, non_camel_case_types, missing_docs)]
|
||||
impl<__children> ErrorBoundaryPropsBuilder<(__children, (ErrorHandler,))> {
|
||||
#[deprecated(note = "Repeated field handle_error")]
|
||||
pub fn handle_error(
|
||||
self,
|
||||
_: ErrorBoundaryPropsBuilder_Error_Repeated_field_handle_error,
|
||||
) -> ErrorBoundaryPropsBuilder<(__children, (ErrorHandler,))> {
|
||||
self
|
||||
}
|
||||
}
|
||||
#[allow(dead_code, non_camel_case_types, missing_docs)]
|
||||
impl<
|
||||
__handle_error: ErrorBoundaryPropsBuilder_Optional<ErrorHandler>,
|
||||
__children: ErrorBoundaryPropsBuilder_Optional<Element>,
|
||||
> ErrorBoundaryPropsBuilder<(__children, __handle_error)>
|
||||
{
|
||||
pub fn build(self) -> ErrorBoundaryProps {
|
||||
let (children, handle_error) = self.fields;
|
||||
let children = ErrorBoundaryPropsBuilder_Optional::into_value(children, VNode::empty);
|
||||
let handle_error = ErrorBoundaryPropsBuilder_Optional::into_value(handle_error, || {
|
||||
ErrorHandler(Rc::new(default_handler))
|
||||
});
|
||||
ErrorBoundaryProps {
|
||||
children,
|
||||
handle_error,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,7 @@ impl<E: Into<Error>> From<E> for CapturedError {
|
||||
|
||||
impl std::fmt::Display for CapturedError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
std::fmt::Display::fmt(&*self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
any_props::{AnyProps, BoxedAnyProps},
|
||||
innerlude::{throw_error, RenderError, ScopeOrder, ScopeState},
|
||||
innerlude::{RenderError, ScopeOrder, ScopeState},
|
||||
scope_context::{Scope, SuspenseLocation},
|
||||
scopes::ScopeId,
|
||||
virtual_dom::VirtualDom,
|
||||
@@ -108,8 +108,8 @@ impl VirtualDom {
|
||||
fn handle_element_return(&self, node: &mut Element, scope: &Scope) {
|
||||
match node {
|
||||
Err(RenderError::Error(e)) => {
|
||||
tracing::error!("Error while rendering component `{}`:\n{e}", scope.name);
|
||||
throw_error(e.clone());
|
||||
tracing::error!("Error while rendering component `{}`: {e}", scope.name);
|
||||
self.runtime.throw_error(scope.id, e.clone());
|
||||
}
|
||||
Err(RenderError::Suspended(e)) => {
|
||||
let task = e.task();
|
||||
|
||||
@@ -640,7 +640,7 @@ impl VirtualDom {
|
||||
#[instrument(skip(self), level = "trace", name = "VirtualDom::wait_for_suspense")]
|
||||
pub async fn wait_for_suspense(&mut self) {
|
||||
loop {
|
||||
if !self.suspended_tasks_remaining() {
|
||||
if !self.suspended_tasks_remaining() && !self.has_dirty_scopes() {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -736,9 +736,11 @@ impl VirtualDom {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Queue any new events
|
||||
self.queue_events();
|
||||
work_done += 1;
|
||||
|
||||
// Once we have polled a few tasks, we manually yield to the scheduler to give it a chance to run other pending work
|
||||
if work_done > 32 {
|
||||
yield_now().await;
|
||||
|
||||
@@ -61,9 +61,7 @@ fn clear_error_boundary() {
|
||||
handle_error: |error: ErrorContext| {
|
||||
error.clear_errors();
|
||||
|
||||
rsx! {
|
||||
"We cleared it"
|
||||
}
|
||||
rsx! { "We cleared it" }
|
||||
},
|
||||
|
||||
ThrowsError {}
|
||||
|
||||
Reference in new issue
Block a user