feat(dashboard): add inbox task actions (#32)

* feat(dashboard): add inbox task actions

* style(dashboard): format inbox actions
This commit is contained in:
Eyejoker
2026-04-27 01:47:42 +09:00
committed by GitHub
parent 22bd24ec88
commit a352b9af5b
2 changed files with 46 additions and 1 deletions

View File

@@ -593,11 +593,17 @@ function ControlRail({ data, t }: { data: DashboardState; t: Messages }) {
function InboxPanel({ function InboxPanel({
overview, overview,
tasks,
locale, locale,
onTaskAction,
taskActionKey,
t, t,
}: { }: {
overview: DashboardOverview; overview: DashboardOverview;
tasks: DashboardTask[];
locale: Locale; locale: Locale;
onTaskAction: (task: DashboardTask, action: DashboardTaskAction) => void;
taskActionKey: TaskActionKey | null;
t: Messages; t: Messages;
}) { }) {
const [filter, setFilter] = useState<InboxFilter>('all'); const [filter, setFilter] = useState<InboxFilter>('all');
@@ -672,6 +678,13 @@ function InboxPanel({
<div className="inbox-list" aria-label={t.inbox.cardsAria}> <div className="inbox-list" aria-label={t.inbox.cardsAria}>
{filteredItems.map((item) => { {filteredItems.map((item) => {
const href = inboxTargetHref(item); const href = inboxTargetHref(item);
const linkedTask =
item.source === 'scheduled-task' && item.taskId
? tasks.find((task) => task.id === item.taskId)
: undefined;
const linkedTaskActions = linkedTask
? taskActionsFor(linkedTask)
: [];
return ( return (
<article <article
className={`inbox-card inbox-${item.severity}`} className={`inbox-card inbox-${item.severity}`}
@@ -717,6 +730,25 @@ function InboxPanel({
{item.taskId ? t.inbox.openTask : t.inbox.openRoom} {item.taskId ? t.inbox.openTask : t.inbox.openRoom}
</a> </a>
) : null} ) : null}
{linkedTask && linkedTaskActions.length > 0 ? (
<div className="task-actions inbox-actions">
{linkedTaskActions.map((action) => {
const actionKey: TaskActionKey = `${linkedTask.id}:${action}`;
const busy = taskActionKey === actionKey;
return (
<button
className={`task-action task-action-${action}`}
disabled={busy}
key={action}
onClick={() => onTaskAction(linkedTask, action)}
type="button"
>
{busy ? t.tasks.actions.busy : t.tasks.actions[action]}
</button>
);
})}
</div>
) : null}
</article> </article>
); );
})} })}
@@ -1459,7 +1491,16 @@ function App() {
<h2>{t.panels.inbox}</h2> <h2>{t.panels.inbox}</h2>
<span>{t.panels.inboxQueue}</span> <span>{t.panels.inboxQueue}</span>
</div> </div>
<InboxPanel locale={locale} overview={data.overview} t={t} /> <InboxPanel
locale={locale}
onTaskAction={(task, action) =>
void handleTaskAction(task, action)
}
overview={data.overview}
taskActionKey={taskActionKey}
tasks={data.tasks}
t={t}
/>
</section> </section>
) : null} ) : null}

View File

@@ -1000,6 +1000,10 @@ progress::-moz-progress-bar {
text-decoration: none; text-decoration: none;
} }
.inbox-actions {
padding-top: 2px;
}
.health-overview { .health-overview {
display: flex; display: flex;
gap: 10px; gap: 10px;