mirror of
https://github.com/lifegpc/eh-downloader.git
synced 2026-06-06 05:38:44 +08:00
Remove fresh dashboard
This commit is contained in:
@@ -1,190 +0,0 @@
|
||||
import { Head } from "$fresh/runtime.ts";
|
||||
import { Component, ContextType } from "preact";
|
||||
import { StateUpdater, useEffect, useState } from "preact/hooks";
|
||||
import Icon from "preact-material-components/Icon.js";
|
||||
import List from "preact-material-components/List.js";
|
||||
import TopAppBar from "preact-material-components/TopAppBar.js";
|
||||
import StyleSheet from "../components/StyleSheet.tsx";
|
||||
import { GlobalCtx } from "../components/GlobalContext.tsx";
|
||||
import Settings from "./Settings.tsx";
|
||||
import t, { i18n_map, I18NMap } from "../server/i18n.ts";
|
||||
import TaskManager from "./TaskManager.tsx";
|
||||
import { initState, set_state } from "../server/state.ts";
|
||||
import NewTask from "../components/NewTask.tsx";
|
||||
import { parse_int } from "../server/parse.ts";
|
||||
import { addDarkModeListener, detect_darkmode } from "../server/dark.ts";
|
||||
import { registeServiceWorker } from "../server/sw.ts";
|
||||
import { initCfg } from "../server/cfg.ts";
|
||||
import { load_dmodule } from "../server/dmodule.ts";
|
||||
import CreateRootUser from "../components/CreateRootUser.tsx";
|
||||
import { check_auth_status } from "../server/auth.ts";
|
||||
import Login from "../components/Login.tsx";
|
||||
|
||||
export type ContainerProps = {
|
||||
i18n: I18NMap;
|
||||
lang: string;
|
||||
};
|
||||
|
||||
enum DarkMode {
|
||||
Auto,
|
||||
Light,
|
||||
Dark,
|
||||
}
|
||||
|
||||
function darkmode_next(d: DarkMode) {
|
||||
if (d === DarkMode.Auto) return DarkMode.Light;
|
||||
if (d === DarkMode.Dark) return DarkMode.Auto;
|
||||
return DarkMode.Dark;
|
||||
}
|
||||
|
||||
export default class Container extends Component<ContainerProps> {
|
||||
static contextType = GlobalCtx;
|
||||
declare context: ContextType<typeof GlobalCtx>;
|
||||
render() {
|
||||
i18n_map.value = this.props.i18n;
|
||||
const [display, set_display] = useState(false);
|
||||
const [state, set_state1] = useState("#/");
|
||||
const [darkmode, set_darkmode1] = useState(DarkMode.Auto);
|
||||
const [dmodule_loaded, set_dmodule_loaded] = useState(false);
|
||||
const set_darkmode: StateUpdater<DarkMode> = (u) => {
|
||||
const v = typeof u === "function" ? u(darkmode) : u;
|
||||
set_darkmode1(v);
|
||||
localStorage.setItem("darkmode", JSON.stringify(v));
|
||||
if (v === DarkMode.Auto) {
|
||||
if (detect_darkmode()) {
|
||||
document.body.classList.add("dark-scheme");
|
||||
} else {
|
||||
document.body.classList.remove("dark-scheme");
|
||||
}
|
||||
} else if (v === DarkMode.Dark) {
|
||||
document.body.classList.add("dark-scheme");
|
||||
} else {
|
||||
document.body.classList.remove("dark-scheme");
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
const dm = parse_int(
|
||||
localStorage.getItem("darkmode"),
|
||||
DarkMode.Auto,
|
||||
);
|
||||
set_darkmode1(dm);
|
||||
if (dm === DarkMode.Auto) {
|
||||
if (detect_darkmode()) {
|
||||
document.body.classList.add("dark-scheme");
|
||||
}
|
||||
} else if (dm === DarkMode.Dark) {
|
||||
document.body.classList.add("dark-scheme");
|
||||
}
|
||||
registeServiceWorker("/sw.js", { updateViaCache: "all" }).catch(
|
||||
(e) => {
|
||||
console.error("Failed to registe service worker.");
|
||||
console.error(e);
|
||||
},
|
||||
);
|
||||
initCfg();
|
||||
addDarkModeListener((e) => {
|
||||
if (darkmode === DarkMode.Auto) {
|
||||
if (e.matches) {
|
||||
document.body.classList.add("dark-scheme");
|
||||
} else {
|
||||
document.body.classList.remove("dark-scheme");
|
||||
}
|
||||
}
|
||||
});
|
||||
load_dmodule().then(() => set_dmodule_loaded(true)).catch((e) => {
|
||||
console.error(e);
|
||||
});
|
||||
initState(set_state1);
|
||||
check_auth_status().catch((e) => {
|
||||
console.error(e);
|
||||
});
|
||||
}, []);
|
||||
let main = null;
|
||||
if (dmodule_loaded) {
|
||||
main = (
|
||||
<div class="main">
|
||||
<Settings show={state === "#/settings"} />
|
||||
<TaskManager
|
||||
base="#/task_manager"
|
||||
show={state === "#/task_manager"}
|
||||
/>
|
||||
<NewTask show={state === "#/task_manager/new"} />
|
||||
<CreateRootUser show={state === "#/create_root_user"} />
|
||||
<Login show={state === "#/login"} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<Head>
|
||||
<title>{t("common.title")}</title>
|
||||
<link
|
||||
rel="manifest"
|
||||
href={`/manifest.json?lang=${this.props.lang}`}
|
||||
/>
|
||||
<GlobalCtx.Provider value={this.context}>
|
||||
<StyleSheet href="https://fonts.googleapis.com/icon?family=Material+Icons" />
|
||||
<StyleSheet href="bootstrap/dist/css/bootstrap.min.css" />
|
||||
<StyleSheet href="preact-material-components/style.css" />
|
||||
<StyleSheet href="common.css" />
|
||||
</GlobalCtx.Provider>
|
||||
</Head>
|
||||
<TopAppBar onNav={() => set_display(true)}>
|
||||
<TopAppBar.Row>
|
||||
<TopAppBar.Section align-start>
|
||||
<TopAppBar.Icon navigation>menu</TopAppBar.Icon>
|
||||
<TopAppBar.Title>
|
||||
{t("common.title")}
|
||||
</TopAppBar.Title>
|
||||
</TopAppBar.Section>
|
||||
<TopAppBar.Section align-end>
|
||||
<TopAppBar.Icon
|
||||
onClick={() => {
|
||||
set_darkmode(darkmode_next(darkmode));
|
||||
}}
|
||||
navigation
|
||||
>
|
||||
{darkmode === DarkMode.Auto
|
||||
? "brightness_auto"
|
||||
: darkmode === DarkMode.Dark
|
||||
? "dark_mode"
|
||||
: "light_mode"}
|
||||
</TopAppBar.Icon>
|
||||
<TopAppBar.Icon>more_vert</TopAppBar.Icon>
|
||||
</TopAppBar.Section>
|
||||
</TopAppBar.Row>
|
||||
</TopAppBar>
|
||||
<List class={"nav-menu" + (display ? " open" : "")}>
|
||||
<List.Item onClick={() => set_display(false)}>
|
||||
<Icon>close</Icon>
|
||||
</List.Item>
|
||||
<List.Item
|
||||
onClick={() => {
|
||||
set_display(false);
|
||||
set_state("#/");
|
||||
}}
|
||||
>
|
||||
<Icon>home</Icon>
|
||||
</List.Item>
|
||||
<List.Item
|
||||
onClick={() => {
|
||||
set_display(false);
|
||||
set_state("#/task_manager");
|
||||
}}
|
||||
>
|
||||
<Icon>task</Icon>
|
||||
</List.Item>
|
||||
<List.Item
|
||||
onClick={() => {
|
||||
set_display(false);
|
||||
set_state("#/settings");
|
||||
}}
|
||||
>
|
||||
<Icon>settings</Icon>
|
||||
</List.Item>
|
||||
</List>
|
||||
{main}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,333 +0,0 @@
|
||||
import { Component, ContextType } from "preact";
|
||||
import { useEffect, useRef, useState } from "preact/hooks";
|
||||
import Button from "preact-material-components/Button.js";
|
||||
import Snackbar from "preact-material-components/Snackbar.js";
|
||||
import { tw } from "twind";
|
||||
import { GlobalCtx } from "../components/GlobalContext.tsx";
|
||||
import type { ConfigType } from "../config.ts";
|
||||
import { ThumbnailMethod } from "../config.ts";
|
||||
import SettingsCheckbox from "../components/SettingsCheckbox.tsx";
|
||||
import SettingsContext from "../components/SettingsContext.tsx";
|
||||
import SettingsText from "../components/SettingsText.tsx";
|
||||
import t from "../server/i18n.ts";
|
||||
import SettingsSelect from "../components/SettingsSelect.tsx";
|
||||
import type { _MdDialog, DialogAction } from "../server/md3.ts";
|
||||
import { MdDialog, MdTextButton } from "../server/dmodule.ts";
|
||||
import StringRecordsBox from "../components/StringRecordsBox.tsx";
|
||||
|
||||
export type SettingsProps = {
|
||||
show: boolean;
|
||||
};
|
||||
|
||||
export default class Settings extends Component<SettingsProps> {
|
||||
static contextType = GlobalCtx;
|
||||
declare context: ContextType<typeof GlobalCtx>;
|
||||
render() {
|
||||
if (!this.props.show) return;
|
||||
if (!MdDialog.value) return;
|
||||
if (!MdTextButton.value) return;
|
||||
const Dialog = MdDialog.value;
|
||||
const TextButton = MdTextButton.value;
|
||||
const [settings, set_settings] = useState<ConfigType | undefined>();
|
||||
const [error, set_error] = useState<string | undefined>();
|
||||
const [changed, set_changed] = useState<Set<string>>(new Set());
|
||||
const [new_cookies, set_new_cookies] = useState<string>("");
|
||||
const [disabled, set_disabled] = useState(false);
|
||||
const fetchSettings = async () => {
|
||||
const re = await fetch("/api/config");
|
||||
set_settings(await re.json());
|
||||
set_changed(new Set());
|
||||
set_new_cookies("");
|
||||
};
|
||||
const saveSettings = async () => {
|
||||
if (!settings) return;
|
||||
const s: Record<string, unknown> = settings;
|
||||
const d: Record<string, unknown> = {};
|
||||
for (const i of changed) {
|
||||
if (i === "cookies") d[i] = new_cookies;
|
||||
else d[i] = s[i];
|
||||
}
|
||||
const re = await fetch("/api/config", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(d),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
const r = await re.json();
|
||||
set_changed(new Set());
|
||||
set_new_cookies("");
|
||||
return r;
|
||||
};
|
||||
const loadData = () => {
|
||||
fetchSettings().catch((e) => {
|
||||
set_error(t("settings.failed"));
|
||||
console.error(e);
|
||||
});
|
||||
};
|
||||
useEffect(loadData, []);
|
||||
const snack = useRef<Snackbar>();
|
||||
const show_snack = (message: string) => {
|
||||
snack.current?.MDComponent?.show({ message });
|
||||
};
|
||||
let data;
|
||||
if (error) {
|
||||
show_snack(error);
|
||||
data = <div class={tw`text-red-500`}>{error}</div>;
|
||||
} else if (settings) {
|
||||
const ref = useRef<SettingsText<"text">>();
|
||||
const dlg = useRef<_MdDialog>();
|
||||
const showDlg = () => {
|
||||
if (!changed.size) {
|
||||
show_snack(t("settings.no_changed"));
|
||||
return;
|
||||
}
|
||||
dlg.current?.show();
|
||||
};
|
||||
const save = () => {
|
||||
set_disabled(true);
|
||||
saveSettings().then((d) => {
|
||||
set_disabled(false);
|
||||
show_snack(
|
||||
t("settings.saved") +
|
||||
(d.is_unsafe ? t("settings.need_restart") : ""),
|
||||
);
|
||||
loadData();
|
||||
}).catch((e) => {
|
||||
set_disabled(false);
|
||||
show_snack(t("settings.failed"));
|
||||
console.error(e);
|
||||
});
|
||||
};
|
||||
data = (
|
||||
<div class="settings">
|
||||
<SettingsContext
|
||||
set_changed={set_changed}
|
||||
set_settings={set_settings}
|
||||
>
|
||||
<div class="check-box">
|
||||
<SettingsCheckbox
|
||||
name="download_original_img"
|
||||
checked={settings.download_original_img}
|
||||
description={t(
|
||||
"settings.download_original_img",
|
||||
)}
|
||||
/>
|
||||
<SettingsCheckbox
|
||||
name="ex"
|
||||
checked={settings.ex}
|
||||
description={t("settings.ex")}
|
||||
/>
|
||||
<SettingsCheckbox
|
||||
name="mpv"
|
||||
checked={settings.mpv}
|
||||
description={t("settings.mpv")}
|
||||
/>
|
||||
<SettingsCheckbox
|
||||
name="export_zip_jpn_title"
|
||||
checked={settings.export_zip_jpn_title}
|
||||
description={t("settings.export_zip_jpn_title")}
|
||||
/>
|
||||
<SettingsCheckbox
|
||||
name="remove_previous_gallery"
|
||||
checked={settings.remove_previous_gallery}
|
||||
description={t(
|
||||
"settings.remove_previous_gallery",
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div class="text-box">
|
||||
<SettingsSelect
|
||||
name="thumbnail_method"
|
||||
list={[{
|
||||
value: ThumbnailMethod.FFMPEG_BINARY,
|
||||
text: t("settings.thumbnail_method0"),
|
||||
}, {
|
||||
value: ThumbnailMethod.FFMPEG_API,
|
||||
text: t("settings.thumbnail_method1"),
|
||||
}]}
|
||||
description={t("settings.thumbnail_method")}
|
||||
selectedIndex={settings.thumbnail_method}
|
||||
/>
|
||||
<SettingsText
|
||||
name="port"
|
||||
value={settings.port}
|
||||
description={t("settings.port")}
|
||||
type="number"
|
||||
min={0}
|
||||
max={65535}
|
||||
outlined={true}
|
||||
/>
|
||||
<SettingsText
|
||||
name="base"
|
||||
value={settings.base}
|
||||
description={t("settings.base")}
|
||||
type="text"
|
||||
outlined={true}
|
||||
/>
|
||||
<div class="ua">
|
||||
<SettingsText
|
||||
name="ua"
|
||||
value={settings.ua ? settings.ua : ""}
|
||||
description={t("settings.ua")}
|
||||
type="text"
|
||||
outlined={true}
|
||||
ref={ref}
|
||||
>
|
||||
</SettingsText>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (ref.current) {
|
||||
const ua = navigator.userAgent;
|
||||
const t = ref.current;
|
||||
t.update(ua);
|
||||
t.set_value(ua);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t("settings.ua_now")}
|
||||
</Button>
|
||||
</div>
|
||||
<SettingsText
|
||||
name="max_task_count"
|
||||
value={settings.max_task_count}
|
||||
description={t("settings.max_task_count")}
|
||||
type="number"
|
||||
min={1}
|
||||
outlined={true}
|
||||
/>
|
||||
<SettingsText
|
||||
name="max_retry_count"
|
||||
value={settings.max_retry_count}
|
||||
description={t("settings.max_retry_count")}
|
||||
type="number"
|
||||
min={1}
|
||||
outlined={true}
|
||||
/>
|
||||
<SettingsText
|
||||
name="max_download_img_count"
|
||||
value={settings.max_download_img_count}
|
||||
description={t(
|
||||
"settings.max_download_img_count",
|
||||
)}
|
||||
type="number"
|
||||
min={1}
|
||||
outlined={true}
|
||||
/>
|
||||
<SettingsText
|
||||
name="db_path"
|
||||
value={settings.db_path || ""}
|
||||
type="text"
|
||||
description={t("settings.db_path")}
|
||||
helpertext={t("settings.db_path_help")}
|
||||
outlined={true}
|
||||
/>
|
||||
<SettingsText
|
||||
name="hostname"
|
||||
value={settings.hostname}
|
||||
description={t("settings.hostname")}
|
||||
type="text"
|
||||
outlined={true}
|
||||
/>
|
||||
<SettingsText
|
||||
name="meili_host"
|
||||
value={settings.meili_host || ""}
|
||||
description={t("settings.meili_host")}
|
||||
type="text"
|
||||
outlined={true}
|
||||
/>
|
||||
<SettingsText
|
||||
name="meili_update_api_key"
|
||||
value={settings.meili_update_api_key || ""}
|
||||
description={t("settings.meili_update_api_key")}
|
||||
type="text"
|
||||
outlined={true}
|
||||
/>
|
||||
<SettingsText
|
||||
name="meili_search_api_key"
|
||||
value={settings.meili_search_api_key || ""}
|
||||
description={t("settings.meili_search_api_key")}
|
||||
type="text"
|
||||
outlined={true}
|
||||
/>
|
||||
<SettingsText
|
||||
name="ffmpeg_path"
|
||||
value={settings.ffmpeg_path}
|
||||
description={t("settings.ffmpeg_path")}
|
||||
type="text"
|
||||
outlined={true}
|
||||
/>
|
||||
<SettingsText
|
||||
name="cookies"
|
||||
value={new_cookies}
|
||||
description={t("settings.cookies")}
|
||||
type="text"
|
||||
set_value={set_new_cookies}
|
||||
label={t(
|
||||
`settings.enter${
|
||||
settings.cookies ? "_new" : ""
|
||||
}_cookies`,
|
||||
)}
|
||||
outlined={true}
|
||||
/>
|
||||
<SettingsText
|
||||
name="img_verify_secret"
|
||||
value={settings.img_verify_secret || ""}
|
||||
description={t("settings.img_verify_secret")}
|
||||
type="text"
|
||||
outlined={true}
|
||||
/>
|
||||
<div>
|
||||
<label style={{ display: "block" }}>
|
||||
{t("settings.meili_hosts")}
|
||||
</label>
|
||||
<StringRecordsBox
|
||||
value={settings.meili_hosts || {}}
|
||||
sign=":"
|
||||
set_value={(_) => {
|
||||
set_changed((v) => {
|
||||
v.add("meili_hosts");
|
||||
return v;
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</SettingsContext>
|
||||
<Button onClick={loadData}>{t("common.reload")}</Button>
|
||||
<Button onClick={showDlg} disabled={disabled}>
|
||||
{t("common.save")}
|
||||
</Button>
|
||||
<Dialog
|
||||
/**@ts-ignore */
|
||||
ref={dlg}
|
||||
onclosed={(ev) => {
|
||||
const e = ev as CustomEvent<DialogAction>;
|
||||
if (e.detail.action === "yes") {
|
||||
save();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span slot="headline">{t("settings.save_dlg")}</span>
|
||||
<div slot="footer">
|
||||
<TextButton dialog-action="yes">
|
||||
{t("common.yes")}
|
||||
</TextButton>
|
||||
<TextButton dialog-action="close">
|
||||
{t("common.no")}
|
||||
</TextButton>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
data = <div class={tw`text-red-500`}>{t("common.loading")}</div>;
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
{data}
|
||||
<Snackbar ref={snack} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,212 +0,0 @@
|
||||
import { Component, ContextType } from "preact";
|
||||
import { useEffect, useRef, useState } from "preact/hooks";
|
||||
import { signal } from "@preact/signals";
|
||||
import { GlobalCtx } from "../components/GlobalContext.tsx";
|
||||
import type { TaskDetail } from "../task.ts";
|
||||
import { TaskStatus } from "../task.ts";
|
||||
import { Sortable } from "sortable";
|
||||
import type {
|
||||
TaskClientSocketData,
|
||||
TaskServerSocketData,
|
||||
} from "../server/task.ts";
|
||||
import { get_ws_host } from "../server/utils.ts";
|
||||
import Task from "../components/Task.tsx";
|
||||
import Fab from "preact-material-components/Fab.js";
|
||||
import Icon from "preact-material-components/Icon.js";
|
||||
import { set_state } from "../server/state.ts";
|
||||
import t from "../server/i18n.ts";
|
||||
import { TaskFilterBar, TaskStatusFlag } from "../components/TaskFilterBar.tsx";
|
||||
|
||||
export type TaskManagerProps = {
|
||||
base: string;
|
||||
show: boolean;
|
||||
};
|
||||
|
||||
const tasks = signal(new Map<number, TaskDetail>());
|
||||
const task_list = signal(new Array<number>());
|
||||
export const task_ws = signal<WebSocket | undefined>(undefined);
|
||||
export function sendTaskMessage(mes: TaskClientSocketData) {
|
||||
const ws = task_ws.value;
|
||||
if (ws && ws.readyState === ws.OPEN) {
|
||||
ws.send(JSON.stringify(mes));
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
type SortableEvent = CustomEvent & {
|
||||
oldIndex: number | undefined;
|
||||
newIndex: number | undefined;
|
||||
};
|
||||
|
||||
export default class TaskManager extends Component<TaskManagerProps> {
|
||||
static contextType = GlobalCtx;
|
||||
declare context: ContextType<typeof GlobalCtx>;
|
||||
sortable?: Sortable;
|
||||
render() {
|
||||
const ul = useRef<HTMLDivElement>();
|
||||
useEffect(() => {
|
||||
if (!this.props.show) {
|
||||
this.sortable?.destroy();
|
||||
this.sortable = undefined;
|
||||
return;
|
||||
}
|
||||
this.sortable = new Sortable(ul.current, {
|
||||
handle: ".task_handle",
|
||||
onSort: (evt: SortableEvent) => {
|
||||
if (
|
||||
evt.newIndex === undefined || evt.oldIndex === undefined
|
||||
) return;
|
||||
const tl = task_list.value;
|
||||
tl.splice(evt.newIndex, 0, tl.splice(evt.oldIndex, 1)[0]);
|
||||
},
|
||||
});
|
||||
}, [this.props.show]);
|
||||
useEffect(() => {
|
||||
const ws = new WebSocket(`${get_ws_host()}/api/task`);
|
||||
console.log(ws);
|
||||
task_ws.value = ws;
|
||||
function sendMessage(mes: TaskClientSocketData) {
|
||||
ws.send(JSON.stringify(mes));
|
||||
}
|
||||
ws.onopen = () => {
|
||||
sendMessage({ type: "task_list" });
|
||||
};
|
||||
ws.onmessage = (e) => {
|
||||
const t: TaskServerSocketData = JSON.parse(e.data);
|
||||
function sendTaskChangedEvent(id: number) {
|
||||
self.dispatchEvent(
|
||||
new CustomEvent("task_changed", { detail: id }),
|
||||
);
|
||||
}
|
||||
if (t.type == "close") {
|
||||
ws.close();
|
||||
} else if (t.type == "tasks") {
|
||||
let running_index = -1;
|
||||
t.tasks.forEach((ta) => {
|
||||
const is_running = t.running.includes(ta.id);
|
||||
tasks.value.set(ta.id, {
|
||||
base: ta,
|
||||
status: is_running
|
||||
? TaskStatus.Running
|
||||
: TaskStatus.Wait,
|
||||
});
|
||||
const tl = task_list.value;
|
||||
if (!tl.includes(ta.id)) {
|
||||
tl.push(ta.id);
|
||||
if (is_running) {
|
||||
if (tl.length) {
|
||||
tl.splice(
|
||||
running_index + 1,
|
||||
0,
|
||||
tl.splice(tl.length - 1, 1)[0],
|
||||
);
|
||||
}
|
||||
running_index += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.forceUpdate();
|
||||
} else if (t.type == "new_task") {
|
||||
tasks.value.set(t.detail.id, {
|
||||
base: t.detail,
|
||||
status: TaskStatus.Wait,
|
||||
});
|
||||
if (!task_list.value.includes(t.detail.id)) {
|
||||
task_list.value.push(t.detail.id);
|
||||
}
|
||||
this.forceUpdate();
|
||||
} else if (t.type == "task_started") {
|
||||
const task = tasks.value.get(t.detail.id);
|
||||
if (task === undefined) {
|
||||
tasks.value.set(t.detail.id, {
|
||||
base: t.detail,
|
||||
status: TaskStatus.Running,
|
||||
});
|
||||
const tl = task_list.value;
|
||||
if (!tl.includes(t.detail.id)) {
|
||||
tl.push(t.detail.id);
|
||||
if (tl.length) {
|
||||
tl.splice(0, 0, tl.splice(tl.length - 1, 1)[0]);
|
||||
}
|
||||
}
|
||||
this.forceUpdate();
|
||||
} else {
|
||||
task.status = TaskStatus.Running;
|
||||
sendTaskChangedEvent(t.detail.id);
|
||||
const tl = task_list.value;
|
||||
const ind = tl.indexOf(task.base.id);
|
||||
if (ind > 0) {
|
||||
tl.splice(0, 0, tl.splice(ind, 1)[0]);
|
||||
this.sortable?.sort(tl.map((t) => t.toString()));
|
||||
}
|
||||
}
|
||||
} else if (t.type == "task_finished") {
|
||||
const task = tasks.value.get(t.detail.id);
|
||||
if (task !== undefined) {
|
||||
task.status = TaskStatus.Finished;
|
||||
sendTaskChangedEvent(t.detail.id);
|
||||
const tl = task_list.value;
|
||||
const ind = tl.indexOf(task.base.id);
|
||||
if (ind < tl.length - 1 && ind > -1) {
|
||||
tl.splice(tl.length - 1, 0, tl.splice(ind, 1)[0]);
|
||||
this.sortable?.sort(tl.map((t) => t.toString()));
|
||||
}
|
||||
}
|
||||
} else if (t.type == "task_progress") {
|
||||
const task = tasks.value.get(t.detail.task_id);
|
||||
if (task !== undefined) {
|
||||
task.progress = t.detail.detail;
|
||||
sendTaskChangedEvent(t.detail.task_id);
|
||||
}
|
||||
} else if (t.type == "task_updated") {
|
||||
const task = tasks.value.get(t.detail.id);
|
||||
if (task) {
|
||||
task.base = t.detail;
|
||||
}
|
||||
} else if (t.type === "task_error") {
|
||||
const task = tasks.value.get(t.detail.task.id);
|
||||
if (task) {
|
||||
task.status = TaskStatus.Failed;
|
||||
task.error = t.detail.error;
|
||||
task.fataled = t.detail.fatal;
|
||||
sendTaskChangedEvent(task.base.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
self.addEventListener("beforeunload", () => {
|
||||
sendMessage({ type: "close" });
|
||||
});
|
||||
}, []);
|
||||
if (!this.props.show) return null;
|
||||
const [flags, set_flags] = useState(TaskStatusFlag.All);
|
||||
return (
|
||||
<div class="task_manager">
|
||||
<Fab
|
||||
class="new_task"
|
||||
onClick={() => {
|
||||
set_state(`${this.props.base}/new`);
|
||||
}}
|
||||
>
|
||||
<Icon>add</Icon>
|
||||
</Fab>
|
||||
<div class="task_amounts">
|
||||
<TaskFilterBar value={flags} set_value={set_flags} />
|
||||
</div>
|
||||
<div
|
||||
class="task_details"
|
||||
// @ts-ignore Checked
|
||||
ref={ul}
|
||||
>
|
||||
{task_list.value.map((k) => {
|
||||
const t = tasks.value.get(k);
|
||||
if (t) {
|
||||
return <Task task={t} flags={flags} />;
|
||||
} else {
|
||||
return <div data-id={k}></div>;
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user