feat(ui): Add support for slack chat (#6015)

* feat(ui): Add support for slack chat

* updated icons and styling

* Add to all the pages

* Fix UT failure
This commit is contained in:
Vivek Ratnavel Subramanian 2022-07-14 07:01:27 -07:00 committed by GitHub
parent 0a921abf8b
commit 4f61169df6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 344 additions and 28 deletions

View File

@ -33,6 +33,7 @@ import org.openmetadata.catalog.security.AuthenticationConfiguration;
import org.openmetadata.catalog.security.AuthorizerConfiguration;
import org.openmetadata.catalog.security.jwt.JWTTokenConfiguration;
import org.openmetadata.catalog.slack.SlackPublisherConfiguration;
import org.openmetadata.catalog.slackChat.SlackChatConfiguration;
public class CatalogApplicationConfig extends Configuration {
@JsonProperty("database")
@ -105,6 +106,11 @@ public class CatalogApplicationConfig extends Configuration {
@Setter
private boolean sandboxModeEnabled;
@JsonProperty("slackChat")
@Getter
@Setter
private SlackChatConfiguration slackChatConfiguration = new SlackChatConfiguration();
@JsonProperty("secretsManagerConfiguration")
@Getter
@Setter

View File

@ -30,6 +30,7 @@ import org.openmetadata.catalog.security.AuthenticationConfiguration;
import org.openmetadata.catalog.security.AuthorizerConfiguration;
import org.openmetadata.catalog.security.jwt.JWKSResponse;
import org.openmetadata.catalog.security.jwt.JWTTokenGenerator;
import org.openmetadata.catalog.slackChat.SlackChatConfiguration;
@Path("/v1/config")
@Api(value = "Get configuration")
@ -111,6 +112,29 @@ public class ConfigResource {
return sandboxConfiguration;
}
@GET
@Path(("/slackChat"))
@Operation(
operationId = "getSlackChatConfiguration",
summary = "Get Slack Chat Configuration",
tags = "config",
responses = {
@ApiResponse(
responseCode = "200",
description = "Get Slack Chat Configuration",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = SlackChatConfiguration.class)))
})
public SlackChatConfiguration getSlackChatConfiguration() {
SlackChatConfiguration slackChatConfiguration = new SlackChatConfiguration();
if (catalogApplicationConfig.getSlackChatConfiguration() != null) {
slackChatConfiguration = catalogApplicationConfig.getSlackChatConfiguration();
}
return slackChatConfiguration;
}
@GET
@Path(("/airflow"))
@Operation(

View File

@ -0,0 +1,13 @@
package org.openmetadata.catalog.slackChat;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class SlackChatConfiguration {
private String apiToken;
private String botName;
private List<String> channels;
}

View File

@ -36,6 +36,7 @@ import org.openmetadata.catalog.security.AuthenticationConfiguration;
import org.openmetadata.catalog.security.AuthorizerConfiguration;
import org.openmetadata.catalog.security.jwt.JWKSKey;
import org.openmetadata.catalog.security.jwt.JWKSResponse;
import org.openmetadata.catalog.slackChat.SlackChatConfiguration;
import org.openmetadata.catalog.util.TestUtils;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@ -74,6 +75,15 @@ class ConfigResourceTest extends CatalogApplicationTest {
assertEquals(config.getAirflowConfiguration().getApiEndpoint(), auth.getApiEndpoint());
}
@Test
void get_slack_chat_configs_200_OK() throws IOException {
WebTarget target = getConfigResource("slackChat");
SlackChatConfiguration slackChatConfiguration =
TestUtils.get(target, SlackChatConfiguration.class, TEST_AUTH_HEADERS);
assertEquals(config.getSlackChatConfiguration().getApiToken(), slackChatConfiguration.getApiToken());
assertEquals(config.getSlackChatConfiguration().getBotName(), slackChatConfiguration.getBotName());
}
@Test
void get_jwks_configs_200_OK() throws IOException {
WebTarget target = getConfigResource("jwks");

View File

@ -159,3 +159,8 @@ airflowConfiguration:
password: "admin"
metadataApiEndpoint: "http://localhost:8585/api"
authProvider: "no-auth"
slackChat:
apiToken: "token"
botName: "bot"
channels: ["support"]

View File

@ -244,3 +244,7 @@ health:
successAttempts: 1
sandboxModeEnabled: ${SANDBOX_MODE_ENABLED:-false}
slackChat:
apiToken: ${SLACK_CHAT_API_TOKEN:-""}
botName: ${SLACK_CHAT_BOT_NAME:-""}
channels: ${SLACK_CHAT_CHANNELS:-[]}

View File

@ -72,6 +72,7 @@
"react-quill": "^1.3.5",
"react-router-dom": "^5.2.0",
"react-select": "^5.2.2",
"react-slack-chat": "https://github.com/vivekratnavel/react-slack-chat.git",
"react-slick": "^0.28.1",
"react-table": "^7.7.0",
"react-tippy": "^1.4.0",

View File

@ -24,17 +24,48 @@ import {
faSearch,
faTimes,
} from '@fortawesome/free-solid-svg-icons';
import React, { FunctionComponent } from 'react';
import { AxiosError } from 'axios';
import { SlackChatConfig } from 'Models';
import React, { FunctionComponent, useEffect, useState } from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.min.css';
import { AuthProvider } from './authentication/auth-provider/AuthProvider';
import { fetchSlackConfig } from './axiosAPIs/miscAPI';
import SlackChat from './components/SlackChat/SlackChat';
import WebSocketProvider from './components/web-scoket/web-scoket.provider';
import { toastOptions } from './constants/toast.constants';
import ErrorBoundry from './ErrorBoundry/ErrorBoundry';
import AppRouter from './router/AppRouter';
const App: FunctionComponent = () => {
const [slackConfig, setSlackConfig] = useState<SlackChatConfig | undefined>();
const fetchSlackChatConfig = () => {
fetchSlackConfig()
.then((res) => {
if (res.data) {
const { apiToken, botName, channels } = res.data;
const slackConfig = {
apiToken,
botName,
channels,
};
setSlackConfig(slackConfig);
} else {
throw '';
}
})
.catch((err: AxiosError) => {
// eslint-disable-next-line no-console
console.error(err);
setSlackConfig(undefined);
});
};
useEffect(() => {
fetchSlackChatConfig();
}, []);
library.add(
faTimes,
faCheck,
@ -56,6 +87,9 @@ const App: FunctionComponent = () => {
<WebSocketProvider>
<AuthProvider childComponentType={AppRouter}>
<AppRouter />
{slackConfig && slackConfig.apiToken ? (
<SlackChat slackConfig={slackConfig} />
) : null}
</AuthProvider>
</WebSocketProvider>
</ErrorBoundry>

View File

@ -0,0 +1,5 @@
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="256" cy="256" r="256" fill="white"/>
<path d="M372.366 276.948V213.4C372.366 182.501 360.106 152.867 338.282 131.018C316.459 109.169 286.86 96.8945 255.998 96.8945C225.135 96.8945 195.536 109.169 173.713 131.018C151.889 152.867 139.629 182.501 139.629 213.4V276.948C139.629 307.847 151.889 337.481 173.713 359.33C195.536 381.179 225.135 393.453 255.998 393.453C286.86 393.453 316.459 381.179 338.282 359.33C360.106 337.481 372.366 307.847 372.366 276.948ZM216.749 311.794C217.733 310.801 218.903 310.013 220.192 309.475C221.481 308.937 222.864 308.661 224.261 308.661C225.657 308.661 227.04 308.937 228.329 309.475C229.618 310.013 230.788 310.801 231.772 311.794C234.947 314.989 238.722 317.526 242.879 319.256C247.037 320.987 251.495 321.878 255.998 321.878C260.5 321.878 264.958 320.987 269.115 319.256C273.273 317.526 277.048 314.989 280.223 311.794C282.215 309.8 284.917 308.679 287.735 308.679C290.552 308.679 293.253 309.8 295.245 311.794C297.237 313.788 298.356 316.493 298.356 319.313C298.356 322.134 297.237 324.839 295.245 326.834C258.536 363.162 199.4 329.164 216.749 311.794Z" fill="#7147E8"/>
<path d="M425.263 192.215H413.203C407.977 154.19 389.177 119.344 360.28 94.1204C331.381 68.8965 294.338 55 256 55C217.662 55 180.619 68.8965 151.72 94.1204C122.822 119.344 104.023 154.19 98.7969 192.215H86.7369C78.3197 192.215 70.2473 195.563 64.2955 201.522C58.3437 207.48 55 215.563 55 223.99V287.538C55 295.965 58.3437 304.047 64.2955 310.005C70.2473 315.965 78.3197 319.312 86.7369 319.312H118.474C121.279 319.312 123.97 318.196 125.954 316.21C127.938 314.223 129.053 311.529 129.053 308.721V202.807C129.085 200.268 128.206 197.803 126.575 195.859C124.944 193.915 122.67 192.621 120.166 192.215C125.288 159.835 141.783 130.346 166.682 109.054C191.583 87.7614 223.254 76.0633 256 76.0633C288.746 76.0633 320.417 87.7614 345.318 109.054C370.217 130.346 386.712 159.835 391.834 192.215C389.331 192.621 387.056 193.915 385.425 195.859C383.794 197.803 382.915 200.268 382.947 202.807V308.721C382.947 311.529 384.062 314.223 386.046 316.21C388.03 318.196 390.72 319.312 393.526 319.312C393.534 346.543 384.016 372.916 366.622 393.851C349.229 414.786 325.061 428.96 298.316 433.911C298.782 430.163 298.445 426.359 297.327 422.752C296.21 419.145 294.338 415.818 291.835 412.992C289.333 410.166 286.258 407.907 282.815 406.363C279.373 404.82 275.641 404.029 271.869 404.043H250.71C243.697 404.043 236.969 406.832 232.01 411.799C227.05 416.764 224.263 423.499 224.263 430.521C224.263 437.544 227.05 444.279 232.01 449.245C236.969 454.21 243.697 457 250.71 457H277.158C313.632 457 348.612 442.493 374.404 416.672C400.195 390.851 414.684 355.829 414.684 319.312H425.263C433.68 319.312 441.753 315.965 447.705 310.005C453.656 304.047 457 295.965 457 287.538V223.99C457 215.563 453.656 207.48 447.705 201.522C441.753 195.563 433.68 192.215 425.263 192.215Z" fill="#35198E"/>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,10 @@
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M512 256C512 397.387 397.387 512 256 512C114.613 512 0 397.387 0 256C0 114.613 114.613 0 256 0C397.387 0 512 114.613 512 256Z" fill="url(#paint0_linear_11219_10541)"/>
<path d="M314.203 247.938C337.719 230.227 352.953 202.086 352.953 170.449C352.953 116.992 309.461 73.5 256 73.5C202.543 73.5 159.051 116.992 159.051 170.449C159.051 202.086 174.281 230.227 197.797 247.938C134.836 271.57 89.9023 332.383 89.9023 403.5H119.902C119.902 328.453 180.957 267.402 256.004 267.402C331.047 267.402 392.102 328.453 392.102 403.5H422.102C422.098 332.383 377.168 271.57 314.203 247.938ZM189.051 170.449C189.051 133.531 219.082 103.5 256 103.5C292.918 103.5 322.949 133.531 322.949 170.449C322.949 207.367 292.918 237.402 256 237.402C219.082 237.402 189.051 207.367 189.051 170.449Z" fill="white"/>
<defs>
<linearGradient id="paint0_linear_11219_10541" x1="256" y1="512" x2="256" y2="0" gradientUnits="userSpaceOnUse">
<stop stop-color="#35198E"/>
<stop offset="1" stop-color="#8D6AF1"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -64,6 +64,10 @@ export const fetchSandboxConfig = (): Promise<AxiosResponse> => {
return APIClient.get('/config/sandbox');
};
export const fetchSlackConfig = (): Promise<AxiosResponse> => {
return APIClient.get('/config/slackChat');
};
export const fetchAirflowConfig = (): Promise<AxiosResponse> => {
return APIClient.get('/config/airflow');
};

View File

@ -13,7 +13,7 @@
import { AxiosError, AxiosResponse } from 'axios';
import { capitalize } from 'lodash';
import { FormatedTableData } from 'Models';
import { FormattedTableData } from 'Models';
import React, { FC, HTMLAttributes, useEffect, useState } from 'react';
import { getSuggestions } from '../../axiosAPIs/miscAPI';
import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants';
@ -35,7 +35,7 @@ const NodeSuggestions: FC<EntitySuggestionProps> = ({
entityType,
onSelectHandler,
}) => {
const [data, setData] = useState<Array<FormatedTableData>>([]);
const [data, setData] = useState<Array<FormattedTableData>>([]);
const [isOpen, setIsOpen] = useState<boolean>(false);
const [searchValue, setSearchValue] = useState<string>('');

View File

@ -12,7 +12,7 @@
*/
import { Button, Card, Typography } from 'antd';
import { FormatedTableData } from 'Models';
import { FormattedTableData } from 'Models';
import React, { Fragment, FunctionComponent } from 'react';
import { Link } from 'react-router-dom';
import { EntityReference } from '../../generated/type/entityReference';
@ -20,14 +20,14 @@ import { getEntityName } from '../../utils/CommonUtils';
import { getEntityIcon, getEntityLink } from '../../utils/TableUtils';
import { leftPanelAntCardStyle } from '../containers/PageLayout';
interface Prop {
entityList: Array<FormatedTableData>;
entityList: Array<FormattedTableData>;
headerText: string | JSX.Element;
noDataPlaceholder: JSX.Element;
testIDText: string;
}
interface AntdEntityListProp {
entityList: Array<FormatedTableData>;
entityList: Array<FormattedTableData>;
headerText?: string | JSX.Element;
headerTextLabel: string;
noDataPlaceholder: JSX.Element;

View File

@ -23,7 +23,7 @@ import {
AggregationType,
Bucket,
FilterObject,
FormatedTableData,
FormattedTableData,
SearchResponse,
} from 'Models';
import React, {
@ -102,7 +102,7 @@ const Explore: React.FC<ExploreProps> = ({
...INITIAL_FILTERS,
...initialFilter,
};
const [data, setData] = useState<Array<FormatedTableData>>([]);
const [data, setData] = useState<Array<FormattedTableData>>([]);
const [filters, setFilters] = useState<FilterObject>({
...filterObject,
...searchFilter,

View File

@ -11,7 +11,7 @@
* limitations under the License.
*/
import { FormatedTableData, SearchDataFunctionType } from 'Models';
import { FormattedTableData, SearchDataFunctionType } from 'Models';
import { FeedFilter } from '../../enums/mydata.enum';
import { Thread, ThreadType } from '../../generated/entity/feed/thread';
import { User } from '../../generated/entity/teams/user';
@ -34,8 +34,8 @@ export interface MyDataProps {
ownedDataCount: number;
countPipelines: number;
userDetails?: User;
ownedData: Array<FormatedTableData>;
followedData: Array<FormatedTableData>;
ownedData: Array<FormattedTableData>;
followedData: Array<FormattedTableData>;
feedData: Thread[];
paging: Paging;
isFeedLoading: boolean;

View File

@ -0,0 +1,68 @@
/*
* Copyright 2021 Collate
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { SlackChatConfig } from 'Models';
import React, { FC, useMemo } from 'react';
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
import { ReactSlackChat } from 'react-slack-chat/dist/react-slack-chat-with-default-hooks';
import AppState from '../../AppState';
import ChannelIcon from '../../assets/img/slackChat/icon-support.svg';
import UserIcon from '../../assets/img/slackChat/icon-user.svg';
type Props = {
slackConfig: SlackChatConfig;
};
const SlackChat: FC<Props> = ({ slackConfig }) => {
const currentUser = useMemo(
() => AppState.getCurrentUserDetails(),
[AppState.userDetails, AppState.nonSecureUserDetails]
);
const channels = slackConfig.channels.map((ch) => {
return { name: ch, icon: ChannelIcon };
});
const customHooks = [
{
id: 'getUrl',
action: () => Promise.resolve('URL: ' + window.location.href),
},
{
id: 'getUser',
action: () =>
Promise.resolve(
`User: ${currentUser?.name}, Email: ${currentUser?.email}, Name: ${currentUser?.displayName}, Admin: ${currentUser?.isAdmin}`
),
},
];
const botName = currentUser?.name || slackConfig.botName || 'support-bot';
return (
<div className="slack-chat">
<ReactSlackChat
closeChatButton
apiToken={slackConfig.apiToken}
botName={botName}
channels={channels}
defaultMessage="Welcome! Someone will help shortly."
helpText="Need Help?"
hooks={customHooks}
singleUserMode={false}
themeColor="#7147E8"
userImage={UserIcon}
/>
</div>
);
};
export default SlackChat;

View File

@ -11,7 +11,7 @@
* limitations under the License.
*/
import { FormatedTableData } from 'Models';
import { FormattedTableData } from 'Models';
import React, { Fragment, FunctionComponent, useEffect, useState } from 'react';
import { getRecentlyViewedData, prepareLabel } from '../../utils/CommonUtils';
import { EntityListWithAntd } from '../EntityList/EntityList';
@ -19,7 +19,7 @@ import Loader from '../Loader/Loader';
const RecentlyViewed: FunctionComponent = () => {
const recentlyViewedData = getRecentlyViewedData();
const [data, setData] = useState<Array<FormatedTableData>>([]);
const [data, setData] = useState<Array<FormattedTableData>>([]);
const [isLoading, setIsloading] = useState<boolean>(false);
const prepareData = () => {
@ -35,7 +35,7 @@ const RecentlyViewed: FunctionComponent = () => {
};
})
.filter((item) => item.name);
setData(formattedData as unknown as FormatedTableData[]);
setData(formattedData as unknown as FormattedTableData[]);
setIsloading(false);
}
};

View File

@ -17,7 +17,7 @@ import {
getByText,
render,
} from '@testing-library/react';
import { FormatedTableData } from 'Models';
import { FormattedTableData } from 'Models';
import React from 'react';
import { MemoryRouter } from 'react-router';
import SearchedData from './SearchedData';
@ -62,7 +62,7 @@ const mockData = [
tier: { tagFQN: 'tier3' },
index: 'index1',
},
] as FormatedTableData[];
] as FormattedTableData[];
const mockPaginate = jest.fn();

View File

@ -12,7 +12,7 @@
*/
import { isUndefined } from 'lodash';
import { FormatedTableData } from 'Models';
import { FormattedTableData } from 'Models';
import PropTypes from 'prop-types';
import React, { ReactNode } from 'react';
import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants';
@ -29,7 +29,7 @@ import Loader from '../Loader/Loader';
import Onboarding from '../onboarding/Onboarding';
type SearchedDataProp = {
children?: ReactNode;
data: Array<FormatedTableData>;
data: Array<FormattedTableData>;
currentPage: number;
isLoading?: boolean;
paginate: (value: string | number) => void;

View File

@ -201,7 +201,13 @@ declare module 'Models' {
href: string;
};
export type FormatedTableData = {
export type SlackChatConfig = {
apiToken: string;
botName: string;
channels: string[];
};
export type FormattedTableData = {
id: string;
name: string;
displayName: string;
@ -286,7 +292,7 @@ declare module 'Models' {
}
export interface GlossaryTermAssets {
data: FormatedTableData[];
data: FormattedTableData[];
total: number;
currPage: number;
}
@ -357,7 +363,7 @@ declare module 'Models' {
_type?: string;
_id?: string;
_score?: number;
_source: FormatedTableData;
_source: FormattedTableData;
};
export type SearchResponse = {

View File

@ -15,7 +15,7 @@ import { AxiosError, AxiosResponse } from 'axios';
import { Operation } from 'fast-json-patch';
import { isEmpty, isNil, isUndefined } from 'lodash';
import { observer } from 'mobx-react';
import { FormatedTableData } from 'Models';
import { FormattedTableData } from 'Models';
import React, {
Fragment,
useCallback,
@ -73,8 +73,8 @@ const MyDataPage = () => {
const [countUsers, setCountUsers] = useState<number>();
const [countTeams, setCountTeams] = useState<number>();
const [ownedData, setOwnedData] = useState<Array<FormatedTableData>>();
const [followedData, setFollowedData] = useState<Array<FormatedTableData>>();
const [ownedData, setOwnedData] = useState<Array<FormattedTableData>>();
const [followedData, setFollowedData] = useState<Array<FormattedTableData>>();
const [ownedDataCount, setOwnedDataCount] = useState(0);
const [followedDataCount, setFollowedDataCount] = useState(0);
const [pendingTaskCount, setPendingTaskCount] = useState(0);
@ -411,7 +411,7 @@ const MyDataPage = () => {
updateThreadData(threadId, postId, isThread, data, setEntityThread);
};
const fetchOMDMode = () => {
const fetchSandboxMode = () => {
fetchSandboxConfig()
.then((res) => {
if (res.data) {
@ -446,7 +446,7 @@ const MyDataPage = () => {
}, [currentUser]);
useEffect(() => {
fetchOMDMode();
fetchSandboxMode();
fetchData(true);
fetchMyTaskData();
}, []);

View File

@ -57,6 +57,15 @@ jest.mock('../../axiosAPIs/miscAPI', () => ({
},
})
),
fetchSlackConfig: jest.fn().mockImplementation(() =>
Promise.resolve({
data: {
apiToken: '',
botName: '',
channels: [],
},
})
),
}));
jest.mock('../../axiosAPIs/tableAPI', () => ({
@ -205,8 +214,11 @@ describe('Test MyData page component', () => {
/GithubStarButton.component/i
);
const slackChat = await queryByText(container, /SlackChat.component/i);
expect(myData).toBeInTheDocument();
expect(githubStarButton).not.toBeInTheDocument();
expect(slackChat).not.toBeInTheDocument();
});
it('Component should render in sandbox mode', async () => {

View File

@ -1878,6 +1878,13 @@
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.4.4":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.6.tgz#6a1ef59f838debd670421f8c7f2cbb8da9751580"
integrity sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==
dependencies:
regenerator-runtime "^0.13.4"
"@babel/template@^7.14.5", "@babel/template@^7.3.3", "@babel/template@^7.4.0":
version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4"
@ -2164,11 +2171,21 @@
resolved "https://registry.yarnpkg.com/@exodus/schemasafe/-/schemasafe-1.0.0-rc.6.tgz#7985f681564cff4ffaebb5896eb4be20af3aae7a"
integrity sha512-dDnQizD94EdBwEj/fh3zPRa/HWCS9O5au2PuHhZBbuM3xWHxuaKzPBOEWze7Nn0xW68MIpZ7Xdyn1CoCpjKCuQ==
"@fortawesome/fontawesome-common-types@6.1.1":
version "6.1.1"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.1.1.tgz#7dc996042d21fc1ae850e3173b5c67b0549f9105"
integrity sha512-wVn5WJPirFTnzN6tR95abCx+ocH+3IFLXAgyavnf9hUmN0CfWoDjPT/BAWsUVwSlYYVBeCLJxaqi7ZGe4uSjBA==
"@fortawesome/fontawesome-common-types@^0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.3.0.tgz#949995a05c0d8801be7e0a594f775f1dbaa0d893"
integrity sha512-CA3MAZBTxVsF6SkfkHXDerkhcQs0QPofy43eFdbWJJkZiq3SfiaH1msOkac59rQaqto5EqWnASboY1dBuKen5w==
"@fortawesome/fontawesome-free@^6.1.1":
version "6.1.1"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-6.1.1.tgz#bf5d45611ab74890be386712a0e5d998c65ee2a1"
integrity sha512-J/3yg2AIXc9wznaVqpHVX3Wa5jwKovVF0AMYSnbmcXTiL3PpRPfF58pzWucCwEiCJBp+hCNRLWClTomD8SseKg==
"@fortawesome/fontawesome-svg-core@^1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.3.0.tgz#343fac91fa87daa630d26420bfedfba560f85885"
@ -2176,6 +2193,13 @@
dependencies:
"@fortawesome/fontawesome-common-types" "^0.3.0"
"@fortawesome/fontawesome-svg-core@^6.1.1":
version "6.1.1"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.1.1.tgz#3424ec6182515951816be9b11665d67efdce5b5f"
integrity sha512-NCg0w2YIp81f4V6cMGD9iomfsIj7GWrqmsa0ZsPh59G7PKiGN1KymZNxmF00ssuAlo/VZmpK6xazsGOwzKYUMg==
dependencies:
"@fortawesome/fontawesome-common-types" "6.1.1"
"@fortawesome/free-solid-svg-icons@^6.0.0":
version "6.0.0"
resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.0.0.tgz#bed4a501b631c6cfa35c09830f7cb63ffca1589d"
@ -2183,6 +2207,13 @@
dependencies:
"@fortawesome/fontawesome-common-types" "^0.3.0"
"@fortawesome/free-solid-svg-icons@^6.1.1":
version "6.1.1"
resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.1.1.tgz#3369e673f8fe8be2fba30b1ec274d47490a830a6"
integrity sha512-0/5exxavOhI/D4Ovm2r3vxNojGZioPwmFrKg0ZUH69Q68uFhFPs6+dhAToh6VEQBntxPRYPuT5Cg1tpNa9JUPg==
dependencies:
"@fortawesome/fontawesome-common-types" "6.1.1"
"@fortawesome/react-fontawesome@^0.1.17":
version "0.1.17"
resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.17.tgz#06fc06cb1a721e38e5b50b4a1cb851e9b9c77d7a"
@ -2190,6 +2221,13 @@
dependencies:
prop-types "^15.8.1"
"@fortawesome/react-fontawesome@^0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz#d90dd8a9211830b4e3c08e94b63a0ba7291ddcf4"
integrity sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==
dependencies:
prop-types "^15.8.1"
"@github/g-emoji-element@^1.1.5":
version "1.1.5"
resolved "https://registry.yarnpkg.com/@github/g-emoji-element/-/g-emoji-element-1.1.5.tgz#4fd6b20caf49b88705cf3365d1d1f00a69dfa29a"
@ -4353,6 +4391,11 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
base64-arraybuffer@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc"
integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==
base64-js@^1.3.1, base64-js@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
@ -5417,6 +5460,13 @@ css-color-keywords@^1.0.0:
resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
integrity sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=
css-line-break@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-2.1.0.tgz#bfef660dfa6f5397ea54116bb3cb4873edbc4fa0"
integrity sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==
dependencies:
utrie "^1.0.2"
css-loader@3.4.2:
version "3.4.2"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.4.2.tgz#d3fdb3358b43f233b78501c5ed7b1c6da6133202"
@ -7445,6 +7495,11 @@ getpass@^0.1.1:
dependencies:
assert-plus "^1.0.0"
gh-emoji@^0.2.5:
version "0.2.5"
resolved "https://registry.yarnpkg.com/gh-emoji/-/gh-emoji-0.2.5.tgz#a6755eba4f9c2af24a473c27a4963433286bbeff"
integrity sha512-UsQk7SV8OQqoqGOz0Iq4evioAJVAYHmvjYrY6m1h5aBcovUhRvKbdDpB3AgbyemKJd13+QiDPUsrznveg3mWWQ==
glob-parent@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
@ -7855,6 +7910,14 @@ html-webpack-plugin@^4.5.1:
tapable "^1.1.3"
util.promisify "1.0.0"
html2canvas@^1.0.0-rc.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/html2canvas/-/html2canvas-1.4.1.tgz#7cef1888311b5011d507794a066041b14669a543"
integrity sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==
dependencies:
css-line-break "^2.1.0"
text-segmentation "^1.0.3"
htmlparser2@6.1.0, htmlparser2@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
@ -11840,6 +11903,14 @@ prompts@^2.0.1:
kleur "^3.0.3"
sisteransi "^1.0.5"
prop-types@15.6.2:
version "15.6.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
integrity sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==
dependencies:
loose-envify "^1.3.1"
object-assign "^4.1.1"
prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
@ -12574,7 +12645,7 @@ react-dom-factories@^1.0.0:
resolved "https://registry.yarnpkg.com/react-dom-factories/-/react-dom-factories-1.0.2.tgz#eb7705c4db36fb501b3aa38ff759616aa0ff96e0"
integrity sha1-63cFxNs2+1AbOqOP91lhaqD/luA=
react-dom@^16.14.0:
react-dom@^16.14.0, react-dom@^16.8.6:
version "16.14.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89"
integrity sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==
@ -12743,6 +12814,23 @@ react-select@^5.2.2:
prop-types "^15.6.0"
react-transition-group "^4.3.0"
"react-slack-chat@https://github.com/vivekratnavel/react-slack-chat.git":
version "1.15.1"
resolved "https://github.com/vivekratnavel/react-slack-chat.git#92735b89f2744c8beff7708be668f52ddbd6ca6e"
dependencies:
"@babel/runtime" "^7.4.4"
"@fortawesome/fontawesome-free" "^6.1.1"
"@fortawesome/fontawesome-svg-core" "^6.1.1"
"@fortawesome/free-solid-svg-icons" "^6.1.1"
"@fortawesome/react-fontawesome" "^0.2.0"
classnames "^2.2.6"
gh-emoji "^0.2.5"
html2canvas "^1.0.0-rc.1"
prop-types "15.6.2"
react "^16.8.6"
react-dom "^16.8.6"
slack "^11.0.2"
react-slick@^0.28.1:
version "0.28.1"
resolved "https://registry.yarnpkg.com/react-slick/-/react-slick-0.28.1.tgz#12c18d991b59432df9c3757ba540a227b3fb85b9"
@ -12828,7 +12916,7 @@ react-transition-group@^4.3.0:
loose-envify "^1.4.0"
prop-types "^15.6.2"
react@^16.14.0:
react@^16.14.0, react@^16.8.6:
version "16.14.0"
resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d"
integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==
@ -13855,6 +13943,13 @@ sisteransi@^1.0.5:
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==
slack@^11.0.2:
version "11.0.2"
resolved "https://registry.yarnpkg.com/slack/-/slack-11.0.2.tgz#30f68527c5d1712b7faa3141db7716f89ac6e911"
integrity sha512-rv842+S+AGyZCmMMd8xPtW5DvJ9LzWTAKfxi8Gw57oYlXgcKtFuHd4nqk6lTPpRKdUGn3tx/Drd0rjQR3dQPqw==
dependencies:
tiny-json-http "^7.0.2"
slash@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"
@ -14633,6 +14728,13 @@ text-encoding@^0.7.0:
resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.7.0.tgz#f895e836e45990624086601798ea98e8f36ee643"
integrity sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==
text-segmentation@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/text-segmentation/-/text-segmentation-1.0.3.tgz#52a388159efffe746b24a63ba311b6ac9f2d7943"
integrity sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==
dependencies:
utrie "^1.0.2"
text-table@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@ -14668,6 +14770,11 @@ tiny-invariant@^1.0.2:
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875"
integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==
tiny-json-http@^7.0.2:
version "7.4.2"
resolved "https://registry.yarnpkg.com/tiny-json-http/-/tiny-json-http-7.4.2.tgz#2948d7a7f650d69df65f10982f126b5c5520ce3d"
integrity sha512-+3ns4PfQTLaF69zGASkAfDoOEVmwYTXSDrU6VR93h317uFOW7evFzKa7Ih9JzPHiYSee3lUXHLAGhws2wFSexQ==
tiny-warning@^1.0.0, tiny-warning@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
@ -15284,6 +15391,13 @@ utils-merge@1.0.1:
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
utrie@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/utrie/-/utrie-1.0.2.tgz#d42fe44de9bc0119c25de7f564a6ed1b2c87a645"
integrity sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==
dependencies:
base64-arraybuffer "^1.0.2"
uuid@^3.3.2, uuid@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"