import * as React from "react"; import {useRef, useState} from "react"; import {Registry} from "tc-shared/events"; import {Translatable} from "tc-shared/ui/react-elements/i18n"; import {FlatInputField} from "tc-shared/ui/react-elements/InputField"; import {Settings, settings} from "tc-shared/settings"; import {Checkbox} from "tc-shared/ui/react-elements/Checkbox"; import {Tooltip} from "tc-shared/ui/react-elements/Tooltip"; import {TypeInfo} from "tc-shared/connectionlog/Definitions"; import { getRegisteredNotificationDispatchers, isNotificationEnabled } from "tc-shared/connectionlog/DispatcherNotifications"; import {isFocusRequestEnabled} from "tc-shared/connectionlog/DispatcherFocus"; const cssStyle = require("./Notifications.scss"); type NotificationState = "enabled" | "disabled" | "unavailable"; interface EventGroup { key: string; name: string; events?: (keyof TypeInfo)[]; subgroups?: EventGroup[]; } interface NotificationSettingsEvents { action_set_filter: { filter: string }, /* will toggle a notify_event_info */ action_toggle_group: { groupKey: string, collapsed: boolean }, action_set_state: { key: string, state: "log" | "notification" | "focus", value: NotificationState }, query_events: {}, query_event_info: { key: string }, notify_events: { groups: EventGroup[], focusEnabled: boolean }, notify_event_info: { key: string; name: string; focus: NotificationState; notification: NotificationState; log: NotificationState; }, notify_set_state_result: { key: string, state: "log" | "notification" | "focus", value: NotificationState } } const EventTableHeader = (props: { focus: boolean }) => { return (
Event
{!props.focus ? undefined :
Focus ( Draw focus to the window when the event occurs )}>
}
Notify ( Sending out a system notification )}>
Log ( Log the event within the client server log )}>
) }; const EventTableEntry = React.memo((props: { events: Registry, event: string, depth: number, focusEnabled: boolean }) => { const [name, setName] = useState(() => { props.events.fire_react("query_event_info", {key: props.event}); return undefined; }); const [notificationState, setNotificationState] = useState("unavailable"); const [logState, setLogState] = useState("unavailable"); const [focusState, setFocusState] = useState("unavailable"); const [notificationApplying, setNotificationApplying] = useState(false); const [logApplying, setLogApplying] = useState(false); const [focusApplying, setFocusApplying] = useState(false); props.events.reactUse("notify_event_info", event => { if (event.key !== props.event) return; setName(event.name); setNotificationState(event.notification); setLogState(event.log); setFocusState(event.focus); }); props.events.reactUse("action_set_state", event => { if (event.key !== props.event) return; switch (event.state) { case "notification": setNotificationApplying(true); break; case "log": setLogApplying(true); break; case "focus": setFocusApplying(true); break; } }); props.events.reactUse("notify_set_state_result", event => { if (event.key !== props.event) return; switch (event.state) { case "notification": setNotificationApplying(false); setNotificationState(event.value); break; case "log": setLogApplying(false); setLogState(event.value); break; case "focus": setFocusApplying(false); setFocusState(event.value); break; } }); let notificationElement, logElement, focusElement; if (notificationState === "unavailable") { notificationElement = null; } else { notificationElement = ( { props.events.fire("action_set_state", { key: props.event, state: "notification", value: value ? "enabled" : "disabled" }); }} disabled={notificationApplying}/> ); } if (logState === "unavailable") { logElement = null; } else { logElement = ( { props.events.fire("action_set_state", { key: props.event, state: "log", value: value ? "enabled" : "disabled" }); }} disabled={logApplying}/> ); } if (focusState === "unavailable") { focusElement = null; } else { focusElement = ( { props.events.fire("action_set_state", { key: props.event, state: "focus", value: value ? "enabled" : "disabled" }); }} disabled={focusApplying}/> ); } return (
{name || props.event}
{!props.focusEnabled ? undefined :
{focusElement}
}
{notificationElement}
{logElement}
); }); const EventTableGroupEntry = (props: { events: Registry, group: EventGroup, depth: number, focusEnabled: boolean }) => { const [collapsed, setCollapsed] = useState(false); props.events.reactUse("action_toggle_group", event => { if (event.groupKey !== props.group.key) return; setCollapsed(event.collapsed); }); return <>
props.events.fire("action_toggle_group", { collapsed: !collapsed, groupKey: props.group.key })}/> {props.group.name}
{props.focusEnabled ?
: undefined}
{!collapsed && props.group.events?.map(e => )} {!collapsed && props.group.subgroups?.map(e => )} ; }; const NoFilterResultsEmpty = (props: { shown: boolean }) => ( ); const EventTableBody = (props: { events: Registry, focusEnabled: boolean }) => { const refContainer = useRef(); const [events, setEvents] = useState<"loading" | EventGroup[]>(() => { props.events.fire("query_events"); return "loading"; }); props.events.reactUse("notify_events", event => setEvents(event.groups)); return (
{events === "loading" ? undefined : events.map(e => ) }
) }; const EventTable = (props: { events: Registry }) => { const [focusEnabled, setFocusEnabled] = useState(__build.target === "client"); props.events.reactUse("notify_events", event => { if (event.focusEnabled !== focusEnabled) setFocusEnabled(event.focusEnabled); }); return (
); }; const EventFilter = (props: { events: Registry }) => { return (
Filter Events} labelType={"floating"} onChange={text => props.events.fire_react("action_set_filter", {filter: text})} />
) }; export const NotificationSettings = () => { const events = useRef>(undefined); if (events.current === undefined) { events.current = new Registry(); initializeController(events.current); } return (<>
); }; const knownEventGroups: EventGroup[] = [ { key: "client", name: "Client events", subgroups: [ { key: "client-messages", name: "Messages", events: [ "client.poke.received", "client.poke.send", "private.message.send", "private.message.received" ] }, { key: "client-view", name: "View", events: [ "client.view.enter", "client.view.enter.own.channel", "client.view.move", "client.view.move.own", "client.view.move.own.channel", "client.view.leave", "client.view.leave.own.channel" ] } ] }, { key: "server", name: "Server", events: [ "global.message", "server.closed", "server.banned", ] }, { key: "connection", name: "Connection", events: [ "connection.begin", "connection.connected", "connection.failed" ] } ]; const groupNames: { [T in keyof TypeInfo]?: string } = {}; groupNames["client.poke.received"] = tr("You received a poke"); groupNames["client.poke.send"] = tr("You send a poke"); groupNames["private.message.send"] = tr("You received a private message"); groupNames["private.message.received"] = tr("You send a private message"); groupNames["client.view.enter"] = tr("A client enters your view"); groupNames["client.view.enter.own.channel"] = tr("A client enters your view and your channel"); groupNames["client.view.move"] = tr("A client switches/gets moved/kicked"); groupNames["client.view.move.own.channel"] = tr("A client switches/gets moved/kicked in to/out of your channel"); groupNames["client.view.move.own"] = tr("You've been moved or kicked"); groupNames["client.view.leave"] = tr("A client leaves/disconnects of your view"); groupNames["client.view.leave.own.channel"] = tr("A client leaves/disconnects of your channel"); groupNames["global.message"] = tr("A server message has been send"); groupNames["server.closed"] = tr("The server has been closed"); groupNames["server.banned"] = tr("You've been banned from the server"); groupNames["connection.begin"] = tr("You're connecting to a server"); groupNames["connection.connected"] = tr("You've successfully connected to the server"); groupNames["connection.failed"] = tr("You're connect attempt failed"); function initializeController(events: Registry) { let filter = undefined; events.on(["query_events", "action_set_filter"], event => { if (event.type === "action_set_filter") filter = event.as<"action_set_filter">().filter; const groupMapper = (group: EventGroup) => { const result = { name: group.name, events: group.events?.filter(e => { if (!filter) return true; if (e.toLowerCase().indexOf(filter) !== -1) return true; if (!groupNames[e]) return false; return groupNames[e].indexOf(filter) !== -1; }), key: group.key, subgroups: group.subgroups?.map(groupMapper).filter(e => !!e) } as EventGroup; if (!result.subgroups?.length && !result.events?.length) return undefined; return result; }; events.fire_react("notify_events", { groups: knownEventGroups.map(groupMapper).filter(e => !!e), focusEnabled: __build.target === "client" }); }); events.on("query_event_info", event => { events.fire_react("notify_event_info", { key: event.key, name: groupNames[event.key] || event.key, log: settings.getValue(Settings.FN_EVENTS_LOG_ENABLED(event.key), true) ? "enabled" : "disabled", notification: getRegisteredNotificationDispatchers().findIndex(e => e as any === event.key) === -1 ? "unavailable" : isNotificationEnabled(event.key as any) ? "enabled" : "disabled", focus: isFocusRequestEnabled(event.key as any) ? "enabled" : "disabled" }); }); events.on("action_set_state", event => { switch (event.state) { case "log": settings.setValue(Settings.FN_EVENTS_LOG_ENABLED(event.key), event.value === "enabled"); break; case "notification": settings.setValue(Settings.FN_EVENTS_NOTIFICATION_ENABLED(event.key), event.value === "enabled"); break; case "focus": settings.setValue(Settings.FN_EVENTS_FOCUS_ENABLED(event.key), event.value === "enabled"); break; } events.fire_react("notify_set_state_result", { key: event.key, state: event.state, value: event.value }); }); }