[Update] (Affect to backend) Plugin System. Saveable if the plugin is enabled or not.
Add functions that merge plugins data.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { useRef } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import {
|
||||
@@ -29,6 +30,7 @@ export const App = () => {
|
||||
const { currentIsBackendReady } = useIsBackendReady();
|
||||
const { WindowGeometryController } = useWindow();
|
||||
const { i18n } = useTranslation();
|
||||
const fetchPluginsHasRunRef = useRef(false);
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
@@ -44,7 +46,7 @@ export const App = () => {
|
||||
|
||||
{(currentIsBackendReady.data === false || currentIsVrctAvailable.data === false)
|
||||
? <SplashComponent />
|
||||
: <Contents key={i18n.language}/>
|
||||
: <Contents key={i18n.language} fetchPluginsHasRunRef={fetchPluginsHasRunRef} />
|
||||
}
|
||||
|
||||
<SnackbarController />
|
||||
@@ -52,11 +54,11 @@ export const App = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const Contents = () => {
|
||||
const Contents = ({ fetchPluginsHasRunRef }) => {
|
||||
const { currentIsSoftwareUpdating } = useIsSoftwareUpdating();
|
||||
return (
|
||||
<>
|
||||
<PluginsController />
|
||||
<PluginsController fetchPluginsHasRunRef={fetchPluginsHasRunRef} />
|
||||
<SubtitlesController />
|
||||
|
||||
<WindowTitleBar />
|
||||
|
||||
@@ -5,21 +5,80 @@ if (typeof window !== "undefined") {
|
||||
window.React = React;
|
||||
}
|
||||
|
||||
export const PluginsController = () => {
|
||||
const hasRunRef = useRef(false);
|
||||
export const PluginsController = ({ fetchPluginsHasRunRef }) => {
|
||||
const {
|
||||
loadAllPlugins,
|
||||
asyncUpdatePluginInfoList,
|
||||
asyncLoadAllPlugins,
|
||||
asyncFetchPluginsInfo,
|
||||
currentPluginsData,
|
||||
updatePluginsData,
|
||||
currentSavedPluginsStatus,
|
||||
} = usePlugins();
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasRunRef.current) {
|
||||
asyncUpdatePluginInfoList().then(() => {
|
||||
loadAllPlugins();
|
||||
});
|
||||
const loadPlugins = async () => {
|
||||
try {
|
||||
await asyncLoadAllPlugins();
|
||||
const info_array = await asyncFetchPluginsInfo();
|
||||
updatePluginsData(prev => {
|
||||
// Map を利用してそれぞれの配列を plugin_id で参照できるようにする
|
||||
const infoMap = new Map(info_array.map(info => [info.plugin_id, info]));
|
||||
const prevMap = new Map(prev.data.map(item => [item.plugin_id, item]));
|
||||
|
||||
// info_array にある各アイテムについて、prev.data に同じ plugin_id があればマージ
|
||||
const merged = info_array.map(info => {
|
||||
if (prevMap.has(info.plugin_id)) {
|
||||
return { ...info, ...prevMap.get(info.plugin_id) };
|
||||
}
|
||||
return info;
|
||||
});
|
||||
|
||||
// prev.data にのみ存在するアイテムを追加し、is_outdated: true を付与
|
||||
prev.data.forEach(item => {
|
||||
if (!infoMap.has(item.plugin_id)) {
|
||||
merged.push({ ...item, is_outdated: true });
|
||||
}
|
||||
});
|
||||
|
||||
return merged;
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
if (!fetchPluginsHasRunRef.current) {
|
||||
loadPlugins();
|
||||
}
|
||||
return () => hasRunRef.current = true;
|
||||
return () => fetchPluginsHasRunRef.current = true;
|
||||
}, []);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
updatePluginsData(prev => {
|
||||
// currentSavedPluginsStatus.data の各要素を Map 化して plugin_id で参照
|
||||
const savedMap = new Map(currentSavedPluginsStatus.data.map(saved => [saved.plugin_id, saved]));
|
||||
const prevMap = new Map(prev.data.map(item => [item.plugin_id, item]));
|
||||
|
||||
// prev.data にある各アイテムについて、保存済みの状態情報があればマージ
|
||||
const merged = prev.data.map(item => {
|
||||
if (savedMap.has(item.plugin_id)) {
|
||||
return { ...item, is_enabled: savedMap.get(item.plugin_id).is_enabled };
|
||||
}
|
||||
return item;
|
||||
});
|
||||
|
||||
// currentSavedPluginsStatus.data にのみ存在する項目があれば追加
|
||||
currentSavedPluginsStatus.data.forEach(saved => {
|
||||
if (!prevMap.has(saved.plugin_id)) {
|
||||
merged.push({ plugin_id: saved.plugin_id, is_enabled: saved.is_enabled });
|
||||
}
|
||||
});
|
||||
|
||||
return merged;
|
||||
});
|
||||
}, [currentSavedPluginsStatus]);
|
||||
|
||||
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -1,35 +0,0 @@
|
||||
import {
|
||||
SwitchBox,
|
||||
} from "../index";
|
||||
import { _DownloadButton } from "../_atoms/_download_button/_DownloadButton";
|
||||
import styles from "./DownloadPlugins.module.scss";
|
||||
|
||||
export const DownloadPlugins = ({plugin_info, plugin_status, ...props}) => {
|
||||
const option = {
|
||||
id: plugin_info.plugin_id,
|
||||
is_pending: plugin_info.is_pending,
|
||||
is_downloaded: plugin_info.is_downloaded,
|
||||
progress: null,
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
{plugin_info.is_downloaded && plugin_info.is_plugin_supported &&
|
||||
<SwitchBox
|
||||
variable={plugin_status}
|
||||
toggleFunction={plugin_status.toggleFunction}
|
||||
/>}
|
||||
{plugin_info.is_plugin_supported ?
|
||||
<_DownloadButton
|
||||
option={option}
|
||||
downloadStartFunction={props.downloadStartFunction}
|
||||
/>
|
||||
:
|
||||
<div className={styles.unavailable_text}>
|
||||
Downloaded but outdated.
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -12,4 +12,4 @@ export { SwitchBox } from "./switch_box/SwitchBox";
|
||||
export { ThresholdComponent } from "./threshold_component/ThresholdComponent";
|
||||
export { WordFilter, WordFilterListToggleComponent } from "./word_filter/WordFilter";
|
||||
export { DownloadModels } from "./download_models/DownloadModels";
|
||||
export { DownloadPlugins } from "./download_plugins/DownloadPlugins";
|
||||
export { PluginsControlComponent } from "./plugins_control_component/PluginsControlComponent";
|
||||
@@ -0,0 +1,48 @@
|
||||
import {
|
||||
SwitchBox,
|
||||
} from "../index";
|
||||
import { _DownloadButton } from "../_atoms/_download_button/_DownloadButton";
|
||||
import styles from "./PluginsControlComponent.module.scss";
|
||||
|
||||
export const PluginsControlComponent = ({ variable_state, plugin_status, toggleFunction, ...props }) => {
|
||||
const option = {
|
||||
id: plugin_status.plugin_id,
|
||||
is_pending: plugin_status.is_pending,
|
||||
is_downloaded: plugin_status.is_downloaded,
|
||||
data: plugin_status.is_enabled,
|
||||
state: variable_state,
|
||||
progress: null,
|
||||
};
|
||||
|
||||
const adjustedToggleFunction = () => {
|
||||
toggleFunction(plugin_status.plugin_id);
|
||||
};
|
||||
|
||||
let is_turn_on_able = false;
|
||||
if (plugin_status.is_downloaded && plugin_status.is_plugin_supported) {
|
||||
is_turn_on_able = true;
|
||||
}
|
||||
if (plugin_status.is_outdated) {
|
||||
is_turn_on_able = true;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
{is_turn_on_able &&
|
||||
<SwitchBox
|
||||
variable={option}
|
||||
toggleFunction={adjustedToggleFunction}
|
||||
/>}
|
||||
{plugin_status.is_plugin_supported ?
|
||||
<_DownloadButton
|
||||
option={option}
|
||||
downloadStartFunction={props.downloadStartFunction}
|
||||
/>
|
||||
:
|
||||
<div className={styles.unavailable_text}>
|
||||
Downloaded but outdated.
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -22,6 +22,7 @@
|
||||
}
|
||||
|
||||
.toggle_control {
|
||||
position: relative;
|
||||
@include toggle_control_styles;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { usePlugins } from "@logics_configs";
|
||||
import styles from "./Plugins.module.scss";
|
||||
import { DownloadPlugins } from "../_components";
|
||||
import { PluginsControlComponent } from "../_components";
|
||||
|
||||
export const Plugins = () => {
|
||||
return (
|
||||
@@ -14,16 +14,15 @@ export const Plugins = () => {
|
||||
const PluginDownloadContainer = () => {
|
||||
const {
|
||||
downloadAndExtractPlugin,
|
||||
currentPluginsInfoList,
|
||||
updatePluginsInfoList,
|
||||
currentPluginsData,
|
||||
updatePluginsData,
|
||||
currentSavedPluginsStatus,
|
||||
updateSavedPluginsStatus,
|
||||
currentLoadedPluginsList,
|
||||
// updateLoadedPluginsList,
|
||||
setSavedPluginsStatus,
|
||||
} = usePlugins();
|
||||
|
||||
|
||||
const downloadStartFunction = async (target_plugin_id) => {
|
||||
updatePluginsInfoList((old_value) => {
|
||||
updatePluginsData((old_value) => {
|
||||
const new_value = old_value.data.map(d => {
|
||||
if (d.plugin_id === target_plugin_id) {
|
||||
d.is_pending = true;
|
||||
@@ -32,9 +31,9 @@ const PluginDownloadContainer = () => {
|
||||
});
|
||||
return new_value;
|
||||
});
|
||||
const target_plugin_info = currentPluginsInfoList.data.find(d => d.plugin_id === target_plugin_id);
|
||||
const target_plugin_info = currentPluginsData.data.find(d => d.plugin_id === target_plugin_id);
|
||||
downloadAndExtractPlugin(target_plugin_info).then(() => {
|
||||
updatePluginsInfoList((old_value) => {
|
||||
updatePluginsData((old_value) => {
|
||||
const new_value = old_value.data.map(d => {
|
||||
if (d.plugin_id === target_plugin_id) {
|
||||
d.is_pending = false;
|
||||
@@ -46,60 +45,41 @@ const PluginDownloadContainer = () => {
|
||||
});
|
||||
})
|
||||
};
|
||||
// console.log(currentPluginsInfoList.data);
|
||||
|
||||
|
||||
// const plugin_list = currentPluginsInfoList.data;
|
||||
const plugin_list = [...currentPluginsInfoList.data, ...currentLoadedPluginsList.data];
|
||||
// const plugin_list = [
|
||||
// {
|
||||
// title: "VRCT Example Plugins 1",
|
||||
// plugin_id: "vrct_plugin_example_1",
|
||||
// asset_name: "vrct_plugin_example_1.zip",
|
||||
// plugin_version: "0.0.6",
|
||||
// min_supported_vrct_version: "3.0.4",
|
||||
// max_supported_vrct_version: "3.0.6",
|
||||
// is_plugin_supported: true,
|
||||
// // url: manifest_url
|
||||
// },
|
||||
// {
|
||||
// title: "VRCT Example Plugins 2",
|
||||
// plugin_id: "vrct_plugin_example_2",
|
||||
// asset_name: "vrct_plugin_example_2.zip",
|
||||
// plugin_version: "0.0.1",
|
||||
// min_supported_vrct_version: "3.0.4",
|
||||
// max_supported_vrct_version: "3.0.7",
|
||||
// is_plugin_supported: true,
|
||||
// // url: manifest_url
|
||||
// },
|
||||
// ];
|
||||
|
||||
const getTargetPluginStatus = (target_plugin_id) => {
|
||||
let plugin_status = currentSavedPluginsStatus.data.find(d => d.plugin_id === target_plugin_id) ?? {};
|
||||
const is_downloaded = currentLoadedPluginsList.data.find(d => d.plugin_id === target_plugin_id) ? true : false;
|
||||
|
||||
plugin_status.toggleFunction = () => {
|
||||
updateSavedPluginsStatus((old_value) => {
|
||||
const new_value = old_value.data.map(d => {
|
||||
if (d.plugin_id === target_plugin_id) {
|
||||
d.data = !d.data;
|
||||
d.state = "ok";
|
||||
}
|
||||
return d;
|
||||
});
|
||||
return new_value;
|
||||
const toggleFunction = (target_plugin_id) => {
|
||||
const is_exists = currentSavedPluginsStatus.data.some(d => d.plugin_id === target_plugin_id);
|
||||
let new_value = [];
|
||||
if (is_exists) {
|
||||
new_value = currentSavedPluginsStatus.data.map(d => {
|
||||
if (d.plugin_id === target_plugin_id) {
|
||||
d.is_enabled = !d.is_enabled;
|
||||
}
|
||||
return d;
|
||||
});
|
||||
} else {
|
||||
new_value.push(...currentSavedPluginsStatus.data);
|
||||
new_value.push({
|
||||
plugin_id: target_plugin_id,
|
||||
is_enabled: true,
|
||||
});
|
||||
}
|
||||
plugin_status.is_downloaded = is_downloaded;
|
||||
plugin_status.is_pending = false;
|
||||
return plugin_status;
|
||||
};
|
||||
|
||||
|
||||
// currentPluginsData.data で、is_downloaded が true のものだけ残す
|
||||
new_value = new_value.filter(item => {
|
||||
return currentPluginsData.data.some(plugin => plugin.plugin_id === item.plugin_id && plugin.is_downloaded);
|
||||
});
|
||||
|
||||
setSavedPluginsStatus(new_value);
|
||||
}
|
||||
|
||||
const variable_state = currentSavedPluginsStatus.state;
|
||||
|
||||
|
||||
return (
|
||||
<div className={styles.plugins_list_container}>
|
||||
{plugin_list.map((plugin) => (
|
||||
{currentPluginsData.data.map((plugin) => (
|
||||
<div key={plugin.plugin_id} className={styles.plugin_wrapper}>
|
||||
<p className={styles.title}>{plugin.title}</p>
|
||||
<p className={styles.plugin_id}>{plugin.plugin_id}</p>
|
||||
@@ -113,9 +93,10 @@ const PluginDownloadContainer = () => {
|
||||
Compatible: {plugin.min_supported_vrct_version} ~ {plugin.max_supported_vrct_version}
|
||||
</p>
|
||||
</div>
|
||||
<DownloadPlugins
|
||||
plugin_info={plugin}
|
||||
plugin_status={getTargetPluginStatus(plugin.plugin_id)}
|
||||
<PluginsControlComponent
|
||||
variable_state={variable_state}
|
||||
toggleFunction={toggleFunction}
|
||||
plugin_status={plugin}
|
||||
downloadStartFunction={downloadStartFunction}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -2,13 +2,12 @@ import React from "react";
|
||||
import { usePlugins } from "@logics_configs";
|
||||
|
||||
export const PluginHost = () => {
|
||||
const { currentLoadedPluginsList } = usePlugins();
|
||||
// console.log(currentLoadedPluginsList.data);
|
||||
const { currentPluginsData } = usePlugins();
|
||||
|
||||
return (
|
||||
<div>
|
||||
{currentLoadedPluginsList.data
|
||||
.filter((plugin) => plugin.location === "main_section")
|
||||
{currentPluginsData.data
|
||||
.filter((plugin) => plugin.is_enabled && plugin.location === "main_section")
|
||||
.map((plugin, index) => {
|
||||
const PluginComponent = plugin.component;
|
||||
return PluginComponent ? <PluginComponent key={index} /> : null;
|
||||
|
||||
Reference in New Issue
Block a user