mirror of
https://github.com/euzu/tuliprox.git
synced 2026-10-20 23:02:34 +02:00
save config, show modified pages
This commit is contained in:
@@ -34,9 +34,9 @@ pub fn ApiConfigView() -> Html {
|
||||
|
||||
{
|
||||
let on_form_change = config_view_ctx.on_form_change.clone();
|
||||
let deps = (form_state.form.clone(), form_state.modified);
|
||||
use_effect_with(deps, move |(form, modified)| {
|
||||
on_form_change.emit(ConfigForm::Api(*modified, form.clone()));
|
||||
let deps = (form_state.clone(), form_state.modified);
|
||||
use_effect_with(deps, move |(state, modified)| {
|
||||
on_form_change.emit(ConfigForm::Api(*modified, state.form.clone()));
|
||||
|| ()
|
||||
});
|
||||
}
|
||||
|
||||
@@ -70,12 +70,12 @@ pub fn ConfigView() -> Html {
|
||||
let translate = translate.clone();
|
||||
let edit_mode = edit_mode.clone();
|
||||
|
||||
use_memo((form_state, edit_mode), move |(forms, edit)| {
|
||||
let modified = collect_modified!(forms, [
|
||||
main, api, schedules, video, messaging, web_ui,
|
||||
reverse_proxy, hd_homerun, proxy, ipcheck
|
||||
])
|
||||
.iter()
|
||||
use_memo((form_state, edit_mode, translate), move |(forms, edit, translate)| {
|
||||
let forms: &ConfigFormState = forms;
|
||||
let modified_pages = collect_modified!(forms, [
|
||||
main, api, schedules, video, messaging, web_ui,
|
||||
reverse_proxy, hd_homerun, proxy, ipcheck
|
||||
]).iter()
|
||||
.filter_map(|maybe_form| maybe_form.as_ref().map(config_form_to_config_page))
|
||||
.collect::<Vec<ConfigPage>>();
|
||||
|
||||
@@ -94,7 +94,7 @@ pub fn ConfigView() -> Html {
|
||||
|
||||
let editing = **edit;
|
||||
tab_configs.into_iter().map(|(page, label, children, icon)| {
|
||||
let is_modified = editing && modified.contains(&page);
|
||||
let is_modified = editing && modified_pages.contains(&page);
|
||||
TabItem {
|
||||
id: page.to_string(),
|
||||
title: translate.t(label),
|
||||
|
||||
@@ -31,8 +31,9 @@ pub fn HdHomerunConfigView() -> Html {
|
||||
|
||||
{
|
||||
let on_form_change = config_view_ctx.on_form_change.clone();
|
||||
use_effect_with(form_state.clone(), move |state| {
|
||||
on_form_change.emit(ConfigForm::HdHomerun(state.modified, state.form.clone()));
|
||||
let deps = (form_state.clone(), form_state.modified);
|
||||
use_effect_with(deps, move |(state, modified)| {
|
||||
on_form_change.emit(ConfigForm::HdHomerun(*modified, state.form.clone()));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -37,8 +37,9 @@ pub fn IpCheckConfigView() -> Html {
|
||||
|
||||
{
|
||||
let on_form_change = config_view_ctx.on_form_change.clone();
|
||||
use_effect_with(form_state.clone(), move |state| {
|
||||
on_form_change.emit(ConfigForm::IpCheck(state.modified, state.form.clone()));
|
||||
let deps = (form_state.clone(), form_state.modified);
|
||||
use_effect_with(deps, move |(state, modified)| {
|
||||
on_form_change.emit(ConfigForm::IpCheck(*modified, state.form.clone()));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -49,8 +49,9 @@ pub fn MainConfigView() -> Html {
|
||||
|
||||
{
|
||||
let on_form_change = config_view_ctx.on_form_change.clone();
|
||||
use_effect_with(form_state.clone(), move |state| {
|
||||
on_form_change.emit(ConfigForm::Main(state.modified, state.form.clone()));
|
||||
let deps = (form_state.clone(), form_state.modified);
|
||||
use_effect_with(deps, move |(state, modified)| {
|
||||
on_form_change.emit(ConfigForm::Main(*modified, state.form.clone()));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
use std::rc::Rc;
|
||||
use std::str::FromStr;
|
||||
use crate::app::components::{Card, Chip, RadioButtonGroup};
|
||||
use crate::app::context::ConfigContext;
|
||||
use crate::{config_field, config_field_child, config_field_empty, config_field_hide, config_field_optional, edit_field_list, edit_field_text, edit_field_text_option, generate_form_reducer};
|
||||
use shared::model::{MessagingConfigDto, MsgKind, PushoverMessagingConfigDto, RestMessagingConfigDto,
|
||||
TelegramMessagingConfigDto};
|
||||
use yew::prelude::*;
|
||||
use yew_i18n::use_translation;
|
||||
use crate::app::components::config::config_page::ConfigForm;
|
||||
use crate::app::components::config::config_view_context::ConfigViewContext;
|
||||
use crate::app::components::config::macros::HasFormData;
|
||||
use crate::app::components::{Card, Chip, RadioButtonGroup};
|
||||
use crate::app::context::ConfigContext;
|
||||
use crate::{
|
||||
config_field, config_field_child, config_field_empty, config_field_hide, config_field_optional,
|
||||
edit_field_list, edit_field_text, edit_field_text_option, generate_form_reducer,
|
||||
};
|
||||
use shared::model::{
|
||||
MessagingConfigDto, MsgKind, PushoverMessagingConfigDto, RestMessagingConfigDto,
|
||||
TelegramMessagingConfigDto,
|
||||
};
|
||||
use std::rc::Rc;
|
||||
use std::str::FromStr;
|
||||
use yew::prelude::*;
|
||||
use yew_i18n::use_translation;
|
||||
|
||||
const LABEL_NOTIFY_ON: &str = "LABEL.NOTIFY_ON";
|
||||
const LABEL_TELEGRAM: &str = "LABEL.TELEGRAM";
|
||||
@@ -56,34 +61,43 @@ generate_form_reducer!(
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
#[function_component]
|
||||
pub fn MessagingConfigView() -> Html {
|
||||
let translate = use_translation();
|
||||
let config_ctx = use_context::<ConfigContext>().expect("ConfigContext not found");
|
||||
let config_view_ctx = use_context::<ConfigViewContext>().expect("ConfigViewContext not found");
|
||||
|
||||
let telegram_state: UseReducerHandle<TelegramMessagingConfigFormState> = use_reducer(|| {
|
||||
TelegramMessagingConfigFormState { form: TelegramMessagingConfigDto::default(), modified: false }
|
||||
});
|
||||
let rest_state: UseReducerHandle<RestMessagingConfigFormState> = use_reducer(|| {
|
||||
RestMessagingConfigFormState { form: RestMessagingConfigDto::default(), modified: false }
|
||||
});
|
||||
let telegram_state: UseReducerHandle<TelegramMessagingConfigFormState> =
|
||||
use_reducer(|| TelegramMessagingConfigFormState {
|
||||
form: TelegramMessagingConfigDto::default(),
|
||||
modified: false,
|
||||
});
|
||||
let rest_state: UseReducerHandle<RestMessagingConfigFormState> =
|
||||
use_reducer(|| RestMessagingConfigFormState {
|
||||
form: RestMessagingConfigDto::default(),
|
||||
modified: false,
|
||||
});
|
||||
|
||||
let pushover_state: UseReducerHandle<PushoverMessagingConfigFormState> = use_reducer(|| {
|
||||
PushoverMessagingConfigFormState { form: PushoverMessagingConfigDto::default(), modified: false }
|
||||
});
|
||||
let pushover_state: UseReducerHandle<PushoverMessagingConfigFormState> =
|
||||
use_reducer(|| PushoverMessagingConfigFormState {
|
||||
form: PushoverMessagingConfigDto::default(),
|
||||
modified: false,
|
||||
});
|
||||
|
||||
let messaging_state: UseReducerHandle<MessagingConfigFormState> = use_reducer(|| {
|
||||
MessagingConfigFormState { form: MessagingConfigDto::default(), modified: false }
|
||||
});
|
||||
let messaging_state: UseReducerHandle<MessagingConfigFormState> =
|
||||
use_reducer(|| MessagingConfigFormState {
|
||||
form: MessagingConfigDto::default(),
|
||||
modified: false,
|
||||
});
|
||||
|
||||
let notify_on_options = use_memo((), |_| vec![
|
||||
MsgKind::Info.to_string(),
|
||||
MsgKind::Stats.to_string(),
|
||||
MsgKind::Error.to_string(),
|
||||
MsgKind::Watch.to_string(),
|
||||
]);
|
||||
let notify_on_options = use_memo((), |_| {
|
||||
vec![
|
||||
MsgKind::Info.to_string(),
|
||||
MsgKind::Stats.to_string(),
|
||||
MsgKind::Error.to_string(),
|
||||
MsgKind::Watch.to_string(),
|
||||
]
|
||||
});
|
||||
|
||||
{
|
||||
let on_form_change = config_view_ctx.on_form_change.clone();
|
||||
@@ -92,87 +106,88 @@ pub fn MessagingConfigView() -> Html {
|
||||
let rest_state = rest_state.clone();
|
||||
let pushover_state = pushover_state.clone();
|
||||
|
||||
use_effect_with(
|
||||
(messaging_state, telegram_state, rest_state, pushover_state),
|
||||
move |(m, t, r, p)| {
|
||||
let mut form = m.form.clone();
|
||||
form.telegram = Some(t.form.clone());
|
||||
form.rest = Some(r.form.clone());
|
||||
form.pushover = Some(p.form.clone());
|
||||
|
||||
let modified = m.modified || t.modified || r.modified || p.modified;
|
||||
on_form_change.emit(ConfigForm::Messaging(modified, form));
|
||||
},
|
||||
let deps = (
|
||||
messaging_state.modified,
|
||||
telegram_state.modified,
|
||||
rest_state.modified,
|
||||
pushover_state.modified,
|
||||
messaging_state,
|
||||
telegram_state,
|
||||
rest_state,
|
||||
pushover_state,
|
||||
);
|
||||
use_effect_with(deps, move |(mm, tm, rm, pm, m, t, r, p)| {
|
||||
let mut form = m.form.clone();
|
||||
form.telegram = Some(t.form.clone());
|
||||
form.rest = Some(r.form.clone());
|
||||
form.pushover = Some(p.form.clone());
|
||||
|
||||
let modified = *mm || *tm || *rm || *pm;
|
||||
on_form_change.emit(ConfigForm::Messaging(modified, form));
|
||||
});
|
||||
}
|
||||
|
||||
let render_telegram = |telegram: Option<&TelegramMessagingConfigDto>| {
|
||||
match telegram {
|
||||
Some(entry) => html! {
|
||||
<Card class="tp__config-view__card">
|
||||
<h1>{translate.t("LABEL.TELEGRAM")}</h1>
|
||||
{ config_field!(entry, translate.t(LABEL_BOT_TOKEN), bot_token) }
|
||||
{ config_field_child!(translate.t(LABEL_CHAT_IDS), {
|
||||
html! {
|
||||
<div class="tp__config-view__tags">
|
||||
{
|
||||
if entry.chat_ids.is_empty() {
|
||||
html! {}
|
||||
} else {
|
||||
html! { for entry.chat_ids.iter().map(|t| html! { <Chip label={t.clone()} /> }) }
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
})}
|
||||
</Card>
|
||||
},
|
||||
None => html! {
|
||||
<Card class="tp__config-view__card">
|
||||
<h1>{translate.t(LABEL_TELEGRAM)}</h1>
|
||||
{ config_field_empty!(translate.t(LABEL_BOT_TOKEN)) }
|
||||
{ config_field_empty!(translate.t(LABEL_CHAT_IDS)) }
|
||||
</Card>
|
||||
},
|
||||
}
|
||||
let render_telegram = |telegram: Option<&TelegramMessagingConfigDto>| match telegram {
|
||||
Some(entry) => html! {
|
||||
<Card class="tp__config-view__card">
|
||||
<h1>{translate.t("LABEL.TELEGRAM")}</h1>
|
||||
{ config_field!(entry, translate.t(LABEL_BOT_TOKEN), bot_token) }
|
||||
{ config_field_child!(translate.t(LABEL_CHAT_IDS), {
|
||||
html! {
|
||||
<div class="tp__config-view__tags">
|
||||
{
|
||||
if entry.chat_ids.is_empty() {
|
||||
html! {}
|
||||
} else {
|
||||
html! { for entry.chat_ids.iter().map(|t| html! { <Chip label={t.clone()} /> }) }
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
})}
|
||||
</Card>
|
||||
},
|
||||
None => html! {
|
||||
<Card class="tp__config-view__card">
|
||||
<h1>{translate.t(LABEL_TELEGRAM)}</h1>
|
||||
{ config_field_empty!(translate.t(LABEL_BOT_TOKEN)) }
|
||||
{ config_field_empty!(translate.t(LABEL_CHAT_IDS)) }
|
||||
</Card>
|
||||
},
|
||||
};
|
||||
|
||||
let render_rest = |rest: Option<&RestMessagingConfigDto>| {
|
||||
match rest {
|
||||
Some(entry) => html! {
|
||||
<Card class="tp__config-view__card">
|
||||
<h1>{translate.t(LABEL_REST)}</h1>
|
||||
{ config_field!(entry, translate.t(LABEL_URL), url) }
|
||||
</Card>
|
||||
},
|
||||
None => html! {
|
||||
<Card class="tp__config-view__card">
|
||||
<h1>{translate.t(LABEL_REST)}</h1>
|
||||
{ config_field_empty!(translate.t(LABEL_URL)) }
|
||||
</Card>
|
||||
},
|
||||
}
|
||||
let render_rest = |rest: Option<&RestMessagingConfigDto>| match rest {
|
||||
Some(entry) => html! {
|
||||
<Card class="tp__config-view__card">
|
||||
<h1>{translate.t(LABEL_REST)}</h1>
|
||||
{ config_field!(entry, translate.t(LABEL_URL), url) }
|
||||
</Card>
|
||||
},
|
||||
None => html! {
|
||||
<Card class="tp__config-view__card">
|
||||
<h1>{translate.t(LABEL_REST)}</h1>
|
||||
{ config_field_empty!(translate.t(LABEL_URL)) }
|
||||
</Card>
|
||||
},
|
||||
};
|
||||
|
||||
let render_pushover = |pushover: Option<&PushoverMessagingConfigDto>| {
|
||||
match pushover {
|
||||
Some(entry) => html! {
|
||||
<Card class="tp__config-view__card">
|
||||
<h1>{translate.t(LABEL_PUSHOVER)}</h1>
|
||||
{ config_field_optional!(entry, translate.t(LABEL_URL), url) }
|
||||
{ config_field_hide!(entry, translate.t(LABEL_TOKEN), token) }
|
||||
{ config_field!(entry, translate.t(LABEL_USER), user) }
|
||||
</Card>
|
||||
},
|
||||
None => html! {
|
||||
<Card class="tp__config-view__card">
|
||||
<h1>{translate.t(LABEL_PUSHOVER)}</h1>
|
||||
{ config_field_empty!(translate.t(LABEL_URL)) }
|
||||
{ config_field_empty!(translate.t(LABEL_TOKEN)) }
|
||||
{ config_field_empty!(translate.t(LABEL_USER)) }
|
||||
</Card>
|
||||
},
|
||||
}
|
||||
let render_pushover = |pushover: Option<&PushoverMessagingConfigDto>| match pushover {
|
||||
Some(entry) => html! {
|
||||
<Card class="tp__config-view__card">
|
||||
<h1>{translate.t(LABEL_PUSHOVER)}</h1>
|
||||
{ config_field_optional!(entry, translate.t(LABEL_URL), url) }
|
||||
{ config_field_hide!(entry, translate.t(LABEL_TOKEN), token) }
|
||||
{ config_field!(entry, translate.t(LABEL_USER), user) }
|
||||
</Card>
|
||||
},
|
||||
None => html! {
|
||||
<Card class="tp__config-view__card">
|
||||
<h1>{translate.t(LABEL_PUSHOVER)}</h1>
|
||||
{ config_field_empty!(translate.t(LABEL_URL)) }
|
||||
{ config_field_empty!(translate.t(LABEL_TOKEN)) }
|
||||
{ config_field_empty!(translate.t(LABEL_USER)) }
|
||||
</Card>
|
||||
},
|
||||
};
|
||||
|
||||
let render_empty = || {
|
||||
@@ -194,21 +209,21 @@ pub fn MessagingConfigView() -> Html {
|
||||
if let Some(config) = &config_ctx.config {
|
||||
if let Some(messaging) = &config.config.messaging {
|
||||
html! {
|
||||
<>
|
||||
<div class="tp__messaging-config-view__header tp__config-view-page__header">
|
||||
{ config_field_child!(translate.t(LABEL_NOTIFY_ON), {
|
||||
html! { <div class="tp__messaging-config-view__notify-on">
|
||||
{ for messaging.notify_on.iter().map(|t| html! { <Chip label={t.to_string()} /> }) }
|
||||
</div> }
|
||||
})}
|
||||
</div>
|
||||
<div class="tp__messaging-config-view__body tp__config-view-page__body">
|
||||
{render_telegram(messaging.telegram.as_ref())}
|
||||
{render_rest(messaging.rest.as_ref())}
|
||||
{render_pushover(messaging.pushover.as_ref())}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
<>
|
||||
<div class="tp__messaging-config-view__header tp__config-view-page__header">
|
||||
{ config_field_child!(translate.t(LABEL_NOTIFY_ON), {
|
||||
html! { <div class="tp__messaging-config-view__notify-on">
|
||||
{ for messaging.notify_on.iter().map(|t| html! { <Chip label={t.to_string()} /> }) }
|
||||
</div> }
|
||||
})}
|
||||
</div>
|
||||
<div class="tp__messaging-config-view__body tp__config-view-page__body">
|
||||
{render_telegram(messaging.telegram.as_ref())}
|
||||
{render_rest(messaging.rest.as_ref())}
|
||||
{render_pushover(messaging.pushover.as_ref())}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
} else {
|
||||
render_empty()
|
||||
}
|
||||
@@ -219,47 +234,55 @@ pub fn MessagingConfigView() -> Html {
|
||||
|
||||
let render_edit_mode = || {
|
||||
let msg_state = messaging_state.clone();
|
||||
let notify_on_selections = Rc::new(msg_state.form.notify_on.iter().map(ToString::to_string).collect());
|
||||
let notify_on_selections = Rc::new(
|
||||
msg_state
|
||||
.form
|
||||
.notify_on
|
||||
.iter()
|
||||
.map(ToString::to_string)
|
||||
.collect(),
|
||||
);
|
||||
html! {
|
||||
<>
|
||||
<div class="tp__messaging-config-view__header tp__config-view-page__header">
|
||||
{ config_field_child!(translate.t("LABEL.NOTIFY_ON"), {
|
||||
html! { <RadioButtonGroup
|
||||
multi_select={true} none_allowed={true}
|
||||
on_select={Callback::from(move |selections: Rc<Vec<String>>| {
|
||||
msg_state.dispatch(MessagingConfigFormAction::NotifyOn(
|
||||
selections.iter().filter_map(|s| MsgKind::from_str(s).ok()).collect()));
|
||||
})}
|
||||
options={notify_on_options.clone()}
|
||||
selected={notify_on_selections}
|
||||
/>
|
||||
}})}
|
||||
</div>
|
||||
<div class="tp__messaging-config-view__body tp__config-view-page__body">
|
||||
<Card class="tp__config-view__card">
|
||||
<h1>{translate.t(LABEL_TELEGRAM)}</h1>
|
||||
{ edit_field_text!(telegram_state, translate.t(LABEL_BOT_TOKEN), bot_token, TelegramMessagingConfigFormAction::BotToken) }
|
||||
{ edit_field_list!(telegram_state, translate.t(LABEL_CHAT_IDS), chat_ids, TelegramMessagingConfigFormAction::ChatIds, translate.t("LABEL.ADD_CHAT_ID")) }
|
||||
</Card>
|
||||
<>
|
||||
<div class="tp__messaging-config-view__header tp__config-view-page__header">
|
||||
{ config_field_child!(translate.t("LABEL.NOTIFY_ON"), {
|
||||
html! { <RadioButtonGroup
|
||||
multi_select={true} none_allowed={true}
|
||||
on_select={Callback::from(move |selections: Rc<Vec<String>>| {
|
||||
msg_state.dispatch(MessagingConfigFormAction::NotifyOn(
|
||||
selections.iter().filter_map(|s| MsgKind::from_str(s).ok()).collect()));
|
||||
})}
|
||||
options={notify_on_options.clone()}
|
||||
selected={notify_on_selections}
|
||||
/>
|
||||
}})}
|
||||
</div>
|
||||
<div class="tp__messaging-config-view__body tp__config-view-page__body">
|
||||
<Card class="tp__config-view__card">
|
||||
<h1>{translate.t(LABEL_TELEGRAM)}</h1>
|
||||
{ edit_field_text!(telegram_state, translate.t(LABEL_BOT_TOKEN), bot_token, TelegramMessagingConfigFormAction::BotToken) }
|
||||
{ edit_field_list!(telegram_state, translate.t(LABEL_CHAT_IDS), chat_ids, TelegramMessagingConfigFormAction::ChatIds, translate.t("LABEL.ADD_CHAT_ID")) }
|
||||
</Card>
|
||||
|
||||
<Card class="tp__config-view__card">
|
||||
<h1>{translate.t(LABEL_REST)}</h1>
|
||||
{ edit_field_text!(rest_state, translate.t(LABEL_URL), url, RestMessagingConfigFormAction::Url) }
|
||||
</Card>
|
||||
<Card class="tp__config-view__card">
|
||||
<h1>{translate.t(LABEL_REST)}</h1>
|
||||
{ edit_field_text!(rest_state, translate.t(LABEL_URL), url, RestMessagingConfigFormAction::Url) }
|
||||
</Card>
|
||||
|
||||
<Card class="tp__config-view__card">
|
||||
<h1>{translate.t(LABEL_PUSHOVER)}</h1>
|
||||
{ edit_field_text_option!(pushover_state, translate.t(LABEL_URL), url, PushoverMessagingConfigFormAction::Url) }
|
||||
{ edit_field_text!(pushover_state, translate.t(LABEL_TOKEN), token, PushoverMessagingConfigFormAction::Token, true) }
|
||||
{ edit_field_text!(pushover_state, translate.t(LABEL_USER), user, PushoverMessagingConfigFormAction::User) }
|
||||
</Card>
|
||||
</div>
|
||||
</>
|
||||
}};
|
||||
<Card class="tp__config-view__card">
|
||||
<h1>{translate.t(LABEL_PUSHOVER)}</h1>
|
||||
{ edit_field_text_option!(pushover_state, translate.t(LABEL_URL), url, PushoverMessagingConfigFormAction::Url) }
|
||||
{ edit_field_text!(pushover_state, translate.t(LABEL_TOKEN), token, PushoverMessagingConfigFormAction::Token, true) }
|
||||
{ edit_field_text!(pushover_state, translate.t(LABEL_USER), user, PushoverMessagingConfigFormAction::User) }
|
||||
</Card>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
};
|
||||
|
||||
html! {
|
||||
<div class="tp__messaging-config-view tp__config-view-page">
|
||||
{ if *config_view_ctx.edit_mode { render_edit_mode() } else { render_view_mode() } }
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +36,9 @@ pub fn ProxyConfigView() -> Html {
|
||||
|
||||
{
|
||||
let on_form_change = config_view_ctx.on_form_change.clone();
|
||||
use_effect_with(form_state.clone(), move |state| {
|
||||
on_form_change.emit(ConfigForm::Proxy(state.modified, state.form.clone()));
|
||||
let deps = (form_state.clone(), form_state.modified);
|
||||
use_effect_with(deps, move |(state, modified)| {
|
||||
on_form_change.emit(ConfigForm::Proxy(*modified, state.form.clone()));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -123,23 +123,9 @@ pub fn ReverseProxyConfigView() -> Html {
|
||||
use_effect_with((reverse_proxy_cfg, config_view_ctx.edit_mode.clone()), move |(cfg, _mode)| {
|
||||
if let Some(rp) = cfg {
|
||||
reverse_proxy_state.dispatch(ReverseProxyConfigFormAction::SetAll((*rp).clone()));
|
||||
|
||||
if let Some(cache) = &rp.cache {
|
||||
cache_state.dispatch(CacheConfigFormAction::SetAll(cache.clone()));
|
||||
} else {
|
||||
cache_state.dispatch(CacheConfigFormAction::SetAll(CacheConfigDto::default()));
|
||||
}
|
||||
if let Some(rl) = &rp.rate_limit {
|
||||
rate_limit_state.dispatch(RateLimitConfigFormAction::SetAll(rl.clone()));
|
||||
} else {
|
||||
rate_limit_state.dispatch(RateLimitConfigFormAction::SetAll(RateLimitConfigDto::default()));
|
||||
}
|
||||
if let Some(stream) = &rp.stream {
|
||||
stream_state.dispatch(StreamConfigFormAction::SetAll(stream.clone()));
|
||||
} else {
|
||||
stream_state.dispatch(StreamConfigFormAction::SetAll(StreamConfigDto::default()));
|
||||
}
|
||||
|
||||
cache_state.dispatch(CacheConfigFormAction::SetAll(rp.cache.as_ref().map_or_else(CacheConfigDto::default, |c| c.clone())));
|
||||
rate_limit_state.dispatch(RateLimitConfigFormAction::SetAll(rp.rate_limit.as_ref().map_or_else(RateLimitConfigDto::default, |rl| rl.clone())));
|
||||
stream_state.dispatch(StreamConfigFormAction::SetAll(rp.stream.as_ref().map_or_else(StreamConfigDto::default, |s| s.clone())));
|
||||
} else {
|
||||
reverse_proxy_state.dispatch(ReverseProxyConfigFormAction::SetAll(ReverseProxyConfigDto::default()));
|
||||
cache_state.dispatch(CacheConfigFormAction::SetAll(CacheConfigDto::default()));
|
||||
|
||||
@@ -61,8 +61,9 @@ pub fn SchedulesConfigView() -> Html {
|
||||
|
||||
{
|
||||
let on_form_change = config_view_ctx.on_form_change.clone();
|
||||
use_effect_with(form_state.clone(), move |state| {
|
||||
on_form_change.emit(ConfigForm::Schedules(state.modified, state.form.clone()));
|
||||
let deps = (form_state.clone(), form_state.modified);
|
||||
use_effect_with(deps, move |(state, modified)| {
|
||||
on_form_change.emit(ConfigForm::Schedules(*modified, state.form.clone()));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,8 @@ pub fn VideoConfigView() -> Html {
|
||||
let on_form_change = config_view_ctx.on_form_change.clone();
|
||||
let download_state = download_state.clone();
|
||||
let video_state = video_state.clone();
|
||||
use_effect_with((video_state.modified, download_state.modified, video_state, download_state),
|
||||
let deps = (video_state.modified, download_state.modified, video_state, download_state);
|
||||
use_effect_with(deps,
|
||||
move |(vm, dm, v, d)| {
|
||||
let mut form = v.form.clone();
|
||||
form.download = if *dm { Some(d.form.clone()) } else { form.download };
|
||||
|
||||
@@ -79,8 +79,8 @@ pub fn WebUiConfigView() -> Html {
|
||||
let webui_state = webui_state.clone();
|
||||
let auth_state = auth_state.clone();
|
||||
let csp_state = csp_state.clone();
|
||||
|
||||
use_effect_with((webui_state.modified, auth_state.modified, csp_state.modified, webui_state, auth_state, csp_state),
|
||||
let deps = (webui_state.modified, auth_state.modified, csp_state.modified, webui_state, auth_state, csp_state);
|
||||
use_effect_with(deps,
|
||||
move |(wm, am, cm, w, a, c)| {
|
||||
let mut form = w.form.clone();
|
||||
form.auth = Some(a.form.clone());
|
||||
|
||||
@@ -12,6 +12,19 @@ pub struct TabItem {
|
||||
pub inactive_class: Option<String>,
|
||||
}
|
||||
|
||||
// impl TabItem {
|
||||
// pub fn new(id: String, title: String, icon: String, children: Html) -> Self {
|
||||
// Self {
|
||||
// id,
|
||||
// title,
|
||||
// icon,
|
||||
// children,
|
||||
// active_class: None,
|
||||
// inactive_class: None,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Properties, Clone, PartialEq)]
|
||||
pub struct TabSetProps {
|
||||
pub tabs: Rc<Vec<TabItem>>,
|
||||
|
||||
Reference in New Issue
Block a user