From a9537c7961a05970c68d591a8e404c5034c246e2 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Fri, 21 Apr 2023 11:47:29 +0100 Subject: [PATCH] Add option to enable/disable feed failure notices. (#716) * Add new notifyOnFailure option * Disable state buttons when updating is set * Linting --- changelog.d/716.feature | 1 + src/Connections/FeedConnection.ts | 5 +++++ src/FormatUtil.ts | 2 +- src/Notifications/GitLabWatcher.ts | 3 --- src/Widgets/GoNebMigrator.ts | 2 +- tests/FeedReader.spec.ts | 8 +++---- web/components/elements/Button.module.scss | 4 ++++ web/components/roomConfig/FeedsConfig.tsx | 22 ++++++++++++------- .../roomConfig/GenericWebhookConfig.tsx | 6 ++--- .../roomConfig/GithubRepoConfig.tsx | 6 ++--- .../roomConfig/GitlabRepoConfig.tsx | 6 ++--- .../roomConfig/JiraProjectConfig.tsx | 6 ++--- web/components/roomConfig/RoomConfig.tsx | 13 +++++++++++ 13 files changed, 55 insertions(+), 29 deletions(-) create mode 100644 changelog.d/716.feature diff --git a/changelog.d/716.feature b/changelog.d/716.feature new file mode 100644 index 00000000..958c5451 --- /dev/null +++ b/changelog.d/716.feature @@ -0,0 +1 @@ +Notifications for RSS feed failures can now be toggled on and off. The feature is now **off** by default. \ No newline at end of file diff --git a/src/Connections/FeedConnection.ts b/src/Connections/FeedConnection.ts index 7a561ee7..ed403834 100644 --- a/src/Connections/FeedConnection.ts +++ b/src/Connections/FeedConnection.ts @@ -25,6 +25,7 @@ export interface FeedConnectionState extends IConnectionState { url: string; label?: string; template?: string; + notifyOnFailure?: boolean; } export interface FeedConnectionSecrets { @@ -225,6 +226,10 @@ export class FeedConnection extends BaseConnection implements IConnection { // To avoid short term failures bubbling up, if the error is serious, we still bubble. return; } + if (!this.state.notifyOnFailure) { + // User hasn't opted into notifications on failure + return; + } if (!this.hasError) { await this.intent.sendEvent(this.roomId, { msgtype: 'm.notice', diff --git a/src/FormatUtil.ts b/src/FormatUtil.ts index c2532ce0..f0424b39 100644 --- a/src/FormatUtil.ts +++ b/src/FormatUtil.ts @@ -4,7 +4,7 @@ import emoji from "node-emoji"; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore import { JiraIssue } from './Jira/Types'; -import { formatLabels, getPartialBodyForJiraIssue, hashId, getPartialBodyForGithubIssue, getPartialBodyForGithubRepo, MinimalGitHubRepo, MinimalGitHubIssue } from "./libRs"; +import { formatLabels, getPartialBodyForJiraIssue, hashId, getPartialBodyForGithubIssue, getPartialBodyForGithubRepo, MinimalGitHubIssue } from "./libRs"; interface IMinimalPR { html_url: string; diff --git a/src/Notifications/GitLabWatcher.ts b/src/Notifications/GitLabWatcher.ts index 264294ec..f18f5e9f 100644 --- a/src/Notifications/GitLabWatcher.ts +++ b/src/Notifications/GitLabWatcher.ts @@ -29,8 +29,5 @@ export class GitLabWatcher extends EventEmitter implements NotificationWatcherTa private async getNotifications() { log.info(`Fetching events from GitLab for ${this.userId}`); - const events = await this.client.getEvents({ - after: new Date(this.since) - }); } } \ No newline at end of file diff --git a/src/Widgets/GoNebMigrator.ts b/src/Widgets/GoNebMigrator.ts index aacceaf8..67539a3e 100644 --- a/src/Widgets/GoNebMigrator.ts +++ b/src/Widgets/GoNebMigrator.ts @@ -2,7 +2,7 @@ import { Logger } from "matrix-appservice-bridge"; import axios from "axios"; import { FeedConnection, FeedConnectionState, GitHubRepoConnection, GitHubRepoConnectionState } from "../Connections"; -import { AllowedEvents as GitHubAllowedEvents, AllowedEventsNames as GitHubAllowedEventsNames } from "../Connections/GithubRepo"; +import { AllowedEventsNames as GitHubAllowedEventsNames } from "../Connections/GithubRepo"; const log = new Logger("GoNebMigrator"); diff --git a/tests/FeedReader.spec.ts b/tests/FeedReader.spec.ts index ed4feeae..153be2fd 100644 --- a/tests/FeedReader.spec.ts +++ b/tests/FeedReader.spec.ts @@ -14,7 +14,7 @@ class MockConnectionManager extends EventEmitter { super(); } - getAllConnectionsOfType(type: unknown) { + getAllConnectionsOfType() { return this.connections; } } @@ -32,7 +32,7 @@ class MockMessageQueue extends EventEmitter implements MessageQueue { this.emit('pushed', data, single); } - async pushWait(data: MessageQueueMessage, timeout?: number, single?: boolean): Promise { + async pushWait(): Promise { throw new Error('Not yet implemented'); } } @@ -73,13 +73,13 @@ describe("FeedReader", () => { config, cm, mq, { getAccountData: () => Promise.resolve({ 'http://test/': [] } as unknown as T), - setAccountData: () => Promise.resolve(), + setAccountData: () => Promise.resolve(), }, new MockHttpClient({ headers: {}, data: feedContents } as AxiosResponse) as unknown as AxiosStatic, ); const event: any = await new Promise((resolve) => { - mq.on('pushed', (data, _) => { resolve(data); feedReader.stop() }); + mq.on('pushed', (data) => { resolve(data); feedReader.stop() }); }); expect(event.eventName).to.equal('feed.entry'); diff --git a/web/components/elements/Button.module.scss b/web/components/elements/Button.module.scss index 5dcc6450..26fadb5e 100644 --- a/web/components/elements/Button.module.scss +++ b/web/components/elements/Button.module.scss @@ -22,4 +22,8 @@ .remove { color: #FF5B55; background-color: transparent; + + &:disabled { + background-color: transparent; + } } \ No newline at end of file diff --git a/web/components/roomConfig/FeedsConfig.tsx b/web/components/roomConfig/FeedsConfig.tsx index b64639af..e4663dab 100644 --- a/web/components/roomConfig/FeedsConfig.tsx +++ b/web/components/roomConfig/FeedsConfig.tsx @@ -28,10 +28,11 @@ const FeedRecentResults: FunctionComponent<{item: FeedResponseItem}> = ({ item } } const DOCUMENTATION_LINK = "https://matrix-org.github.io/matrix-hookshot/latest/setup/feeds.html#feed-templates"; -const ConnectionConfiguration: FunctionComponent> = ({existingConnection, onSave, onRemove, isMigrationCandidate}) => { +const ConnectionConfiguration: FunctionComponent> = ({existingConnection, onSave, onRemove, isMigrationCandidate, isUpdating}) => { const urlRef = createRef(); const labelRef = createRef(); const templateRef = createRef(); + const notifyRef = createRef(); const canSave = !existingConnection?.id || (existingConnection?.canEdit ?? false); const canEdit = canSave && !isMigrationCandidate; const handleSave = useCallback((evt: Event) => { @@ -45,10 +46,13 @@ const ConnectionConfiguration: FunctionComponent { existingConnection && } @@ -58,14 +62,16 @@ const ConnectionConfiguration: FunctionComponent - + + + +

See the documentation for help writing templates.

- - { canSave && } - { canEdit && existingConnection?.id && } + { canSave && } + { canEdit && existingConnection?.id && } ; diff --git a/web/components/roomConfig/GenericWebhookConfig.tsx b/web/components/roomConfig/GenericWebhookConfig.tsx index a91cfce8..7a6648c6 100644 --- a/web/components/roomConfig/GenericWebhookConfig.tsx +++ b/web/components/roomConfig/GenericWebhookConfig.tsx @@ -28,7 +28,7 @@ const EXAMPLE_SCRIPT = `if (data.counter === undefined) { const DOCUMENTATION_LINK = "https://matrix-org.github.io/matrix-hookshot/latest/setup/webhooks.html#script-api"; const CODE_MIRROR_EXTENSIONS = [javascript({})]; -const ConnectionConfiguration: FunctionComponent> = ({serviceConfig, existingConnection, onSave, onRemove}) => { +const ConnectionConfiguration: FunctionComponent> = ({serviceConfig, existingConnection, onSave, onRemove, isUpdating}) => { const [transFn, setTransFn] = useState(existingConnection?.config.transformationFunction as string || EXAMPLE_SCRIPT); const [transFnEnabled, setTransFnEnabled] = useState(serviceConfig.allowJsTransformationFunctions && !!existingConnection?.config.transformationFunction); const nameRef = createRef(); @@ -67,8 +67,8 @@ const ConnectionConfiguration: FunctionComponent See the documentation for help writing transformation functions

- { canEdit && } - { canEdit && existingConnection && } + { canEdit && } + { canEdit && existingConnection && } ; }; diff --git a/web/components/roomConfig/GithubRepoConfig.tsx b/web/components/roomConfig/GithubRepoConfig.tsx index 48a7045c..eb749c44 100644 --- a/web/components/roomConfig/GithubRepoConfig.tsx +++ b/web/components/roomConfig/GithubRepoConfig.tsx @@ -18,7 +18,7 @@ function getRepoFullName(state: GitHubRepoConnectionState) { } const ConnectionConfiguration: FunctionComponent> = ({ - showAuthPrompt, loginLabel, serviceConfig, api, existingConnection, onSave, onRemove + showAuthPrompt, loginLabel, serviceConfig, api, existingConnection, onSave, onRemove, isUpdating }) => { // Assume true if we have no auth prompt. const [authedResponse, setAuthResponse] = useState(null); @@ -159,8 +159,8 @@ const ConnectionConfiguration: FunctionComponent - { canEdit && consideredAuthenticated && } - { canEdit && existingConnection?.id && } + { canEdit && consideredAuthenticated && } + { canEdit && existingConnection?.id && } ; }; diff --git a/web/components/roomConfig/GitlabRepoConfig.tsx b/web/components/roomConfig/GitlabRepoConfig.tsx index e2876e01..084b0068 100644 --- a/web/components/roomConfig/GitlabRepoConfig.tsx +++ b/web/components/roomConfig/GitlabRepoConfig.tsx @@ -10,7 +10,7 @@ import { DropItem } from "../elements/DropdownSearch"; import { ConnectionSearch } from "../elements/ConnectionSearch"; const EventType = "uk.half-shot.matrix-hookshot.gitlab.repository"; -const ConnectionConfiguration: FunctionComponent> = ({api, existingConnection, onSave, onRemove }) => { +const ConnectionConfiguration: FunctionComponent> = ({api, existingConnection, onSave, onRemove, isUpdating }) => { const [enabledHooks, setEnabledHooks] = useState(existingConnection?.config.enableHooks || []); const toggleEnabledHook = useCallback((evt: any) => { @@ -107,8 +107,8 @@ const ConnectionConfiguration: FunctionComponent - { canEdit && } - { canEdit && existingConnection && } + { canEdit && } + { canEdit && existingConnection && } ; }; diff --git a/web/components/roomConfig/JiraProjectConfig.tsx b/web/components/roomConfig/JiraProjectConfig.tsx index ed048c6c..2261e3df 100644 --- a/web/components/roomConfig/JiraProjectConfig.tsx +++ b/web/components/roomConfig/JiraProjectConfig.tsx @@ -11,7 +11,7 @@ import { DropItem } from "../elements/DropdownSearch"; const EventType = "uk.half-shot.matrix-hookshot.jira.project"; -const ConnectionConfiguration: FunctionComponent> = ({api, existingConnection, onSave, onRemove }) => { +const ConnectionConfiguration: FunctionComponent> = ({api, existingConnection, onSave, onRemove, isUpdating }) => { const [allowedEvents, setAllowedEvents] = useState(existingConnection?.config.events || ['issue_created']); const toggleEvent = useCallback((evt: Event) => { @@ -93,8 +93,8 @@ const ConnectionConfiguration: FunctionComponent - { canEdit && } - { canEdit && existingConnection && } + { canEdit && } + { canEdit && existingConnection && } ; }; diff --git a/web/components/roomConfig/RoomConfig.tsx b/web/components/roomConfig/RoomConfig.tsx index 03da44d2..b9f8294a 100644 --- a/web/components/roomConfig/RoomConfig.tsx +++ b/web/components/roomConfig/RoomConfig.tsx @@ -13,6 +13,8 @@ export interface ConnectionConfigurationProps void, + isUpdating: boolean, + isMigrationCandidate?: boolean, existingConnection?: ConnectionType; onRemove?: () => void, api: BridgeAPI; @@ -64,6 +66,7 @@ export const RoomConfig = function(false); // We need to increment this every time we create a connection in order to properly reset the state. const [ newConnectionKey, incrementConnectionKey ] = useReducer(n => n+1, 0); + const [ updatingConnection, isUpdatingConnection ] = useState(false); const clearCurrentError = () => { setError(error => error?.forPrevious ? error : null); @@ -125,6 +128,7 @@ export const RoomConfig = function { + isUpdatingConnection(true); api.createConnection(roomId, connectionEventType, config).then(result => { // Force reload incrementConnectionKey(undefined); @@ -140,6 +144,8 @@ export const RoomConfig = function { + isUpdatingConnection(false); }); }, [api, roomId, connectionEventType]); @@ -167,6 +173,7 @@ export const RoomConfig = function} } { !error && connections === null && } @@ -178,6 +185,7 @@ export const RoomConfig = function { + isUpdatingConnection(true); api.updateConnection(roomId, c.id, config).then(() => { c.config = config; // Force reload @@ -189,6 +197,8 @@ export const RoomConfig = function { + isUpdatingConnection(false); }); }} onRemove={() => { @@ -203,6 +213,7 @@ export const RoomConfig = function ) } @@ -214,6 +225,8 @@ export const RoomConfig = function ) }