Skip to content

Commit

Permalink
[8.x] [Synthetics] Fixes partial updates for params and params viewing (
Browse files Browse the repository at this point in the history
#195866) (#197850)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Synthetics] Fixes partial updates for params and params viewing
(#195866)](#195866)

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

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

<!--BACKPORT
[{"author":{"name":"Shahzad","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-10-25T15:06:52Z","message":"[Synthetics]
Fixes partial updates for params and params viewing (#195866)\n\n##
Summary\r\n\r\nFixes
https://github.com/elastic/kibana/issues/167781\r\n\r\nIn docs we says
that only key/value pairs are required, but in actual\r\nedit, that
means rest of the data was being lost on edits\r\n\r\nAllow partial
updates to params edit API !!\r\n\r\nThis PR makes sure prev objects is
fetched and merged with new data\r\nhence allowing partial updates
!!\r\n\r\nWe are also allowing the ability to view value of the secret
once it's\r\nsaved via API !!\r\n\r\n### Value is hidden\r\nParam value
will not be visible unless user is `super_user` or\r\n`kibana_admin`,
though user can assign new
value.\r\n\r\n---------\r\n\r\nCo-authored-by: Justin Kambic
<[email protected]>","sha":"0ff9a8a9d9ff2bdb99562eeca29152bd0a0c4385","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","backport:prev-minor","ci:project-deploy-observability","Team:obs-ux-management"],"title":"[Synthetics]
Fixes partial updates for params and params
viewing","number":195866,"url":"https://github.com/elastic/kibana/pull/195866","mergeCommit":{"message":"[Synthetics]
Fixes partial updates for params and params viewing (#195866)\n\n##
Summary\r\n\r\nFixes
https://github.com/elastic/kibana/issues/167781\r\n\r\nIn docs we says
that only key/value pairs are required, but in actual\r\nedit, that
means rest of the data was being lost on edits\r\n\r\nAllow partial
updates to params edit API !!\r\n\r\nThis PR makes sure prev objects is
fetched and merged with new data\r\nhence allowing partial updates
!!\r\n\r\nWe are also allowing the ability to view value of the secret
once it's\r\nsaved via API !!\r\n\r\n### Value is hidden\r\nParam value
will not be visible unless user is `super_user` or\r\n`kibana_admin`,
though user can assign new
value.\r\n\r\n---------\r\n\r\nCo-authored-by: Justin Kambic
<[email protected]>","sha":"0ff9a8a9d9ff2bdb99562eeca29152bd0a0c4385"}},"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/195866","number":195866,"mergeCommit":{"message":"[Synthetics]
Fixes partial updates for params and params viewing (#195866)\n\n##
Summary\r\n\r\nFixes
https://github.com/elastic/kibana/issues/167781\r\n\r\nIn docs we says
that only key/value pairs are required, but in actual\r\nedit, that
means rest of the data was being lost on edits\r\n\r\nAllow partial
updates to params edit API !!\r\n\r\nThis PR makes sure prev objects is
fetched and merged with new data\r\nhence allowing partial updates
!!\r\n\r\nWe are also allowing the ability to view value of the secret
once it's\r\nsaved via API !!\r\n\r\n### Value is hidden\r\nParam value
will not be visible unless user is `super_user` or\r\n`kibana_admin`,
though user can assign new
value.\r\n\r\n---------\r\n\r\nCo-authored-by: Justin Kambic
<[email protected]>","sha":"0ff9a8a9d9ff2bdb99562eeca29152bd0a0c4385"}}]}]
BACKPORT-->

Co-authored-by: Shahzad <[email protected]>
  • Loading branch information
kibanamachine and shahzad31 authored Oct 25, 2024
1 parent 9f5ff83 commit 4c22558
Show file tree
Hide file tree
Showing 12 changed files with 355 additions and 110 deletions.
6 changes: 3 additions & 3 deletions docs/api/synthetics/params/edit-param.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ You must have `all` privileges for the *Synthetics* feature in the *{observabili
[[parameter-edit-request-body]]
==== Request body

The request body should contain the following attributes:
The request body can contain the following attributes, it can't be empty at least one attribute is required.:

`key`::
(Required, string) The key of the parameter.
(Optional, string) The key of the parameter.

`value`::
(Required, string) The updated value associated with the parameter.
(Optional, string) The updated value associated with the parameter.

`description`::
(Optional, string) The updated description of the parameter.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ journey(`GlobalParameters`, async ({ page, params }) => {
await page.click('text=Delete ParameterEdit Parameter >> :nth-match(button, 2)');
await page.click('[aria-label="Key"]');
await page.fill('[aria-label="Key"]', 'username2');
await page.click('[aria-label="Value"]');
await page.fill('[aria-label="Value"]', 'elastic2');
await page.click('[aria-label="New value"]');
await page.fill('[aria-label="New value"]', 'elastic2');
await page.click('.euiComboBox__inputWrap');
await page.fill('[aria-label="Tags"]', 'staging');
await page.press('[aria-label="Tags"]', 'Enter');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { EuiText } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';

export function OptionalText() {
return (
<EuiText size="xs" color="subdued">
{i18n.translate('xpack.synthetics.sloEdit.optionalLabel', {
defaultMessage: 'Optional',
})}
</EuiText>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { FormProvider } from 'react-hook-form';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { i18n } from '@kbn/i18n';
import { useDispatch, useSelector } from 'react-redux';
import { isEmpty } from 'lodash';
import { NoPermissionsTooltip } from '../../common/components/permissions';
import {
addNewGlobalParamAction,
Expand Down Expand Up @@ -80,18 +81,29 @@ export const AddParamFlyout = ({
const onSubmit = (formData: SyntheticsParams) => {
const { namespaces, ...paramRequest } = formData;
const shareAcrossSpaces = namespaces?.includes(ALL_SPACES_ID);
const newParamData = {
...paramRequest,
};

if (isEditingItem && id) {
// omit value if it's empty
if (isEmpty(newParamData.value)) {
// @ts-ignore this is a valid check
delete newParamData.value;
}
}

if (isEditingItem && id) {
dispatch(
editGlobalParamAction.get({
id,
paramRequest: { ...paramRequest, share_across_spaces: shareAcrossSpaces },
paramRequest,
})
);
} else {
dispatch(
addNewGlobalParamAction.get({
...paramRequest,
...newParamData,
share_across_spaces: shareAcrossSpaces,
})
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,11 @@
*/
import React from 'react';
import { ALL_SPACES_ID } from '@kbn/security-plugin/public';
import {
EuiCheckbox,
EuiComboBox,
EuiFieldText,
EuiForm,
EuiFormRow,
EuiTextArea,
} from '@elastic/eui';
import { EuiCheckbox, EuiComboBox, EuiFieldText, EuiForm, EuiFormRow } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { Controller, useFormContext, useFormState } from 'react-hook-form';
import { OptionalText } from '../components/optional_text';
import { ParamValueField } from './param_value_field';
import { SyntheticsParams } from '../../../../../../common/runtime_types';
import { ListParamItem } from './params_list';

Expand Down Expand Up @@ -61,25 +56,8 @@ export const AddParamForm = ({
})}
/>
</EuiFormRow>
<EuiFormRow
fullWidth
label={VALUE_LABEL}
isInvalid={Boolean(errors?.value)}
error={errors?.value?.message}
>
<EuiTextArea
data-test-subj="syntheticsAddParamFormTextArea"
fullWidth
aria-label={VALUE_LABEL}
{...register('value', {
required: {
value: true,
message: VALUE_REQUIRED,
},
})}
/>
</EuiFormRow>
<EuiFormRow fullWidth label={TAGS_LABEL}>
<ParamValueField isEditingItem={isEditingItem} />
<EuiFormRow fullWidth label={TAGS_LABEL} labelAppend={<OptionalText />}>
<Controller
control={control}
name="tags"
Expand All @@ -102,7 +80,7 @@ export const AddParamForm = ({
)}
/>
</EuiFormRow>
<EuiFormRow fullWidth label={DESCRIPTION_LABEL}>
<EuiFormRow fullWidth label={DESCRIPTION_LABEL} labelAppend={<OptionalText />}>
<EuiFieldText
data-test-subj="syntheticsAddParamFormFieldText"
fullWidth
Expand Down Expand Up @@ -173,6 +151,6 @@ const KEY_EXISTS = i18n.translate('xpack.synthetics.monitorManagement.param.keyE
defaultMessage: 'Key already exists',
});

const VALUE_REQUIRED = i18n.translate('xpack.synthetics.monitorManagement.value.required', {
export const VALUE_REQUIRED = i18n.translate('xpack.synthetics.monitorManagement.value.required', {
defaultMessage: 'Value is required',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { EuiCallOut, EuiFormRow, EuiSpacer, EuiTextArea } from '@elastic/eui';
import React from 'react';
import { useFormContext, useFormState } from 'react-hook-form';
import { i18n } from '@kbn/i18n';
import { OptionalText } from '../components/optional_text';
import { ListParamItem } from './params_list';
import { SyntheticsParams } from '../../../../../../common/runtime_types';
import { VALUE_LABEL, VALUE_REQUIRED } from './add_param_form';

export const ParamValueField = ({ isEditingItem }: { isEditingItem: ListParamItem | null }) => {
const { register } = useFormContext<SyntheticsParams>();
const { errors } = useFormState<SyntheticsParams>();

if (isEditingItem) {
return (
<>
<EuiFormRow
fullWidth
label={NEW_VALUE_LABEL}
isInvalid={Boolean(errors?.value)}
error={errors?.value?.message}
labelAppend={<OptionalText />}
>
<EuiTextArea
data-test-subj="syntheticsAddParamFormTextArea"
fullWidth
aria-label={NEW_VALUE_LABEL}
{...register('value')}
/>
</EuiFormRow>
<EuiSpacer size="xs" />
<EuiCallOut
size="s"
title={i18n.translate('xpack.synthetics.paramValueField.euiCallOut.newValue', {
defaultMessage:
'Assign a new value to update this parameter, or leave blank to keep the current value.',
})}
iconType="iInCircle"
/>
</>
);
}

return (
<EuiFormRow
fullWidth
label={VALUE_LABEL}
isInvalid={Boolean(errors?.value)}
error={errors?.value?.message}
>
<EuiTextArea
data-test-subj="syntheticsAddParamFormTextArea"
fullWidth
aria-label={VALUE_LABEL}
{...register('value', {
required: {
value: true,
message: VALUE_REQUIRED,
},
})}
/>
</EuiFormRow>
);
};

export const NEW_VALUE_LABEL = i18n.translate(
'xpack.synthetics.monitorManagement.paramForm.newValue',
{
defaultMessage: 'New value',
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

import { isEmpty } from 'lodash';
import { INITIAL_REST_VERSION, SYNTHETICS_API_URLS } from '../../../../../common/constants';
import {
DeleteParamsResponse,
Expand Down Expand Up @@ -35,16 +36,22 @@ export const editGlobalParam = async ({
id,
}: {
id: string;
paramRequest: SyntheticsParamRequest;
}): Promise<SyntheticsParams> =>
apiService.put<SyntheticsParams>(
paramRequest: Partial<SyntheticsParamRequest>;
}): Promise<SyntheticsParams> => {
const data = paramRequest;
if (isEmpty(paramRequest.value)) {
// omit empty value
delete data.value;
}
return await apiService.put<SyntheticsParams>(
SYNTHETICS_API_URLS.PARAMS + `/${id}`,
paramRequest,
data,
SyntheticsParamsCodec,
{
version: INITIAL_REST_VERSION,
}
);
};

export const deleteGlobalParams = async (ids: string[]): Promise<DeleteParamsResponse[]> =>
apiService.delete(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { schema, TypeOf } from '@kbn/config-schema';
import { SavedObjectsFindResponse } from '@kbn/core/server';
import { isEmpty } from 'lodash';
import { escapeQuotes } from '@kbn/es-query';
import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common';
import { RouteContext } from './types';
import { MonitorSortFieldSchema } from '../../common/runtime_types/monitor_management/sort_field';
import { getAllLocations } from '../synthetics_service/get_all_locations';
Expand Down Expand Up @@ -269,3 +270,26 @@ function parseMappingKey(key: string | undefined) {
return key;
}
}

export const validateRouteSpaceName = async (routeContext: RouteContext) => {
const { spaceId, server, request, response } = routeContext;
if (spaceId === DEFAULT_SPACE_ID) {
// default space is always valid
return { spaceId: DEFAULT_SPACE_ID };
}

try {
await server.spaces?.spacesService.getActiveSpace(request);
} catch (error) {
if (error.output?.statusCode === 404) {
return {
spaceId,
invalidResponse: response.notFound({
body: { message: `Kibana space '${spaceId}' does not exist` },
}),
};
}
}

return { invalidResponse: undefined };
};
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ import { syntheticsParamType } from '../../../../common/types/saved_objects';
import { SYNTHETICS_API_URLS } from '../../../../common/constants';

const ParamsObjectSchema = schema.object({
key: schema.string(),
value: schema.string(),
key: schema.string({
minLength: 1,
}),
value: schema.string({
minLength: 1,
}),
description: schema.maybe(schema.string()),
tags: schema.maybe(schema.arrayOf(schema.string())),
share_across_spaces: schema.maybe(schema.boolean()),
Expand Down
Loading

0 comments on commit 4c22558

Please sign in to comment.