cleaning up components, beginning to pull out slack logic
This commit is contained in:
parent
b377997617
commit
1b7715d0c8
16 changed files with 311 additions and 288 deletions
|
@ -3,7 +3,7 @@ export const getSlackInstallURL = (callback: CallableFunction) => {
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then(res => {
|
.then(res => {
|
||||||
console.log('Got slack url', res);
|
console.log('Got slack url', res);
|
||||||
callback(res.data.url, res.data.state_token)
|
callback(res.data.url)
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
import Grid from "@mui/material/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
import TextField from "@mui/material/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
import Typography from "@mui/material/Typography";
|
|
||||||
import FormControl from "@mui/material/FormControl";
|
|
||||||
import InputLabel from "@mui/material/InputLabel";
|
|
||||||
|
|
||||||
import {setBridgeLabel} from "../../api/bridge";
|
import {setBridgeLabel} from "../../api/bridge";
|
||||||
import {useState} from "react";
|
import {useState} from "react";
|
||||||
|
|
|
@ -5,16 +5,15 @@ import MenuItem from "@mui/material/MenuItem";
|
||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
import {stepCompleteType} from "./joinForm";
|
import {stepCompleteType} from "./joinForm";
|
||||||
|
|
||||||
import {joinSlackChannel} from "../../api/slack";
|
import {getSlackChannels, joinSlackChannel} from "../../api/slack";
|
||||||
import {useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
|
import {channelsType} from "../../types/channel";
|
||||||
|
import {bridgeType} from "../../types/bridge";
|
||||||
|
|
||||||
|
|
||||||
export interface JoinChannelProps {
|
export interface JoinChannelProps {
|
||||||
channels: Array<{
|
platform: string;
|
||||||
name: string;
|
bridge: bridgeType;
|
||||||
id: string;
|
|
||||||
is_member: boolean;
|
|
||||||
}>;
|
|
||||||
selectedChannel: string;
|
selectedChannel: string;
|
||||||
setSelectedChannel: CallableFunction;
|
setSelectedChannel: CallableFunction;
|
||||||
setStepComplete: CallableFunction;
|
setStepComplete: CallableFunction;
|
||||||
|
@ -22,16 +21,26 @@ export interface JoinChannelProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const JoinChannel = ({
|
const JoinChannel = ({
|
||||||
channels,
|
platform,
|
||||||
|
bridge,
|
||||||
selectedChannel,
|
selectedChannel,
|
||||||
setSelectedChannel,
|
setSelectedChannel,
|
||||||
setStepComplete,
|
setStepComplete,
|
||||||
stepComplete
|
stepComplete
|
||||||
}: JoinChannelProps) => {
|
}: JoinChannelProps) => {
|
||||||
console.log('joinchannel channels', channels)
|
|
||||||
const [errored, setErrored] = useState(false);
|
const [errored, setErrored] = useState(false);
|
||||||
|
const [channels, setChannels] = useState<channelsType[]>();
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (bridge){
|
||||||
|
switch(platform){
|
||||||
|
case "Slack":
|
||||||
|
getSlackChannels(setChannels)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [platform, bridge])
|
||||||
|
|
||||||
const onJoinChannel = (response) => {
|
const onJoinChannel = (response) => {
|
||||||
if (response.status === 'success'){
|
if (response.status === 'success'){
|
||||||
setErrored(false)
|
setErrored(false)
|
||||||
|
@ -47,11 +56,15 @@ const JoinChannel = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
const onJoinButtonClicked = () => {
|
const onJoinButtonClicked = () => {
|
||||||
|
switch(platform){
|
||||||
|
case "Slack":
|
||||||
let channel_id = channels.filter(chan => chan.name === selectedChannel)
|
let channel_id = channels.filter(chan => chan.name === selectedChannel)
|
||||||
.map(chan => chan.id)[0]
|
.map(chan => chan.id)[0]
|
||||||
joinSlackChannel(channel_id, onJoinChannel)
|
joinSlackChannel(channel_id, onJoinChannel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={"list-row"}>
|
<div className={"list-row"}>
|
||||||
<FormControl sx={{width: "50%"}}>
|
<FormControl sx={{width: "50%"}}>
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
import Typography from "@mui/material/Typography";
|
|
||||||
import Accordion from '@mui/material/Accordion';
|
|
||||||
import AccordionDetails from '@mui/material/AccordionDetails';
|
|
||||||
import AccordionSummary from '@mui/material/AccordionSummary';
|
|
||||||
|
|
||||||
|
|
||||||
import {Group} from "../../types/group";
|
import {Group} from "../../types/group";
|
||||||
import {JoinStep} from './joinStep';
|
import {JoinStep} from './joinStep';
|
||||||
import {JoinPlatform} from "./joinPlatform";
|
import {JoinLogin} from "./joinLogin";
|
||||||
import {useState, useEffect} from "react";
|
import {useState, useEffect} from "react";
|
||||||
import Grid from '@mui/material/Grid';
|
|
||||||
import TextField from "@mui/material/TextField";
|
|
||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
import {setBridgeLabel} from "../../api/bridge";
|
|
||||||
import {getSlackChannels} from "../../api/slack";
|
|
||||||
import {createChannel} from "../../api/channel";
|
import {createChannel} from "../../api/channel";
|
||||||
import FormControl from "@mui/material/FormControl";
|
|
||||||
import Select from "@mui/material/Select"
|
|
||||||
import InputLabel from '@mui/material/InputLabel';
|
|
||||||
import MenuItem from '@mui/material/MenuItem';
|
|
||||||
import {JoinBridge} from "./joinBridge";
|
import {JoinBridge} from "./joinBridge";
|
||||||
import JoinChannel from "./joinChannel";
|
import JoinChannel from "./joinChannel";
|
||||||
|
import {bridgeType} from "../../types/bridge";
|
||||||
|
|
||||||
export interface JoinFormProps {
|
export interface JoinFormProps {
|
||||||
group?: Group
|
group?: Group
|
||||||
invite_token: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface stepCompleteType {
|
export interface stepCompleteType {
|
||||||
|
@ -32,31 +19,30 @@ export interface stepCompleteType {
|
||||||
channel: boolean;
|
channel: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const JoinForm = ({group, invite_token}: JoinFormProps) => {
|
export interface stepErrorType {
|
||||||
const [bridgeCreated, setBridgeCreated] = useState(false);
|
login: string;
|
||||||
const [bridgeErrorMessage, setBridgeErrorMessage] = useState('');
|
bridge: string;
|
||||||
|
channel: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const JoinForm = ({group}: JoinFormProps) => {
|
||||||
|
// The platform selected to log in to
|
||||||
const [platform, setPlatform] = useState<string>();
|
const [platform, setPlatform] = useState<string>();
|
||||||
const [channels, setChannels] = useState<Array<{
|
const [bridge, setBridge] = useState<bridgeType>();
|
||||||
name: string;
|
|
||||||
id: string;
|
|
||||||
is_member: boolean;
|
|
||||||
}>
|
|
||||||
>();
|
|
||||||
const [selectedChannel, setSelectedChannel] = useState<string>('');
|
const [selectedChannel, setSelectedChannel] = useState<string>('');
|
||||||
const [bridge, setBridge] = useState<{
|
|
||||||
Label: string;
|
|
||||||
Protocol: string;
|
|
||||||
team_name: string;
|
|
||||||
id: string;
|
|
||||||
}>();
|
|
||||||
const [stepComplete, setStepComplete] = useState<stepCompleteType>({
|
const [stepComplete, setStepComplete] = useState<stepCompleteType>({
|
||||||
login: false,
|
login: false,
|
||||||
bridge: false,
|
bridge: false,
|
||||||
channel: false
|
channel: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [bridgeCreated, setBridgeCreated] = useState(false);
|
||||||
|
const [bridgeErrorMessage, setBridgeErrorMessage] = useState('');
|
||||||
|
|
||||||
|
|
||||||
const createBridgedChannel = () => {
|
const createBridgedChannel = () => {
|
||||||
createChannel(selectedChannel, bridge.id, invite_token, onBridgedChannelCreated)
|
createChannel(selectedChannel, bridge.id, group.invite_token, onBridgedChannelCreated)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onBridgedChannelCreated = (result) => {
|
const onBridgedChannelCreated = (result) => {
|
||||||
|
@ -69,15 +55,6 @@ export const JoinForm = ({group, invite_token}: JoinFormProps) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (bridge !== undefined){
|
|
||||||
setStepComplete({...stepComplete, login:true})
|
|
||||||
}
|
|
||||||
if (bridge !== undefined && channels === undefined){
|
|
||||||
getSlackChannels(setChannels)
|
|
||||||
}
|
|
||||||
}, [bridge])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<header className={'section-header'}>
|
<header className={'section-header'}>
|
||||||
|
@ -89,10 +66,13 @@ export const JoinForm = ({group, invite_token}: JoinFormProps) => {
|
||||||
id={'login'}
|
id={'login'}
|
||||||
completed={stepComplete.login}
|
completed={stepComplete.login}
|
||||||
>
|
>
|
||||||
<JoinPlatform
|
<JoinLogin
|
||||||
platformSetter = {setPlatform}
|
platform={platform}
|
||||||
bridgeSetter = {setBridge}
|
setPlatform = {setPlatform}
|
||||||
completeSetter= {setStepComplete}
|
bridge={bridge}
|
||||||
|
setBridge = {setBridge}
|
||||||
|
stepComplete = {stepComplete}
|
||||||
|
setStepComplete = {setStepComplete}
|
||||||
/>
|
/>
|
||||||
</JoinStep>
|
</JoinStep>
|
||||||
<JoinStep
|
<JoinStep
|
||||||
|
@ -117,7 +97,8 @@ export const JoinForm = ({group, invite_token}: JoinFormProps) => {
|
||||||
completed={stepComplete.channel}
|
completed={stepComplete.channel}
|
||||||
>
|
>
|
||||||
<JoinChannel
|
<JoinChannel
|
||||||
channels={channels}
|
platform={platform}
|
||||||
|
bridge={bridge}
|
||||||
selectedChannel={selectedChannel}
|
selectedChannel={selectedChannel}
|
||||||
setSelectedChannel={setSelectedChannel}
|
setSelectedChannel={setSelectedChannel}
|
||||||
setStepComplete={setStepComplete}
|
setStepComplete={setStepComplete}
|
||||||
|
|
60
client/src/components/join/joinGroup.tsx
Normal file
60
client/src/components/join/joinGroup.tsx
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import React, {useState} from 'react';
|
||||||
|
|
||||||
|
import {Group} from '../../types/group'
|
||||||
|
import {groupInvite} from '../../api/groups'
|
||||||
|
import TextField from "@mui/material/TextField";
|
||||||
|
import Button from "@mui/material/Button";
|
||||||
|
|
||||||
|
export interface JoinGroupProps {
|
||||||
|
group: Group;
|
||||||
|
setGroup: React.Dispatch<React.SetStateAction<Group>>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const JoinGroup = ({
|
||||||
|
group,
|
||||||
|
setGroup
|
||||||
|
}: JoinGroupProps) => {
|
||||||
|
const [text, setText] = useState('');
|
||||||
|
const [authError, setAuthError] = useState(false);
|
||||||
|
const [errorText, setErrorText] = useState('');
|
||||||
|
|
||||||
|
const onGroupLogin = (response) => {
|
||||||
|
if (response.status !== "success"){
|
||||||
|
setAuthError(true);
|
||||||
|
setErrorText(response.message);
|
||||||
|
setGroup(undefined);
|
||||||
|
} else if (response.status === "success"){
|
||||||
|
setAuthError(false);
|
||||||
|
setErrorText('');
|
||||||
|
setGroup(response.data)
|
||||||
|
console.log(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
groupInvite(text, onGroupLogin)
|
||||||
|
}
|
||||||
|
|
||||||
|
const textChanged = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setText(event.target.value)
|
||||||
|
setGroup(undefined)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className={"InputGroup"}>
|
||||||
|
<TextField
|
||||||
|
error={authError}
|
||||||
|
helperText={errorText}
|
||||||
|
className={"Input"}
|
||||||
|
label={"Join with invite token"}
|
||||||
|
onChange={textChanged}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
onClick={handleClick}
|
||||||
|
color={authError ? "error" : undefined}
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
72
client/src/components/join/joinLogin.tsx
Normal file
72
client/src/components/join/joinLogin.tsx
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
Select which platform you're joining from!
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, {useEffect, useState} from 'react';
|
||||||
|
import InputLabel from '@mui/material/InputLabel';
|
||||||
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
|
import FormControl from '@mui/material/FormControl';
|
||||||
|
import Select from '@mui/material/Select';
|
||||||
|
|
||||||
|
import {SlackLogin} from "../platforms/slackLogin";
|
||||||
|
|
||||||
|
enum PLATFORMS {
|
||||||
|
Slack = 'Slack'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const JoinLogin = ({
|
||||||
|
platform,
|
||||||
|
setPlatform,
|
||||||
|
bridge,
|
||||||
|
setBridge,
|
||||||
|
stepComplete,
|
||||||
|
setStepComplete
|
||||||
|
}) => {
|
||||||
|
const [loginComponent, setLoginComponent] = useState(<></>);
|
||||||
|
|
||||||
|
|
||||||
|
const handleSelect = (event) => {
|
||||||
|
setBridge(undefined);
|
||||||
|
setPlatform(event.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
switch(platform){
|
||||||
|
case "Slack":
|
||||||
|
setLoginComponent(<SlackLogin
|
||||||
|
bridge={bridge}
|
||||||
|
setBridge={setBridge}
|
||||||
|
/>)
|
||||||
|
default:
|
||||||
|
setLoginComponent(<></>)
|
||||||
|
|
||||||
|
}
|
||||||
|
}, [platform])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (bridge !== undefined) {
|
||||||
|
setStepComplete({...stepComplete, login:true})
|
||||||
|
}
|
||||||
|
},[bridge])
|
||||||
|
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div className={"list-row"}>
|
||||||
|
<FormControl sx={{width: "50%"}}>
|
||||||
|
<InputLabel>Select Platform</InputLabel>
|
||||||
|
<Select
|
||||||
|
// value={platform}
|
||||||
|
onChange={handleSelect}
|
||||||
|
label={"Select Platform"}
|
||||||
|
>
|
||||||
|
<MenuItem value={'Slack'}>Slack</MenuItem>
|
||||||
|
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
{
|
||||||
|
platform ? loginComponent : <div style={{width: "50%"}}></div>
|
||||||
|
}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,120 +0,0 @@
|
||||||
/*
|
|
||||||
Select which platform you're joining from!
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React, {useEffect, useRef, useState} from 'react';
|
|
||||||
import Box from '@mui/material/Box';
|
|
||||||
import InputLabel from '@mui/material/InputLabel';
|
|
||||||
import MenuItem from '@mui/material/MenuItem';
|
|
||||||
import FormControl from '@mui/material/FormControl';
|
|
||||||
import Select from '@mui/material/Select';
|
|
||||||
import Button from "@mui/material/Button";
|
|
||||||
|
|
||||||
import {getSlackInstallURL} from "../../api/slack";
|
|
||||||
import {getBridgeByStateToken} from "../../api/bridge";
|
|
||||||
import {JoinSlack} from "../panels/joinSlack";
|
|
||||||
|
|
||||||
enum PLATFORMS {
|
|
||||||
Slack = 'Slack'
|
|
||||||
}
|
|
||||||
|
|
||||||
export const JoinPlatform = ({
|
|
||||||
platformSetter,
|
|
||||||
bridgeSetter,
|
|
||||||
completeSetter
|
|
||||||
}) => {
|
|
||||||
const [platform, setPlatform] = useState<PLATFORMS>();
|
|
||||||
const [installLink, setInstallLink] = useState();
|
|
||||||
const [stateToken, setStateToken] = useState();
|
|
||||||
const [bridge, setBridge] = useState();
|
|
||||||
|
|
||||||
const pingTimeout = useRef(null);
|
|
||||||
|
|
||||||
const handleSelect = (event) => {
|
|
||||||
setPlatform(event.target.value);
|
|
||||||
platformSetter(event.target.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (platform === "Slack") {
|
|
||||||
console.log('Getting slack URL')
|
|
||||||
getSlackInstallURL(handleInstallLink)
|
|
||||||
}
|
|
||||||
}, [platform])
|
|
||||||
|
|
||||||
const handleInstallLink = (url, state_token) => {
|
|
||||||
setInstallLink(url);
|
|
||||||
setStateToken(state_token);
|
|
||||||
// pingForBridge()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const pingForBridge = () => {
|
|
||||||
if (bridge === undefined) {
|
|
||||||
console.log('bridge is', bridge);
|
|
||||||
getBridgeByStateToken(setBridge);
|
|
||||||
|
|
||||||
pingTimeout.current = setTimeout(pingForBridge, 1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (stateToken !== undefined) {
|
|
||||||
if (bridge === undefined){
|
|
||||||
pingForBridge()
|
|
||||||
// pingTimeout.current = setInterval(pingForBridge, 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return () => {clearInterval(pingTimeout.current)}
|
|
||||||
|
|
||||||
// if (stateToken !== undefined){
|
|
||||||
// if (bridge === undefined){
|
|
||||||
// console.log('bridge is', bridge)
|
|
||||||
// pingTimeout.current = setTimeout(() => {
|
|
||||||
// getBridgeByStateToken(setBridge);
|
|
||||||
// }, 1000)
|
|
||||||
// // setTimeout(pingForBridge, 1000);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
}, [stateToken, bridge])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
bridgeSetter(bridge)
|
|
||||||
}, [bridge])
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
//
|
|
||||||
// }, [installLink])
|
|
||||||
|
|
||||||
const openInstallTab = () => {
|
|
||||||
|
|
||||||
window.open(installLink, '_blank').focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
return(
|
|
||||||
<div className={"list-row"}>
|
|
||||||
<FormControl sx={{width: "50%"}}>
|
|
||||||
<InputLabel>Select Platform</InputLabel>
|
|
||||||
<Select
|
|
||||||
// value={platform}
|
|
||||||
onChange={handleSelect}
|
|
||||||
label={"Select Platform"}
|
|
||||||
>
|
|
||||||
<MenuItem value={'Slack'}>Slack</MenuItem>
|
|
||||||
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
{
|
|
||||||
installLink && platform == "Slack" ?
|
|
||||||
<Button
|
|
||||||
variant={"outlined"}
|
|
||||||
onClick={openInstallTab}>
|
|
||||||
Add to Slack
|
|
||||||
</Button>
|
|
||||||
: <div style={{width: "50%"}}></div>
|
|
||||||
}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -4,58 +4,23 @@ import TextField from '@mui/material/TextField';
|
||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
|
|
||||||
import {JoinForm} from "../join/joinForm";
|
import {JoinForm} from "../join/joinForm";
|
||||||
|
import {JoinGroup} from '../join/joinGroup';
|
||||||
|
|
||||||
import {Group} from "../../types/group";
|
import {Group} from "../../types/group";
|
||||||
import {groupInvite} from "../../api/groups";
|
import {groupInvite} from "../../api/groups";
|
||||||
|
|
||||||
export default function JoinPanel(){
|
export default function JoinPanel(){
|
||||||
const [text, setText] = useState('');
|
|
||||||
const [authError, setAuthError] = useState(false);
|
|
||||||
const [errorText, setErrorText] = useState('');
|
|
||||||
const [group, setGroup] = useState<Group>(undefined);
|
const [group, setGroup] = useState<Group>(undefined);
|
||||||
|
|
||||||
const onGroupLogin = (response) => {
|
|
||||||
if (response.status !== "success"){
|
|
||||||
setAuthError(true);
|
|
||||||
setErrorText(response.message);
|
|
||||||
setGroup(undefined);
|
|
||||||
} else if (response.status === "success"){
|
|
||||||
setAuthError(false);
|
|
||||||
setErrorText('');
|
|
||||||
setGroup(response.data)
|
|
||||||
console.log(response)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleClick = () => {
|
|
||||||
groupInvite(text, onGroupLogin)
|
|
||||||
}
|
|
||||||
|
|
||||||
const textChanged = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
setText(event.target.value)
|
|
||||||
setGroup(undefined)
|
|
||||||
}
|
|
||||||
return(
|
return(
|
||||||
<div className={"JoinPanel"}>
|
<div className={"JoinPanel"}>
|
||||||
<div className={"InputGroup"}>
|
<JoinGroup
|
||||||
<TextField
|
group={group}
|
||||||
error={authError}
|
setGroup={setGroup}
|
||||||
helperText={errorText}
|
|
||||||
className={"Input"}
|
|
||||||
label={"Join with invite token"}
|
|
||||||
onChange={textChanged}
|
|
||||||
/>
|
/>
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
onClick={handleClick}
|
|
||||||
color={authError ? "error" : undefined}
|
|
||||||
>
|
|
||||||
Submit
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
{ group ?
|
{ group ?
|
||||||
<JoinForm
|
<JoinForm
|
||||||
group = {group}
|
group = {group}
|
||||||
invite_token = {text}
|
|
||||||
/> : undefined
|
/> : undefined
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
export const JoinSlack = () => {
|
|
||||||
return(
|
|
||||||
<></>
|
|
||||||
)
|
|
||||||
}
|
|
55
client/src/components/platforms/slackLogin.tsx
Normal file
55
client/src/components/platforms/slackLogin.tsx
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import React, {useEffect, useRef, useState} from 'react'
|
||||||
|
import Button from "@mui/material/Button";
|
||||||
|
import {getSlackInstallURL} from "../../api/slack";
|
||||||
|
import {getBridgeByStateToken} from "../../api/bridge";
|
||||||
|
|
||||||
|
export const SlackLogin = ({
|
||||||
|
bridge,
|
||||||
|
setBridge
|
||||||
|
}) => {
|
||||||
|
const [installLink, setInstallLink] = useState();
|
||||||
|
const [installStarted, setInstallStarted] = useState(false)
|
||||||
|
const pingTimeout = useRef(null);
|
||||||
|
|
||||||
|
const openInstallTab = () => {
|
||||||
|
window.open(installLink, '_blank').focus();
|
||||||
|
setInstallStarted(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getSlackInstallURL(handleInstallLink)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const handleInstallLink = (url) => {
|
||||||
|
setInstallLink(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const pingForBridge = () => {
|
||||||
|
if (bridge === undefined) {
|
||||||
|
getBridgeByStateToken(setBridge);
|
||||||
|
pingTimeout.current = setTimeout(pingForBridge, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (installStarted) {
|
||||||
|
if (bridge === undefined){
|
||||||
|
pingForBridge()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return () => {clearInterval(pingTimeout.current)}
|
||||||
|
|
||||||
|
|
||||||
|
}, [installStarted, bridge])
|
||||||
|
|
||||||
|
return(
|
||||||
|
<Button
|
||||||
|
variant={"outlined"}
|
||||||
|
onClick={openInstallTab}
|
||||||
|
color={bridge !== undefined ? 'success': undefined}
|
||||||
|
disabled={installLink === undefined}
|
||||||
|
>
|
||||||
|
{installLink === undefined ? 'Waiting for Install Link...' : 'Add to Slack'}
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
6
client/src/types/bridge.tsx
Normal file
6
client/src/types/bridge.tsx
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
export interface bridgeType {
|
||||||
|
Label: string;
|
||||||
|
Protocol: string;
|
||||||
|
team_name: string;
|
||||||
|
id: string;
|
||||||
|
}
|
5
client/src/types/channel.tsx
Normal file
5
client/src/types/channel.tsx
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export interface channelsType {
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
is_member: boolean;
|
||||||
|
}
|
0
client/src/types/slack.tsx
Normal file
0
client/src/types/slack.tsx
Normal file
|
@ -1,14 +1,15 @@
|
||||||
import config from 'config';
|
import config from 'config';
|
||||||
const { InstallProvider, LogLevel, FileInstallationStore } = require('@slack/oauth');
|
import {Request, Response} from 'express';
|
||||||
import {NextFunction, Request, Response} from 'express';
|
|
||||||
import {AppDataSource} from "../db/data-source";
|
import {AppDataSource} from "../db/data-source";
|
||||||
import {Bridge} from "../entities/bridge.entity";
|
import {Bridge} from "../entities/bridge.entity";
|
||||||
import {Group} from "../entities/group.entity";
|
import {Group} from "../entities/group.entity";
|
||||||
import {JoinSlackChannelInput} from "../schemas/slack.schema";
|
import {JoinSlackChannelInput} from "../schemas/slack.schema";
|
||||||
import { randomUUID } from "crypto";
|
import {randomUUID} from "crypto";
|
||||||
import {log} from "util";
|
|
||||||
import {Join} from "typeorm";
|
|
||||||
import logger from "../logging";
|
import logger from "../logging";
|
||||||
|
import {authTest, slackChannel } from "../types/slack";
|
||||||
|
import { slackConfigType } from "../types/config";
|
||||||
|
|
||||||
|
const { InstallProvider, LogLevel, FileInstallationStore } = require('@slack/oauth');
|
||||||
|
|
||||||
const scopes = ['bot', 'channels:write', 'channels:write.invites', 'chat:write:bot', 'chat:write:user', 'users.profile:read'];
|
const scopes = ['bot', 'channels:write', 'channels:write.invites', 'chat:write:bot', 'chat:write:user', 'users.profile:read'];
|
||||||
const bridgeRepository = AppDataSource.getRepository(Bridge)
|
const bridgeRepository = AppDataSource.getRepository(Bridge)
|
||||||
|
@ -16,61 +17,15 @@ const groupRepository = AppDataSource.getRepository(Group)
|
||||||
|
|
||||||
const SLACK_COOKIE_NAME = "slack-oauth-state";
|
const SLACK_COOKIE_NAME = "slack-oauth-state";
|
||||||
|
|
||||||
const slackConfig = config.get<{
|
const slackConfig = config.get<slackConfigType>('slackConfig');
|
||||||
client_id: string,
|
|
||||||
client_secret: string,
|
|
||||||
signing_secret: string,
|
|
||||||
state_secret: string
|
|
||||||
}>('slackConfig');
|
|
||||||
|
|
||||||
export interface slackChannel {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
is_channel: boolean;
|
|
||||||
is_group: boolean;
|
|
||||||
is_im: boolean;
|
|
||||||
is_mpim: boolean;
|
|
||||||
is_private: boolean;
|
|
||||||
created: number;
|
|
||||||
is_archived: boolean;
|
|
||||||
is_general: boolean;
|
|
||||||
unlinked: number;
|
|
||||||
name_normalized: string;
|
|
||||||
is_shared: boolean;
|
|
||||||
is_org_shared: boolean;
|
|
||||||
is_pending_ext_shared: boolean;
|
|
||||||
pending_shared: [];
|
|
||||||
context_team_id: string;
|
|
||||||
updated: number;
|
|
||||||
creator: string;
|
|
||||||
is_ext_shared: boolean;
|
|
||||||
shared_team_ids: string[];
|
|
||||||
is_member: boolean;
|
|
||||||
num_members: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface authTest {
|
|
||||||
ok: boolean;
|
|
||||||
url: string;
|
|
||||||
team: string;
|
|
||||||
user: string;
|
|
||||||
team_id: string;
|
|
||||||
user_id: string;
|
|
||||||
bot_id: string;
|
|
||||||
is_enterprise_install: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const installer = new InstallProvider({
|
const installer = new InstallProvider({
|
||||||
clientId: slackConfig.client_id,
|
clientId: slackConfig.client_id,
|
||||||
clientSecret: slackConfig.client_secret,
|
clientSecret: slackConfig.client_secret,
|
||||||
authVersion: 'v1',
|
authVersion: 'v1',
|
||||||
scopes,
|
scopes,
|
||||||
// stateSecret: slackConfig.state_secret,
|
|
||||||
stateVerification: false,
|
stateVerification: false,
|
||||||
// installationStore: new FileInstallationStore(),
|
|
||||||
logLevel: LogLevel.DEBUG,
|
logLevel: LogLevel.DEBUG,
|
||||||
// stateCookieName: SLACK_COOKIE_NAME
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,8 +49,7 @@ export const SlackInstallLinkHandler = async(
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
status: 'success',
|
status: 'success',
|
||||||
data: {
|
data: {
|
||||||
url,
|
url
|
||||||
state_token
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
6
server/src/types/config.ts
Normal file
6
server/src/types/config.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
export interface slackConfigType {
|
||||||
|
client_id: string,
|
||||||
|
client_secret: string,
|
||||||
|
signing_secret: string,
|
||||||
|
state_secret: string
|
||||||
|
}
|
36
server/src/types/slack.ts
Normal file
36
server/src/types/slack.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
export interface slackChannel {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
is_channel: boolean;
|
||||||
|
is_group: boolean;
|
||||||
|
is_im: boolean;
|
||||||
|
is_mpim: boolean;
|
||||||
|
is_private: boolean;
|
||||||
|
created: number;
|
||||||
|
is_archived: boolean;
|
||||||
|
is_general: boolean;
|
||||||
|
unlinked: number;
|
||||||
|
name_normalized: string;
|
||||||
|
is_shared: boolean;
|
||||||
|
is_org_shared: boolean;
|
||||||
|
is_pending_ext_shared: boolean;
|
||||||
|
pending_shared: [];
|
||||||
|
context_team_id: string;
|
||||||
|
updated: number;
|
||||||
|
creator: string;
|
||||||
|
is_ext_shared: boolean;
|
||||||
|
shared_team_ids: string[];
|
||||||
|
is_member: boolean;
|
||||||
|
num_members: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface authTest {
|
||||||
|
ok: boolean;
|
||||||
|
url: string;
|
||||||
|
team: string;
|
||||||
|
user: string;
|
||||||
|
team_id: string;
|
||||||
|
user_id: string;
|
||||||
|
bot_id: string;
|
||||||
|
is_enterprise_install: boolean;
|
||||||
|
}
|
Loading…
Reference in a new issue