From 1687b5031ac22adb5061315d0f6304aa1df64954 Mon Sep 17 00:00:00 2001 From: sylenien Date: Tue, 6 Dec 2022 11:37:37 +0100 Subject: [PATCH] change(ui): create ms teams components --- frontend/app/assets/integrations/teams.svg | 44 +++++++ .../Client/Integrations/Integrations.tsx | 4 +- .../Integrations/Teams/TeamsAddForm.tsx | 113 ++++++++++++++++++ .../Integrations/Teams/TeamsChannelList.tsx | 51 ++++++++ .../Client/Integrations/Teams/index.tsx | 55 +++++++++ frontend/app/components/ui/SVG.tsx | 3 +- frontend/app/duck/integrations/index.js | 2 + frontend/app/duck/integrations/teams.js | 88 ++++++++++++++ frontend/app/svg/icons/integrations/teams.svg | 44 +++++++ 9 files changed, 402 insertions(+), 2 deletions(-) create mode 100644 frontend/app/assets/integrations/teams.svg create mode 100644 frontend/app/components/Client/Integrations/Teams/TeamsAddForm.tsx create mode 100644 frontend/app/components/Client/Integrations/Teams/TeamsChannelList.tsx create mode 100644 frontend/app/components/Client/Integrations/Teams/index.tsx create mode 100644 frontend/app/duck/integrations/teams.js create mode 100644 frontend/app/svg/icons/integrations/teams.svg diff --git a/frontend/app/assets/integrations/teams.svg b/frontend/app/assets/integrations/teams.svg new file mode 100644 index 000000000..e93adb2b8 --- /dev/null +++ b/frontend/app/assets/integrations/teams.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/app/components/Client/Integrations/Integrations.tsx b/frontend/app/components/Client/Integrations/Integrations.tsx index 8080213b1..73572c9b0 100644 --- a/frontend/app/components/Client/Integrations/Integrations.tsx +++ b/frontend/app/components/Client/Integrations/Integrations.tsx @@ -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: }, { title: 'Github', slug: 'github', category: 'Errors', icon: 'integrations/github', component: }, { title: 'Slack', category: 'Errors', icon: 'integrations/slack', component: }, + { title: 'MS Teams', category: 'Errors', icon: 'integrations/teams', component: }, ], }, { diff --git a/frontend/app/components/Client/Integrations/Teams/TeamsAddForm.tsx b/frontend/app/components/Client/Integrations/Teams/TeamsAddForm.tsx new file mode 100644 index 000000000..018a5f0ca --- /dev/null +++ b/frontend/app/components/Client/Integrations/Teams/TeamsAddForm.tsx @@ -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 { + 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 ( +
+
+ + + + + + + + +
+
+ + + +
+ + +
+
+ + {errors && ( +
+ {errors.map((error) => ( + + {error} + + ))} +
+ )} +
+ ); + } +} + +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); diff --git a/frontend/app/components/Client/Integrations/Teams/TeamsChannelList.tsx b/frontend/app/components/Client/Integrations/Teams/TeamsChannelList.tsx new file mode 100644 index 000000000..9c5189705 --- /dev/null +++ b/frontend/app/components/Client/Integrations/Teams/TeamsChannelList.tsx @@ -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) => { + props.edit(instance); + props.onEdit(); + }; + + return ( +
+ +
+ Integrate MS Teams with OpenReplay and share insights with the rest of the team, directly from the recording page. +
+ +
+ } + size="small" + show={list.size === 0} + > + {list.map((c: any) => ( +
onEdit(c)} + > +
+
{c.name}
+
{c.endpoint}
+
+
+ ))} + + + ); +} + +export default connect( + (state: any) => ({ + list: state.getIn(['teams', 'list']), + }), + { remove, edit, init } +)(TeamsChannelList); diff --git a/frontend/app/components/Client/Integrations/Teams/index.tsx b/frontend/app/components/Client/Integrations/Teams/index.tsx new file mode 100644 index 000000000..d5fdba6fc --- /dev/null +++ b/frontend/app/components/Client/Integrations/Teams/index.tsx @@ -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 ( +
+ {active && ( +
+ setActive(false)} /> +
+ )} +
+
+

