diff --git a/kibana-reports/package.json b/kibana-reports/package.json index 7652f19a..87d18883 100644 --- a/kibana-reports/package.json +++ b/kibana-reports/package.json @@ -30,6 +30,7 @@ "@types/dompurify": "^2.0.4", "@types/jsdom": "^16.2.4", "babel-polyfill": "^6.26.0", + "cheerio": "^1.0.0-rc.3", "cron-validator": "^1.1.1", "dompurify": "^2.1.1", "elastic-builder": "^2.7.1", diff --git a/kibana-reports/public/components/main/report_details/report_details.tsx b/kibana-reports/public/components/main/report_details/report_details.tsx index f1e361e5..f40d4f5c 100644 --- a/kibana-reports/public/components/main/report_details/report_details.tsx +++ b/kibana-reports/public/components/main/report_details/report_details.tsx @@ -147,20 +147,12 @@ export function ReportDetails(props) { scheduleDetails: `\u2014`, alertDetails: `\u2014`, channel: deliveryType, - kibanaRecipients: deliveryParams.kibana_recipients - ? deliveryParams.kibana_recipients - : `\u2014`, emailRecipients: deliveryType === 'Channel' ? deliveryParams.recipients : `\u2014`, emailSubject: deliveryType === 'Channel' ? deliveryParams.title : `\u2014`, emailBody: deliveryType === 'Channel' ? deliveryParams.textDescription : `\u2014`, - reportAsAttachment: - deliveryType === 'Channel' && - deliveryParams.email_format === 'Attachment' - ? 'True' - : 'False', queryUrl: queryUrl, }; return reportDetails; @@ -194,9 +186,16 @@ export function ReportDetails(props) { let formatUpper = data['defaultFileFormat']; formatUpper = fileFormatsUpper[formatUpper]; return ( - { - generateReportById(reportId, props.httpClient, handleSuccessToast, handleErrorToast); - }}> + { + generateReportById( + reportId, + props.httpClient, + handleSuccessToast, + handleErrorToast + ); + }} + > {formatUpper + ' '} @@ -307,18 +306,10 @@ export function ReportDetails(props) { -

Delivery settings

+

Notification settings

- - - - - - - diff --git a/kibana-reports/public/components/report_definitions/delivery/delivery.tsx b/kibana-reports/public/components/report_definitions/delivery/delivery.tsx index dac8d3eb..e2286997 100644 --- a/kibana-reports/public/components/report_definitions/delivery/delivery.tsx +++ b/kibana-reports/public/components/report_definitions/delivery/delivery.tsx @@ -22,9 +22,8 @@ import { EuiPageContentBody, EuiHorizontalRule, EuiSpacer, - EuiRadioGroup, + EuiCheckbox, } from '@elastic/eui'; -import { KibanaUserDelivery } from './kibana_user'; import { DELIVERY_TYPE_OPTIONS } from './delivery_constants'; import 'react-mde/lib/styles/css/react-mde-all.css'; import { reportDefinitionParams } from '../create/create_report_definition'; @@ -44,22 +43,31 @@ export function ReportDelivery(props: ReportDeliveryProps) { editDefinitionId, reportDefinitionRequest, httpClientProps, - showEmailRecipientsError, } = props; - const [deliveryType, setDeliveryType] = useState(DELIVERY_TYPE_OPTIONS[0].id); + const [emailCheckbox, setEmailCheckbox] = useState(false); - const handleDeliveryType = (e: string) => { - setDeliveryType(e); - reportDefinitionRequest.delivery.delivery_type = e; + const handleEmailCheckbox = (e: { + target: { checked: React.SetStateAction }; + }) => { + setEmailCheckbox(e.target.checked); + if (e.target.checked) { + // if checked, set delivery type to email + reportDefinitionRequest.delivery.delivery_type = + DELIVERY_TYPE_OPTIONS[1].id; + } else { + // uncheck email checkbox means to use default setting, which is kibana user + defaultCreateDeliveryParams(); + } }; - const deliverySetting = (props: ReportDeliveryProps) => { - return deliveryType === DELIVERY_TYPE_OPTIONS[0].id ? ( - - ) : ( - - ); + const emailDelivery = emailCheckbox ? : null; + + const defaultCreateDeliveryParams = () => { + reportDefinitionRequest.delivery = { + delivery_type: DELIVERY_TYPE_OPTIONS[0].id, + delivery_params: { kibana_recipients: [] }, + }; }; useEffect(() => { @@ -67,10 +75,14 @@ export function ReportDelivery(props: ReportDeliveryProps) { httpClientProps .get(`../api/reporting/reportDefinitions/${editDefinitionId}`) .then(async (response) => { - handleDeliveryType(response.report_definition.delivery.delivery_type); + const isEmailSelected = + response.report_definition.delivery.delivery_type === + DELIVERY_TYPE_OPTIONS[1].id; + handleEmailCheckbox({ target: { checked: isEmailSelected } }); }); } else { - reportDefinitionRequest.delivery.delivery_type = deliveryType; + // By default it's set to deliver to kibana user + defaultCreateDeliveryParams(); } }, []); @@ -78,20 +90,19 @@ export function ReportDelivery(props: ReportDeliveryProps) { -

Delivery settings

+

Notification settings

- - - + - {deliverySetting(props)} + {emailDelivery}
); diff --git a/kibana-reports/public/components/report_definitions/delivery/delivery_constants.tsx b/kibana-reports/public/components/report_definitions/delivery/delivery_constants.tsx index 523d13d5..109d5386 100644 --- a/kibana-reports/public/components/report_definitions/delivery/delivery_constants.tsx +++ b/kibana-reports/public/components/report_definitions/delivery/delivery_constants.tsx @@ -13,27 +13,7 @@ * permissions and limitations under the License. */ -export const EMAIL_RECIPIENT_OPTIONS = [ - // TODO: remove once we support actual kibana users - { label: 'admin (self)' }, - { label: 'davidcui' }, - { label: 'szhongna' }, - { label: 'jadhanir' }, - { label: 'kvngar' }, -]; - -export const EMAIL_FORMAT_OPTIONS = [ - { - id: 'Attachment', - label: 'Email with report as attached file', - }, - // TODO: add it back when we have fully support for embedded html - { - id: 'Embedded HTML', - label: 'Embedded HTML report', - disabled: true, - }, -]; +export const EMAIL_RECIPIENT_OPTIONS = []; export const DELIVERY_TYPE_OPTIONS = [ { diff --git a/kibana-reports/public/components/report_definitions/delivery/email.tsx b/kibana-reports/public/components/report_definitions/delivery/email.tsx index a93381df..513034ef 100644 --- a/kibana-reports/public/components/report_definitions/delivery/email.tsx +++ b/kibana-reports/public/components/report_definitions/delivery/email.tsx @@ -13,58 +13,14 @@ * permissions and limitations under the License. */ -import { - EuiComboBox, - EuiFieldText, - EuiFormRow, - EuiLink, - EuiListGroup, - EuiPopover, - EuiRadioGroup, - EuiSpacer, - EuiText, -} from '@elastic/eui'; +import { EuiComboBox, EuiFieldText, EuiFormRow, EuiSpacer } from '@elastic/eui'; import React, { useEffect } from 'react'; import { useState } from 'react'; -import { - EMAIL_FORMAT_OPTIONS, - EMAIL_RECIPIENT_OPTIONS, -} from './delivery_constants'; import ReactMDE from 'react-mde'; import { ReportDeliveryProps } from './delivery'; -import { - ChannelSchemaType, - DeliverySchemaType, - KibanaUserSchemaType, -} from 'server/model'; +import { ChannelSchemaType, DeliverySchemaType } from 'server/model'; import { converter } from '../utils'; - -const INSERT_PLACEHOLDER_OPTIONS = [ - { - label: 'Report details URL', - href: '#', - iconType: 'link', - size: 's', - }, - { - label: 'Report source URL', - href: '#', - iconType: 'link', - size: 's', - }, - { - label: 'File download URL', - href: '#', - iconType: 'link', - size: 's', - }, - { - label: 'Report creation timestamp', - href: '#', - iconType: 'clock', - size: 's', - }, -]; +import { DELIVERY_TYPE_OPTIONS } from './delivery_constants'; export const EmailDelivery = (props: ReportDeliveryProps) => { const { @@ -75,41 +31,13 @@ export const EmailDelivery = (props: ReportDeliveryProps) => { showEmailRecipientsError, } = props; - const [emailRecipients, setEmailRecipients] = useState([]); + const [emailRecipients, setOptions] = useState([]); + const [selectedEmailRecipients, setSelectedEmailRecipients] = useState([]); const [emailSubject, setEmailSubject] = useState(''); const [emailBody, setEmailBody] = useState(''); - const [emailFormat, setEmailFormat] = useState(EMAIL_FORMAT_OPTIONS[0].id); const [selectedTab, setSelectedTab] = React.useState<'write' | 'preview'>( 'write' ); - const [insertPlaceholder, setInsertPlaceholder] = useState(false); - - const handleInsertPlaceholderClick = () => { - setInsertPlaceholder((insertPlaceholder) => !insertPlaceholder); - }; - const closeInsertPlaceholder = () => setInsertPlaceholder(false); - - const placeholderInsert = ( - - - Insert placeholder - - - ); - - const InsertPlaceholderPopover = () => { - return ( -
- - - -
- ); - }; const handleCreateEmailRecipient = ( searchValue: string, @@ -131,15 +59,15 @@ export const EmailDelivery = (props: ReportDeliveryProps) => { (option) => option.label.trim().toLowerCase() === normalizedSearchValue ) === -1 ) { - EMAIL_RECIPIENT_OPTIONS.push(newOption); + setOptions([...emailRecipients, newOption]); } // Select the option. - handleEmailRecipients([...emailRecipients, newOption]); + handleEmailRecipients([...selectedEmailRecipients, newOption]); }; const handleEmailRecipients = (e) => { - setEmailRecipients(e); + setSelectedEmailRecipients(e); reportDefinitionRequest.delivery.delivery_params.recipients = e.map( (option) => option.label ); @@ -150,11 +78,6 @@ export const EmailDelivery = (props: ReportDeliveryProps) => { reportDefinitionRequest.delivery.delivery_params.title = e.target.value; }; - const handleEmailFormat = (e) => { - setEmailFormat(e); - reportDefinitionRequest.delivery.delivery_params.email_format = e; - }; - const handleEmailBody = (e) => { setEmailBody(e); reportDefinitionRequest.delivery.delivery_params.textDescription = e; @@ -164,42 +87,34 @@ export const EmailDelivery = (props: ReportDeliveryProps) => { }; // TODO: need better handling when we add full support for kibana user report delivery - const emailBodyLabel = - emailFormat === 'Embedded HTML' - ? `Add optional message (${selectedTab} mode)` - : `Email body (${selectedTab} mode)`; - - const showPlaceholder = - emailFormat === 'Embedded HTML' ? null : ; + const optionalMessageLabel = `Add optional message (${selectedTab} mode)`; const defaultEditDeliveryParams = (delivery: DeliverySchemaType) => { //TODO: need better handle? - if (delivery.delivery_type === 'Kibana user') { - //@ts-ignore - const kibanaUserParams: KibanaUserSchemaType = delivery.delivery_params; - const { kibana_recipients } = kibanaUserParams; + // if the original notification setting is kibana user + if (delivery.delivery_type === DELIVERY_TYPE_OPTIONS[0].id) { defaultCreateDeliveryParams(); delete reportDefinitionRequest.delivery.delivery_params.kibana_recipients; } else { //@ts-ignore const emailParams: ChannelSchemaType = delivery.delivery_params; - const { recipients, title, textDescription, email_format } = emailParams; + const { recipients, title, textDescription } = emailParams; recipients.map((emailRecipient) => - handleCreateEmailRecipient(emailRecipient, emailRecipients) + handleCreateEmailRecipient(emailRecipient, selectedEmailRecipients) ); setEmailSubject(title); reportDefinitionRequest.delivery.delivery_params.title = title; + reportDefinitionRequest.delivery.delivery_params.origin = location.origin; handleEmailBody(textDescription); - handleEmailFormat(email_format); } }; const defaultCreateDeliveryParams = () => { reportDefinitionRequest.delivery.delivery_params = { - recipients: emailRecipients.map((option) => option.label), + recipients: selectedEmailRecipients.map((option) => option.label), title: emailSubject, - email_format: emailFormat, + origin: location.origin, //TODO: need better render textDescription: emailBody, htmlDescription: converter.makeHtml(emailBody), @@ -227,8 +142,8 @@ export const EmailDelivery = (props: ReportDeliveryProps) => { > { /> - - - - { /> - + { // check delivery type const delivery = report.report_definition.delivery; @@ -49,37 +47,73 @@ export const deliverReport = async ( if (deliveryType === DELIVERY_TYPE.channel) { // deliver through one of [Slack, Chime, Email] - //@ts-ignore - const { email_format: emailFormat, ...rest } = deliveryParams; - // compose request body - if (emailFormat === EMAIL_FORMAT.attachment) { - const reportFormat = - report.report_definition.report_params.core_params.report_format; - const attachment = { - fileName: reportData.fileName, - fileEncoding: reportFormat === FORMAT.csv ? 'text' : 'base64', - //TODO: figure out when this data field is actually needed - // fileContentType: 'application/pdf', - fileData: reportData.dataUrl, - }; - const deliveryBody = { - ...rest, - refTag: reportId, - attachment, - }; - - const res = await callCluster( - notificationClient, - 'notification.send', - { - body: deliveryBody, - }, - isScheduledTask - ); - //TODO: need better error handling or logging - } + const { + query_url: queryUrl, + report_definition: { + report_params: { report_name: reportName }, + }, + } = report; + const { htmlDescription, origin } = deliveryParams; + const originalQueryUrl = origin + queryUrl; + /** + * have to manually compose the url because the Kibana url for AES is.../_plugin/kibana/app/opendistro_kibana_reports#/report_details/${reportId} + * while default Kibana is just .../app/opendistro_kibana_reports#/report_details/${reportId} + */ + const reportDetailUrl = `${originalQueryUrl.replace( + /\/app\/.*$/i, + '' + )}/app/opendistro_kibana_reports#/report_details/${reportId}`; + const template = composeEmbeddedHtml( + htmlDescription, + originalQueryUrl, + reportDetailUrl, + reportName + ); + const deliveryBody = { + ...deliveryParams, + htmlDescription: template, + refTag: reportId, + }; + // send email + const notificationResp = await callCluster( + notificationClient, + 'notification.send', + { + body: deliveryBody, + }, + isScheduledTask + ); + /** + * notification plugin response example: + * { + "refTag": "jeWuU3UBp8p83fn6xwzB", + "recipients": [ + { + "recipient": "odfe@amazon.com", + "statusCode": 200, + "statusText": "Success" + }, + { + "recipient": "wrong.odfe@amazon.com", + "statusCode": 503, + "statusText": "sendEmail Error, SES status:400:Optional[Bad Request]" + } + ] + } + */ + logger.info( + `notification plugin response: ${JSON.stringify(notificationResp)}` + ); + notificationResp.recipients.map((recipient) => { + if (recipient.statusCode !== 200) { + throw new Error( + `Fail to deliver report ${JSON.stringify( + notificationResp.recipients + )}` + ); + } + }); } else { - //TODO: No attachment, use embedded html (not implemented yet) // empty kibana recipients array //TODO: tmp solution // @ts-ignore diff --git a/kibana-reports/server/routes/reportDefinition.ts b/kibana-reports/server/routes/reportDefinition.ts index 36d18e1e..d846b19b 100644 --- a/kibana-reports/server/routes/reportDefinition.ts +++ b/kibana-reports/server/routes/reportDefinition.ts @@ -100,14 +100,14 @@ export default function (router: IRouter) { request, response ): Promise> => { - const reportDefinition: ReportDefinitionSchemaType = request.body; + let reportDefinition = request.body; const savedReportDefinitionId = request.params.reportDefinitionId; const esClient = context.core.elasticsearch.legacy.client; //@ts-ignore const logger = context.reporting_plugin.logger; // input validation try { - reportDefinitionSchema.validate(reportDefinition); + reportDefinition = reportDefinitionSchema.validate(reportDefinition); } catch (error) { logger.error( `Failed input validation for update report definition ${error}` diff --git a/kibana-reports/server/routes/utils/constants.ts b/kibana-reports/server/routes/utils/constants.ts index 6060aa68..912658b7 100644 --- a/kibana-reports/server/routes/utils/constants.ts +++ b/kibana-reports/server/routes/utils/constants.ts @@ -71,11 +71,6 @@ export enum DELIVERY_TYPE { channel = 'Channel', } -export enum EMAIL_FORMAT { - embeddedHtml = 'Embedded HTML', - attachment = 'Attachment', -} - // https://www.elastic.co/guide/en/elasticsearch/reference/6.8/search-request-from-size.html export const DEFAULT_MAX_SIZE = 10000; diff --git a/kibana-reports/server/routes/utils/notification/deliveryContentHelper.ts b/kibana-reports/server/routes/utils/notification/deliveryContentHelper.ts new file mode 100644 index 00000000..3e36bd0e --- /dev/null +++ b/kibana-reports/server/routes/utils/notification/deliveryContentHelper.ts @@ -0,0 +1,45 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file 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 fs from 'fs'; +import cheerio from 'cheerio'; + +export const composeEmbeddedHtml = ( + htmlDescription: string, + originalQueryUrl: string, + reportDetailUrl: string, + reportName: string +) => { + //TODO: need to add AWS styling + const logoAsBase64 = fs.readFileSync( + `${__dirname}/notification_content_template/logo.png`, + 'base64' + ); + + const $ = cheerio.load( + fs.readFileSync( + `${__dirname}/notification_content_template/email_content_template.html` + ) + ); + // set each link and logo + $('.logo').attr('src', `data:image/png;base64,${logoAsBase64}`); + $('.report_name').attr('href', reportDetailUrl).text(reportName); + $('.report_snapshot').attr('href', originalQueryUrl); + $('.optional_message').html(htmlDescription); + //TODO: Add this once we have the actual link to download + // $('.report_download').attr('href', '') + + return $.root().html(); +}; diff --git a/kibana-reports/server/routes/utils/notification/notification_content_template/email_content_template.html b/kibana-reports/server/routes/utils/notification/notification_content_template/email_content_template.html new file mode 100644 index 00000000..d6481718 --- /dev/null +++ b/kibana-reports/server/routes/utils/notification/notification_content_template/email_content_template.html @@ -0,0 +1,471 @@ + + + + + + + Kibana Reports: %REPORT_TITLE% + + + + + A new Kibana report is available                 +                                 +                                 +                                 +                               + + + + + + + + + + + \ No newline at end of file diff --git a/kibana-reports/server/routes/utils/notification/notification_content_template/logo.png b/kibana-reports/server/routes/utils/notification/notification_content_template/logo.png new file mode 100644 index 00000000..46aa560a Binary files /dev/null and b/kibana-reports/server/routes/utils/notification/notification_content_template/logo.png differ diff --git a/kibana-reports/yarn.lock b/kibana-reports/yarn.lock index 0568186a..bb10f111 100644 --- a/kibana-reports/yarn.lock +++ b/kibana-reports/yarn.lock @@ -2580,6 +2580,11 @@ bn.js@^5.1.1: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b" integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ== +boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -2900,6 +2905,18 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== +cheerio@^1.0.0-rc.3: + version "1.0.0-rc.3" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.3.tgz#094636d425b2e9c0f4eb91a46c05630c9a1a8bf6" + integrity sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA== + dependencies: + css-select "~1.2.0" + dom-serializer "~0.1.1" + entities "~1.1.1" + htmlparser2 "^3.9.1" + lodash "^4.15.0" + parse5 "^3.0.1" + chokidar@^2.1.8: version "2.1.8" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" @@ -3343,6 +3360,21 @@ css-box-model@^1.2.0: dependencies: tiny-invariant "^1.0.6" +css-select@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg= + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + +css-what@2.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" + integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== + css.escape@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" @@ -3647,6 +3679,14 @@ dom-helpers@^5.0.1, dom-helpers@^5.1.3: "@babel/runtime" "^7.8.7" csstype "^3.0.2" +dom-serializer@0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + dom-serializer@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.0.1.tgz#79695eb49af3cd8abc8d93a73da382deb1ca0795" @@ -3656,6 +3696,14 @@ dom-serializer@^1.0.1: domhandler "^3.0.0" entities "^2.0.0" +dom-serializer@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0" + integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA== + dependencies: + domelementtype "^1.3.0" + entities "^1.1.1" + dom4@^2.1.5: version "2.1.5" resolved "https://registry.yarnpkg.com/dom4/-/dom4-2.1.5.tgz#f98a94eb67b340f0fa5b42b0ee9c38cda035428e" @@ -3666,6 +3714,11 @@ domain-browser@^1.1.1: resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== +domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== + domelementtype@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.1.tgz#1f8bdfe91f5a78063274e803b4bdcedf6e94f94d" @@ -3678,6 +3731,13 @@ domexception@^2.0.1: dependencies: webidl-conversions "^5.0.0" +domhandler@^2.3.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" + integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== + dependencies: + domelementtype "1" + domhandler@^3.0, domhandler@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-3.0.0.tgz#51cd13efca31da95bbb0c5bee3a48300e333b3e9" @@ -3690,6 +3750,22 @@ dompurify@^2.1.1: resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.1.1.tgz#b5aa988676b093a9c836d8b855680a8598af25fe" integrity sha512-NijiNVkS/OL8mdQL1hUbCD6uty/cgFpmNiuFxrmJ5YPH2cXrPKIewoixoji56rbZ6XBPmtM8GA8/sf9unlSuwg== +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^1.5.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== + dependencies: + dom-serializer "0" + domelementtype "1" + domutils@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.2.0.tgz#f3ce1610af5c30280bde1b71f84b018b958f32cf" @@ -3800,6 +3876,11 @@ enhanced-resolve@~0.9.0: memory-fs "^0.2.0" tapable "^0.1.8" +entities@^1.1.1, entities@~1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" + integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== + entities@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f" @@ -4974,6 +5055,18 @@ html@^1.0.0: dependencies: concat-stream "^1.4.7" +htmlparser2@^3.9.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" + integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== + dependencies: + domelementtype "^1.3.1" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^3.1.1" + htmlparser2@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-4.1.0.tgz#9a4ef161f2e4625ebf7dfbe6c0a2f52d18a59e78" @@ -6340,7 +6433,7 @@ lodash.unescape@4.0.1: resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c" integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw= -lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4, lodash@^4.3.0, lodash@~4.17.10: +lodash@^4.0.0, lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4, lodash@^4.3.0, lodash@~4.17.10: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== @@ -6889,6 +6982,13 @@ npm-run-path@^4.0.0: gauge "~2.7.3" set-blocking "~2.0.0" +nth-check@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" + integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== + dependencies: + boolbase "~1.0.0" + number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" @@ -7195,6 +7295,13 @@ parse5@5.1.1: resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== +parse5@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c" + integrity sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA== + dependencies: + "@types/node" "*" + pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"