From 6533af8757f4cfe54a2adeec05706445b400c610 Mon Sep 17 00:00:00 2001 From: mehidi258 Date: Tue, 8 Feb 2022 22:48:27 +0600 Subject: [PATCH 1/2] Add weghting screen page in react --- assets/css/dashboard.css | 109 ++++++++- assets/js/weighting/components/field-group.js | 181 ++++++++++++++ assets/js/weighting/components/field-item.js | 102 ++++++++ assets/js/weighting/components/meta-Item.js | 72 ++++++ .../js/weighting/components/undo-changes.js | 20 ++ assets/js/weighting/dummyData.js | 224 ++++++++++++++++++ assets/js/weighting/index.js | 214 +++++++++++++++++ assets/js/weighting/utils.js | 7 + includes/classes/Feature/Search/Weighting.php | 92 +++---- package-lock.json | 45 ++-- package.json | 3 +- 11 files changed, 982 insertions(+), 87 deletions(-) create mode 100644 assets/js/weighting/components/field-group.js create mode 100644 assets/js/weighting/components/field-item.js create mode 100644 assets/js/weighting/components/meta-Item.js create mode 100644 assets/js/weighting/components/undo-changes.js create mode 100644 assets/js/weighting/dummyData.js create mode 100644 assets/js/weighting/index.js create mode 100644 assets/js/weighting/utils.js diff --git a/assets/css/dashboard.css b/assets/css/dashboard.css index 19f2d6bbb3..72f24ca62d 100644 --- a/assets/css/dashboard.css +++ b/assets/css/dashboard.css @@ -658,18 +658,97 @@ h2.ep-list-features { * Weighting */ -.weighting-settings .postbox { +.weighting-settings { box-sizing: border-box; max-width: 650px; - & * { - box-sizing: border-box; + & .postbox { + + & .components-range-control__number { + display: none; + } + + & .postbox__header { + align-items: center; + border-bottom: 1px solid #c3c4c7; + display: flex; + } + + & .undo-changes { + background-color: transparent; + border: 0; + color: #1e8cbe; + cursor: pointer; + margin-left: auto; + padding: 0 10px; + + &:hover { + text-decoration: underline; + } + } + + & * { + box-sizing: border-box; + } + } + + & .add-meta-key-wrap { + align-items: center; + display: flex; + + & legend { + top: 0; + } + } + + & .add-meta-key { + width: 300px; + } + + & .submit__button { + align-items: center; + background: #fff; + bottom: 0; + display: flex; + padding: 10px; + position: sticky; + + & button { + margin-right: 10px; + } + } + +} + +.components-range-control__wrapper { + min-width: 100px; + + & span:last-child { + background-color: #1e8cbe; + pointer-events: none; } } +div.components-base-control__field { + align-items: center; + display: flex; + height: 20px; + margin: 0; + + & .components-base-control__label { + margin: 0; + } +} + +.field-item .components-base-control__help { + margin-top: -10px; + padding: 0; +} + .weighting-settings .postbox h2.hndle { color: #444; cursor: inherit; + width: 110px; } .weighting-settings fieldset { @@ -702,9 +781,26 @@ h2.ep-list-features { background: #f9f9f9; } -.weighting-settings .searchable { +.field-item { + align-items: center; + display: flex; +} + +.remove-meta-item { + cursor: pointer; + + & path { + fill: #d84440; + } +} + +.field-item p { display: inline-block; - width: 120px; + padding: 0 10px; + + & a { + text-decoration: none; + } } .weighting-settings .weighting { @@ -713,7 +809,6 @@ h2.ep-list-features { } .weighting-settings .weighting label { - margin-right: 10px; min-width: 80px; } @@ -724,7 +819,7 @@ h2.ep-list-features { height: 1em; margin: 0; vertical-align: middle; - width: 200px; + width: 120px; } .weighting-settings input[type="range"]:focus { diff --git a/assets/js/weighting/components/field-group.js b/assets/js/weighting/components/field-group.js new file mode 100644 index 0000000000..57777abce8 --- /dev/null +++ b/assets/js/weighting/components/field-group.js @@ -0,0 +1,181 @@ +/** + * Wordpress Dependecies. + */ +import { useState } from '@wordpress/element'; +import AsyncSelect from 'react-select/async'; +import { __ } from '@wordpress/i18n'; +import PropTypes from 'prop-types'; + +/** + * Internal Dependencies. + */ +import FieldItem from './field-item'; +import MetaItem from './meta-Item'; +import { sortListByOrder } from '../utils'; + +const FieldGroup = ({ + postType, + onChangeHandler, + getCurrentFormData, + formData, + setFormData, + undoHandler, + savedData, +}) => { + const [selectedValue, setSelectedValue] = useState(null); + + // handle selection + const handleChange = (value) => { + let currentFormData = getCurrentFormData(postType.name); + if (currentFormData.metas.findIndex((metaItem) => metaItem.name === value.name) === -1) { + currentFormData = { + ...currentFormData, + metas: [...currentFormData.metas, value], + }; + } + const excludedFormData = formData.filter((item) => item.name !== postType.name); + const newFormData = [...excludedFormData, currentFormData]; + setFormData(sortListByOrder(newFormData)); + setSelectedValue(value); + }; + + // load options using API call + const loadOptions = (inputValue) => { + return fetch( + `https://jsonplaceholder.typicode.com/posts?search=${inputValue}$post_type=${postType.name}`, + ) + .then((res) => res.json()) + .then((result) => { + const newResult = []; + result.forEach((item) => { + newResult.push({ + name: item.title, + searchable: false, + weight: 10, + }); + }); + return newResult; + }); + }; + + const removeMetaItem = (metaName) => { + const newCurrentFormData = { + ...getCurrentFormData(postType.name), + metas: getCurrentFormData(postType.name).metas.filter((item) => item.name !== metaName), + }; + + const excludedFormData = formData.filter((item) => item.name !== postType.name); + const newFormData = [...excludedFormData, newCurrentFormData]; + setFormData(sortListByOrder(newFormData)); + }; + + const currentOriginalData = savedData.find((item) => item.name === postType.name); + + return ( + <> +
+

{__('Attributes', 'elasticpress')}

+
+ {postType.attributes.map((attribute, index) => { + const fieldType = 'attributes'; + const isAttributeChanged = + JSON.stringify(attribute) !== + JSON.stringify(currentOriginalData[fieldType][index]); + return ( + + ); + })} +
+
+
+

{__('Taxonomies', 'elasticpress')}

+
+ {postType.taxonomies.map((taxonomy, index) => { + const fieldType = 'taxonomies'; + const isAttributeChanged = + JSON.stringify(taxonomy) !== + JSON.stringify(currentOriginalData[fieldType][index]); + + return ( + + ); + })} +
+
+
+

{__('Meta to be indexed', 'elasticpress')}

+
+ {getCurrentFormData(postType.name) && + getCurrentFormData(postType.name).metas && + getCurrentFormData(postType.name).metas.map((meta, index) => { + const fieldType = 'metas'; + const isAttributeChanged = + JSON.stringify(meta) !== + JSON.stringify(currentOriginalData[fieldType][index]); + return ( + + ); + })} +
+ {__('Add Meta Key:', 'elasticpress')} +
+ e.name} + getOptionValue={(e) => e.name} + loadOptions={loadOptions} + // onInputChange={handleInputChange} + onChange={handleChange} + /> +
+
+
+
+ + ); +}; + +FieldGroup.propTypes = { + postType: PropTypes.object.isRequired, + onChangeHandler: PropTypes.func.isRequired, + getCurrentFormData: PropTypes.func.isRequired, + formData: PropTypes.array.isRequired, + setFormData: PropTypes.func.isRequired, + undoHandler: PropTypes.func.isRequired, + savedData: PropTypes.array.isRequired, +}; + +export default FieldGroup; diff --git a/assets/js/weighting/components/field-item.js b/assets/js/weighting/components/field-item.js new file mode 100644 index 0000000000..4e5c8baf45 --- /dev/null +++ b/assets/js/weighting/components/field-item.js @@ -0,0 +1,102 @@ +/** + * Wordpress Dependencies. + */ +import { RangeControl } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import PropTypes from 'prop-types'; + +/** + * Internal Dependecies. + */ +import UndoChanges from './undo-changes'; + +const FieldItem = (props) => { + const { + postType, + attribute, + fieldType, + onChangeHandler, + getCurrentFormData, + currentIndex, + undoHandler, + isAttributeChanged, + } = props; + + return ( +
+ {attribute.label} + +

+ +

+ + {getCurrentFormData(postType.name)[fieldType][currentIndex].indexable && ( +

+ +

+ )} + + {getCurrentFormData(postType.name)[fieldType][currentIndex].searchable && + getCurrentFormData(postType.name)[fieldType][currentIndex].indexable && ( +

+ + onChangeHandler(value, postType.name, fieldType, attribute.name) + } + min={1} + max={100} + /> +

+ )} + + {isAttributeChanged && } +
+ ); +}; + +FieldItem.propTypes = { + postType: PropTypes.object.isRequired, + attribute: PropTypes.object.isRequired, + fieldType: PropTypes.string.isRequired, + onChangeHandler: PropTypes.func.isRequired, + getCurrentFormData: PropTypes.func.isRequired, + currentIndex: PropTypes.number.isRequired, + undoHandler: PropTypes.func.isRequired, + isAttributeChanged: PropTypes.bool.isRequired, +}; + +export default FieldItem; diff --git a/assets/js/weighting/components/meta-Item.js b/assets/js/weighting/components/meta-Item.js new file mode 100644 index 0000000000..877dae5a00 --- /dev/null +++ b/assets/js/weighting/components/meta-Item.js @@ -0,0 +1,72 @@ +/** + * WordPress dependencies. + */ +import { RangeControl } from '@wordpress/components'; +import { closeSmall, Icon } from '@wordpress/icons'; +import { __ } from '@wordpress/i18n'; +import PropTypes from 'prop-types'; + +const MetaItem = ({ + postType, + attribute, + fieldType, + onChangeHandler, + getCurrentFormData, + currentIndex, + removeMetaItem, +}) => { + return ( +
+ + removeMetaItem(attribute.name)} icon={closeSmall} /> + + {attribute.name} + +

+ +

+ + {getCurrentFormData(postType.name)[fieldType][currentIndex].searchable && ( +

+ + onChangeHandler(value, postType.name, fieldType, attribute.name) + } + min={1} + max={100} + /> +

+ )} +
+ ); +}; + +MetaItem.propTypes = { + postType: PropTypes.object.isRequired, + attribute: PropTypes.object.isRequired, + fieldType: PropTypes.string.isRequired, + onChangeHandler: PropTypes.func.isRequired, + getCurrentFormData: PropTypes.func.isRequired, + currentIndex: PropTypes.number.isRequired, + removeMetaItem: PropTypes.func.isRequired, +}; + +export default MetaItem; diff --git a/assets/js/weighting/components/undo-changes.js b/assets/js/weighting/components/undo-changes.js new file mode 100644 index 0000000000..689d88147a --- /dev/null +++ b/assets/js/weighting/components/undo-changes.js @@ -0,0 +1,20 @@ +/** + * Wordpress Dependencies. + */ +import { __ } from '@wordpress/i18n'; +import PropTypes from 'prop-types'; + +const UndoChanges = ({ undoHandler, undoProps }) => { + return ( + + ); +}; + +UndoChanges.propTypes = { + undoHandler: PropTypes.func.isRequired, + undoProps: PropTypes.object.isRequired, +}; + +export default UndoChanges; diff --git a/assets/js/weighting/dummyData.js b/assets/js/weighting/dummyData.js new file mode 100644 index 0000000000..98e5482731 --- /dev/null +++ b/assets/js/weighting/dummyData.js @@ -0,0 +1,224 @@ +export const dummyData = [ + { + label: 'Posts', + name: 'post', + indexable: true, + order: 0, + + attributes: [ + { + label: 'Title', + name: 'post_title', + indexable: true, + searchable: true, + weight: 40, + }, + { + label: 'Content', + name: 'post_content', + indexable: false, + searchable: false, + weight: 1, + }, + { + label: 'Excerpt', + name: 'post_excerpt', + indexable: false, + searchable: false, + weight: 1, + }, + { + label: 'Author', + name: 'post_author', + indexable: false, + searchable: false, + weight: 1, + }, + ], + + taxonomies: [ + { + label: 'Categories', + name: 'post_categories', + indexable: false, + searchable: false, + weight: 1, + }, + { + label: 'Tags', + name: 'post_tags', + indexable: false, + searchable: false, + weight: 1, + }, + { + label: 'Formats', + name: 'post_formats', + indexable: false, + searchable: false, + weight: 1, + }, + ], + + metas: [ + // { + // name: 'example_key', + // searchable: false, + // weight: 10, + // }, + // { + // name: 'another_key', + // searchable: false, + // weight: 10, + // }, + // { + // name: 'one_more_key', + // searchable: false, + // weight: 10, + // }, + ], + }, + { + label: 'Pages', + name: 'page', + indexable: true, + order: 1, + + attributes: [ + { + label: 'Title', + name: 'post_title', + indexable: false, + searchable: false, + weight: 1, + }, + { + label: 'Content', + name: 'post_content', + indexable: false, + searchable: false, + weight: 1, + }, + { + label: 'Excerpt', + name: 'post_excerpt', + indexable: false, + searchable: false, + weight: 1, + }, + { + label: 'Author', + name: 'post_author', + indexable: false, + searchable: false, + weight: 1, + }, + ], + + taxonomies: [ + { + label: 'Categories', + name: 'post_categories', + indexable: false, + searchable: false, + weight: 1, + }, + { + label: 'Tags', + name: 'post_tags', + indexable: false, + searchable: false, + weight: 1, + }, + { + label: 'Formats', + name: 'post_formats', + indexable: false, + searchable: false, + weight: 1, + }, + ], + + metas: [], + }, + { + label: 'Product', + name: 'product', + indexable: true, + order: 2, + + attributes: [ + { + label: 'Title', + name: 'post_title', + indexable: false, + searchable: false, + weight: 1, + }, + { + label: 'Content', + name: 'post_content', + indexable: false, + searchable: false, + weight: 1, + }, + { + label: 'Excerpt', + name: 'post_excerpt', + indexable: false, + searchable: false, + weight: 1, + }, + { + label: 'Author', + name: 'post_author', + indexable: false, + searchable: false, + weight: 1, + }, + ], + + taxonomies: [ + { + label: 'Categories', + name: 'post_categories', + indexable: false, + searchable: false, + weight: 1, + }, + { + label: 'Tags', + name: 'post_tags', + indexable: false, + searchable: false, + weight: 1, + }, + { + label: 'Formats', + name: 'post_formats', + indexable: false, + searchable: false, + weight: 1, + }, + ], + metas: [], + }, +]; + +export const dummyMetaKeys = [ + { + name: 'example_key', + searchable: false, + weight: 10, + }, + { + name: 'another_key', + searchable: false, + weight: 10, + }, + { + name: 'one_more_key', + searchable: false, + weight: 10, + }, +]; diff --git a/assets/js/weighting/index.js b/assets/js/weighting/index.js new file mode 100644 index 0000000000..9c4d94daef --- /dev/null +++ b/assets/js/weighting/index.js @@ -0,0 +1,214 @@ +/** + * WordPress dependencies. + */ +import { render, WPElement, useState, useEffect } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal Dependencies. + */ +import FieldGroup from './components/field-group'; +import { dummyData } from './dummyData'; +import { sortListByOrder } from './utils'; + +/** + * component. + * + * @return {WPElement} Element. + */ +const App = () => { + const [formData, setFormData] = useState([]); + const [savedData, setSavedData] = useState([]); + const [isSaving, setIsSaving] = useState(false); + + const hasChanges = JSON.stringify(savedData) !== JSON.stringify(formData); + + /** + * Fetch api response on component mount and set instead of dummy data. + */ + useEffect(() => { + setTimeout(() => { + setSavedData(dummyData); + setFormData(dummyData); + }, 200); + }, []); + + /** + * Get currently editing form type + * + * @param {string} postType type of the wp post. + * @return {Object} currently editing form. + */ + const getCurrentFormData = (postType) => formData.find((item) => item.name === postType); + + /** + * Get currently editing form type + * + * @param {string} postType type of the wp post. + * @return {Object} currently editing form. + */ + const getSavedFormData = (postType) => savedData.find((item) => item.name === postType); + + const undoHandler = (props) => { + const { currentIndex, fieldType, postType, attribute } = props; + let currentFormData = getCurrentFormData(postType.name); + const savedFormData = getSavedFormData(postType.name); + + currentFormData = { + ...currentFormData, + [fieldType]: currentFormData[fieldType].map((item) => { + let newItem = item; + if (item.name === attribute.name) { + newItem = savedFormData[fieldType][currentIndex]; + } + return newItem; + }), + }; + + const excludeOldCurrentFormData = formData.filter((item) => item.name !== postType.name); + + const newFormData = [...excludeOldCurrentFormData, currentFormData]; + + setFormData(sortListByOrder(newFormData)); + }; + + /** + * Handle input changes. + * + * @param {Object} event react synthetic event + * @param {string} postType wp post type + * @param {string} type type of the field + * @param {string} attributeName field attribute name + */ + const onChangeHandler = (event, postType, type, attributeName) => { + let currentFormData = getCurrentFormData(postType); + + if (type === 'root') { + currentFormData = { ...currentFormData, indexable: !currentFormData.indexable }; + } else { + currentFormData = { + ...currentFormData, + [type]: currentFormData[type].map((item) => { + let newItem = item; + if (typeof event === 'number' && item.name === attributeName) { + newItem = { ...newItem, weight: event }; + } else if (item.name === attributeName) { + newItem = { ...newItem, [event.target.name]: !newItem[event.target.name] }; + } + return newItem; + }), + }; + } + + const excludeOldCurrentFormData = formData.filter((item) => item.name !== postType); + + const newFormData = [...excludeOldCurrentFormData, currentFormData]; + + setFormData(sortListByOrder(newFormData)); + }; + + /** + * Reset all changes of the form. + */ + const resetAllChanges = () => { + setFormData(sortListByOrder(dummyData)); + }; + + /** + * Handle for submission. + * + * @param {Object} event react synthetic event. + */ + const handleSubmit = (event) => { + event.preventDefault(); + setIsSaving(true); + + // do api request to save formData + setTimeout(() => { + console.log({ formData }); + }, 500); + + setIsSaving(false); + }; + + return ( +
+

{__('Manage Search Fields & Weighting', 'elasticpress')}

+
+

+ {__( + 'Adding more weight to an item will mean it will have more presence during searches. Add more weight to the items that are more important and need more prominence during searches. For example, adding more weight to the title attribute will cause search matches on the post title to apear mor prominently.', + 'elasticpress', + )} +

+

+ {__( + 'Important: If you enable or disable indexing for a field, you will need to refresh your index after saving your settings', + 'elasticpress', + )} +

+
+ {formData.map((postType) => ( +
+
+

{postType.label}

+
+ +
+ + {hasChanges && ( + + )} +
+ + {postType.indexable && ( + + )} +
+ ))} + +
+ + + + {hasChanges + ? __('Please re-sync your data after saving.', 'elasticpress') + : __('You have nothing to save.', 'elasticpress')} + +
+
+ ); +}; + +render(, document.getElementById('ep-weighting-screen')); diff --git a/assets/js/weighting/utils.js b/assets/js/weighting/utils.js new file mode 100644 index 0000000000..7b0847f5b3 --- /dev/null +++ b/assets/js/weighting/utils.js @@ -0,0 +1,7 @@ +/** + * Sort list by order. + * + * @param {Array} list items to bo sorted. + * @return {Array} sorted list by it's order. + */ +export const sortListByOrder = (list = []) => list.sort((a, b) => a.order - b.order); diff --git a/includes/classes/Feature/Search/Weighting.php b/includes/classes/Feature/Search/Weighting.php index 95902a8ea4..9b15194ec9 100644 --- a/includes/classes/Feature/Search/Weighting.php +++ b/includes/classes/Feature/Search/Weighting.php @@ -40,6 +40,32 @@ public function setup() { add_filter( 'ep_query_weighting_fields', [ $this, 'adjust_weight_for_cross_fields' ], 10, 5 ); } + /** + * Returns unique list of meta keys + * + * @param string $post_type Post type + * + * @return array + */ + public function get_meta_keys_for_post_type( $post_type ) { + + + $meta_keys = array(); + $posts = get_posts( array( 'post_type' => $post_type, 'limit' => -1 ) ); + + + foreach ( $posts as $post ) { + $post_meta_keys = get_post_custom_keys( $post->ID ); + var_dump($post_meta_keys); + $meta_keys = array_merge( $meta_keys, $post_meta_keys ); + } + + // Use array_unique to remove duplicate meta_keys that we received from all posts + // Use array_values to reset the index of the array + return array_values( array_unique( $meta_keys ) ); + + } + /** * Returns a grouping of all the fields that support weighting for the post type * @@ -211,58 +237,7 @@ public function add_weighting_submenu_page() { public function render_settings_page() { include EP_PATH . '/includes/partials/header.php'; ?>
- -

-

-

- -
- - - -
-

-
- -
-

-
- get_registered_feature( 'search' ); - - $post_types = $search->get_searchable_post_types(); - - $current_values = $this->get_weighting_configuration(); - - foreach ( $post_types as $post_type ) : - $fields = $this->get_weightable_fields_for_post_type( $post_type ); - $post_type_object = get_post_type_object( $post_type ); - ?> -
-

labels->menu_name ); ?>

- - render_settings_section( $post_type, $field_group, $current_values ); - endforeach; - ?> -
- -
+
-
+
+

+ id="" name="weighting[][][enabled]"> + +

+

- id="" name="weighting[][][enabled]"> - + id="" name="weighting[][][enabled]"> +

@@ -326,6 +306,8 @@ public function render_settings_section( $post_type, $field, $current_values ) { " name="weighting[][][weight]" >

+ +

Date: Wed, 9 Feb 2022 22:06:02 +0600 Subject: [PATCH 2/2] Fix weghting screen --- assets/css/dashboard.css | 8 ++++++-- assets/js/weighting/index.js | 37 +++++++++++++++++++++++++++++++++--- package-lock.json | 19 ++++++++---------- package.json | 1 + 4 files changed, 49 insertions(+), 16 deletions(-) diff --git a/assets/css/dashboard.css b/assets/css/dashboard.css index 72f24ca62d..1ac874893a 100644 --- a/assets/css/dashboard.css +++ b/assets/css/dashboard.css @@ -713,8 +713,12 @@ h2.ep-list-features { padding: 10px; position: sticky; - & button { - margin-right: 10px; + & .note { + margin-left: 10px; + } + + & .reset-all-changes-button { + margin-left: auto; } } diff --git a/assets/js/weighting/index.js b/assets/js/weighting/index.js index 9c4d94daef..57c1940568 100644 --- a/assets/js/weighting/index.js +++ b/assets/js/weighting/index.js @@ -114,6 +114,28 @@ const App = () => { setFormData(sortListByOrder(dummyData)); }; + /** + * Reset current form changes. + * + * @param {string} postType name of the post type. + */ + const resetCurrentFormChanges = (postType) => { + const savedFormData = getSavedFormData(postType); + const excludeOldCurrentFormData = formData.filter((item) => item.name !== postType); + + const newFormData = [...excludeOldCurrentFormData, savedFormData]; + + setFormData(sortListByOrder(newFormData)); + }; + + /** + * Check if current has changes. + * + * @param {string} postType name of the post type. + */ + const hasCurrentFormChanges = (postType) => + JSON.stringify(getCurrentFormData(postType)) !== JSON.stringify(getSavedFormData(postType)); + /** * Handle for submission. * @@ -166,11 +188,11 @@ const App = () => {
- {hasChanges && ( + {hasCurrentFormChanges(postType.name) && ( @@ -201,11 +223,20 @@ const App = () => { {isSaving ? __('Saving…', 'elasticpress') : __('Save changes', 'elasticpress')} - + {hasChanges ? __('Please re-sync your data after saving.', 'elasticpress') : __('You have nothing to save.', 'elasticpress')} + + ); diff --git a/package-lock.json b/package-lock.json index 42388a7cf2..66ae5bb6a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17087,22 +17087,19 @@ } }, "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "requires": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", - "react-is": "^16.8.1" + "react-is": "^16.13.1" }, "dependencies": { - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" } } }, diff --git a/package.json b/package.json index 2dcb7ef8e0..2e9bb1cd8e 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "focus-trap-react": "^8.8.2", "jquery": "^3.6.0", "promise-polyfill": "^8.2.1", + "prop-types": "^15.8.1", "react": "^16.14.0", "react-beautiful-dnd": "^11.0.5", "react-dom": "^16.14.0",