mirror of
https://github.com/matrix-org/matrix-hookshot.git
synced 2025-03-10 21:19:13 +00:00

* Add dynamic imports for room configs. * Try to move code editor to imports * Load code editor on demand to save a bundle load. * Load fonts from npm * changelog * lint
108 lines
4.9 KiB
TypeScript
108 lines
4.9 KiB
TypeScript
import { FunctionComponent, createRef } from "preact";
|
|
import { useCallback, useState } from "preact/hooks"
|
|
import { BridgeConfig } from "../../BridgeAPI";
|
|
import { FeedConnectionState, FeedResponseItem } from "../../../src/Connections/FeedConnection";
|
|
import { ConnectionConfigurationProps, IRoomConfigText, RoomConfig } from "./RoomConfig";
|
|
import { Button, ButtonSet, InputField } from "../elements";
|
|
import styles from "./FeedConnection.module.scss";
|
|
|
|
import FeedsIcon from "../../icons/feeds.png";
|
|
|
|
const DEFAULT_TEMPLATE = "New post in $FEEDNAME: $LINK"
|
|
|
|
const FeedRecentResults: FunctionComponent<{item: FeedResponseItem}> = ({ item }) => {
|
|
if (!item.secrets) {
|
|
return null;
|
|
}
|
|
return <>
|
|
<h3>Recent feed results</h3>
|
|
{!item.secrets.lastResults.length && <span>There have been no recent updates for this feed.</span>}
|
|
<ul>
|
|
{item.secrets.lastResults.map(item => <li className={styles.resultListItem} key={item.timestamp}>
|
|
{new Date(item.timestamp).toLocaleString()}:
|
|
{item.ok && `✅ Successful fetch`}
|
|
{!item.ok && `⚠️ ${item.error}`}
|
|
</li>)}
|
|
</ul>
|
|
</>;
|
|
}
|
|
const DOCUMENTATION_LINK = "https://matrix-org.github.io/matrix-hookshot/latest/setup/feeds.html#feed-templates";
|
|
|
|
const ConnectionConfiguration: FunctionComponent<ConnectionConfigurationProps<ServiceConfig, FeedResponseItem, FeedConnectionState>> = ({existingConnection, onSave, onRemove, isMigrationCandidate, isUpdating}) => {
|
|
const urlRef = createRef<HTMLInputElement>();
|
|
const labelRef = createRef<HTMLInputElement>();
|
|
const templateRef = createRef<HTMLInputElement>();
|
|
const canSave = !existingConnection?.id || (existingConnection?.canEdit ?? false);
|
|
const canEdit = canSave && !isMigrationCandidate;
|
|
const [notifyOnFailure, setNotifyOnFailure] = useState<boolean>(existingConnection?.config.notifyOnFailure ?? false);
|
|
|
|
const handleSave = useCallback((evt: Event) => {
|
|
evt.preventDefault();
|
|
if (!canSave) {
|
|
return;
|
|
}
|
|
const url = urlRef?.current?.value || existingConnection?.config.url;
|
|
if (url) {
|
|
onSave({
|
|
url,
|
|
label: labelRef?.current?.value || existingConnection?.config.label,
|
|
template: templateRef.current?.value || existingConnection?.config.template,
|
|
notifyOnFailure,
|
|
})
|
|
}
|
|
}, [canSave, onSave, urlRef, labelRef, templateRef, notifyOnFailure, existingConnection]);
|
|
|
|
const onlyVisibleOnExistingConnection = !!existingConnection;
|
|
|
|
|
|
return <form onSubmit={handleSave}>
|
|
{ existingConnection && <FeedRecentResults item={existingConnection} />}
|
|
|
|
<InputField visible={true} label="URL" noPadding={true}>
|
|
<input ref={urlRef} disabled={!canEdit || !!existingConnection} type="text" value={existingConnection?.config.url} />
|
|
</InputField>
|
|
<InputField visible={true} label="Label" noPadding={true}>
|
|
<input ref={labelRef} disabled={!canSave} type="text" value={existingConnection?.config.label} />
|
|
</InputField>
|
|
<InputField visible={onlyVisibleOnExistingConnection} label="Send a notice on read failure" noPadding={true}>
|
|
<input disabled={!canSave} type="checkbox" checked={notifyOnFailure} onChange={useCallback(() => setNotifyOnFailure(v => !v), [])} />
|
|
</InputField>
|
|
<InputField visible={onlyVisibleOnExistingConnection} label="Template" noPadding={true}>
|
|
<input ref={templateRef} disabled={!canSave} type="text" value={existingConnection?.config.template} placeholder={DEFAULT_TEMPLATE} />
|
|
<p> See the <a target="_blank" rel="noopener noreferrer" href={DOCUMENTATION_LINK}>documentation</a> for help writing templates. </p>
|
|
</InputField>
|
|
<ButtonSet>
|
|
{ canSave && <Button type="submit" disabled={isUpdating}>{ existingConnection?.id ? "Save" : "Subscribe" }</Button>}
|
|
{ canEdit && existingConnection?.id && <Button intent="remove" onClick={onRemove} disabled={isUpdating}>Unsubscribe</Button>}
|
|
</ButtonSet>
|
|
|
|
</form>;
|
|
};
|
|
|
|
interface ServiceConfig {
|
|
pollIntervalSeconds: number,
|
|
}
|
|
|
|
const roomConfigText: IRoomConfigText = {
|
|
header: 'RSS/Atom feeds',
|
|
createNew: 'Subscribe to a feed',
|
|
listCanEdit: 'Feeds subscribed to',
|
|
listCantEdit: 'Feeds subscribed to',
|
|
};
|
|
|
|
const RoomConfigListItemFunc = (c: FeedResponseItem) => c.config.label || c.config.url;
|
|
|
|
const FeedsConfig: BridgeConfig = ({ roomId, showHeader }) => {
|
|
return <RoomConfig<ServiceConfig, FeedResponseItem, FeedConnectionState>
|
|
headerImg={FeedsIcon}
|
|
showHeader={showHeader}
|
|
roomId={roomId}
|
|
type="feeds"
|
|
connectionEventType="uk.half-shot.matrix-hookshot.feed"
|
|
text={roomConfigText}
|
|
listItemName={RoomConfigListItemFunc}
|
|
connectionConfigComponent={ConnectionConfiguration}
|
|
/>;
|
|
};
|
|
|
|
export default FeedsConfig; |