refactor(webui): use central scheduling controls

This commit is contained in:
2026-07-21 12:05:02 +02:00
parent 98b797a95d
commit 770ecf8786
3 changed files with 26 additions and 39 deletions

View File

@@ -52,7 +52,7 @@ assert.match(page, /<DataGridEmptyAction/);
assert.doesNotMatch(page, /EmailAddressInput|MailboxAddress|addressSuggestions|addressLookupQuery/);
assert.match(page, /type="email"[\s\S]*aria-label=\{I18N\.participantEmail\}/);
assert.doesNotMatch(page, /header: I18N\.required|<table|scheduling-table|scheduling-card(?:\s|"|`)/);
assert.match(page, /aria-label=\{i18nMessage\("i18n:govoplan-scheduling\.decide_on_value/);
assert.match(page, /<TableActionGroup[\s\S]*label: i18nMessage\("i18n:govoplan-scheduling\.decide_on_value/);
assert.match(page, /submitSchedulingAvailability\(settings, selected\.id/);
assert.match(page, /option_revision: slot\.revision/);
assert.match(page, /getSchedulingAvailabilityResponse\(settings, selected\.id\)/);

View File

@@ -11,12 +11,15 @@ import {
XCircle
} from "lucide-react";
import {
AdminIconButton,
Button,
Card,
DataGrid,
DataGridEmptyAction,
DataGridRowActions,
DateTimeField,
ModuleSubnav,
TableActionGroup,
ToggleSwitch,
hasScope,
i18nMessage,
@@ -578,9 +581,7 @@ export default function SchedulingPage({ settings, auth }: { settings: ApiSettin
<h1>{I18N.requests}</h1>
</div>
<div className="scheduling-page-actions">
<Button type="button" className="scheduling-icon-button" onClick={() => void loadRequests()} title={I18N.refresh} aria-label={I18N.refresh}>
<RefreshCw aria-hidden="true" size={16} />
</Button>
<AdminIconButton label={I18N.refresh} icon={<RefreshCw aria-hidden="true" size={16} />} onClick={() => void loadRequests()} disabled={loading} />
{canWrite ? (
<Button type="button" variant="primary" onClick={beginCreate}>
<Plus aria-hidden="true" size={16} /> {I18N.add}
@@ -883,33 +884,31 @@ function EditableSlots({
{
id: "start",
header: I18N.start,
minWidth: 200,
minWidth: 280,
resizable: true,
value: (slot) => slot.start_at,
render: (slot, index) => (
<input
className="scheduling-grid-input"
<DateTimeField
className="scheduling-grid-date-time"
required
type="datetime-local"
aria-label={I18N.start}
value={slot.start_at}
onChange={(event) => onChange(index, "start_at", event.target.value)} />
onChange={(value) => onChange(index, "start_at", value)} />
)
},
{
id: "end",
header: I18N.end,
minWidth: 200,
minWidth: 280,
resizable: true,
value: (slot) => slot.end_at,
render: (slot, index) => (
<input
className="scheduling-grid-input"
<DateTimeField
className="scheduling-grid-date-time"
required
type="datetime-local"
aria-label={I18N.end}
value={slot.end_at}
onChange={(event) => onChange(index, "end_at", event.target.value)} />
onChange={(value) => onChange(index, "end_at", value)} />
)
},
{
@@ -1087,17 +1086,14 @@ function CandidateSlotsGrid({
header: I18N.actions,
width: 72,
sticky: "end",
render: (slot) => canDecide ? (
<Button
className="scheduling-icon-button"
type="button"
title={i18nMessage("i18n:govoplan-scheduling.decide_on_value.196409cd", { value0: slot.label })}
aria-label={i18nMessage("i18n:govoplan-scheduling.decide_on_value.196409cd", { value0: slot.label })}
disabled={saving}
onClick={() => onDecide(slot)}>
<Check aria-hidden="true" size={16} />
</Button>
) : null
render: (slot) => <TableActionGroup actions={[{
id: "decide",
label: i18nMessage("i18n:govoplan-scheduling.decide_on_value.196409cd", { value0: slot.label }),
icon: <Check aria-hidden="true" size={16} />,
applicable: canDecide,
disabled: saving,
onClick: () => onDecide(slot)
}]} />
}
];

View File

@@ -89,15 +89,6 @@
gap: 6px;
}
.scheduling-icon-button.btn {
width: 34px;
min-width: 34px;
height: 34px;
min-height: 34px;
padding: 0;
justify-content: center;
}
.scheduling-alert,
.scheduling-success {
margin: 10px 14px 0;
@@ -107,8 +98,8 @@
}
.scheduling-alert {
border-color: var(--danger);
color: var(--danger);
border-color: var(--danger-border-strong);
color: var(--danger-text-strong);
background: var(--danger-soft);
}
@@ -163,7 +154,7 @@
}
.scheduling-list-item:hover {
background: var(--hover-bg);
background: var(--hover-tint-soft);
}
.scheduling-list-item.is-selected {
@@ -247,7 +238,7 @@
.scheduling-freebusy.busy,
.scheduling-freebusy.error {
color: var(--danger);
color: var(--danger-text-strong);
}
.scheduling-columns {
@@ -317,7 +308,7 @@
border: var(--border-line);
border-radius: 6px;
color: var(--text);
background: var(--input-bg);
background: var(--control-bg);
font: inherit;
}