@getontime/cli 4.0.2 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/assets/{Backstage-CAjkmeJm.js → Backstage-BhtXVpms.js} +2 -2
- package/client/assets/Backstage-BhtXVpms.js.br +0 -0
- package/client/assets/Backstage-BhtXVpms.js.gz +0 -0
- package/client/assets/{Backstage-CAjkmeJm.js.map → Backstage-BhtXVpms.js.map} +1 -1
- package/client/assets/{Countdown-ChuA9az_.js → Countdown-NmGi1KMx.js} +2 -2
- package/client/assets/Countdown-NmGi1KMx.js.br +0 -0
- package/client/assets/Countdown-NmGi1KMx.js.gz +0 -0
- package/client/assets/Countdown-NmGi1KMx.js.map +1 -0
- package/client/assets/{CustomTranslationModal-C3R_2T5s.js → CustomTranslationModal-BBNxpds0.js} +2 -2
- package/client/assets/CustomTranslationModal-BBNxpds0.js.br +0 -0
- package/client/assets/CustomTranslationModal-BBNxpds0.js.gz +0 -0
- package/client/assets/{CustomTranslationModal-C3R_2T5s.js.map → CustomTranslationModal-BBNxpds0.js.map} +1 -1
- package/client/assets/{DelayIndicator-vT7n8ypf.js → DelayIndicator-CFCDQ7FN.js} +2 -2
- package/client/assets/DelayIndicator-CFCDQ7FN.js.br +0 -0
- package/client/assets/DelayIndicator-CFCDQ7FN.js.gz +0 -0
- package/client/assets/{DelayIndicator-vT7n8ypf.js.map → DelayIndicator-CFCDQ7FN.js.map} +1 -1
- package/client/assets/{EditorFeatureWrapper-DHfuO3EA.js → EditorFeatureWrapper-D55c8JBz.js} +2 -2
- package/client/assets/EditorFeatureWrapper-D55c8JBz.js.br +0 -0
- package/client/assets/EditorFeatureWrapper-D55c8JBz.js.gz +0 -0
- package/client/assets/{EditorFeatureWrapper-DHfuO3EA.js.map → EditorFeatureWrapper-D55c8JBz.js.map} +1 -1
- package/client/assets/{EditorUtils-Da5ALK1P.js → EditorUtils-CFE106qQ.js} +2 -2
- package/client/assets/EditorUtils-CFE106qQ.js.br +0 -0
- package/client/assets/EditorUtils-CFE106qQ.js.gz +0 -0
- package/client/assets/{EditorUtils-Da5ALK1P.js.map → EditorUtils-CFE106qQ.js.map} +1 -1
- package/client/assets/{Empty-gWT_HMeu.js → Empty-C-JO_XAr.js} +2 -2
- package/client/assets/Empty-C-JO_XAr.js.br +2 -0
- package/client/assets/Empty-C-JO_XAr.js.gz +0 -0
- package/client/assets/{Empty-gWT_HMeu.js.map → Empty-C-JO_XAr.js.map} +1 -1
- package/client/assets/{EmptyPage-Dcbg6rmF.js → EmptyPage-BSzsxpGg.js} +2 -2
- package/client/assets/EmptyPage-BSzsxpGg.js.br +1 -0
- package/client/assets/EmptyPage-BSzsxpGg.js.gz +0 -0
- package/client/assets/{EmptyPage-Dcbg6rmF.js.map → EmptyPage-BSzsxpGg.js.map} +1 -1
- package/client/assets/{FollowButton-CSqJSvix.js → FollowButton-Mox6N4JW.js} +2 -2
- package/client/assets/FollowButton-Mox6N4JW.js.br +0 -0
- package/client/assets/FollowButton-Mox6N4JW.js.gz +0 -0
- package/client/assets/{FollowButton-CSqJSvix.js.map → FollowButton-Mox6N4JW.js.map} +1 -1
- package/client/assets/MessageControlExport-BL2ip9qN.js +2 -0
- package/client/assets/MessageControlExport-BL2ip9qN.js.br +0 -0
- package/client/assets/MessageControlExport-BL2ip9qN.js.gz +0 -0
- package/client/assets/{MessageControlExport-lXK21piH.js.map → MessageControlExport-BL2ip9qN.js.map} +1 -1
- package/client/assets/{MilestoneEditor-Bge8xLrV.js → MilestoneEditor-DcWPGKNK.js} +2 -2
- package/client/assets/MilestoneEditor-DcWPGKNK.js.br +0 -0
- package/client/assets/MilestoneEditor-DcWPGKNK.js.gz +0 -0
- package/client/assets/{MilestoneEditor-Bge8xLrV.js.map → MilestoneEditor-DcWPGKNK.js.map} +1 -1
- package/client/assets/Modal-D3tAPV2u.css +1 -0
- package/client/assets/Modal-D3tAPV2u.css.br +0 -0
- package/client/assets/Modal-D3tAPV2u.css.gz +0 -0
- package/client/assets/Modal-krcwDRb-.js +2 -0
- package/client/assets/Modal-krcwDRb-.js.br +0 -0
- package/client/assets/Modal-krcwDRb-.js.gz +0 -0
- package/client/assets/Modal-krcwDRb-.js.map +1 -0
- package/client/assets/{MultiPartProgressBar-D3jJZjb5.js → MultiPartProgressBar-BXQbpM-j.js} +2 -2
- package/client/assets/MultiPartProgressBar-BXQbpM-j.js.br +0 -0
- package/client/assets/MultiPartProgressBar-BXQbpM-j.js.gz +0 -0
- package/client/assets/{MultiPartProgressBar-D3jJZjb5.js.map → MultiPartProgressBar-BXQbpM-j.js.map} +1 -1
- package/client/assets/{OperatorExport-BUhxjLUx.js → OperatorExport-C50KHBrD.js} +2 -2
- package/client/assets/OperatorExport-C50KHBrD.js.br +0 -0
- package/client/assets/OperatorExport-C50KHBrD.js.gz +0 -0
- package/client/assets/{OperatorExport-BUhxjLUx.js.map → OperatorExport-C50KHBrD.js.map} +1 -1
- package/client/assets/OverviewWrapper-MGJ1uE5W.js +2 -0
- package/client/assets/OverviewWrapper-MGJ1uE5W.js.br +0 -0
- package/client/assets/OverviewWrapper-MGJ1uE5W.js.gz +0 -0
- package/client/assets/OverviewWrapper-MGJ1uE5W.js.map +1 -0
- package/client/assets/{ProjectInfo-z4k3cipS.js → ProjectInfo-CJ-GLvVG.js} +2 -2
- package/client/assets/ProjectInfo-CJ-GLvVG.js.br +0 -0
- package/client/assets/ProjectInfo-CJ-GLvVG.js.gz +0 -0
- package/client/assets/{ProjectInfo-z4k3cipS.js.map → ProjectInfo-CJ-GLvVG.js.map} +1 -1
- package/client/assets/{ProtectRoute-CrcWfOlG.js → ProtectRoute-DJ9xZnPI.js} +2 -2
- package/client/assets/ProtectRoute-DJ9xZnPI.js.br +0 -0
- package/client/assets/ProtectRoute-DJ9xZnPI.js.gz +0 -0
- package/client/assets/{ProtectRoute-CrcWfOlG.js.map → ProtectRoute-DJ9xZnPI.js.map} +1 -1
- package/client/assets/{ProtectedCuesheet-Deo4Aw6f.js → ProtectedCuesheet-B8tg6Mmo.js} +2 -2
- package/client/assets/ProtectedCuesheet-B8tg6Mmo.js.br +0 -0
- package/client/assets/ProtectedCuesheet-B8tg6Mmo.js.gz +0 -0
- package/client/assets/{ProtectedCuesheet-Deo4Aw6f.js.map → ProtectedCuesheet-B8tg6Mmo.js.map} +1 -1
- package/client/assets/ProtectedEditor-Bl4wV72N.js +3 -0
- package/client/assets/ProtectedEditor-Bl4wV72N.js.br +0 -0
- package/client/assets/ProtectedEditor-Bl4wV72N.js.gz +0 -0
- package/client/assets/ProtectedEditor-Bl4wV72N.js.map +1 -0
- package/client/assets/{RundownEntry-D61IqkXb.js → RundownEntry-D9tXNXPy.js} +2 -2
- package/client/assets/RundownEntry-D9tXNXPy.js.br +0 -0
- package/client/assets/RundownEntry-D9tXNXPy.js.gz +0 -0
- package/client/assets/{RundownEntry-D61IqkXb.js.map → RundownEntry-D9tXNXPy.js.map} +1 -1
- package/client/assets/RundownExport-D6uAmFbb.js +3 -0
- package/client/assets/RundownExport-D6uAmFbb.js.br +0 -0
- package/client/assets/RundownExport-D6uAmFbb.js.gz +0 -0
- package/client/assets/RundownExport-D6uAmFbb.js.map +1 -0
- package/client/assets/{Select-CedN80WS.js → Select-BLA-yQMq.js} +2 -2
- package/client/assets/Select-BLA-yQMq.js.br +0 -0
- package/client/assets/Select-BLA-yQMq.js.gz +0 -0
- package/client/assets/{Select-CedN80WS.js.map → Select-BLA-yQMq.js.map} +1 -1
- package/client/assets/{Studio-DUzPBS6P.js → Studio-DbP92DTf.js} +2 -2
- package/client/assets/Studio-DbP92DTf.js.br +0 -0
- package/client/assets/Studio-DbP92DTf.js.gz +0 -0
- package/client/assets/{Studio-DUzPBS6P.js.map → Studio-DbP92DTf.js.map} +1 -1
- package/client/assets/{StyleEditor-D2z65PB7.js → StyleEditor-DNjZ46Qf.js} +2 -2
- package/client/assets/StyleEditor-DNjZ46Qf.js.br +0 -0
- package/client/assets/StyleEditor-DNjZ46Qf.js.gz +0 -0
- package/client/assets/{StyleEditor-D2z65PB7.js.map → StyleEditor-DNjZ46Qf.js.map} +1 -1
- package/client/assets/{SuperscriptTime-CIrcMcyg.js → SuperscriptTime-C8ypTVpH.js} +2 -2
- package/client/assets/SuperscriptTime-C8ypTVpH.js.br +0 -0
- package/client/assets/SuperscriptTime-C8ypTVpH.js.gz +0 -0
- package/client/assets/{SuperscriptTime-CIrcMcyg.js.map → SuperscriptTime-C8ypTVpH.js.map} +1 -1
- package/client/assets/{TimeElements-CALNfv6u.js → TimeElements-DlEBhXe0.js} +2 -2
- package/client/assets/TimeElements-DlEBhXe0.js.br +0 -0
- package/client/assets/TimeElements-DlEBhXe0.js.gz +0 -0
- package/client/assets/{TimeElements-CALNfv6u.js.map → TimeElements-DlEBhXe0.js.map} +1 -1
- package/client/assets/{TimeInput-Dg1naiy3.js → TimeInput-DU09ewqh.js} +2 -2
- package/client/assets/TimeInput-DU09ewqh.js.br +0 -0
- package/client/assets/TimeInput-DU09ewqh.js.gz +0 -0
- package/client/assets/{TimeInput-Dg1naiy3.js.map → TimeInput-DU09ewqh.js.map} +1 -1
- package/client/assets/{TimelinePage-Cwm0svjN.js → TimelinePage-DTwqRihn.js} +2 -2
- package/client/assets/TimelinePage-DTwqRihn.js.br +0 -0
- package/client/assets/TimelinePage-DTwqRihn.js.gz +0 -0
- package/client/assets/{TimelinePage-Cwm0svjN.js.map → TimelinePage-DTwqRihn.js.map} +1 -1
- package/client/assets/{Timer-BvEmZbmF.css → Timer-B7nk3TMf.css} +1 -1
- package/client/assets/Timer-B7nk3TMf.css.br +0 -0
- package/client/assets/Timer-B7nk3TMf.css.gz +0 -0
- package/client/assets/{Timer-BVXskRjc.js → Timer-jjWAunJc.js} +2 -2
- package/client/assets/Timer-jjWAunJc.js.br +0 -0
- package/client/assets/Timer-jjWAunJc.js.gz +0 -0
- package/client/assets/{Timer-BVXskRjc.js.map → Timer-jjWAunJc.js.map} +1 -1
- package/client/assets/TimerControlExport-i0ZDpUx7.js +2 -0
- package/client/assets/TimerControlExport-i0ZDpUx7.js.br +0 -0
- package/client/assets/TimerControlExport-i0ZDpUx7.js.gz +0 -0
- package/client/assets/{TimerControlExport-C8ECtLBd.js.map → TimerControlExport-i0ZDpUx7.js.map} +1 -1
- package/client/assets/{TitleCard-CZl9wSHS.js → TitleCard-BgOtucv6.js} +2 -2
- package/client/assets/TitleCard-BgOtucv6.js.br +0 -0
- package/client/assets/TitleCard-BgOtucv6.js.gz +0 -0
- package/client/assets/{TitleCard-CZl9wSHS.js.map → TitleCard-BgOtucv6.js.map} +1 -1
- package/client/assets/{Tooltip-D9XRnwOW.js → Tooltip-C0rGHLsB.js} +2 -2
- package/client/assets/Tooltip-C0rGHLsB.js.br +0 -0
- package/client/assets/Tooltip-C0rGHLsB.js.gz +0 -0
- package/client/assets/{Tooltip-D9XRnwOW.js.map → Tooltip-C0rGHLsB.js.map} +1 -1
- package/client/assets/{ViewLogo-_3Z1hIHi.js → ViewLogo--9miplQv.js} +2 -2
- package/client/assets/ViewLogo--9miplQv.js.br +0 -0
- package/client/assets/ViewLogo--9miplQv.js.gz +0 -0
- package/client/assets/{ViewLogo-_3Z1hIHi.js.map → ViewLogo--9miplQv.js.map} +1 -1
- package/client/assets/{ViewParamsEditor-Bca1TIDW.js → ViewParamsEditor-BFu_0oIb.js} +2 -2
- package/client/assets/ViewParamsEditor-BFu_0oIb.js.br +0 -0
- package/client/assets/ViewParamsEditor-BFu_0oIb.js.gz +0 -0
- package/client/assets/{ViewParamsEditor-Bca1TIDW.js.map → ViewParamsEditor-BFu_0oIb.js.map} +1 -1
- package/client/assets/{dateConfig-DRQGMWDF.js → dateConfig-WYqMzV9D.js} +2 -2
- package/client/assets/dateConfig-WYqMzV9D.js.br +0 -0
- package/client/assets/dateConfig-WYqMzV9D.js.gz +0 -0
- package/client/assets/{dateConfig-DRQGMWDF.js.map → dateConfig-WYqMzV9D.js.map} +1 -1
- package/client/assets/{editorSettings-BU0pTMSY.js → editorSettings-CCHx-wCx.js} +2 -2
- package/client/assets/editorSettings-CCHx-wCx.js.br +0 -0
- package/client/assets/editorSettings-CCHx-wCx.js.gz +0 -0
- package/client/assets/{editorSettings-BU0pTMSY.js.map → editorSettings-CCHx-wCx.js.map} +1 -1
- package/client/assets/{getProgress-Cw79NL_O.js → getProgress-B94Ieskb.js} +2 -2
- package/client/assets/getProgress-B94Ieskb.js.br +0 -0
- package/client/assets/getProgress-B94Ieskb.js.gz +0 -0
- package/client/assets/{getProgress-Cw79NL_O.js.map → getProgress-B94Ieskb.js.map} +1 -1
- package/client/assets/{index-BQEUaoAf.js → index-njXwwjfn.js} +3 -3
- package/client/assets/index-njXwwjfn.js.br +0 -0
- package/client/assets/index-njXwwjfn.js.gz +0 -0
- package/client/assets/{index-BQEUaoAf.js.map → index-njXwwjfn.js.map} +1 -1
- package/client/assets/{offset-DJAHqjFW.js → offset-D1q-72D-.js} +2 -2
- package/client/assets/offset-D1q-72D-.js.br +0 -0
- package/client/assets/offset-D1q-72D-.js.gz +0 -0
- package/client/assets/{offset-DJAHqjFW.js.map → offset-D1q-72D-.js.map} +1 -1
- package/client/assets/{parseUserTime-BeTKj08M.js → parseUserTime-Bc1pSJR2.js} +2 -2
- package/client/assets/parseUserTime-Bc1pSJR2.js.br +0 -0
- package/client/assets/parseUserTime-Bc1pSJR2.js.gz +0 -0
- package/client/assets/{parseUserTime-BeTKj08M.js.map → parseUserTime-Bc1pSJR2.js.map} +1 -1
- package/client/assets/{playbackstate-B_khF6xU.js → playbackstate-BpzbtG9F.js} +2 -2
- package/client/assets/playbackstate-BpzbtG9F.js.br +0 -0
- package/client/assets/playbackstate-BpzbtG9F.js.gz +0 -0
- package/client/assets/{playbackstate-B_khF6xU.js.map → playbackstate-BpzbtG9F.js.map} +1 -1
- package/client/assets/{presentation.utils-KwY-ACf7.js → presentation.utils-B2baBe3j.js} +2 -2
- package/client/assets/presentation.utils-B2baBe3j.js.br +0 -0
- package/client/assets/presentation.utils-B2baBe3j.js.gz +0 -0
- package/client/assets/{presentation.utils-KwY-ACf7.js.map → presentation.utils-B2baBe3j.js.map} +1 -1
- package/client/assets/{rundownUtils-BZHazkXR.js → rundownUtils-H6xvQyre.js} +2 -2
- package/client/assets/rundownUtils-H6xvQyre.js.br +0 -0
- package/client/assets/rundownUtils-H6xvQyre.js.gz +0 -0
- package/client/assets/{rundownUtils-BZHazkXR.js.map → rundownUtils-H6xvQyre.js.map} +1 -1
- package/client/assets/{useCustomFields-DqCYz8Kt.js → useCustomFields-Da0Li7nQ.js} +2 -2
- package/client/assets/useCustomFields-Da0Li7nQ.js.br +0 -0
- package/client/assets/useCustomFields-Da0Li7nQ.js.gz +0 -0
- package/client/assets/{useCustomFields-DqCYz8Kt.js.map → useCustomFields-Da0Li7nQ.js.map} +1 -1
- package/client/assets/{useFollowComponent-Ctfhf2or.js → useFollowComponent-Qo3FobyV.js} +2 -2
- package/client/assets/useFollowComponent-Qo3FobyV.js.br +0 -0
- package/client/assets/useFollowComponent-Qo3FobyV.js.gz +0 -0
- package/client/assets/{useFollowComponent-Ctfhf2or.js.map → useFollowComponent-Qo3FobyV.js.map} +1 -1
- package/client/assets/{useProjectData-C1hVamxc.js → useProjectData-DW06zQvF.js} +2 -2
- package/client/assets/useProjectData-DW06zQvF.js.br +0 -0
- package/client/assets/useProjectData-DW06zQvF.js.gz +0 -0
- package/client/assets/{useProjectData-C1hVamxc.js.map → useProjectData-DW06zQvF.js.map} +1 -1
- package/client/assets/{useReport-B4dMYcNL.js → useReport-DhFY2L8v.js} +2 -2
- package/client/assets/useReport-DhFY2L8v.js.br +0 -0
- package/client/assets/useReport-DhFY2L8v.js.gz +0 -0
- package/client/assets/{useReport-B4dMYcNL.js.map → useReport-DhFY2L8v.js.map} +1 -1
- package/client/assets/useRundown-ihoU8qBi.js +2 -0
- package/client/assets/useRundown-ihoU8qBi.js.br +0 -0
- package/client/assets/useRundown-ihoU8qBi.js.gz +0 -0
- package/client/assets/useRundown-ihoU8qBi.js.map +1 -0
- package/client/assets/{useWindowTitle-DqdFTWns.js → useWindowTitle-B2UzPuki.js} +2 -2
- package/client/assets/useWindowTitle-B2UzPuki.js.br +0 -0
- package/client/assets/useWindowTitle-B2UzPuki.js.gz +0 -0
- package/client/assets/{useWindowTitle-DqdFTWns.js.map → useWindowTitle-B2UzPuki.js.map} +1 -1
- package/client/assets/{validateEvent-P9sf7C10.js → validateEvent-BJMwP_mq.js} +2 -2
- package/client/assets/validateEvent-BJMwP_mq.js.br +0 -0
- package/client/assets/validateEvent-BJMwP_mq.js.gz +0 -0
- package/client/assets/{validateEvent-P9sf7C10.js.map → validateEvent-BJMwP_mq.js.map} +1 -1
- package/client/assets/{vendor-CCiSQ9k9.js → vendor-9UkPSc5K.js} +3 -3
- package/client/assets/vendor-9UkPSc5K.js.br +0 -0
- package/client/assets/vendor-9UkPSc5K.js.gz +0 -0
- package/client/assets/{vendor-CCiSQ9k9.js.map → vendor-9UkPSc5K.js.map} +1 -1
- package/client/assets/{viewLoader.utils-CmM-4-pk.js → viewLoader.utils-DQGhrjSp.js} +2 -2
- package/client/assets/viewLoader.utils-DQGhrjSp.js.br +0 -0
- package/client/assets/viewLoader.utils-DQGhrjSp.js.gz +0 -0
- package/client/assets/{viewLoader.utils-CmM-4-pk.js.map → viewLoader.utils-DQGhrjSp.js.map} +1 -1
- package/client/index.html +2 -2
- package/package.json +1 -1
- package/server/index.cjs +82 -82
- package/client/assets/Backstage-CAjkmeJm.js.br +0 -0
- package/client/assets/Backstage-CAjkmeJm.js.gz +0 -0
- package/client/assets/Countdown-ChuA9az_.js.br +0 -0
- package/client/assets/Countdown-ChuA9az_.js.gz +0 -0
- package/client/assets/Countdown-ChuA9az_.js.map +0 -1
- package/client/assets/CustomTranslationModal-C3R_2T5s.js.br +0 -0
- package/client/assets/CustomTranslationModal-C3R_2T5s.js.gz +0 -0
- package/client/assets/DelayIndicator-vT7n8ypf.js.br +0 -0
- package/client/assets/DelayIndicator-vT7n8ypf.js.gz +0 -0
- package/client/assets/EditorFeatureWrapper-DHfuO3EA.js.br +0 -0
- package/client/assets/EditorFeatureWrapper-DHfuO3EA.js.gz +0 -0
- package/client/assets/EditorUtils-Da5ALK1P.js.br +0 -0
- package/client/assets/EditorUtils-Da5ALK1P.js.gz +0 -0
- package/client/assets/Empty-gWT_HMeu.js.br +0 -0
- package/client/assets/Empty-gWT_HMeu.js.gz +0 -0
- package/client/assets/EmptyPage-Dcbg6rmF.js.br +0 -0
- package/client/assets/EmptyPage-Dcbg6rmF.js.gz +0 -0
- package/client/assets/FollowButton-CSqJSvix.js.br +0 -0
- package/client/assets/FollowButton-CSqJSvix.js.gz +0 -0
- package/client/assets/MessageControlExport-lXK21piH.js +0 -2
- package/client/assets/MessageControlExport-lXK21piH.js.br +0 -0
- package/client/assets/MessageControlExport-lXK21piH.js.gz +0 -0
- package/client/assets/MilestoneEditor-Bge8xLrV.js.br +0 -0
- package/client/assets/MilestoneEditor-Bge8xLrV.js.gz +0 -0
- package/client/assets/Modal-BgJx3SNK.css +0 -1
- package/client/assets/Modal-BgJx3SNK.css.br +0 -0
- package/client/assets/Modal-BgJx3SNK.css.gz +0 -0
- package/client/assets/Modal-C2sFA0zf.js +0 -2
- package/client/assets/Modal-C2sFA0zf.js.br +0 -0
- package/client/assets/Modal-C2sFA0zf.js.gz +0 -0
- package/client/assets/Modal-C2sFA0zf.js.map +0 -1
- package/client/assets/MultiPartProgressBar-D3jJZjb5.js.br +0 -0
- package/client/assets/MultiPartProgressBar-D3jJZjb5.js.gz +0 -0
- package/client/assets/OperatorExport-BUhxjLUx.js.br +0 -0
- package/client/assets/OperatorExport-BUhxjLUx.js.gz +0 -0
- package/client/assets/OverviewWrapper-BveJ6GjK.js +0 -2
- package/client/assets/OverviewWrapper-BveJ6GjK.js.br +0 -0
- package/client/assets/OverviewWrapper-BveJ6GjK.js.gz +0 -0
- package/client/assets/OverviewWrapper-BveJ6GjK.js.map +0 -1
- package/client/assets/ProjectInfo-z4k3cipS.js.br +0 -0
- package/client/assets/ProjectInfo-z4k3cipS.js.gz +0 -0
- package/client/assets/ProtectRoute-CrcWfOlG.js.br +0 -0
- package/client/assets/ProtectRoute-CrcWfOlG.js.gz +0 -0
- package/client/assets/ProtectedCuesheet-Deo4Aw6f.js.br +0 -0
- package/client/assets/ProtectedCuesheet-Deo4Aw6f.js.gz +0 -0
- package/client/assets/ProtectedEditor-C_SYWpL2.js +0 -3
- package/client/assets/ProtectedEditor-C_SYWpL2.js.br +0 -0
- package/client/assets/ProtectedEditor-C_SYWpL2.js.gz +0 -0
- package/client/assets/ProtectedEditor-C_SYWpL2.js.map +0 -1
- package/client/assets/RundownEntry-D61IqkXb.js.br +0 -0
- package/client/assets/RundownEntry-D61IqkXb.js.gz +0 -0
- package/client/assets/RundownExport-C6YhMGOC.js +0 -3
- package/client/assets/RundownExport-C6YhMGOC.js.br +0 -0
- package/client/assets/RundownExport-C6YhMGOC.js.gz +0 -0
- package/client/assets/RundownExport-C6YhMGOC.js.map +0 -1
- package/client/assets/Select-CedN80WS.js.br +0 -0
- package/client/assets/Select-CedN80WS.js.gz +0 -0
- package/client/assets/Studio-DUzPBS6P.js.br +0 -0
- package/client/assets/Studio-DUzPBS6P.js.gz +0 -0
- package/client/assets/StyleEditor-D2z65PB7.js.br +0 -0
- package/client/assets/StyleEditor-D2z65PB7.js.gz +0 -0
- package/client/assets/SuperscriptTime-CIrcMcyg.js.br +0 -0
- package/client/assets/SuperscriptTime-CIrcMcyg.js.gz +0 -0
- package/client/assets/TimeElements-CALNfv6u.js.br +0 -0
- package/client/assets/TimeElements-CALNfv6u.js.gz +0 -0
- package/client/assets/TimeInput-Dg1naiy3.js.br +0 -0
- package/client/assets/TimeInput-Dg1naiy3.js.gz +0 -0
- package/client/assets/TimelinePage-Cwm0svjN.js.br +0 -0
- package/client/assets/TimelinePage-Cwm0svjN.js.gz +0 -0
- package/client/assets/Timer-BVXskRjc.js.br +0 -0
- package/client/assets/Timer-BVXskRjc.js.gz +0 -0
- package/client/assets/Timer-BvEmZbmF.css.br +0 -0
- package/client/assets/Timer-BvEmZbmF.css.gz +0 -0
- package/client/assets/TimerControlExport-C8ECtLBd.js +0 -2
- package/client/assets/TimerControlExport-C8ECtLBd.js.br +0 -0
- package/client/assets/TimerControlExport-C8ECtLBd.js.gz +0 -0
- package/client/assets/TitleCard-CZl9wSHS.js.br +0 -0
- package/client/assets/TitleCard-CZl9wSHS.js.gz +0 -0
- package/client/assets/Tooltip-D9XRnwOW.js.br +0 -4
- package/client/assets/Tooltip-D9XRnwOW.js.gz +0 -0
- package/client/assets/ViewLogo-_3Z1hIHi.js.br +0 -0
- package/client/assets/ViewLogo-_3Z1hIHi.js.gz +0 -0
- package/client/assets/ViewParamsEditor-Bca1TIDW.js.br +0 -0
- package/client/assets/ViewParamsEditor-Bca1TIDW.js.gz +0 -0
- package/client/assets/dateConfig-DRQGMWDF.js.br +0 -0
- package/client/assets/dateConfig-DRQGMWDF.js.gz +0 -0
- package/client/assets/editorSettings-BU0pTMSY.js.br +0 -0
- package/client/assets/editorSettings-BU0pTMSY.js.gz +0 -0
- package/client/assets/getProgress-Cw79NL_O.js.br +0 -0
- package/client/assets/getProgress-Cw79NL_O.js.gz +0 -0
- package/client/assets/index-BQEUaoAf.js.br +0 -0
- package/client/assets/index-BQEUaoAf.js.gz +0 -0
- package/client/assets/offset-DJAHqjFW.js.br +0 -0
- package/client/assets/offset-DJAHqjFW.js.gz +0 -0
- package/client/assets/parseUserTime-BeTKj08M.js.br +0 -0
- package/client/assets/parseUserTime-BeTKj08M.js.gz +0 -0
- package/client/assets/playbackstate-B_khF6xU.js.br +0 -0
- package/client/assets/playbackstate-B_khF6xU.js.gz +0 -0
- package/client/assets/presentation.utils-KwY-ACf7.js.br +0 -0
- package/client/assets/presentation.utils-KwY-ACf7.js.gz +0 -0
- package/client/assets/rundownUtils-BZHazkXR.js.br +0 -0
- package/client/assets/rundownUtils-BZHazkXR.js.gz +0 -0
- package/client/assets/useCustomFields-DqCYz8Kt.js.br +0 -0
- package/client/assets/useCustomFields-DqCYz8Kt.js.gz +0 -0
- package/client/assets/useFollowComponent-Ctfhf2or.js.br +0 -0
- package/client/assets/useFollowComponent-Ctfhf2or.js.gz +0 -0
- package/client/assets/useProjectData-C1hVamxc.js.br +0 -0
- package/client/assets/useProjectData-C1hVamxc.js.gz +0 -0
- package/client/assets/useReport-B4dMYcNL.js.br +0 -0
- package/client/assets/useReport-B4dMYcNL.js.gz +0 -0
- package/client/assets/useRundown-BfpjcCEJ.js +0 -2
- package/client/assets/useRundown-BfpjcCEJ.js.br +0 -0
- package/client/assets/useRundown-BfpjcCEJ.js.gz +0 -0
- package/client/assets/useRundown-BfpjcCEJ.js.map +0 -1
- package/client/assets/useWindowTitle-DqdFTWns.js.br +0 -0
- package/client/assets/useWindowTitle-DqdFTWns.js.gz +0 -0
- package/client/assets/validateEvent-P9sf7C10.js.br +0 -3
- package/client/assets/validateEvent-P9sf7C10.js.gz +0 -0
- package/client/assets/vendor-CCiSQ9k9.js.br +0 -0
- package/client/assets/vendor-CCiSQ9k9.js.gz +0 -0
- package/client/assets/viewLoader.utils-CmM-4-pk.js.br +0 -0
- package/client/assets/viewLoader.utils-CmM-4-pk.js.gz +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"mappings":"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","names":["customFieldLabelToKey","label","defaultImportMap","useKeyDown","callback","targetKey","options","isDisabled","onKeyDown","useCallback","event","useEffect","ExternalLink","href","inline","children","handleClick","openLink","jsxs","cx","style","IoOpenOutline","getLatestVersion","res","axios","apiRepoLatest","placeholder","useAppVersion","fetchData","status","isFetching","isError","refetch","useQuery","APP_VERSION","previousData","_previousQuery","dayInMs","isLocalhost","hasUpdates","version","AppVersion","data","Panel.Paragraph","appVersion","Panel.Error","isOntimeCloud","jsx","AboutPanel","Fragment","Panel.Header","Panel.Section","Panel.Card","Panel.SubHeader","websiteUrl","githubSponsorUrl","buyMeACoffeeUrl","documentationUrl","githubUrl","discordUrl","useScrollIntoView","name","location","ref","useRef","oscApiDocsUrl","AutomationSettingsForm","enabledAutomations","enabledOscIn","oscPortIn","handleSubmit","reset","register","setError","watch","setValue","errors","isSubmitting","isDirty","isValid","useForm","onSubmit","formData","editAutomationSettings","error","message","maybeAxiosError","onReset","canSubmit","Panel.InlineElements","Button","Panel.Divider","Info","preventEscape","Panel.Loader","Panel.Title","Panel.ListGroup","Panel.ListItem","Panel.Field","_a","Switch","value","_b","_c","Input","isOnlyNumbers","humanConstants","staticAutocompleteOptions","eventStaticPropertiesNow","eventStaticPropertiesNext","makeAutoCompleteList","customFields","key","matchRemaining","a","b","i","searchString","selectFromLastTemplate","text","lastBraceIndex","TemplateInput","forwardRef","props","onChange","rest","useCustomFields","localRef","useClickOutside","setShowSuggestions","autocompleteList","useMemo","inputValue","setInputValue","useState","suggestions","setSuggestions","showSuggestions","updateSuggestions","template","suggestion","handleInputChange","handleSuggestion","prev","remaining","mergeRefs","cycles","isAutomation","automation","staticSelectProperties","staticNextSelectProperties","makeFieldList","checkDuplicates","triggers","triggersMap","duplicates","trigger","OntimeActionForm","index","rowErrors","selectedAction","setSelectedAction","handleSetAction","Select","translatedValue","_d","_e","integrationsDocsUrl","AutomationForm","onClose","isEdit","useAutomationSettings","fieldList","control","getValues","setFocus","fieldFilters","appendFilter","removeFilter","useFieldArray","fieldOutputs","appendOutput","removeOutput","handleAddNewFilter","handleAddNewOSCOutput","handleAddNewHTTPOutput","handleAddnewOntimeAction","handleTestOSCOutput","values","testOutput","handleTestHTTPOutput","handleTestOntimeAction","handleEdit","handleCreate","id","editAutomation","addAutomation","Panel.Indent","RadioGroup","field","IconButton","IoTrash","IoAdd","output","isOSCOutput","Tag","isHTTPOutput","_f","startsWithHttp","_g","isOntimeAction","_h","automationPlaceholder","AutomationsList","automations","automationFormData","setAutomationFormData","deleteError","setDeleteError","handleDelete","deleteAutomation","arrayAutomations","Panel.Table","Panel.TableEmpty","automationId","IoPencil","TriggerForm","initialId","initialTitle","initialAutomationId","initialTrigger","onCancel","postSubmit","editTrigger","addTrigger","automationSelect","cycle","TriggersListItem","title","duplicate","isEditing","setIsEditing","IoWarningOutline","TriggersList","showForm","setShowForm","deleteTrigger","canAdd","AutomationPanel","settingsRef","triggersRef","automationsRef","isLoading","InfoNif","useInfo","address","nif","linkToOtherHost","CopyTag","IoArrowUp","makeCSVFromArrayOfArrays","arrayOfArrays","stringify","getCombinedReport","report","rundown","flatOrder","combinedReport","entry","isOntimeEvent","csvHeader","makeReportCSV","csv","formatTime","ReportSettings","reportData","useReport","useRundown","clearReport","deleteAllReport","downloadCSV","blob","createBlob","downloadBlob","IoTrashBin","start","end","targetOptions","OntimeView","defaultValues","URLPresetForm","urlPreset","addPreset","updatePreset","isMutating","useUpdateUrlPreset","clearErrors","urlRef","setupSubmit","generateOptions","preset","generateUrlPresetOptions","unwrapError","validateParams","Panel.Description","Textarea","urlPresetsDocs","URLPresets","formState","setFormState","useUrlPresets","deletePreset","openNewForm","openEditForm","closeForm","handleLinks","FeaturePanel","presetsRef","linkRef","reportRef","GenerateLinkFormExport","excelPath","apiEntryUrl","upload","file","getWorksheetNames","importRundownPreview","downloadAsExcel","rundownId","fileName","response","sheetsPath","verifyAuthenticationStatus","requestConnection","sheetId","revokeAuthentication","previewRundown","uploadRundown","validateExcelImport","isExcelFile","validateProjectFile","isOntimeFile","validateLogo","dbPath","getDb","filename","downloadProject","fileDownload","fileContent","uploadProjectFile","patchData","patchDb","createProject","project","quickProject","getProjects","loadProject","loadDemo","duplicateProject","newFilename","url","decodedUrl","renameProject","deleteProject","headerLine","startFileNameIndex","endFileNameIndex","initialStepData","initialState","useSheetStore","create","set","get","patch","stepData","worksheetNames","currentImportMap","useGoogleSheet","queryClient","useQueryClient","patchStepData","state","setRundown","setCustomFields","fileOptions","rundowns","RUNDOWN","CUSTOM_FIELDS","namedImportMap","isNamedImportMap","obj","convertToImportMap","custom","accumulator","ontimeName","importName","persistImportMap","getPersistImportMap","getPersistedOptions","ImportMapForm","hasErrors","isSpreadsheet","onSubmitExport","onSubmitImport","revoke","fields","append","remove","loading","setLoading","handleExport","importMap","handleRevoke","handleImportPreview","deleteCustomImport","addCustomImport","canSubmitSpreadsheet","canSubmitGSheet","Tooltip","maybeOntimeError","checkRegex","googleSheetDocsUrl","GSheetInfo","GSheetSetup","connect","verifyAuth","setFile","authKey","setAuthKey","authLink","setAuthLink","setSheetId","setWorksheets","authenticationStatus","setAuthenticationStatus","authenticationError","getAuthStatus","result","untilAuthenticated","handleCancelFlow","handleClientSecret","handleConnect","attempts","names","handleAuthenticate","canConnect","canAuthenticate","isAuthenticated","isAuthenticating","IoShieldCheckmarkOutline","IoCheckmark","booleanToText","PreviewRundown","eventIndex","fieldKeys","fieldLabels","entryId","isOntimeGroup","colour","getAccessibleColour","isOntimeMilestone","countToEnd","skip","flag","millisToString","IoLink","ImportReview","onFinished","currentRundown","importRundown","resetPreview","handleCancel","applyImport","PreviewSpreadsheet","SourcesPanel","importFlow","setImportFlow","hasFile","setHasFile","exportRundown","fileInputRef","handleFile","fileToUpload","uploadExcel","getWorksheetNamesExcel","errorMessage","getErrorMessage","handleUpload","resetFlow","openGSheetFlow","cancelGSheetFlow","handleSubmitImportPreview","previewData","importRundownPreviewExcel","cancelImportMap","handleFinished","handleSubmitExport","isExcelFlow","isGSheetFlow","showInput","showCompleted","showAuth","showImportMap","showReview","IoDownloadOutline","Editor.Separator","IoCloudOutline","CustomFieldForm","initialColour","initialLabel","initialKey","_","setColour","type","newField","handleSelectColour","isEditMode","SwatchSelect","_field","CustomFieldEntry","fieldKey","onEdit","onDelete","Swatch","CustomFieldSettings","isAdding","setIsAdding","handleInitiateCreate","customField","postCustomField","handleEditField","editCustomField","deleteCustomField","AppLink","customFieldsDocsUrl","useProjectRundowns","PROJECT_RUNDOWNS","fetchProjectRundownList","queryRefetchIntervalSlow","useMutateProjectRundowns","ontimeQueryClient","useMutation","createRundown","deleteRundown","load","loadRundown","ManageRundownForm","ManageRundowns","isOpenDelete","deleteHandlers","useDisclosure","isOpenLoad","loadHandlers","isNewLoad","newHandlers","targetRundown","setTargetRundown","actionError","setActionError","openLoad","openDelete","submitRundownLoad","submitRundownDelete","handleDownloadXlsx","numEntries","isLoaded","DropdownMenu","IoDocumentOutline","IoEllipsisHorizontal","Dialog","RundownDefaultSettings","defaultDuration","linkPrevious","defaultTimeStrategy","defaultWarnTime","defaultDangerTime","defaultTimerType","defaultEndAction","setDefaultDuration","setLinkPrevious","setTimeStrategy","setWarnTime","setDangerTime","setDefaultTimerType","setDefaultEndAction","useEditorSettings","durationInMs","parseUserTime","warnTimeInMs","dangerTimeInMs","TimeStrategy","TimeInput","editorSettingsDefaults","TimerType","EndAction","ManagePanel","defaultsRef","customRef","rundownsRef","sheetsRef","RedirectClientModal","isOpen","currentPath","origin","path","setPath","selected","setSelected","setRedirect","setClientRemote","handleRedirect","newPath","enabledPresets","viewOptions","navigatorConstants","view","Modal","IoArrowForward","ClientList","useClientStore","store","clients","isOpenRedirect","redirectHandler","isOpenRename","renameHandler","setIdentify","targetId","setTargetId","openRename","openRedirect","ontimeClients","otherClients","targetClient","RenameClientModal","client","identify","isCurrent","ClientControlPanel","LogExport","extract","Log","NetworkLogPanel","clientsRef","logRef","isDocker","quickStartDefaults","QuickStart","invalidateAllCaches","ProjectCreateForm","handleSubmitCreate","placeholderProjectList","useProjectList","PROJECT_LIST","attempt","useOrderedProjectList","files","lastLoadedProject","reorderedProjectFiles","currentlyLoadedIndex","projectFiles","ProjectForm","action","makeProjectPatch","mergeKeys","patchObject","isKeyOfType","ProjectMergeForm","PROJECT_DATA","ProjectListItem","current","updatedAt","editingFilename","editingMode","onRefetch","onToggleEditMode","submitError","setSubmitError","handleSubmitAction","actionType","handleLoad","handleToggleEditMode","editMode","isCurrentlyBeingEdited","showProjectForm","showMergeForm","classes","ActionMenu","onChangeEditMode","onLoad","onMerge","handleRename","handleDuplicate","handleDownload","IoPencilOutline","IoCopyOutline","ProjectList","setEditingMode","setEditingFilename","handleClear","handleRefetch","numProjects","ManageProjects","searchParams","setSearchParams","useSearchParams","isCreatingProject","handleToggleCreate","handleSelectFile","handleImport","selectedFile","handleCloseForm","ProjectPanel","setLocation","manageProjectsRef","handleQuickClose","GeneralPinInput","formName","disabled","isVisible","setVisible","isAlphanumeric","IoEyeOutline","TranslationModal","lazy","__vitePreload","GeneralSettings","useSettings","handler","postSettings","disableInputs","disableSubmit","ProjectData","useProjectData","updateProjectData","useUpdateProjectData","handleUploadProjectLogo","uploadProjectLogo","projectLogoRest","uploadInputRef","handleClickUpload","handleDeleteLogo","e","handleAddCustom","projectLogoPath","idx","CodeEditor","CodeEditorModal","css","setCSS","setIsDirty","saveLoading","setSaveLoading","resetLoading","setResetLoading","cssRef","handleRestore","defaultCss","restoreCSSContents","handleSave","postCSSContents","clear","fetchServerCSS","getCSSContents","cssOverrideDocsUrl","ViewSettings","mutateAsync","useViewSettings","isCodeEditorOpen","codeEditorHandler","SwatchPickerRHF","SettingsPanel","dataRef","generalRef","viewRef","ShutdownPanel","isElectron","sendToElectron","useElectronEvent","cancelRef","sendShutdown","canShutdown","Panel.Highlight","PanelContent","IoClose","staticOptions","useAppSettingsMenu","option","settingsKey","useAppSettingsNavigation","selectedPanel","panel","close","panelId","PanelList","isSelected","PanelListItem","isKeyEnter","secondary","secondaryClasses","AppSettings","ErrorBoundary","memo","EditorOverview","OverviewWrapper","TitleOverview","StartTimes","ProgressOverview","OffsetOverview","MetadataTimes","ClockOverview","ImportProjectButton","onFinish","WelcomeProjectList","Welcome","navigate","useNavigate","handleLoadProject","handleLoadDemo","handleCallCreate","Editor.Title","Editor.Label","Checkbox","checked","postShowWelcomeDialog","WelcomePlacement","showDialog","useDialogStore","clearDialog","Rundown","TimerControl","MessageControl","Editor","isSettingsOpen","useWindowTitle","useElectronListener","toggleSettings","useHotkeys","styles","NavigationMenu","IoApps","IoSettingsOutline","ProtectedEditor","ProtectRoute"],"ignoreList":[],"sources":["../../../../packages/utils/src/customField-utils/customFieldUtils.ts","../../../../packages/utils/src/feature/spreadsheet-import/spreadsheetImport.ts","../../src/common/hooks/useKeyDown.ts","../../src/common/components/link/external-link/ExternalLink.tsx","../../src/common/api/external.ts","../../src/common/hooks-query/useAppVersion.ts","../../src/features/app-settings/panel/about-panel/AppVersion.tsx","../../src/features/app-settings/panel/about-panel/AboutPanel.tsx","../../src/common/hooks/useScrollIntoView.tsx","../../src/features/app-settings/panel/automations-panel/AutomationSettingsForm.tsx","../../src/features/app-settings/panel/automations-panel/template-input/templateInput.utils.ts","../../src/features/app-settings/panel/automations-panel/template-input/TemplateInput.tsx","../../src/features/app-settings/panel/automations-panel/automationUtils.ts","../../src/features/app-settings/panel/automations-panel/OntimeActionForm.tsx","../../src/features/app-settings/panel/automations-panel/AutomationForm.tsx","../../src/features/app-settings/panel/automations-panel/AutomationsList.tsx","../../src/features/app-settings/panel/automations-panel/TriggerForm.tsx","../../src/features/app-settings/panel/automations-panel/TriggersListItem.tsx","../../src/features/app-settings/panel/automations-panel/TriggersList.tsx","../../src/features/app-settings/panel/automations-panel/AutomationPanel.tsx","../../src/features/app-settings/panel/network-panel/NetworkInterfaces.tsx","../../src/common/utils/csv.ts","../../src/features/app-settings/panel/feature-panel/reportSettings.utils.ts","../../src/features/app-settings/panel/feature-panel/ReportSettings.tsx","../../src/features/app-settings/panel/feature-panel/composite/URLPresetForm.tsx","../../src/features/app-settings/panel/feature-panel/URLPresets.tsx","../../src/features/app-settings/panel/feature-panel/FeaturePanel.tsx","../../src/common/api/excel.ts","../../src/common/api/sheets.ts","../../src/common/utils/uploadUtils.ts","../../src/common/api/db.ts","../../src/features/app-settings/panel/manage-panel/sources-panel/useSheetStore.ts","../../src/features/app-settings/panel/manage-panel/sources-panel/useGoogleSheet.ts","../../src/features/app-settings/panel/manage-panel/sources-panel/import-map/importMapUtils.ts","../../src/features/app-settings/panel/manage-panel/sources-panel/import-map/ImportMapForm.tsx","../../src/features/app-settings/panel/manage-panel/sources-panel/GSheetInfo.tsx","../../src/features/app-settings/panel/manage-panel/sources-panel/GSheetSetup.tsx","../../src/features/app-settings/panel/manage-panel/sources-panel/preview/PreviewRundown.tsx","../../src/features/app-settings/panel/manage-panel/sources-panel/ImportReview.tsx","../../src/features/app-settings/panel/manage-panel/sources-panel/SourcesPanel.tsx","../../src/features/app-settings/panel/manage-panel/composite/CustomFieldForm.tsx","../../src/features/app-settings/panel/manage-panel/composite/CustomFieldEntry.tsx","../../src/features/app-settings/panel/manage-panel/CustomFields.tsx","../../src/common/hooks-query/useProjectRundowns.ts","../../src/features/app-settings/panel/manage-panel/ManageRundownForm.tsx","../../src/features/app-settings/panel/manage-panel/ManageRundowns.tsx","../../src/features/app-settings/panel/manage-panel/RundownDefaultSettings.tsx","../../src/features/app-settings/panel/manage-panel/ManagePanel.tsx","../../src/common/components/client-modal/RedirectClientModal.tsx","../../src/features/app-settings/panel/network-panel/client-control/ClientList.tsx","../../src/features/app-settings/panel/network-panel/client-control/ClientControlPanel.tsx","../../src/features/app-settings/panel/network-panel/NetworkLogExport.tsx","../../src/features/app-settings/panel/network-panel/NetworkLogPanel.tsx","../../src/features/app-settings/quick-start/quickStart.utils.ts","../../src/features/app-settings/quick-start/QuickStart.tsx","../../src/features/app-settings/panel/project-panel/ProjectCreateForm.tsx","../../src/common/hooks-query/useProjectList.ts","../../src/features/app-settings/panel/project-panel/ProjectForm.tsx","../../src/features/app-settings/panel/project-panel/project.utils.ts","../../src/features/app-settings/panel/project-panel/ProjectMergeForm.tsx","../../src/features/app-settings/panel/project-panel/ProjectListItem.tsx","../../src/features/app-settings/panel/project-panel/ProjectList.tsx","../../src/features/app-settings/panel/project-panel/ManageProjects.tsx","../../src/features/app-settings/panel/project-panel/ProjectPanel.tsx","../../src/features/app-settings/panel/settings-panel/composite/GeneralPinInput.tsx","../../src/features/app-settings/panel/settings-panel/GeneralSettings.tsx","../../src/features/app-settings/panel/settings-panel/ProjectData.tsx","../../src/features/app-settings/panel/settings-panel/composite/StyleEditorModal.tsx","../../src/features/app-settings/panel/settings-panel/ViewSettings.tsx","../../src/features/app-settings/panel/settings-panel/SettingsPanel.tsx","../../src/features/app-settings/panel/shutdown-panel/ShutdownPanel.tsx","../../src/features/app-settings/panel-content/PanelContent.tsx","../../src/features/app-settings/useAppSettingsMenu.tsx","../../src/features/app-settings/useAppSettingsNavigation.tsx","../../src/features/app-settings/panel-list/PanelList.tsx","../../src/features/app-settings/AppSettings.tsx","../../src/features/overview/EditorOverview.tsx","../../src/views/editor/welcome/composite/ImportProjectButton.tsx","../../src/views/editor/welcome/composite/WelcomeProjectList.tsx","../../src/views/editor/welcome/Welcome.tsx","../../src/views/editor/welcome/WelcomePlacement.tsx","../../src/views/editor/Editor.tsx","../../src/views/editor/ProtectedEditor.tsx"],"sourcesContent":["import type { CustomFields } from 'ontime-types';\n\n/**\n * Transforms an alphanumeric label with spaces into a valid key\n */\nexport function customFieldLabelToKey(label: string): string {\n return label.trim().replaceAll(' ', '_');\n}\n\n/**\n * Finds an object key in the CustomFields object that matches the given label\n */\nexport function customKeyFromLabel(label: string, fields: CustomFields): string | null {\n const maybeMatchingKey = Object.keys(fields).find((key) => fields[key].label === label);\n if (maybeMatchingKey) {\n return maybeMatchingKey;\n }\n return null;\n}\n","export type ImportOptions = keyof typeof defaultImportMap | 'custom';\nexport type ImportCustom = Record<string, string>;\nexport type ImportMap = typeof defaultImportMap & { custom: ImportCustom };\n\n// Record of ontime name and import name\nexport const defaultImportMap = {\n worksheet: 'event schedule',\n flag: 'flag',\n timeStart: 'time start',\n linkStart: 'link start',\n timeEnd: 'time end',\n duration: 'duration',\n cue: 'cue',\n title: 'title',\n countToEnd: 'count to end',\n skip: 'skip',\n note: 'note',\n colour: 'colour',\n endAction: 'end action',\n timerType: 'timer type',\n timeWarning: 'warning time',\n timeDanger: 'danger time',\n custom: {},\n id: 'id',\n};\n\n/**\n * Validates whether an object is an Import Map\n * @param obj\n */\nexport function isImportMap(obj: unknown): obj is ImportMap {\n if (typeof obj !== 'object' || obj === null) {\n return false;\n }\n\n const keys = Object.keys(defaultImportMap);\n return keys.every((key) => Object.hasOwn(obj, key));\n}\n","import { useCallback, useEffect } from 'react';\n\ntype UseKeyDown = (callback: () => void, targetKey: string, options?: { isDisabled?: boolean }) => void;\n\nexport const useKeyDown: UseKeyDown = (callback, targetKey, options = {}) => {\n const { isDisabled = false } = options;\n\n const onKeyDown = useCallback(\n (event: KeyboardEvent) => {\n const targetKeyPressed = event.key === targetKey && !event.repeat;\n if (targetKeyPressed && !isDisabled) {\n event.preventDefault();\n callback();\n }\n },\n [callback, isDisabled, targetKey],\n );\n\n useEffect(() => {\n document.addEventListener('keydown', onKeyDown);\n return () => {\n document.removeEventListener('keydown', onKeyDown);\n };\n }, [onKeyDown]);\n};\n","import { MouseEvent, ReactNode } from 'react';\nimport { IoOpenOutline } from 'react-icons/io5';\n\nimport { openLink } from '../../../utils/linkUtils';\nimport { cx } from '../../../utils/styleUtils';\n\nimport style from './ExternalLink.module.scss';\n\ninterface ExternalLinkProps {\n href: string;\n children: ReactNode;\n inline?: boolean;\n}\n\nexport default function ExternalLink({ href, inline, children }: ExternalLinkProps) {\n const handleClick = (event: MouseEvent) => {\n event.preventDefault();\n openLink(href);\n };\n\n return (\n <a\n href='#!'\n target='_blank'\n rel='noreferrer'\n className={cx([style.link, inline && style.inline])}\n onClick={handleClick}\n >\n {children} <IoOpenOutline style={{ fontSize: '1em' }} />\n </a>\n );\n}\n","import axios from 'axios';\n\nimport { apiRepoLatest } from '../../externals';\n\nexport type HasUpdate = {\n url: string;\n version: string;\n};\n\n/**\n * HTTP request to get the latest version and url from github\n */\nexport async function getLatestVersion(): Promise<HasUpdate> {\n const res = await axios.get(apiRepoLatest);\n return {\n url: res.data.html_url as string,\n version: res.data.tag_name as string,\n };\n}\n","import { useQuery } from '@tanstack/react-query';\nimport { dayInMs } from 'ontime-utils';\n\nimport { version } from '../../../../../package.json';\nimport { isLocalhost } from '../../externals';\nimport { APP_VERSION } from '../api/constants';\nimport { getLatestVersion, HasUpdate } from '../api/external';\n\nconst placeholder: HasUpdate & { hasUpdates: boolean } = { url: '', version: '', hasUpdates: false };\n\nexport default function useAppVersion() {\n const {\n data: fetchData,\n status,\n isFetching,\n isError,\n refetch,\n } = useQuery({\n queryKey: APP_VERSION,\n queryFn: getLatestVersion,\n placeholderData: (previousData, _previousQuery) => previousData,\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n retry: false,\n staleTime: dayInMs,\n enabled: isLocalhost,\n });\n\n const hasUpdates = fetchData?.version && !fetchData.version.includes(version);\n\n const data = fetchData ? { ...fetchData, hasUpdates } : placeholder;\n\n return { data, placeholder, status, isFetching, isError, refetch };\n}\n","import ExternalLink from '../../../../common/components/link/external-link/ExternalLink';\nimport useAppVersion from '../../../../common/hooks-query/useAppVersion';\nimport { appVersion, isOntimeCloud } from '../../../../externals';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nexport default function AppVersion() {\n const { data, isError } = useAppVersion();\n\n if (isError) {\n return (\n <Panel.Paragraph>\n {`You are currently using Ontime version ${appVersion}`}\n <Panel.Error>{`Could not fetch version information: ${isError}`}</Panel.Error>\n </Panel.Paragraph>\n );\n }\n\n if (data.hasUpdates) {\n return (\n <Panel.Paragraph>\n {`You are currently using Ontime version ${appVersion}.`}\n <br />\n <br />\n {`A new version ${data.version} is available.`} <br />\n {isOntimeCloud ? (\n 'You can restart your stage to get the latest available version.'\n ) : (\n <ExternalLink href={data.url}>Please visit the release page to download</ExternalLink>\n )}\n </Panel.Paragraph>\n );\n }\n\n return <Panel.Paragraph>{`You are currently using the latest version of Ontime: ${appVersion}`}</Panel.Paragraph>;\n}\n","import ExternalLink from '../../../../common/components/link/external-link/ExternalLink';\nimport {\n buyMeACoffeeUrl,\n discordUrl,\n documentationUrl,\n githubSponsorUrl,\n githubUrl,\n websiteUrl,\n} from '../../../../externals';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport AppVersion from './AppVersion';\n\nexport default function AboutPanel() {\n return (\n <>\n <Panel.Header>About Ontime</Panel.Header>\n <Panel.Section>\n <Panel.Card>\n <Panel.SubHeader>Ontime</Panel.SubHeader>\n <Panel.Paragraph>\n Free, open-source software for managing rundowns and event timers\n <ExternalLink href={websiteUrl}>www.getontime.no</ExternalLink>\n </Panel.Paragraph>\n <Panel.Paragraph>\n Considering sponsoring our work\n <ExternalLink href={githubSponsorUrl}>GitHub Sponsors</ExternalLink>\n <ExternalLink href={buyMeACoffeeUrl}>Buy Me a Coffee</ExternalLink>\n </Panel.Paragraph>\n <Panel.Paragraph>\n If you are looking for an online version of Ontime, consider trying out our cloud service\n <ExternalLink href={websiteUrl}>www.getontime.no</ExternalLink>\n </Panel.Paragraph>\n </Panel.Card>\n <Panel.SubHeader>Current version</Panel.SubHeader>\n <AppVersion />\n <Panel.SubHeader>Links</Panel.SubHeader>\n <ExternalLink href={documentationUrl}>Read the docs</ExternalLink>\n <ExternalLink href={githubUrl}>Follow the project on GitHub</ExternalLink>\n <ExternalLink href={discordUrl}>Discord server</ExternalLink>\n </Panel.Section>\n </>\n );\n}\n","import { useEffect, useRef } from 'react';\n\nexport default function useScrollIntoView<T extends HTMLElement>(name: string, location?: string) {\n const ref = useRef<T>(null);\n\n useEffect(() => {\n if (location && ref.current) {\n if (location === name) {\n ref.current.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }\n }\n }, [location, name]);\n\n return ref;\n}\n","import { useForm } from 'react-hook-form';\n\nimport { editAutomationSettings } from '../../../../common/api/automation';\nimport { maybeAxiosError } from '../../../../common/api/utils';\nimport Button from '../../../../common/components/buttons/Button';\nimport Info from '../../../../common/components/info/Info';\nimport Input from '../../../../common/components/input/input/Input';\nimport ExternalLink from '../../../../common/components/link/external-link/ExternalLink';\nimport Switch from '../../../../common/components/switch/Switch';\nimport { preventEscape } from '../../../../common/utils/keyEvent';\nimport { isOnlyNumbers } from '../../../../common/utils/regex';\nimport { isOntimeCloud } from '../../../../externals';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nconst oscApiDocsUrl = 'https://docs.getontime.no/api/protocols/osc/';\n\ninterface AutomationSettingsProps {\n enabledAutomations: boolean;\n enabledOscIn: boolean;\n oscPortIn: number;\n}\n\nexport default function AutomationSettingsForm({\n enabledAutomations,\n enabledOscIn,\n oscPortIn,\n}: AutomationSettingsProps) {\n const {\n handleSubmit,\n reset,\n register,\n setError,\n watch,\n setValue,\n formState: { errors, isSubmitting, isDirty, isValid },\n } = useForm<AutomationSettingsProps>({\n mode: 'onChange',\n defaultValues: { enabledAutomations, enabledOscIn, oscPortIn },\n resetOptions: {\n keepDirtyValues: false,\n },\n });\n\n const onSubmit = async (formData: AutomationSettingsProps) => {\n try {\n await editAutomationSettings(formData);\n reset(formData);\n } catch (error) {\n const message = maybeAxiosError(error);\n setError('root', { message });\n }\n };\n\n const onReset = () => {\n reset({ enabledAutomations, enabledOscIn, oscPortIn });\n };\n\n const canSubmit = !isSubmitting && isDirty && isValid;\n\n return (\n <Panel.Card>\n <Panel.SubHeader>\n Automation settings\n <Panel.InlineElements>\n <Button variant='ghosted' onClick={onReset} disabled={!canSubmit}>\n Revert to saved\n </Button>\n <Button\n variant='primary'\n type='submit'\n form='automation-settings-form'\n disabled={!canSubmit}\n loading={isSubmitting}\n >\n Save\n </Button>\n </Panel.InlineElements>\n </Panel.SubHeader>\n {errors?.root && <Panel.Error>{errors.root.message}</Panel.Error>}\n\n <Panel.Divider />\n\n <Panel.Section>\n <Info>\n <p>Control Ontime and share its data with external systems in your workflow.</p>\n <p>- Automations allow Ontime to send its data on lifecycle triggers.</p>\n <p>- OSC Input tells Ontime to listen to messages on the specific port.</p>\n <br />\n <ExternalLink href={oscApiDocsUrl}>See the docs</ExternalLink>\n </Info>\n </Panel.Section>\n\n <Panel.Section\n as='form'\n id='automation-settings-form'\n onSubmit={handleSubmit(onSubmit)}\n onKeyDown={(event) => preventEscape(event, onReset)}\n >\n <Panel.Loader isLoading={false} />\n\n <Panel.Title>Automation</Panel.Title>\n <Panel.ListGroup>\n <Panel.ListItem>\n <Panel.Field\n title='Enable automations'\n description='Allow Ontime to send messages on lifecycle triggers'\n error={errors.enabledAutomations?.message}\n />\n <Switch\n size='large'\n checked={watch('enabledAutomations')}\n onCheckedChange={(value: boolean) =>\n setValue('enabledAutomations', value, { shouldDirty: true, shouldValidate: true })\n }\n />\n </Panel.ListItem>\n </Panel.ListGroup>\n\n <Panel.Title>OSC Input</Panel.Title>\n\n <Panel.ListGroup>\n {isOntimeCloud && <Info>For security reasons OSC integrations are not available in the cloud service.</Info>}\n <Panel.ListItem>\n <Panel.Field\n title='OSC input'\n description='Allow control of Ontime through OSC'\n error={errors.enabledOscIn?.message}\n />\n <Switch\n size='large'\n checked={watch('enabledOscIn')}\n onCheckedChange={(value: boolean) =>\n setValue('enabledOscIn', value, { shouldDirty: true, shouldValidate: true })\n }\n />\n </Panel.ListItem>\n <Panel.ListItem>\n <Panel.Field\n title='Listen on port'\n description='Port for incoming OSC. Default: 8888'\n error={errors.oscPortIn?.message}\n />\n <Input\n id='oscPortIn'\n placeholder='8888'\n maxLength={5}\n style={{ textAlign: 'right', width: '5rem' }}\n type='number'\n fluid\n {...register('oscPortIn', {\n required: { value: true, message: 'Required field' },\n max: { value: 65535, message: 'Port must be within range 1024 - 65535' },\n min: { value: 1024, message: 'Port must be within range 1024 - 65535' },\n pattern: {\n value: isOnlyNumbers,\n message: 'Value should be numeric',\n },\n })}\n />\n </Panel.ListItem>\n </Panel.ListGroup>\n </Panel.Section>\n </Panel.Card>\n );\n}\n","import { CustomFields } from 'ontime-types';\n\nconst humanConstants = [\n '{{human.clock}}',\n '{{human.duration}}',\n '{{human.expectedEnd}}',\n '{{human.runningTimer}}',\n '{{human.elapsedTime}}',\n '{{human.startedAt}}',\n];\n\nconst staticAutocompleteOptions = [\n '{{clock}}',\n '{{timer.addedTime}}',\n '{{timer.current}}',\n '{{timer.duration}}',\n '{{timer.elapsed}}',\n '{{timer.expectedFinish}}',\n '{{timer.secondaryTimer}}',\n '{{timer.startedAt}}',\n '{{rundown.selectedEventIndex}}',\n '{{rundown.numEvents}}',\n '{{rundown.plannedStart}}',\n '{{rundown.plannedEnd}}',\n '{{rundown.actualStart}}',\n '{{offset.absolute}}',\n '{{offset.relative}}',\n '{{offset.expectedRundownEnd}}',\n '{{offset.expectedGroupEnd}}',\n '{{offset.expectedFlagStart}}',\n];\n\nconst eventStaticPropertiesNow = [\n '{{eventNow.id}}',\n '{{eventNow.cue}}',\n '{{eventNow.title}}',\n '{{eventNow.note}}',\n '{{eventNow.timeStart}}',\n '{{eventNow.timeEnd}}',\n '{{eventNow.duration}}',\n '{{eventNow.colour}}',\n '{{eventNow.delay}}',\n];\n\nconst eventStaticPropertiesNext = [\n '{{eventNext.id}}',\n '{{eventNext.cue}}',\n '{{eventNext.title}}',\n '{{eventNext.note}}',\n '{{eventNext.timeStart}}',\n '{{eventNext.timeEnd}}',\n '{{eventNext.duration}}',\n '{{eventNext.colour}}',\n '{{eventNext.delay}}',\n];\n\n/**\n * Creates a it of possible autocomplete suggestions\n * Based on RuntimeState\n * Appends the human readable variants to it\n * It is manually kept in sync with the automation parseTemplate functions\n */\nexport function makeAutoCompleteList(customFields: CustomFields): string[] {\n return [\n ...humanConstants,\n ...staticAutocompleteOptions,\n ...eventStaticPropertiesNow,\n ...Object.entries(customFields).map(([key]) => `{{eventNow.custom.${key}}}`),\n ...eventStaticPropertiesNext,\n ...Object.entries(customFields).map(([key]) => `{{eventNext.custom.${key}}}`),\n ];\n}\n\n/**\n * Returns the partial string b needed to autocomplete string a\n * @example matchRemaining('te', 'test') -> 'st'\n * @example matchRemaining('{{', '{{human}}') -> 'man}}'\n */\nexport function matchRemaining(a: string, b: string) {\n if (a === b) {\n return '';\n }\n\n // naive match assuming that a template will start with {{\n if (a.endsWith('{{') && b.startsWith('{{')) {\n return b.substring(2);\n }\n\n // naive match assuming that a template will start with {\n if (a.endsWith('{') && b.startsWith('{{')) {\n return b.substring(1);\n }\n\n for (let i = 0; i < b.length; i++) {\n const searchString = b.substring(0, i + 1);\n if (a.endsWith(searchString)) {\n return b.substring(i + 1);\n }\n }\n\n return '';\n}\n\n/**\n * Selects the last starting template in a string\n */\nexport function selectFromLastTemplate(text: string) {\n const lastBraceIndex = text.lastIndexOf('{{');\n if (lastBraceIndex !== -1) {\n return text.slice(lastBraceIndex);\n }\n return '';\n}\n","import { forwardRef, useMemo, useState } from 'react';\nimport { mergeRefs, useClickOutside } from '@mantine/hooks';\n\nimport Input, { type InputProps } from '../../../../../common/components/input/input/Input';\nimport useCustomFields from '../../../../../common/hooks-query/useCustomFields';\n\nimport { makeAutoCompleteList, matchRemaining, selectFromLastTemplate } from './templateInput.utils';\n\nimport style from './TemplateInput.module.scss';\n\ninterface TemplateInputProps extends InputProps {}\n\nconst TemplateInput = forwardRef(function TemplateInput(props: TemplateInputProps, ref) {\n const { value, onChange, ...rest } = props;\n const { data } = useCustomFields();\n const localRef = useClickOutside(() => setShowSuggestions(false));\n\n const autocompleteList = useMemo(() => {\n return makeAutoCompleteList(data);\n }, [data]);\n\n const [inputValue, setInputValue] = useState(value || '');\n const [suggestions, setSuggestions] = useState<string[]>([]);\n const [showSuggestions, setShowSuggestions] = useState(false);\n\n const updateSuggestions = (value: string) => {\n const template = selectFromLastTemplate(value);\n return autocompleteList.filter((suggestion) => suggestion.startsWith(template));\n };\n\n const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n setInputValue(event.target.value);\n\n if (event.target.value.endsWith('{')) {\n setShowSuggestions(true);\n setSuggestions(updateSuggestions(event.target.value));\n } else if (event.target.value === '' || event.target.value.endsWith('}}')) {\n setShowSuggestions(false);\n } else if (showSuggestions) {\n setSuggestions(updateSuggestions(event.target.value));\n }\n\n onChange?.(event);\n };\n\n const handleSuggestion = (value: string) => {\n setInputValue((prev) => {\n const remaining = matchRemaining(prev as string, value);\n return prev + remaining;\n });\n setShowSuggestions(false);\n };\n\n return (\n <div className={style.wrapper} ref={mergeRefs(localRef, ref)}>\n <Input value={inputValue} {...rest} onChange={handleInputChange} fluid />\n {showSuggestions && suggestions.length > 0 && (\n <ul className={style.suggestions}>\n {suggestions.map((suggestion) => (\n <li key={suggestion} onClick={() => handleSuggestion(suggestion)}>\n {suggestion}\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n});\n\nexport default TemplateInput;\n","import { Automation, AutomationDTO, CustomFields, TimerLifeCycle, Trigger } from 'ontime-types';\n\ntype CycleLabel = {\n id: number;\n label: string;\n value: keyof typeof TimerLifeCycle;\n};\n\nexport const cycles: CycleLabel[] = [\n { id: 1, label: 'On Load', value: 'onLoad' },\n { id: 2, label: 'On Start', value: 'onStart' },\n { id: 3, label: 'On Pause', value: 'onPause' },\n { id: 4, label: 'On Stop', value: 'onStop' },\n { id: 5, label: 'Every second', value: 'onClock' },\n { id: 6, label: 'On Timer Update', value: 'onUpdate' },\n { id: 7, label: 'On Finish', value: 'onFinish' },\n { id: 8, label: 'On Warning', value: 'onWarning' },\n { id: 9, label: 'On Danger', value: 'onDanger' },\n];\n\n/**\n * We use this guard to find out if the form is receiving an existing automation or creating a DTO\n * We do this by checking whether an ID has been generated\n */\nexport function isAutomation(automation: AutomationDTO | Automation): automation is Automation {\n return Object.hasOwn(automation, 'id');\n}\n\nconst staticSelectProperties = [\n { value: 'eventNow.id', label: 'ID' },\n { value: 'eventNow.title', label: 'Title' },\n { value: 'eventNow.cue', label: 'Cue' },\n { value: 'eventNow.countToEnd', label: 'Count to end' },\n { value: 'eventNow.note', label: 'Note' },\n { value: 'eventNow.colour', label: 'Colour' },\n];\n\nconst staticNextSelectProperties = [\n { value: 'eventNext.id', label: 'Next ID' },\n { value: 'eventNext.title', label: 'Next Title' },\n { value: 'eventNext.cue', label: 'Next Cue' },\n];\n\ntype SelectableField = {\n value: string; // string encodes path in runtime state object\n label: string;\n};\n\nexport function makeFieldList(customFields: CustomFields): SelectableField[] {\n return [\n ...staticSelectProperties,\n ...Object.entries(customFields).map(([key, { label }]) => ({\n value: `eventNow.custom.${key}`,\n label: `Custom: ${label}`,\n })),\n ...staticNextSelectProperties,\n ...Object.entries(customFields).map(([key, { label }]) => ({\n value: `eventNext.custom.${key}`,\n label: `Next custom: ${label}`,\n })),\n ];\n}\n\n/**\n * We warn the user if they have created multiple links between the same automation and a trigger\n */\nexport function checkDuplicates(triggers: Trigger[]) {\n const triggersMap: Record<string, string[]> = {};\n const duplicates = [];\n\n for (let i = 0; i < triggers.length; i++) {\n const trigger = triggers[i];\n if (!Object.hasOwn(triggersMap, trigger.trigger)) {\n triggersMap[trigger.trigger] = [];\n }\n\n if (triggersMap[trigger.trigger].includes(trigger.automationId)) {\n duplicates.push(i);\n } else {\n triggersMap[trigger.trigger].push(trigger.automationId);\n }\n }\n return duplicates.length > 0 ? duplicates : undefined;\n}\n","import { PropsWithChildren, useState } from 'react';\nimport { UseFormRegister, UseFormSetValue, UseFormWatch } from 'react-hook-form';\nimport { AutomationDTO, OntimeAction, OntimeActionKey, SecondarySource } from 'ontime-types';\n\nimport Input from '../../../../common/components/input/input/Input';\nimport Select from '../../../../common/components/select/Select';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport style from './AutomationForm.module.scss';\n\ninterface OntimeActionFormProps {\n index: number;\n register: UseFormRegister<AutomationDTO>;\n rowErrors?: {\n action?: { message?: string };\n time?: { message?: string };\n text?: { message?: string };\n visible?: { message?: string };\n secondarySource?: { message?: string };\n };\n value: OntimeAction['action'];\n watch: UseFormWatch<AutomationDTO>;\n setValue: UseFormSetValue<AutomationDTO>;\n}\n\nexport default function OntimeActionForm({\n index,\n register,\n setValue,\n rowErrors,\n value,\n children,\n watch,\n}: PropsWithChildren<OntimeActionFormProps>) {\n const [selectedAction, setSelectedAction] = useState<string>(value);\n\n const handleSetAction = (value: OntimeActionKey) => {\n setValue(`outputs.${index}.action`, value, { shouldDirty: true });\n setSelectedAction(value);\n };\n\n return (\n <div className={style.actionSection}>\n <label>\n Action\n <Select\n onValueChange={(value) => {\n handleSetAction(value as OntimeActionKey);\n }}\n value={watch(`outputs.${index}.action`)}\n options={[\n { value: 'aux1-pause', label: 'Aux 1: pause' },\n { value: 'aux2-pause', label: 'Aux 2: pause' },\n { value: 'aux3-pause', label: 'Aux 3: pause' },\n\n { value: 'aux1-start', label: 'Aux 1: start' },\n { value: 'aux2-start', label: 'Aux 2: start' },\n { value: 'aux3-start', label: 'Aux 3: start' },\n\n { value: 'aux1-stop', label: 'Aux 1: stop' },\n { value: 'aux2-stop', label: 'Aux 2: stop' },\n { value: 'aux3-stop', label: 'Aux 3: stop' },\n\n { value: 'aux1-set', label: 'Aux 1: set' },\n { value: 'aux2-set', label: 'Aux 2: set' },\n { value: 'aux3-set', label: 'Aux 3: set' },\n\n { value: 'message-set', label: 'Primary Message: set' },\n { value: 'message-secondary', label: 'Secondary Message: source' },\n ]}\n />\n <Panel.Error>{rowErrors?.action?.message}</Panel.Error>\n </label>\n\n {selectedAction.startsWith('aux') && selectedAction.endsWith('set') && (\n <label>\n New time\n <Input\n {...register(`outputs.${index}.time`, {\n required: { value: true, message: 'Required field' },\n })}\n fluid\n placeholder='eg: 10m5s'\n />\n <Panel.Error>{rowErrors?.time?.message}</Panel.Error>\n </label>\n )}\n\n {selectedAction === 'message-set' && (\n <>\n <label>\n Text (leave empty for no change)\n <Input {...register(`outputs.${index}.text`)} fluid placeholder='eg: Timer is finished' />\n <Panel.Error>{rowErrors?.text?.message}</Panel.Error>\n </label>\n <label>\n Visibility\n <Select\n onValueChange={(value) => {\n // we need to translate the undefined value to 'untouched'\n const translatedValue = value === 'untouched' ? undefined : (value as boolean | undefined);\n setValue(`outputs.${index}.visible`, translatedValue, { shouldDirty: true });\n }}\n value={watch(`outputs.${index}.visible`) === undefined ? 'untouched' : watch(`outputs.${index}.visible`)}\n options={[\n { value: 'untouched', label: 'Untouched' },\n { value: true, label: 'Show' },\n { value: false, label: 'Hide' },\n ]}\n />\n <Panel.Error>{rowErrors?.visible?.message}</Panel.Error>\n </label>\n </>\n )}\n\n {selectedAction === 'message-secondary' && (\n <label>\n Timer secondary source\n <Select\n onValueChange={(value) => {\n setValue(`outputs.${index}.secondarySource`, value as SecondarySource, { shouldDirty: true });\n }}\n value={watch(`outputs.${index}.secondarySource`)}\n options={[\n { value: null, label: 'Select secondary source', disabled: true },\n { value: 'aux1', label: 'Auxiliary timer 1' },\n { value: 'aux2', label: 'Auxiliary timer 2' },\n { value: 'aux3', label: 'Auxiliary timer 3' },\n { value: 'external', label: 'External' },\n { value: 'null', label: 'None' },\n ]}\n />\n <Panel.Error>{rowErrors?.secondarySource?.message}</Panel.Error>\n </label>\n )}\n <div className={style.test}>{children}</div>\n </div>\n );\n}\n","import { useEffect, useMemo } from 'react';\nimport { useFieldArray, useForm } from 'react-hook-form';\nimport { IoAdd, IoTrash } from 'react-icons/io5';\nimport {\n Automation,\n AutomationDTO,\n HTTPOutput,\n isHTTPOutput,\n isOntimeAction,\n isOSCOutput,\n OntimeAction,\n OSCOutput,\n} from 'ontime-types';\n\nimport { addAutomation, editAutomation, testOutput } from '../../../../common/api/automation';\nimport { maybeAxiosError } from '../../../../common/api/utils';\nimport Button from '../../../../common/components/buttons/Button';\nimport IconButton from '../../../../common/components/buttons/IconButton';\nimport Info from '../../../../common/components/info/Info';\nimport Input from '../../../../common/components/input/input/Input';\nimport ExternalLink from '../../../../common/components/link/external-link/ExternalLink';\nimport RadioGroup from '../../../../common/components/radio-group/RadioGroup';\nimport Select from '../../../../common/components/select/Select';\nimport Tag from '../../../../common/components/tag/Tag';\nimport useAutomationSettings from '../../../../common/hooks-query/useAutomationSettings';\nimport useCustomFields from '../../../../common/hooks-query/useCustomFields';\nimport { preventEscape } from '../../../../common/utils/keyEvent';\nimport { startsWithHttp } from '../../../../common/utils/regex';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport TemplateInput from './template-input/TemplateInput';\nimport { isAutomation, makeFieldList } from './automationUtils';\nimport OntimeActionForm from './OntimeActionForm';\n\nimport style from './AutomationForm.module.scss';\n\nconst integrationsDocsUrl = 'https://docs.getontime.no/api/automation/#using-variables-in-automation';\n\ninterface AutomationFormProps {\n automation: Automation | AutomationDTO;\n onClose: () => void;\n}\n\nexport default function AutomationForm({ automation, onClose }: AutomationFormProps) {\n const isEdit = isAutomation(automation);\n const { data } = useCustomFields();\n const { refetch } = useAutomationSettings();\n const fieldList = useMemo(() => makeFieldList(data), [data]);\n\n const {\n control,\n handleSubmit,\n getValues,\n register,\n setError,\n setFocus,\n setValue,\n watch,\n formState: { errors, isSubmitting, isDirty, isValid },\n } = useForm<AutomationDTO>({\n mode: 'onChange',\n defaultValues: {\n title: automation?.title ?? '',\n filterRule: automation?.filterRule ?? 'all',\n filters: automation?.filters ?? [],\n outputs: automation?.outputs ?? [],\n },\n resetOptions: {\n keepDirtyValues: true,\n },\n });\n\n const {\n fields: fieldFilters,\n append: appendFilter,\n remove: removeFilter,\n } = useFieldArray({\n name: 'filters',\n control,\n });\n\n const {\n fields: fieldOutputs,\n append: appendOutput,\n remove: removeOutput,\n } = useFieldArray({\n name: 'outputs',\n control,\n });\n\n // give initial focus to the title field\n useEffect(() => {\n setFocus('title');\n }, [setFocus]);\n\n const handleAddNewFilter = () => {\n appendFilter({ field: '', operator: 'equals', value: '' });\n };\n\n const handleAddNewOSCOutput = () => {\n // @ts-expect-error -- we dont want to pass a port to the new object\n appendOutput({ type: 'osc', targetIP: '', targetPort: undefined, address: '', args: '' });\n };\n\n const handleAddNewHTTPOutput = () => {\n appendOutput({ type: 'http', url: '' });\n };\n\n const handleAddnewOntimeAction = () => {\n appendOutput({ type: 'ontime', action: 'aux1-start' });\n };\n\n const handleTestOSCOutput = async (index: number) => {\n try {\n const values = getValues(`outputs.${index}`) as OSCOutput;\n if (!values.targetIP || !values.targetPort || !values.address) {\n return;\n }\n await testOutput({\n type: 'osc',\n targetIP: values.targetIP,\n targetPort: values.targetPort,\n address: values.address,\n args: values.args,\n });\n } catch (_error) {\n /** we dont handle errors here, users should use the network tab */\n }\n };\n\n const handleTestHTTPOutput = async (index: number) => {\n try {\n const values = getValues(`outputs.${index}`) as HTTPOutput;\n if (!values.url) {\n return;\n }\n await testOutput({\n type: 'http',\n url: values.url,\n });\n } catch (_error) {\n /** we dont handle errors here, users should use the network tab */\n }\n };\n\n const handleTestOntimeAction = async (index: number) => {\n try {\n const values = getValues(`outputs.${index}`) as OntimeAction;\n // NOTE: there is no meaningful validation to do here, we let the server deal with the data\n await testOutput({\n ...values,\n type: 'ontime',\n });\n } catch (_error) {\n /** we dont handle errors here */\n }\n };\n\n const onSubmit = async (values: AutomationDTO) => {\n if (isAutomation(automation)) {\n await handleEdit(automation.id, { id: automation.id, ...values });\n } else {\n await handleCreate(values);\n }\n refetch();\n\n async function handleEdit(id: string, values: Automation) {\n try {\n await editAutomation(id, values);\n onClose();\n } catch (error) {\n setError('root', { message: maybeAxiosError(error) });\n }\n }\n\n async function handleCreate(values: AutomationDTO) {\n try {\n await addAutomation(values);\n onClose();\n } catch (error) {\n setError('root', { message: maybeAxiosError(error) });\n }\n }\n };\n\n const canSubmit = !isSubmitting && isDirty && isValid;\n\n return (\n <Panel.Indent\n as='form'\n name='automation-form'\n onSubmit={handleSubmit(onSubmit)}\n className={style.outerColumn}\n onKeyDown={(event) => preventEscape(event, onClose)}\n >\n <Panel.SubHeader>{isEdit ? 'Edit automation' : 'Create automation'}</Panel.SubHeader>\n <div className={style.innerSection}>\n <h3>Automation options</h3>\n <div className={style.titleSection}>\n <label>\n Title\n <Input\n {...register('title', { required: { value: true, message: 'Required field' } })}\n fluid\n placeholder='Load preset'\n />\n </label>\n <Panel.Error>{errors.title?.message}</Panel.Error>\n </div>\n </div>\n\n <div className={style.innerSection}>\n <h3>Filters (optional)</h3>\n <div className={style.ruleSection}>\n <label>\n Trigger outputs if\n <RadioGroup\n orientation='horizontal'\n value={watch('filterRule')}\n onValueChange={(value) => setValue('filterRule', value, { shouldDirty: true })}\n items={[\n { value: 'all', label: 'All filters pass' },\n { value: 'any', label: 'Any filter passes' },\n ]}\n />\n </label>\n {fieldFilters.map((field, index) => {\n const key = `filters.${index}.field.${field.id}`;\n return (\n <div key={key} className={style.filterSection}>\n <label>\n Runtime data source\n <Select\n value={watch(`filters.${index}.field`)}\n onValueChange={(value) => setValue(`filters.${index}.field`, value, { shouldDirty: true })}\n options={fieldList.map(({ value, label }) => ({ value, label }))}\n aria-label='Event field'\n />\n <Panel.Error>{errors.filters?.[index]?.field?.message}</Panel.Error>\n </label>\n <label>\n Matching condition\n <Select\n value={watch(`filters.${index}.operator`)}\n onValueChange={(value) =>\n setValue(`filters.${index}.operator`, value as 'equals' | 'not_equals' | 'contains', {\n shouldDirty: true,\n })\n }\n options={[\n { value: 'equals', label: 'equals' },\n { value: 'not_equals', label: 'not equals' },\n { value: 'contains', label: 'contains' },\n ]}\n aria-label='Operator'\n />\n <Panel.Error>{errors.filters?.[index]?.operator?.message}</Panel.Error>\n </label>\n <label>\n Value to match\n <Input {...register(`filters.${index}.value`)} fluid placeholder='<empty / no value>' />\n </label>\n <div>\n <span> </span>\n <div>\n <IconButton aria-label='Delete' variant='ghosted-destructive' onClick={() => removeFilter(index)}>\n <IoTrash />\n </IconButton>\n </div>\n </div>\n </div>\n );\n })}\n <div>\n <Button type='submit' onClick={handleAddNewFilter}>\n Add filter <IoAdd />\n </Button>\n </div>\n </div>\n </div>\n\n <div className={style.innerColumn}>\n <h3>Outputs</h3>\n <Info>\n Automation outputs can be used to send data from Ontime to external software.\n <ExternalLink href={integrationsDocsUrl}>See the documentation for templates</ExternalLink>\n </Info>\n\n {fieldOutputs.map((output, index) => {\n if (isOSCOutput(output)) {\n const rowErrors = errors.outputs?.[index] as\n | {\n targetIP?: { message?: string };\n targetPort?: { message?: string };\n address?: { message?: string };\n args?: { message?: string };\n }\n | undefined;\n\n return (\n <div key={output.id} className={style.outputCard}>\n <Tag>OSC</Tag>\n <div className={style.oscSection}>\n <label>\n Target IP\n <Input\n {...register(`outputs.${index}.targetIP`, {\n required: { value: true, message: 'Required field' },\n })}\n fluid\n placeholder='127.0.0.1'\n />\n <Panel.Error>{rowErrors?.targetIP?.message}</Panel.Error>\n </label>\n <label>\n Target Port\n <Input\n {...register(`outputs.${index}.targetPort`, {\n required: { value: true, message: 'Required field' },\n setValueAs: (value) => (value === '' ? 0 : Number(value)),\n max: { value: 65535, message: 'Port must be within range 1024 - 65535' },\n min: { value: 1024, message: 'Port must be within range 1024 - 65535' },\n })}\n fluid\n type='number'\n maxLength={5}\n placeholder='8000'\n />\n <Panel.Error>{rowErrors?.targetPort?.message}</Panel.Error>\n </label>\n <label>\n Address\n <Input {...register(`outputs.${index}.address`)} fluid placeholder='/cue/start' />\n <Panel.Error>{rowErrors?.address?.message}</Panel.Error>\n </label>\n <label>\n Arguments\n <TemplateInput {...register(`outputs.${index}.args`)} value={output.args} placeholder='1' />\n <Panel.Error>{rowErrors?.args?.message}</Panel.Error>\n </label>\n <div>\n <span> </span>\n <Panel.InlineElements relation='inner'>\n <Button variant='ghosted-white' onClick={() => handleTestOSCOutput(index)}>\n Test\n </Button>\n <IconButton aria-label='Delete' variant='ghosted-destructive' onClick={() => removeOutput(index)}>\n <IoTrash />\n </IconButton>\n </Panel.InlineElements>\n </div>\n </div>\n </div>\n );\n }\n if (isHTTPOutput(output)) {\n const rowErrors = errors.outputs?.[index] as\n | {\n url?: { message?: string };\n }\n | undefined;\n return (\n <div key={output.id} className={style.outputCard}>\n <Tag>HTTP</Tag>\n <div className={style.httpSection}>\n <label>\n Target URL\n <Input\n {...register(`outputs.${index}.url`, {\n required: { value: true, message: 'Required field' },\n pattern: {\n value: startsWithHttp,\n message: 'HTTP messages should target http:// or https://',\n },\n })}\n fluid\n placeholder='http://127.0.0.1/start/1'\n />\n <Panel.Error>{rowErrors?.url?.message}</Panel.Error>\n </label>\n <div>\n <span> </span>\n <Panel.InlineElements relation='inner'>\n <Button variant='ghosted-white' onClick={() => handleTestHTTPOutput(index)}>\n Test\n </Button>\n <IconButton aria-label='Delete' variant='ghosted-destructive' onClick={() => removeOutput(index)}>\n <IoTrash />\n </IconButton>\n </Panel.InlineElements>\n </div>\n </div>\n </div>\n );\n }\n\n if (isOntimeAction(output)) {\n const rowErrors = errors.outputs?.[index] as\n | {\n action?: { message?: string };\n time?: { message?: string };\n text?: { message?: string };\n visible?: { message?: string };\n secondarySource?: { message?: string };\n }\n | undefined;\n return (\n <div key={output.id} className={style.outputCard}>\n <Tag>Ontime action</Tag>\n <OntimeActionForm\n value={output.action}\n index={index}\n register={register}\n rowErrors={rowErrors}\n setValue={setValue}\n watch={watch}\n >\n <span> </span>\n <Panel.InlineElements relation='inner'>\n <Button variant='ghosted-white' onClick={() => handleTestOntimeAction(index)}>\n Test\n </Button>\n <IconButton aria-label='Delete' variant='ghosted-destructive' onClick={() => removeOutput(index)}>\n <IoTrash />\n </IconButton>\n </Panel.InlineElements>\n </OntimeActionForm>\n </div>\n );\n }\n\n // there should be no other output types\n return null;\n })}\n <Panel.InlineElements relation='inner'>\n <Button onClick={handleAddNewOSCOutput}>\n OSC <IoAdd />\n </Button>\n <Button onClick={handleAddNewHTTPOutput}>\n HTTP <IoAdd />\n </Button>\n <Button onClick={handleAddnewOntimeAction}>\n Ontime action <IoAdd />\n </Button>\n </Panel.InlineElements>\n </div>\n\n <Panel.InlineElements align='end'>\n {errors?.root && <Panel.Error>{errors.root.message}</Panel.Error>}\n <Button onClick={onClose}>Cancel</Button>\n <Button variant='primary' type='submit' disabled={!canSubmit} loading={isSubmitting}>\n Save\n </Button>\n </Panel.InlineElements>\n </Panel.Indent>\n );\n}\n","import { Fragment, useState } from 'react';\nimport { IoAdd, IoPencil, IoTrash } from 'react-icons/io5';\nimport { AutomationDTO, NormalisedAutomation } from 'ontime-types';\n\nimport { deleteAutomation } from '../../../../common/api/automation';\nimport { maybeAxiosError } from '../../../../common/api/utils';\nimport Button from '../../../../common/components/buttons/Button';\nimport IconButton from '../../../../common/components/buttons/IconButton';\nimport Tag from '../../../../common/components/tag/Tag';\nimport useAutomationSettings from '../../../../common/hooks-query/useAutomationSettings';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport AutomationForm from './AutomationForm';\n\nconst automationPlaceholder: AutomationDTO = {\n title: '',\n filterRule: 'all',\n filters: [],\n outputs: [],\n};\n\ninterface AutomationsListProps {\n automations: NormalisedAutomation;\n}\n\nexport default function AutomationsList(props: AutomationsListProps) {\n const { automations } = props;\n const { refetch } = useAutomationSettings();\n const [automationFormData, setAutomationFormData] = useState<AutomationDTO | null>(null);\n const [deleteError, setDeleteError] = useState<string | null>(null);\n\n const handleDelete = async (id: string) => {\n try {\n setDeleteError(null);\n await deleteAutomation(id);\n } catch (error) {\n setDeleteError(maybeAxiosError(error));\n } finally {\n refetch();\n }\n };\n\n const arrayAutomations = Object.keys(automations);\n\n return (\n <Panel.Card>\n <Panel.SubHeader>\n Manage automations\n <Button\n type='submit'\n disabled={Boolean(automationFormData)}\n onClick={() => setAutomationFormData(automationPlaceholder)}\n >\n New <IoAdd />\n </Button>\n </Panel.SubHeader>\n\n <Panel.Divider />\n\n {automationFormData !== null && (\n <AutomationForm automation={automationFormData} onClose={() => setAutomationFormData(null)} />\n )}\n\n <Panel.Table>\n <thead>\n <tr>\n <th style={{ width: '45%' }}>Title</th>\n <th style={{ width: '15%' }}>Trigger rule</th>\n <th style={{ width: '15%' }}>Filters</th>\n <th style={{ width: '15%' }}>Outputs</th>\n <th />\n </tr>\n </thead>\n <tbody>\n {arrayAutomations.length === 0 && (\n <Panel.TableEmpty\n handleClick={!automationFormData ? () => setAutomationFormData(automationPlaceholder) : undefined}\n />\n )}\n {arrayAutomations.map((automationId) => {\n if (!Object.hasOwn(automations, automationId)) {\n return null;\n }\n return (\n <Fragment key={automationId}>\n <tr>\n <td>{automations[automationId].title}</td>\n <td>\n <Tag>{automations[automationId].filterRule}</Tag>\n </td>\n <td>{automations[automationId].filters.length}</td>\n <td>{automations[automationId].outputs.length}</td>\n <Panel.InlineElements align='end' relation='inner' as='td'>\n <IconButton\n variant='ghosted-white'\n aria-label='Edit entry'\n onClick={() => setAutomationFormData(automations[automationId])}\n >\n <IoPencil />\n </IconButton>\n <IconButton\n variant='ghosted-destructive'\n aria-label='Delete entry'\n onClick={() => handleDelete(automationId)}\n >\n <IoTrash />\n </IconButton>\n </Panel.InlineElements>\n </tr>\n </Fragment>\n );\n })}\n {deleteError && (\n <tr>\n <td colSpan={5}>\n <Panel.Error>{deleteError}</Panel.Error>\n </td>\n </tr>\n )}\n </tbody>\n </Panel.Table>\n </Panel.Card>\n );\n}\n","import { useEffect } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { NormalisedAutomation, TimerLifeCycle, TriggerDTO } from 'ontime-types';\n\nimport { addTrigger, editTrigger } from '../../../../common/api/automation';\nimport { maybeAxiosError } from '../../../../common/api/utils';\nimport Button from '../../../../common/components/buttons/Button';\nimport Input from '../../../../common/components/input/input/Input';\nimport Select from '../../../../common/components/select/Select';\nimport { preventEscape } from '../../../../common/utils/keyEvent';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport { cycles } from './automationUtils';\n\ninterface TriggerFormProps {\n automations: NormalisedAutomation;\n initialId?: string;\n initialTitle?: string;\n initialAutomationId?: string;\n initialTrigger?: TimerLifeCycle;\n onCancel: () => void;\n postSubmit: () => void;\n}\n\nexport default function TriggerForm({\n automations,\n initialId,\n initialTitle,\n initialAutomationId,\n initialTrigger,\n onCancel,\n postSubmit,\n}: TriggerFormProps) {\n const {\n handleSubmit,\n register,\n setFocus,\n setError,\n watch,\n setValue,\n formState: { errors, isSubmitting, isValid, isDirty },\n } = useForm<TriggerDTO>({\n defaultValues: {\n title: initialTitle,\n trigger: initialTrigger ?? (cycles[0].value as TimerLifeCycle | undefined),\n automationId: initialAutomationId ?? automations?.[Object.keys(automations)[0]]?.id,\n },\n resetOptions: {\n keepDirtyValues: true,\n },\n });\n\n // give initial focus to the title field\n useEffect(() => {\n setFocus('title');\n }, [setFocus]);\n\n const onSubmit = async (values: TriggerDTO) => {\n // if we were passed an ID we are editing a Trigger\n if (initialId) {\n try {\n await editTrigger(initialId, { id: initialId, ...values });\n postSubmit();\n } catch (error) {\n setError('root', { message: `Failed to save changes to trigger ${maybeAxiosError(error)}` });\n }\n return;\n }\n\n // otherwise we are creating a new automation\n try {\n await addTrigger(values);\n postSubmit();\n } catch (error) {\n setError('root', { message: `Failed to save trigger ${maybeAxiosError(error)}` });\n }\n };\n\n const automationSelect = Object.keys(automations).map((automation) => {\n return {\n value: automation,\n label: automations[automation].title,\n };\n });\n\n const canSubmit = isDirty && isValid;\n\n return (\n <Panel.Indent\n as='form'\n name='trigger-form'\n onSubmit={handleSubmit(onSubmit)}\n onKeyDown={(event) => preventEscape(event, onCancel)}\n >\n <Panel.SubHeader>{initialId ? 'Edit trigger' : 'Create trigger'}</Panel.SubHeader>\n <label>\n Title\n <Input\n {...register('title', { required: { value: true, message: 'Required field' } })}\n fluid\n defaultValue={initialTitle}\n />\n <Panel.Error>{errors.title?.message}</Panel.Error>\n </label>\n <label>\n Lifecycle trigger\n <Select\n value={watch('trigger')}\n onValueChange={(value) => setValue('trigger', value as TimerLifeCycle, { shouldDirty: true })}\n options={cycles.map((cycle) => ({ value: cycle.value, label: cycle.label }))}\n aria-label='Lifecycle trigger'\n />\n <Panel.Error>{errors.trigger?.message}</Panel.Error>\n </label>\n <label>\n Automation title\n <Select\n value={watch('automationId')}\n onValueChange={(value) => setValue('automationId', value, { shouldDirty: true })}\n options={automationSelect}\n aria-label='Automation title'\n />\n <Panel.Error>{errors.automationId?.message}</Panel.Error>\n </label>\n <Panel.InlineElements align='end'>\n <Button disabled={isSubmitting} onClick={onCancel}>\n Cancel\n </Button>\n <Button type='submit' variant='primary' disabled={!canSubmit} loading={isSubmitting}>\n Save\n </Button>\n </Panel.InlineElements>\n </Panel.Indent>\n );\n}\n","import { useState } from 'react';\nimport { IoPencil, IoTrash, IoWarningOutline } from 'react-icons/io5';\nimport { NormalisedAutomation, TimerLifeCycle } from 'ontime-types';\n\nimport IconButton from '../../../../common/components/buttons/IconButton';\nimport Tag from '../../../../common/components/tag/Tag';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport { cycles } from './automationUtils';\nimport AutomationForm from './TriggerForm';\n\ninterface TriggersListItemProps {\n automations: NormalisedAutomation;\n id: string;\n title: string;\n trigger: TimerLifeCycle;\n automationId: string;\n duplicate?: boolean;\n handleDelete: () => void;\n postSubmit: () => void;\n}\n\nexport default function TriggersListItem(props: TriggersListItemProps) {\n const { automations, id, title, trigger, automationId, duplicate, handleDelete, postSubmit } = props;\n const [isEditing, setIsEditing] = useState(false);\n\n if (isEditing) {\n return (\n <tr>\n <td colSpan={99}>\n <AutomationForm\n automations={automations}\n initialId={id}\n initialTitle={title}\n initialTrigger={trigger}\n initialAutomationId={automationId}\n onCancel={() => setIsEditing(false)}\n postSubmit={() => {\n setIsEditing(false);\n postSubmit();\n }}\n />\n </td>\n </tr>\n );\n }\n\n return (\n <tr data-warn={duplicate}>\n <Panel.InlineElements as='td' relation='inner'>\n {duplicate && (\n <IoWarningOutline\n color='#FFBC56' // $orange-500\n />\n )}\n {title}\n </Panel.InlineElements>\n <td>\n <Tag>{cycles.find((cycle) => cycle.value === trigger)?.label}</Tag>\n </td>\n <td>\n <Tag>{automations?.[automationId]?.title}</Tag>\n </td>\n <Panel.InlineElements align='end' relation='inner' as='td'>\n <IconButton variant='ghosted-white' aria-label='Edit entry' onClick={() => setIsEditing(true)}>\n <IoPencil />\n </IconButton>\n <IconButton variant='ghosted-destructive' aria-label='Delete entry' onClick={handleDelete}>\n <IoTrash />\n </IconButton>\n </Panel.InlineElements>\n </tr>\n );\n}\n","import { Fragment, useMemo, useState } from 'react';\nimport { IoAdd } from 'react-icons/io5';\nimport { NormalisedAutomation, Trigger } from 'ontime-types';\n\nimport { deleteTrigger } from '../../../../common/api/automation';\nimport { maybeAxiosError } from '../../../../common/api/utils';\nimport Button from '../../../../common/components/buttons/Button';\nimport useAutomationSettings from '../../../../common/hooks-query/useAutomationSettings';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport { checkDuplicates } from './automationUtils';\nimport AutomationForm from './TriggerForm';\nimport TriggersListItem from './TriggersListItem';\n\ninterface TriggersListProps {\n triggers: Trigger[];\n automations: NormalisedAutomation;\n}\n\nexport default function TriggersList(props: TriggersListProps) {\n const { triggers, automations } = props;\n const [showForm, setShowForm] = useState(false);\n const { refetch } = useAutomationSettings();\n const [deleteError, setDeleteError] = useState<string | null>(null);\n\n const handleDelete = async (id: string) => {\n try {\n await deleteTrigger(id);\n } catch (error) {\n setDeleteError(maybeAxiosError(error));\n } finally {\n refetch();\n }\n };\n\n const postSubmit = () => {\n setShowForm(false);\n refetch();\n };\n\n const duplicates = useMemo(() => checkDuplicates(triggers), [triggers]);\n\n // there is no point letting user creating a trigger if there are no automations\n const canAdd = Object.keys(automations).length > 0;\n\n return (\n <Panel.Card>\n <Panel.SubHeader>\n Manage triggers\n <Button type='submit' form='trigger-form' disabled={!canAdd} loading={false} onClick={() => setShowForm(true)}>\n New <IoAdd />\n </Button>\n </Panel.SubHeader>\n <Panel.Divider />\n <Panel.Section>\n {duplicates && (\n <Panel.Error>\n You have created multiple links between the same trigger and automation which can performance issues.\n </Panel.Error>\n )}\n {showForm && (\n <AutomationForm automations={automations} onCancel={() => setShowForm(false)} postSubmit={postSubmit} />\n )}\n <Panel.Table>\n <thead>\n <tr>\n <th style={{ width: '35%' }}>Title</th>\n <th style={{ width: '25%' }}>Lifecycle trigger</th>\n <th style={{ width: '25%' }}>Automation</th>\n <th />\n </tr>\n </thead>\n <tbody>\n {!showForm && triggers.length === 0 && (\n <Panel.TableEmpty\n label='Create an automation to attach triggers to'\n handleClick={canAdd ? () => setShowForm(true) : undefined}\n />\n )}\n {triggers.map((trigger, index) => {\n return (\n <Fragment key={trigger.id}>\n <TriggersListItem\n automations={automations}\n id={trigger.id}\n title={trigger.title}\n trigger={trigger.trigger}\n automationId={trigger.automationId}\n duplicate={duplicates?.includes(index)}\n handleDelete={() => handleDelete(trigger.id)}\n postSubmit={postSubmit}\n />\n {deleteError && (\n <tr>\n <td colSpan={5}>\n <Panel.Error>{deleteError}</Panel.Error>\n </td>\n </tr>\n )}\n </Fragment>\n );\n })}\n </tbody>\n </Panel.Table>\n </Panel.Section>\n </Panel.Card>\n );\n}\n","import useScrollIntoView from '../../../../common/hooks/useScrollIntoView';\nimport useAutomationSettings from '../../../../common/hooks-query/useAutomationSettings';\nimport type { PanelBaseProps } from '../../panel-list/PanelList';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport AutomationSettingsForm from './AutomationSettingsForm';\nimport AutomationsList from './AutomationsList';\nimport TriggersList from './TriggersList';\n\nexport default function AutomationPanel({ location }: PanelBaseProps) {\n const { data, status } = useAutomationSettings();\n const settingsRef = useScrollIntoView<HTMLDivElement>('settings', location);\n const triggersRef = useScrollIntoView<HTMLDivElement>('triggers', location);\n const automationsRef = useScrollIntoView<HTMLDivElement>('automations', location);\n\n const isLoading = status === 'pending';\n\n return (\n <>\n <Panel.Header>Automation</Panel.Header>\n <Panel.Section>\n <Panel.Loader isLoading={isLoading} />\n <div ref={settingsRef}>\n <AutomationSettingsForm\n enabledAutomations={data.enabledAutomations}\n enabledOscIn={data.enabledOscIn}\n oscPortIn={data.oscPortIn}\n />\n </div>\n <div ref={automationsRef}>\n <AutomationsList automations={data.automations} />\n </div>\n <div ref={triggersRef}>\n <TriggersList triggers={data.triggers} automations={data.automations} />\n </div>\n </Panel.Section>\n </>\n );\n}\n","import { IoArrowUp } from 'react-icons/io5';\n\nimport CopyTag from '../../../../common/components/copy-tag/CopyTag';\nimport useInfo from '../../../../common/hooks-query/useInfo';\nimport { linkToOtherHost, openLink } from '../../../../common/utils/linkUtils';\nimport { isLocalhost } from '../../../../externals';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport style from './NetworkInterfaces.module.scss';\n\nexport default function InfoNif() {\n const { data } = useInfo();\n\n const handleClick = (address: string) => openLink(address);\n\n return (\n <Panel.InlineElements>\n {data.networkInterfaces.map((nif) => {\n // interfaces outside localhost wont have access\n if (nif.name === 'localhost' && !isLocalhost) return null;\n const address = linkToOtherHost(nif.address);\n\n return (\n <CopyTag key={nif.name} copyValue={address} onClick={() => handleClick(address)}>\n {`${nif.name} - ${nif.address}`} <IoArrowUp className={style.goIcon} />\n </CopyTag>\n );\n })}\n </Panel.InlineElements>\n );\n}\n","import { stringify } from 'csv-stringify/browser/esm/sync';\n\n/**\n * Converts an array of arrays to a CSV file\n */\nexport function makeCSVFromArrayOfArrays(arrayOfArrays: string[][]): string {\n return stringify(arrayOfArrays);\n}\n","import { EntryId, isOntimeEvent, MaybeNumber, OntimeReport, RundownEntries } from 'ontime-types';\n\nimport { makeCSVFromArrayOfArrays } from '../../../../common/utils/csv';\nimport { formatTime } from '../../../../common/utils/time';\n\nexport type CombinedReport = {\n id: EntryId;\n index: number;\n title: string;\n cue: string;\n scheduledStart: number;\n actualStart: MaybeNumber;\n scheduledEnd: number;\n actualEnd: MaybeNumber;\n};\n\n/**\n * Creates a combined report with the rundown data\n */\nexport function getCombinedReport(\n report: OntimeReport,\n rundown: RundownEntries,\n flatOrder: EntryId[],\n): CombinedReport[] {\n if (Object.keys(report).length === 0) return [];\n if (flatOrder.length === 0) return [];\n\n const combinedReport: CombinedReport[] = [];\n\n let index = 1;\n for (let i = 0; i < flatOrder.length; i++) {\n const id = flatOrder[i];\n const entry = rundown[id];\n if (!entry || !isOntimeEvent(entry)) continue;\n\n if (!(id in report)) {\n combinedReport.push({\n id: id,\n index: index,\n title: entry.title,\n cue: entry.cue,\n scheduledStart: entry.timeStart,\n actualEnd: null,\n scheduledEnd: entry.timeEnd,\n actualStart: null,\n });\n }\n\n if (id in report) {\n combinedReport.push({\n id: id,\n index: index,\n title: entry.title,\n cue: entry.cue,\n scheduledStart: entry.timeStart,\n actualEnd: report[id].endedAt,\n scheduledEnd: entry.timeEnd,\n actualStart: report[id].startedAt,\n });\n }\n index++;\n }\n\n return combinedReport;\n}\n\nconst csvHeader = ['Index', 'Title', 'Cue', 'Scheduled Start', 'Actual Start', 'Scheduled End', 'Actual End'];\n\n/**\n * Transforms a CombinedReport into a CSV string\n */\nexport function makeReportCSV(combinedReport: CombinedReport[]) {\n const csv: string[][] = [];\n csv.push(csvHeader);\n\n for (const entry of combinedReport) {\n csv.push([\n String(entry.index),\n entry.title,\n entry.cue,\n formatTime(entry.scheduledStart),\n formatTime(entry.actualStart),\n formatTime(entry.scheduledEnd),\n formatTime(entry.actualEnd),\n ]);\n }\n\n return makeCSVFromArrayOfArrays(csv);\n}\n","import { useMemo } from 'react';\nimport { IoTrashBin } from 'react-icons/io5';\n\nimport { deleteAllReport } from '../../../../common/api/report';\nimport { createBlob, downloadBlob } from '../../../../common/api/utils';\nimport Button from '../../../../common/components/buttons/Button';\nimport useReport from '../../../../common/hooks-query/useReport';\nimport useRundown from '../../../../common/hooks-query/useRundown';\nimport { cx } from '../../../../common/utils/styleUtils';\nimport { formatTime } from '../../../../common/utils/time';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport { CombinedReport, getCombinedReport, makeReportCSV } from './reportSettings.utils';\n\nimport style from './ReportSettings.module.scss';\n\nexport default function ReportSettings() {\n const { data: reportData } = useReport();\n const { data } = useRundown();\n\n const clearReport = async () => await deleteAllReport();\n const downloadCSV = (combinedReport: CombinedReport[]) => {\n if (!combinedReport) {\n return;\n }\n const csv = makeReportCSV(combinedReport);\n const blob = createBlob(csv, 'text/csv;charset=utf-8;');\n downloadBlob(blob, 'ontime-report.csv');\n };\n\n const combinedReport = useMemo(() => {\n return getCombinedReport(reportData, data.entries, data.flatOrder);\n }, [reportData, data.entries, data.flatOrder]);\n\n return (\n <Panel.Section>\n <Panel.Card>\n <Panel.SubHeader>Report</Panel.SubHeader>\n <Panel.Divider />\n <Panel.Section>\n <Panel.Title>\n Manage report\n <Panel.InlineElements>\n <Button onClick={() => downloadCSV(combinedReport)} disabled={combinedReport.length === 0}>\n <IoTrashBin />\n Export CSV\n </Button>\n <Button variant='subtle-destructive' onClick={clearReport} disabled={combinedReport.length === 0}>\n <IoTrashBin />\n Clear All\n </Button>\n </Panel.InlineElements>\n </Panel.Title>\n </Panel.Section>\n <Panel.Section>\n <Panel.Table>\n <thead>\n <tr>\n <th>#</th>\n <th>Cue</th>\n <th>Title</th>\n <th>Scheduled Start</th>\n <th>Actual Start</th>\n <th>Scheduled End</th>\n <th>Actual End</th>\n </tr>\n </thead>\n <tbody>\n {combinedReport.length === 0 && (\n <Panel.TableEmpty label='Reports are generated when running through the show.' />\n )}\n\n {combinedReport.map((entry) => {\n const start = (() => {\n if (entry.actualStart === null) return null;\n if (entry.actualStart <= entry.scheduledStart) return 'under';\n return 'over';\n })();\n const end = (() => {\n if (entry.actualEnd === null) return null;\n if (entry.actualEnd <= entry.scheduledEnd) return 'under';\n return 'over';\n })();\n return (\n <tr key={entry.id}>\n <th>{entry.index}</th>\n <th>{entry.cue}</th>\n <th>{entry.title}</th>\n <th className={cx([start && style[start]])}>{formatTime(entry.scheduledStart)}</th>\n <th className={cx([start && style[start]])}>{formatTime(entry.actualStart)}</th>\n <th className={cx([end && style[end]])}>{formatTime(entry.scheduledEnd)}</th>\n <th className={cx([end && style[end]])}>{formatTime(entry.actualEnd)}</th>\n </tr>\n );\n })}\n </tbody>\n </Panel.Table>\n </Panel.Section>\n </Panel.Card>\n </Panel.Section>\n );\n}\n","import { useEffect, useRef } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { OntimeView, OntimeViewPresettable, URLPreset } from 'ontime-types';\n\nimport { maybeAxiosError, unwrapError } from '../../../../../common/api/utils';\nimport Button from '../../../../../common/components/buttons/Button';\nimport Input from '../../../../../common/components/input/input/Input';\nimport Textarea from '../../../../../common/components/input/textarea/Textarea';\nimport Select, { SelectOption } from '../../../../../common/components/select/Select';\nimport { useUpdateUrlPreset } from '../../../../../common/hooks-query/useUrlPresets';\nimport { preventEscape } from '../../../../../common/utils/keyEvent';\nimport { generateUrlPresetOptions } from '../../../../../common/utils/urlPresets';\nimport * as Panel from '../../../panel-utils/PanelUtils';\n\nimport style from './URLPresetForm.module.scss';\n\nconst targetOptions: SelectOption<OntimeViewPresettable>[] = [\n { value: OntimeView.Cuesheet, label: 'Cuesheet' },\n { value: OntimeView.Operator, label: 'Operator' },\n { value: OntimeView.Timer, label: 'Timer' },\n { value: OntimeView.Backstage, label: 'Backstage' },\n { value: OntimeView.Timeline, label: 'Timeline' },\n { value: OntimeView.StudioClock, label: 'Studio Clock' },\n { value: OntimeView.Countdown, label: 'Countdown' },\n { value: OntimeView.ProjectInfo, label: 'Project Info' },\n];\n\nconst defaultValues: URLPreset = {\n alias: '',\n target: OntimeView.Timer,\n search: '',\n enabled: true,\n};\n\ninterface URLPresetFormProps {\n urlPreset?: URLPreset;\n onClose: () => void;\n}\n\nexport default function URLPresetForm({ urlPreset, onClose }: URLPresetFormProps) {\n const { addPreset, updatePreset, isMutating } = useUpdateUrlPreset();\n\n const {\n handleSubmit,\n register,\n setFocus,\n setError,\n clearErrors,\n setValue,\n getValues,\n watch,\n formState: { errors, isSubmitting, isValid, isDirty },\n } = useForm<URLPreset>({\n defaultValues: urlPreset ?? defaultValues,\n resetOptions: {\n keepDirtyValues: true,\n },\n });\n const urlRef = useRef<HTMLInputElement>(null);\n\n const setupSubmit = async (data: URLPreset) => {\n try {\n if (urlPreset) {\n await updatePreset(urlPreset.alias, data);\n } else {\n await addPreset(data);\n }\n onClose();\n } catch (error) {\n setError('root', { message: maybeAxiosError(error) });\n }\n };\n\n useEffect(() => {\n setFocus('alias');\n }, [setFocus]);\n\n const generateOptions = () => {\n clearErrors();\n\n try {\n const preset = generateUrlPresetOptions(getValues('alias'), urlRef.current?.value.trim() ?? '');\n setValue('target', preset.target, { shouldDirty: true, shouldValidate: true });\n setValue('search', preset.search, { shouldDirty: true, shouldValidate: true });\n } catch (error) {\n setError('root', { message: unwrapError(error) });\n return;\n }\n };\n\n const validateParams = (value: string) => {\n try {\n new URLSearchParams(value);\n return true;\n } catch (error) {\n return unwrapError(error) || 'Invalid URL parameters';\n }\n };\n\n return (\n <Panel.Indent\n as='form'\n onSubmit={handleSubmit(setupSubmit)}\n onKeyDown={(event) => preventEscape(event, onClose)}\n className={style.column}\n >\n <input hidden name='enabled' value='true' />\n\n <div>1. Enter URL and let Ontime generate the preset options</div>\n <Panel.InlineElements>\n <div>\n <Panel.Description>Alias</Panel.Description>\n <Input {...register('alias', { required: 'Alias is required' })} />\n </div>\n <div className={style.expand}>\n <Panel.Description>Generate options (paste URL to generate options)</Panel.Description>\n <Panel.InlineElements>\n <Input placeholder='Paste URL' fluid ref={urlRef} />\n <Button onClick={generateOptions}>Generate</Button>\n </Panel.InlineElements>\n </div>\n </Panel.InlineElements>\n <div> - or -</div>\n <div>2. Choose a view and its parameters</div>\n <div>\n <Panel.Description>Target</Panel.Description>\n <Select\n options={targetOptions}\n {...register('target', { required: 'Target is required' })}\n value={watch('target')}\n onValueChange={(value) => setValue('target', value, { shouldDirty: true })}\n />\n </div>\n <div>\n <Panel.Description>Parameters</Panel.Description>\n <Textarea\n fluid\n rows={3}\n {...register('search', {\n validate: validateParams,\n })}\n />\n <Panel.Error>{errors.search?.message}</Panel.Error>\n </div>\n <div>\n <Panel.Error>{errors.root?.message}</Panel.Error>\n <Panel.InlineElements align='end'>\n <Button onClick={onClose}>Cancel</Button>\n <Button variant='primary' type='submit' disabled={!isValid || !isDirty} loading={isSubmitting || isMutating}>\n Save\n </Button>\n </Panel.InlineElements>\n </div>\n </Panel.Indent>\n );\n}\n","import { useState } from 'react';\nimport { IoAdd, IoOpenOutline, IoPencil, IoTrash } from 'react-icons/io5';\nimport { URLPreset } from 'ontime-types';\n\nimport Button from '../../../../common/components/buttons/Button';\nimport IconButton from '../../../../common/components/buttons/IconButton';\nimport Info from '../../../../common/components/info/Info';\nimport ExternalLink from '../../../../common/components/link/external-link/ExternalLink';\nimport Switch from '../../../../common/components/switch/Switch';\nimport Tag from '../../../../common/components/tag/Tag';\nimport useUrlPresets, { useUpdateUrlPreset } from '../../../../common/hooks-query/useUrlPresets';\nimport { handleLinks } from '../../../../common/utils/linkUtils';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport URLPresetForm from './composite/URLPresetForm';\n\ntype FormState = {\n isOpen: boolean;\n preset?: URLPreset;\n};\n\nconst urlPresetsDocs = 'https://docs.getontime.no/features/url-presets/';\n\nexport default function URLPresets() {\n const [formState, setFormState] = useState<FormState>({ isOpen: false, preset: undefined });\n const { data, status } = useUrlPresets();\n const { deletePreset, isMutating } = useUpdateUrlPreset();\n\n const openNewForm = () => setFormState({ isOpen: true });\n const openEditForm = (preset: URLPreset) => setFormState({ isOpen: true, preset });\n const closeForm = () => setFormState({ isOpen: false, preset: undefined });\n\n return (\n <Panel.Section>\n <Panel.Card>\n <Panel.SubHeader>\n URL presets\n <Button onClick={openNewForm}>\n New <IoAdd />\n </Button>\n </Panel.SubHeader>\n <Panel.Divider />\n <Panel.Section>\n <Info>\n URL presets are user pre-defined aliases to Ontime URLs.\n <br />\n This URL can contain full configuration including parameters, or simply route to a specific view.\n <br />\n <br />\n The easiest way to get started is to copy an URL from your browser and paste it into the form.\n <ExternalLink href={urlPresetsDocs}>See the docs</ExternalLink>\n </Info>\n </Panel.Section>\n <Panel.Section>\n <Panel.Loader isLoading={status === 'pending'} />\n {formState.isOpen && <URLPresetForm urlPreset={formState.preset} onClose={closeForm} />}\n <Panel.Table>\n <thead>\n <tr>\n <th>Enabled</th>\n <th>Target view</th>\n <th>Alias</th>\n <th />\n </tr>\n </thead>\n <tbody>\n {data.length === 0 && <Panel.TableEmpty handleClick={openNewForm} />}\n {data.map((preset, index) => {\n return (\n <tr key={preset.alias}>\n <td>\n <Switch defaultChecked={preset.enabled} onCheckedChange={() => {}} />\n </td>\n <td>\n <Tag>{preset.target}</Tag>\n </td>\n <td style={{ width: '100%' }}>{preset.alias}</td>\n <Panel.InlineElements relation='inner' as='td'>\n <IconButton\n variant='ghosted-white'\n onClick={(event) => handleLinks(preset.alias, event)}\n disabled={isMutating}\n >\n <IoOpenOutline />\n </IconButton>\n <IconButton\n onClick={() => openEditForm(preset)}\n variant='ghosted-white'\n aria-label='Edit entry'\n data-testid={`field__edit_${index}`}\n disabled={isMutating}\n >\n <IoPencil />\n </IconButton>\n <IconButton\n onClick={() => deletePreset(preset.alias)}\n variant='ghosted-destructive'\n aria-label='Delete entry'\n data-testid={`field__delete_${index}`}\n disabled={isMutating}\n >\n <IoTrash />\n </IconButton>\n </Panel.InlineElements>\n </tr>\n );\n })}\n </tbody>\n </Panel.Table>\n </Panel.Section>\n </Panel.Card>\n </Panel.Section>\n );\n}\n","import useScrollIntoView from '../../../../common/hooks/useScrollIntoView';\nimport { isOntimeCloud } from '../../../../externals';\nimport GenerateLinkFormExport from '../../../sharing/GenerateLinkFormExport';\nimport type { PanelBaseProps } from '../../panel-list/PanelList';\nimport * as Panel from '../../panel-utils/PanelUtils';\nimport InfoNif from '../network-panel/NetworkInterfaces';\n\nimport ReportSettings from './ReportSettings';\nimport URLPresets from './URLPresets';\n\nexport default function FeaturePanel({ location }: PanelBaseProps) {\n const presetsRef = useScrollIntoView<HTMLDivElement>('presets', location);\n const linkRef = useScrollIntoView<HTMLDivElement>('link', location);\n const reportRef = useScrollIntoView<HTMLDivElement>('report', location);\n\n return (\n <>\n <Panel.Header>Sharing and reporting</Panel.Header>\n <div ref={presetsRef}>\n <URLPresets />\n </div>\n <div ref={linkRef}>\n <Panel.Section>\n <Panel.Card>\n <Panel.SubHeader>Share Ontime Link</Panel.SubHeader>\n {!isOntimeCloud && (\n <>\n <Panel.Paragraph>Ontime is streaming on the following network interfaces</Panel.Paragraph>\n <InfoNif />\n </>\n )}\n <Panel.Divider />\n <GenerateLinkFormExport />\n </Panel.Card>\n </Panel.Section>\n </div>\n <div ref={reportRef}>\n <ReportSettings />\n </div>\n </>\n );\n}\n","import axios, { AxiosResponse } from 'axios';\nimport { CustomFields, Rundown } from 'ontime-types';\nimport { ImportMap } from 'ontime-utils';\n\nimport { apiEntryUrl } from './constants';\nimport { downloadBlob } from './utils';\n\nconst excelPath = `${apiEntryUrl}/excel`;\n\n/**\n * upload Excel file to server\n * @return string - file ID op the uploaded file\n */\nexport async function upload(file: File) {\n const formData = new FormData();\n formData.append('excel', file);\n await axios.post(`${excelPath}/upload`, formData, {\n headers: {\n 'Content-Type': 'multipart/form-data',\n },\n });\n}\n\n/**\n * Get Worksheet names\n * @return string[] - array of available worksheets\n */\nexport async function getWorksheetNames(): Promise<string[]> {\n const response: AxiosResponse<string[]> = await axios.get(`${excelPath}/worksheets`);\n return response.data;\n}\n\ntype PreviewSpreadsheetResponse = {\n rundown: Rundown;\n customFields: CustomFields;\n};\nexport async function importRundownPreview(options: ImportMap): Promise<PreviewSpreadsheetResponse> {\n const response: AxiosResponse<PreviewSpreadsheetResponse> = await axios.post(`${excelPath}/preview`, {\n options,\n });\n return response.data;\n}\n\n/**\n * Downloads a xlsx representation of the rundown from the server\n */\nexport async function downloadAsExcel(rundownId: string, fileName?: string) {\n try {\n const response = await axios.get(`${excelPath}/${rundownId}/export`, {\n responseType: 'blob',\n });\n\n downloadBlob(response.data, `${fileName ?? 'Ontime_rundown'}.xlsx`);\n } catch (error) {\n console.error('Error downloading file:', error);\n }\n}\n","import axios, { AxiosResponse } from 'axios';\nimport { AuthenticationStatus, CustomFields, Rundown } from 'ontime-types';\nimport { ImportMap } from 'ontime-utils';\n\nimport { apiEntryUrl } from './constants';\n\nconst sheetsPath = `${apiEntryUrl}/sheets`;\n\n/**\n * HTTP request to verify whether we are authenticated with Google Sheet service\n */\nexport const verifyAuthenticationStatus = async (): Promise<{\n authenticated: AuthenticationStatus;\n sheetId: string;\n}> => {\n const response = await axios.get(`${sheetsPath}/connect`);\n return response.data;\n};\n\n/**\n * HTTP request to initiate the authentication service with google\n */\nexport const requestConnection = async (\n file: File,\n sheetId: string,\n): Promise<{\n verification_url: string;\n user_code: string;\n}> => {\n const formData = new FormData();\n formData.append('client_secret', file);\n\n const response = await axios.post(`${sheetsPath}/${sheetId}/connect`, formData, {\n headers: {\n 'Content-Type': 'multipart/form-data',\n },\n });\n\n return response.data;\n};\n\n/**\n * HTTP request to revoke authentication to google sheet\n */\nexport const revokeAuthentication = async (): Promise<{ authenticated: AuthenticationStatus }> => {\n const response = await axios.post(`${sheetsPath}/revoke`);\n return response.data;\n};\n\n/**\n * HTTP request to upload preview the contents of a google sheet as rundown\n */\nexport const previewRundown = async (\n sheetId: string,\n options: ImportMap,\n): Promise<{\n rundown: Rundown;\n customFields: CustomFields;\n}> => {\n const response = await axios.post(`${sheetsPath}/${sheetId}/read`, { options });\n return response.data;\n};\n\nexport const getWorksheetNames = async (sheetId: string): Promise<string[]> => {\n const response: AxiosResponse<string[]> = await axios.post(`${sheetsPath}/${sheetId}/worksheets`);\n return response.data;\n};\n\n/**\n * HTTP request to upload the rundown to a google sheet\n */\nexport const uploadRundown = async (sheetId: string, options: ImportMap): Promise<void> => {\n const response = await axios.post(`${sheetsPath}/${sheetId}/write`, { options });\n return response.data;\n};\n","/**\n * Collection of rules for pre-validating a spreadsheet\n * @param file\n */\nexport function validateExcelImport(file: File) {\n if (!isExcelFile(file)) {\n throw new Error('Unknown file type');\n }\n\n // Check if file is empty\n if (file.size === 0) {\n throw new Error('File is empty');\n }\n\n // Limit file size of an Excel file to around 10MB\n if (file.size > 10_000_000) {\n throw new Error('File size limit (10MB) exceeded');\n }\n}\n\n/**\n * Collection of rules for pre-validating a project file\n * @param file\n */\nexport function validateProjectFile(file: File) {\n if (!isOntimeFile(file)) {\n throw new Error('Unknown file type');\n }\n\n // Check if file is empty\n if (file.size === 0) {\n throw new Error('File is empty');\n }\n\n // Limit file size of a project file to around 1MB\n if (file.size > 2_000_000) {\n throw new Error('File size limit (2MB) exceeded');\n }\n}\n\nexport function isExcelFile(file: File | null) {\n return file?.name.endsWith('.xlsx');\n}\n\nexport function isOntimeFile(file: File | null) {\n return file?.name.endsWith('.json');\n}\n\n/**\n * Collection of rules for pre-validating a project file\n * @param file\n */\nexport function validateLogo(file: File) {\n // Check if file is empty\n if (file.size === 0) {\n throw new Error('File is empty');\n }\n\n // Limit file size of a project file to around 1.5MB\n if (file.size > 1_500_000) {\n throw new Error('File size limit (1.5MB) exceeded');\n }\n}\n","import axios, { AxiosResponse } from 'axios';\nimport { DatabaseModel, MessageResponse, ProjectData, ProjectFileListResponse, QuickStartData } from 'ontime-types';\n\nimport { apiEntryUrl } from './constants';\nimport { createBlob, downloadBlob } from './utils';\n\nconst dbPath = `${apiEntryUrl}/db`;\n\n/**\n * HTTP request to the current DB\n */\nexport function getDb(filename: string): Promise<AxiosResponse<DatabaseModel>> {\n return axios.post(`${dbPath}/download`, { filename });\n}\n\n/**\n * Request download of the current project file\n * @param fileName\n */\nexport async function downloadProject(fileName: string) {\n try {\n const { data, name } = await fileDownload(fileName);\n\n const fileContent = JSON.stringify(data, null, 2);\n\n const blob = createBlob(fileContent, 'application/json;charset=utf-8;');\n downloadBlob(blob, `${name}.json`);\n } catch (error) {\n console.error(error);\n }\n}\n\n/**\n * HTTP request to upload project file\n */\nexport async function uploadProjectFile(file: File): Promise<MessageResponse> {\n const formData = new FormData();\n formData.append('project', file);\n const response = await axios.post(`${dbPath}/upload`, formData, {\n headers: {\n 'Content-Type': 'multipart/form-data',\n },\n });\n return response.data;\n}\n\n/**\n * Make patch changes to the objects in the db\n */\nexport async function patchData(patchDb: Partial<DatabaseModel>): Promise<AxiosResponse<DatabaseModel>> {\n return await axios.patch(dbPath, patchDb);\n}\n\n/**\n * HTTP request to create a project file\n */\nexport async function createProject(\n project: Partial<\n ProjectData & {\n filename: string;\n }\n >,\n): Promise<MessageResponse> {\n const res = await axios.post(`${dbPath}/new`, project);\n return res.data;\n}\n\n/**\n * HTTP request to create a project file\n */\nexport async function quickProject(data: QuickStartData): Promise<MessageResponse> {\n const res = await axios.post(`${dbPath}/quick`, data);\n return res.data;\n}\n\n/**\n * HTTP request to get the list of available project files\n */\nexport async function getProjects(): Promise<ProjectFileListResponse> {\n const res = await axios.get(`${dbPath}/all`);\n return res.data;\n}\n\n/**\n * HTTP request to load a project file\n */\nexport async function loadProject(filename: string): Promise<MessageResponse> {\n const res = await axios.post(`${dbPath}/load`, {\n filename,\n });\n return res.data;\n}\n\n/**\n * HTTP request to load the demo project file\n */\nexport async function loadDemo(): Promise<MessageResponse> {\n const res = await axios.post(`${dbPath}/demo`);\n return res.data;\n}\n\n/**\n * HTTP request to duplicate a project file\n */\nexport async function duplicateProject(filename: string, newFilename: string): Promise<MessageResponse> {\n const url = `${dbPath}/${filename}/duplicate`;\n const decodedUrl = decodeURIComponent(url);\n const res = await axios.post(decodedUrl, {\n newFilename,\n });\n return res.data;\n}\n\n/**\n * HTTP request to rename a project file\n */\nexport async function renameProject(filename: string, newFilename: string): Promise<MessageResponse> {\n const url = `${dbPath}/${filename}/rename`;\n const decodedUrl = decodeURIComponent(url);\n const res = await axios.put(decodedUrl, {\n newFilename,\n });\n return res.data;\n}\n\n/**\n * HTTP request to delete a project file\n */\nexport async function deleteProject(filename: string): Promise<MessageResponse> {\n const url = `${dbPath}/${filename}`;\n const decodedUrl = decodeURIComponent(url);\n const res = await axios.delete(decodedUrl);\n return res.data;\n}\n\n/**\n * Utility function gets project from db\n * @param fileName\n * @returns\n */\nasync function fileDownload(fileName: string): Promise<{ data: DatabaseModel; name: string }> {\n const response = await getDb(fileName);\n\n const headerLine = response.headers['Content-Disposition'];\n\n // try and get the filename from the response\n let name = fileName;\n if (headerLine != null) {\n const startFileNameIndex = headerLine.indexOf('\"') + 1;\n const endFileNameIndex = headerLine.lastIndexOf('\"');\n name = headerLine.substring(startFileNameIndex, endFileNameIndex);\n }\n\n return { data: response.data, name };\n}\n","import { AuthenticationStatus, CustomFields, Rundown } from 'ontime-types';\nimport { defaultImportMap, ImportMap } from 'ontime-utils';\nimport { create } from 'zustand';\n\ntype SheetStore = {\n stepData: typeof initialStepData;\n patchStepData: (patch: Partial<typeof initialStepData>) => void;\n setWorksheets: (worksheetNames: string[] | null) => void;\n worksheetNames: string[] | null;\n\n //gSheet\n sheetId: string | null;\n setSheetId: (sheetId: string | null) => void;\n authenticationStatus: AuthenticationStatus;\n setAuthenticationStatus: (status: AuthenticationStatus) => void;\n\n // we get this from a preview response\n rundown: Rundown | null;\n setRundown: (rundown: Rundown | null) => void;\n\n // we get this from a preview response\n customFields: CustomFields | null;\n setCustomFields: (customFields: CustomFields | null) => void;\n\n spreadsheetImportMap: ImportMap;\n patchSpreadsheetImportMap: <T extends keyof ImportMap>(field: T, value: ImportMap[T]) => void;\n\n reset: () => void;\n resetPreview: () => void;\n};\n\nconst initialStepData = {\n authenticate: { available: false, error: '' },\n sheetId: { available: false, error: '' },\n worksheet: { available: false, error: '' },\n pullPush: { available: false, error: '' },\n};\n\nconst initialState = {\n stepData: initialStepData,\n worksheetNames: null,\n sheetId: null,\n authenticationStatus: 'not_authenticated' as AuthenticationStatus,\n rundown: null,\n customFields: null,\n spreadsheetImportMap: defaultImportMap,\n};\n\nexport const useSheetStore = create<SheetStore>((set, get) => ({\n ...initialState,\n\n patchStepData: (patch: Partial<typeof initialStepData>) => {\n const stepData = get().stepData;\n set({ stepData: { ...stepData, ...patch } });\n },\n\n setWorksheets: (worksheetNames: string[] | null) => set({ worksheetNames }),\n\n setSheetId: (sheetId: string | null) => set({ sheetId }),\n\n setAuthenticationStatus: (status: AuthenticationStatus) => set({ authenticationStatus: status }),\n\n setRundown: (rundown: Rundown | null) => set({ rundown }),\n\n setCustomFields: (customFields: CustomFields | null) => set({ customFields }),\n\n patchSpreadsheetImportMap: <T extends keyof ImportMap>(field: T, value: ImportMap[T]) => {\n const currentImportMap = get().spreadsheetImportMap;\n if (currentImportMap[field] !== value) {\n currentImportMap[field] = value;\n }\n },\n\n reset: () => set(initialState),\n resetPreview: () => set({ rundown: null, customFields: null }),\n}));\n","import { useQueryClient } from '@tanstack/react-query';\nimport { AuthenticationStatus, CustomFields, ProjectRundowns } from 'ontime-types';\nimport { ImportMap } from 'ontime-utils';\n\nimport { CUSTOM_FIELDS, RUNDOWN } from '../../../../../common/api/constants';\nimport { patchData } from '../../../../../common/api/db';\nimport {\n previewRundown,\n requestConnection,\n revokeAuthentication,\n uploadRundown,\n verifyAuthenticationStatus,\n} from '../../../../../common/api/sheets';\nimport { maybeAxiosError } from '../../../../../common/api/utils';\n\nimport { useSheetStore } from './useSheetStore';\n\nexport default function useGoogleSheet() {\n const queryClient = useQueryClient();\n // functions push data to store\n const patchStepData = useSheetStore((state) => state.patchStepData);\n const setRundown = useSheetStore((state) => state.setRundown);\n const setCustomFields = useSheetStore((state) => state.setCustomFields);\n\n /** whether the current session has been authenticated */\n const verifyAuth = async (): Promise<{ authenticated: AuthenticationStatus; sheetId: string } | void> => {\n try {\n return await verifyAuthenticationStatus();\n } catch (error) {\n patchStepData({ authenticate: { available: false, error: maybeAxiosError(error) } });\n }\n };\n\n /** requests connection to a google sheet */\n const connect = async (\n file: File,\n sheetId: string,\n ): Promise<{ verification_url: string; user_code: string } | void> => {\n try {\n return await requestConnection(file, sheetId);\n } catch (error) {\n patchStepData({ authenticate: { available: false, error: maybeAxiosError(error) } });\n }\n };\n\n /** requests the revoking of an existing authenticated session */\n const revoke = async (): Promise<{ authenticated: AuthenticationStatus } | void> => {\n try {\n return await revokeAuthentication();\n } catch (error) {\n patchStepData({ authenticate: { available: false, error: maybeAxiosError(error) } });\n }\n };\n\n /** fetches data from a worksheet by its ID */\n const importRundownPreview = async (sheetId: string, fileOptions: ImportMap) => {\n try {\n const data = await previewRundown(sheetId, fileOptions);\n setRundown(data.rundown);\n setCustomFields(data.customFields);\n } catch (error) {\n patchStepData({ pullPush: { available: true, error: maybeAxiosError(error) } });\n }\n };\n\n /** writes data to a worksheet by its ID */\n const exportRundown = async (sheetId: string, fileOptions: ImportMap) => {\n try {\n // write data to google\n await uploadRundown(sheetId, fileOptions);\n patchStepData({ pullPush: { available: false, error: '' } });\n } catch (error) {\n patchStepData({ pullPush: { available: true, error: maybeAxiosError(error) } });\n }\n };\n\n /** applies rundown and customFields to current project */\n const importRundown = async (rundowns: ProjectRundowns, customFields: CustomFields) => {\n try {\n await patchData({ rundowns, customFields });\n // we are unable to optimistically set the rundown since we need\n // it to be normalised\n await queryClient.invalidateQueries({\n queryKey: [RUNDOWN, CUSTOM_FIELDS],\n });\n } catch (error) {\n patchStepData({ pullPush: { available: true, error: maybeAxiosError(error) } });\n }\n };\n\n return {\n connect,\n revoke,\n verifyAuth,\n\n importRundownPreview,\n importRundown,\n exportRundown,\n };\n}\n","import { ImportCustom, ImportMap } from 'ontime-utils';\n\nexport type NamedImportMap = typeof namedImportMap;\n\n// Record of label and import name\nconst namedImportMap = {\n Worksheet: 'event schedule',\n Flag: 'flag',\n Start: 'time start',\n 'Link start': 'link start',\n End: 'time end',\n Duration: 'duration',\n Cue: 'cue',\n Title: 'title',\n 'Count to end': 'count to end',\n Skip: 'skip',\n Note: 'notes',\n Colour: 'colour',\n 'End action': 'end action',\n 'Timer type': 'timer type',\n 'Time warning': 'warning time',\n 'Time danger': 'danger time',\n ID: 'id',\n custom: [] as ImportCustom[],\n};\n\nfunction isNamedImportMap(obj: unknown): obj is NamedImportMap {\n if (typeof obj !== 'object' || obj === null) {\n return false;\n }\n\n const keys = Object.keys(namedImportMap);\n return keys.every((key) => Object.hasOwn(obj, key));\n}\n\nexport function convertToImportMap(namedImportMap: NamedImportMap): ImportMap {\n const custom = namedImportMap.custom.reduce((accumulator, { ontimeName, importName }) => {\n if (ontimeName && importName) {\n accumulator[ontimeName.trim()] = importName.trim();\n }\n return accumulator;\n }, {});\n\n return {\n worksheet: namedImportMap.Worksheet,\n flag: namedImportMap.Flag,\n timeStart: namedImportMap.Start,\n linkStart: namedImportMap['Link start'],\n timeEnd: namedImportMap.End,\n duration: namedImportMap.Duration,\n cue: namedImportMap.Cue,\n title: namedImportMap.Title,\n countToEnd: namedImportMap['Count to end'],\n skip: namedImportMap.Skip,\n note: namedImportMap.Note,\n colour: namedImportMap.Colour,\n endAction: namedImportMap['End action'],\n timerType: namedImportMap['Timer type'],\n timeWarning: namedImportMap['Time warning'],\n timeDanger: namedImportMap['Time danger'],\n custom,\n id: namedImportMap.ID,\n };\n}\n\nexport function persistImportMap(options: NamedImportMap) {\n localStorage.setItem('import-options', JSON.stringify(options));\n}\n\nfunction getPersistImportMap(): unknown {\n const options = localStorage.getItem('import-options');\n if (!options) {\n throw new Error('no import options found');\n }\n return JSON.parse(options);\n}\n\nexport function getPersistedOptions(): NamedImportMap {\n try {\n const options = getPersistImportMap();\n if (!isNamedImportMap(options)) {\n return namedImportMap;\n }\n return options;\n } catch {\n return namedImportMap;\n }\n}\n","import { useEffect, useState } from 'react';\nimport { useFieldArray, useForm } from 'react-hook-form';\nimport { IoAdd, IoTrash } from 'react-icons/io5';\nimport { checkRegex, ImportMap } from 'ontime-utils';\n\nimport Button from '../../../../../../common/components/buttons/Button';\nimport IconButton from '../../../../../../common/components/buttons/IconButton';\nimport Input from '../../../../../../common/components/input/input/Input';\nimport Select from '../../../../../../common/components/select/Select';\nimport Tooltip from '../../../../../../common/components/tooltip/Tooltip';\nimport * as Panel from '../../../../panel-utils/PanelUtils';\nimport useGoogleSheet from '../useGoogleSheet';\nimport { useSheetStore } from '../useSheetStore';\n\nimport { convertToImportMap, getPersistedOptions, NamedImportMap, persistImportMap } from './importMapUtils';\n\nimport style from '../SourcesPanel.module.scss';\n\ninterface ImportMapFormProps {\n hasErrors: boolean;\n isSpreadsheet: boolean;\n onCancel: () => void;\n onSubmitExport: (importMap: ImportMap) => Promise<void>;\n onSubmitImport: (importMap: ImportMap) => Promise<void>;\n}\n\nexport default function ImportMapForm({\n hasErrors,\n isSpreadsheet,\n onCancel,\n onSubmitExport,\n onSubmitImport,\n}: ImportMapFormProps) {\n const namedImportMap = getPersistedOptions();\n const { revoke } = useGoogleSheet();\n const {\n control,\n handleSubmit,\n register,\n setValue,\n watch,\n formState: { errors, isValid },\n } = useForm<NamedImportMap>({\n mode: 'onChange',\n defaultValues: namedImportMap,\n values: namedImportMap,\n });\n\n const { fields, append, remove } = useFieldArray({\n control,\n name: 'custom',\n });\n\n const stepData = useSheetStore((state) => state.stepData);\n const worksheetNames = useSheetStore((state) => state.worksheetNames);\n\n const [loading, setLoading] = useState<'' | 'export' | 'import'>('');\n\n // Set first sheet as default worksheet when 'event schedule' sheet is not there\n useEffect(() => {\n if (!worksheetNames || worksheetNames.length === 0) return;\n if (!worksheetNames.includes(namedImportMap.Worksheet)) {\n setValue('Worksheet', worksheetNames[0], { shouldValidate: true, shouldDirty: true });\n }\n }, [worksheetNames, setValue, namedImportMap.Worksheet]);\n\n const handleExport = async (values: NamedImportMap) => {\n setLoading('export');\n const importMap = convertToImportMap(values);\n\n await onSubmitExport(importMap);\n setLoading('');\n };\n\n const handleRevoke = async () => {\n await revoke();\n onCancel();\n };\n\n const handleImportPreview = async (values: NamedImportMap) => {\n setLoading('import');\n const importMap = convertToImportMap(values);\n persistImportMap(values);\n await onSubmitImport(importMap);\n setLoading('');\n };\n\n const deleteCustomImport = (index: number) => {\n remove(index);\n };\n\n const addCustomImport = () => {\n append({});\n };\n\n const isLoading = Boolean(loading);\n const canSubmitSpreadsheet = isSpreadsheet && !isLoading;\n const canSubmitGSheet = !isLoading && !stepData.worksheet.error;\n const canSubmit = !hasErrors && isValid && (canSubmitSpreadsheet || canSubmitGSheet);\n\n return (\n <Panel.Section as='form' id='import-map'>\n <Panel.Title>\n Import options\n <Panel.InlineElements>\n {!isSpreadsheet && (\n <Tooltip\n text='Revoke the google authentication'\n render={<Button />}\n onClick={handleRevoke}\n disabled={isLoading}\n >\n Revoke\n </Tooltip>\n )}\n <Button onClick={onCancel} disabled={isLoading}>\n Cancel\n </Button>\n {!isSpreadsheet && (\n <Button\n variant='primary'\n onClick={handleSubmit(handleExport)}\n disabled={!canSubmitGSheet}\n loading={loading === 'export'}\n >\n Export\n </Button>\n )}\n <Button\n variant='primary'\n onClick={handleSubmit(handleImportPreview)}\n disabled={!canSubmit}\n loading={loading === 'import'}\n >\n Import preview\n </Button>\n </Panel.InlineElements>\n </Panel.Title>\n <Panel.Table>\n <thead>\n <tr>\n <th>Ontime field</th>\n <th>Column name in spreadsheet</th>\n <th className={style.singleActionCell} />\n </tr>\n </thead>\n <tbody>\n {Object.entries(namedImportMap).map(([label, importName]) => {\n if (label === 'custom') {\n return null;\n }\n if (label === 'Worksheet') {\n return (\n <tr key={importName as string}>\n <td>{label}</td>\n <td>\n <Select\n id={importName as string}\n value={watch(label as keyof NamedImportMap) as string}\n onValueChange={(value: string) =>\n setValue(label as keyof NamedImportMap, value, { shouldDirty: true })\n }\n options={worksheetNames?.map((name) => ({ value: name, label: name })) || []}\n />\n </td>\n <td className={style.singleActionCell} />\n </tr>\n );\n }\n return (\n <tr key={importName as string}>\n <td>{label}</td>\n <td>\n <Input\n id={importName as string}\n fluid\n maxLength={25}\n defaultValue={importName as string}\n placeholder='Use default column name'\n {...register(label as keyof NamedImportMap)}\n />\n </td>\n <td className={style.singleActionCell} />\n </tr>\n );\n })}\n {fields.map((field, index) => {\n const ontimeName = field.ontimeName;\n const importName = field.importName;\n const maybeOntimeError = errors.custom?.[index]?.ontimeName?.message;\n const key = `custom.${index}.ontimeName`;\n return (\n <tr key={key}>\n <td>\n <Input\n maxLength={25}\n fluid\n defaultValue={ontimeName}\n placeholder='Name of the field as shown in Ontime'\n {...register(`custom.${index}.ontimeName`, {\n validate: (value) => {\n if (!checkRegex.isAlphanumericWithSpace(value))\n return 'Only alphanumeric characters and space are allowed';\n return true;\n },\n })}\n />\n {maybeOntimeError && <Panel.Error>{maybeOntimeError}</Panel.Error>}\n </td>\n <td>\n <Input\n maxLength={25}\n fluid\n defaultValue={importName}\n placeholder='Name of the column in the spreadsheet'\n {...register(`custom.${index}.importName`)}\n />\n </td>\n <td className={style.singleActionCell}>\n <IconButton\n variant='ghosted-destructive'\n aria-label='Delete entry'\n onClick={() => deleteCustomImport(index)}\n >\n <IoTrash />\n </IconButton>\n </td>\n </tr>\n );\n })}\n <tr>\n <td />\n <Panel.InlineElements as='td' align='end'>\n <Button onClick={addCustomImport}>\n Add custom field <IoAdd />\n </Button>\n </Panel.InlineElements>\n <td />\n </tr>\n </tbody>\n </Panel.Table>\n <Panel.Error>{stepData.worksheet.error}</Panel.Error>\n </Panel.Section>\n );\n}\n","import Info from '../../../../../common/components/info/Info';\nimport ExternalLink from '../../../../../common/components/link/external-link/ExternalLink';\n\nconst googleSheetDocsUrl = 'https://docs.getontime.no/features/import-spreadsheet-gsheet/';\n\nexport default function GSheetInfo() {\n return (\n <Info>\n Ontime can import data from spreadsheets by: <br />\n - importing the spreadsheet file in Ontime <br />\n - synchronising your project with a Google Sheet\n <br />\n <br />\n To synchronise with a Google Sheet, you will need to allow Ontime to authenticate with your Google account.\n <ExternalLink href={googleSheetDocsUrl}>See the docs</ExternalLink>\n </Info>\n );\n}\n","import { ChangeEvent, useEffect, useState } from 'react';\nimport { IoCheckmark, IoShieldCheckmarkOutline } from 'react-icons/io5';\n\nimport { getWorksheetNames } from '../../../../../common/api/sheets';\nimport { maybeAxiosError } from '../../../../../common/api/utils';\nimport Button from '../../../../../common/components/buttons/Button';\nimport CopyTag from '../../../../../common/components/copy-tag/CopyTag';\nimport Input from '../../../../../common/components/input/input/Input';\nimport { openLink } from '../../../../../common/utils/linkUtils';\nimport * as Panel from '../../../panel-utils/PanelUtils';\n\nimport useGoogleSheet from './useGoogleSheet';\nimport { useSheetStore } from './useSheetStore';\n\ninterface GSheetSetupProps {\n onCancel: () => void;\n}\n\nexport default function GSheetSetup(props: GSheetSetupProps) {\n const { onCancel } = props;\n\n const { revoke, connect, verifyAuth } = useGoogleSheet();\n const [file, setFile] = useState<File | null>(null);\n const [authKey, setAuthKey] = useState<string | null>(null);\n const [loading, setLoading] = useState<'' | 'cancel' | 'connect' | 'authenticate'>('');\n const [authLink, setAuthLink] = useState('');\n\n const sheetId = useSheetStore((state) => state.sheetId);\n const setSheetId = useSheetStore((state) => state.setSheetId);\n const setWorksheets = useSheetStore((state) => state.setWorksheets);\n const patchStepData = useSheetStore((state) => state.patchStepData);\n const authenticationStatus = useSheetStore((state) => state.authenticationStatus);\n const setAuthenticationStatus = useSheetStore((state) => state.setAuthenticationStatus);\n const authenticationError = useSheetStore((state) => state.stepData.authenticate.error);\n\n /** Check if we are authenticated */\n const getAuthStatus = async () => {\n const result = await verifyAuth();\n if (result) {\n setAuthenticationStatus(result.authenticated);\n }\n };\n\n /** check if the current session has been authenticated */\n useEffect(() => {\n patchStepData({ authenticate: { available: false, error: '' } });\n untilAuthenticated();\n }, []);\n\n // user cancels the flow\n const handleRevoke = async () => {\n setLoading('cancel');\n await revoke();\n await getAuthStatus();\n setLoading('');\n };\n\n const handleCancelFlow = () => {\n onCancel();\n };\n\n /**\n * Gets file from input\n */\n const handleClientSecret = (event: ChangeEvent<HTMLInputElement>) => {\n if (!event.target.files?.length) {\n return;\n }\n setFile(event.target.files[0]);\n };\n\n /**\n * Requests connection to google auth\n */\n const handleConnect = async () => {\n if (!file) return;\n if (!sheetId) return;\n patchStepData({ worksheet: { available: false, error: '' } });\n\n setLoading('connect');\n const result = await connect(file, sheetId);\n if (result) {\n setAuthLink(result.verification_url);\n setAuthKey(result.user_code);\n }\n setLoading('');\n };\n\n const untilAuthenticated = async (attempts: number = 0) => {\n const result = await verifyAuth();\n if (result?.authenticated) {\n setAuthenticationStatus(result.authenticated);\n if (result.authenticated !== 'pending') {\n if (result.authenticated == 'authenticated') {\n try {\n const names = await getWorksheetNames(result.sheetId);\n setWorksheets(names);\n } catch (error) {\n const message = maybeAxiosError(error);\n patchStepData({ worksheet: { available: false, error: message } });\n }\n }\n setLoading('');\n return;\n }\n }\n if (attempts <= 10) {\n setTimeout(() => untilAuthenticated(attempts + 1), 2000);\n return;\n }\n setLoading('');\n };\n\n /**\n * Open google auth\n */\n const handleAuthenticate = async () => {\n setLoading('authenticate');\n\n // open link and schedule a check for when the user focuses again\n openLink(authLink);\n window.addEventListener(\n 'focus',\n async () => {\n untilAuthenticated();\n },\n { once: true },\n );\n };\n\n const canConnect = file && sheetId;\n const canAuthenticate = Boolean(authKey) && Boolean(authLink);\n const isLoading = Boolean(loading);\n const isAuthenticated = authenticationStatus === 'authenticated';\n const isAuthenticating = authenticationStatus === 'pending';\n\n return (\n <Panel.Section>\n <Panel.Title>\n Sync with Google Sheet (experimental)\n {isAuthenticated ? (\n <Button onClick={handleRevoke} loading={loading === 'cancel'}>\n Revoke Authentication\n </Button>\n ) : (\n <Button onClick={handleCancelFlow}>Go Back</Button>\n )}\n </Panel.Title>\n <Panel.ListGroup>\n <Panel.Description>Upload Client Secret provided by Google</Panel.Description>\n <Panel.Error>{authenticationError}</Panel.Error>\n <Input fluid type='file' onChange={handleClientSecret} accept='.json' disabled={isLoading || canAuthenticate} />\n </Panel.ListGroup>\n <Panel.ListGroup>\n <Panel.Description>Enter ID of sheet to synchronise</Panel.Description>\n <Panel.Error>{undefined}</Panel.Error>\n <Input\n fluid\n placeholder='Sheet ID'\n onChange={(event) => setSheetId(event.target.value)}\n disabled={isLoading || canAuthenticate}\n />\n </Panel.ListGroup>\n {!canAuthenticate ? (\n <Panel.ListGroup>\n <Panel.InlineElements>\n <Button onClick={handleConnect} disabled={!canConnect || isLoading} loading={loading === 'connect'}>\n <IoCheckmark />\n Connect\n </Button>\n </Panel.InlineElements>\n </Panel.ListGroup>\n ) : (\n <Panel.ListGroup>\n <Panel.InlineElements>\n {isAuthenticating && <span>Authenticating...</span>}\n <CopyTag copyValue={authKey ?? ''} disabled={!canAuthenticate}>\n {authKey ? authKey : 'Upload files to generate Auth Key'}\n </CopyTag>\n <Button onClick={handleAuthenticate} disabled={!canAuthenticate}>\n <IoShieldCheckmarkOutline />\n Authenticate\n </Button>\n </Panel.InlineElements>\n </Panel.ListGroup>\n )}\n </Panel.Section>\n );\n}\n","import { Fragment } from 'react';\nimport { IoLink } from 'react-icons/io5';\nimport { CustomFields, isOntimeEvent, isOntimeGroup, isOntimeMilestone, Rundown } from 'ontime-types';\nimport { millisToString } from 'ontime-utils';\n\nimport Tag from '../../../../../../common/components/tag/Tag';\nimport { getAccessibleColour } from '../../../../../../common/utils/styleUtils';\nimport * as Panel from '../../../../panel-utils/PanelUtils';\n\nimport style from './PreviewRundown.module.scss';\n\ninterface PreviewRundownProps {\n rundown: Rundown;\n customFields: CustomFields;\n}\n\nfunction booleanToText(value?: boolean) {\n return value ? 'Yes' : undefined;\n}\n\nexport default function PreviewRundown(props: PreviewRundownProps) {\n const { rundown, customFields } = props;\n\n // we only count Ontime Events which are 1 based in client\n let eventIndex = 0;\n\n const fieldKeys = Object.keys(customFields);\n const fieldLabels = fieldKeys.map((key) => customFields[key].label);\n\n return (\n <Panel.Table className={style.nowrap}>\n <thead>\n <tr>\n <th>#</th>\n <th>Type</th>\n <th>Cue</th>\n <th>Title</th>\n <th>Flag</th>\n <th>Time Start</th>\n <th>Time End</th>\n <th>Duration</th>\n <th>Warning Time</th>\n <th>Danger Time</th>\n <th>Count to end</th>\n <th>Skip</th>\n <th>Colour</th>\n <th>Timer Type</th>\n <th>End Action</th>\n {fieldLabels.map((label) => (\n <th key={label}>{label}</th>\n ))}\n <th>ID</th>\n </tr>\n </thead>\n <tbody>\n {rundown.flatOrder.map((entryId) => {\n const entry = rundown.entries[entryId];\n if (isOntimeGroup(entry)) {\n const colour = entry.colour ? getAccessibleColour(entry.colour) : {};\n return (\n <tr key={entry.id}>\n <td className={style.center}>\n <Tag>-</Tag>\n </td>\n <td className={style.center}>\n <Tag>{entry.type}</Tag>\n </td>\n <td /> {/** CUE */}\n <td>{entry.title}</td>\n <td /> {/** Flag */}\n <td /> {/** Time Start */}\n <td /> {/** Time End */}\n <td /> {/** Duration */}\n <td /> {/** Warning Time */}\n <td /> {/** Danger Time */}\n <td /> {/** Count to end */}\n <td /> {/** Skip */}\n <td style={{ ...colour }}>{entry.colour}</td>\n <td /> {/** Timer Type */}\n <td /> {/** End Action */}\n {fieldKeys.map((field) => {\n let value = '';\n if (field in entry.custom) {\n value = entry.custom[field];\n }\n return <td key={field}>{value}</td>;\n })}\n <td className={style.center}>\n <Tag>{entry.id}</Tag>\n </td>\n </tr>\n );\n }\n if (isOntimeMilestone(entry)) {\n const colour = entry.colour ? getAccessibleColour(entry.colour) : {};\n return (\n <Fragment key={entry.id}>\n <tr>\n <td /> {/** Index */}\n <td className={style.center}>\n <Tag>{entry.type}</Tag>\n </td>\n <td className={style.nowrap}>{entry.cue}</td>\n <td>{entry.title}</td>\n <td /> {/** Flag */}\n <td /> {/** Time Start */}\n <td /> {/** Time End */}\n <td /> {/** Duration */}\n <td /> {/** Warning Time */}\n <td /> {/** Danger Time */}\n <td /> {/** Count to end */}\n <td /> {/** Skip */}\n <td style={{ ...colour }}>{entry.colour}</td>\n <td /> {/** Timer Type */}\n <td /> {/** End Action */}\n {fieldKeys.map((field) => {\n let value = '';\n if (field in entry.custom) {\n value = entry.custom[field];\n }\n return <td key={field}>{value}</td>;\n })}\n <td className={style.center}>\n <Tag>{entry.id}</Tag>\n </td>\n </tr>\n {entry.note && (\n <tr>\n <td colSpan={99} className={style.secondaryRow}>\n Note: {entry.note}\n </td>\n </tr>\n )}\n </Fragment>\n );\n }\n if (!isOntimeEvent(entry)) {\n return null;\n }\n eventIndex += 1;\n const colour = entry.colour ? getAccessibleColour(entry.colour) : {};\n const countToEnd = booleanToText(entry.countToEnd);\n const skip = booleanToText(entry.skip);\n const flag = booleanToText(entry.flag);\n\n return (\n <Fragment key={entry.id}>\n <tr>\n <td className={style.center}>\n <Tag>{eventIndex}</Tag>\n </td>\n <td className={style.center}>\n <Tag>{entry.type}</Tag>\n </td>\n <td className={style.nowrap}>{entry.cue}</td>\n <td>{entry.title}</td>\n <td className={style.center}>{flag && <Tag>{flag}</Tag>}</td>\n <td className={style.flex}>\n <span className={entry.linkStart ? style.subdued : undefined}>{millisToString(entry.timeStart)}</span>\n {entry.linkStart && <IoLink className={style.linkStartActive} />}\n </td>\n <td>{millisToString(entry.timeEnd)}</td>\n <td>{millisToString(entry.duration)}</td>\n <td>{millisToString(entry.timeWarning)}</td>\n <td>{millisToString(entry.timeDanger)}</td>\n <td className={style.center}>{countToEnd && <Tag>{countToEnd}</Tag>}</td>\n <td>{skip && <Tag>{skip}</Tag>}</td>\n <td style={{ ...colour }}>{entry.colour}</td>\n <td className={style.center}>\n <Tag>{entry.timerType}</Tag>\n </td>\n <td className={style.center}>\n <Tag>{entry.endAction}</Tag>\n </td>\n {fieldKeys.map((field) => {\n let value = '';\n if (field in entry.custom) {\n value = entry.custom[field];\n }\n return <td key={field}>{value}</td>;\n })}\n <td className={style.center}>\n <Tag>{entry.id}</Tag>\n </td>\n </tr>\n {entry.note && (\n <tr>\n <td colSpan={99} className={style.secondaryRow}>\n Note: {entry.note}\n </td>\n </tr>\n )}\n </Fragment>\n );\n })}\n </tbody>\n </Panel.Table>\n );\n}\n","import { useState } from 'react';\nimport { CustomFields, Rundown } from 'ontime-types';\n\nimport Button from '../../../../../common/components/buttons/Button';\nimport useRundown from '../../../../../common/hooks-query/useRundown';\nimport * as Panel from '../../../panel-utils/PanelUtils';\n\nimport PreviewSpreadsheet from './preview/PreviewRundown';\nimport useGoogleSheet from './useGoogleSheet';\nimport { useSheetStore } from './useSheetStore';\n\ninterface ImportReviewProps {\n rundown: Rundown;\n customFields: CustomFields;\n onFinished: () => void;\n onCancel: () => void;\n}\n\nexport default function ImportReview(props: ImportReviewProps) {\n const { rundown, customFields, onFinished, onCancel } = props;\n const { data: currentRundown } = useRundown();\n const [loading, setLoading] = useState(false);\n const { importRundown } = useGoogleSheet();\n const resetPreview = useSheetStore((state) => state.resetPreview);\n\n const handleCancel = () => {\n resetPreview();\n onCancel();\n };\n\n const applyImport = async () => {\n setLoading(true);\n\n // we need to import on-top of the currently loaded rundown\n // so the id needs to match\n await importRundown(\n {\n [currentRundown.id]: { ...rundown, id: currentRundown.id, title: currentRundown.title },\n },\n customFields,\n );\n setLoading(false);\n onFinished();\n };\n\n return (\n <Panel.Section>\n <Panel.Title>\n Review Rundown\n <Panel.InlineElements>\n <Button onClick={handleCancel} variant='ghosted' disabled={loading}>\n Cancel\n </Button>\n <Button onClick={applyImport} variant='primary' loading={loading}>\n Apply\n </Button>\n </Panel.InlineElements>\n </Panel.Title>\n <PreviewSpreadsheet rundown={rundown} customFields={customFields} />\n </Panel.Section>\n );\n}\n","import { ChangeEvent, useRef, useState } from 'react';\nimport { IoCloudOutline, IoDownloadOutline } from 'react-icons/io5';\nimport { getErrorMessage, ImportMap } from 'ontime-utils';\n\nimport {\n getWorksheetNames as getWorksheetNamesExcel,\n importRundownPreview as importRundownPreviewExcel,\n upload as uploadExcel,\n} from '../../../../../common/api/excel';\nimport { getWorksheetNames } from '../../../../../common/api/sheets';\nimport { maybeAxiosError } from '../../../../../common/api/utils';\nimport Button from '../../../../../common/components/buttons/Button';\nimport * as Editor from '../../../../../common/components/editor-utils/EditorUtils';\nimport { validateExcelImport } from '../../../../../common/utils/uploadUtils';\nimport * as Panel from '../../../panel-utils/PanelUtils';\n\nimport ImportMapForm from './import-map/ImportMapForm';\nimport GSheetInfo from './GSheetInfo';\nimport GSheetSetup from './GSheetSetup';\nimport ImportReview from './ImportReview';\nimport useGoogleSheet from './useGoogleSheet';\nimport { useSheetStore } from './useSheetStore';\n\nimport style from './SourcesPanel.module.scss';\n\nexport default function SourcesPanel() {\n const [importFlow, setImportFlow] = useState<'none' | 'excel' | 'gsheet' | 'finished'>('none');\n const [error, setError] = useState('');\n const [hasFile, setHasFile] = useState<'none' | 'loading' | 'done'>('none');\n\n const { exportRundown, importRundownPreview, verifyAuth } = useGoogleSheet();\n\n const setWorksheets = useSheetStore((state) => state.setWorksheets);\n const authenticationStatus = useSheetStore((state) => state.authenticationStatus);\n const setAuthenticationStatus = useSheetStore((state) => state.setAuthenticationStatus);\n const rundown = useSheetStore((state) => state.rundown);\n const setRundown = useSheetStore((state) => state.setRundown);\n const customFields = useSheetStore((state) => state.customFields);\n const setCustomFields = useSheetStore((state) => state.setCustomFields);\n const setSheetId = useSheetStore((state) => state.setSheetId);\n const sheetId = useSheetStore((state) => state.sheetId);\n\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const handleFile = async (event: ChangeEvent<HTMLInputElement>) => {\n const fileToUpload = event.target.files?.[0];\n\n if (!fileToUpload) {\n setWorksheets(null);\n setHasFile('none');\n return;\n }\n try {\n setHasFile('loading');\n validateExcelImport(fileToUpload);\n await uploadExcel(fileToUpload);\n const names = await getWorksheetNamesExcel();\n setWorksheets(names);\n setImportFlow('excel');\n setHasFile('done');\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n setError(`Error uploading file: ${errorMessage}`);\n setWorksheets(null);\n setHasFile('none');\n }\n };\n\n const handleUpload = () => {\n fileInputRef.current?.click();\n };\n\n const resetFlow = () => {\n // we purposely omit clearing the authentication status\n setImportFlow('none');\n setRundown(null);\n setHasFile('none');\n setWorksheets(null);\n setCustomFields(null);\n setError('');\n setSheetId(null);\n };\n\n const openGSheetFlow = async () => {\n const result = await verifyAuth();\n if (result) {\n setAuthenticationStatus(result.authenticated);\n setSheetId(result.sheetId);\n if (result.authenticated === 'authenticated' && result.sheetId) {\n try {\n const names = await getWorksheetNames(result.sheetId);\n setWorksheets(names);\n } catch (error) {\n const message = maybeAxiosError(error);\n setError(`Error getting worksheets: ${message}`);\n }\n }\n }\n setImportFlow('gsheet');\n };\n\n const cancelGSheetFlow = () => {\n resetFlow();\n };\n\n const handleSubmitImportPreview = async (importMap: ImportMap) => {\n setError(''); // to clear previous error\n if (importFlow === 'excel') {\n try {\n const previewData = await importRundownPreviewExcel(importMap);\n setRundown(previewData.rundown);\n setCustomFields(previewData.customFields);\n } catch (error) {\n setError(maybeAxiosError(error));\n }\n }\n\n if (importFlow === 'gsheet') {\n if (!sheetId) return;\n await importRundownPreview(sheetId, importMap);\n }\n };\n\n const cancelImportMap = async () => {\n resetFlow();\n if (authenticationStatus === 'authenticated') {\n const result = await verifyAuth();\n if (result) {\n setAuthenticationStatus(result.authenticated);\n }\n }\n };\n\n const handleFinished = () => {\n setImportFlow('finished');\n setRundown(null);\n setHasFile('none');\n setWorksheets(null);\n setCustomFields(null);\n setError('');\n };\n\n const handleSubmitExport = async (importMap: ImportMap) => {\n if (!sheetId) return;\n await exportRundown(sheetId, importMap);\n };\n\n const isExcelFlow = importFlow === 'excel';\n const isGSheetFlow = importFlow === 'gsheet';\n const isAuthenticated = authenticationStatus === 'authenticated';\n const showInput = importFlow === 'none';\n const showCompleted = importFlow === 'finished';\n const showAuth = isGSheetFlow && !isAuthenticated;\n const showImportMap = (isGSheetFlow && isAuthenticated) || (isExcelFlow && hasFile === 'done');\n const showReview = rundown !== null && customFields !== null;\n\n return (\n <Panel.Section>\n <Panel.Card>\n <Panel.SubHeader>Synchronise your rundown with an external source</Panel.SubHeader>\n {error && <Panel.Error>{error}</Panel.Error>}\n {showInput && (\n <>\n <GSheetInfo />\n <input\n ref={fileInputRef}\n style={{ display: 'none' }}\n type='file'\n onChange={handleFile}\n accept='.xlsx'\n data-testid='file-input'\n />\n <div className={style.uploadSection}>\n <div>\n <Button variant='primary' onClick={handleUpload} loading={hasFile === 'loading'}>\n <IoDownloadOutline />\n Import from spreadsheet\n </Button>\n <Panel.Description>Accepts .xlsx files</Panel.Description>\n </div>\n <Editor.Separator orientation='vertical' />\n <div>\n <Button variant='primary' onClick={openGSheetFlow} disabled={hasFile !== 'none'}>\n <IoCloudOutline />\n Synchronise with Google\n </Button>\n <Panel.Description>Start authentication process</Panel.Description>\n </div>\n </div>\n </>\n )}\n {showCompleted && (\n <div className={style.finishSection}>\n {error ? (\n <span key='finish__error' className={style.error}>\n Import failed\n </span>\n ) : (\n <span key='finish__success' className={style.success}>\n Import successful\n </span>\n )}\n <Button variant='primary' onClick={resetFlow}>\n Return\n </Button>\n </div>\n )}\n {showAuth && <GSheetSetup onCancel={cancelGSheetFlow} />}\n {showImportMap && !showReview && (\n <ImportMapForm\n hasErrors={Boolean(error)}\n isSpreadsheet={isExcelFlow}\n onCancel={cancelImportMap}\n onSubmitExport={handleSubmitExport}\n onSubmitImport={handleSubmitImportPreview}\n />\n )}\n {showReview && (\n <ImportReview\n rundown={rundown}\n customFields={customFields}\n onFinished={handleFinished}\n onCancel={cancelImportMap}\n />\n )}\n </Panel.Card>\n </Panel.Section>\n );\n}\n","import { useEffect, useState } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { CustomField } from 'ontime-types';\nimport { checkRegex, customFieldLabelToKey } from 'ontime-utils';\n\nimport { maybeAxiosError } from '../../../../../common/api/utils';\nimport Button from '../../../../../common/components/buttons/Button';\nimport Info from '../../../../../common/components/info/Info';\nimport SwatchSelect from '../../../../../common/components/input/colour-input/SwatchSelect';\nimport Input from '../../../../../common/components/input/input/Input';\nimport RadioGroup from '../../../../../common/components/radio-group/RadioGroup';\nimport useCustomFields from '../../../../../common/hooks-query/useCustomFields';\nimport { preventEscape } from '../../../../../common/utils/keyEvent';\nimport * as Panel from '../../../panel-utils/PanelUtils';\n\nimport style from '../ManagePanel.module.scss';\n\ninterface CustomFieldsFormProps {\n onSubmit: (field: CustomField) => Promise<void>;\n onCancel: () => void;\n initialColour?: string;\n initialLabel?: string;\n initialKey?: string;\n}\n\ntype CustomFieldFormData = CustomField & { key: string };\n\nexport default function CustomFieldForm({\n onSubmit,\n onCancel,\n initialColour,\n initialLabel,\n initialKey,\n}: CustomFieldsFormProps) {\n const { data } = useCustomFields();\n\n // we use this to force an update\n const [_, setColour] = useState(initialColour || '');\n\n const {\n handleSubmit,\n register,\n setFocus,\n setError,\n setValue,\n getValues,\n watch,\n formState: { errors, isSubmitting, isValid, isDirty },\n } = useForm<CustomFieldFormData>({\n defaultValues: { type: 'text', label: initialLabel || '', colour: initialColour || '' },\n resetOptions: {\n keepDirtyValues: true,\n },\n });\n\n const setupSubmit = async (values: CustomFieldFormData) => {\n const { type, label, colour } = values;\n const newField: CustomField = {\n type,\n colour,\n label,\n };\n try {\n await onSubmit(newField);\n } catch (error) {\n setError('root', { type: 'custom', message: maybeAxiosError(error) });\n }\n };\n\n // give initial focus to the label\n useEffect(() => {\n setFocus('label');\n }, [setFocus]);\n\n const handleSelectColour = (colour: string) => {\n setColour(colour);\n setValue('colour', colour, { shouldDirty: true });\n };\n\n const colour = getValues('colour');\n const canSubmit = isDirty && isValid;\n // if initial values are given, we can assume we are in edit mode\n const isEditMode = initialKey !== undefined;\n\n return (\n <Panel.Indent as='form' onSubmit={handleSubmit(setupSubmit)} onKeyDown={(event) => preventEscape(event, onCancel)}>\n <Info>\n Please note that images can quickly deteriorate your app's performance.\n <br />\n Prefer using small, and compressed images.\n </Info>\n <div>\n <Panel.Description>Type</Panel.Description>\n <RadioGroup\n orientation='horizontal'\n disabled={isEditMode}\n onValueChange={(value) => setValue('type', value, { shouldDirty: true })}\n value={watch('type')}\n items={[\n { value: 'text', label: 'Text' },\n { value: 'image', label: 'Image' },\n ]}\n />\n </div>\n <div className={style.twoCols}>\n <label>\n <Panel.Description>Label (only alphanumeric characters are allowed)</Panel.Description>\n {errors.label && <Panel.Error>{errors.label.message}</Panel.Error>}\n <Input\n {...register('label', {\n required: { value: true, message: 'Required field' },\n onChange: () => setValue('key', customFieldLabelToKey(getValues('label')) ?? 'N/A'),\n validate: (value) => {\n if (value.trim().length === 0) return 'Required field';\n if (!checkRegex.isAlphanumericWithSpace(value))\n return 'Only alphanumeric characters and space are allowed';\n if (!isEditMode) {\n if (isEditMode && Object.keys(data).includes(value)) return 'Custom fields must be unique';\n }\n return true;\n },\n })}\n fluid\n />\n </label>\n\n <label>\n <Panel.Description>Key (use in Integrations and API)</Panel.Description>\n <Input {...register('key')} variant='ghosted' readOnly fluid />\n </label>\n </div>\n <label>\n <Panel.Description>Colour</Panel.Description>\n <SwatchSelect name='colour' value={colour} handleChange={(_field, value) => handleSelectColour(value)} />\n </label>\n {errors.root && <Panel.Error>{errors.root.message}</Panel.Error>}\n <Panel.InlineElements relation='inner' align='end'>\n <Button variant='ghosted' onClick={onCancel}>\n Cancel\n </Button>\n <Button type='submit' variant='primary' disabled={!canSubmit} loading={isSubmitting}>\n Save\n </Button>\n </Panel.InlineElements>\n </Panel.Indent>\n );\n}\n","import { useState } from 'react';\nimport { IoPencil, IoTrash } from 'react-icons/io5';\nimport { CustomField, CustomFieldKey } from 'ontime-types';\n\nimport IconButton from '../../../../../common/components/buttons/IconButton';\nimport CopyTag from '../../../../../common/components/copy-tag/CopyTag';\nimport Swatch from '../../../../../common/components/input/colour-input/Swatch';\nimport Tag from '../../../../../common/components/tag/Tag';\nimport * as Panel from '../../../panel-utils/PanelUtils';\n\nimport CustomFieldForm from './CustomFieldForm';\n\nimport style from '../ManagePanel.module.scss';\n\ninterface CustomFieldEntryProps {\n colour: string;\n label: string;\n fieldKey: string;\n type: CustomField['type'];\n onEdit: (key: CustomFieldKey, patch: CustomField) => Promise<void>;\n onDelete: (key: CustomFieldKey) => Promise<void>;\n}\n\nexport default function CustomFieldEntry(props: CustomFieldEntryProps) {\n const { colour, label, fieldKey, type, onEdit, onDelete } = props;\n const [isEditing, setIsEditing] = useState(false);\n\n const handleEdit = async (patch: CustomField) => {\n await onEdit(fieldKey, patch);\n setIsEditing(false);\n };\n\n if (isEditing) {\n return (\n <tr>\n <td colSpan={99}>\n <CustomFieldForm\n onCancel={() => setIsEditing(false)}\n onSubmit={handleEdit}\n initialColour={colour}\n initialLabel={label}\n initialKey={fieldKey}\n />\n </td>\n </tr>\n );\n }\n\n return (\n <tr>\n <td>\n <Swatch color={colour} />\n </td>\n <td>\n <Tag>{type}</Tag>\n </td>\n <td className={style.halfWidth}>{label}</td>\n <td className={style.fullWidth}>\n <CopyTag size='small' copyValue={fieldKey}>\n {fieldKey}\n </CopyTag>\n </td>\n <Panel.InlineElements relation='inner' as='td'>\n <IconButton variant='ghosted-white' aria-label='Edit entry' onClick={() => setIsEditing(true)}>\n <IoPencil />\n </IconButton>\n <IconButton variant='ghosted-destructive' aria-label='Delete entry' onClick={() => onDelete(fieldKey)}>\n <IoTrash />\n </IconButton>\n </Panel.InlineElements>\n </tr>\n );\n}\n","import { useState } from 'react';\nimport { IoAdd } from 'react-icons/io5';\nimport { CustomField, CustomFieldKey } from 'ontime-types';\n\nimport { deleteCustomField, editCustomField, postCustomField } from '../../../../common/api/customFields';\nimport Button from '../../../../common/components/buttons/Button';\nimport Info from '../../../../common/components/info/Info';\nimport AppLink from '../../../../common/components/link/app-link/AppLink';\nimport ExternalLink from '../../../../common/components/link/external-link/ExternalLink';\nimport useCustomFields from '../../../../common/hooks-query/useCustomFields';\nimport { customFieldsDocsUrl } from '../../../../externals';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport CustomFieldEntry from './composite/CustomFieldEntry';\nimport CustomFieldForm from './composite/CustomFieldForm';\n\nexport default function CustomFieldSettings() {\n const { data, refetch } = useCustomFields();\n const [isAdding, setIsAdding] = useState(false);\n\n const handleInitiateCreate = () => {\n setIsAdding(true);\n };\n\n const handleCancel = () => {\n setIsAdding(false);\n };\n\n const handleCreate = async (customField: CustomField) => {\n await postCustomField(customField);\n refetch();\n setIsAdding(false);\n };\n\n const handleEditField = async (key: CustomFieldKey, customField: CustomField) => {\n await editCustomField(key, customField);\n refetch();\n };\n\n const handleDelete = async (key: CustomFieldKey) => {\n try {\n await deleteCustomField(key);\n refetch();\n } catch (_error) {\n /** we do not handle errors here */\n }\n };\n\n return (\n <Panel.Section>\n <Panel.Card>\n <Panel.SubHeader>\n Custom fields\n <Button onClick={handleInitiateCreate}>\n New <IoAdd />\n </Button>\n </Panel.SubHeader>\n <Panel.Divider />\n <Panel.Section>\n <Info>\n Custom fields allow for additional information to be added to an event.\n <br />\n <br />\n To use custom fields as a data source in an{' '}\n <AppLink search='settings=automation__automations'>Automation</AppLink>, please note the generated key.\n <ExternalLink href={customFieldsDocsUrl}>See the docs</ExternalLink>\n </Info>\n </Panel.Section>\n <Panel.Section>\n {isAdding && <CustomFieldForm onSubmit={handleCreate} onCancel={handleCancel} />}\n <Panel.Table>\n <thead>\n <tr>\n <th>Colour</th>\n <th>Type</th>\n <th>Name</th>\n <th>Key (used in Automations)</th>\n <th />\n </tr>\n </thead>\n <tbody>\n {Object.entries(data).map(([key, { colour, label, type }]) => {\n return (\n <CustomFieldEntry\n key={key}\n fieldKey={key}\n colour={colour}\n label={label}\n type={type}\n onEdit={handleEditField}\n onDelete={handleDelete}\n />\n );\n })}\n </tbody>\n </Panel.Table>\n </Panel.Section>\n </Panel.Card>\n </Panel.Section>\n );\n}\n","import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { ProjectRundownsList } from 'ontime-types';\n\nimport { queryRefetchIntervalSlow } from '../../ontimeConfig';\nimport { PROJECT_RUNDOWNS } from '../api/constants';\nimport { createRundown, deleteRundown, fetchProjectRundownList, loadRundown } from '../api/rundown';\n\n/**\n * Project rundowns\n */\nexport function useProjectRundowns() {\n const { data, status, isError, refetch, isFetching } = useQuery<ProjectRundownsList>({\n queryKey: PROJECT_RUNDOWNS,\n queryFn: fetchProjectRundownList,\n placeholderData: (previousData, _previousQuery) => previousData,\n refetchInterval: queryRefetchIntervalSlow,\n });\n return { data: data ?? { loaded: '', rundowns: [] }, status, isError, refetch, isFetching };\n}\n\nexport function useMutateProjectRundowns() {\n const ontimeQueryClient = useQueryClient();\n\n const { mutateAsync: create } = useMutation({\n mutationFn: createRundown,\n onMutate: () => {\n ontimeQueryClient.cancelQueries({ queryKey: PROJECT_RUNDOWNS });\n },\n onSuccess: (response) => {\n ontimeQueryClient.setQueryData(PROJECT_RUNDOWNS, response.data);\n },\n });\n\n const { mutateAsync: remove } = useMutation({\n mutationFn: deleteRundown,\n onMutate: () => {\n ontimeQueryClient.cancelQueries({ queryKey: PROJECT_RUNDOWNS });\n },\n onSuccess: (response) => {\n ontimeQueryClient.setQueryData(PROJECT_RUNDOWNS, response.data);\n },\n });\n\n const { mutateAsync: load } = useMutation({\n mutationFn: loadRundown,\n onMutate: () => {\n ontimeQueryClient.cancelQueries({ queryKey: PROJECT_RUNDOWNS });\n },\n onSuccess: (response) => {\n ontimeQueryClient.setQueryData(PROJECT_RUNDOWNS, response.data);\n },\n });\n\n return { create, remove, load };\n}\n","import { useEffect } from 'react';\nimport { useForm } from 'react-hook-form';\n\nimport Button from '../../../../common/components/buttons/Button';\nimport Input from '../../../../common/components/input/input/Input';\nimport { useMutateProjectRundowns } from '../../../../common/hooks-query/useProjectRundowns';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\ntype NewRundownFormState = {\n title: string;\n};\n\ninterface ManageRundownForm {\n onClose: () => void;\n}\n\nexport function ManageRundownForm({ onClose }: ManageRundownForm) {\n const { create } = useMutateProjectRundowns();\n\n const {\n handleSubmit,\n register,\n setFocus,\n setError,\n formState: { errors, isSubmitting },\n } = useForm<NewRundownFormState>({\n defaultValues: { title: '' },\n });\n\n const createRundown = async (values: NewRundownFormState) => {\n try {\n await create(values.title || 'untitled');\n onClose();\n } catch (error) {\n setError('root', { message: `Failed to create rundown. ${error}` });\n }\n };\n\n // give initial focus to the title field\n useEffect(() => {\n setFocus('title');\n }, [setFocus]);\n\n return (\n <Panel.Indent as='form' onSubmit={handleSubmit(createRundown)}>\n <Panel.Section>\n <label>\n <Panel.Description>Rundown title</Panel.Description>\n <Input {...register('title')} fluid placeholder='Your rundown name' />\n </label>\n </Panel.Section>\n <Panel.InlineElements relation='inner' align='end'>\n <Button variant='ghosted' disabled={isSubmitting} onClick={onClose}>\n Cancel\n </Button>\n <Button type='submit' variant='primary' disabled={isSubmitting}>\n Create rundown\n </Button>\n </Panel.InlineElements>\n {errors.root && <Panel.Error>{errors.root.message}</Panel.Error>}\n </Panel.Indent>\n );\n}\n","import { useState } from 'react';\nimport { IoAdd, IoDocumentOutline, IoDownloadOutline, IoEllipsisHorizontal, IoTrash } from 'react-icons/io5';\nimport { useDisclosure } from '@mantine/hooks';\n\nimport { downloadAsExcel } from '../../../../common/api/excel';\nimport { maybeAxiosError } from '../../../../common/api/utils';\nimport Button from '../../../../common/components/buttons/Button';\nimport IconButton from '../../../../common/components/buttons/IconButton';\nimport Dialog from '../../../../common/components/dialog/Dialog';\nimport { DropdownMenu } from '../../../../common/components/dropdown-menu/DropdownMenu';\nimport Tag from '../../../../common/components/tag/Tag';\nimport { useMutateProjectRundowns, useProjectRundowns } from '../../../../common/hooks-query/useProjectRundowns';\nimport { cx } from '../../../../common/utils/styleUtils';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport { ManageRundownForm } from './ManageRundownForm';\n\nimport style from './ManagePanel.module.scss';\n\nexport default function ManageRundowns() {\n const { data } = useProjectRundowns();\n const { remove, load } = useMutateProjectRundowns();\n const [isOpenDelete, deleteHandlers] = useDisclosure();\n const [isOpenLoad, loadHandlers] = useDisclosure();\n const [isNewLoad, newHandlers] = useDisclosure();\n const [targetRundown, setTargetRundown] = useState('');\n const [actionError, setActionError] = useState<string | null>(null);\n\n const openLoad = (id: string) => {\n setActionError(null);\n setTargetRundown(id);\n loadHandlers.open();\n };\n\n const openDelete = (id: string) => {\n setActionError(null);\n setTargetRundown(id);\n deleteHandlers.open();\n };\n\n const submitRundownLoad = async () => {\n try {\n await load(targetRundown);\n } catch (error) {\n setActionError(`Failed to load rundown. ${maybeAxiosError(error)}`);\n } finally {\n loadHandlers.close();\n }\n };\n\n const submitRundownDelete = async () => {\n try {\n await remove(targetRundown);\n } catch (error) {\n setActionError(`Failed to delete rundown. ${maybeAxiosError(error)}`);\n } finally {\n deleteHandlers.close();\n }\n };\n\n const handleDownloadXlsx = async (rundownId: string, title: string) => {\n await downloadAsExcel(rundownId, title);\n };\n\n return (\n <>\n <Panel.Section>\n <Panel.Card>\n <Panel.SubHeader>\n Manage project rundowns\n <Panel.InlineElements>\n <Button\n onClick={() => {\n setActionError(null);\n newHandlers.open();\n }}\n >\n New <IoAdd />\n </Button>\n </Panel.InlineElements>\n </Panel.SubHeader>\n <Panel.Divider />\n <Panel.Section>\n {isNewLoad && <ManageRundownForm onClose={newHandlers.close} />}\n {actionError && <Panel.Error>{actionError}</Panel.Error>}\n <Panel.Table>\n <thead>\n <tr>\n <th># Entries</th>\n <th style={{ width: '100%' }}>Title</th>\n <th />\n </tr>\n </thead>\n <tbody>\n {data?.rundowns?.map(({ id, numEntries, title }) => {\n const isLoaded = data.loaded === id;\n return (\n <tr key={id} className={cx([isLoaded && style.current])}>\n <td>{numEntries}</td>\n <td>\n {title} {isLoaded && <Tag>Loaded</Tag>}\n </td>\n <td>\n <DropdownMenu\n render={<IconButton variant='ghosted-white' />}\n items={[\n {\n type: 'item',\n icon: IoDownloadOutline,\n label: 'Load',\n onClick: () => openLoad(id),\n disabled: isLoaded,\n },\n {\n type: 'item',\n icon: IoDocumentOutline,\n label: 'Download .xlsx',\n onClick: () => handleDownloadXlsx(id, title),\n },\n {\n type: 'item',\n icon: IoTrash,\n label: 'Delete',\n onClick: () => openDelete(id),\n disabled: isLoaded,\n },\n ]}\n >\n <IoEllipsisHorizontal />\n </DropdownMenu>\n </td>\n </tr>\n );\n })}\n </tbody>\n </Panel.Table>\n </Panel.Section>\n </Panel.Card>\n </Panel.Section>\n <Dialog\n isOpen={isOpenDelete}\n onClose={deleteHandlers.close}\n title='Load rundown'\n showBackdrop\n showCloseButton\n bodyElements={\n <>\n You will lose all data in your rundown. <br /> Are you sure?\n </>\n }\n footerElements={\n <>\n <Button size='large' onClick={deleteHandlers.close}>\n Cancel\n </Button>\n <Button variant='destructive' size='large' onClick={submitRundownDelete}>\n Delete rundown\n </Button>\n </>\n }\n />\n <Dialog\n isOpen={isOpenLoad}\n onClose={loadHandlers.close}\n title='Load rundown'\n showBackdrop\n showCloseButton\n bodyElements={\n <>\n The current playback will be stopped. <br /> Are you sure?\n </>\n }\n footerElements={\n <>\n <Button size='large' onClick={loadHandlers.close}>\n Cancel\n </Button>\n <Button variant='primary' size='large' onClick={submitRundownLoad}>\n Load rundown\n </Button>\n </>\n }\n />\n </>\n );\n}\n","import { EndAction, TimerType, TimeStrategy } from 'ontime-types';\nimport { parseUserTime } from 'ontime-utils';\n\nimport TimeInput from '../../../../common/components/input/time-input/TimeInput';\nimport Select from '../../../../common/components/select/Select';\nimport Switch from '../../../../common/components/switch/Switch';\nimport { editorSettingsDefaults, useEditorSettings } from '../../../../common/stores/editorSettings';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nexport default function RundownDefaultSettings() {\n const {\n defaultDuration,\n linkPrevious,\n defaultTimeStrategy,\n defaultWarnTime,\n defaultDangerTime,\n defaultTimerType,\n defaultEndAction,\n setDefaultDuration,\n setLinkPrevious,\n setTimeStrategy,\n setWarnTime,\n setDangerTime,\n setDefaultTimerType,\n setDefaultEndAction,\n } = useEditorSettings((state) => state);\n\n const durationInMs = parseUserTime(defaultDuration);\n const warnTimeInMs = parseUserTime(defaultWarnTime);\n const dangerTimeInMs = parseUserTime(defaultDangerTime);\n\n return (\n <Panel.Section>\n <Panel.Card>\n <Panel.SubHeader>Rundown defaults</Panel.SubHeader>\n <Panel.Divider />\n <Panel.Section>\n <Panel.Title>Default settings for new events</Panel.Title>\n <Panel.ListGroup>\n <Panel.ListItem>\n <Panel.Field\n title='Link previous'\n description='Whether the start time of new events should be linked to the previous event end time'\n />\n <Switch size='large' checked={linkPrevious} onCheckedChange={setLinkPrevious} />\n </Panel.ListItem>\n <Panel.ListItem>\n <Panel.Field\n title='Timer strategy'\n description='Which time should be maintained when event schedule is recalculated'\n />\n <Select\n value={defaultTimeStrategy}\n onValueChange={(value) => setTimeStrategy(value as TimeStrategy)}\n options={[\n { value: TimeStrategy.LockDuration, label: 'Duration' },\n { value: TimeStrategy.LockEnd, label: 'End Time' },\n ]}\n />\n </Panel.ListItem>\n </Panel.ListGroup>\n <Panel.ListGroup>\n <Panel.ListItem>\n <Panel.Field title='Default duration' description='Default duration for new events' />\n <TimeInput<'defaultDuration'>\n name='defaultDuration'\n submitHandler={(_field, value) => setDefaultDuration(value)}\n time={durationInMs}\n placeholder={editorSettingsDefaults.duration}\n />\n </Panel.ListItem>\n <Panel.ListItem>\n <Panel.Field title='Timer type' description='Default type of timer for new events' />\n <Select\n value={defaultTimerType}\n onValueChange={(value) => setDefaultTimerType(value as TimerType)}\n options={[\n { value: TimerType.CountDown, label: 'Count down' },\n { value: TimerType.CountUp, label: 'Count up' },\n { value: TimerType.Clock, label: 'Clock' },\n { value: TimerType.None, label: 'None' },\n ]}\n />\n </Panel.ListItem>\n <Panel.ListItem>\n <Panel.Field title='End Action' description='Default end action for new events' />\n <Select\n value={defaultEndAction}\n onValueChange={(value) => setDefaultEndAction(value as EndAction)}\n options={[\n { value: EndAction.None, label: 'None' },\n { value: EndAction.LoadNext, label: 'Load next' },\n { value: EndAction.PlayNext, label: 'Play next' },\n ]}\n />\n </Panel.ListItem>\n </Panel.ListGroup>\n <Panel.ListGroup>\n <Panel.ListItem>\n <Panel.Field title='Warning time' description='Default threshold for warning time in an event' />\n <TimeInput<'warnTime'>\n name='warnTime'\n submitHandler={(_field, value) => setWarnTime(value)}\n time={warnTimeInMs}\n placeholder={editorSettingsDefaults.warnTime}\n />\n </Panel.ListItem>\n <Panel.ListItem>\n <Panel.Field title='Danger time' description='Default threshold for danger time in an event' />\n <TimeInput<'dangerTime'>\n name='dangerTime'\n submitHandler={(_field, value) => setDangerTime(value)}\n time={dangerTimeInMs}\n placeholder={editorSettingsDefaults.dangerTime}\n />\n </Panel.ListItem>\n </Panel.ListGroup>\n </Panel.Section>\n </Panel.Card>\n </Panel.Section>\n );\n}\n","import useScrollIntoView from '../../../../common/hooks/useScrollIntoView';\nimport type { PanelBaseProps } from '../../panel-list/PanelList';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport SourcesPanel from './sources-panel/SourcesPanel';\nimport CustomFieldSettings from './CustomFields';\nimport ManageRundowns from './ManageRundowns';\nimport RundownDefaultSettings from './RundownDefaultSettings';\n\nexport default function ManagePanel({ location }: PanelBaseProps) {\n const defaultsRef = useScrollIntoView<HTMLDivElement>('defaults', location);\n const customRef = useScrollIntoView<HTMLDivElement>('custom', location);\n const rundownsRef = useScrollIntoView<HTMLDivElement>('rundowns', location);\n const sheetsRef = useScrollIntoView<HTMLDivElement>('sheets', location);\n\n return (\n <>\n <Panel.Header>Project data</Panel.Header>\n <div ref={defaultsRef}>\n <RundownDefaultSettings />\n </div>\n <div ref={customRef}>\n <CustomFieldSettings />\n </div>\n <div ref={rundownsRef}>\n <ManageRundowns />\n </div>\n <div ref={sheetsRef}>\n <SourcesPanel />\n </div>\n </>\n );\n}\n","import { useState } from 'react';\nimport { IoArrowForward } from 'react-icons/io5';\n\nimport { navigatorConstants } from '../../../viewerConfig';\nimport { setClientRemote } from '../../hooks/useSocket';\nimport useUrlPresets from '../../hooks-query/useUrlPresets';\nimport Button from '../buttons/Button';\nimport Info from '../info/Info';\nimport Input from '../input/input/Input';\nimport AppLink from '../link/app-link/AppLink';\nimport Modal from '../modal/Modal';\nimport Select from '../select/Select';\n\nimport style from './RedirectClientModal.module.scss';\n\ninterface RedirectClientModalProps {\n id: string;\n name: string;\n currentPath: string;\n origin: string;\n isOpen: boolean;\n onClose: () => void;\n}\n\nexport function RedirectClientModal({ id, isOpen, name, currentPath, origin, onClose }: RedirectClientModalProps) {\n const { data } = useUrlPresets();\n const [path, setPath] = useState(currentPath);\n const [selected, setSelected] = useState('/');\n\n const { setRedirect } = setClientRemote;\n\n const handleRedirect = (newPath: string) => {\n if (newPath === '/' || newPath === currentPath) {\n return;\n }\n\n if (newPath.startsWith('preset-')) {\n setRedirect({ target: id, redirect: newPath.slice(7) });\n } else {\n setRedirect({ target: id, redirect: newPath });\n }\n\n onClose();\n };\n\n const enabledPresets = data.filter((preset) => preset.enabled);\n\n const viewOptions = [\n ...navigatorConstants.map((view) => ({\n value: `/${view.url}`,\n label: view.label,\n })),\n ...enabledPresets.map((preset) => ({\n value: `preset-${preset.alias}`,\n label: `URL Preset: ${preset.alias}`,\n })),\n ];\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n showCloseButton\n showBackdrop\n title={`Redirect: ${name}`}\n bodyElements={\n <>\n <Info>\n Remotely redirect the client to a different URL. <br />\n Either by entering a custom path or selecting a URL Preset.\n <br />\n <br />\n <AppLink search='settings=sharing__presets'>Manage URL Presets</AppLink>\n </Info>\n <div className={style.inlineEntry}>\n <span className={style.label}>Enter custom path</span>\n <label className={style.textEntry}>\n {origin}\n <Input placeholder='eg. /timer' fluid value={path} onChange={(event) => setPath(event.target.value)} />\n </label>\n <Button\n variant='primary'\n aria-label='Redirect'\n disabled={path === currentPath || path === ''}\n className={style.redirect}\n onClick={() => handleRedirect(path)}\n >\n Redirect\n <IoArrowForward />\n </Button>\n </div>\n <div>\n <span className={style.label}>Select View or URL Preset</span>\n <div className={style.inlineEntry}>\n <label className={style.textEntry}>\n {origin}\n <Select\n fluid\n options={viewOptions}\n defaultValue={viewOptions[0].value}\n onValueChange={(value) => setSelected(value)}\n disabled={enabledPresets.length === 0}\n />\n </label>\n <Button\n variant='primary'\n aria-label='Redirect to preset'\n className={style.redirect}\n disabled={enabledPresets.length === 0 || selected === '/'}\n onClick={() => handleRedirect(selected)}\n >\n Redirect <IoArrowForward />\n </Button>\n </div>\n </div>\n </>\n }\n />\n );\n}\n","import { useState } from 'react';\nimport { useDisclosure } from '@mantine/hooks';\nimport { Client } from 'ontime-types';\n\nimport Button from '../../../../../common/components/buttons/Button';\nimport { RedirectClientModal } from '../../../../../common/components/client-modal/RedirectClientModal';\nimport { RenameClientModal } from '../../../../../common/components/client-modal/RenameClientModal';\nimport Tag from '../../../../../common/components/tag/Tag';\nimport { setClientRemote } from '../../../../../common/hooks/useSocket';\nimport { useClientStore } from '../../../../../common/stores/clientStore';\nimport { cx } from '../../../../../common/utils/styleUtils';\nimport * as Panel from '../../../panel-utils/PanelUtils';\n\nimport style from './ClientControlPanel.module.scss';\n\nexport default function ClientList() {\n const id = useClientStore((store) => store.id);\n const clients = useClientStore((store) => store.clients);\n const [isOpenRedirect, redirectHandler] = useDisclosure();\n const [isOpenRename, renameHandler] = useDisclosure();\n const { setIdentify } = setClientRemote;\n\n const [targetId, setTargetId] = useState('');\n\n const openRename = (targetId: string) => {\n setTargetId(targetId);\n renameHandler.open();\n };\n\n const openRedirect = (targetId: string) => {\n setTargetId(targetId);\n redirectHandler.open();\n };\n\n const ontimeClients = Object.entries(clients).filter(([_, { type }]) => type === 'ontime');\n const otherClients = Object.entries(clients).filter(([_, { type }]) => type !== 'ontime');\n\n const targetClient: Client | undefined = clients[targetId];\n\n return (\n <>\n {isOpenRedirect && targetClient !== undefined && (\n <RedirectClientModal\n id={targetId}\n name={targetClient.name}\n origin={targetClient.origin}\n currentPath={targetClient.path}\n isOpen={isOpenRedirect}\n onClose={redirectHandler.close}\n />\n )}\n {isOpenRename && (\n <RenameClientModal\n id={targetId}\n name={targetClient?.name}\n isOpen={isOpenRename}\n onClose={renameHandler.close}\n />\n )}\n <Panel.Section>\n <Panel.Title>Ontime Clients ({ontimeClients.length})</Panel.Title>\n <Panel.Table>\n <thead>\n <tr>\n <td style={{ width: '20%' }}>Client Name</td>\n <td>Path</td>\n <td />\n </tr>\n </thead>\n <tbody>\n {ontimeClients.map(([key, client]) => {\n const { identify, name, path } = client;\n const isCurrent = id === key;\n return (\n <tr key={key} className={cx([isCurrent && style.self])}>\n <Panel.InlineElements relation='inner' as='td'>\n {isCurrent && <Tag>SELF</Tag>}\n {name}\n </Panel.InlineElements>\n <td className={style.copiable}>{path}</td>\n <Panel.InlineElements relation='inner' as='td'>\n <Button\n size='small'\n className={`${identify ? style.blink : ''}`}\n disabled={isCurrent}\n variant={identify ? 'primary' : 'subtle'}\n data-testid={isCurrent ? '' : 'not-self-identify'}\n onClick={() => {\n setIdentify({ target: key, identify: !identify });\n }}\n >\n Identify\n </Button>\n <Button\n size='small'\n data-testid={isCurrent ? '' : 'not-self-rename'}\n onClick={() => openRename(key)}\n >\n Rename\n </Button>\n\n <Button\n size='small'\n disabled={isCurrent}\n data-testid={isCurrent ? '' : 'not-self-redirect'}\n onClick={() => openRedirect(key)}\n >\n Redirect\n </Button>\n </Panel.InlineElements>\n </tr>\n );\n })}\n </tbody>\n </Panel.Table>\n </Panel.Section>\n <Panel.Divider />\n <Panel.Section>\n <Panel.Title>Other Clients ({otherClients.length})</Panel.Title>\n <Panel.Table>\n <thead>\n <tr>\n <td className={style.halfWidthNoWrap}>Client Name</td>\n <td className={style.halfWidthNoWrap}>Client type</td>\n </tr>\n </thead>\n <tbody>\n {otherClients.map(([key, client]) => {\n const { name, type } = client;\n\n return (\n <tr key={key}>\n <td>{name}</td>\n <td>{type}</td>\n </tr>\n );\n })}\n </tbody>\n </Panel.Table>\n </Panel.Section>\n </>\n );\n}\n","import * as Panel from '../../../panel-utils/PanelUtils';\n\nimport ClientList from './ClientList';\n\nexport default function ClientControlPanel() {\n return (\n <Panel.Section>\n <Panel.Card>\n <Panel.SubHeader>Manage clients</Panel.SubHeader>\n <Panel.Divider />\n <ClientList />\n </Panel.Card>\n </Panel.Section>\n );\n}\n","import { MouseEvent } from 'react';\nimport { IoArrowUp } from 'react-icons/io5';\n\nimport Button from '../../../../common/components/buttons/Button';\nimport { handleLinks } from '../../../../common/utils/linkUtils';\nimport Log from '../../../log/Log';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport style from './NetworkLogExport.module.scss';\n\nexport default function LogExport() {\n const extract = (event: MouseEvent) => {\n handleLinks('log', event);\n };\n\n return (\n <Panel.Section>\n <Panel.Card>\n <Panel.SubHeader>\n Event log\n <Button onClick={extract}>\n Extract <IoArrowUp className={style.iconRotate} />\n </Button>\n </Panel.SubHeader>\n <Panel.Divider />\n <Log />\n </Panel.Card>\n </Panel.Section>\n );\n}\n","import { useEffect } from 'react';\nimport { MessageTag } from 'ontime-types';\n\nimport useScrollIntoView from '../../../../common/hooks/useScrollIntoView';\nimport { usePing } from '../../../../common/hooks/useSocket';\nimport { sendSocket } from '../../../../common/utils/socket';\nimport { isDocker } from '../../../../externals';\nimport type { PanelBaseProps } from '../../panel-list/PanelList';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport ClientControlPanel from './client-control/ClientControlPanel';\nimport LogExport from './NetworkLogExport';\n\nexport default function NetworkLogPanel({ location }: PanelBaseProps) {\n const clientsRef = useScrollIntoView<HTMLDivElement>('clients', location);\n const logRef = useScrollIntoView<HTMLDivElement>('log', location);\n\n return (\n <>\n <Panel.Header>Network</Panel.Header>\n {isDocker && (\n <Panel.Section>\n <OntimeCloudStats />\n </Panel.Section>\n )}\n <div ref={logRef}>\n <LogExport />\n </div>\n <div ref={clientsRef}>\n <ClientControlPanel />\n </div>\n </>\n );\n}\n\nfunction OntimeCloudStats() {\n const { ping } = usePing();\n\n /**\n * Send immediate ping request, and keep sending on an interval\n */\n useEffect(() => {\n sendSocket(MessageTag.Ping, new Date());\n\n const doPing = setInterval(() => {\n sendSocket(MessageTag.Ping, new Date());\n }, 5000);\n\n return () => {\n clearInterval(doPing);\n };\n }, []);\n\n return (\n <Panel.SubHeader>\n Ontime cloud\n <Panel.Description>Current ping: {ping}ms</Panel.Description>\n </Panel.SubHeader>\n );\n}\n","import type { QuickStartData } from 'ontime-types';\n\nexport const quickStartDefaults: QuickStartData = {\n project: {\n title: '',\n },\n settings: {\n timeFormat: '24',\n language: 'en',\n },\n};\n","import { useForm } from 'react-hook-form';\nimport { QuickStartData } from 'ontime-types';\nimport { parseUserTime } from 'ontime-utils';\n\nimport { quickProject } from '../../../common/api/db';\nimport { invalidateAllCaches, maybeAxiosError } from '../../../common/api/utils';\nimport Button from '../../../common/components/buttons/Button';\nimport Input from '../../../common/components/input/input/Input';\nimport TimeInput from '../../../common/components/input/time-input/TimeInput';\nimport Modal from '../../../common/components/modal/Modal';\nimport Select from '../../../common/components/select/Select';\nimport { editorSettingsDefaults, useEditorSettings } from '../../../common/stores/editorSettings';\nimport * as Panel from '../panel-utils/PanelUtils';\n\nimport { quickStartDefaults } from './quickStart.utils';\n\ninterface QuickStartProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\nexport default function QuickStart({ isOpen, onClose }: QuickStartProps) {\n const { defaultWarnTime, defaultDangerTime, setDangerTime, setWarnTime } = useEditorSettings();\n\n const {\n handleSubmit,\n register,\n formState: { errors, isSubmitting, isValid },\n watch,\n setError,\n setValue,\n } = useForm<QuickStartData>({\n defaultValues: quickStartDefaults,\n values: quickStartDefaults,\n resetOptions: {\n keepDirtyValues: true,\n },\n });\n\n const onSubmit = async (formData: QuickStartData) => {\n try {\n if (formData.project.title === '') {\n formData.project.title = 'untitled';\n }\n await quickProject(formData);\n await invalidateAllCaches();\n onClose();\n } catch (error) {\n setError('root', { message: maybeAxiosError(error) });\n }\n };\n\n const warnTimeInMs = parseUserTime(defaultWarnTime);\n const dangerTimeInMs = parseUserTime(defaultDangerTime);\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n showBackdrop\n showCloseButton\n title='Create new project...'\n bodyElements={\n <form onSubmit={handleSubmit(onSubmit)} id='quick-start'>\n <Panel.ListGroup>\n <Panel.ListItem>\n <Panel.Field title='Project title' description='Shown as the title in some views' />\n <Input maxLength={150} placeholder='Project title' fluid {...register('project.title')} />\n </Panel.ListItem>\n <Panel.ListItem>\n <Panel.Field\n title='Time format'\n description='Default time format to show in views 12 /24 hours'\n error={errors.settings?.timeFormat?.message}\n />\n <Select\n value={watch('settings.timeFormat')}\n onValueChange={(value: '12' | '24') => setValue('settings.timeFormat', value, { shouldDirty: true })}\n defaultValue='24'\n options={[\n { value: '12', label: '12 hours 11:00:10 PM' },\n { value: '24', label: '24 hours 23:00:10' },\n ]}\n />\n </Panel.ListItem>\n <Panel.ListItem>\n <Panel.Field\n title='Views language'\n description='Language to be displayed in views'\n error={errors.settings?.language?.message}\n />\n <Select\n value={watch('settings.language')}\n onValueChange={(value: string) => setValue('settings.language', value, { shouldDirty: true })}\n defaultValue='en'\n options={[\n { value: 'en', label: 'English' },\n { value: 'fr', label: 'French' },\n { value: 'de', label: 'German' },\n { value: 'it', label: 'Italian' },\n { value: 'pt', label: 'Portuguese' },\n { value: 'es', label: 'Spanish' },\n ]}\n />\n </Panel.ListItem>\n </Panel.ListGroup>\n\n <Panel.ListGroup>\n <Panel.ListItem>\n <Panel.Field title='Warning time' description='Default threshold for warning time in an event' />\n <TimeInput<'warnTime'>\n name='warnTime'\n submitHandler={(_field, value) => setWarnTime(value)}\n time={warnTimeInMs}\n placeholder={editorSettingsDefaults.warnTime}\n />\n </Panel.ListItem>\n <Panel.ListItem>\n <Panel.Field title='Danger time' description='Default threshold for danger time in an event' />\n <TimeInput<'dangerTime'>\n name='dangerTime'\n submitHandler={(_field, value) => setDangerTime(value)}\n time={dangerTimeInMs}\n placeholder={editorSettingsDefaults.dangerTime}\n />\n </Panel.ListItem>\n </Panel.ListGroup>\n </form>\n }\n footerElements={\n <>\n {errors?.root && <Panel.Error>{errors.root.message}</Panel.Error>}\n <Button variant='ghosted' onClick={onClose} disabled={false}>\n Cancel\n </Button>\n <Button variant='primary' type='submit' form='quick-start' disabled={!isValid} loading={isSubmitting}>\n Create project\n </Button>\n </>\n }\n />\n );\n}\n","import { useEffect, useState } from 'react';\nimport { useForm } from 'react-hook-form';\n\nimport { createProject } from '../../../../common/api/db';\nimport { maybeAxiosError } from '../../../../common/api/utils';\nimport Button from '../../../../common/components/buttons/Button';\nimport Input from '../../../../common/components/input/input/Input';\nimport { preventEscape } from '../../../../common/utils/keyEvent';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport style from './ProjectPanel.module.scss';\n\ninterface ProjectCreateFromProps {\n onClose: () => void;\n}\n\ntype ProjectCreateFormValues = {\n title?: string;\n description?: string;\n info?: string;\n url?: string;\n custom?: { title: string; value: string }[];\n};\n\nexport default function ProjectCreateForm({ onClose }: ProjectCreateFromProps) {\n const [error, setError] = useState<string | null>(null);\n\n const {\n handleSubmit,\n register,\n formState: { isSubmitting, isValid },\n setFocus,\n } = useForm<ProjectCreateFormValues>({\n defaultValues: { title: '' },\n values: { title: '' },\n resetOptions: {\n keepDirtyValues: true,\n },\n });\n\n // set focus to first field\n useEffect(() => {\n setFocus('title');\n }, [setFocus]);\n\n const handleSubmitCreate = async (values: ProjectCreateFormValues) => {\n try {\n setError(null);\n\n const filename = values.title ?? 'untitled';\n\n await createProject({ filename });\n\n onClose();\n } catch (error) {\n setError(maybeAxiosError(error));\n }\n };\n\n return (\n <Panel.Indent\n as='form'\n onSubmit={handleSubmit(handleSubmitCreate)}\n onKeyDown={(event) => preventEscape(event, onClose)}\n >\n <Panel.Title>\n Create new project\n <Panel.InlineElements>\n <Button onClick={onClose} variant='ghosted' disabled={isSubmitting}>\n Cancel\n </Button>\n <Button disabled={!isValid} type='submit' loading={isSubmitting} variant='primary'>\n Create project\n </Button>\n </Panel.InlineElements>\n </Panel.Title>\n {error && <Panel.Error>{error}</Panel.Error>}\n <Panel.Section className={style.innerColumn}>\n <Panel.Description>Project title</Panel.Description>\n <Input fluid placeholder='Your project name' {...register('title')} />\n </Panel.Section>\n </Panel.Indent>\n );\n}\n","import { useMemo } from 'react';\nimport { useQuery } from '@tanstack/react-query';\nimport { ProjectFileListResponse } from 'ontime-types';\n\nimport { queryRefetchIntervalSlow } from '../../ontimeConfig';\nimport { PROJECT_LIST } from '../api/constants';\nimport { getProjects } from '../api/db';\n\nconst placeholderProjectList: ProjectFileListResponse = {\n files: [],\n lastLoadedProject: '',\n};\n\nfunction useProjectList() {\n const { data, status, refetch } = useQuery({\n queryKey: PROJECT_LIST,\n queryFn: getProjects,\n placeholderData: (previousData, _previousQuery) => previousData,\n retry: 5,\n retryDelay: (attempt: number) => attempt * 2500,\n refetchInterval: queryRefetchIntervalSlow,\n networkMode: 'always',\n });\n return { data: data ?? placeholderProjectList, status, refetch };\n}\n\nexport function useOrderedProjectList() {\n const response = useProjectList();\n const { files, lastLoadedProject } = response.data;\n\n const reorderedProjectFiles = useMemo(() => {\n if (!files.length) return [];\n\n const currentlyLoadedIndex = files.findIndex((project) => project.filename === lastLoadedProject);\n\n if (currentlyLoadedIndex === -1) return files;\n\n const projectFiles = [...files];\n const current = projectFiles.splice(currentlyLoadedIndex, 1)[0];\n\n return [current, ...projectFiles];\n }, [files, lastLoadedProject]);\n\n return { ...response, data: { reorderedProjectFiles, lastLoadedProject: response.data.lastLoadedProject } };\n}\n","import { useEffect } from 'react';\nimport { useForm } from 'react-hook-form';\n\nimport Button from '../../../../common/components/buttons/Button';\nimport Input from '../../../../common/components/input/input/Input';\nimport { preventEscape } from '../../../../common/utils/keyEvent';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport style from './ProjectPanel.module.scss';\n\nexport type ProjectFormValues = {\n filename: string;\n};\n\ninterface ProjectFormProps {\n action: 'duplicate' | 'rename' | 'merge';\n filename: string;\n onCancel: () => void;\n onSubmit: (values: ProjectFormValues) => Promise<void>;\n}\n\nexport default function ProjectForm({ action, filename, onSubmit, onCancel }: ProjectFormProps) {\n const {\n handleSubmit,\n register,\n formState: { isSubmitting, isDirty, isValid },\n setFocus,\n } = useForm<ProjectFormValues>({\n defaultValues: { filename },\n values: { filename },\n resetOptions: {\n keepDirtyValues: true,\n },\n });\n\n useEffect(() => {\n setFocus('filename');\n }, [setFocus]);\n\n return (\n <form\n onSubmit={handleSubmit(onSubmit)}\n onKeyDown={(event) => preventEscape(event, onCancel)}\n className={style.form}\n >\n <Input\n className={style.formInput}\n id='filename'\n placeholder='Enter new name'\n {...register('filename', { required: true })}\n />\n <Panel.InlineElements relation='inner'>\n <Button onClick={onCancel} variant='ghosted' disabled={isSubmitting}>\n Cancel\n </Button>\n <Button\n variant='primary'\n disabled={!isDirty || !isValid || isSubmitting}\n type='submit'\n className={style.saveButton}\n >\n {action}\n </Button>\n </Panel.InlineElements>\n </form>\n );\n}\n","import { DatabaseModel, isKeyOfType } from 'ontime-types';\n\nexport async function makeProjectPatch(data: DatabaseModel, mergeKeys: Record<string, boolean>) {\n const patchObject: Partial<DatabaseModel> = {};\n\n for (const key in mergeKeys) {\n if (isKeyOfType(key, data) && mergeKeys[key]) {\n // if the rundown is merged we also need the custom fields\n if (key === 'rundowns') {\n patchObject.customFields = data['customFields'];\n }\n Object.assign(patchObject, { [key]: data[key] });\n }\n }\n\n return patchObject;\n}\n","import { useState } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { useQueryClient } from '@tanstack/react-query';\n\nimport { PROJECT_DATA } from '../../../../common/api/constants';\nimport { getDb, patchData } from '../../../../common/api/db';\nimport { maybeAxiosError } from '../../../../common/api/utils';\nimport Button from '../../../../common/components/buttons/Button';\nimport Info from '../../../../common/components/info/Info';\nimport Switch from '../../../../common/components/switch/Switch';\nimport { cx } from '../../../../common/utils/styleUtils';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport { makeProjectPatch } from './project.utils';\n\nimport style from './ProjectPanel.module.scss';\n\ninterface ProjectMergeFromProps {\n onClose: () => void;\n fileName: string;\n}\n\ntype ProjectMergeFormValues = {\n project: boolean;\n rundowns: boolean;\n viewSettings: boolean;\n urlPresets: boolean;\n automation: boolean;\n};\n\nexport default function ProjectMergeForm({ onClose, fileName }: ProjectMergeFromProps) {\n const [error, setError] = useState<string | null>(null);\n const queryClient = useQueryClient();\n\n const {\n handleSubmit,\n watch,\n setValue,\n formState: { isSubmitting, isValid, isDirty },\n } = useForm<ProjectMergeFormValues>({\n defaultValues: {\n project: false,\n rundowns: false,\n viewSettings: false,\n urlPresets: false,\n automation: false,\n },\n resetOptions: {\n keepDirtyValues: true,\n },\n });\n\n const handleSubmitCreate = async (values: ProjectMergeFormValues) => {\n const allFalse = Object.values(values).every((value) => !value);\n if (allFalse) {\n setError('At least one option must be selected');\n return;\n }\n\n try {\n setError(null);\n\n // make patch object\n const { data } = await getDb(fileName);\n if (!data.settings.version.startsWith('4.')) {\n setError('The project you are attempting to merge is from an older version and it need to be migrated first');\n return;\n }\n const patch = await makeProjectPatch(data, values);\n\n // request patch\n await patchData(patch);\n await queryClient.invalidateQueries({ queryKey: PROJECT_DATA });\n onClose();\n } catch (error) {\n setError(maybeAxiosError(error));\n }\n };\n\n return (\n <Panel.Section as='form' onSubmit={handleSubmit(handleSubmitCreate)}>\n <Panel.Title>\n Partial project merge\n <Panel.InlineElements>\n <Button onClick={onClose} variant='ghosted' disabled={isSubmitting}>\n Cancel\n </Button>\n <Button type='submit' disabled={!isValid || !isDirty} loading={isSubmitting} variant='primary'>\n Merge\n </Button>\n </Panel.InlineElements>\n </Panel.Title>\n {error && <Panel.Error>{error}</Panel.Error>}\n <Panel.Section className={cx([style.innerColumn, style.inlineLabels])}>\n <Panel.Description>\n Select data from <i>{`\"${fileName}\"`}</i> to merge into the current project.\n </Panel.Description>\n <Info type='warning'>\n This process is irreversible and can result in data loss. <br />\n You may want to create a duplicate backup beforehand.\n </Info>\n <label>\n <Switch\n size='large'\n checked={watch('project')}\n onCheckedChange={(value: boolean) => setValue('project', value, { shouldDirty: true })}\n />\n Project data\n </label>\n <label>\n <Switch\n size='large'\n checked={watch('rundowns')}\n onCheckedChange={(value: boolean) => setValue('rundowns', value, { shouldDirty: true })}\n />\n Rundown + Custom Fields\n </label>\n <label>\n <Switch\n size='large'\n checked={watch('viewSettings')}\n onCheckedChange={(value: boolean) => setValue('viewSettings', value, { shouldDirty: true })}\n />\n View Settings\n </label>\n <label>\n <Switch\n size='large'\n checked={watch('urlPresets')}\n onCheckedChange={(value: boolean) => setValue('urlPresets', value, { shouldDirty: true })}\n />\n URL Presets\n </label>\n <label>\n <Switch\n size='large'\n checked={watch('automation')}\n onCheckedChange={(value: boolean) => setValue('automation', value, { shouldDirty: true })}\n />\n Automation Settings\n </label>\n </Panel.Section>\n </Panel.Section>\n );\n}\n","import { useState } from 'react';\nimport {\n IoCopyOutline,\n IoDocumentOutline,\n IoDownloadOutline,\n IoEllipsisHorizontal,\n IoPencilOutline,\n IoTrash,\n} from 'react-icons/io5';\n\nimport {\n deleteProject,\n downloadProject,\n duplicateProject,\n loadProject,\n renameProject,\n} from '../../../../common/api/db';\nimport { invalidateAllCaches, maybeAxiosError } from '../../../../common/api/utils';\nimport IconButton from '../../../../common/components/buttons/IconButton';\nimport { DropdownMenu } from '../../../../common/components/dropdown-menu/DropdownMenu';\nimport { cx } from '../../../../common/utils/styleUtils';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport ProjectForm, { ProjectFormValues } from './ProjectForm';\nimport ProjectMergeForm from './ProjectMergeForm';\n\nimport style from './ProjectPanel.module.scss';\n\nexport type EditMode = 'rename' | 'duplicate' | 'merge' | null;\n\ninterface ProjectListItemProps {\n current?: boolean;\n filename: string;\n updatedAt: string;\n onToggleEditMode: (editMode: EditMode, filename: string | null) => void;\n onSubmit: () => void;\n onRefetch: () => Promise<void>;\n editingFilename: string | null;\n editingMode: EditMode | null;\n}\n\nexport default function ProjectListItem({\n current,\n updatedAt,\n editingFilename,\n editingMode,\n filename,\n onRefetch,\n onSubmit,\n onToggleEditMode,\n}: ProjectListItemProps) {\n const [submitError, setSubmitError] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n\n const handleSubmitAction = (actionType: 'rename' | 'duplicate') => {\n return async (values: ProjectFormValues) => {\n setLoading(true);\n setSubmitError(null);\n try {\n if (!values.filename) {\n setSubmitError('Filename cannot be blank');\n return;\n }\n const action = actionType === 'rename' ? renameProject : duplicateProject;\n await action(filename, values.filename);\n await onRefetch();\n onSubmit();\n } catch (error) {\n setSubmitError(maybeAxiosError(error));\n } finally {\n setLoading(false);\n }\n };\n };\n\n const handleLoad = async (filename: string) => {\n setLoading(true);\n setSubmitError(null);\n try {\n await loadProject(filename);\n await onRefetch();\n await invalidateAllCaches();\n } catch (error) {\n setSubmitError(maybeAxiosError(error));\n } finally {\n setLoading(false);\n }\n };\n\n const handleDelete = async (filename: string) => {\n setLoading(true);\n setSubmitError(null);\n try {\n await deleteProject(filename);\n await onRefetch();\n } catch (error) {\n setSubmitError(maybeAxiosError(error));\n } finally {\n setLoading(false);\n }\n };\n\n const handleToggleEditMode = (editMode: EditMode, filename: string | null) => {\n setSubmitError(null);\n onToggleEditMode(editMode, filename);\n };\n\n const handleCancel = () => {\n handleToggleEditMode(null, null);\n };\n\n const isCurrentlyBeingEdited = filename === editingFilename;\n const showProjectForm = (editingMode === 'rename' || editingMode === 'duplicate') && filename === editingFilename;\n const showMergeForm = editingMode === 'merge' && isCurrentlyBeingEdited;\n const classes = cx([current && !isCurrentlyBeingEdited && style.current, isCurrentlyBeingEdited && style.isEditing]);\n\n return (\n <>\n {submitError && (\n <tr key='filename-error'>\n <td colSpan={99}>\n <Panel.Error>{submitError}</Panel.Error>\n </td>\n </tr>\n )}\n <tr key={filename} className={classes}>\n {showProjectForm ? (\n <td colSpan={99}>\n <ProjectForm\n action={editingMode}\n filename={filename}\n onSubmit={editingMode === 'duplicate' ? handleSubmitAction('duplicate') : handleSubmitAction('rename')}\n onCancel={handleCancel}\n />\n </td>\n ) : (\n <>\n <td className={style.containCell}>{filename}</td>\n <td>{current ? 'Currently loaded' : new Date(updatedAt).toLocaleString()}</td>\n <td>\n <ActionMenu\n current={current}\n filename={filename}\n onChangeEditMode={handleToggleEditMode}\n onDelete={handleDelete}\n onLoad={handleLoad}\n isDisabled={loading || showMergeForm}\n onMerge={(filename) => handleToggleEditMode('merge', filename)}\n />\n </td>\n </>\n )}\n </tr>\n {showMergeForm && (\n <tr>\n <td colSpan={99}>\n <ProjectMergeForm onClose={handleCancel} fileName={filename} />\n </td>\n </tr>\n )}\n </>\n );\n}\n\ninterface ActionMenuProps {\n current?: boolean;\n filename: string;\n isDisabled: boolean;\n onChangeEditMode: (editMode: EditMode, filename: string) => void;\n onDelete: (filename: string) => Promise<void>;\n onLoad: (filename: string) => Promise<void>;\n onMerge: (filename: string) => void;\n}\nfunction ActionMenu(props: ActionMenuProps) {\n const { current, filename, isDisabled, onChangeEditMode, onDelete, onLoad, onMerge } = props;\n\n const handleRename = () => {\n onChangeEditMode('rename', filename);\n };\n\n const handleDuplicate = () => {\n onChangeEditMode('duplicate', filename);\n };\n\n const handleDownload = async () => {\n await downloadProject(filename);\n };\n\n return (\n <DropdownMenu\n render={<IconButton variant='ghosted-white' />}\n disabled={isDisabled}\n items={[\n {\n type: 'item',\n icon: IoDownloadOutline,\n label: 'Load',\n onClick: () => onLoad(filename),\n disabled: current,\n },\n {\n type: 'item',\n icon: IoDownloadOutline,\n label: 'Partial Load',\n onClick: () => onMerge(filename),\n disabled: current,\n },\n { type: 'item', icon: IoPencilOutline, label: 'Rename', onClick: handleRename },\n { type: 'item', icon: IoCopyOutline, label: 'Duplicate', onClick: handleDuplicate },\n { type: 'item', icon: IoDocumentOutline, label: 'Download', onClick: handleDownload },\n { type: 'divider' },\n { type: 'item', icon: IoTrash, label: 'Delete', onClick: () => onDelete(filename), disabled: current },\n ]}\n >\n <IoEllipsisHorizontal />\n </DropdownMenu>\n );\n}\n","import { useState } from 'react';\n\nimport Info from '../../../../common/components/info/Info';\nimport { useOrderedProjectList } from '../../../../common/hooks-query/useProjectList';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport ProjectListItem, { EditMode } from './ProjectListItem';\n\nimport style from './ProjectPanel.module.scss';\n\nexport default function ProjectList() {\n const { data, refetch, status } = useOrderedProjectList();\n\n const [editingMode, setEditingMode] = useState<EditMode | null>(null);\n const [editingFilename, setEditingFilename] = useState<string | null>(null);\n\n const handleToggleEditMode = (editMode: EditMode, filename: string | null) => {\n setEditingMode((prev) => (prev === editMode && filename === editingFilename ? null : editMode));\n setEditingFilename(filename);\n };\n\n const handleClear = () => {\n setEditingMode(null);\n setEditingFilename(null);\n };\n\n const handleRefetch = async () => {\n await refetch();\n };\n\n if (status === 'pending') {\n return (\n <div className={style.empty}>\n <Panel.Loader isLoading />\n </div>\n );\n }\n\n const numProjects = data.reorderedProjectFiles.length;\n\n return (\n <>\n {numProjects > 20 && (\n <Info className={style.warningInfo} type='warning'>\n You have {numProjects} projects. Consider deleting unused projects to improve performance.\n </Info>\n )}\n <Panel.Table>\n <thead>\n <tr>\n <th className={style.containCell}>File Name</th>\n <th>Last Used</th>\n <th />\n </tr>\n </thead>\n <tbody>\n {data.reorderedProjectFiles.map((project) => (\n <ProjectListItem\n key={project.filename}\n filename={project.filename}\n updatedAt={project.updatedAt}\n onToggleEditMode={handleToggleEditMode}\n onSubmit={handleClear}\n onRefetch={handleRefetch}\n editingFilename={editingFilename}\n editingMode={editingMode}\n current={project.filename === data.lastLoadedProject}\n />\n ))}\n </tbody>\n </Panel.Table>\n </>\n );\n}\n","import { ChangeEvent, useRef, useState } from 'react';\nimport { IoAdd } from 'react-icons/io5';\nimport { useSearchParams } from 'react-router';\n\nimport { uploadProjectFile } from '../../../../common/api/db';\nimport { invalidateAllCaches, maybeAxiosError } from '../../../../common/api/utils';\nimport Button from '../../../../common/components/buttons/Button';\nimport { validateProjectFile } from '../../../../common/utils/uploadUtils';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport ProjectCreateForm from './ProjectCreateForm';\nimport ProjectList from './ProjectList';\n\nexport default function ManageProjects() {\n const [searchParams, setSearchParams] = useSearchParams();\n const [error, setError] = useState('');\n const [loading, setLoading] = useState<'import' | null>(null);\n\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const isCreatingProject = searchParams.get('new') === 'true';\n\n const handleToggleCreate = () => {\n searchParams.set('new', isCreatingProject ? 'false' : 'true');\n setSearchParams(searchParams);\n };\n\n const handleSelectFile = () => {\n fileInputRef.current?.click();\n };\n\n const handleImport = async (event: ChangeEvent<HTMLInputElement>) => {\n const selectedFile = event.target?.files?.[0];\n if (!selectedFile) {\n return;\n }\n\n setLoading('import');\n\n try {\n validateProjectFile(selectedFile);\n await uploadProjectFile(selectedFile);\n } catch (error) {\n const errorMessage = maybeAxiosError(error);\n setError(`Error uploading file: ${errorMessage}`);\n } finally {\n await invalidateAllCaches();\n }\n\n setLoading(null);\n };\n\n const handleCloseForm = () => {\n searchParams.delete('new');\n setSearchParams(searchParams);\n };\n\n return (\n <Panel.Section>\n <input\n ref={fileInputRef}\n style={{ display: 'none' }}\n type='file'\n onChange={handleImport}\n accept='.json'\n data-testid='file-input'\n />\n <Panel.Card>\n <Panel.SubHeader>\n Manage projects\n <Panel.InlineElements>\n <Button\n onClick={handleSelectFile}\n disabled={Boolean(loading) || isCreatingProject}\n loading={loading === 'import'}\n >\n Import\n </Button>\n <Button onClick={handleToggleCreate} disabled={Boolean(loading) || isCreatingProject}>\n New <IoAdd />\n </Button>\n </Panel.InlineElements>\n </Panel.SubHeader>\n {error && <Panel.Error>{error}</Panel.Error>}\n <Panel.Divider />\n {isCreatingProject && <ProjectCreateForm onClose={handleCloseForm} />}\n <ProjectList />\n </Panel.Card>\n </Panel.Section>\n );\n}\n","import useScrollIntoView from '../../../../common/hooks/useScrollIntoView';\nimport type { PanelBaseProps } from '../../panel-list/PanelList';\nimport * as Panel from '../../panel-utils/PanelUtils';\nimport QuickStart from '../../quick-start/QuickStart';\nimport type { SettingsOptionId } from '../../useAppSettingsMenu';\n\nimport ManageProjects from './ManageProjects';\n\ninterface ProjectPanelProps extends PanelBaseProps {\n setLocation: (location: SettingsOptionId) => void;\n}\n\nexport default function ProjectPanel({ location, setLocation }: ProjectPanelProps) {\n const manageProjectsRef = useScrollIntoView<HTMLDivElement>('list', location);\n\n const handleQuickClose = () => {\n setLocation('project');\n };\n\n return (\n <>\n <Panel.Header>Project</Panel.Header>\n <QuickStart isOpen={location === 'create'} onClose={handleQuickClose} />\n <div ref={manageProjectsRef}>\n <ManageProjects />\n </div>\n </>\n );\n}\n","import { PropsWithChildren, useState } from 'react';\nimport { UseFormRegister } from 'react-hook-form';\nimport { IoEyeOutline } from 'react-icons/io5';\nimport { Settings } from 'ontime-types';\n\nimport IconButton from '../../../../../common/components/buttons/IconButton';\nimport Input from '../../../../../common/components/input/input/Input';\nimport { isAlphanumeric } from '../../../../../common/utils/regex';\n\nimport style from './GeneralPinInput.module.scss';\n\ninterface GeneralPinInputProps {\n register: UseFormRegister<Settings>;\n formName: keyof Settings;\n disabled?: boolean;\n}\n\nexport default function GeneralPinInput({ register, formName, disabled }: PropsWithChildren<GeneralPinInputProps>) {\n const [isVisible, setVisible] = useState(false);\n\n return (\n <div className={style.container}>\n <Input\n type={isVisible ? 'text' : 'password'}\n maxLength={4}\n {...register(formName, {\n pattern: {\n value: isAlphanumeric,\n message: 'Only alphanumeric characters are allowed',\n },\n })}\n placeholder='-'\n disabled={disabled}\n />\n <IconButton\n onMouseDown={() => setVisible(true)}\n onMouseUp={() => setVisible(false)}\n variant='ghosted'\n aria-label='Show pin code'\n >\n <IoEyeOutline />\n </IconButton>\n </div>\n );\n}\n","import { lazy, useEffect } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { useDisclosure } from '@mantine/hooks';\nimport { Settings } from 'ontime-types';\n\nimport { postSettings } from '../../../../common/api/settings';\nimport { maybeAxiosError } from '../../../../common/api/utils';\nimport Button from '../../../../common/components/buttons/Button';\nimport Input from '../../../../common/components/input/input/Input';\nimport Select from '../../../../common/components/select/Select';\nimport useSettings from '../../../../common/hooks-query/useSettings';\nimport { preventEscape } from '../../../../common/utils/keyEvent';\nimport { isOnlyNumbers } from '../../../../common/utils/regex';\nimport { isOntimeCloud } from '../../../../externals';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport GeneralPinInput from './composite/GeneralPinInput';\n\nconst TranslationModal = lazy(() => import('./composite/CustomTranslationModal'));\n\nexport default function GeneralSettings() {\n const { data, status, refetch } = useSettings();\n const {\n handleSubmit,\n register,\n reset,\n setError,\n watch,\n setValue,\n formState: { isSubmitting, isDirty, isValid, errors },\n } = useForm<Settings>({\n mode: 'onChange',\n defaultValues: data,\n values: data,\n resetOptions: {\n keepDirtyValues: true,\n },\n });\n\n const [isOpen, handler] = useDisclosure();\n\n // update form if we get new data from server\n useEffect(() => {\n if (data) {\n reset(data);\n }\n }, [data, reset]);\n\n const onSubmit = async (formData: Settings) => {\n try {\n await postSettings(formData);\n } catch (error) {\n const message = maybeAxiosError(error);\n setError('root', { message });\n } finally {\n await refetch();\n }\n };\n\n const disableInputs = status === 'pending';\n const disableSubmit = isSubmitting || !isDirty || !isValid;\n const submitError = '';\n\n const onReset = () => {\n reset(data);\n };\n\n const isLoading = status === 'pending';\n\n return (\n <>\n <TranslationModal isOpen={isOpen} onClose={handler.close} />\n <Panel.Section\n as='form'\n onSubmit={handleSubmit(onSubmit)}\n onKeyDown={(event) => preventEscape(event, onReset)}\n id='app-settings'\n >\n <Panel.Card>\n <Panel.SubHeader>\n General settings\n <Panel.InlineElements>\n <Button disabled={!isDirty || isSubmitting} variant='ghosted' onClick={onReset}>\n Revert to saved\n </Button>\n <Button\n type='submit'\n form='app-settings'\n name='general-settings-submit'\n loading={isSubmitting}\n disabled={disableSubmit}\n variant='primary'\n >\n Save\n </Button>\n </Panel.InlineElements>\n </Panel.SubHeader>\n {submitError && <Panel.Error>{submitError}</Panel.Error>}\n <Panel.Divider />\n <Panel.Section>\n <Panel.Loader isLoading={isLoading} />\n <Panel.ListGroup>\n <Panel.ListItem>\n <Panel.Field\n title='Ontime server port'\n description={\n isOntimeCloud\n ? 'Server port disabled for Ontime Cloud'\n : 'Port ontime server listens in. Defaults to 4001 (needs app restart)'\n }\n error={errors.serverPort?.message}\n />\n <Input\n id='serverPort'\n type='number'\n maxLength={5}\n style={{ width: '75px' }}\n disabled={isOntimeCloud}\n {...register('serverPort', {\n required: { value: true, message: 'Required field' },\n max: { value: 65535, message: 'Port must be within range 1024 - 65535' },\n min: { value: 1024, message: 'Port must be within range 1024 - 65535' },\n pattern: {\n value: isOnlyNumbers,\n message: 'Value should be numeric',\n },\n })}\n />\n </Panel.ListItem>\n <Panel.ListItem>\n <Panel.Field\n title='Editor pin code'\n description='Protect the editor view with a pin code'\n error={errors.editorKey?.message}\n />\n <GeneralPinInput register={register} formName='editorKey' disabled={disableInputs} />\n </Panel.ListItem>\n <Panel.ListItem>\n <Panel.Field\n title='Operator pin code'\n description='Protect the operator and cuesheet views with a pin code'\n error={errors.operatorKey?.message}\n />\n <GeneralPinInput register={register} formName='operatorKey' disabled={disableInputs} />\n </Panel.ListItem>\n <Panel.ListItem>\n <Panel.Field\n title='Time format'\n description='Default time format to show in views 12 /24 hours'\n error={errors.timeFormat?.message}\n />\n <Select\n value={watch('timeFormat')}\n onValueChange={(value) => setValue('timeFormat', value as '12' | '24', { shouldDirty: true })}\n defaultValue='24'\n options={[\n { value: '12', label: '12 hours 11:00:10 PM' },\n { value: '24', label: '24 hours 23:00:10' },\n ]}\n />\n </Panel.ListItem>\n <Panel.ListItem>\n <Panel.Field\n title='Views language'\n description='Language to be displayed in views'\n error={errors.language?.message}\n />\n <Select\n value={watch('language')}\n onValueChange={(value) => setValue('language', value, { shouldDirty: true })}\n disabled={disableInputs}\n defaultValue='en'\n options={[\n { value: 'en', label: 'English' },\n { value: 'fr', label: 'French' },\n { value: 'de', label: 'German' },\n { value: 'it', label: 'Italian' },\n { value: 'pt', label: 'Portuguese' },\n { value: 'es', label: 'Spanish' },\n { value: 'custom', label: 'Custom' },\n ]}\n />\n <Button onClick={handler.open}>Edit custom translation</Button>\n </Panel.ListItem>\n </Panel.ListGroup>\n </Panel.Section>\n </Panel.Card>\n </Panel.Section>\n </>\n );\n}\n","import { ChangeEvent, useEffect, useRef } from 'react';\nimport { useFieldArray, useForm } from 'react-hook-form';\nimport { IoAdd, IoDownloadOutline, IoTrash } from 'react-icons/io5';\nimport { type ProjectData } from 'ontime-types';\n\nimport { projectLogoPath } from '../../../../common/api/constants';\nimport { uploadProjectLogo } from '../../../../common/api/project';\nimport { maybeAxiosError } from '../../../../common/api/utils';\nimport Button from '../../../../common/components/buttons/Button';\nimport Input from '../../../../common/components/input/input/Input';\nimport Textarea from '../../../../common/components/input/textarea/Textarea';\nimport useProjectData, { useUpdateProjectData } from '../../../../common/hooks-query/useProjectData';\nimport { preventEscape } from '../../../../common/utils/keyEvent';\nimport { validateLogo } from '../../../../common/utils/uploadUtils';\nimport { documentationUrl } from '../../../../externals';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport style from './SettingsPanel.module.scss';\n\nexport default function ProjectData() {\n const { data, status } = useProjectData();\n const { updateProjectData } = useUpdateProjectData();\n\n const {\n handleSubmit,\n register,\n reset,\n formState: { isSubmitting, isValid, isDirty, errors },\n setError,\n clearErrors,\n watch,\n control,\n setValue,\n } = useForm({\n defaultValues: data,\n values: data,\n resetOptions: {\n keepDirtyValues: true,\n },\n mode: 'onChange',\n });\n\n const { fields, append, remove } = useFieldArray({\n control,\n name: 'custom',\n });\n\n // reset form values if data changes\n useEffect(() => {\n if (data) {\n reset(data);\n }\n }, [data, reset]);\n\n const handleUploadProjectLogo = async (event: ChangeEvent<HTMLInputElement>) => {\n const file = event.target.files?.[0];\n clearErrors('logo');\n\n if (!file) {\n return;\n }\n\n try {\n validateLogo(file);\n const response = await uploadProjectLogo(file);\n\n setValue('logo', response.data.logoFilename, {\n shouldDirty: true,\n });\n } catch (error) {\n const message = maybeAxiosError(error);\n setError('logo', { message });\n }\n };\n\n const { ref, ...projectLogoRest } = register('logo');\n\n const uploadInputRef = useRef<HTMLInputElement | null>(null);\n\n const handleClickUpload = () => {\n uploadInputRef.current?.click();\n };\n\n const handleDeleteLogo = (e: React.MouseEvent<HTMLButtonElement>) => {\n e.preventDefault();\n e.stopPropagation();\n setValue('logo', null, {\n shouldDirty: true,\n });\n };\n\n const handleAddCustom = () => {\n append({ title: '', value: '', url: '' });\n };\n\n const onSubmit = async (formData: ProjectData) => {\n try {\n clearErrors();\n await updateProjectData(formData);\n } catch (error) {\n const message = maybeAxiosError(error);\n setError('root', { message });\n }\n };\n\n // reset data to the initial state\n const onReset = () => {\n reset(data);\n };\n\n const isLoading = status === 'pending';\n\n return (\n <Panel.Section as='form' onSubmit={handleSubmit(onSubmit)} onKeyDown={(event) => preventEscape(event, onReset)}>\n <Panel.Card>\n <Panel.SubHeader>\n Project data\n <Panel.InlineElements>\n <Button onClick={onReset} disabled={isSubmitting || !isDirty}>\n Revert to saved\n </Button>\n <Button variant='primary' type='submit' disabled={!isDirty || !isValid} loading={isSubmitting}>\n Save\n </Button>\n </Panel.InlineElements>\n </Panel.SubHeader>\n <Panel.Divider />\n <Panel.Section>\n <Panel.Loader isLoading={isLoading} />\n <label>\n Project title\n <Input\n fluid\n maxLength={50}\n placeholder='Project title is shown in production views'\n {...register('title')}\n />\n </label>\n <Panel.Section style={{ marginTop: 0 }}>\n <label>\n Project logo\n <input\n type='file'\n style={{ display: 'none' }}\n accept='image/*'\n {...projectLogoRest}\n ref={(e) => {\n ref(e);\n uploadInputRef.current = e;\n }}\n onChange={handleUploadProjectLogo}\n />\n <Panel.Card className={style.uploadLogoCard}>\n {watch('logo') ? (\n <>\n <img src={`${projectLogoPath}/${watch('logo')}`} />\n <Button\n variant='subtle-destructive'\n disabled={isSubmitting || !watch('logo')}\n onClick={handleDeleteLogo}\n >\n <IoTrash />\n Delete\n </Button>\n </>\n ) : (\n <Button disabled={isSubmitting} onClick={handleClickUpload} type='button'>\n <IoDownloadOutline />\n Upload logo\n </Button>\n )}\n {errors?.logo?.message && <Panel.Error>{errors.logo.message}</Panel.Error>}\n </Panel.Card>\n </label>\n </Panel.Section>\n\n <label>\n Project description\n <Input fluid maxLength={100} placeholder='Euro Love, Malmö 2024' {...register('description')} />\n </label>\n <label>\n Project info\n <Textarea\n fluid\n maxLength={150}\n placeholder='Wi-Fi password: 1234'\n resize='vertical'\n {...register('info')}\n />\n </label>\n <label>\n Project QR code URL\n <Input fluid placeholder={documentationUrl} {...register('url')} />\n </label>\n <Panel.Section style={{ marginTop: 0 }}>\n <Panel.ListItem>\n <Panel.Field title='Custom data' description='' />\n <Button onClick={handleAddCustom}>\n Add <IoAdd />\n </Button>\n </Panel.ListItem>\n {fields.length > 0 &&\n fields.map((field, idx) => {\n const rowErrors = errors.custom?.[idx] as\n | {\n title?: { message?: string };\n value?: { message?: string };\n }\n | undefined;\n return (\n <div key={field.id} className={style.customDataItem}>\n <div className={style.titleRow}>\n <label className={style.title}>\n Title\n <Input\n fluid\n defaultValue={field.title}\n placeholder='Title of your custom data'\n {...register(`custom.${idx}.title`, {\n required: { value: true, message: 'Field cannot be empty' },\n })}\n />\n </label>\n <Button variant='subtle-destructive' onClick={() => remove(idx)}>\n <IoTrash />\n Delete\n </Button>\n </div>\n {rowErrors?.title?.message && <Panel.Error>{rowErrors.title.message}</Panel.Error>}\n <label>\n Text\n <Textarea\n fluid\n rows={3}\n resize='vertical'\n defaultValue={field.value}\n placeholder='Text of your custom data'\n {...register(`custom.${idx}.value`, {\n required: { value: true, message: 'Field cannot be empty' },\n })}\n />\n {rowErrors?.value?.message && <Panel.Error>{rowErrors.value.message}</Panel.Error>}\n </label>\n <label>\n Image URL (optional)\n <div className={style.customImage}>\n <Input\n fluid\n defaultValue={field.url}\n placeholder='Paste image URL (optional)'\n {...register(`custom.${idx}.url`)}\n />\n <div className={style.imageContainer}>\n {watch(`custom.${idx}.url`) && (\n <img src={watch(`custom.${idx}.url`)} alt='' loading='lazy' className='info__image' />\n )}\n </div>\n </div>\n </label>\n </div>\n );\n })}\n </Panel.Section>\n </Panel.Section>\n </Panel.Card>\n </Panel.Section>\n );\n}\n","import { lazy, useEffect, useRef, useState } from 'react';\n\nimport { getCSSContents, postCSSContents, restoreCSSContents } from '../../../../../common/api/assets';\nimport Button from '../../../../../common/components/buttons/Button';\nimport Info from '../../../../../common/components/info/Info';\nimport Modal from '../../../../../common/components/modal/Modal';\nimport * as Panel from '../../../panel-utils/PanelUtils';\n\nimport style from './StyleEditorModal.module.scss';\n\nconst CodeEditor = lazy(() => import('./StyleEditor'));\n\ninterface CodeEditorModalProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\ninterface CSSRef {\n getCss: () => string;\n}\n\nexport default function CodeEditorModal({ isOpen, onClose }: CodeEditorModalProps) {\n const [css, setCSS] = useState('');\n const [isDirty, setIsDirty] = useState(false);\n const [saveLoading, setSaveLoading] = useState(false);\n const [resetLoading, setResetLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const cssRef = useRef<CSSRef>(null);\n\n const handleRestore = async () => {\n try {\n setResetLoading(true);\n const defaultCss = await restoreCSSContents();\n setCSS(defaultCss);\n } catch (_error) {\n /** no error handling for now */\n } finally {\n setResetLoading(false);\n }\n };\n\n const handleSave = async () => {\n try {\n setSaveLoading(true);\n if (cssRef.current) {\n await postCSSContents(cssRef.current.getCss());\n setCSS(cssRef.current.getCss());\n setIsDirty(false);\n }\n } catch (_error) {\n /** no error handling for now */\n } finally {\n setSaveLoading(false);\n }\n };\n\n const clear = () => setCSS('');\n\n useEffect(() => {\n async function fetchServerCSS() {\n // check for isOpen to fetch recent css\n if (isOpen) {\n try {\n const css = await getCSSContents();\n setCSS(css);\n } catch (_error) {\n setError('Failed to load CSS from server');\n /** no error handling for now */\n }\n }\n }\n fetchServerCSS();\n }, [isOpen]);\n\n return (\n <Modal\n title='Edit CSS override'\n isOpen={isOpen}\n onClose={onClose}\n showCloseButton\n showBackdrop\n bodyElements={\n <CodeEditor ref={cssRef} initialValue={css} language='css' isDirty={isDirty} setIsDirty={setIsDirty} />\n }\n footerElements={\n <div className={style.column}>\n <Info>Invalid CSS will be refused by the browser</Info>\n {error && <Panel.Error className={style.right}>{`Error: ${error}`}</Panel.Error>}\n <Panel.InlineElements align='apart' className={style.editorActions}>\n <Button variant='ghosted' size='large' onClick={handleRestore} disabled={saveLoading || resetLoading}>\n Reset to example\n </Button>\n <Panel.InlineElements>\n <Button variant='ghosted' size='large' onClick={clear}>\n Clear\n </Button>\n <Button size='large' onClick={onClose}>\n Cancel\n </Button>\n <Button\n variant='primary'\n size='large'\n onClick={handleSave}\n disabled={saveLoading || resetLoading || !isDirty}\n loading={saveLoading}\n >\n Save changes\n </Button>\n </Panel.InlineElements>\n </Panel.InlineElements>\n </div>\n }\n />\n );\n}\n","import { useEffect } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { useDisclosure } from '@mantine/hooks';\nimport { ViewSettings as ViewSettingsType } from 'ontime-types';\n\nimport { maybeAxiosError } from '../../../../common/api/utils';\nimport Button from '../../../../common/components/buttons/Button';\nimport Info from '../../../../common/components/info/Info';\nimport { SwatchPickerRHF } from '../../../../common/components/input/colour-input/SwatchPicker';\nimport ExternalLink from '../../../../common/components/link/external-link/ExternalLink';\nimport Switch from '../../../../common/components/switch/Switch';\nimport useViewSettings from '../../../../common/hooks-query/useViewSettings';\nimport { preventEscape } from '../../../../common/utils/keyEvent';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport CodeEditorModal from './composite/StyleEditorModal';\n\nconst cssOverrideDocsUrl = 'https://docs.getontime.no/features/custom-styling/';\n\nexport default function ViewSettings() {\n const { data, status, mutateAsync } = useViewSettings();\n const [isCodeEditorOpen, codeEditorHandler] = useDisclosure();\n\n const {\n control,\n handleSubmit,\n setError,\n reset,\n setValue,\n watch,\n formState: { isSubmitting, isDirty, errors },\n } = useForm<ViewSettingsType>({\n defaultValues: data,\n values: data,\n resetOptions: {\n keepDirtyValues: true,\n },\n });\n\n // update form if we get new data from server\n useEffect(() => {\n if (data) {\n reset(data);\n }\n }, [data, reset]);\n\n const onSubmit = async (formData: ViewSettingsType) => {\n try {\n mutateAsync(formData);\n } catch (error) {\n const message = maybeAxiosError(error);\n setError('root', { message });\n }\n };\n\n const onReset = () => {\n reset(data);\n };\n\n if (!control) {\n return null;\n }\n\n return (\n <Panel.Section\n as='form'\n onSubmit={handleSubmit(onSubmit)}\n onKeyDown={(event) => preventEscape(event, onReset)}\n id='view-settings'\n >\n <Panel.Card>\n <Panel.SubHeader>\n View settings\n <Panel.InlineElements>\n <Button disabled={!isDirty} variant='ghosted' onClick={onReset}>\n Revert to saved\n </Button>\n <Button type='submit' loading={isSubmitting} disabled={!isDirty} variant='primary'>\n Save\n </Button>\n </Panel.InlineElements>\n </Panel.SubHeader>\n <Panel.Divider />\n <Info>\n You can customise the styles applied to Ontime views by providing overriding CSS rules.\n <br />\n <ExternalLink href={cssOverrideDocsUrl}>See the docs</ExternalLink>\n </Info>\n <Panel.Section>\n <Panel.Loader isLoading={status === 'pending'} />\n <Panel.Error>{errors.root?.message}</Panel.Error>\n <Panel.ListGroup>\n <CodeEditorModal isOpen={isCodeEditorOpen} onClose={codeEditorHandler.close} />\n <Panel.ListItem>\n <Panel.Field\n title='Override CSS styles'\n description='Enables overriding view styles with custom stylesheet'\n />\n <Switch\n size='large'\n checked={watch('overrideStyles')}\n onCheckedChange={(value: boolean) => setValue('overrideStyles', value, { shouldDirty: true })}\n />\n <Button onClick={codeEditorHandler.open} disabled={isSubmitting}>\n Edit CSS override\n </Button>\n </Panel.ListItem>\n </Panel.ListGroup>\n <Panel.ListGroup>\n <Panel.ListItem>\n <Panel.Field title='Timer colour' description='Default colour of a running timer' />\n <SwatchPickerRHF name='normalColor' control={control} />\n </Panel.ListItem>\n <Panel.ListItem>\n <Panel.Field title='Warning colour' description='Colour of a running timer in warning mode' />\n <SwatchPickerRHF name='warningColor' control={control} />\n </Panel.ListItem>\n <Panel.ListItem>\n <Panel.Field title='Danger colour' description='Colour of a running timer in danger mode' />\n <SwatchPickerRHF name='dangerColor' control={control} />\n </Panel.ListItem>\n </Panel.ListGroup>\n </Panel.Section>\n </Panel.Card>\n </Panel.Section>\n );\n}\n","import useScrollIntoView from '../../../../common/hooks/useScrollIntoView';\nimport type { PanelBaseProps } from '../../panel-list/PanelList';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nimport GeneralSettings from './GeneralSettings';\nimport ProjectData from './ProjectData';\nimport ViewSettings from './ViewSettings';\n\nexport default function SettingsPanel({ location }: PanelBaseProps) {\n const dataRef = useScrollIntoView<HTMLDivElement>('data', location);\n const generalRef = useScrollIntoView<HTMLDivElement>('general', location);\n const viewRef = useScrollIntoView<HTMLDivElement>('view', location);\n\n return (\n <>\n <Panel.Header>Settings</Panel.Header>\n <div ref={dataRef}>\n <ProjectData />\n </div>\n <div ref={generalRef}>\n <GeneralSettings />\n </div>\n <div ref={viewRef}>\n <ViewSettings />\n </div>\n </>\n );\n}\n","import { useRef } from 'react';\nimport { useDisclosure } from '@mantine/hooks';\n\nimport Button from '../../../../common/components/buttons/Button';\nimport Dialog from '../../../../common/components/dialog/Dialog';\nimport { useElectronEvent } from '../../../../common/hooks/useElectronEvent';\nimport { isLocalhost, isOntimeCloud } from '../../../../externals';\nimport * as Panel from '../../panel-utils/PanelUtils';\n\nexport default function ShutdownPanel() {\n const { isElectron, sendToElectron } = useElectronEvent();\n const [isOpen, handler] = useDisclosure();\n const cancelRef = useRef<HTMLButtonElement | null>(null);\n\n const sendShutdown = () => {\n sendToElectron('shutdown', 'now');\n handler.close();\n };\n\n const canShutdown = isElectron || isLocalhost;\n\n return (\n <>\n <Panel.Header>Shutdown Ontime</Panel.Header>\n <Panel.Section>\n {isOntimeCloud ? (\n <Panel.Highlight>\n For security reasons, shutting down the server must be done from the Ontime Cloud dashboard.\n </Panel.Highlight>\n ) : (\n <Panel.Paragraph>\n This will shutdown the Ontime server. <br />\n The runtime state will be lost, but your project is kept for next time.\n </Panel.Paragraph>\n )}\n <Button variant='destructive' onClick={handler.open} disabled={!(isElectron || isLocalhost)}>\n Shutdown ontime\n </Button>\n {!canShutdown && (\n <Panel.Description>Note: Ontime can only be shutdown from the machine it is running in.</Panel.Description>\n )}\n <Dialog\n isOpen={isOpen}\n title='Shutdown Ontime'\n showCloseButton\n onClose={handler.close}\n bodyElements={\n <Panel.Paragraph>\n This will shutdown the Ontime server. <br /> Are you sure?\n </Panel.Paragraph>\n }\n footerElements={\n <>\n <Button ref={cancelRef} onClick={handler.close} variant='ghosted-white'>\n Cancel\n </Button>\n <Button variant='destructive' onClick={sendShutdown} disabled={!canShutdown}>\n Shutdown\n </Button>\n </>\n }\n />\n </Panel.Section>\n </>\n );\n}\n","import { PropsWithChildren } from 'react';\nimport { IoClose } from 'react-icons/io5';\n\nimport Button from '../../../common/components/buttons/Button';\n\nimport style from './PanelContent.module.scss';\n\ninterface PanelContentProps {\n onClose: () => void;\n}\n\nexport default function PanelContent({ onClose, children }: PropsWithChildren<PanelContentProps>) {\n return (\n <div className={style.contentWrapper}>\n <div className={style.content}>{children}</div>\n <div className={style.corner}>\n <Button size='large' onClick={onClose}>\n Close settings <IoClose />\n </Button>\n </div>\n </div>\n );\n}\n","import { useMemo } from 'react';\n\nimport useAppVersion from '../../common/hooks-query/useAppVersion';\n\nexport type SettingsOption = {\n id: string;\n label: string;\n secondary?: Readonly<SettingsOption[]>;\n split?: boolean;\n highlight?: string;\n};\n\nconst staticOptions = [\n {\n id: 'settings',\n label: 'Settings',\n secondary: [\n { id: 'settings__data', label: 'Project data' },\n { id: 'settings__general', label: 'General settings' },\n { id: 'settings__view', label: 'View settings' },\n ],\n },\n {\n id: 'project',\n label: 'Project',\n split: true,\n secondary: [\n { id: 'project__create', label: 'Create...' },\n { id: 'project__list', label: 'Manage projects' },\n ],\n },\n {\n id: 'manage',\n label: 'Project settings',\n secondary: [\n { id: 'manage__defaults', label: 'Rundown defaults' },\n { id: 'manage__custom', label: 'Custom fields' },\n { id: 'manage__rundowns', label: 'Manage rundowns' },\n { id: 'manage__sheets', label: 'Import spreadsheet' },\n { id: 'manage__sheets', label: 'Sync with Google Sheet' },\n ],\n },\n {\n id: 'automation',\n label: 'Automation',\n split: true,\n secondary: [\n { id: 'automation__settings', label: 'Automation settings' },\n { id: 'automation__automations', label: 'Manage automations' },\n { id: 'automation__triggers', label: 'Manage triggers' },\n ],\n },\n {\n id: 'sharing',\n label: 'Sharing and reporting',\n split: true,\n secondary: [\n { id: 'sharing__presets', label: 'URL Presets' },\n {\n id: 'sharing__link',\n label: 'Share link',\n },\n { id: 'sharing__report', label: 'Runtime report' },\n ],\n },\n {\n id: 'network',\n label: 'Network',\n split: true,\n secondary: [\n {\n id: 'network__log',\n label: 'Event log',\n },\n {\n id: 'network__clients',\n label: 'Manage clients',\n },\n ],\n },\n {\n id: 'about',\n label: 'About',\n split: true,\n },\n {\n id: 'shutdown',\n label: 'Shutdown',\n split: true,\n },\n] as const;\n\nexport type SettingsOptionId = (typeof staticOptions)[number]['id'];\n\nexport function useAppSettingsMenu() {\n const { data } = useAppVersion();\n\n const options: Readonly<SettingsOption[]> = useMemo(\n () =>\n staticOptions.map((option) => ({\n ...option,\n highlight: option.id === 'about' && data.hasUpdates ? 'New version available' : undefined,\n })),\n [data],\n );\n\n return { options };\n}\n","import { useCallback, useMemo } from 'react';\nimport { useSearchParams } from 'react-router';\n\nimport { SettingsOptionId } from './useAppSettingsMenu';\n\nconst settingsKey = 'settings';\n\nexport default function useAppSettingsNavigation() {\n const [searchParams, setSearchParams] = useSearchParams();\n\n const selectedPanel = useMemo(\n () => (searchParams.get(settingsKey) as SettingsOptionId | null) ?? 'project',\n [searchParams],\n );\n const isOpen = useMemo(() => Boolean(searchParams.get(settingsKey)), [searchParams]);\n const [panel, location] = selectedPanel.split('__');\n\n const close = useCallback(() => {\n searchParams.delete(settingsKey);\n setSearchParams(searchParams);\n }, [searchParams, setSearchParams]);\n\n const setLocation = useCallback(\n (panelId: SettingsOptionId) => {\n searchParams.set(settingsKey, panelId);\n setSearchParams(searchParams);\n },\n [searchParams, setSearchParams],\n );\n\n return { isOpen, panel, location, setLocation, close };\n}\n","import { Fragment } from 'react';\n\nimport Tooltip from '../../../common/components/tooltip/Tooltip';\nimport { isKeyEnter } from '../../../common/utils/keyEvent';\nimport { cx } from '../../../common/utils/styleUtils';\nimport { SettingsOption, SettingsOptionId, useAppSettingsMenu } from '../useAppSettingsMenu';\nimport useAppSettingsNavigation from '../useAppSettingsNavigation';\n\nimport style from './PanelList.module.scss';\n\nexport interface PanelBaseProps {\n location?: string;\n}\n\ninterface PanelListProps extends PanelBaseProps {\n selectedPanel: string;\n}\n\nexport default function PanelList({ selectedPanel, location }: PanelListProps) {\n const { options } = useAppSettingsMenu();\n\n return (\n <ul className={style.tabs}>\n {options.map((panel) => {\n const isSelected = selectedPanel === panel.id;\n if (panel.highlight) {\n return (\n <Tooltip key={panel.id} text={panel.highlight} render={<span />}>\n <PanelListItem panel={panel} location={location} isSelected={isSelected} />\n </Tooltip>\n );\n }\n return <PanelListItem key={panel.id} panel={panel} location={location} isSelected={isSelected} />;\n })}\n </ul>\n );\n}\n\ninterface PanelListItemProps {\n panel: SettingsOption;\n isSelected: boolean;\n location?: string;\n}\n\nfunction PanelListItem(props: PanelListItemProps) {\n const { panel, isSelected, location } = props;\n const { setLocation } = useAppSettingsNavigation();\n\n const classes = cx([\n style.primary,\n isSelected && style.active,\n panel.split && style.split,\n panel.highlight && style.highlight,\n ]);\n\n return (\n <Fragment key={panel.id}>\n <li\n key={panel.id}\n onClick={() => setLocation(panel.id as SettingsOptionId)}\n onKeyDown={(event) => {\n isKeyEnter(event) && setLocation(panel.id as SettingsOptionId);\n }}\n className={classes}\n tabIndex={0}\n role='button'\n >\n {panel.label}\n </li>\n {panel.secondary?.map((secondary, index) => {\n const id = secondary.id.split('__')[1];\n const secondaryClasses = cx([style.secondary, isSelected && location === id ? style.active : null]);\n return (\n <li\n key={secondary.id + index}\n onClick={() => setLocation(secondary.id as SettingsOptionId)}\n onKeyDown={(event) => {\n isKeyEnter(event) && setLocation(secondary.id as SettingsOptionId);\n }}\n className={secondaryClasses}\n role='button'\n >\n {secondary.label}\n </li>\n );\n })}\n </Fragment>\n );\n}\n","import { ErrorBoundary } from '@sentry/react';\n\nimport { useKeyDown } from '../../common/hooks/useKeyDown';\n\nimport AboutPanel from './panel/about-panel/AboutPanel';\nimport AutomationPanel from './panel/automations-panel/AutomationPanel';\nimport FeaturePanel from './panel/feature-panel/FeaturePanel';\nimport ManagePanel from './panel/manage-panel/ManagePanel';\nimport NetworkLogPanel from './panel/network-panel/NetworkLogPanel';\nimport ProjectPanel from './panel/project-panel/ProjectPanel';\nimport SettingsPanel from './panel/settings-panel/SettingsPanel';\nimport ShutdownPanel from './panel/shutdown-panel/ShutdownPanel';\nimport PanelContent from './panel-content/PanelContent';\nimport PanelList from './panel-list/PanelList';\nimport useAppSettingsNavigation from './useAppSettingsNavigation';\n\nimport style from './AppSettings.module.scss';\n\nexport default function AppSettings() {\n const { close, panel, location, setLocation } = useAppSettingsNavigation();\n useKeyDown(close, 'Escape');\n\n return (\n <div className={style.container}>\n <ErrorBoundary>\n <PanelList selectedPanel={panel} location={location} />\n <PanelContent onClose={close}>\n {panel === 'settings' && <SettingsPanel location={location} />}\n {panel === 'project' && <ProjectPanel location={location} setLocation={setLocation} />}\n {panel === 'manage' && <ManagePanel location={location} />}\n {panel === 'automation' && <AutomationPanel location={location} />}\n {panel === 'sharing' && <FeaturePanel location={location} />}\n {panel === 'network' && <NetworkLogPanel location={location} />}\n {panel === 'about' && <AboutPanel />}\n {panel === 'shutdown' && <ShutdownPanel />}\n </PanelContent>\n </ErrorBoundary>\n </div>\n );\n}\n","import { memo, PropsWithChildren } from 'react';\n\nimport { ClockOverview, MetadataTimes, OffsetOverview, ProgressOverview, StartTimes } from './composite/TimeElements';\nimport TitleOverview from './composite/TitleOverview';\nimport { OverviewWrapper } from './OverviewWrapper';\n\nexport default memo(EditorOverview);\nfunction EditorOverview({ children }: PropsWithChildren) {\n return (\n <OverviewWrapper navElements={children}>\n <TitleOverview />\n <StartTimes />\n <ProgressOverview />\n <OffsetOverview />\n <MetadataTimes />\n <ClockOverview />\n </OverviewWrapper>\n );\n}\n","/**\n * Handles importing of a project in the welcome modal\n * the logic is mostly duplicated from ManageProjects.tsx\n */\n\nimport { ChangeEvent, useRef } from 'react';\n\nimport { uploadProjectFile } from '../../../../common/api/db';\nimport { invalidateAllCaches } from '../../../../common/api/utils';\nimport Button from '../../../../common/components/buttons/Button';\nimport { validateProjectFile } from '../../../../common/utils/uploadUtils';\n\ninterface ImportProjectButtonProps {\n onFinish: () => void;\n}\n\nexport default function ImportProjectButton({ onFinish }: ImportProjectButtonProps) {\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const handleSelectFile = () => {\n fileInputRef.current?.click();\n };\n\n const handleImport = async (event: ChangeEvent<HTMLInputElement>) => {\n const selectedFile = event.target?.files?.[0];\n if (!selectedFile) {\n return;\n }\n\n try {\n validateProjectFile(selectedFile);\n await uploadProjectFile(selectedFile);\n } catch (error) {\n /** we do not handle errors here */\n } finally {\n await invalidateAllCaches();\n onFinish();\n }\n };\n\n return (\n <>\n <input\n ref={fileInputRef}\n style={{ display: 'none' }}\n type='file'\n onChange={handleImport}\n accept='.json'\n data-testid='file-input'\n />\n\n <Button onClick={handleSelectFile}>Import project</Button>\n </>\n );\n}\n","import { useOrderedProjectList } from '../../../../common/hooks-query/useProjectList';\n\nimport style from '../Welcome.module.scss';\n\ninterface WelcomeProjectListProps {\n loadProject: (filename: string) => Promise<void>;\n onClose: () => void;\n}\n\nexport default function WelcomeProjectList(props: WelcomeProjectListProps) {\n const { loadProject, onClose } = props;\n const { data } = useOrderedProjectList();\n\n return (\n <tbody>\n {data.reorderedProjectFiles.map((project) => {\n if (project.filename === data.lastLoadedProject) {\n return (\n <tr className={style.current} key={project.filename} onClick={onClose}>\n <td>{project.filename}</td>\n <td>Loaded from last session</td>\n </tr>\n );\n }\n return (\n <tr key={project.filename} onClick={() => loadProject(project.filename)}>\n <td>{project.filename}</td>\n <td>{new Date(project.updatedAt).toLocaleString()}</td>\n </tr>\n );\n })}\n </tbody>\n );\n}\n","import { IoClose } from 'react-icons/io5';\nimport { useNavigate } from 'react-router';\n\nimport { loadDemo, loadProject } from '../../../common/api/db';\nimport { postShowWelcomeDialog } from '../../../common/api/settings';\nimport { invalidateAllCaches } from '../../../common/api/utils';\nimport Button from '../../../common/components/buttons/Button';\nimport IconButton from '../../../common/components/buttons/IconButton';\nimport Checkbox from '../../../common/components/checkbox/Checkbox';\nimport * as Editor from '../../../common/components/editor-utils/EditorUtils';\nimport ExternalLink from '../../../common/components/link/external-link/ExternalLink';\nimport Modal from '../../../common/components/modal/Modal';\nimport { appVersion, discordUrl, documentationUrl, websiteUrl } from '../../../externals';\n\nimport ImportProjectButton from './composite/ImportProjectButton';\nimport WelcomeProjectList from './composite/WelcomeProjectList';\n\nimport style from './Welcome.module.scss';\n\ninterface WelcomeProps {\n onClose: () => void;\n}\n\nexport default function Welcome({ onClose }: WelcomeProps) {\n const navigate = useNavigate();\n\n /** handle loading a selected project */\n const handleLoadProject = async (filename: string) => {\n try {\n await loadProject(filename);\n await invalidateAllCaches();\n onClose();\n } catch (_error) {\n /** no error handling for now */\n }\n };\n\n /** handle loading the demo project */\n const handleLoadDemo = async () => {\n try {\n await loadDemo();\n await invalidateAllCaches();\n onClose();\n } catch (_error) {\n /** no error handling for now */\n }\n };\n\n /** handle redirect to create modal */\n const handleCallCreate = () => {\n navigate('/editor?settings=project__create');\n onClose();\n };\n\n return (\n <Modal\n isOpen\n onClose={() => onClose()}\n showBackdrop\n bodyElements={\n <div className={style.sections}>\n <div className={style.about}>\n <img src='ontime-logo.png' alt='ontime' className={style.logo} />\n <div>Ontime v{appVersion}</div>\n <ExternalLink href={websiteUrl}>Website</ExternalLink>\n <ExternalLink href={documentationUrl}>Read the docs</ExternalLink>\n <ExternalLink href={discordUrl}>Discord server</ExternalLink>\n </div>\n <div className={style.column}>\n <div className={style.header}>\n Welcome to Ontime\n <IconButton aria-label='close welcome modal' variant='subtle-white' onClick={() => onClose()}>\n <IoClose />\n </IconButton>\n </div>\n <Editor.Title>Select project</Editor.Title>\n <div className={style.tableContainer}>\n <table className={style.table}>\n <thead>\n <tr>\n <th>File Name</th>\n <th>Last Used</th>\n </tr>\n </thead>\n <WelcomeProjectList loadProject={handleLoadProject} onClose={() => onClose()} />\n </table>\n </div>\n </div>\n </div>\n }\n footerElements={\n <div className={style.column}>\n <div className={style.buttonRow}>\n <Button onClick={handleLoadDemo}>Load demo project</Button>\n <ImportProjectButton onFinish={() => onClose()} />\n <Button variant='primary' onClick={handleCallCreate}>\n Create new...\n </Button>\n </div>\n <Editor.Label className={style.inline}>\n <Checkbox defaultChecked onCheckedChange={(checked) => postShowWelcomeDialog(checked)} />\n Show this modal on next startup\n </Editor.Label>\n </div>\n }\n />\n );\n}\n","import { useDialogStore } from '../../../common/stores/dialogStore';\n\nimport Welcome from './Welcome';\n\nexport default function WelcomePlacement() {\n const showDialog = useDialogStore((state) => state.showDialog);\n const clearDialog = useDialogStore((state) => state.clearDialog);\n\n if (!showDialog) {\n return null;\n }\n\n return <Welcome onClose={clearDialog} />;\n}\n","import { lazy, useCallback, useEffect } from 'react';\nimport { IoApps, IoClose, IoSettingsOutline } from 'react-icons/io5';\nimport { useDisclosure, useHotkeys } from '@mantine/hooks';\n\nimport IconButton from '../../common/components/buttons/IconButton';\nimport NavigationMenu from '../../common/components/navigation-menu/NavigationMenu';\nimport { useElectronListener } from '../../common/hooks/useElectronEvent';\nimport { useWindowTitle } from '../../common/hooks/useWindowTitle';\nimport AppSettings from '../../features/app-settings/AppSettings';\nimport useAppSettingsNavigation from '../../features/app-settings/useAppSettingsNavigation';\nimport EditorOverview from '../../features/overview/EditorOverview';\n\nimport WelcomePlacement from './welcome/WelcomePlacement';\n\nimport styles from './Editor.module.scss';\n\nconst Rundown = lazy(() => import('../../features/rundown/RundownExport'));\nconst TimerControl = lazy(() => import('../../features/control/playback/TimerControlExport'));\nconst MessageControl = lazy(() => import('../../features/control/message/MessageControlExport'));\n\nexport default function Editor() {\n const { isOpen: isSettingsOpen, setLocation, close } = useAppSettingsNavigation();\n const [isOpen, handler] = useDisclosure();\n\n useWindowTitle('Editor');\n\n // we need to register the listener to change the editor location\n useElectronListener();\n\n // listen to shutdown request from electron process\n useEffect(() => {\n if (window.process?.type === 'renderer') {\n window.ipcRenderer.on('user-request-shutdown', () => {\n setLocation('shutdown');\n });\n }\n }, [setLocation]);\n\n const toggleSettings = useCallback(() => {\n if (isSettingsOpen) {\n close();\n } else {\n setLocation('settings');\n }\n }, [close, isSettingsOpen, setLocation]);\n\n useHotkeys([['mod + ,', toggleSettings]]);\n\n return (\n <div className={styles.mainContainer} data-testid='event-editor'>\n <WelcomePlacement />\n <NavigationMenu isOpen={isOpen} onClose={handler.close} />\n <EditorOverview>\n <IconButton aria-label='Toggle navigation' variant='subtle-white' size='xlarge' onClick={handler.open}>\n <IoApps />\n </IconButton>\n <IconButton aria-label='Toggle settings' variant='subtle-white' size='xlarge' onClick={toggleSettings}>\n {isSettingsOpen ? <IoClose /> : <IoSettingsOutline />}\n </IconButton>\n </EditorOverview>\n {isSettingsOpen ? (\n <AppSettings />\n ) : (\n <div id='panels' className={styles.panelContainer}>\n <div className={styles.left}>\n <TimerControl />\n <MessageControl />\n </div>\n <Rundown />\n </div>\n )}\n </div>\n );\n}\n","import ProtectRoute from '../../common/components/protect-route/ProtectRoute';\n\nimport Editor from './Editor';\n\nexport default function ProtectedEditor() {\n return (\n <ProtectRoute permission='editor'>\n <Editor />\n </ProtectRoute>\n );\n}\n"],"file":"assets/ProtectedEditor-C_SYWpL2.js"}
|