Merge pull request #100 from linagora/92-manage-event-trnsparency
manage transparency
This commit is contained in:
@@ -1045,6 +1045,296 @@ describe("Event Full Display", () => {
|
|||||||
screen.getAllByDisplayValue(new RegExp(date, "i"))[0]
|
screen.getAllByDisplayValue(new RegExp(date, "i"))[0]
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
it("saves event and moves it when calendar is changed", async () => {
|
||||||
|
const spyPut = jest
|
||||||
|
.spyOn(eventThunks, "putEventAsync")
|
||||||
|
.mockImplementation((payload) => () => Promise.resolve(payload) as any);
|
||||||
|
const spyMove = jest
|
||||||
|
.spyOn(eventThunks, "moveEventAsync")
|
||||||
|
.mockImplementation((payload) => () => Promise.resolve(payload) as any);
|
||||||
|
const spyRemove = jest.spyOn(eventThunks, "removeEvent");
|
||||||
|
|
||||||
|
const day = new Date();
|
||||||
|
const preloadedTwoCals = {
|
||||||
|
user: {
|
||||||
|
userData: {
|
||||||
|
sub: "test",
|
||||||
|
email: "test@test.com",
|
||||||
|
openpaasId: "667037022b752d0026472254",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
calendars: {
|
||||||
|
list: {
|
||||||
|
"667037022b752d0026472254/cal1": {
|
||||||
|
id: "667037022b752d0026472254/cal1",
|
||||||
|
name: "Calendar One",
|
||||||
|
color: "#FF0000",
|
||||||
|
events: {
|
||||||
|
event1: {
|
||||||
|
uid: "uid-base",
|
||||||
|
id: "event1",
|
||||||
|
title: "Test Event",
|
||||||
|
calId: "667037022b752d0026472254/cal1",
|
||||||
|
start: day.toISOString(),
|
||||||
|
end: day.toISOString(),
|
||||||
|
organizer: { cn: "test", cal_address: "test@test.com" },
|
||||||
|
attendee: [{ cn: "test", cal_address: "test@test.com" }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"667037022b752d0026472254/cal2": {
|
||||||
|
id: "667037022b752d0026472254/cal2",
|
||||||
|
name: "Calendar Two",
|
||||||
|
color: "#00FF00",
|
||||||
|
events: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pending: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
renderWithProviders(
|
||||||
|
<EventDisplayModal
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
calId={"667037022b752d0026472254/cal1"}
|
||||||
|
eventId={"event1"}
|
||||||
|
/>,
|
||||||
|
preloadedTwoCals
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.mouseDown(screen.getByLabelText("Calendar"));
|
||||||
|
|
||||||
|
const option = await screen.findByText("Calendar Two");
|
||||||
|
fireEvent.click(option);
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByText("Save"));
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(spyPut).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(spyMove).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(spyRemove).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("removes recurrence instances when saving an edited recurring series", async () => {
|
||||||
|
const spyPut = jest
|
||||||
|
.spyOn(eventThunks, "putEventAsync")
|
||||||
|
.mockImplementation((payload) => () => Promise.resolve(payload) as any);
|
||||||
|
const spyRemove = jest.spyOn(eventThunks, "removeEvent");
|
||||||
|
|
||||||
|
const day = new Date();
|
||||||
|
const preloadedRecurrence = {
|
||||||
|
user: {
|
||||||
|
userData: {
|
||||||
|
sub: "test",
|
||||||
|
email: "test@test.com",
|
||||||
|
openpaasId: "667037022b752d0026472254",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
calendars: {
|
||||||
|
list: {
|
||||||
|
"667037022b752d0026472254/cal1": {
|
||||||
|
id: "667037022b752d0026472254/cal1",
|
||||||
|
name: "First Calendar",
|
||||||
|
color: "#FF0000",
|
||||||
|
events: {
|
||||||
|
"base/20250101": {
|
||||||
|
uid: "base/20250101",
|
||||||
|
calId: "667037022b752d0026472254/cal1",
|
||||||
|
title: "eventA",
|
||||||
|
},
|
||||||
|
"base/20250201": {
|
||||||
|
uid: "base/20250201",
|
||||||
|
calId: "667037022b752d0026472254/cal1",
|
||||||
|
title: "eventB",
|
||||||
|
},
|
||||||
|
"base/20250301": {
|
||||||
|
uid: "base/20250301",
|
||||||
|
title: "Recurring event",
|
||||||
|
calId: "667037022b752d0026472254/cal1",
|
||||||
|
start: day.toISOString(),
|
||||||
|
end: day.toISOString(),
|
||||||
|
organizer: { cal_address: "test@test.com" },
|
||||||
|
attendee: [{ cal_address: "test@test.com", cn: "Test" }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pending: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
renderWithProviders(
|
||||||
|
<EventDisplayModal
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
calId={"667037022b752d0026472254/cal1"}
|
||||||
|
eventId={"base/20250301"}
|
||||||
|
/>,
|
||||||
|
preloadedRecurrence
|
||||||
|
);
|
||||||
|
|
||||||
|
act(() => fireEvent.click(screen.getByText("Save")));
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(spyPut).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(spyRemove).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("InfoRow renders error style when error prop is true", () => {
|
||||||
|
renderWithProviders(<InfoRow icon={<span>i</span>} text="Bad" error />);
|
||||||
|
expect(screen.getByText("Bad")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls onClose from useEffect if event or calendar missing", () => {
|
||||||
|
renderWithProviders(
|
||||||
|
<EventDisplayModal
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
calId={"nonexistent/cal"}
|
||||||
|
eventId={"ghost"}
|
||||||
|
/>,
|
||||||
|
preloadedState
|
||||||
|
);
|
||||||
|
expect(mockOnClose).toHaveBeenCalledWith({}, "backdropClick");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders error row when event has error", () => {
|
||||||
|
const errorState = {
|
||||||
|
...preloadedState,
|
||||||
|
calendars: {
|
||||||
|
list: {
|
||||||
|
"667037022b752d0026472254/cal1": {
|
||||||
|
...preloadedState.calendars.list["667037022b752d0026472254/cal1"],
|
||||||
|
events: {
|
||||||
|
event1: {
|
||||||
|
...preloadedState.calendars.list[
|
||||||
|
"667037022b752d0026472254/cal1"
|
||||||
|
].events.event1,
|
||||||
|
error: "Something went wrong",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pending: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
renderWithProviders(
|
||||||
|
<EventDisplayModal
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
calId={"667037022b752d0026472254/cal1"}
|
||||||
|
eventId={"event1"}
|
||||||
|
/>,
|
||||||
|
errorState
|
||||||
|
);
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
fireEvent.click(screen.getByText("Show More"));
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText("Something went wrong")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can remove an attendee with the close button", () => {
|
||||||
|
renderWithProviders(
|
||||||
|
<EventDisplayModal
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
calId={"667037022b752d0026472254/cal1"}
|
||||||
|
eventId={"event1"}
|
||||||
|
/>,
|
||||||
|
preloadedState
|
||||||
|
);
|
||||||
|
|
||||||
|
const removeBtn = screen.getAllByTestId("CloseIcon").pop()!;
|
||||||
|
fireEvent.click(removeBtn);
|
||||||
|
|
||||||
|
expect(screen.queryByText(/John/)).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows more attendees when overflow, then toggles back", () => {
|
||||||
|
const overflowState = {
|
||||||
|
...preloadedState,
|
||||||
|
calendars: {
|
||||||
|
list: {
|
||||||
|
"667037022b752d0026472254/cal1": {
|
||||||
|
...preloadedState.calendars.list["667037022b752d0026472254/cal1"],
|
||||||
|
events: {
|
||||||
|
event1: {
|
||||||
|
...preloadedState.calendars.list[
|
||||||
|
"667037022b752d0026472254/cal1"
|
||||||
|
].events.event1,
|
||||||
|
attendee: new Array(6).fill(null).map((_, i) => ({
|
||||||
|
cn: `Person${i}`,
|
||||||
|
cal_address: `p${i}@test.com`,
|
||||||
|
})),
|
||||||
|
organizer: { cn: "test", cal_address: "test@test.com" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
renderWithProviders(
|
||||||
|
<EventDisplayModal
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
calId={"667037022b752d0026472254/cal1"}
|
||||||
|
eventId={"event1"}
|
||||||
|
/>,
|
||||||
|
overflowState
|
||||||
|
);
|
||||||
|
|
||||||
|
const toggle = screen.getByText(/Show more/);
|
||||||
|
fireEvent.click(toggle);
|
||||||
|
|
||||||
|
expect(screen.getByText(/Show less/)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders video conference info when x_openpass_videoconference exists", () => {
|
||||||
|
const videoState = {
|
||||||
|
...preloadedState,
|
||||||
|
calendars: {
|
||||||
|
list: {
|
||||||
|
"667037022b752d0026472254/cal1": {
|
||||||
|
...preloadedState.calendars.list["667037022b752d0026472254/cal1"],
|
||||||
|
events: {
|
||||||
|
event1: {
|
||||||
|
...preloadedState.calendars.list[
|
||||||
|
"667037022b752d0026472254/cal1"
|
||||||
|
].events.event1,
|
||||||
|
x_openpass_videoconference: "https://meet.test/video",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
renderWithProviders(
|
||||||
|
<EventDisplayModal
|
||||||
|
open={true}
|
||||||
|
onClose={mockOnClose}
|
||||||
|
calId={"667037022b752d0026472254/cal1"}
|
||||||
|
eventId={"event1"}
|
||||||
|
/>,
|
||||||
|
videoState
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText("Video conference available")).toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Helper functions", () => {
|
describe("Helper functions", () => {
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ describe("EventPopover", () => {
|
|||||||
location: "Zoom",
|
location: "Zoom",
|
||||||
organizer: { cn: "test", cal_address: "test@test.com" },
|
organizer: { cn: "test", cal_address: "test@test.com" },
|
||||||
timezone: "Europe/Paris",
|
timezone: "Europe/Paris",
|
||||||
transp: "OPAQUE",
|
transp: "TRANSPARENT",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fill inputs
|
// Fill inputs
|
||||||
|
|||||||
@@ -89,13 +89,13 @@ export default function EventDisplayModal({
|
|||||||
);
|
);
|
||||||
const [allday, setAllDay] = useState(event?.allday);
|
const [allday, setAllDay] = useState(event?.allday);
|
||||||
const [repetition, setRepetition] = useState<RepetitionObject>(
|
const [repetition, setRepetition] = useState<RepetitionObject>(
|
||||||
event.repetition ?? ({} as RepetitionObject)
|
event?.repetition ?? ({} as RepetitionObject)
|
||||||
);
|
);
|
||||||
const [alarm, setAlarm] = useState(event?.alarm?.trigger ?? "");
|
const [alarm, setAlarm] = useState(event?.alarm?.trigger ?? "");
|
||||||
const [busy, setBusy] = useState("");
|
const [busy, setBusy] = useState(event?.transp ?? "OPAQUE");
|
||||||
const [eventClass, setEventClass] = useState(event?.class ?? "PUBLIC");
|
const [eventClass, setEventClass] = useState(event?.class ?? "PUBLIC");
|
||||||
const [timezone, setTimezone] = useState(event?.timezone ?? "UTC");
|
const [timezone, setTimezone] = useState(event?.timezone ?? "UTC");
|
||||||
const [newCalId, setNewCalId] = useState(event.calId);
|
const [newCalId, setNewCalId] = useState(event?.calId);
|
||||||
const [calendarid, setCalendarid] = useState(
|
const [calendarid, setCalendarid] = useState(
|
||||||
calId.split("/")[0] === user.userData.openpaasId
|
calId.split("/")[0] === user.userData.openpaasId
|
||||||
? userPersonnalCalendars.findIndex((cal) => cal.id === calId)
|
? userPersonnalCalendars.findIndex((cal) => cal.id === calId)
|
||||||
@@ -112,7 +112,7 @@ export default function EventDisplayModal({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const organizer =
|
const organizer =
|
||||||
event.attendee?.find(
|
event?.attendee?.find(
|
||||||
(a) => a.cal_address === event?.organizer?.cal_address
|
(a) => a.cal_address === event?.organizer?.cal_address
|
||||||
) ?? ({} as userAttendee);
|
) ?? ({} as userAttendee);
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ export default function EventDisplayModal({
|
|||||||
if (!event || !calendar) {
|
if (!event || !calendar) {
|
||||||
onClose({}, "backdropClick");
|
onClose({}, "backdropClick");
|
||||||
}
|
}
|
||||||
setRepetition(event.repetition ?? ({} as RepetitionObject));
|
setRepetition(event?.repetition ?? ({} as RepetitionObject));
|
||||||
}, [open, eventId, dispatch, onClose, event]);
|
}, [open, eventId, dispatch, onClose, event]);
|
||||||
|
|
||||||
if (!event || !calendar) return null;
|
if (!event || !calendar) return null;
|
||||||
@@ -158,7 +158,7 @@ export default function EventDisplayModal({
|
|||||||
organizer: event.organizer,
|
organizer: event.organizer,
|
||||||
timezone,
|
timezone,
|
||||||
attendee: [organizer, ...attendees],
|
attendee: [organizer, ...attendees],
|
||||||
transp: "OPAQUE",
|
transp: busy,
|
||||||
color: userPersonnalCalendars[calendarid]?.color,
|
color: userPersonnalCalendars[calendarid]?.color,
|
||||||
alarm: { trigger: alarm, action: "EMAIL" },
|
alarm: { trigger: alarm, action: "EMAIL" },
|
||||||
};
|
};
|
||||||
@@ -471,32 +471,32 @@ export default function EventDisplayModal({
|
|||||||
setRepetition={setRepetition}
|
setRepetition={setRepetition}
|
||||||
isOwn={isOwn}
|
isOwn={isOwn}
|
||||||
/>
|
/>
|
||||||
|
<FormControl fullWidth margin="dense" size="small">
|
||||||
<FormControl fullWidth margin="dense" size="small">
|
<InputLabel id="alarm">Alarm</InputLabel>
|
||||||
<InputLabel id="alarm">Alarm</InputLabel>
|
<Select
|
||||||
<Select
|
labelId="alarm"
|
||||||
labelId="alarm"
|
label="Alarm"
|
||||||
label="Alarm"
|
value={alarm}
|
||||||
value={alarm}
|
disabled={!isOwn}
|
||||||
disabled={!isOwn}
|
onChange={(e: SelectChangeEvent) =>
|
||||||
onChange={(e: SelectChangeEvent) => setAlarm(e.target.value)}
|
setAlarm(e.target.value)
|
||||||
>
|
}
|
||||||
<MenuItem value={""}>No Alarm</MenuItem>
|
>
|
||||||
<MenuItem value={"-PT1M"}>1 minute</MenuItem>
|
<MenuItem value={""}>No Alarm</MenuItem>
|
||||||
<MenuItem value={"-PT5M"}>2 minutes</MenuItem>
|
<MenuItem value={"-PT1M"}>1 minute</MenuItem>
|
||||||
<MenuItem value={"-PT10M"}>10 minutes</MenuItem>
|
<MenuItem value={"-PT5M"}>2 minutes</MenuItem>
|
||||||
<MenuItem value={"-PT15M"}>15 minutes</MenuItem>
|
<MenuItem value={"-PT10M"}>10 minutes</MenuItem>
|
||||||
<MenuItem value={"-PT30M"}>30 minutes</MenuItem>
|
<MenuItem value={"-PT15M"}>15 minutes</MenuItem>
|
||||||
<MenuItem value={"-PT1H"}>1 hours</MenuItem>
|
<MenuItem value={"-PT30M"}>30 minutes</MenuItem>
|
||||||
<MenuItem value={"-PT2H"}>2 hours</MenuItem>
|
<MenuItem value={"-PT1H"}>1 hours</MenuItem>
|
||||||
<MenuItem value={"-PT5H"}>5 hours</MenuItem>
|
<MenuItem value={"-PT2H"}>2 hours</MenuItem>
|
||||||
<MenuItem value={"-PT12H"}>12 hours</MenuItem>
|
<MenuItem value={"-PT5H"}>5 hours</MenuItem>
|
||||||
<MenuItem value={"-PT1D"}>1 day</MenuItem>
|
<MenuItem value={"-PT12H"}>12 hours</MenuItem>
|
||||||
<MenuItem value={"-PT2D"}>2 days</MenuItem>
|
<MenuItem value={"-PT1D"}>1 day</MenuItem>
|
||||||
<MenuItem value={"-PT1W"}>1 week</MenuItem>
|
<MenuItem value={"-PT2D"}>2 days</MenuItem>
|
||||||
</Select>
|
<MenuItem value={"-PT1W"}>1 week</MenuItem>
|
||||||
</FormControl>
|
</Select>
|
||||||
|
</FormControl>
|
||||||
<FormControl fullWidth margin="dense" size="small">
|
<FormControl fullWidth margin="dense" size="small">
|
||||||
<InputLabel id="Visibility">Visibility</InputLabel>
|
<InputLabel id="Visibility">Visibility</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
@@ -513,6 +513,19 @@ export default function EventDisplayModal({
|
|||||||
<MenuItem value={"PRIVATE"}>Private</MenuItem>
|
<MenuItem value={"PRIVATE"}>Private</MenuItem>
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
<FormControl fullWidth margin="dense" size="small">
|
||||||
|
<InputLabel id="busy">is Busy</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId="busy"
|
||||||
|
value={busy}
|
||||||
|
disabled={!isOwn}
|
||||||
|
label="is busy"
|
||||||
|
onChange={(e: SelectChangeEvent) => setBusy(e.target.value)}
|
||||||
|
>
|
||||||
|
<MenuItem value={"TRANSPARENT"}>Free</MenuItem>
|
||||||
|
<MenuItem value={"OPAQUE"}>Busy </MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
{/* Error */}
|
{/* Error */}
|
||||||
{event.error && (
|
{event.error && (
|
||||||
<InfoRow
|
<InfoRow
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ function EventPopover({
|
|||||||
const [attendees, setAttendees] = useState<userAttendee[]>([]);
|
const [attendees, setAttendees] = useState<userAttendee[]>([]);
|
||||||
const [alarm, setAlarm] = useState("");
|
const [alarm, setAlarm] = useState("");
|
||||||
const [eventClass, setEventClass] = useState("PUBLIC");
|
const [eventClass, setEventClass] = useState("PUBLIC");
|
||||||
const [busy, setBusy] = useState("");
|
const [busy, setBusy] = useState("OPAQUE");
|
||||||
|
|
||||||
const [timezone, setTimezone] = useState(
|
const [timezone, setTimezone] = useState(
|
||||||
Intl.DateTimeFormat().resolvedOptions().timeZone
|
Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||||
@@ -115,7 +115,7 @@ function EventPopover({
|
|||||||
cutype: "INDIVIDUAL",
|
cutype: "INDIVIDUAL",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
transp: "OPAQUE",
|
transp: busy,
|
||||||
color: userPersonnalCalendars[calendarid]?.color,
|
color: userPersonnalCalendars[calendarid]?.color,
|
||||||
alarm: { trigger: alarm, action: "EMAIL" },
|
alarm: { trigger: alarm, action: "EMAIL" },
|
||||||
};
|
};
|
||||||
@@ -326,6 +326,18 @@ function EventPopover({
|
|||||||
<MenuItem value={"PRIVATE"}>Private</MenuItem>
|
<MenuItem value={"PRIVATE"}>Private</MenuItem>
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
<FormControl fullWidth margin="dense" size="small">
|
||||||
|
<InputLabel id="busy">is Busy</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId="busy"
|
||||||
|
value={busy}
|
||||||
|
label="is busy"
|
||||||
|
onChange={(e: SelectChangeEvent) => setBusy(e.target.value)}
|
||||||
|
>
|
||||||
|
<MenuItem value={"TRANSPARENT"}>Free</MenuItem>
|
||||||
|
<MenuItem value={"OPAQUE"}>Busy </MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ export function calendarEventToJCal(
|
|||||||
["summary", {}, "text", event.title ?? ""],
|
["summary", {}, "text", event.title ?? ""],
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
if (event.alarm) {
|
if (event.alarm?.trigger) {
|
||||||
const valarm = [
|
const valarm = [
|
||||||
["trigger", {}, "duration", event.alarm.trigger],
|
["trigger", {}, "duration", event.alarm.trigger],
|
||||||
["action", {}, "text", event.alarm.action],
|
["action", {}, "text", event.alarm.action],
|
||||||
|
|||||||
Reference in New Issue
Block a user