Microsoft Teams

+
+ +
+
+ ); +}; + +MSTeams.displayName = 'MSTeams'; + +export default connect( + (state: any) => ({ + istance: state.getIn(['teams', 'instance']), + }), + { fetchList, init } +)(MSTeams); diff --git a/frontend/app/components/ui/SVG.tsx b/frontend/app/components/ui/SVG.tsx index 3a23f63b8..a04c041a7 100644 --- a/frontend/app/components/ui/SVG.tsx +++ b/frontend/app/components/ui/SVG.tsx @@ -1,7 +1,7 @@ import React from 'react'; -export type IconNames = 'alarm-clock' | 'alarm-plus' | 'all-sessions' | 'analytics' | 'anchor' | 'arrow-alt-square-right' | 'arrow-bar-left' | 'arrow-clockwise' | 'arrow-down-short' | 'arrow-down' | 'arrow-repeat' | 'arrow-right-short' | 'arrow-square-left' | 'arrow-square-right' | 'arrow-up-short' | 'arrow-up' | 'arrows-angle-extend' | 'avatar/icn_bear' | 'avatar/icn_beaver' | 'avatar/icn_bird' | 'avatar/icn_bison' | 'avatar/icn_camel' | 'avatar/icn_chameleon' | 'avatar/icn_deer' | 'avatar/icn_dog' | 'avatar/icn_dolphin' | 'avatar/icn_elephant' | 'avatar/icn_fish' | 'avatar/icn_fox' | 'avatar/icn_gorilla' | 'avatar/icn_hippo' | 'avatar/icn_horse' | 'avatar/icn_hyena' | 'avatar/icn_kangaroo' | 'avatar/icn_lemur' | 'avatar/icn_mammel' | 'avatar/icn_monkey' | 'avatar/icn_moose' | 'avatar/icn_panda' | 'avatar/icn_penguin' | 'avatar/icn_porcupine' | 'avatar/icn_quail' | 'avatar/icn_rabbit' | 'avatar/icn_rhino' | 'avatar/icn_sea_horse' | 'avatar/icn_sheep' | 'avatar/icn_snake' | 'avatar/icn_squirrel' | 'avatar/icn_tapir' | 'avatar/icn_turtle' | 'avatar/icn_vulture' | 'avatar/icn_wild1' | 'avatar/icn_wild_bore' | 'ban' | 'bar-chart-line' | 'bar-pencil' | 'bell-fill' | 'bell-plus' | 'bell-slash' | 'bell' | 'binoculars' | 'book' | 'browser/browser' | 'browser/chrome' | 'browser/edge' | 'browser/electron' | 'browser/facebook' | 'browser/firefox' | 'browser/ie' | 'browser/opera' | 'browser/safari' | 'bullhorn' | 'business-time' | 'calendar-alt' | 'calendar-check' | 'calendar-day' | 'calendar' | 'call' | 'camera-alt' | 'camera-video-off' | 'camera-video' | 'camera' | 'caret-down-fill' | 'caret-left-fill' | 'caret-right-fill' | 'caret-up-fill' | 'chat-dots' | 'chat-right-text' | 'chat-square-quote' | 'check-circle-fill' | 'check-circle' | 'check' | 'chevron-double-left' | 'chevron-double-right' | 'chevron-down' | 'chevron-left' | 'chevron-right' | 'chevron-up' | 'circle-fill' | 'circle' | 'clipboard-list-check' | 'clock' | 'close' | 'cloud-fog2-fill' | 'code' | 'cog' | 'cogs' | 'collection' | 'columns-gap-filled' | 'columns-gap' | 'console/error' | 'console/exception' | 'console/info' | 'console/warning' | 'console' | 'controller' | 'cookies' | 'copy' | 'credit-card-front' | 'cubes' | 'dash' | 'dashboard-icn' | 'desktop' | 'device' | 'diagram-3' | 'dizzy' | 'door-closed' | 'doublecheck' | 'download' | 'drag' | 'edit' | 'ellipsis-v' | 'enter' | 'envelope' | 'errors-icon' | 'event/click' | 'event/clickrage' | 'event/code' | 'event/i-cursor' | 'event/input' | 'event/link' | 'event/location' | 'event/resize' | 'event/view' | 'exclamation-circle' | 'expand-wide' | 'explosion' | 'external-link-alt' | 'eye-slash-fill' | 'eye-slash' | 'eye' | 'fetch' | 'file-code' | 'file-medical-alt' | 'file-pdf' | 'file' | 'filter' | 'filters/arrow-return-right' | 'filters/browser' | 'filters/click' | 'filters/clickrage' | 'filters/code' | 'filters/console' | 'filters/country' | 'filters/cpu-load' | 'filters/custom' | 'filters/device' | 'filters/dom-complete' | 'filters/duration' | 'filters/error' | 'filters/fetch-failed' | 'filters/fetch' | 'filters/file-code' | 'filters/graphql' | 'filters/i-cursor' | 'filters/input' | 'filters/lcpt' | 'filters/link' | 'filters/location' | 'filters/memory-load' | 'filters/metadata' | 'filters/os' | 'filters/perfromance-network-request' | 'filters/platform' | 'filters/referrer' | 'filters/resize' | 'filters/rev-id' | 'filters/state-action' | 'filters/ttfb' | 'filters/user-alt' | 'filters/userid' | 'filters/view' | 'flag-na' | 'folder-plus' | 'folder2' | 'fullscreen' | 'funnel/cpu-fill' | 'funnel/cpu' | 'funnel/dizzy' | 'funnel/emoji-angry-fill' | 'funnel/emoji-angry' | 'funnel/emoji-dizzy-fill' | 'funnel/exclamation-circle-fill' | 'funnel/exclamation-circle' | 'funnel/file-earmark-break-fill' | 'funnel/file-earmark-break' | 'funnel/file-earmark-minus-fill' | 'funnel/file-earmark-minus' | 'funnel/file-medical-alt' | 'funnel/file-x' | 'funnel/hdd-fill' | 'funnel/hourglass-top' | 'funnel/image-fill' | 'funnel/image' | 'funnel/microchip' | 'funnel/mouse' | 'funnel/patch-exclamation-fill' | 'funnel/sd-card' | 'funnel-fill' | 'funnel-new' | 'funnel' | 'gear-fill' | 'gear' | 'geo-alt-fill-custom' | 'github' | 'graph-up-arrow' | 'graph-up' | 'grid-3x3' | 'grid-check' | 'grid-horizontal' | 'grip-horizontal' | 'hash' | 'hdd-stack' | 'headset' | 'heart-rate' | 'high-engagement' | 'history' | 'hourglass-start' | 'id-card' | 'image' | 'info-circle-fill' | 'info-circle' | 'info-square' | 'info' | 'inspect' | 'integrations/assist' | 'integrations/bugsnag-text' | 'integrations/bugsnag' | 'integrations/cloudwatch-text' | 'integrations/cloudwatch' | 'integrations/datadog' | 'integrations/elasticsearch-text' | 'integrations/elasticsearch' | 'integrations/github' | 'integrations/graphql' | 'integrations/jira-text' | 'integrations/jira' | 'integrations/mobx' | 'integrations/newrelic-text' | 'integrations/newrelic' | 'integrations/ngrx' | 'integrations/openreplay-text' | 'integrations/openreplay' | 'integrations/redux' | 'integrations/rollbar-text' | 'integrations/rollbar' | 'integrations/segment' | 'integrations/sentry-text' | 'integrations/sentry' | 'integrations/slack-bw' | 'integrations/slack' | 'integrations/stackdriver' | 'integrations/sumologic-text' | 'integrations/sumologic' | 'integrations/vuejs' | 'journal-code' | 'layer-group' | 'lightbulb-on' | 'lightbulb' | 'link-45deg' | 'list-alt' | 'list-arrow' | 'list-ul' | 'list' | 'lock-alt' | 'magic' | 'map-marker-alt' | 'memory' | 'mic-mute' | 'mic' | 'minus' | 'mobile' | 'mouse-alt' | 'network' | 'next1' | 'no-dashboard' | 'no-metrics-chart' | 'no-metrics' | 'os/android' | 'os/chrome_os' | 'os/fedora' | 'os/ios' | 'os/linux' | 'os/mac_os_x' | 'os/other' | 'os/ubuntu' | 'os/windows' | 'os' | 'pause-fill' | 'pause' | 'pdf-download' | 'pencil-stop' | 'pencil' | 'percent' | 'performance-icon' | 'person-fill' | 'person' | 'pie-chart-fill' | 'pin-fill' | 'play-circle-light' | 'play-circle' | 'play-fill-new' | 'play-fill' | 'play-hover' | 'play' | 'plus-circle' | 'plus' | 'prev1' | 'puzzle-piece' | 'puzzle' | 'question-circle' | 'question-lg' | 'quote-left' | 'quote-right' | 'quotes' | 'record-circle' | 'redo-back' | 'redo' | 'remote-control' | 'replay-10' | 'resources-icon' | 'safe-fill' | 'safe' | 'sandglass' | 'search' | 'search_notification' | 'server' | 'share-alt' | 'shield-lock' | 'signup' | 'skip-forward-fill' | 'skip-forward' | 'slack' | 'slash-circle' | 'sliders' | 'social/slack' | 'social/trello' | 'spinner' | 'star-solid' | 'star' | 'step-forward' | 'stop-record-circle' | 'stopwatch' | 'store' | 'sync-alt' | 'table-new' | 'table' | 'tablet-android' | 'tachometer-slow' | 'tachometer-slowest' | 'tags' | 'team-funnel' | 'telephone-fill' | 'telephone' | 'text-paragraph' | 'tools' | 'trash' | 'turtle' | 'user-alt' | 'user-circle' | 'user-friends' | 'users' | 'vendors/graphql' | 'vendors/mobx' | 'vendors/ngrx' | 'vendors/redux' | 'vendors/vuex' | 'web-vitals' | 'wifi' | 'window-alt' | 'window-restore' | 'window-x' | 'window' | 'zoom-in'; +export type IconNames = 'alarm-clock' | 'alarm-plus' | 'all-sessions' | 'analytics' | 'anchor' | 'arrow-alt-square-right' | 'arrow-bar-left' | 'arrow-clockwise' | 'arrow-down-short' | 'arrow-down' | 'arrow-repeat' | 'arrow-right-short' | 'arrow-square-left' | 'arrow-square-right' | 'arrow-up-short' | 'arrow-up' | 'arrows-angle-extend' | 'avatar/icn_bear' | 'avatar/icn_beaver' | 'avatar/icn_bird' | 'avatar/icn_bison' | 'avatar/icn_camel' | 'avatar/icn_chameleon' | 'avatar/icn_deer' | 'avatar/icn_dog' | 'avatar/icn_dolphin' | 'avatar/icn_elephant' | 'avatar/icn_fish' | 'avatar/icn_fox' | 'avatar/icn_gorilla' | 'avatar/icn_hippo' | 'avatar/icn_horse' | 'avatar/icn_hyena' | 'avatar/icn_kangaroo' | 'avatar/icn_lemur' | 'avatar/icn_mammel' | 'avatar/icn_monkey' | 'avatar/icn_moose' | 'avatar/icn_panda' | 'avatar/icn_penguin' | 'avatar/icn_porcupine' | 'avatar/icn_quail' | 'avatar/icn_rabbit' | 'avatar/icn_rhino' | 'avatar/icn_sea_horse' | 'avatar/icn_sheep' | 'avatar/icn_snake' | 'avatar/icn_squirrel' | 'avatar/icn_tapir' | 'avatar/icn_turtle' | 'avatar/icn_vulture' | 'avatar/icn_wild1' | 'avatar/icn_wild_bore' | 'ban' | 'bar-chart-line' | 'bar-pencil' | 'bell-fill' | 'bell-plus' | 'bell-slash' | 'bell' | 'binoculars' | 'book' | 'browser/browser' | 'browser/chrome' | 'browser/edge' | 'browser/electron' | 'browser/facebook' | 'browser/firefox' | 'browser/ie' | 'browser/opera' | 'browser/safari' | 'bullhorn' | 'business-time' | 'calendar-alt' | 'calendar-check' | 'calendar-day' | 'calendar' | 'call' | 'camera-alt' | 'camera-video-off' | 'camera-video' | 'camera' | 'caret-down-fill' | 'caret-left-fill' | 'caret-right-fill' | 'caret-up-fill' | 'chat-dots' | 'chat-right-text' | 'chat-square-quote' | 'check-circle-fill' | 'check-circle' | 'check' | 'chevron-double-left' | 'chevron-double-right' | 'chevron-down' | 'chevron-left' | 'chevron-right' | 'chevron-up' | 'circle-fill' | 'circle' | 'clipboard-list-check' | 'clock' | 'close' | 'cloud-fog2-fill' | 'code' | 'cog' | 'cogs' | 'collection' | 'columns-gap-filled' | 'columns-gap' | 'console/error' | 'console/exception' | 'console/info' | 'console/warning' | 'console' | 'controller' | 'cookies' | 'copy' | 'credit-card-front' | 'cubes' | 'dash' | 'dashboard-icn' | 'desktop' | 'device' | 'diagram-3' | 'dizzy' | 'door-closed' | 'doublecheck' | 'download' | 'drag' | 'edit' | 'ellipsis-v' | 'enter' | 'envelope' | 'errors-icon' | 'event/click' | 'event/clickrage' | 'event/code' | 'event/i-cursor' | 'event/input' | 'event/link' | 'event/location' | 'event/resize' | 'event/view' | 'exclamation-circle' | 'expand-wide' | 'explosion' | 'external-link-alt' | 'eye-slash-fill' | 'eye-slash' | 'eye' | 'fetch' | 'file-code' | 'file-medical-alt' | 'file-pdf' | 'file' | 'filter' | 'filters/arrow-return-right' | 'filters/browser' | 'filters/click' | 'filters/clickrage' | 'filters/code' | 'filters/console' | 'filters/country' | 'filters/cpu-load' | 'filters/custom' | 'filters/device' | 'filters/dom-complete' | 'filters/duration' | 'filters/error' | 'filters/fetch-failed' | 'filters/fetch' | 'filters/file-code' | 'filters/graphql' | 'filters/i-cursor' | 'filters/input' | 'filters/lcpt' | 'filters/link' | 'filters/location' | 'filters/memory-load' | 'filters/metadata' | 'filters/os' | 'filters/perfromance-network-request' | 'filters/platform' | 'filters/referrer' | 'filters/resize' | 'filters/rev-id' | 'filters/state-action' | 'filters/ttfb' | 'filters/user-alt' | 'filters/userid' | 'filters/view' | 'flag-na' | 'folder-plus' | 'folder2' | 'fullscreen' | 'funnel/cpu-fill' | 'funnel/cpu' | 'funnel/dizzy' | 'funnel/emoji-angry-fill' | 'funnel/emoji-angry' | 'funnel/emoji-dizzy-fill' | 'funnel/exclamation-circle-fill' | 'funnel/exclamation-circle' | 'funnel/file-earmark-break-fill' | 'funnel/file-earmark-break' | 'funnel/file-earmark-minus-fill' | 'funnel/file-earmark-minus' | 'funnel/file-medical-alt' | 'funnel/file-x' | 'funnel/hdd-fill' | 'funnel/hourglass-top' | 'funnel/image-fill' | 'funnel/image' | 'funnel/microchip' | 'funnel/mouse' | 'funnel/patch-exclamation-fill' | 'funnel/sd-card' | 'funnel-fill' | 'funnel-new' | 'funnel' | 'gear-fill' | 'gear' | 'geo-alt-fill-custom' | 'github' | 'graph-up-arrow' | 'graph-up' | 'grid-3x3' | 'grid-check' | 'grid-horizontal' | 'grip-horizontal' | 'hash' | 'hdd-stack' | 'headset' | 'heart-rate' | 'high-engagement' | 'history' | 'hourglass-start' | 'id-card' | 'image' | 'info-circle-fill' | 'info-circle' | 'info-square' | 'info' | 'inspect' | 'integrations/assist' | 'integrations/bugsnag-text' | 'integrations/bugsnag' | 'integrations/cloudwatch-text' | 'integrations/cloudwatch' | 'integrations/datadog' | 'integrations/elasticsearch-text' | 'integrations/elasticsearch' | 'integrations/github' | 'integrations/graphql' | 'integrations/jira-text' | 'integrations/jira' | 'integrations/mobx' | 'integrations/newrelic-text' | 'integrations/newrelic' | 'integrations/ngrx' | 'integrations/openreplay-text' | 'integrations/openreplay' | 'integrations/redux' | 'integrations/rollbar-text' | 'integrations/rollbar' | 'integrations/segment' | 'integrations/sentry-text' | 'integrations/sentry' | 'integrations/slack-bw' | 'integrations/slack' | 'integrations/stackdriver' | 'integrations/sumologic-text' | 'integrations/sumologic' | 'integrations/teams' | 'integrations/vuejs' | 'journal-code' | 'layer-group' | 'lightbulb-on' | 'lightbulb' | 'link-45deg' | 'list-alt' | 'list-arrow' | 'list-ul' | 'list' | 'lock-alt' | 'magic' | 'map-marker-alt' | 'memory' | 'mic-mute' | 'mic' | 'minus' | 'mobile' | 'mouse-alt' | 'network' | 'next1' | 'no-dashboard' | 'no-metrics-chart' | 'no-metrics' | 'os/android' | 'os/chrome_os' | 'os/fedora' | 'os/ios' | 'os/linux' | 'os/mac_os_x' | 'os/other' | 'os/ubuntu' | 'os/windows' | 'os' | 'pause-fill' | 'pause' | 'pdf-download' | 'pencil-stop' | 'pencil' | 'percent' | 'performance-icon' | 'person-fill' | 'person' | 'pie-chart-fill' | 'pin-fill' | 'play-circle-light' | 'play-circle' | 'play-fill-new' | 'play-fill' | 'play-hover' | 'play' | 'plus-circle' | 'plus' | 'prev1' | 'puzzle-piece' | 'puzzle' | 'question-circle' | 'question-lg' | 'quote-left' | 'quote-right' | 'quotes' | 'record-circle' | 'redo-back' | 'redo' | 'remote-control' | 'replay-10' | 'resources-icon' | 'safe-fill' | 'safe' | 'sandglass' | 'search' | 'search_notification' | 'server' | 'share-alt' | 'shield-lock' | 'signup' | 'skip-forward-fill' | 'skip-forward' | 'slack' | 'slash-circle' | 'sliders' | 'social/slack' | 'social/trello' | 'spinner' | 'star-solid' | 'star' | 'step-forward' | 'stop-record-circle' | 'stopwatch' | 'store' | 'sync-alt' | 'table-new' | 'table' | 'tablet-android' | 'tachometer-slow' | 'tachometer-slowest' | 'tags' | 'team-funnel' | 'telephone-fill' | 'telephone' | 'text-paragraph' | 'tools' | 'trash' | 'turtle' | 'user-alt' | 'user-circle' | 'user-friends' | 'users' | 'vendors/graphql' | 'vendors/mobx' | 'vendors/ngrx' | 'vendors/redux' | 'vendors/vuex' | 'web-vitals' | 'wifi' | 'window-alt' | 'window-restore' | 'window-x' | 'window' | 'zoom-in'; interface Props { name: IconNames; @@ -289,6 +289,7 @@ const SVG = (props: Props) => { case 'integrations/stackdriver': return ; case 'integrations/sumologic-text': return ; case 'integrations/sumologic': return ; + case 'integrations/teams': return ; case 'integrations/vuejs': return ; case 'journal-code': return ; case 'layer-group': return ; diff --git a/frontend/app/duck/integrations/index.js b/frontend/app/duck/integrations/index.js index 0274f7c80..dec847235 100644 --- a/frontend/app/duck/integrations/index.js +++ b/frontend/app/duck/integrations/index.js @@ -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, }; diff --git a/frontend/app/duck/integrations/teams.js b/frontend/app/duck/integrations/teams.js new file mode 100644 index 000000000..9d9add27a --- /dev/null +++ b/frontend/app/duck/integrations/teams.js @@ -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, + }; +} diff --git a/frontend/app/svg/icons/integrations/teams.svg b/frontend/app/svg/icons/integrations/teams.svg new file mode 100644 index 000000000..e93adb2b8 --- /dev/null +++ b/frontend/app/svg/icons/integrations/teams.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + +