Eui 3.6.0 (#21968)
* bump EUI to 3.6.0 * replace CopyButton with EuiCopy * remove snapshot file from deleted CopyButton component
This commit is contained in:
parent
341d5008dc
commit
67401cea92
|
@ -60,7 +60,7 @@
|
||||||
"url": "https://github.com/elastic/kibana.git"
|
"url": "https://github.com/elastic/kibana.git"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@elastic/eui": "3.4.0",
|
"@elastic/eui": "3.6.0",
|
||||||
"@elastic/filesaver": "1.1.2",
|
"@elastic/filesaver": "1.1.2",
|
||||||
"@elastic/numeral": "2.3.2",
|
"@elastic/numeral": "2.3.2",
|
||||||
"@elastic/ui-ace": "0.2.3",
|
"@elastic/ui-ace": "0.2.3",
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`render 1`] = `
|
|
||||||
<EuiToolTip
|
|
||||||
content="Copy to clipboard"
|
|
||||||
position="top"
|
|
||||||
>
|
|
||||||
<EuiButton
|
|
||||||
color="primary"
|
|
||||||
fill={false}
|
|
||||||
iconSide="left"
|
|
||||||
onClick={[Function]}
|
|
||||||
onMouseOut={[Function]}
|
|
||||||
size="s"
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
Copy snippet
|
|
||||||
</EuiButton>
|
|
||||||
</EuiToolTip>
|
|
||||||
`;
|
|
|
@ -1,75 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
|
||||||
* license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright
|
|
||||||
* ownership. Elasticsearch B.V. licenses this file to you 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 React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import {
|
|
||||||
EuiButton,
|
|
||||||
EuiToolTip,
|
|
||||||
} from '@elastic/eui';
|
|
||||||
import { copyToClipboard } from '../../copy_to_clipboard';
|
|
||||||
|
|
||||||
const UNCOPIED_MSG = 'Copy to clipboard';
|
|
||||||
const COPIED_MSG = 'Copied';
|
|
||||||
|
|
||||||
export class CopyButton extends React.Component {
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
tooltipText: UNCOPIED_MSG
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
copySnippet = () => {
|
|
||||||
const isCopied = copyToClipboard(this.props.textToCopy);
|
|
||||||
if (isCopied) {
|
|
||||||
this.setState({
|
|
||||||
tooltipText: COPIED_MSG,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resetTooltipText = () => {
|
|
||||||
this.setState({
|
|
||||||
tooltipText: UNCOPIED_MSG,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<EuiToolTip
|
|
||||||
content={this.state.tooltipText}
|
|
||||||
>
|
|
||||||
<EuiButton
|
|
||||||
size="s"
|
|
||||||
onClick={this.copySnippet}
|
|
||||||
onMouseOut={this.resetTooltipText}
|
|
||||||
>
|
|
||||||
Copy snippet
|
|
||||||
</EuiButton>
|
|
||||||
</EuiToolTip>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CopyButton.propTypes = {
|
|
||||||
textToCopy: PropTypes.string.isRequired,
|
|
||||||
};
|
|
|
@ -1,32 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
|
||||||
* license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright
|
|
||||||
* ownership. Elasticsearch B.V. licenses this file to you 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 React from 'react';
|
|
||||||
import { shallow } from 'enzyme';
|
|
||||||
|
|
||||||
import {
|
|
||||||
CopyButton,
|
|
||||||
} from './copy_button';
|
|
||||||
|
|
||||||
test('render', () => {
|
|
||||||
const component = shallow(<CopyButton
|
|
||||||
textToCopy={'text that is copied to clipboard'}
|
|
||||||
/>);
|
|
||||||
expect(component).toMatchSnapshot();
|
|
||||||
});
|
|
|
@ -20,13 +20,14 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Content } from './content';
|
import { Content } from './content';
|
||||||
import { CopyButton } from './copy_button';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
EuiCodeBlock,
|
EuiCodeBlock,
|
||||||
EuiFlexGroup,
|
EuiFlexGroup,
|
||||||
EuiFlexItem,
|
EuiFlexItem,
|
||||||
EuiSpacer,
|
EuiSpacer,
|
||||||
|
EuiCopy,
|
||||||
|
EuiButton,
|
||||||
} from '@elastic/eui';
|
} from '@elastic/eui';
|
||||||
|
|
||||||
export function Instruction({ commands, paramValues, textPost, textPre, replaceTemplateStrings }) {
|
export function Instruction({ commands, paramValues, textPost, textPre, replaceTemplateStrings }) {
|
||||||
|
@ -56,9 +57,18 @@ export function Instruction({ commands, paramValues, textPost, textPre, replaceT
|
||||||
if (commands) {
|
if (commands) {
|
||||||
const cmdText = commands.map(cmd => { return replaceTemplateStrings(cmd, paramValues); }).join('\n');
|
const cmdText = commands.map(cmd => { return replaceTemplateStrings(cmd, paramValues); }).join('\n');
|
||||||
copyButton = (
|
copyButton = (
|
||||||
<CopyButton
|
<EuiCopy
|
||||||
textToCopy={cmdText}
|
textToCopy={cmdText}
|
||||||
/>
|
>
|
||||||
|
{(copy) => (
|
||||||
|
<EuiButton
|
||||||
|
size="s"
|
||||||
|
onClick={copy}
|
||||||
|
>
|
||||||
|
Copy snippet
|
||||||
|
</EuiButton>
|
||||||
|
)}
|
||||||
|
</EuiCopy>
|
||||||
);
|
);
|
||||||
commandBlock = (
|
commandBlock = (
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
|
||||||
* license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright
|
|
||||||
* ownership. Elasticsearch B.V. licenses this file to you 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
function createHiddenTextElement(text) {
|
|
||||||
const textElement = document.createElement('span');
|
|
||||||
textElement.textContent = text;
|
|
||||||
textElement.style.all = 'unset';
|
|
||||||
// prevents scrolling to the end of the page
|
|
||||||
textElement.style.position = 'fixed';
|
|
||||||
textElement.style.top = 0;
|
|
||||||
textElement.style.clip = 'rect(0, 0, 0, 0)';
|
|
||||||
// used to preserve spaces and line breaks
|
|
||||||
textElement.style.whiteSpace = 'pre';
|
|
||||||
// do not inherit user-select (it may be `none`)
|
|
||||||
textElement.style.webkitUserSelect = 'text';
|
|
||||||
textElement.style.MozUserSelect = 'text';
|
|
||||||
textElement.style.msUserSelect = 'text';
|
|
||||||
textElement.style.userSelect = 'text';
|
|
||||||
return textElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function copyToClipboard(text) {
|
|
||||||
let isCopied = true;
|
|
||||||
const range = document.createRange();
|
|
||||||
const selection = window.getSelection();
|
|
||||||
const elementToBeCopied = createHiddenTextElement(text);
|
|
||||||
|
|
||||||
document.body.appendChild(elementToBeCopied);
|
|
||||||
range.selectNode(elementToBeCopied);
|
|
||||||
selection.removeAllRanges();
|
|
||||||
selection.addRange(range);
|
|
||||||
|
|
||||||
if (!document.execCommand('copy')) {
|
|
||||||
isCopied = false;
|
|
||||||
console.warn('Unable to copy to clipboard.'); // eslint-disable-line no-console
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selection) {
|
|
||||||
if (typeof selection.removeRange === 'function') {
|
|
||||||
selection.removeRange(range);
|
|
||||||
} else {
|
|
||||||
selection.removeAllRanges();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.body.removeChild(elementToBeCopied);
|
|
||||||
|
|
||||||
return isCopied;
|
|
||||||
}
|
|
|
@ -79,7 +79,7 @@
|
||||||
"yargs": "4.7.1"
|
"yargs": "4.7.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@elastic/eui": "3.4.0",
|
"@elastic/eui": "3.6.0",
|
||||||
"@elastic/node-crypto": "0.1.2",
|
"@elastic/node-crypto": "0.1.2",
|
||||||
"@elastic/node-phantom-simple": "2.2.4",
|
"@elastic/node-phantom-simple": "2.2.4",
|
||||||
"@elastic/numeral": "2.3.2",
|
"@elastic/numeral": "2.3.2",
|
||||||
|
|
|
@ -30,6 +30,7 @@ exports[`ActionsSection renders with no actions selected 1`] = `
|
||||||
compressed={false}
|
compressed={false}
|
||||||
disabled={false}
|
disabled={false}
|
||||||
id="skip_result_cb"
|
id="skip_result_cb"
|
||||||
|
indeterminate={false}
|
||||||
label="Skip result (recommended)"
|
label="Skip result (recommended)"
|
||||||
onChange={[MockFunction]}
|
onChange={[MockFunction]}
|
||||||
/>
|
/>
|
||||||
|
@ -68,6 +69,7 @@ exports[`ActionsSection renders with no actions selected 1`] = `
|
||||||
compressed={false}
|
compressed={false}
|
||||||
disabled={false}
|
disabled={false}
|
||||||
id="skip_model_update_cb"
|
id="skip_model_update_cb"
|
||||||
|
indeterminate={false}
|
||||||
label="Skip model update"
|
label="Skip model update"
|
||||||
onChange={[MockFunction]}
|
onChange={[MockFunction]}
|
||||||
/>
|
/>
|
||||||
|
@ -118,6 +120,7 @@ exports[`ActionsSection renders with skip_result and skip_model_update selected
|
||||||
compressed={false}
|
compressed={false}
|
||||||
disabled={false}
|
disabled={false}
|
||||||
id="skip_result_cb"
|
id="skip_result_cb"
|
||||||
|
indeterminate={false}
|
||||||
label="Skip result (recommended)"
|
label="Skip result (recommended)"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
/>
|
/>
|
||||||
|
@ -156,6 +159,7 @@ exports[`ActionsSection renders with skip_result and skip_model_update selected
|
||||||
compressed={false}
|
compressed={false}
|
||||||
disabled={false}
|
disabled={false}
|
||||||
id="skip_model_update_cb"
|
id="skip_model_update_cb"
|
||||||
|
indeterminate={false}
|
||||||
label="Skip model update"
|
label="Skip model update"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
/>
|
/>
|
||||||
|
@ -206,6 +210,7 @@ exports[`ActionsSection renders with skip_result selected 1`] = `
|
||||||
compressed={false}
|
compressed={false}
|
||||||
disabled={false}
|
disabled={false}
|
||||||
id="skip_result_cb"
|
id="skip_result_cb"
|
||||||
|
indeterminate={false}
|
||||||
label="Skip result (recommended)"
|
label="Skip result (recommended)"
|
||||||
onChange={[MockFunction]}
|
onChange={[MockFunction]}
|
||||||
/>
|
/>
|
||||||
|
@ -244,6 +249,7 @@ exports[`ActionsSection renders with skip_result selected 1`] = `
|
||||||
compressed={false}
|
compressed={false}
|
||||||
disabled={false}
|
disabled={false}
|
||||||
id="skip_model_update_cb"
|
id="skip_model_update_cb"
|
||||||
|
indeterminate={false}
|
||||||
label="Skip model update"
|
label="Skip model update"
|
||||||
onChange={[MockFunction]}
|
onChange={[MockFunction]}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -133,6 +133,7 @@ exports[`RuleEditorFlyout renders the flyout after adding a condition to a rule
|
||||||
compressed={false}
|
compressed={false}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
id="enable_conditions_checkbox"
|
id="enable_conditions_checkbox"
|
||||||
|
indeterminate={false}
|
||||||
label="Add numeric conditions for when the rule applies. Multiple conditions are combined using AND."
|
label="Add numeric conditions for when the rule applies. Multiple conditions are combined using AND."
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
/>
|
/>
|
||||||
|
@ -367,6 +368,7 @@ exports[`RuleEditorFlyout renders the flyout after setting the rule to edit 1`]
|
||||||
compressed={false}
|
compressed={false}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
id="enable_conditions_checkbox"
|
id="enable_conditions_checkbox"
|
||||||
|
indeterminate={false}
|
||||||
label="Add numeric conditions for when the rule applies. Multiple conditions are combined using AND."
|
label="Add numeric conditions for when the rule applies. Multiple conditions are combined using AND."
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
/>
|
/>
|
||||||
|
@ -587,6 +589,7 @@ exports[`RuleEditorFlyout renders the flyout for creating a rule with conditions
|
||||||
compressed={false}
|
compressed={false}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
id="enable_conditions_checkbox"
|
id="enable_conditions_checkbox"
|
||||||
|
indeterminate={false}
|
||||||
label="Add numeric conditions for when the rule applies. Multiple conditions are combined using AND."
|
label="Add numeric conditions for when the rule applies. Multiple conditions are combined using AND."
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -20,6 +20,7 @@ exports[`ScopeExpression renders when empty list of filter IDs is supplied 1`] =
|
||||||
compressed={false}
|
compressed={false}
|
||||||
disabled={false}
|
disabled={false}
|
||||||
id="scope_cb_domain"
|
id="scope_cb_domain"
|
||||||
|
indeterminate={false}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
/>
|
/>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
|
@ -58,6 +59,7 @@ exports[`ScopeExpression renders when enabled set to false 1`] = `
|
||||||
compressed={false}
|
compressed={false}
|
||||||
disabled={false}
|
disabled={false}
|
||||||
id="scope_cb_domain"
|
id="scope_cb_domain"
|
||||||
|
indeterminate={false}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
/>
|
/>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
|
@ -211,6 +213,7 @@ exports[`ScopeExpression renders when filter ID and type supplied 1`] = `
|
||||||
compressed={false}
|
compressed={false}
|
||||||
disabled={false}
|
disabled={false}
|
||||||
id="scope_cb_domain"
|
id="scope_cb_domain"
|
||||||
|
indeterminate={false}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
/>
|
/>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
|
@ -364,6 +367,7 @@ exports[`ScopeExpression renders when no filter ID or type supplied 1`] = `
|
||||||
compressed={false}
|
compressed={false}
|
||||||
disabled={false}
|
disabled={false}
|
||||||
id="scope_cb_domain"
|
id="scope_cb_domain"
|
||||||
|
indeterminate={false}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
/>
|
/>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
|
|
|
@ -19,6 +19,7 @@ exports[`ScopeSection false canGetFilters privilege show NoPermissionCallOut whe
|
||||||
compressed={false}
|
compressed={false}
|
||||||
disabled={false}
|
disabled={false}
|
||||||
id="enable_scope_checkbox"
|
id="enable_scope_checkbox"
|
||||||
|
indeterminate={false}
|
||||||
label="Add a filter list to limit where the rule applies."
|
label="Add a filter list to limit where the rule applies."
|
||||||
onChange={[MockFunction]}
|
onChange={[MockFunction]}
|
||||||
/>
|
/>
|
||||||
|
@ -51,6 +52,7 @@ exports[`ScopeSection renders when enabled with no scope supplied 1`] = `
|
||||||
compressed={false}
|
compressed={false}
|
||||||
disabled={false}
|
disabled={false}
|
||||||
id="enable_scope_checkbox"
|
id="enable_scope_checkbox"
|
||||||
|
indeterminate={false}
|
||||||
label="Add a filter list to limit where the rule applies."
|
label="Add a filter list to limit where the rule applies."
|
||||||
onChange={[MockFunction]}
|
onChange={[MockFunction]}
|
||||||
/>
|
/>
|
||||||
|
@ -97,6 +99,7 @@ exports[`ScopeSection renders when enabled with scope supplied 1`] = `
|
||||||
compressed={false}
|
compressed={false}
|
||||||
disabled={false}
|
disabled={false}
|
||||||
id="enable_scope_checkbox"
|
id="enable_scope_checkbox"
|
||||||
|
indeterminate={false}
|
||||||
label="Add a filter list to limit where the rule applies."
|
label="Add a filter list to limit where the rule applies."
|
||||||
onChange={[MockFunction]}
|
onChange={[MockFunction]}
|
||||||
/>
|
/>
|
||||||
|
@ -143,6 +146,7 @@ exports[`ScopeSection renders when not enabled 1`] = `
|
||||||
compressed={false}
|
compressed={false}
|
||||||
disabled={false}
|
disabled={false}
|
||||||
id="enable_scope_checkbox"
|
id="enable_scope_checkbox"
|
||||||
|
indeterminate={false}
|
||||||
label="Add a filter list to limit where the rule applies."
|
label="Add a filter list to limit where the rule applies."
|
||||||
onChange={[MockFunction]}
|
onChange={[MockFunction]}
|
||||||
/>
|
/>
|
||||||
|
@ -172,6 +176,7 @@ exports[`ScopeSection show NoFilterListsCallOut when no filter list IDs 1`] = `
|
||||||
compressed={false}
|
compressed={false}
|
||||||
disabled={false}
|
disabled={false}
|
||||||
id="enable_scope_checkbox"
|
id="enable_scope_checkbox"
|
||||||
|
indeterminate={false}
|
||||||
label="Add a filter list to limit where the rule applies."
|
label="Add a filter list to limit where the rule applies."
|
||||||
onChange={[MockFunction]}
|
onChange={[MockFunction]}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
esutils "^2.0.2"
|
esutils "^2.0.2"
|
||||||
js-tokens "^3.0.0"
|
js-tokens "^3.0.0"
|
||||||
|
|
||||||
"@elastic/eui@3.4.0":
|
"@elastic/eui@3.6.0":
|
||||||
version "3.4.0"
|
version "3.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-3.4.0.tgz#8eb661b56fc84a27682e008ef9d6913d1b519c07"
|
resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-3.6.0.tgz#ce55a321510dfeb20ca0b46061cbbd29a70b91cd"
|
||||||
dependencies:
|
dependencies:
|
||||||
classnames "^2.2.5"
|
classnames "^2.2.5"
|
||||||
core-js "^2.5.1"
|
core-js "^2.5.1"
|
||||||
|
|
|
@ -81,9 +81,9 @@
|
||||||
version "0.0.0"
|
version "0.0.0"
|
||||||
uid ""
|
uid ""
|
||||||
|
|
||||||
"@elastic/eui@3.4.0":
|
"@elastic/eui@3.6.0":
|
||||||
version "3.4.0"
|
version "3.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-3.4.0.tgz#8eb661b56fc84a27682e008ef9d6913d1b519c07"
|
resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-3.6.0.tgz#ce55a321510dfeb20ca0b46061cbbd29a70b91cd"
|
||||||
dependencies:
|
dependencies:
|
||||||
classnames "^2.2.5"
|
classnames "^2.2.5"
|
||||||
core-js "^2.5.1"
|
core-js "^2.5.1"
|
||||||
|
|
Loading…
Reference in a new issue