diff --git a/app/controllers/miq_ae_class_controller.rb b/app/controllers/miq_ae_class_controller.rb
index d13ce6bb009..953e2afd164 100644
--- a/app/controllers/miq_ae_class_controller.rb
+++ b/app/controllers/miq_ae_class_controller.rb
@@ -520,6 +520,7 @@ def edit_method
id = x_node.split('-')
end
@ae_method = find_record_with_rbac(MiqAeMethod, id[1])
+ @embedded_methods = MiqAeMethod.where(:relative_path => @ae_method[:embedded_methods].map { |str| str.sub(/^\//, '') })
@selectable_methods = embedded_method_regex(@ae_method.fqname)
if playbook_style_location?(@ae_method.location)
# these variants are implemented in Angular
@@ -1815,6 +1816,32 @@ def namespace
render :json => find_record_with_rbac(MiqAeNamespace, params[:id]).attributes.slice('name', 'description', 'enabled')
end
+ def ae_domains
+ domains = MiqAeDomain.where(:enabled => true).order("name").select("id, name")
+ render :json => {:domains => domains}
+ end
+
+ def ae_methods
+ methods = MiqAeMethod
+ .name_path_search(params[:search])
+ .where(params[:domain_id] ? {:domain_id => params[:domain_id]} : {})
+ .where(params[:ids] ? {:id => params[:ids]&.split(',')} : {})
+ .select("id, relative_path, name")
+ .order('name')
+ render :json => {:methods => methods}
+ end
+
+ def ae_method_operations
+ ids = params[:ids].split(",")
+ @edit[:new][:embedded_methods] = MiqAeMethod.where(:id => ids).pluck(:relative_path).map { |path| "/#{path}" }
+ @changed = true
+ render :update do |page|
+ page << javascript_prologue
+ page << javascript_for_miq_button_visibility(@changed)
+ page << "miqSparkle(false);"
+ end
+ end
+
private
def feature_by_action
diff --git a/app/javascript/components/AeInlineMethod/FilterNamespace.jsx b/app/javascript/components/AeInlineMethod/FilterNamespace.jsx
new file mode 100644
index 00000000000..70fb145ae9c
--- /dev/null
+++ b/app/javascript/components/AeInlineMethod/FilterNamespace.jsx
@@ -0,0 +1,56 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {
+ Select, SelectItem, Search,
+} from 'carbon-components-react';
+import { noSelect } from './helper';
+
+const FilterNamespace = ({ domains, onSearch }) => {
+ /** Function to render the search text. */
+ const renderSearchText = () => (
+
+
+ onSearch({ searchText: noSelect })}
+ onChange={(event) => onSearch({ searchText: event.target.value || noSelect })}
+ />
+
+ );
+
+ /** Function to render the domain items in a drop-down list. */
+ const renderDomainList = () => (
+
+ );
+
+ return (
+
+ {renderSearchText()}
+ {domains && renderDomainList()}
+
+ );
+};
+
+export default FilterNamespace;
+
+FilterNamespace.propTypes = {
+ domains: PropTypes.arrayOf(PropTypes.any),
+ onSearch: PropTypes.func.isRequired,
+};
+
+FilterNamespace.defaultProps = {
+ domains: undefined,
+};
diff --git a/app/javascript/components/AeInlineMethod/NamespaceSelector.jsx b/app/javascript/components/AeInlineMethod/NamespaceSelector.jsx
new file mode 100644
index 00000000000..8e6b9a39ccf
--- /dev/null
+++ b/app/javascript/components/AeInlineMethod/NamespaceSelector.jsx
@@ -0,0 +1,106 @@
+import React, { useState, useMemo, useCallback } from 'react';
+import PropTypes from 'prop-types';
+import { useQuery } from 'react-query';
+import { Loading } from 'carbon-components-react';
+import { debounce } from 'lodash';
+import FilterNamespace from './FilterNamespace';
+import MiqDataTable from '../miq-data-table';
+import NotificationMessage from '../notification-message';
+import { CellAction } from '../miq-data-table/helper';
+import {
+ methodSelectorHeaders, formatMethods, searchUrl, namespaceUrls,
+} from './helper';
+import './style.scss';
+
+const NamespaceSelector = ({ onSelectMethod, selectedIds }) => {
+ const [filterData, setFilterData] = useState({ searchText: '', selectedDomain: '' });
+
+ /** Loads the domains and stores in domainData for 60 seconds. */
+ const { data: domainsData, isLoading: domainsLoading } = useQuery(
+ 'domainsData',
+ async() => (await http.get(namespaceUrls.aeDomainsUrl)).domains,
+ {
+ staleTime: 60000,
+ }
+ );
+
+ /** Loads the methods and stores in methodsData for 60 seconds.
+ * If condition works on page load
+ * Else part would work if there is a change in filterData.
+ */
+ const { data, isLoading: methodsLoading } = useQuery(
+ ['methodsData', filterData.searchText, filterData.selectedDomain],
+ async() => {
+ if (!filterData.searchText && !filterData.selectedDomain) {
+ const response = await http.get(namespaceUrls.aeMethodsUrl);
+ return formatMethods(response.methods);
+ }
+ const url = searchUrl(filterData.selectedDomain, filterData.searchText);
+ const response = await http.get(url);
+ return formatMethods(response.methods);
+ },
+ {
+ keepPreviousData: true,
+ refetchOnWindowFocus: false,
+ staleTime: 60000,
+ }
+ );
+
+ /** Debounce the search text by delaying the text input provided to the API. */
+ const debouncedSearch = debounce((newFilterData) => {
+ setFilterData(newFilterData);
+ }, 300);
+
+ /** Function to handle the onSearch event during a filter change event. */
+ const onSearch = useCallback(
+ (newFilterData) => debouncedSearch(newFilterData),
+ [debouncedSearch]
+ );
+
+ /** Function to handle the click event of a cell in the data table. */
+ const onCellClick = (selectedRow, cellType, checked) => {
+ const selectedItems = cellType === CellAction.selectAll
+ ? data && data.map((item) => item.id)
+ : [selectedRow];
+ onSelectMethod({ selectedItems, cellType, checked });
+ };
+
+ /** Function to render the list which depends on the data and selectedIds.
+ * List is memoized to prevent unnecessary re-renders when other state values change. */
+ const renderContents = useMemo(() => {
+ if (!data || data.length === 0) {
+ return ;
+ }
+
+ return (
+ onCellClick(selectedRow, cellType, event.target.checked)}
+ />
+ );
+ }, [data, selectedIds]);
+
+ return (
+
+
+
+ {(domainsLoading || methodsLoading)
+ ?
+ : renderContents}
+
+
+ );
+};
+
+NamespaceSelector.propTypes = {
+ onSelectMethod: PropTypes.func.isRequired,
+ selectedIds: PropTypes.arrayOf(PropTypes.any).isRequired,
+};
+
+export default NamespaceSelector;
diff --git a/app/javascript/components/AeInlineMethod/helper.js b/app/javascript/components/AeInlineMethod/helper.js
new file mode 100644
index 00000000000..f846d4fe4df
--- /dev/null
+++ b/app/javascript/components/AeInlineMethod/helper.js
@@ -0,0 +1,61 @@
+export const namespaceUrls = {
+ aeMethodsUrl: '/miq_ae_class/ae_methods',
+ aeMethodOperationsUrl: '/miq_ae_class/ae_method_operations',
+ aeDomainsUrl: '/miq_ae_class/ae_domains',
+};
+
+export const noSelect = 'NONE';
+
+/** Headers needed for the data-table list. */
+export const methodSelectorHeaders = [
+ {
+ key: 'name',
+ header: 'Name',
+ },
+ {
+ key: 'path',
+ header: 'Relative path',
+ },
+];
+
+export const methodListHeaders = [
+ ...methodSelectorHeaders,
+ { key: 'remove', header: __('Remove'), actionCell: true },
+];
+
+/** Function to format the method data needed for the data-table list. */
+export const formatMethods = (methods) => (methods.map((item) => ({
+ id: item.id.toString(),
+ name: { text: item.name, icon: 'icon node-icon fa-ruby' },
+ path: item.relative_path,
+})));
+
+const removeMethodButton = () => ({
+ is_button: true,
+ actionCell: true,
+ title: __('Remove'),
+ text: __('Remove'),
+ alt: __('Remove'),
+ kind: 'danger',
+ callback: 'removeMethod',
+});
+
+export const formatListMethods = (methods) => (methods.map((item, index) => ({
+ id: item.id.toString(),
+ name: { text: item.name, icon: 'icon node-icon fa-ruby' },
+ path: item.relative_path,
+ remove: removeMethodButton(item, index),
+})));
+
+/** Function to return a conditional URL based on the selected filters. */
+export const searchUrl = (selectedDomain, text) => {
+ const queryParams = [];
+ if (selectedDomain && selectedDomain !== noSelect) {
+ queryParams.push(`domain_id=${selectedDomain}`);
+ }
+ if (text && text !== noSelect) {
+ queryParams.push(`search=${text}`);
+ }
+ const queryString = queryParams.length > 0 ? `?${queryParams.join('&')}` : '';
+ return `${namespaceUrls.aeMethodsUrl}${queryString}`;
+};
diff --git a/app/javascript/components/AeInlineMethod/index.jsx b/app/javascript/components/AeInlineMethod/index.jsx
new file mode 100644
index 00000000000..09dc91e7b2a
--- /dev/null
+++ b/app/javascript/components/AeInlineMethod/index.jsx
@@ -0,0 +1,190 @@
+import React, { useState, useEffect } from 'react';
+import { QueryClient, QueryClientProvider } from 'react-query';
+import PropTypes from 'prop-types';
+import {
+ Modal, Button, ModalBody, Accordion, AccordionItem,
+} from 'carbon-components-react';
+import { AddAlt16 } from '@carbon/icons-react';
+import NotificationMessage from '../notification-message';
+import MiqDataTable from '../miq-data-table';
+import NamespaceSelector from './NamespaceSelector';
+import { CellAction } from '../miq-data-table/helper';
+import { formatListMethods, methodListHeaders, namespaceUrls } from './helper';
+
+/** Component to render a tree and to select an embedded method. */
+const AeInlineMethod = ({ type, selected }) => {
+ const queryClient = new QueryClient();
+
+ const [data, setData] = useState({
+ isModalOpen: false,
+ selectedIds: selected ? selected.map((item) => item.id.toString()) : [],
+ rows: selected ? formatListMethods(selected) : [],
+ notification: false,
+ });
+
+ useEffect(() => {
+ setData({ ...data, notification: data.selectedIds.length > 20 });
+ }, [data.selectedIds]);
+
+ /** Function to show/hide the modal. */
+ const showModal = (status) => setData({ ...data, isModalOpen: status });
+
+ /** Function to handle the select-all check-box click event. */
+ const onSelectAll = (selectedItems, checked) => setData({ ...data, selectedIds: checked ? [...selectedItems] : [] });
+
+ /** Function to handle the list row selection events.
+ * selectedItem is passed as an array. */
+ const onItemSelect = (selectedItems, checked) => {
+ if (checked) {
+ data.selectedIds.push(selectedItems[0].id);
+ } else {
+ data.selectedIds = data.selectedIds.filter((item) => item !== selectedItems[0].id);
+ }
+ setData({ ...data, selectedIds: [...data.selectedIds] });
+ };
+
+ /** Function to add/remove an selected items. */
+ const onSelectMethod = (selectedItems, cellType, checked) => {
+ switch (cellType) {
+ case CellAction.selectAll: onSelectAll(selectedItems, checked); break;
+ default: onItemSelect(selectedItems, checked); break;
+ }
+ };
+
+ /** Updates the ruby form with the selected methods. */
+ const updateRubyForm = (ids) => $.get(`${namespaceUrls.aeMethodOperationsUrl}?&ids=${ids}`);
+
+ /** Function to handle the click events for the list. */
+ const onCellClickHandler = (item) => {
+ if (item && item.callbackAction && item.callbackAction === 'removeMethod') {
+ const ids = data.selectedIds.filter((id) => id !== item.id);
+ setData({
+ rows: data.rows.filter((row) => row.id !== item.id),
+ selectedIds: ids,
+ });
+ updateRubyForm(ids.map((str) => parseInt(str, 10)));
+ }
+ };
+
+ /** Function to handle the modal submit action. */
+ const submitModal = () => {
+ if (data.selectedIds.length > 0) {
+ const ids = data.selectedIds.map((str) => parseInt(str, 10));
+ http.get(`${namespaceUrls.aeMethodsUrl}?ids=${ids}`)
+ .then(({ methods }) => {
+ setData({
+ ...data, rows: formatListMethods(methods), isModalOpen: false,
+ });
+ updateRubyForm(ids);
+ });
+ } else {
+ setData({
+ ...data, rows: [], isModalOpen: false,
+ });
+ }
+ };
+
+ /** Function to render the modal with namespace selector component. */
+ const renderModalSelector = () => (
+ showModal(false)}
+ onRequestSubmit={() => submitModal()}
+ onSecondarySubmit={() => showModal(false)}
+ primaryButtonDisabled={data.selectedIds.length > 20 || data.selectedIds.length === 0}
+ >
+
+ {
+ data.isModalOpen
+ && (
+
+ {
+ data.notification &&
+ }
+ onSelectMethod(selectedItems, cellType, checked)}
+ selectedIds={data.selectedIds}
+ />
+
+ )
+ }
+
+
+ );
+
+ /** Function to render the contents of the list. */
+ const renderList = () => (data.rows && data.rows.length > 0
+ ? (
+
+ onCellClickHandler(selectedRow)}
+ />
+
+ )
+ : (
+
+
+
+ ));
+
+ const renderAddButton = () => (
+
+ {
+ data.selectedIds.length > 0 && (
+
+ {__('Listing')}
+ {` ${data.selectedIds.length} `}
+ {__('Method(s)')}
+
+ )
+ }
+
+
+ );
+
+ const renderAccordionContents = () => (
+
+
+ {renderAddButton()}
+ {renderList()}
+
+
+ );
+
+ return (
+
+ {renderAccordionContents()}
+ {renderModalSelector()}
+
+ );
+};
+
+export default AeInlineMethod;
+
+AeInlineMethod.propTypes = {
+ type: PropTypes.string.isRequired,
+ selected: PropTypes.arrayOf(PropTypes.any),
+};
+
+AeInlineMethod.defaultProps = {
+ selected: undefined,
+};
diff --git a/app/javascript/components/AeInlineMethod/style.scss b/app/javascript/components/AeInlineMethod/style.scss
new file mode 100644
index 00000000000..1c89e69cb43
--- /dev/null
+++ b/app/javascript/components/AeInlineMethod/style.scss
@@ -0,0 +1,79 @@
+.ae-inline-method-modal {
+ .bx--modal-content {
+ margin-bottom: 0;
+ }
+
+ .inline-method-selector {
+ display: flex;
+ flex-direction: column;
+ min-height: 520px;
+
+ .inline-filters {
+ display: flex;
+ flex-direction: row;
+ align-items: end;
+ gap: 10px;
+
+ .search-wrapper {
+ display: flex;
+ flex-grow: 1;
+ flex-direction: column;
+ align-items: flex-start;
+ }
+ }
+
+ .inline-contents-wrapper {
+ display: flex;
+ flex-direction: column;
+ margin-top: 20px;
+
+ .miq-inline-method-list {
+ margin-top: 0;
+
+ .bx--data-table-content {
+ margin-bottom: 0;
+
+ .bx--data-table--sticky-header {
+ max-height: 25rem;
+ }
+ }
+ }
+
+ .miq-notification-message-container {
+ margin: 0;
+ }
+ }
+ }
+}
+
+
+.miq-custom-form-accordion
+{
+ border: 1px solid #e0e0e0;
+
+ li button.bx--accordion__heading {
+ background: #e0e0e0;
+ }
+ .bx--accordion__item:last-child{
+ border: 0;
+ }
+
+ .bx--accordion__content {
+ padding: 20px;
+ margin: 0;
+
+ .custom-form-buttons {
+ display: flex;
+ justify-content: flex-end;
+
+ .custom-form-buttons-label {
+ flex-grow: 1;
+ font-size: 14px;
+ }
+ }
+
+ .ae-inline-methods-notification {
+ margin-top: 20px;
+ }
+ }
+}
diff --git a/app/javascript/components/miq-data-table/index.jsx b/app/javascript/components/miq-data-table/index.jsx
index ee1d1603eb1..a9d1332861d 100644
--- a/app/javascript/components/miq-data-table/index.jsx
+++ b/app/javascript/components/miq-data-table/index.jsx
@@ -100,7 +100,9 @@ const MiqDataTable = ({
isSortable={isSortable}
isSortHeader={sortHeader}
sortDirection={sortDirection}
- className={classNames('miq-data-table-header', (header.contentButton ? 'header-button' : ''))}
+ className={
+ classNames('miq-data-table-header', (header.contentButton ? 'header-button' : ''), (header.actionCell ? 'action-cell-holder' : ''))
+ }
>
{headerLabel(header.header)}
diff --git a/app/javascript/components/miq-data-table/miq-table-cell.jsx b/app/javascript/components/miq-data-table/miq-table-cell.jsx
index 70ce994af6e..709c1e0d6fc 100644
--- a/app/javascript/components/miq-data-table/miq-table-cell.jsx
+++ b/app/javascript/components/miq-data-table/miq-table-cell.jsx
@@ -248,7 +248,7 @@ const MiqTableCell = ({
cellClick && onCellClick(row, CellAction.itemClick, event)}
- className={classNames(showText ? '' : 'no_text', wrapClass ? 'vertical_align_top' : '')}
+ className={classNames(showText ? '' : 'no_text', wrapClass ? 'vertical_align_top' : '', cell.data.actionCell ? 'action-cell-holder' : '')}
>
{component}
@@ -259,7 +259,9 @@ export default MiqTableCell;
MiqTableCell.propTypes = {
onCellClick: PropTypes.func,
- row: PropTypes.shape({}),
+ row: PropTypes.shape({
+ actionCell: PropTypes.bool,
+ }),
cell: PropTypes.shape({
id: PropTypes.string,
value: PropTypes.string,
diff --git a/app/javascript/packs/component-definitions-common.js b/app/javascript/packs/component-definitions-common.js
index 42171651cc1..5f44a3e43f3 100644
--- a/app/javascript/packs/component-definitions-common.js
+++ b/app/javascript/packs/component-definitions-common.js
@@ -11,6 +11,7 @@ import { Toolbar } from '../components/toolbar';
import ActionForm from '../components/action-form';
import AddRemoveHostAggregateForm from '../components/host-aggregate-form/add-remove-host-aggregate-form';
import AddRemoveSecurityGroupForm from '../components/vm-cloud-add-remove-security-group-form';
+import AeInlineMethod from '../components/AeInlineMethod';
import AggregateStatusCard from '../components/aggregate_status_card';
import AnsibleCredentialsForm from '../components/ansible-credentials-form';
import AnsiblePlayBookEditCatalogForm from '../components/ansible-playbook-edit-catalog-form';
@@ -186,6 +187,7 @@ ManageIQ.component.addReact('ActionForm', ActionForm);
ManageIQ.component.addReact('AddRemoveHostAggregateForm', AddRemoveHostAggregateForm);
ManageIQ.component.addReact('AddRemoveSecurityGroupForm', AddRemoveSecurityGroupForm);
ManageIQ.component.addReact('AggregateStatusCard', AggregateStatusCard);
+ManageIQ.component.addReact('AeInlineMethod', AeInlineMethod);
ManageIQ.component.addReact('AnsibleCredentialsForm', AnsibleCredentialsForm);
ManageIQ.component.addReact('AnsiblePlayBookEditCatalogForm', AnsiblePlayBookEditCatalogForm);
ManageIQ.component.addReact('AnsiblePlaybookWorkflow', AnsiblePlaybookWorkflow);
diff --git a/app/stylesheet/miq-data-table.scss b/app/stylesheet/miq-data-table.scss
index 53a66b56761..2097fba9820 100644
--- a/app/stylesheet/miq-data-table.scss
+++ b/app/stylesheet/miq-data-table.scss
@@ -310,6 +310,10 @@ table.miq_preview {
width: 100px !important;
}
+.action-cell-holder {
+ max-width: 150px !important;
+}
+
.reconfigure-form {
.reconfigure-sub-form {
display: flex;
diff --git a/app/views/miq_ae_class/_embedded_methods.html.haml b/app/views/miq_ae_class/_embedded_methods.html.haml
index bfce9a82565..aae0a544bfd 100644
--- a/app/views/miq_ae_class/_embedded_methods.html.haml
+++ b/app/views/miq_ae_class/_embedded_methods.html.haml
@@ -3,33 +3,4 @@
= embedded_method_list(@record[:embedded_methods])
- else
%hr
- %h3
- = _('Embedded Methods')
- #automate-inline-method-select{'ng-controller' => 'aeInlineMethodSelectionController as vm', 'ng-init' => "vm.selectable = {key: '^aem-(?!#{@selectable_methods}$)'};"}
- .pull-right
- %button.btn.btn-primary{:type => "button",
- 'ng-click' => 'vm.openModal();',
- :align => "left"}= _('Add Method')
- .clearfix
- :javascript
- miq_bootstrap('#automate-inline-method-select');
- - if !@edit[:new][:embedded_methods].nil? && !@edit[:new][:embedded_methods].empty?
- %table.table.table-striped.table-hover.table-condensed.table-bordered
- %thead
- %th= _('Path')
- %th= _('Actions')
- %tbody
- - @edit[:new][:embedded_methods].try(:each_with_index) do |method, i|
- %tr
- %td
- %text_field_tag
- = _(method.to_s)
- %td{:class => "action-cell"}
- = link_to(_('Remove'),
- {:action => "embedded_methods_remove", :id => i},
- {"data-miq_sparkle_on" => true,
- "data-miq_sparkle_off" => true,
- 'data-method' => :post,
- :remote => true,
- :class => "btn btn-default btn-block btn-sm",
- :title => _("Click to delete this input field from method")})
+ = react('AeInlineMethod', {:type => "aeInlineMethod", :selected => @embedded_methods})
diff --git a/config/routes.rb b/config/routes.rb
index ee0a80aa46b..8f705708af1 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1907,6 +1907,9 @@
explorer
method_form_fields
namespace
+ ae_domains
+ ae_methods
+ ae_method_operations
show
],
:post => %w[
diff --git a/package.json b/package.json
index edcf5fec2e1..abdd7b155d9 100644
--- a/package.json
+++ b/package.json
@@ -90,6 +90,7 @@
"react-codemirror2": "^6.0.0",
"react-dom": "~16.13.1",
"react-markdown": "6.0.0",
+ "react-query": "^3.39.3",
"react-redux": "^7.1.1",
"react-router": "~5.1.2",
"react-router-dom": "~5.1.2",
diff --git a/spec/config/routes.pending.yml b/spec/config/routes.pending.yml
index 2ac9ca1ab9b..f89eba359f4 100644
--- a/spec/config/routes.pending.yml
+++ b/spec/config/routes.pending.yml
@@ -722,6 +722,9 @@ MiqActionController:
- x_search_by_name
- x_show
MiqAeClassController:
+- ae_domains
+- ae_methods
+- ae_method_operations
- adv_search_button
- adv_search_clear
- adv_search_load_choice
diff --git a/yarn.lock b/yarn.lock
index 299ee640857..b98a1ec548e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1282,7 +1282,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.0, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.16.7, @babel/runtime@npm:^7.19.4, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.6.3, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.1, @babel/runtime@npm:^7.9.2":
+"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.0, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.16.7, @babel/runtime@npm:^7.19.4, @babel/runtime@npm:^7.23.8, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.2, @babel/runtime@npm:^7.6.3, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.1, @babel/runtime@npm:^7.9.2":
version: 7.24.7
resolution: "@babel/runtime@npm:7.24.7"
dependencies:
@@ -4137,6 +4137,13 @@ __metadata:
languageName: node
linkType: hard
+"big-integer@npm:^1.6.16":
+ version: 1.6.52
+ resolution: "big-integer@npm:1.6.52"
+ checksum: 10/4bc6ae152a96edc9f95020f5fc66b13d26a9ad9a021225a9f0213f7e3dc44269f423aa8c42e19d6ac4a63bb2b22140b95d10be8f9ca7a6d9aa1b22b330d1f514
+ languageName: node
+ linkType: hard
+
"big.js@npm:^3.1.3":
version: 3.2.0
resolution: "big.js@npm:3.2.0"
@@ -4393,6 +4400,22 @@ __metadata:
languageName: node
linkType: hard
+"broadcast-channel@npm:^3.4.1":
+ version: 3.7.0
+ resolution: "broadcast-channel@npm:3.7.0"
+ dependencies:
+ "@babel/runtime": "npm:^7.7.2"
+ detect-node: "npm:^2.1.0"
+ js-sha3: "npm:0.8.0"
+ microseconds: "npm:0.2.0"
+ nano-time: "npm:1.0.0"
+ oblivious-set: "npm:1.0.0"
+ rimraf: "npm:3.0.2"
+ unload: "npm:2.2.0"
+ checksum: 10/ccf6be63c5ed03965f00c28f2cc55028ca3d6eb6f47cb430cc7a5e1ed404c54601c32bc87db24d11f229c80201fd2e606f5c9683543875a7e26ca06e23079782
+ languageName: node
+ linkType: hard
+
"brorand@npm:^1.0.1, brorand@npm:^1.1.0":
version: 1.1.0
resolution: "brorand@npm:1.1.0"
@@ -6632,7 +6655,7 @@ __metadata:
languageName: node
linkType: hard
-"detect-node@npm:^2.0.4":
+"detect-node@npm:^2.0.4, detect-node@npm:^2.1.0":
version: 2.1.0
resolution: "detect-node@npm:2.1.0"
checksum: 10/832184ec458353e41533ac9c622f16c19f7c02d8b10c303dfd3a756f56be93e903616c0bb2d4226183c9351c15fc0b3dba41a17a2308262afabcfa3776e6ae6e
@@ -10801,6 +10824,13 @@ __metadata:
languageName: node
linkType: hard
+"js-sha3@npm:0.8.0":
+ version: 0.8.0
+ resolution: "js-sha3@npm:0.8.0"
+ checksum: 10/a49ac6d3a6bfd7091472a28ab82a94c7fb8544cc584ee1906486536ba1cb4073a166f8c7bb2b0565eade23c5b3a7b8f7816231e0309ab5c549b737632377a20c
+ languageName: node
+ linkType: hard
+
"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0":
version: 4.0.0
resolution: "js-tokens@npm:4.0.0"
@@ -11762,6 +11792,7 @@ __metadata:
react-codemirror2: "npm:^6.0.0"
react-dom: "npm:~16.13.1"
react-markdown: "npm:6.0.0"
+ react-query: "npm:^3.39.3"
react-redux: "npm:^7.1.1"
react-router: "npm:~5.1.2"
react-router-dom: "npm:~5.1.2"
@@ -11826,6 +11857,16 @@ __metadata:
languageName: node
linkType: hard
+"match-sorter@npm:^6.0.2":
+ version: 6.3.4
+ resolution: "match-sorter@npm:6.3.4"
+ dependencies:
+ "@babel/runtime": "npm:^7.23.8"
+ remove-accents: "npm:0.5.0"
+ checksum: 10/80b6cb04415b68b32cc7ec1242cc125f95ca6a8739a787dbc5e8058a120aaf5cb4ff8f8467b6f9949a8d8a6430a44d64659894d26138a03a8c0dd6ba239d5519
+ languageName: node
+ linkType: hard
+
"mathml-tag-names@npm:^2.1.3":
version: 2.1.3
resolution: "mathml-tag-names@npm:2.1.3"
@@ -12021,6 +12062,13 @@ __metadata:
languageName: node
linkType: hard
+"microseconds@npm:0.2.0":
+ version: 0.2.0
+ resolution: "microseconds@npm:0.2.0"
+ checksum: 10/22bfa8553f92c7d95afff6de0aeb2aecf750680d41b8c72b02098ccc5bbbb0a384380ff539292dbd3788f5dfc298682f9d38a2b4c101f5ee2c9471d53934c5fa
+ languageName: node
+ linkType: hard
+
"miller-rabin@npm:^4.0.0":
version: 4.0.1
resolution: "miller-rabin@npm:4.0.1"
@@ -12383,6 +12431,15 @@ __metadata:
languageName: node
linkType: hard
+"nano-time@npm:1.0.0":
+ version: 1.0.0
+ resolution: "nano-time@npm:1.0.0"
+ dependencies:
+ big-integer: "npm:^1.6.16"
+ checksum: 10/eef8548546cc1020625f8e44751a7263e9eddf0412a6a1a6c80a8d2be2ea7973622804a977cdfe796807b85b20ff6c8ba340e8dd20effcc7078193ed5edbb5d4
+ languageName: node
+ linkType: hard
+
"nanoid@npm:^3.3.7":
version: 3.3.7
resolution: "nanoid@npm:3.3.7"
@@ -12845,6 +12902,13 @@ __metadata:
languageName: node
linkType: hard
+"oblivious-set@npm:1.0.0":
+ version: 1.0.0
+ resolution: "oblivious-set@npm:1.0.0"
+ checksum: 10/f31740ea9c3a8242ad2324e4ebb9a35359fbc2e6e7131731a0fc1c8b7b1238eb07e4c8c631a38535243a7b8e3042b7e89f7dc2a95d2989afd6f80bd5793b0aab
+ languageName: node
+ linkType: hard
+
"obuf@npm:^1.0.0, obuf@npm:^1.1.2":
version: 1.1.2
resolution: "obuf@npm:1.1.2"
@@ -14755,6 +14819,24 @@ __metadata:
languageName: node
linkType: hard
+"react-query@npm:^3.39.3":
+ version: 3.39.3
+ resolution: "react-query@npm:3.39.3"
+ dependencies:
+ "@babel/runtime": "npm:^7.5.5"
+ broadcast-channel: "npm:^3.4.1"
+ match-sorter: "npm:^6.0.2"
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ react-dom:
+ optional: true
+ react-native:
+ optional: true
+ checksum: 10/17dc4eb75d2ebc262b685096dfaa203202a883ac43768d0faf80f3ad4bdf791dff0691569d6e8ec2ac81b9377c5477e0a1ebea9f51bae1482ca154f5dde50d2d
+ languageName: node
+ linkType: hard
+
"react-redux@npm:^7.1.1":
version: 7.2.9
resolution: "react-redux@npm:7.2.9"
@@ -15215,6 +15297,13 @@ __metadata:
languageName: node
linkType: hard
+"remove-accents@npm:0.5.0":
+ version: 0.5.0
+ resolution: "remove-accents@npm:0.5.0"
+ checksum: 10/4aa1a9d0c18468515a33c6760b0f8e28dfbceddcb846fac90b2189445445b27b11cc1df9fbceb97b4449438bc13250d77b27d4ab325b2d69933acc156d6c5b50
+ languageName: node
+ linkType: hard
+
"remove-trailing-separator@npm:^1.0.1":
version: 1.1.0
resolution: "remove-trailing-separator@npm:1.1.0"
@@ -15524,25 +15613,25 @@ __metadata:
languageName: node
linkType: hard
-"rimraf@npm:^2.5.4, rimraf@npm:^2.6.3":
- version: 2.7.1
- resolution: "rimraf@npm:2.7.1"
+"rimraf@npm:3.0.2, rimraf@npm:^3.0.2":
+ version: 3.0.2
+ resolution: "rimraf@npm:3.0.2"
dependencies:
glob: "npm:^7.1.3"
bin:
- rimraf: ./bin.js
- checksum: 10/4586c296c736483e297da7cffd19475e4a3e41d07b1ae124aad5d687c79e4ffa716bdac8732ed1db942caf65271cee9dd39f8b639611de161a2753e2112ffe1d
+ rimraf: bin.js
+ checksum: 10/063ffaccaaaca2cfd0ef3beafb12d6a03dd7ff1260d752d62a6077b5dfff6ae81bea571f655bb6b589d366930ec1bdd285d40d560c0dae9b12f125e54eb743d5
languageName: node
linkType: hard
-"rimraf@npm:^3.0.2":
- version: 3.0.2
- resolution: "rimraf@npm:3.0.2"
+"rimraf@npm:^2.5.4, rimraf@npm:^2.6.3":
+ version: 2.7.1
+ resolution: "rimraf@npm:2.7.1"
dependencies:
glob: "npm:^7.1.3"
bin:
- rimraf: bin.js
- checksum: 10/063ffaccaaaca2cfd0ef3beafb12d6a03dd7ff1260d752d62a6077b5dfff6ae81bea571f655bb6b589d366930ec1bdd285d40d560c0dae9b12f125e54eb743d5
+ rimraf: ./bin.js
+ checksum: 10/4586c296c736483e297da7cffd19475e4a3e41d07b1ae124aad5d687c79e4ffa716bdac8732ed1db942caf65271cee9dd39f8b639611de161a2753e2112ffe1d
languageName: node
linkType: hard
@@ -17769,6 +17858,16 @@ __metadata:
languageName: node
linkType: hard
+"unload@npm:2.2.0":
+ version: 2.2.0
+ resolution: "unload@npm:2.2.0"
+ dependencies:
+ "@babel/runtime": "npm:^7.6.2"
+ detect-node: "npm:^2.0.4"
+ checksum: 10/382f676f24b774dc84beaf424326a227929ecad0ea0f319d4fd0812376b3306ea6d7ccf7ea85c6663ed7be552e9e004f429146bad8faf976b43084e29e265d10
+ languageName: node
+ linkType: hard
+
"unpipe@npm:1.0.0, unpipe@npm:~1.0.0":
version: 1.0.0
resolution: "unpipe@npm:1.0.0"