feat(scheduling-webui): build two-pane request workspace
This commit is contained in:
@@ -2,6 +2,7 @@ import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import type { SchedulingRequest } from "../src/api/scheduling.ts";
|
||||
import {
|
||||
applySchedulingAvailabilityChoice,
|
||||
groupSchedulingRequests,
|
||||
schedulingSortPhase,
|
||||
type SchedulingActor
|
||||
@@ -47,6 +48,15 @@ function request(
|
||||
source_path: [],
|
||||
details: {}
|
||||
},
|
||||
notify_on_answers: true,
|
||||
single_choice: false,
|
||||
max_participants_per_option: null,
|
||||
allow_maybe: true,
|
||||
allow_comments: false,
|
||||
participant_email_required: false,
|
||||
anonymous_password_protection_enabled: false,
|
||||
public_participation_policy_enforcement_available: false,
|
||||
public_participation_policy_enforcement_reason: "Public participation gateway not installed",
|
||||
calendar_integration_enabled: false,
|
||||
calendar_freebusy_enabled: false,
|
||||
calendar_hold_enabled: false,
|
||||
@@ -61,11 +71,13 @@ function request(
|
||||
end_at: options.end ?? "2026-07-21T10:00:00Z",
|
||||
timezone: "UTC",
|
||||
position: 0,
|
||||
revision: "0".repeat(64),
|
||||
freebusy_conflicts: [],
|
||||
metadata: {}
|
||||
}],
|
||||
participants: options.participantStatus ? [{
|
||||
id: `participant-${id}`,
|
||||
is_current_participant: true,
|
||||
respondent_id: "membership-1",
|
||||
email: "person@example.test",
|
||||
participant_type: "internal",
|
||||
@@ -88,6 +100,29 @@ test("groups owned, invited, and administrator-only requests without hiding any"
|
||||
assert.deepEqual(groups.other.map((item) => item.id), ["managed"]);
|
||||
});
|
||||
|
||||
test("matches email-only invitations without case sensitivity", () => {
|
||||
const invited = request("email-case", { participantStatus: "invited" });
|
||||
invited.participants[0].is_current_participant = false;
|
||||
invited.participants[0].respondent_id = null;
|
||||
invited.participants[0].email = "Person@Example.Test";
|
||||
|
||||
const groups = groupSchedulingRequests([invited], actor, now);
|
||||
|
||||
assert.deepEqual(groups.invited.map((item) => item.id), ["email-case"]);
|
||||
assert.deepEqual(groups.other, []);
|
||||
});
|
||||
|
||||
test("recognizes the current participant after identity bindings are redacted", () => {
|
||||
const invited = request("safe-projection", { participantStatus: "invited" });
|
||||
invited.participants[0].respondent_id = null;
|
||||
invited.participants[0].email = null;
|
||||
|
||||
const groups = groupSchedulingRequests([invited], actor, now);
|
||||
|
||||
assert.deepEqual(groups.invited.map((item) => item.id), ["safe-projection"]);
|
||||
assert.deepEqual(groups.other, []);
|
||||
});
|
||||
|
||||
test("keeps an organizer's active request in the open phase even if they also responded", () => {
|
||||
const owned = request("mine-and-invited", {
|
||||
organizer: "account-1",
|
||||
@@ -122,3 +157,31 @@ test("orders unanswered by nearest slot before answered, closed, determined, and
|
||||
assert.equal(schedulingSortPhase(groups.invited[0], actor, now), "unanswered");
|
||||
assert.equal(schedulingSortPhase(groups.invited.at(-1)!, actor, now), "past");
|
||||
});
|
||||
|
||||
test("single-choice availability keeps one positive choice while preserving explicit no answers", () => {
|
||||
const next = applySchedulingAvailabilityChoice(
|
||||
["slot-a", "slot-b", "slot-c"],
|
||||
{ "slot-a": "available", "slot-b": "maybe", "slot-c": "unavailable" },
|
||||
"slot-b",
|
||||
"available",
|
||||
true
|
||||
);
|
||||
|
||||
assert.deepEqual(next, {
|
||||
"slot-a": "unavailable",
|
||||
"slot-b": "available",
|
||||
"slot-c": "unavailable"
|
||||
});
|
||||
});
|
||||
|
||||
test("multi-choice availability changes only the selected slot", () => {
|
||||
const next = applySchedulingAvailabilityChoice(
|
||||
["slot-a", "slot-b"],
|
||||
{ "slot-a": "available" },
|
||||
"slot-b",
|
||||
"maybe",
|
||||
false
|
||||
);
|
||||
|
||||
assert.deepEqual(next, { "slot-a": "available", "slot-b": "maybe" });
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user