[8.x] [Console] Add a small action for copying variable names to clipboard (#206628) (#206897)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Console] Add a small action for copying variable names to clipboard
(#206628)](https://github.com/elastic/kibana/pull/206628)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Ignacio
Rivas","email":"rivasign@gmail.com"},"sourceCommit":{"committedDate":"2025-01-16T08:27:31Z","message":"[Console]
Add a small action for copying variable names to clipboard
(#206628)","sha":"983470fb852b5fc011e47b8f7a3d9f917d06a228","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Feature:Console","Team:Kibana
Management","release_note:skip","v9.0.0","backport:prev-minor"],"title":"[Console]
Add a small action for copying variable names to
clipboard","number":206628,"url":"https://github.com/elastic/kibana/pull/206628","mergeCommit":{"message":"[Console]
Add a small action for copying variable names to clipboard
(#206628)","sha":"983470fb852b5fc011e47b8f7a3d9f917d06a228"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/206628","number":206628,"mergeCommit":{"message":"[Console]
Add a small action for copying variable names to clipboard
(#206628)","sha":"983470fb852b5fc011e47b8f7a3d9f917d06a228"}}]}]
BACKPORT-->

Co-authored-by: Ignacio Rivas <rivasign@gmail.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Kibana Machine 2025-01-20 21:28:31 +11:00 committed by GitHub
parent c306e440d6
commit 343c322855
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 84 additions and 0 deletions

View file

@ -22,9 +22,12 @@ import {
EuiCode,
useGeneratedHtmlId,
EuiConfirmModal,
EuiToolTip,
type EuiBasicTableColumn,
} from '@elastic/eui';
import { NotificationsSetup } from '@kbn/core/public';
import { useServicesContext } from '../../contexts';
import { VariableEditorForm } from './variables_editor_form';
import * as utils from './utils';
import { type DevToolsVariable } from './types';
@ -34,6 +37,32 @@ export interface Props {
variables: [];
}
const sendToBrowserClipboard = async (text: string) => {
if (window.navigator?.clipboard) {
await window.navigator.clipboard.writeText(text);
return;
}
throw new Error('Could not copy to clipboard!');
};
const copyToClipboard = async (text: string, notifications: NotificationsSetup) => {
try {
await sendToBrowserClipboard(text);
notifications.toasts.addSuccess({
title: i18n.translate('console.variabllesPage.copyToClipboardSuccess', {
defaultMessage: 'Variable name copied to clipboard',
}),
});
} catch (e) {
notifications.toasts.addError(e, {
title: i18n.translate('console.variabllesPage.copyToClipboardFailed', {
defaultMessage: 'Could not copy variable name to clipboard',
}),
});
}
};
export const VariablesEditor = (props: Props) => {
const isMounted = useRef(false);
const [isAddingVariable, setIsAddingVariable] = useState(false);
@ -41,6 +70,10 @@ export const VariablesEditor = (props: Props) => {
const [variables, setVariables] = useState<DevToolsVariable[]>(props.variables);
const deleteModalTitleId = useGeneratedHtmlId();
const {
services: { notifications },
} = useServicesContext();
// Use a ref to persist the BehaviorSubject across renders
const itemIdToExpandedRowMap$ = useRef(new BehaviorSubject<Record<string, React.ReactNode>>({}));
// Subscribe to the BehaviorSubject and update local state on change
@ -131,6 +164,34 @@ export const VariablesEditor = (props: Props) => {
'data-test-subj': 'variableValueCell',
render: (value: string) => <EuiCode>{value}</EuiCode>,
},
{
field: 'id',
name: '',
width: '40px',
render: (id: string, variable: DevToolsVariable) => {
return (
<EuiToolTip
content={i18n.translate('console.variablesPage.copyVariableToClipboardTooltip', {
defaultMessage: 'Copy variable name to clipboard',
})}
>
<EuiButtonIcon
iconType="copy"
aria-label={i18n.translate(
'console.variablesPage.variablesTable.columns.copyNameButton',
{
defaultMessage: 'Copy {variable} to clipboard',
values: { variable: variable.name },
}
)}
color="primary"
onClick={() => copyToClipboard(`\$\{${variable.name}\}`, notifications)}
data-test-subj={`variableCopyButton-${variable.name}`}
/>
</EuiToolTip>
);
},
},
{
field: 'id',
name: '',

View file

@ -13,6 +13,7 @@ import { FtrProviderContext } from '../../ftr_provider_context';
export default ({ getService, getPageObjects }: FtrProviderContext) => {
const retry = getService('retry');
const log = getService('log');
const browser = getService('browser');
const PageObjects = getPageObjects(['common', 'console', 'header']);
describe('Console variables', function testConsoleVariables() {
@ -45,6 +46,24 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => {
expect(variables).to.eql([]);
});
it('should allow copying a variable to clipboard', async () => {
await PageObjects.console.openConfig();
// Add a new test variable
await PageObjects.console.addNewVariable({ name: 'test_variable', value: 'test' });
// Copy the variable to clipboard
await PageObjects.console.copyVariableToClipboard('test_variable');
await retry.try(async () => {
const actualRequest = await browser.execute(() => navigator.clipboard.readText());
expect(actualRequest.trim()).to.contain('${test_variable}');
});
// Clean up
await PageObjects.console.removeVariables();
});
describe('with variables in url', () => {
it('should send a successful request', async () => {
await PageObjects.console.openConfig();

View file

@ -360,6 +360,10 @@ export class ConsolePageObject extends FtrService {
});
}
public async copyVariableToClipboard(name: string) {
await this.testSubjects.click(`variableCopyButton-${name}`);
}
public async getVariables() {
const table = await this.testSubjects.find('variablesTable');
const rows = await table.findAllByClassName('euiTableRow');