50 lines
2.6 KiB
TypeScript
50 lines
2.6 KiB
TypeScript
// панель «Эпики» бэклога и её узкий вариант — выбор «Эпик» (spec web-app); оба только меняют фильтр, Jira не трогают
|
||
import { Select } from "../../../ui/index.ts";
|
||
import { NONE, type EpicEntry } from "./filters.ts";
|
||
|
||
interface Props { entries: EpicEntry[]; value: string; onChange(v: string): void; hideDone: boolean }
|
||
|
||
// выполненные скрываются при «Скрыть выполненные», кроме выбранного; выбранный, которого нет в данных, остаётся пунктом по ключу
|
||
function listed({ entries, value, hideDone }: Pick<Props, "entries" | "value" | "hideDone">): EpicEntry[] {
|
||
const list = entries.filter((e) => !(hideDone && e.done && e.key !== value));
|
||
if (value && value !== NONE && !entries.some((e) => e.key === value)) list.push({ key: value, title: value, count: 0, done: false });
|
||
return list;
|
||
}
|
||
|
||
export function EpicsPanel(props: Props) {
|
||
const { value, onChange } = props;
|
||
const item = (v: string, title: string, key?: string, count?: number) => (
|
||
<li key={v}>
|
||
<button type="button" className="agile-epics__item" aria-pressed={value === v} onClick={() => onChange(value === v ? "" : v)}>
|
||
<span className="agile-epics__title">{title}</span>
|
||
{key && key !== title && <span className="agile-epics__key">{key}</span>}
|
||
{count !== undefined && <span className="agile-epics__count">{count}</span>}
|
||
</button>
|
||
</li>
|
||
);
|
||
return (
|
||
<aside className="agile-epics" aria-label="Эпики">
|
||
<ul className="agile-epics__list">
|
||
<li>
|
||
<button type="button" className="agile-epics__item" aria-pressed={value === ""} onClick={() => onChange("")}>
|
||
<span className="agile-epics__title">Все задачи</span>
|
||
</button>
|
||
</li>
|
||
{listed(props).map((e) => item(e.key, e.title, e.key, e.count))}
|
||
{item(NONE, "Без эпика")}
|
||
</ul>
|
||
</aside>
|
||
);
|
||
}
|
||
|
||
// forced — панель «Эпики» скрыта, а выбранный эпик должен оставаться виден и снимаем (M-3)
|
||
export function EpicSelect(props: Props & { forced?: boolean }) {
|
||
return (
|
||
<Select aria-label="Эпик" className={`agile-epic-select${props.forced ? " is-forced" : ""}`} value={props.value} onChange={(e) => props.onChange(e.target.value)}>
|
||
<option value="">Все задачи</option>
|
||
{listed(props).map((e) => <option key={e.key} value={e.key}>{e.title}</option>)}
|
||
<option value={NONE}>Без эпика</option>
|
||
</Select>
|
||
);
|
||
}
|