Skip to content

Commit cc0a974

Browse files
committed
Merge remote-tracking branch 'upstream/master' into markdown-eslint-fixes
2 parents b2a4a38 + d8f94b1 commit cc0a974

10 files changed

Lines changed: 169 additions & 10 deletions

File tree

src/core/server/http/integration_tests/router.test.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,61 @@ describe('Handler', () => {
142142
statusCode: 400,
143143
});
144144
});
145+
146+
it('accept to receive an array payload', async () => {
147+
const { server: innerServer, createRouter } = await server.setup(setupDeps);
148+
const router = createRouter('/');
149+
150+
let body: any = null;
151+
router.post(
152+
{
153+
path: '/',
154+
validate: {
155+
body: schema.arrayOf(schema.object({ foo: schema.string() })),
156+
},
157+
},
158+
(context, req, res) => {
159+
body = req.body;
160+
return res.ok({ body: 'ok' });
161+
}
162+
);
163+
await server.start();
164+
165+
await supertest(innerServer.listener)
166+
.post('/')
167+
.send([{ foo: 'bar' }, { foo: 'dolly' }])
168+
.expect(200);
169+
170+
expect(body).toEqual([{ foo: 'bar' }, { foo: 'dolly' }]);
171+
});
172+
173+
it('accept to receive a json primitive payload', async () => {
174+
const { server: innerServer, createRouter } = await server.setup(setupDeps);
175+
const router = createRouter('/');
176+
177+
let body: any = null;
178+
router.post(
179+
{
180+
path: '/',
181+
validate: {
182+
body: schema.number(),
183+
},
184+
},
185+
(context, req, res) => {
186+
body = req.body;
187+
return res.ok({ body: 'ok' });
188+
}
189+
);
190+
await server.start();
191+
192+
await supertest(innerServer.listener)
193+
.post('/')
194+
.type('json')
195+
.send('12')
196+
.expect(200);
197+
198+
expect(body).toEqual(12);
199+
});
145200
});
146201

147202
describe('handleLegacyErrors', () => {

src/core/server/http/router/validator/validator.test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,62 @@ describe('Router validator', () => {
132132
'The validation rule provided in the handler is not valid'
133133
);
134134
});
135+
136+
it('should validate and infer type when data is an array', () => {
137+
expect(
138+
RouteValidator.from({
139+
body: schema.arrayOf(schema.string()),
140+
}).getBody(['foo', 'bar'])
141+
).toStrictEqual(['foo', 'bar']);
142+
expect(
143+
RouteValidator.from({
144+
body: schema.arrayOf(schema.number()),
145+
}).getBody([1, 2, 3])
146+
).toStrictEqual([1, 2, 3]);
147+
expect(
148+
RouteValidator.from({
149+
body: schema.arrayOf(schema.object({ foo: schema.string() })),
150+
}).getBody([{ foo: 'bar' }, { foo: 'dolly' }])
151+
).toStrictEqual([{ foo: 'bar' }, { foo: 'dolly' }]);
152+
153+
expect(() =>
154+
RouteValidator.from({
155+
body: schema.arrayOf(schema.number()),
156+
}).getBody(['foo', 'bar', 'dolly'])
157+
).toThrowError('[0]: expected value of type [number] but got [string]');
158+
expect(() =>
159+
RouteValidator.from({
160+
body: schema.arrayOf(schema.number()),
161+
}).getBody({ foo: 'bar' })
162+
).toThrowError('expected value of type [array] but got [Object]');
163+
});
164+
165+
it('should validate and infer type when data is a primitive', () => {
166+
expect(
167+
RouteValidator.from({
168+
body: schema.string(),
169+
}).getBody('foobar')
170+
).toStrictEqual('foobar');
171+
expect(
172+
RouteValidator.from({
173+
body: schema.number(),
174+
}).getBody(42)
175+
).toStrictEqual(42);
176+
expect(
177+
RouteValidator.from({
178+
body: schema.boolean(),
179+
}).getBody(true)
180+
).toStrictEqual(true);
181+
182+
expect(() =>
183+
RouteValidator.from({
184+
body: schema.string(),
185+
}).getBody({ foo: 'bar' })
186+
).toThrowError('expected value of type [string] but got [Object]');
187+
expect(() =>
188+
RouteValidator.from({
189+
body: schema.number(),
190+
}).getBody('foobar')
191+
).toThrowError('expected value of type [number] but got [string]');
192+
});
135193
});

