This commit is contained in:
2023-06-30 22:47:12 +08:00
parent 9af6954816
commit 10dd3ac03a
3 changed files with 124 additions and 41 deletions

View File

@@ -0,0 +1,97 @@
// @ts-nocheck Chips
import { Component } from "preact";
import { Ref, useRef } from "preact/hooks";
import Chips from "preact-material-components/Chips";
import t from "../server/i18n.ts";
export enum TaskStatusFlag {
None = 0,
Running = 1 << 0,
Waiting = 1 << 1,
Failed = 1 << 2,
Finished = 1 << 3,
All = ~(~0 << 4),
}
type Props = {
value: TaskStatusFlag;
set_value: (v: TaskStatusFlag) => void;
};
export class TaskFilterBar extends Component<Props> {
ref: Ref<Chips | null> | undefined;
get is_all() {
return this.props.value === TaskStatusFlag.All;
}
get is_failed() {
return (this.props.value & TaskStatusFlag.Failed) !== 0;
}
get is_finished() {
return (this.props.value & TaskStatusFlag.Finished) !== 0;
}
get is_running() {
return (this.props.value & TaskStatusFlag.Running) !== 0;
}
get is_waiting() {
return (this.props.value & TaskStatusFlag.Waiting) !== 0;
}
get value() {
if (this.ref && this.ref.current) {
const com = this.ref.current.MDComponent;
if (com) {
return com.chips.slice(1).reduce(
(p, v, i) => v.selected ? p | 1 << i : p,
0,
);
}
}
return TaskStatusFlag.None;
}
render() {
this.ref = useRef<Chips>(null);
const onClick = () => {
const co = () => this.props.set_value(this.value);
setTimeout(co, 0);
};
return (
<Chips ref={this.ref} filter>
<Chips.Chip
selected={this.is_all}
onClick={() => {
const co = () => {
if (this.ref && this.ref.current) {
const com = this.ref.current.MDComponent;
if (com) {
com.chips.slice(1).forEach((v) => {
v.selected = com.chips[0].selected;
});
}
}
this.props.set_value(this.value);
};
setTimeout(co, 0);
}}
>
<Chips.Checkmark />
<Chips.Text>{t("task.all")}</Chips.Text>
</Chips.Chip>
<Chips.Chip selected={this.is_running} onClick={onClick}>
<Chips.Checkmark />
<Chips.Text>{t("task.running")}</Chips.Text>
</Chips.Chip>
<Chips.Chip selected={this.is_waiting} onClick={onClick}>
<Chips.Checkmark />
<Chips.Text>{t("task.waiting")}</Chips.Text>
</Chips.Chip>
<Chips.Chip selected={this.is_failed} onClick={onClick}>
<Chips.Checkmark />
<Chips.Text>{t("task.failed")}</Chips.Text>
</Chips.Chip>
<Chips.Chip selected={this.is_finished} onClick={onClick}>
<Chips.Checkmark />
<Chips.Text>{t("task.finished")}</Chips.Text>
</Chips.Chip>
</Chips>
);
}
}

View File

@@ -1,5 +1,5 @@
import { Component, ContextType } from "preact";
import { useEffect, useRef } from "preact/hooks";
import { useEffect, useRef, useState } from "preact/hooks";
import { signal } from "@preact/signals";
import { GlobalCtx } from "../components/GlobalContext.tsx";
import { TaskDetail, TaskStatus } from "../task.ts";
@@ -11,12 +11,20 @@ import Fab from "preact-material-components/Fab";
import Icon from "preact-material-components/Icon";
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;
};
function map_taskstatus(s: TaskStatus) {
if (s === TaskStatus.Wait) return TaskStatusFlag.Waiting;
else if (s === TaskStatus.Running) return TaskStatusFlag.Running;
else if (s === TaskStatus.Finished) return TaskStatusFlag.Finished;
return TaskStatusFlag.None;
}
const tasks = signal(new Map<number, TaskDetail>());
const task_list = signal(new Array<number>());
export const task_ws = signal<WebSocket | undefined>(undefined);
@@ -165,6 +173,7 @@ export default class TaskManager extends Component<TaskManagerProps> {
});
}, []);
if (!this.props.show) return null;
const [flags, set_flags] = useState(TaskStatusFlag.All);
return (
<div class="task_manager">
<Fab
@@ -176,28 +185,24 @@ export default class TaskManager extends Component<TaskManagerProps> {
<Icon>add</Icon>
</Fab>
<div class="task_amounts">
<div class="mdc-theme--secondary-light">
<p>count</p>
<p>{t("task.all")}</p>
</div>
<div class="btn-success">
<p>count</p>
<p>{t("task.running")}</p>
</div>
<div class="btn-warning">
<p>count</p>
<p>{t("task.waiting")}</p>
</div>
<div class="btn-danger">
<p>count</p>
<p>{t("task.failed")}</p>
</div>
<div class="btn-primary">
<p>count</p>
<p>{t("task.finished")}</p>
</div>
<TaskFilterBar value={flags} set_value={set_flags} />
</div>
<div class="task_details">
<div
class="task_details"
// @ts-ignore Checked
ref={ul}
>
{task_list.value.map((k) => {
const t = tasks.value.get(k);
if (t) {
if (!(flags & map_taskstatus(t.status))) {
return null;
}
return <Task task={t} />;
} else {
return <div data-id={k}></div>;
}
})}
</div>
</div>
);

View File

@@ -172,25 +172,6 @@ body {
height: 64px;
}
.task_amounts>div {
flex: auto;
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: aliceblue;
}
.task_amounts>div:first-child {
border-radius: 8px 0 0 8px;
background-color: black;
}
.task_amounts>div:last-child {
border-radius: 0 8px 8px 0
}
.btn-success {
background-color: #28a745
}