Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,33 @@ import { NOTIFICATION_CONTEXT } from "../../../../configs/modalConfig";
import { useAppDispatch, useAppSelector } from "../../../../store";
import {
checkConflicts,
getSelectedCaptureOptions,
saveSchedulingInfo,
SchedulingInfo,
} from "../../../../slices/eventDetailsSlice";
import {
removeNotificationWizardForm,
addNotification,
} from "../../../../slices/notificationSlice";
import { Recording } from "../../../../slices/recordingSlice";
import {
CaptureOptionSelection,
captureOptions,
contentOverridesInputs,
Recording,
} from "../../../../slices/recordingSlice";
import { useTranslation } from "react-i18next";
import WizardNavigationButtons from "../../../shared/wizard/WizardNavigationButtons";
import SchedulingTime from "../wizards/scheduling/SchedulingTime";
import SchedulingLocation from "../wizards/scheduling/SchedulingLocation";
import SchedulingInputs from "../wizards/scheduling/SchedulingInputs";
import SchedulingCaptureOptions from "../wizards/scheduling/SchedulingCaptureOptions";

import SchedulingConflicts from "../wizards/scheduling/SchedulingConflicts";
import { ParseKeys } from "i18next";
import ModalContentTable from "../../../shared/modals/ModalContentTable";
import i18n from "../../../../i18n/i18n";

