change(ui): create ms teams components

This commit is contained in:
sylenien 2022-12-06 11:37:37 +01:00 committed by Delirium
parent f784ba5351
commit 1687b5031a
9 changed files with 402 additions and 2 deletions

View file

@ -0,0 +1,44 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-334.32495 -518.3335 2897.4829 3110.001">
<path
d="M1554.637 777.5h575.713c54.391 0 98.483 44.092 98.483 98.483v524.398c0 199.901-162.051 361.952-361.952 361.952h-1.711c-199.901.028-361.975-162-362.004-361.901V828.971c.001-28.427 23.045-51.471 51.471-51.471z"
fill="#5059C9" />
<circle r="233.25" cy="440.583" cx="1943.75" fill="#5059C9" />
<circle r="336.917" cy="336.917" cx="1218.083" fill="#7B83EB" />
<path
d="M1667.323 777.5H717.01c-53.743 1.33-96.257 45.931-95.01 99.676v598.105c-7.505 322.519 247.657 590.16 570.167 598.053 322.51-7.893 577.671-275.534 570.167-598.053V877.176c1.245-53.745-41.268-98.346-95.011-99.676z"
fill="#7B83EB" />
<path
d="M1244 777.5v838.145c-.258 38.435-23.549 72.964-59.09 87.598a91.856 91.856 0 01-35.765 7.257H667.613c-6.738-17.105-12.958-34.21-18.142-51.833a631.287 631.287 0 01-27.472-183.49V877.02c-1.246-53.659 41.198-98.19 94.855-99.52z"
opacity=".1" />
<path
d="M1192.167 777.5v889.978a91.802 91.802 0 01-7.257 35.765c-14.634 35.541-49.163 58.833-87.598 59.09H691.975c-8.812-17.105-17.105-34.21-24.362-51.833-7.257-17.623-12.958-34.21-18.142-51.833a631.282 631.282 0 01-27.472-183.49V877.02c-1.246-53.659 41.198-98.19 94.855-99.52z"
opacity=".2" />
<path
d="M1192.167 777.5v786.312c-.395 52.223-42.632 94.46-94.855 94.855h-447.84A631.282 631.282 0 01622 1475.177V877.02c-1.246-53.659 41.198-98.19 94.855-99.52z"
opacity=".2" />
<path
d="M1140.333 777.5v786.312c-.395 52.223-42.632 94.46-94.855 94.855H649.472A631.282 631.282 0 01622 1475.177V877.02c-1.246-53.659 41.198-98.19 94.855-99.52z"
opacity=".2" />
<path
d="M1244 509.522v163.275c-8.812.518-17.105 1.037-25.917 1.037-8.812 0-17.105-.518-25.917-1.037a284.472 284.472 0 01-51.833-8.293c-104.963-24.857-191.679-98.469-233.25-198.003a288.02 288.02 0 01-16.587-51.833h258.648c52.305.198 94.657 42.549 94.856 94.854z"
opacity=".1" />
<path
d="M1192.167 561.355v111.442a284.472 284.472 0 01-51.833-8.293c-104.963-24.857-191.679-98.469-233.25-198.003h190.228c52.304.198 94.656 42.55 94.855 94.854z"
opacity=".2" />
<path
d="M1192.167 561.355v111.442a284.472 284.472 0 01-51.833-8.293c-104.963-24.857-191.679-98.469-233.25-198.003h190.228c52.304.198 94.656 42.55 94.855 94.854z"
opacity=".2" />
<path
d="M1140.333 561.355v103.148c-104.963-24.857-191.679-98.469-233.25-198.003h138.395c52.305.199 94.656 42.551 94.855 94.855z"
opacity=".2" />
<linearGradient gradientTransform="matrix(1 0 0 -1 0 2075.333)" y2="394.261" x2="942.234" y1="1683.073" x1="198.099"
gradientUnits="userSpaceOnUse" id="a">
<stop offset="0" stop-color="#5a62c3" />
<stop offset=".5" stop-color="#4d55bd" />
<stop offset="1" stop-color="#3940ab" />
</linearGradient>
<path
d="M95.01 466.5h950.312c52.473 0 95.01 42.538 95.01 95.01v950.312c0 52.473-42.538 95.01-95.01 95.01H95.01c-52.473 0-95.01-42.538-95.01-95.01V561.51c0-52.472 42.538-95.01 95.01-95.01z"
fill="url(#a)" />
<path d="M820.211 828.193h-189.97v517.297h-121.03V828.193H320.123V727.844h500.088z" fill="#FFF" />
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -26,11 +26,12 @@ import FetchDoc from './FetchDoc';
import ProfilerDoc from './ProfilerDoc';
import AxiosDoc from './AxiosDoc';
import AssistDoc from './AssistDoc';
import { PageTitle, Loader } from 'UI';
import { PageTitle } from 'UI';
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
import withPageTitle from 'HOCs/withPageTitle';
import PiniaDoc from './PiniaDoc'
import ZustandDoc from './ZustandDoc'
import MSTeams from './Teams'
interface Props {
fetch: (name: string, siteId: string) => void;
@ -133,6 +134,7 @@ const integrations = [
{ title: 'Jira', slug: 'jira', category: 'Errors', icon: 'integrations/jira', component: <JiraForm /> },
{ title: 'Github', slug: 'github', category: 'Errors', icon: 'integrations/github', component: <GithubForm /> },
{ title: 'Slack', category: 'Errors', icon: 'integrations/slack', component: <SlackForm /> },
{ title: 'MS Teams', category: 'Errors', icon: 'integrations/teams', component: <MSTeams /> },
],
},
{

View file

@ -0,0 +1,113 @@
import React from 'react';
import { connect } from 'react-redux';
import { edit, save, init, update, remove } from 'Duck/integrations/teams';
import { Form, Input, Button, Message } from 'UI';
import { confirm } from 'UI';
interface Props {
edit: (inst: any) => void;
save: (inst: any) => void;
init: (inst: any) => void;
update: (inst: any) => void;
remove: (id: string) => void;
instance: any;
saving: boolean;
errors: any;
}
class TeamsAddForm extends React.PureComponent<Props> {
componentWillUnmount() {
this.props.init({});
}
save = () => {
const instance = this.props.instance;
if (instance.exists()) {
this.props.update(this.props.instance);
} else {
this.props.save(this.props.instance);
}
};
remove = async (id) => {
if (
await confirm({
header: 'Confirm',
confirmButton: 'Yes, delete',
confirmation: `Are you sure you want to permanently delete this channel?`,
})
) {
this.props.remove(id);
}
};
write = ({ target: { name, value } }) => this.props.edit({ [name]: value });
render() {
const { instance, saving, errors, onClose } = this.props;
return (
<div className="p-5" style={{ minWidth: '300px' }}>
<Form>
<Form.Field>
<label>Name</label>
<Input
name="name"
value={instance.name}
onChange={this.write}
placeholder="Enter any name"
type="text"
/>
</Form.Field>
<Form.Field>
<label>URL</label>
<Input
name="endpoint"
value={instance.endpoint}
onChange={this.write}
placeholder="Slack webhook URL"
type="text"
/>
</Form.Field>
<div className="flex justify-between">
<div className="flex">
<Button
onClick={this.save}
disabled={!instance.validate()}
loading={saving}
variant="primary"
className="float-left mr-2"
>
{instance.exists() ? 'Update' : 'Add'}
</Button>
<Button onClick={onClose}>{'Cancel'}</Button>
</div>
<Button onClick={() => this.remove(instance.webhookId)} disabled={!instance.exists()}>
{'Delete'}
</Button>
</div>
</Form>
{errors && (
<div className="my-3">
{errors.map((error) => (
<Message visible={errors} size="mini" error key={error}>
{error}
</Message>
))}
</div>
)}
</div>
);
}
}
export default connect(
(state: any) => ({
instance: state.getIn(['slack', 'instance']),
saving: state.getIn(['slack', 'saveRequest', 'loading']),
errors: state.getIn(['slack', 'saveRequest', 'errors']),
}),
{ edit, save, init, remove, update }
)(TeamsAddForm);

View file

@ -0,0 +1,51 @@
import React from 'react';
import { connect } from 'react-redux';
import { NoContent } from 'UI';
import { remove, edit, init } from 'Duck/integrations/teams';
import DocLink from 'Shared/DocLink/DocLink';
function TeamsChannelList(props: { list: any, edit: (inst: any) => any, onEdit: () => void }) {
const { list } = props;
const onEdit = (instance: Record<string, any>) => {
props.edit(instance);
props.onEdit();
};
return (
<div className="mt-6">
<NoContent
title={
<div className="p-5 mb-4">
<div className="text-base text-left">
Integrate MS Teams with OpenReplay and share insights with the rest of the team, directly from the recording page.
</div>
<DocLink className="mt-4 text-base" label="Integrate Slack" url="https://docs.openreplay.com/integrations/slack" />
</div>
}
size="small"
show={list.size === 0}
>
{list.map((c: any) => (
<div
key={c.webhookId}
className="border-t px-5 py-2 flex items-center justify-between cursor-pointer hover:bg-active-blue"
onClick={() => onEdit(c)}
>
<div className="flex-grow-0" style={{ maxWidth: '90%' }}>
<div>{c.name}</div>
<div className="truncate test-xs color-gray-medium">{c.endpoint}</div>
</div>
</div>
))}
</NoContent>
</div>
);
}
export default connect(
(state: any) => ({
list: state.getIn(['teams', 'list']),
}),
{ remove, edit, init }
)(TeamsChannelList);

View file

@ -0,0 +1,55 @@
import React, { useEffect } from 'react';
import TeamsChannelList from './TeamsChannelList';
import { fetchList, init } from 'Duck/integrations/teams';
import { connect } from 'react-redux';
import SlackAddForm from './SlackAddForm';
import { Button } from 'UI';
interface Props {
onEdit?: (integration: any) => void;
istance: any;
fetchList: any;
init: any;
}
const MSTeams = (props: Props) => {
const [active, setActive] = React.useState(false);
const onEdit = () => {
setActive(true);
};
const onNew = () => {
setActive(true);
props.init({});
}
useEffect(() => {
props.fetchList();
}, []);
return (
<div className="bg-white h-screen overflow-y-auto flex items-start" style={{ width: active ? '700px' : '350px' }}>
{active && (
<div className="border-r h-full" style={{ width: '350px' }}>
<SlackAddForm onClose={() => setActive(false)} />
</div>
)}
<div className="shrink-0" style={{ width: '350px' }}>
<div className="flex items-center p-5">
<h3 className="text-2xl mr-3">Microsoft Teams</h3>
<Button rounded={true} icon="plus" variant="outline" onClick={onNew}/>
</div>
<TeamsChannelList onEdit={onEdit} />
</div>
</div>
);
};
MSTeams.displayName = 'MSTeams';
export default connect(
(state: any) => ({
istance: state.getIn(['teams', 'instance']),
}),
{ fetchList, init }
)(MSTeams);

File diff suppressed because one or more lines are too long

View file

@ -12,6 +12,7 @@ import GithubConfig from 'Types/integrations/githubConfig';
import IssueTracker from 'Types/integrations/issueTracker';
import slack from './slack';
import integrations from './integrations';
import teams from './teams'
import { createIntegrationReducer } from './reducer';
@ -29,6 +30,7 @@ export default {
github: createIntegrationReducer('github', GithubConfig),
issues: createIntegrationReducer('issues', IssueTracker),
slack,
teams,
integrations,
};

View file

@ -0,0 +1,88 @@
import { Map, List } from 'immutable';
import withRequestState, { RequestTypes } from 'Duck/requestStateCreator';
import Config from 'Types/integrations/slackConfig';
import { createItemInListUpdater } from '../funcTools/tools';
const SAVE = new RequestTypes('msteams/SAVE');
const UPDATE = new RequestTypes('msteams/UPDATE');
const REMOVE = new RequestTypes('msteams/REMOVE');
const FETCH_LIST = new RequestTypes('msteams/FETCH_LIST');
const EDIT = 'msteams/EDIT';
const INIT = 'msteams/INIT';
const idKey = 'webhookId';
const itemInListUpdater = createItemInListUpdater(idKey);
const initialState = Map({
instance: Config(),
list: List(),
});
const reducer = (state = initialState, action = {}) => {
switch (action.type) {
case FETCH_LIST.SUCCESS:
return state.set('list', List(action.data).map(Config));
case UPDATE.SUCCESS:
case SAVE.SUCCESS:
const config = Config(action.data);
return state.update('list', itemInListUpdater(config)).set('instance', config);
case REMOVE.SUCCESS:
return state.update('list', (list) => list.filter((item) => item.webhookId !== action.id)).set('instance', Config());
case EDIT:
return state.mergeIn(['instance'], action.instance);
case INIT:
return state.set('instance', Config(action.instance));
}
return state;
};
export default withRequestState(
{
fetchRequest: FETCH_LIST,
saveRequest: SAVE,
removeRequest: REMOVE,
},
reducer
);
export function fetchList() {
return {
types: FETCH_LIST.toArray(),
call: (client) => client.get('/integrations/msteams/channels'),
};
}
export function save(instance) {
return {
types: SAVE.toArray(),
call: (client) => client.post(`/integrations/msteams`, instance.toData()),
};
}
export function update(instance) {
return {
types: UPDATE.toArray(),
call: (client) => client.put(`/integrations/msteams/${instance.webhookId}`, instance.toData()),
};
}
export function edit(instance) {
return {
type: EDIT,
instance,
};
}
export function init(instance) {
return {
type: INIT,
instance,
};
}
export function remove(id) {
return {
types: REMOVE.toArray(),
call: (client) => client.delete(`/integrations/msteams/${id}`),
id,
};
}

View file

@ -0,0 +1,44 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-334.32495 -518.3335 2897.4829 3110.001">
<path
d="M1554.637 777.5h575.713c54.391 0 98.483 44.092 98.483 98.483v524.398c0 199.901-162.051 361.952-361.952 361.952h-1.711c-199.901.028-361.975-162-362.004-361.901V828.971c.001-28.427 23.045-51.471 51.471-51.471z"
fill="#5059C9" />
<circle r="233.25" cy="440.583" cx="1943.75" fill="#5059C9" />
<circle r="336.917" cy="336.917" cx="1218.083" fill="#7B83EB" />
<path
d="M1667.323 777.5H717.01c-53.743 1.33-96.257 45.931-95.01 99.676v598.105c-7.505 322.519 247.657 590.16 570.167 598.053 322.51-7.893 577.671-275.534 570.167-598.053V877.176c1.245-53.745-41.268-98.346-95.011-99.676z"
fill="#7B83EB" />
<path
d="M1244 777.5v838.145c-.258 38.435-23.549 72.964-59.09 87.598a91.856 91.856 0 01-35.765 7.257H667.613c-6.738-17.105-12.958-34.21-18.142-51.833a631.287 631.287 0 01-27.472-183.49V877.02c-1.246-53.659 41.198-98.19 94.855-99.52z"
opacity=".1" />
<path
d="M1192.167 777.5v889.978a91.802 91.802 0 01-7.257 35.765c-14.634 35.541-49.163 58.833-87.598 59.09H691.975c-8.812-17.105-17.105-34.21-24.362-51.833-7.257-17.623-12.958-34.21-18.142-51.833a631.282 631.282 0 01-27.472-183.49V877.02c-1.246-53.659 41.198-98.19 94.855-99.52z"
opacity=".2" />
<path
d="M1192.167 777.5v786.312c-.395 52.223-42.632 94.46-94.855 94.855h-447.84A631.282 631.282 0 01622 1475.177V877.02c-1.246-53.659 41.198-98.19 94.855-99.52z"
opacity=".2" />
<path
d="M1140.333 777.5v786.312c-.395 52.223-42.632 94.46-94.855 94.855H649.472A631.282 631.282 0 01622 1475.177V877.02c-1.246-53.659 41.198-98.19 94.855-99.52z"
opacity=".2" />
<path
d="M1244 509.522v163.275c-8.812.518-17.105 1.037-25.917 1.037-8.812 0-17.105-.518-25.917-1.037a284.472 284.472 0 01-51.833-8.293c-104.963-24.857-191.679-98.469-233.25-198.003a288.02 288.02 0 01-16.587-51.833h258.648c52.305.198 94.657 42.549 94.856 94.854z"
opacity=".1" />
<path
d="M1192.167 561.355v111.442a284.472 284.472 0 01-51.833-8.293c-104.963-24.857-191.679-98.469-233.25-198.003h190.228c52.304.198 94.656 42.55 94.855 94.854z"
opacity=".2" />
<path
d="M1192.167 561.355v111.442a284.472 284.472 0 01-51.833-8.293c-104.963-24.857-191.679-98.469-233.25-198.003h190.228c52.304.198 94.656 42.55 94.855 94.854z"
opacity=".2" />
<path
d="M1140.333 561.355v103.148c-104.963-24.857-191.679-98.469-233.25-198.003h138.395c52.305.199 94.656 42.551 94.855 94.855z"
opacity=".2" />
<linearGradient gradientTransform="matrix(1 0 0 -1 0 2075.333)" y2="394.261" x2="942.234" y1="1683.073" x1="198.099"
gradientUnits="userSpaceOnUse" id="a">
<stop offset="0" stop-color="#5a62c3" />
<stop offset=".5" stop-color="#4d55bd" />
<stop offset="1" stop-color="#3940ab" />
</linearGradient>
<path
d="M95.01 466.5h950.312c52.473 0 95.01 42.538 95.01 95.01v950.312c0 52.473-42.538 95.01-95.01 95.01H95.01c-52.473 0-95.01-42.538-95.01-95.01V561.51c0-52.472 42.538-95.01 95.01-95.01z"
fill="url(#a)" />
<path d="M820.211 828.193h-189.97v517.297h-121.03V828.193H320.123V727.844h500.088z" fill="#FFF" />
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB