mirror of
https://github.com/matrix-org/matrix-hookshot.git
synced 2025-03-10 13:17:08 +00:00
Convert bridgeAPI usages to preact context. (#871)
* Fix widget client only talking to localhost * Improve error text around widget communication. * changelog * Remove unused. * Simplify code by using a context for bridge API.
This commit is contained in:
parent
caaabbc300
commit
6d3800a018
1
changelog.d/870.bugfix
Normal file
1
changelog.d/870.bugfix
Normal file
@ -0,0 +1 @@
|
|||||||
|
Fix widgets failing with "Request timed out".
|
59
web/App.tsx
59
web/App.tsx
@ -7,6 +7,7 @@ import { LoadingSpinner } from './components/elements/LoadingSpinner';
|
|||||||
import AdminSettings from './components/AdminSettings';
|
import AdminSettings from './components/AdminSettings';
|
||||||
import RoomConfigView from './components/RoomConfigView';
|
import RoomConfigView from './components/RoomConfigView';
|
||||||
import { Alert } from '@vector-im/compound-web';
|
import { Alert } from '@vector-im/compound-web';
|
||||||
|
import { BridgeContext } from './context';
|
||||||
|
|
||||||
interface IMinimalState {
|
interface IMinimalState {
|
||||||
error: string|null,
|
error: string|null,
|
||||||
@ -115,43 +116,39 @@ export default class App extends Component<void, IState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const style = {
|
||||||
|
padding: 'embedType' in this.state && this.state.embedType === EmbedType.IntegrationManager ? "0" : "16px",
|
||||||
|
};
|
||||||
|
if (this.state.error) {
|
||||||
|
return <div style={style}><Alert type="critical" title="An error occured">{this.state.error}</Alert></div>;
|
||||||
|
} else if (this.state.busy) {
|
||||||
|
return <div style={style}><LoadingSpinner /></div>;
|
||||||
|
} else if ("kind" in this.state === false) {
|
||||||
|
console.warn("invalid state", this.state);
|
||||||
|
return <div style={style}><Alert type="critical" title="An error occured">Widget got into an invalid state.</Alert></div>;
|
||||||
|
}
|
||||||
|
|
||||||
// Return the App component.
|
// Return the App component.
|
||||||
let content;
|
let content;
|
||||||
if (this.state.error) {
|
|
||||||
content = <Alert type="critical" title="An error occured">{this.state.error}</Alert>;
|
|
||||||
} else if (this.state.busy) {
|
|
||||||
content = <LoadingSpinner />;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("kind" in this.state) {
|
if (this.state.kind === "admin") {
|
||||||
if (this.state.roomState && this.state.kind === "admin") {
|
content = <AdminSettings roomState={this.state.roomState} />;
|
||||||
content = <AdminSettings bridgeApi={this.state.bridgeApi} roomState={this.state.roomState} />;
|
}else if (this.state.kind === "roomConfig") {
|
||||||
} else if (this.state.kind === "invite") {
|
content = <RoomConfigView
|
||||||
// Fall through for now, we don't support invite widgets *just* yet.
|
roomId={this.state.roomId}
|
||||||
} else if (this.state.kind === "roomConfig") {
|
supportedServices={this.state.supportedServices}
|
||||||
content = <RoomConfigView
|
serviceScope={this.state.serviceScope}
|
||||||
roomId={this.state.roomId}
|
embedType={this.state.embedType}
|
||||||
supportedServices={this.state.supportedServices}
|
/>;
|
||||||
serviceScope={this.state.serviceScope}
|
} else {
|
||||||
embedType={this.state.embedType}
|
return <div style={style}><Alert type="critical" title="An error occured">Unknown widget kind.</Alert></div>;
|
||||||
bridgeApi={this.state.bridgeApi}
|
|
||||||
widgetApi={this.state.widgetApi}
|
|
||||||
/>;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!content) {
|
|
||||||
console.warn("invalid state", this.state);
|
|
||||||
content = <b>Invalid state</b>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const embedType = 'embedType' in this.state ? this.state.embedType : EmbedType.Default;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{
|
<div style={style}>
|
||||||
padding: embedType === "integration-manager" ? "0" : "16px",
|
<BridgeContext.Provider value={{bridgeApi: this.state.bridgeApi}}>
|
||||||
}}>
|
{content}
|
||||||
{content}
|
</BridgeContext.Provider>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,6 @@ export enum EmbedType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type BridgeConfig = FunctionComponent<{
|
export type BridgeConfig = FunctionComponent<{
|
||||||
api: BridgeAPI,
|
|
||||||
roomId: string,
|
roomId: string,
|
||||||
showHeader: boolean,
|
showHeader: boolean,
|
||||||
}>;
|
}>;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { WidgetApi } from "matrix-widget-api";
|
|
||||||
import { useState } from "preact/hooks"
|
import { useState } from "preact/hooks"
|
||||||
import { BridgeAPI, BridgeConfig, EmbedType } from "../BridgeAPI";
|
import { BridgeConfig, EmbedType } from "../BridgeAPI";
|
||||||
import style from "./RoomConfigView.module.scss";
|
import style from "./RoomConfigView.module.scss";
|
||||||
import { ConnectionCard } from "./ConnectionCard";
|
import { ConnectionCard } from "./ConnectionCard";
|
||||||
import { FeedsConfig } from "./roomConfig/FeedsConfig";
|
import { FeedsConfig } from "./roomConfig/FeedsConfig";
|
||||||
@ -17,8 +16,6 @@ import WebhookIcon from "../icons/webhook.png";
|
|||||||
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
widgetApi: WidgetApi,
|
|
||||||
bridgeApi: BridgeAPI,
|
|
||||||
supportedServices: {[service: string]: boolean},
|
supportedServices: {[service: string]: boolean},
|
||||||
serviceScope?: string,
|
serviceScope?: string,
|
||||||
embedType: EmbedType,
|
embedType: EmbedType,
|
||||||
@ -86,7 +83,6 @@ export default function RoomConfigView(props: IProps) {
|
|||||||
const ConfigComponent = connections[activeConnectionType].component;
|
const ConfigComponent = connections[activeConnectionType].component;
|
||||||
content = <ConfigComponent
|
content = <ConfigComponent
|
||||||
roomId={props.roomId}
|
roomId={props.roomId}
|
||||||
api={props.bridgeApi}
|
|
||||||
showHeader={props.embedType !== EmbedType.IntegrationManager}
|
showHeader={props.embedType !== EmbedType.IntegrationManager}
|
||||||
/>;
|
/>;
|
||||||
} else {
|
} else {
|
||||||
@ -109,6 +105,7 @@ export default function RoomConfigView(props: IProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return <div className={style.root}>
|
return <div className={style.root}>
|
||||||
|
|
||||||
{!serviceScope && activeConnectionType &&
|
{!serviceScope && activeConnectionType &&
|
||||||
<header>
|
<header>
|
||||||
<span className={style.backButton} onClick={() => setActiveConnectionType(null)}>
|
<span className={style.backButton} onClick={() => setActiveConnectionType(null)}>
|
||||||
|
@ -1,24 +1,23 @@
|
|||||||
import { useCallback, useEffect, useState } from "preact/hooks";
|
import { useCallback, useContext, useEffect, useState } from "preact/hooks";
|
||||||
import { GetAuthResponse } from "../../../src/Widgets/BridgeWidgetInterface";
|
import { GetAuthResponse } from "../../../src/Widgets/BridgeWidgetInterface";
|
||||||
import { BridgeAPI } from "../../BridgeAPI";
|
|
||||||
import { Button } from "../elements";
|
import { Button } from "../elements";
|
||||||
|
import { BridgeContext } from "../../context";
|
||||||
|
|
||||||
const PollAuthEveryMs = 3000;
|
const PollAuthEveryMs = 3000;
|
||||||
|
|
||||||
|
|
||||||
export const ServiceAuth = ({
|
export const ServiceAuth = ({
|
||||||
api,
|
|
||||||
service,
|
service,
|
||||||
loginLabel = "Log in",
|
loginLabel = "Log in",
|
||||||
authState,
|
authState,
|
||||||
onAuthSucceeded,
|
onAuthSucceeded,
|
||||||
}: {
|
}: {
|
||||||
api: BridgeAPI,
|
|
||||||
service: string,
|
service: string,
|
||||||
authState: GetAuthResponse,
|
authState: GetAuthResponse,
|
||||||
onAuthSucceeded: () => void,
|
onAuthSucceeded: () => void,
|
||||||
loginLabel?: string,
|
loginLabel?: string,
|
||||||
}) => {
|
}) => {
|
||||||
|
const api = useContext(BridgeContext).bridgeApi;
|
||||||
const [pollStateId, setPollStateId] = useState<string|null>();
|
const [pollStateId, setPollStateId] = useState<string|null>();
|
||||||
|
|
||||||
const pollAuth = useCallback(async (pollId) => {
|
const pollAuth = useCallback(async (pollId) => {
|
||||||
|
@ -92,12 +92,11 @@ const roomConfigText: IRoomConfigText = {
|
|||||||
|
|
||||||
const RoomConfigListItemFunc = (c: FeedResponseItem) => c.config.label || c.config.url;
|
const RoomConfigListItemFunc = (c: FeedResponseItem) => c.config.label || c.config.url;
|
||||||
|
|
||||||
export const FeedsConfig: BridgeConfig = ({ api, roomId, showHeader }) => {
|
export const FeedsConfig: BridgeConfig = ({ roomId, showHeader }) => {
|
||||||
|
|
||||||
return <RoomConfig<ServiceConfig, FeedResponseItem, FeedConnectionState>
|
return <RoomConfig<ServiceConfig, FeedResponseItem, FeedConnectionState>
|
||||||
headerImg={FeedsIcon}
|
headerImg={FeedsIcon}
|
||||||
showHeader={showHeader}
|
showHeader={showHeader}
|
||||||
api={api}
|
|
||||||
roomId={roomId}
|
roomId={roomId}
|
||||||
type="feeds"
|
type="feeds"
|
||||||
connectionEventType="uk.half-shot.matrix-hookshot.feed"
|
connectionEventType="uk.half-shot.matrix-hookshot.feed"
|
||||||
|
@ -111,12 +111,11 @@ const RoomConfigText = {
|
|||||||
|
|
||||||
const RoomConfigListItemFunc = (c: GenericHookResponseItem) => c.config.name;
|
const RoomConfigListItemFunc = (c: GenericHookResponseItem) => c.config.name;
|
||||||
|
|
||||||
export const GenericWebhookConfig: BridgeConfig = ({ api, roomId, showHeader }) => {
|
export const GenericWebhookConfig: BridgeConfig = ({ roomId, showHeader }) => {
|
||||||
return <RoomConfig<ServiceConfig, GenericHookResponseItem, GenericHookConnectionState>
|
return <RoomConfig<ServiceConfig, GenericHookResponseItem, GenericHookConnectionState>
|
||||||
headerImg={WebhookIcon}
|
headerImg={WebhookIcon}
|
||||||
darkHeaderImg={true}
|
darkHeaderImg={true}
|
||||||
showHeader={showHeader}
|
showHeader={showHeader}
|
||||||
api={api}
|
|
||||||
roomId={roomId}
|
roomId={roomId}
|
||||||
type="generic"
|
type="generic"
|
||||||
connectionEventType="uk.half-shot.matrix-hookshot.generic.hook"
|
connectionEventType="uk.half-shot.matrix-hookshot.generic.hook"
|
||||||
|
@ -5,11 +5,12 @@ import { EventHookCheckbox } from '../elements/EventHookCheckbox';
|
|||||||
import { FunctionComponent, createRef } from "preact";
|
import { FunctionComponent, createRef } from "preact";
|
||||||
import { GitHubRepoConnectionState, GitHubRepoResponseItem, GitHubRepoConnectionRepoTarget, GitHubRepoConnectionOrgTarget } from "../../../src/Connections/GithubRepo";
|
import { GitHubRepoConnectionState, GitHubRepoResponseItem, GitHubRepoConnectionRepoTarget, GitHubRepoConnectionOrgTarget } from "../../../src/Connections/GithubRepo";
|
||||||
import { InputField, ButtonSet, Button } from "../elements";
|
import { InputField, ButtonSet, Button } from "../elements";
|
||||||
import { useState, useCallback, useMemo, useEffect } from "preact/hooks";
|
import { useState, useCallback, useMemo, useEffect, useContext } from "preact/hooks";
|
||||||
import { DropItem } from "../elements/DropdownSearch";
|
import { DropItem } from "../elements/DropdownSearch";
|
||||||
import ConnectionSearch from "../elements/ConnectionSearch";
|
import ConnectionSearch from "../elements/ConnectionSearch";
|
||||||
import { ServiceAuth } from "./Auth";
|
import { ServiceAuth } from "./Auth";
|
||||||
import { GetAuthResponse } from "../../../src/Widgets/BridgeWidgetInterface";
|
import { GetAuthResponse } from "../../../src/Widgets/BridgeWidgetInterface";
|
||||||
|
import { BridgeContext } from "../../context";
|
||||||
|
|
||||||
const EventType = "uk.half-shot.matrix-hookshot.github.repository";
|
const EventType = "uk.half-shot.matrix-hookshot.github.repository";
|
||||||
|
|
||||||
@ -18,11 +19,12 @@ function getRepoFullName(state: GitHubRepoConnectionState) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ConnectionConfiguration: FunctionComponent<ConnectionConfigurationProps<never, GitHubRepoResponseItem, GitHubRepoConnectionState>> = ({
|
const ConnectionConfiguration: FunctionComponent<ConnectionConfigurationProps<never, GitHubRepoResponseItem, GitHubRepoConnectionState>> = ({
|
||||||
showAuthPrompt, loginLabel, serviceConfig, api, existingConnection, onSave, onRemove, isUpdating
|
showAuthPrompt, loginLabel, serviceConfig, existingConnection, onSave, onRemove, isUpdating
|
||||||
}) => {
|
}) => {
|
||||||
// Assume true if we have no auth prompt.
|
// Assume true if we have no auth prompt.
|
||||||
const [authedResponse, setAuthResponse] = useState<GetAuthResponse|null>(null);
|
const [authedResponse, setAuthResponse] = useState<GetAuthResponse|null>(null);
|
||||||
const [enabledHooks, setEnabledHooks] = useState<string[]>(existingConnection?.config.enableHooks || []);
|
const [enabledHooks, setEnabledHooks] = useState<string[]>(existingConnection?.config.enableHooks || []);
|
||||||
|
const api = useContext(BridgeContext).bridgeApi;
|
||||||
|
|
||||||
const checkAuth = useCallback(() => {
|
const checkAuth = useCallback(() => {
|
||||||
api.getAuth("github").then((res) => {
|
api.getAuth("github").then((res) => {
|
||||||
@ -106,7 +108,7 @@ const ConnectionConfiguration: FunctionComponent<ConnectionConfigurationProps<ne
|
|||||||
const consideredAuthenticated = (authedResponse?.authenticated || !showAuthPrompt);
|
const consideredAuthenticated = (authedResponse?.authenticated || !showAuthPrompt);
|
||||||
|
|
||||||
return <form onSubmit={handleSave}>
|
return <form onSubmit={handleSave}>
|
||||||
{authedResponse && <ServiceAuth onAuthSucceeded={checkAuth} authState={authedResponse} service="github" loginLabel={loginLabel} api={api} />}
|
{authedResponse && <ServiceAuth onAuthSucceeded={checkAuth} authState={authedResponse} service="github" loginLabel={loginLabel} />}
|
||||||
{!existingConnection && consideredAuthenticated && <ConnectionSearch
|
{!existingConnection && consideredAuthenticated && <ConnectionSearch
|
||||||
serviceName="GitHub"
|
serviceName="GitHub"
|
||||||
addNewInstanceUrl={newInstallationUrl}
|
addNewInstanceUrl={newInstallationUrl}
|
||||||
@ -175,12 +177,11 @@ const roomConfigText: IRoomConfigText = {
|
|||||||
|
|
||||||
const RoomConfigListItemFunc = (c: GitHubRepoResponseItem) => getRepoFullName(c.config);
|
const RoomConfigListItemFunc = (c: GitHubRepoResponseItem) => getRepoFullName(c.config);
|
||||||
|
|
||||||
export const GithubRepoConfig: BridgeConfig = ({ api, roomId, showHeader }) => {
|
export const GithubRepoConfig: BridgeConfig = ({ roomId, showHeader }) => {
|
||||||
return <RoomConfig<never, GitHubRepoResponseItem, GitHubRepoConnectionState>
|
return <RoomConfig<never, GitHubRepoResponseItem, GitHubRepoConnectionState>
|
||||||
headerImg={GitHubIcon}
|
headerImg={GitHubIcon}
|
||||||
darkHeaderImg={true}
|
darkHeaderImg={true}
|
||||||
showHeader={showHeader}
|
showHeader={showHeader}
|
||||||
api={api}
|
|
||||||
roomId={roomId}
|
roomId={roomId}
|
||||||
type="github"
|
type="github"
|
||||||
showAuthPrompt={true}
|
showAuthPrompt={true}
|
||||||
|
@ -5,13 +5,15 @@ import { EventHookCheckbox } from '../elements/EventHookCheckbox';
|
|||||||
import { GitLabRepoConnectionState, GitLabRepoResponseItem, GitLabRepoConnectionProjectTarget, GitLabRepoConnectionInstanceTarget } from "../../../src/Connections/GitlabRepo";
|
import { GitLabRepoConnectionState, GitLabRepoResponseItem, GitLabRepoConnectionProjectTarget, GitLabRepoConnectionInstanceTarget } from "../../../src/Connections/GitlabRepo";
|
||||||
import { InputField, ButtonSet, Button } from "../elements";
|
import { InputField, ButtonSet, Button } from "../elements";
|
||||||
import { FunctionComponent, createRef } from "preact";
|
import { FunctionComponent, createRef } from "preact";
|
||||||
import { useState, useCallback, useMemo } from "preact/hooks";
|
import { useState, useCallback, useMemo, useContext } from "preact/hooks";
|
||||||
import { DropItem } from "../elements/DropdownSearch";
|
import { DropItem } from "../elements/DropdownSearch";
|
||||||
import { ConnectionSearch } from "../elements/ConnectionSearch";
|
import { ConnectionSearch } from "../elements/ConnectionSearch";
|
||||||
|
import { BridgeContext } from "../../context";
|
||||||
|
|
||||||
const EventType = "uk.half-shot.matrix-hookshot.gitlab.repository";
|
const EventType = "uk.half-shot.matrix-hookshot.gitlab.repository";
|
||||||
const ConnectionConfiguration: FunctionComponent<ConnectionConfigurationProps<never, GitLabRepoResponseItem, GitLabRepoConnectionState>> = ({api, existingConnection, onSave, onRemove, isUpdating }) => {
|
const ConnectionConfiguration: FunctionComponent<ConnectionConfigurationProps<never, GitLabRepoResponseItem, GitLabRepoConnectionState>> = ({existingConnection, onSave, onRemove, isUpdating }) => {
|
||||||
const [enabledHooks, setEnabledHooks] = useState<string[]>(existingConnection?.config.enableHooks || []);
|
const [enabledHooks, setEnabledHooks] = useState<string[]>(existingConnection?.config.enableHooks || []);
|
||||||
|
const api = useContext(BridgeContext).bridgeApi;
|
||||||
|
|
||||||
const toggleEnabledHook = useCallback((evt: any) => {
|
const toggleEnabledHook = useCallback((evt: any) => {
|
||||||
const key = (evt.target as HTMLElement).getAttribute('x-event-name');
|
const key = (evt.target as HTMLElement).getAttribute('x-event-name');
|
||||||
@ -123,11 +125,10 @@ const RoomConfigText = {
|
|||||||
|
|
||||||
const RoomConfigListItemFunc = (c: GitLabRepoResponseItem) => c.config.path;
|
const RoomConfigListItemFunc = (c: GitLabRepoResponseItem) => c.config.path;
|
||||||
|
|
||||||
export const GitlabRepoConfig: BridgeConfig = ({ api, roomId, showHeader }) => {
|
export const GitlabRepoConfig: BridgeConfig = ({ roomId, showHeader }) => {
|
||||||
return <RoomConfig<never, GitLabRepoResponseItem, GitLabRepoConnectionState>
|
return <RoomConfig<never, GitLabRepoResponseItem, GitLabRepoConnectionState>
|
||||||
headerImg={GitLabIcon}
|
headerImg={GitLabIcon}
|
||||||
showHeader={showHeader}
|
showHeader={showHeader}
|
||||||
api={api}
|
|
||||||
roomId={roomId}
|
roomId={roomId}
|
||||||
type="gitlab"
|
type="gitlab"
|
||||||
text={RoomConfigText}
|
text={RoomConfigText}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { FunctionComponent, createRef } from "preact";
|
import { FunctionComponent, createRef } from "preact";
|
||||||
import { useState, useCallback, useMemo } from "preact/hooks";
|
import { useState, useCallback, useMemo, useContext } from "preact/hooks";
|
||||||
import { BridgeConfig } from "../../BridgeAPI";
|
import { BridgeConfig } from "../../BridgeAPI";
|
||||||
import { ConnectionConfigurationProps, RoomConfig } from "./RoomConfig";
|
import { ConnectionConfigurationProps, RoomConfig } from "./RoomConfig";
|
||||||
import { JiraProjectConnectionState, JiraProjectResponseItem, JiraProjectConnectionProjectTarget, JiraProjectConnectionInstanceTarget } from "../../../src/Connections/JiraProject";
|
import { JiraProjectConnectionState, JiraProjectResponseItem, JiraProjectConnectionProjectTarget, JiraProjectConnectionInstanceTarget } from "../../../src/Connections/JiraProject";
|
||||||
@ -8,11 +8,13 @@ import { EventHookCheckbox } from '../elements/EventHookCheckbox';
|
|||||||
import JiraIcon from "../../icons/jira.png";
|
import JiraIcon from "../../icons/jira.png";
|
||||||
import ConnectionSearch from "../elements/ConnectionSearch";
|
import ConnectionSearch from "../elements/ConnectionSearch";
|
||||||
import { DropItem } from "../elements/DropdownSearch";
|
import { DropItem } from "../elements/DropdownSearch";
|
||||||
|
import { BridgeContext } from "../../context";
|
||||||
|
|
||||||
const EventType = "uk.half-shot.matrix-hookshot.jira.project";
|
const EventType = "uk.half-shot.matrix-hookshot.jira.project";
|
||||||
|
|
||||||
const ConnectionConfiguration: FunctionComponent<ConnectionConfigurationProps<never, JiraProjectResponseItem, JiraProjectConnectionState>> = ({api, existingConnection, onSave, onRemove, isUpdating }) => {
|
const ConnectionConfiguration: FunctionComponent<ConnectionConfigurationProps<never, JiraProjectResponseItem, JiraProjectConnectionState>> = ({existingConnection, onSave, onRemove, isUpdating }) => {
|
||||||
const [allowedEvents, setAllowedEvents] = useState<string[]>(existingConnection?.config.events || ['issue_created']);
|
const [allowedEvents, setAllowedEvents] = useState<string[]>(existingConnection?.config.events || ['issue_created']);
|
||||||
|
const api = useContext(BridgeContext).bridgeApi;
|
||||||
|
|
||||||
const toggleEvent = useCallback((evt: Event) => {
|
const toggleEvent = useCallback((evt: Event) => {
|
||||||
const key = (evt.target as HTMLElement).getAttribute('x-event-name');
|
const key = (evt.target as HTMLElement).getAttribute('x-event-name');
|
||||||
@ -108,11 +110,10 @@ const RoomConfigText = {
|
|||||||
|
|
||||||
const RoomConfigListItemFunc = (c: JiraProjectResponseItem) => c.config.url;
|
const RoomConfigListItemFunc = (c: JiraProjectResponseItem) => c.config.url;
|
||||||
|
|
||||||
export const JiraProjectConfig: BridgeConfig = ({ api, roomId, showHeader }) => {
|
export const JiraProjectConfig: BridgeConfig = ({ roomId, showHeader }) => {
|
||||||
return <RoomConfig<never, JiraProjectResponseItem, JiraProjectConnectionState>
|
return <RoomConfig<never, JiraProjectResponseItem, JiraProjectConnectionState>
|
||||||
headerImg={JiraIcon}
|
headerImg={JiraIcon}
|
||||||
showHeader={showHeader}
|
showHeader={showHeader}
|
||||||
api={api}
|
|
||||||
roomId={roomId}
|
roomId={roomId}
|
||||||
type="jira"
|
type="jira"
|
||||||
text={RoomConfigText}
|
text={RoomConfigText}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { FunctionComponent } from "preact";
|
import { FunctionComponent } from "preact";
|
||||||
import { useCallback, useEffect, useReducer, useState } from "preact/hooks"
|
import { useCallback, useContext, useEffect, useReducer, useState } from "preact/hooks"
|
||||||
import { BridgeAPI, BridgeAPIError } from "../../BridgeAPI";
|
import { BridgeAPIError } from "../../BridgeAPI";
|
||||||
import { ListItem, Card } from "../elements";
|
import { ListItem, Card } from "../elements";
|
||||||
import style from "./RoomConfig.module.scss";
|
import style from "./RoomConfig.module.scss";
|
||||||
import { GetConnectionsResponseItem } from "../../../src/provisioning/api";
|
import { GetConnectionsResponseItem } from "../../../src/provisioning/api";
|
||||||
@ -9,6 +9,7 @@ import { LoadingSpinner } from '../elements/LoadingSpinner';
|
|||||||
import { ErrCode } from "../../../src/api";
|
import { ErrCode } from "../../../src/api";
|
||||||
import { retry } from "../../../src/PromiseUtil";
|
import { retry } from "../../../src/PromiseUtil";
|
||||||
import { Alert } from "@vector-im/compound-web";
|
import { Alert } from "@vector-im/compound-web";
|
||||||
|
import { BridgeContext } from "../../context";
|
||||||
|
|
||||||
export interface ConnectionConfigurationProps<SConfig, ConnectionType extends GetConnectionsResponseItem, ConnectionState extends IConnectionState> {
|
export interface ConnectionConfigurationProps<SConfig, ConnectionType extends GetConnectionsResponseItem, ConnectionState extends IConnectionState> {
|
||||||
serviceConfig: SConfig;
|
serviceConfig: SConfig;
|
||||||
@ -19,7 +20,6 @@ export interface ConnectionConfigurationProps<SConfig, ConnectionType extends Ge
|
|||||||
isMigrationCandidate?: boolean,
|
isMigrationCandidate?: boolean,
|
||||||
existingConnection?: ConnectionType;
|
existingConnection?: ConnectionType;
|
||||||
onRemove?: () => void,
|
onRemove?: () => void,
|
||||||
api: BridgeAPI;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IRoomConfigText {
|
export interface IRoomConfigText {
|
||||||
@ -31,7 +31,6 @@ export interface IRoomConfigText {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface IRoomConfigProps<SConfig, ConnectionType extends GetConnectionsResponseItem, ConnectionState extends IConnectionState> {
|
interface IRoomConfigProps<SConfig, ConnectionType extends GetConnectionsResponseItem, ConnectionState extends IConnectionState> {
|
||||||
api: BridgeAPI;
|
|
||||||
roomId: string;
|
roomId: string;
|
||||||
type: string;
|
type: string;
|
||||||
showAuthPrompt?: boolean;
|
showAuthPrompt?: boolean;
|
||||||
@ -48,7 +47,6 @@ const MAX_CONNECTION_FETCH_ATTEMPTS = 10;
|
|||||||
|
|
||||||
export const RoomConfig = function<SConfig, ConnectionType extends GetConnectionsResponseItem, ConnectionState extends IConnectionState>(props: IRoomConfigProps<SConfig, ConnectionType, ConnectionState>) {
|
export const RoomConfig = function<SConfig, ConnectionType extends GetConnectionsResponseItem, ConnectionState extends IConnectionState>(props: IRoomConfigProps<SConfig, ConnectionType, ConnectionState>) {
|
||||||
const {
|
const {
|
||||||
api,
|
|
||||||
roomId,
|
roomId,
|
||||||
type,
|
type,
|
||||||
showAuthPrompt = false,
|
showAuthPrompt = false,
|
||||||
@ -59,6 +57,7 @@ export const RoomConfig = function<SConfig, ConnectionType extends GetConnection
|
|||||||
listItemName,
|
listItemName,
|
||||||
connectionEventType,
|
connectionEventType,
|
||||||
} = props;
|
} = props;
|
||||||
|
const api = useContext(BridgeContext).bridgeApi;
|
||||||
const ConnectionConfigComponent = props.connectionConfigComponent;
|
const ConnectionConfigComponent = props.connectionConfigComponent;
|
||||||
const [ error, setError ] = useState<null|{header?: string, message: string, isWarning?: boolean, forPrevious?: boolean}>(null);
|
const [ error, setError ] = useState<null|{header?: string, message: string, isWarning?: boolean, forPrevious?: boolean}>(null);
|
||||||
const [ connections, setConnections ] = useState<ConnectionType[]|null>(null);
|
const [ connections, setConnections ] = useState<ConnectionType[]|null>(null);
|
||||||
@ -153,7 +152,6 @@ export const RoomConfig = function<SConfig, ConnectionType extends GetConnection
|
|||||||
<h2>{text.createNew}</h2>
|
<h2>{text.createNew}</h2>
|
||||||
{serviceConfig && <ConnectionConfigComponent
|
{serviceConfig && <ConnectionConfigComponent
|
||||||
key={newConnectionKey}
|
key={newConnectionKey}
|
||||||
api={api}
|
|
||||||
serviceConfig={serviceConfig}
|
serviceConfig={serviceConfig}
|
||||||
onSave={handleSaveOnCreation}
|
onSave={handleSaveOnCreation}
|
||||||
loginLabel={text.login}
|
loginLabel={text.login}
|
||||||
@ -166,7 +164,6 @@ export const RoomConfig = function<SConfig, ConnectionType extends GetConnection
|
|||||||
<h2>{ canEditRoom ? text.listCanEdit : text.listCantEdit }</h2>
|
<h2>{ canEditRoom ? text.listCanEdit : text.listCantEdit }</h2>
|
||||||
{ serviceConfig && connections?.map(c => <ListItem key={c.id} text={listItemName(c)}>
|
{ serviceConfig && connections?.map(c => <ListItem key={c.id} text={listItemName(c)}>
|
||||||
<ConnectionConfigComponent
|
<ConnectionConfigComponent
|
||||||
api={api}
|
|
||||||
serviceConfig={serviceConfig}
|
serviceConfig={serviceConfig}
|
||||||
existingConnection={c}
|
existingConnection={c}
|
||||||
onSave={(config) => {
|
onSave={(config) => {
|
||||||
|
15
web/context.ts
Normal file
15
web/context.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { createContext } from "preact";
|
||||||
|
import type { BridgeAPI } from "./BridgeAPI";
|
||||||
|
|
||||||
|
interface IBridgeContext {
|
||||||
|
bridgeApi: BridgeAPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fakeBridgeContext = {
|
||||||
|
get bridgeApi(): BridgeAPI {
|
||||||
|
throw Error('No context provided');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const BridgeContext = createContext<IBridgeContext>(fakeBridgeContext);
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user