export type InitialValues = {
export type InitialValues = CaptureOptionSelection & {
scheduleStartDate: string;
scheduleStartHour: string;
scheduleStartMinute: string;
Expand Down Expand Up @@ -143,10 +151,23 @@ const EventDetailsSchedulingTab = ({
return value ? t(value as ParseKeys) : "";
};

// changes the inputs in the formik
// finds the agent, whose options are to be displayed in the formik
const getAgent = (deviceId: Recording["id"]) => {
if (deviceId === source.device.id) {
return source.device;
}
return filterDevicesForAccess(user, captureAgents).find(agent => agent.id === deviceId);
};

// changes the inputs and other options in the formik
const changeInputs = (deviceId: Recording["id"], setFieldValue: FormikHelpers<InitialValues>["setFieldValue"]) => {
const agent = getAgent(deviceId);
setFieldValue("captureAgent", deviceId);
setFieldValue("inputs", []);
// Like in the wizard, all inputs and options of the agent are selected
setFieldValue("inputs", getInputs(deviceId).map(input => input.id));
for (const { field, list } of captureOptions) {
setFieldValue(field, agent?.[list]?.map(option => option.id) ?? []);
}
};
const filterCaptureAgents = (agent: Recording) => {
return agent.id === source.agentId || hasDeviceAccess(user, agent.id);
Expand All @@ -161,19 +182,15 @@ const EventDetailsSchedulingTab = ({
accessAllowed(formik.values.captureAgent) &&
!(conflicts.length > 0)
) {
// check if user provided values differ from initial ones
if (!_.isEqual(formik.values, formik.initialValues)) {
if (!_.isEqual(formik.values.inputs, formik.initialValues.inputs)) {
return !_.isEqual(
[...formik.values.inputs].sort(),
[...formik.initialValues.inputs].sort(),
);
} else {
return true;
}
} else {
return false;
}
// check if user provided values differ from initial ones, the order of selected options does not matter
const sortSelected = (values: InitialValues) => ({
...values,
inputs: [...values.inputs].sort(),
streamConfiguration: [...values.streamConfiguration].sort(),
devicePosition: [...values.devicePosition].sort(),
deviceContent: [...values.deviceContent].sort(),
});
return !_.isEqual(sortSelected(formik.values), sortSelected(formik.initialValues));
} else {
return false;
}
Expand Down Expand Up @@ -231,6 +248,7 @@ const EventDetailsSchedulingTab = ({
scheduleEndMinute: source.end.minute != null ? makeTwoDigits(source.end.minute) : "",
captureAgent: source.device.name,
inputs: inputs.filter(input => input !== ""),
...getSelectedCaptureOptions(source.agentConfiguration),
};
};

Expand Down Expand Up @@ -491,31 +509,40 @@ const EventDetailsSchedulingTab = ({
</tr>
}

{/* inputs */}
<tr>
<td>
{t(
"EVENTS.EVENTS.DETAILS.SOURCE.PLACEHOLDER.INPUTS",
)}
</td>
<td>
{!!formik.values.captureAgent &&
!!getInputs(formik.values.captureAgent) &&
getInputs(formik.values.captureAgent).length >
0 &&
(hasAccessRole &&
accessAllowed(formik.values.captureAgent)
? <SchedulingInputs
inputs={getInputs(formik.values.captureAgent)}
/>
: formik.values.inputs.map((input, key) => (
<span key={key}>
{getInputForAgent(formik.values.captureAgent, input)}
<br />
</span>
)))}
</td>
</tr>
{/* inputs, which are not offered if the content configuration determines them */}
{!contentOverridesInputs(getAgent(formik.values.captureAgent)) && (
<tr>
<td>
{t(
"EVENTS.EVENTS.DETAILS.SOURCE.PLACEHOLDER.INPUTS",
)}
</td>
<td>
{!!formik.values.captureAgent &&
!!getInputs(formik.values.captureAgent) &&
getInputs(formik.values.captureAgent).length >
0 &&
(hasAccessRole &&
accessAllowed(formik.values.captureAgent)
? <SchedulingInputs
inputs={getInputs(formik.values.captureAgent)}
/>
: formik.values.inputs.map((input, key) => (
<span key={key}>
{getInputForAgent(formik.values.captureAgent, input)}
<br />
</span>
)))}
</td>
</tr>
)}

{/* other options the agent offers */}
<SchedulingCaptureOptions
agent={getAgent(formik.values.captureAgent)}
selection={formik.values}
disabled={!hasAccessRole || !accessAllowed(formik.values.captureAgent)}
/>
</tbody>
</table>
</div>
Expand Down
49 changes: 34 additions & 15 deletions src/components/events/partials/ModalTabsAndPages/NewSourcePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,13 @@ import {
changeStartMinuteMultiple,
} from "../../../../utils/dateUtils";
import { useAppDispatch, useAppSelector } from "../../../../store";
import { Recording, fetchRecordings } from "../../../../slices/recordingSlice";
import {
CaptureOptionSelection,
Recording,
captureOptions,
contentOverridesInputs,
fetchRecordings,
} from "../../../../slices/recordingSlice";
import { addNotification, removeNotificationWizardForm } from "../../../../slices/notificationSlice";
import { parseISO } from "date-fns";
import WizardNavigationButtons from "../../../shared/wizard/WizardNavigationButtons";
Expand All @@ -46,6 +52,7 @@ import ButtonLikeAnchor from "../../../shared/ButtonLikeAnchor";
import SchedulingTime from "../wizards/scheduling/SchedulingTime";
import SchedulingLocation from "../wizards/scheduling/SchedulingLocation";
import SchedulingInputs from "../wizards/scheduling/SchedulingInputs";
import SchedulingCaptureOptions from "../wizards/scheduling/SchedulingCaptureOptions";
import SchedulingConflicts from "../wizards/scheduling/SchedulingConflicts";
import { ParseKeys } from "i18next";
import { LuCircleX } from "react-icons/lu";
Expand All @@ -54,7 +61,7 @@ import i18n from "../../../../i18n/i18n";
/**
* This component renders the source page for new events in the new event wizard.
*/
interface RequiredFormProps {
interface RequiredFormProps extends CaptureOptionSelection {
scheduleStartDate: string,
sourceMode: string,
// Schedule
Expand Down Expand Up @@ -393,7 +400,7 @@ const Upload = <T extends RequiredFormPropsUpload>({
/*
* Renders fields for providing information for schedule of event
*/
const Schedule = <T extends {
const Schedule = <T extends CaptureOptionSelection & {
location: string
scheduleStartDate: string
scheduleEndDate: string
Expand Down Expand Up @@ -485,17 +492,16 @@ const Schedule = <T extends {
};


const selectedDevice = inputDevices.find(({ name }) => name === formik.values.location);

const renderInputDeviceOptions = () => {
if (formik.values.location) {
const inputDevice = inputDevices.find(
({ name }) => name === formik.values.location,
);
if (!inputDevice) {
if (!selectedDevice) {
return <></>;
}
return (
<SchedulingInputs
inputs={inputDevice.inputs}
inputs={selectedDevice.inputs}
/>
);
}
Expand Down Expand Up @@ -759,17 +765,30 @@ const Schedule = <T extends {
if (inputDevice) {
await formik.setFieldValue("inputs", inputDevice.inputs.map(input => input.id));
}
// Select all options of the location
for (const { field, list } of captureOptions) {
await formik.setFieldValue(field, inputDevice ? inputDevice[list].map(option => option.id) : []);
}
// Set location
await formik.setFieldValue("location", value);
}}
/>
<tr>
<td>{t("EVENTS.EVENTS.NEW.SOURCE.PLACEHOLDER.INPUTS")}</td>
<td>
{/* Render checkbox for each input option of the selected input device*/}
{renderInputDeviceOptions()}
</td>
</tr>
{/* The inputs are not offered, if the content configuration determines them */}
{!contentOverridesInputs(selectedDevice) && (
<tr>
<td>{t("EVENTS.EVENTS.NEW.SOURCE.PLACEHOLDER.INPUTS")}</td>
<td>
{/* Render checkbox for each input option of the selected input device*/}
{renderInputDeviceOptions()}
</td>
</tr>
)}
{/* Other options the selected location offers */}
<SchedulingCaptureOptions
agent={selectedDevice}
selection={formik.values}
disabled={false}
/>
</tbody>
</table>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { useTranslation } from "react-i18next";
import SchedulingInputs from "./SchedulingInputs";
import {
CaptureOptionLists,
CaptureOptionSelection,
captureOptions,
} from "../../../../../slices/recordingSlice";

/**
* Renders a row for every option of a capture agent that can be chosen for an event, in the same way as the inputs
*/
const SchedulingCaptureOptions = ({
agent,
selection,
disabled,
}: {
agent: CaptureOptionLists | undefined,
selection: CaptureOptionSelection,
// Only show what is selected
disabled: boolean,
}) => {
const { t } = useTranslation();

return (
<>
{captureOptions.map(({ field, list, label }) => {
const options = agent?.[list] ?? [];
if (options.length === 0) {
return null;
}

return (
<tr key={field}>
<td>{t(label)}</td>
<td>
{field === "deviceContent" && (
<p>{t("CAPTURE_AGENT.OPTIONS.CONTENT_NOTICE")}</p>
)}
{disabled
? options.filter(option => selection[field].includes(option.id)).map(option => (
<span key={option.id}>
{t(option.value, option.id)}
<br />
</span>
))
: <SchedulingInputs name={field} inputs={options} />}
</td>
</tr>
);
})}
</>
);
};

export default SchedulingCaptureOptions;
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ import { useTranslation } from "react-i18next";
import { Field } from "formik";

const SchedulingInputs = ({
name = "inputs",
inputs,
}: {
// Name of the form field, that holds the ids of the selected inputs
name?: string,
inputs: {
id: string,
value: string
Expand All @@ -17,7 +20,7 @@ const SchedulingInputs = ({
(input, key) => (
<label key={key}>
<Field
name="inputs"
name={name}
type="checkbox"
value={input.id}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,53 @@ const CapabilitiesDetailsTab: React.FC<{
}) => {
const { t } = useTranslation();

const enabled = (flag: boolean) => t(flag ? "YES" : "NO");
const config = agent.parsedCapabilities?.config;

return (
<ModalContentTable>
{/* Which ways of capturing the agent supports. Only agents using capture agent API 2.x report this. */}
{agent.version === "2" && config && (
<div className="obj tbl-details">
<header>
<span>{t("RECORDINGS.RECORDINGS.DETAILS.CAPABILITIES.MODES.CAPTION")}</span>
</header>
<div className="obj-container">
<table className="main-tbl">
<tbody>
<tr>
<td>{t("RECORDINGS.RECORDINGS.DETAILS.CAPABILITIES.MODES.LOCAL")}</td>
<td>{enabled(config.local.capture)}</td>
</tr>
{config.local.capture && (
<tr>
<td>
{t("RECORDINGS.RECORDINGS.DETAILS.CAPABILITIES.MODES.LOCAL")}
{" – "}
{t("RECORDINGS.RECORDINGS.DETAILS.CAPABILITIES.MODES.START_PAUSED")}
</td>
<td>{enabled(config.local.startpaused)}</td>
</tr>
)}
<tr>
<td>{t("RECORDINGS.RECORDINGS.DETAILS.CAPABILITIES.MODES.STREAM")}</td>
<td>{enabled(config.stream.stream)}</td>
</tr>
{config.stream.stream && (
<tr>
<td>
{t("RECORDINGS.RECORDINGS.DETAILS.CAPABILITIES.MODES.STREAM")}
{" – "}
{t("RECORDINGS.RECORDINGS.DETAILS.CAPABILITIES.MODES.START_PAUSED")}
</td>
<td>{enabled(config.stream.startpaused)}</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
)}
{/* If capabilities has no item show corresponding message */}
{agent.capabilities.length > 0 ? (
<div className="obj tbl-details">
Expand Down
Loading
Loading