src/core/server/http/router/validator/validator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ export class RouteValidator<P = {}, Q = {}, B = {}> {
274274
// if options.body.output === 'stream'
275275
return schema.stream();
276276
} else {
277-
return schema.maybe(schema.nullable(schema.object({}, { allowUnknowns: true })));
277+
return schema.maybe(schema.nullable(schema.any({})));
278278
}
279279
}
280280
}

src/legacy/core_plugins/vis_type_table/public/agg_table/agg_table.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,11 @@ export function KbnAggTable(config, RecursionHelper) {
7474
// escape each cell in each row
7575
const csvRows = rows.map(function(row) {
7676
return Object.entries(row).map(([k, v]) => {
77-
return escape(formatted ? columns.find(c => c.id === k).formatter.convert(v) : v);
77+
const column = columns.find(c => c.id === k);
78+
if (formatted && column) {
79+
return escape(column.formatter.convert(v));
80+
}
81+
return escape(v);
7882
});
7983
});
8084

@@ -110,12 +114,16 @@ export function KbnAggTable(config, RecursionHelper) {
110114

111115
if (typeof $scope.dimensions === 'undefined') return;
112116

113-
const { buckets, metrics } = $scope.dimensions;
117+
const { buckets, metrics, splitColumn } = $scope.dimensions;
114118

115119
$scope.formattedColumns = table.columns
116120
.map(function(col, i) {
117121
const isBucket = buckets.find(bucket => bucket.accessor === i);
118-
const dimension = isBucket || metrics.find(metric => metric.accessor === i);
122+
const isSplitColumn = splitColumn
123+
? splitColumn.find(splitColumn => splitColumn.accessor === i)
124+
: undefined;
125+
const dimension =
126+
isBucket || isSplitColumn || metrics.find(metric => metric.accessor === i);
119127

120128
if (!dimension) return;
121129

x-pack/legacy/plugins/watcher/__jest__/client_integration/helpers/watch_create_threshold.helpers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,5 @@ export type TestSubjects =
104104
| 'webhookPathInput'
105105
| 'webhookPortInput'
106106
| 'webhookMethodSelect'
107+
| 'webhookSchemeSelect'
107108
| 'webhookUsernameInput';

x-pack/legacy/plugins/watcher/__jest__/client_integration/watch_create_threshold.test.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,7 @@ describe('<ThresholdWatchEdit /> create route', () => {
487487
const METHOD = 'put';
488488
const HOST = 'localhost';
489489
const PORT = '9200';
490+
const SCHEME = 'http';
490491
const PATH = '/test';
491492
const USERNAME = 'test_user';
492493
const PASSWORD = 'test_password';
@@ -510,6 +511,7 @@ describe('<ThresholdWatchEdit /> create route', () => {
510511
form.setInputValue('webhookMethodSelect', METHOD);
511512
form.setInputValue('webhookHostInput', HOST);
512513
form.setInputValue('webhookPortInput', PORT);
514+
form.setInputValue('webhookSchemeSelect', SCHEME);
513515
form.setInputValue('webhookPathInput', PATH);
514516
form.setInputValue('webhookUsernameInput', USERNAME);
515517
form.setInputValue('webhookPasswordInput', PASSWORD);
@@ -534,6 +536,7 @@ describe('<ThresholdWatchEdit /> create route', () => {
534536
method: METHOD,
535537
host: HOST,
536538
port: Number(PORT),
539+
scheme: SCHEME,
537540
path: PATH,
538541
body:
539542
'{\n "message": "Watch [{{ctx.metadata.name}}] has exceeded the threshold"\n}', // Default

x-pack/legacy/plugins/watcher/common/models/action/webhook_action.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export class WebhookAction extends BaseAction {
1616
this.method = props.method;
1717
this.host = props.host;
1818
this.port = props.port;
19+
this.scheme = props.scheme;
1920
this.path = props.path;
2021
this.body = props.body;
2122
this.contentType = props.contentType;
@@ -30,6 +31,7 @@ export class WebhookAction extends BaseAction {
3031
method: this.method,
3132
host: this.host,
3233
port: this.port,
34+
scheme: this.scheme,
3335
path: this.path,
3436
body: this.body,
3537
contentType: this.contentType,
@@ -47,6 +49,7 @@ export class WebhookAction extends BaseAction {
4749
method: json.method,
4850
host: json.host,
4951
port: json.port,
52+
scheme: json.scheme,
5053
path: json.path,
5154
body: json.body,
5255
contentType: json.contentType,
@@ -72,6 +75,10 @@ export class WebhookAction extends BaseAction {
7275
optionalFields.method = this.method;
7376
}
7477

78+
if (this.scheme) {
79+
optionalFields.scheme = this.scheme;
80+
}
81+
7582
if (this.body) {
7683
optionalFields.body = this.body;
7784
}
@@ -108,7 +115,7 @@ export class WebhookAction extends BaseAction {
108115
const webhookJson = json && json.actionJson && json.actionJson.webhook;
109116
const { errors } = this.validateJson(json.actionJson);
110117

111-
const { path, method, body, auth, headers } = webhookJson;
118+
const { path, method, scheme, body, auth, headers } = webhookJson;
112119

113120
const optionalFields = {};
114121

@@ -120,6 +127,10 @@ export class WebhookAction extends BaseAction {
120127
optionalFields.method = method;
121128
}
122129

130+
if (scheme) {
131+
optionalFields.scheme = scheme;
132+
}
133+
123134
if (body) {
124135
optionalFields.body = body;
125136
}

x-pack/legacy/plugins/watcher/common/types/action_types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export interface WebhookAction extends BaseAction {
5656
method?: 'head' | 'get' | 'post' | 'put' | 'delete';
5757
host: string;
5858
port: number;
59+
scheme?: 'http' | 'https';
5960
path?: string;
6061
body?: string;
6162
username?: string;

x-pack/legacy/plugins/watcher/public/np_ready/application/models/action/webhook_action.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,21 @@ import { i18n } from '@kbn/i18n';
1111
export class WebhookAction extends BaseAction {
1212
constructor(props = {}) {
1313
super(props);
14-
1514
const defaultJson = JSON.stringify(
1615
{ message: 'Watch [{{ctx.metadata.name}}] has exceeded the threshold' },
1716
null,
1817
2
1918
);
2019
this.body = get(props, 'body', props.ignoreDefaults ? null : defaultJson);
21-
2220
this.method = get(props, 'method');
2321
this.host = get(props, 'host');
2422
this.port = get(props, 'port');
23+
this.scheme = get(props, 'scheme', 'http');
2524
this.path = get(props, 'path');
2625
this.username = get(props, 'username');
2726
this.password = get(props, 'password');
2827
this.contentType = get(props, 'contentType');
29-
30-
this.fullPath = `${this.host}:${this.port}${this.path}`;
28+
this.fullPath = `${this.host}:${this.port}${this.path ? '/' + this.path : ''}`;
3129
}
3230

3331
validate() {
@@ -112,6 +110,7 @@ export class WebhookAction extends BaseAction {
112110
method: this.method,
113111
host: this.host,
114112
port: this.port,
113+
scheme: this.scheme,
115114
path: this.path,
116115
body: this.body,
117116
username: this.username,

x-pack/legacy/plugins/watcher/public/np_ready/application/sections/watch_edit/components/threshold_watch_edit/action_fields/webhook_action_fields.tsx

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@ interface Props {
2929

3030
const HTTP_VERBS = ['head', 'get', 'post', 'put', 'delete'];
3131

32+
const SCHEME = ['http', 'https'];
33+
3234
export const WebhookActionFields: React.FunctionComponent<Props> = ({
3335
action,
3436
editAction,
3537
errors,
3638
hasErrors,
3739
}) => {
38-
const { method, host, port, path, body, username, password } = action;
40+
const { method, host, port, scheme, path, body, username, password } = action;
3941

4042
useEffect(() => {
4143
editAction({ key: 'contentType', value: 'application/json' }); // set content-type for threshold watch to json by default
@@ -65,6 +67,27 @@ export const WebhookActionFields: React.FunctionComponent<Props> = ({
6567
</EuiFormRow>
6668
</EuiFlexItem>
6769

70+
<EuiFlexItem>
71+
<EuiFormRow
72+
label={i18n.translate(
73+
'xpack.watcher.sections.watchEdit.threshold.webhookAction.schemeFieldLabel',
74+
{
75+
defaultMessage: 'Scheme',
76+
}
77+
)}
78+
>
79+
<EuiSelect
80+
name="scheme"
81+
value={scheme}
82+
data-test-subj="webhookSchemeSelect"
83+
options={SCHEME.map(verb => ({ text: verb, value: verb }))}
84+
onChange={e => {
85+
editAction({ key: 'scheme', value: e.target.value });
86+
}}
87+
/>
88+
</EuiFormRow>
89+
</EuiFlexItem>
90+
6891
<EuiFlexItem>
6992
<ErrableFormRow
7093
id="webhookHost"

0 commit comments

Comments
 (0)