[bugfix] Plugins: Add error handling. when error occurred while rendering a plugin, set status disabled and an error.
This commit is contained in:
@@ -270,7 +270,7 @@ config_page:
|
|||||||
label: "WebSocket Port"
|
label: "WebSocket Port"
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
save_success: "Settings have been saved"
|
save_success: "Settings have been saved."
|
||||||
|
|
||||||
plugin_notifications:
|
plugin_notifications:
|
||||||
downloading: Downloading the plugin.
|
downloading: Downloading the plugin.
|
||||||
@@ -282,6 +282,7 @@ plugin_notifications:
|
|||||||
updated_error: Update failed.
|
updated_error: Update failed.
|
||||||
|
|
||||||
disabled_out_of_support: The plugin has been disabled. It's not supported on this VRCT version.
|
disabled_out_of_support: The plugin has been disabled. It's not supported on this VRCT version.
|
||||||
|
disabled_due_to_an_error: "An error was detected while running the plugin. Please report this to the plugin developer."
|
||||||
|
|
||||||
is_enabled: The plugin has enabled.
|
is_enabled: The plugin has enabled.
|
||||||
is_disabled: The plugin has disabled.
|
is_disabled: The plugin has disabled.
|
||||||
@@ -282,6 +282,7 @@ plugin_notifications:
|
|||||||
updated_error: プラグインのアップデートに失敗しました。
|
updated_error: プラグインのアップデートに失敗しました。
|
||||||
|
|
||||||
disabled_out_of_support: 現在のバージョンとの互換性がありません。プラグインを無効にしました。
|
disabled_out_of_support: 現在のバージョンとの互換性がありません。プラグインを無効にしました。
|
||||||
|
disabled_due_to_an_error: プラグイン実行中にエラーを検知しました。プラグイン開発者に報告してください。
|
||||||
|
|
||||||
is_enabled: プラグインを有効にしました。
|
is_enabled: プラグインを有効にしました。
|
||||||
is_disabled: プラグインを無効にしました。
|
is_disabled: プラグインを無効にしました。
|
||||||
@@ -105,7 +105,12 @@ const PluginDownloadContainer = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className={styles.plugin_info_wrapper}>
|
<div className={styles.plugin_info_wrapper}>
|
||||||
{plugin.is_error ? (
|
{plugin.is_error ? (
|
||||||
<p style={{ color: "red" }}>Error: {plugin.error_message}</p>
|
<div>
|
||||||
|
<p style={{ color: "red" }}>{t(`plugin_notifications.${plugin.error_message_type}`)}</p>
|
||||||
|
<p style={{ color: "red" }}>plugin_version: {plugin.downloaded_plugin_info.plugin_version}</p>
|
||||||
|
<p style={{ color: "red" }}>min_supported_vrct_version: {plugin.downloaded_plugin_info.min_supported_vrct_version}</p>
|
||||||
|
<p style={{ color: "red" }}>max_supported_vrct_version: {plugin.downloaded_plugin_info.max_supported_vrct_version}</p>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<PluginsControlComponent
|
<PluginsControlComponent
|
||||||
variable_state={variable_state}
|
variable_state={variable_state}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.4rem;
|
gap: 0.4rem;
|
||||||
max-width: 50%;
|
max-width: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.plugin_info_wrapper {
|
.plugin_info_wrapper {
|
||||||
|
|||||||
@@ -1,13 +1,27 @@
|
|||||||
import React from "react";
|
import { usePlugins } from "@logics_configs";
|
||||||
|
import { ErrorBoundary } from "react-error-boundary";
|
||||||
|
|
||||||
export const PluginHost = ({render_components}) => {
|
export const PluginHost = ({ render_components }) => {
|
||||||
|
const { setErrorPlugin } = usePlugins();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{render_components
|
{render_components.map((plugin, index) => {
|
||||||
.map((plugin, index) => {
|
|
||||||
const PluginComponent = plugin.component;
|
const PluginComponent = plugin.component;
|
||||||
return PluginComponent ? <PluginComponent key={index} /> : null;
|
const plugin_id = plugin.plugin_id;
|
||||||
|
|
||||||
|
return PluginComponent ? (
|
||||||
|
<ErrorBoundary
|
||||||
|
key={plugin_id || index}
|
||||||
|
fallbackRender={() => null}
|
||||||
|
onError={(_error, _info) => {
|
||||||
|
// Disable the plugin on error
|
||||||
|
setErrorPlugin(plugin_id, "disabled_due_to_an_error");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PluginComponent />
|
||||||
|
</ErrorBoundary>
|
||||||
|
) : null;
|
||||||
})}
|
})}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -69,14 +69,14 @@ export const SnackbarController = () => {
|
|||||||
}, 100);
|
}, 100);
|
||||||
};
|
};
|
||||||
|
|
||||||
setContainerKey(prevKey => prevKey + 1);
|
// setContainerKey(prevKey => prevKey + 1);
|
||||||
asyncShowNotification();
|
asyncShowNotification();
|
||||||
|
|
||||||
}, [settings]);
|
}, [settings]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ToastContainer
|
<ToastContainer
|
||||||
key={containerKey}
|
// key={containerKey}
|
||||||
position="bottom-left"
|
position="bottom-left"
|
||||||
transition={CustomTransition}
|
transition={CustomTransition}
|
||||||
hideProgressBar={false}
|
hideProgressBar={false}
|
||||||
|
|||||||
@@ -282,44 +282,57 @@ export const usePlugins = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleSavedPluginsStatus = (target_plugin_id) => {
|
const setSavedPluginEnabled = (target_plugin_id, is_enabled) => {
|
||||||
const successPluginNotification = (message) => showNotification_Success(message, {
|
const notify = () => {
|
||||||
|
const msg_key = is_enabled
|
||||||
|
? "plugin_notifications.is_enabled"
|
||||||
|
: "plugin_notifications.is_disabled";
|
||||||
|
showNotification_Success(t(msg_key), {
|
||||||
hide_duration: 1000,
|
hide_duration: 1000,
|
||||||
category_id: "to_enable_plugin"
|
category_id: "switch_enable_plugin",
|
||||||
});
|
});
|
||||||
const is_exists = currentSavedPluginsStatus.data.some(
|
}
|
||||||
|
|
||||||
|
const exists = currentSavedPluginsStatus.data.some(
|
||||||
(d) => d.plugin_id === target_plugin_id
|
(d) => d.plugin_id === target_plugin_id
|
||||||
);
|
);
|
||||||
|
|
||||||
let new_value = [];
|
let new_value = [];
|
||||||
if (is_exists) {
|
|
||||||
|
if (exists) {
|
||||||
new_value = currentSavedPluginsStatus.data.map((d) => {
|
new_value = currentSavedPluginsStatus.data.map((d) => {
|
||||||
if (d.plugin_id === target_plugin_id) {
|
if (d.plugin_id === target_plugin_id) {
|
||||||
d.is_enabled = !d.is_enabled;
|
d.is_enabled = is_enabled;
|
||||||
(d.is_enabled)
|
notify();
|
||||||
? successPluginNotification(t("plugin_notifications.is_enabled"))
|
|
||||||
: successPluginNotification(t("plugin_notifications.is_disabled"));
|
|
||||||
}
|
}
|
||||||
return d;
|
return d;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
new_value.push(...currentSavedPluginsStatus.data);
|
// 存在しない場合は追加
|
||||||
new_value.push({
|
new_value = [
|
||||||
plugin_id: target_plugin_id,
|
...currentSavedPluginsStatus.data,
|
||||||
is_enabled: true,
|
{ plugin_id: target_plugin_id, is_enabled: is_enabled }
|
||||||
});
|
];
|
||||||
successPluginNotification(t("plugin_notifications.is_enabled"))
|
notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 「currentPluginsData.data」でis_downloadedがtrueのものだけ残す
|
// ダウンロード済みプラグインのみ残す
|
||||||
new_value = new_value.filter((item) =>
|
new_value = new_value.filter((item) =>
|
||||||
currentPluginsData.data.some(
|
currentPluginsData.data.some(
|
||||||
(plugin) => plugin.plugin_id === item.plugin_id && plugin.is_downloaded
|
(p) => p.plugin_id === item.plugin_id && p.is_downloaded
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
setSavedPluginsStatus(new_value);
|
setSavedPluginsStatus(new_value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleSavedPluginsStatus = (plugin_id) => {
|
||||||
|
// 現在の状態を探す(未登録なら false とみなす)
|
||||||
|
const current = currentSavedPluginsStatus.data.find(
|
||||||
|
(d) => d.plugin_id === plugin_id
|
||||||
|
)?.is_enabled ?? false;
|
||||||
|
setSavedPluginEnabled(plugin_id, !current);
|
||||||
|
};
|
||||||
|
|
||||||
// Init時の処理 非対応のものを無効化する際に、savedDPluginsStatusから不要なものを削除する処理が邪魔になるので該当コードを削除したバージョン。Init以外で使用する時にはリファクタが必要になる。
|
// Init時の処理 非対応のものを無効化する際に、savedDPluginsStatusから不要なものを削除する処理が邪魔になるので該当コードを削除したバージョン。Init以外で使用する時にはリファクタが必要になる。
|
||||||
const setTargetSavedPluginsStatus_Init = (target_plugin_id, is_enabled) => {
|
const setTargetSavedPluginsStatus_Init = (target_plugin_id, is_enabled) => {
|
||||||
@@ -380,6 +393,15 @@ export const usePlugins = () => {
|
|||||||
showNotification_SaveSuccess();
|
showNotification_SaveSuccess();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const setErrorPlugin = (plugin_id, error_message_type) => {
|
||||||
|
const error_message = t("plugin_notifications.disabled_due_to_an_error");
|
||||||
|
|
||||||
|
setSavedPluginEnabled(plugin_id, false);
|
||||||
|
updateTargetPluginData(plugin_id, "is_error", true);
|
||||||
|
updateTargetPluginData(plugin_id, "error_message_type", error_message_type);
|
||||||
|
showNotification_Error(error_message);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
asyncFetchPluginsInfo,
|
asyncFetchPluginsInfo,
|
||||||
@@ -406,11 +428,15 @@ export const usePlugins = () => {
|
|||||||
currentLoadedPlugins,
|
currentLoadedPlugins,
|
||||||
updateLoadedPlugins,
|
updateLoadedPlugins,
|
||||||
|
|
||||||
|
setSavedPluginEnabled,
|
||||||
toggleSavedPluginsStatus,
|
toggleSavedPluginsStatus,
|
||||||
setTargetSavedPluginsStatus_Init,
|
setTargetSavedPluginsStatus_Init,
|
||||||
setSavedPluginsStatus,
|
setSavedPluginsStatus,
|
||||||
|
|
||||||
|
|
||||||
handlePendingPlugin,
|
handlePendingPlugin,
|
||||||
|
|
||||||
|
setErrorPlugin,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user