Skip to content

Commit 21fb651

Browse files
committed
Return number of policies from data source, surface in assign data source UI
1 parent 566bbb0 commit 21fb651

File tree

5 files changed

+166
-77
lines changed

5 files changed

+166
-77
lines changed

x-pack/legacy/plugins/fleet/public/pages/policy_details/components/assign_datasources.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ export const AssignDatasourcesFlyout: React.FC<Props> = ({
176176
<EuiFlyoutBody>
177177
<DatasourcesTable
178178
datasources={datasources}
179+
withPoliciesCount={true}
179180
loading={isDatasourcesLoading}
180181
message={getTableMessage()}
181182
search={{
@@ -184,6 +185,19 @@ export const AssignDatasourcesFlyout: React.FC<Props> = ({
184185
incremental: true,
185186
schema: true,
186187
},
188+
filters: [
189+
{
190+
type: 'field_value_toggle',
191+
field: 'policies',
192+
value: 0,
193+
name: (
194+
<FormattedMessage
195+
id="xpack.fleet.assignDatasources.unassignedFilterButtonLabel"
196+
defaultMessage="Unassigned"
197+
/>
198+
),
199+
},
200+
],
187201
}}
188202
selection={{
189203
onSelectionChange: (selection: Datasource[]) =>

x-pack/legacy/plugins/fleet/public/pages/policy_details/components/datasources_table.tsx

Lines changed: 85 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,21 @@
66
import React from 'react';
77
import { i18n } from '@kbn/i18n';
88
import { FormattedMessage } from '@kbn/i18n/react';
9-
import { EuiInMemoryTable, EuiInMemoryTableProps, EuiLink } from '@elastic/eui';
9+
import { EuiInMemoryTable, EuiInMemoryTableProps, EuiLink, EuiBadge } from '@elastic/eui';
1010
import { Datasource } from '../../../../common/types/domain_data';
1111
import { useLibs } from '../../../hooks';
1212

1313
interface Props extends EuiInMemoryTableProps {
14-
datasources?: Datasource[];
14+
datasources?: Array<Datasource & { policies?: string[] }>;
15+
withPoliciesCount?: boolean;
1516
}
1617

17-
export const DatasourcesTable: React.FC<Props> = ({
18-
datasources: originalDatasources,
19-
...rest
20-
}) => {
18+
export const DatasourcesTable: React.FC<Props> = (
19+
{ datasources: originalDatasources, withPoliciesCount, ...rest } = {
20+
datasources: [],
21+
withPoliciesCount: false,
22+
}
23+
) => {
2124
const { framework } = useLibs();
2225

2326
// Flatten some values so that they can be searched via in-memory table search
@@ -32,6 +35,7 @@ export const DatasourcesTable: React.FC<Props> = ({
3235
version: packageVersion,
3336
description: packageDescription,
3437
},
38+
policies,
3539
}) => ({
3640
id,
3741
name,
@@ -40,73 +44,88 @@ export const DatasourcesTable: React.FC<Props> = ({
4044
packageTitle,
4145
packageVersion,
4246
packageDescription,
47+
policies: policies?.length || 0,
4348
})
4449
);
4550

51+
const columns: EuiInMemoryTableProps['columns'] = [
52+
{
53+
field: 'name',
54+
name: i18n.translate('xpack.fleet.policyDetails.datasourcesTable.nameColumnTitle', {
55+
defaultMessage: 'Name',
56+
}),
57+
},
58+
{
59+
field: 'packageTitle',
60+
name: i18n.translate('xpack.fleet.policyDetails.datasourcesTable.packageNameColumnTitle', {
61+
defaultMessage: 'Package',
62+
}),
63+
},
64+
{
65+
field: 'packageVersion',
66+
name: i18n.translate('xpack.fleet.policyDetails.datasourcesTable.packageVersionColumnTitle', {
67+
defaultMessage: 'Version',
68+
}),
69+
},
70+
{
71+
field: 'streams',
72+
name: i18n.translate('xpack.fleet.policyDetails.datasourcesTable.streamsCountColumnTitle', {
73+
defaultMessage: 'Streams',
74+
}),
75+
},
76+
{
77+
name: i18n.translate('xpack.fleet.policyDetails.datasourcesTable.actionsColumnTitle', {
78+
defaultMessage: 'Actions',
79+
}),
80+
actions: [
81+
{
82+
render: ({ packageName, packageVersion }: any) => {
83+
return (
84+
<EuiLink
85+
color="primary"
86+
external
87+
target="_blank"
88+
href={`${window.location.origin}${framework.info.basePath}/app/epm#/detail/${packageName}-${packageVersion}`}
89+
>
90+
<FormattedMessage
91+
id="xpack.fleet.policyDetails.datasourcesTable.viewActionLinkText"
92+
defaultMessage="view"
93+
/>
94+
</EuiLink>
95+
);
96+
},
97+
},
98+
],
99+
width: '100px',
100+
},
101+
];
102+
103+
if (withPoliciesCount) {
104+
columns.splice(columns.length - 1, 0, {
105+
field: 'policies',
106+
name: i18n.translate('xpack.fleet.policyDetails.datasourcesTable.policiesColumnTitle', {
107+
defaultMessage: 'Policies',
108+
}),
109+
render: (policies: number) => {
110+
return policies === 0 ? (
111+
<EuiBadge>
112+
<FormattedMessage
113+
id="xpack.fleet.policyDetails.datasourcesTable.unassignedLabelText"
114+
defaultMessage="Unassigned"
115+
/>
116+
</EuiBadge>
117+
) : (
118+
policies
119+
);
120+
},
121+
});
122+
}
123+
46124
return (
47125
<EuiInMemoryTable
48126
itemId="id"
49127
items={datasources}
50-
columns={[
51-
{
52-
field: 'name',
53-
name: i18n.translate('xpack.fleet.policyDetails.datasourcesTable.ameColumnTitle', {
54-
defaultMessage: 'Name',
55-
}),
56-
},
57-
{
58-
field: 'packageTitle',
59-
name: i18n.translate(
60-
'xpack.fleet.policyDetails.datasourcesTable.packageNameColumnTitle',
61-
{
62-
defaultMessage: 'Package',
63-
}
64-
),
65-
},
66-
{
67-
field: 'packageVersion',
68-
name: i18n.translate(
69-
'xpack.fleet.policyDetails.datasourcesTable.packageVersionColumnTitle',
70-
{
71-
defaultMessage: 'Version',
72-
}
73-
),
74-
},
75-
{
76-
field: 'streams',
77-
name: i18n.translate(
78-
'xpack.fleet.policyDetails.datasourcesTable.streamsCountColumnTitle',
79-
{
80-
defaultMessage: 'Streams',
81-
}
82-
),
83-
},
84-
{
85-
name: i18n.translate('xpack.fleet.policyDetails.datasourcesTable.actionsColumnTitle', {
86-
defaultMessage: 'Actions',
87-
}),
88-
actions: [
89-
{
90-
render: ({ packageName, packageVersion }: any) => {
91-
return (
92-
<EuiLink
93-
color="primary"
94-
external
95-
target="_blank"
96-
href={`${window.location.origin}${framework.info.basePath}/app/epm#/detail/${packageName}-${packageVersion}`}
97-
>
98-
<FormattedMessage
99-
id="xpack.fleet.policyDetails.datasourcesTable.viewActionLinkText"
100-
defaultMessage="view"
101-
/>
102-
</EuiLink>
103-
);
104-
},
105-
},
106-
],
107-
width: '100px',
108-
},
109-
]}
128+
columns={columns}
110129
sorting={{
111130
field: 'name',
112131
direction: 'asc',

x-pack/legacy/plugins/ingest/server/libs/policy.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,25 +82,40 @@ export class PolicyLib {
8282
kuery?: string;
8383
page?: number;
8484
perPage?: number;
85+
withDatasources?: boolean;
8586
} = {
8687
page: 1,
8788
perPage: 20,
89+
withDatasources: true,
8890
}
8991
): Promise<{ items: Policy[]; total: number; page: number; perPage: number }> {
9092
const response = await this.adapter.list(user, options);
9193

92-
const dataSourcesIds = unique(flatten(response.items.map(policy => policy.datasources || [])));
93-
94-
const datasources: Datasource[] = await this.libs.datasources.getByIDs(user, dataSourcesIds);
94+
if (options.withDatasources) {
95+
const dataSourcesIds = unique(
96+
flatten(response.items.map(policy => policy.datasources || []))
97+
);
98+
const datasources: Datasource[] = await this.libs.datasources.getByIDs(user, dataSourcesIds);
99+
100+
return {
101+
...response,
102+
items: response.items.map(policy => {
103+
return {
104+
...policy,
105+
datasources: (policy.datasources || []).map(id => {
106+
return datasources.find(ds => ds.id === id);
107+
}),
108+
} as Policy;
109+
}),
110+
};
111+
}
95112

96113
return {
97114
...response,
98115
items: response.items.map(policy => {
99116
return {
100117
...policy,
101-
datasources: (policy.datasources || []).map(id => {
102-
return datasources.find(ds => ds.id === id);
103-
}),
118+
datasources: undefined,
104119
} as Policy;
105120
}),
106121
};

x-pack/legacy/plugins/ingest/server/rest_api/datasource/index.ts

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,25 @@ export const createGETDatasourceRoute = (libs: ServerLibs) => ({
3535
config: {},
3636
handler: (async (
3737
request: FrameworkRequest<{ params: { datasourceId: string } }>
38-
): Promise<ReturnTypeGet<any>> => {
38+
): Promise<ReturnTypeGet<(Datasource & { policies: string[] }) | null>> => {
3939
const datasource = await libs.datasources.get(request.user, request.params.datasourceId);
40-
41-
return { item: datasource, success: true };
40+
if (datasource) {
41+
const policies = await libs.policy.list(request.user, {
42+
kuery: `policies.datasources:"${datasource.id}"`,
43+
page: 1,
44+
perPage: 10000,
45+
withDatasources: false,
46+
});
47+
return {
48+
item: {
49+
...datasource,
50+
policies: policies.items.map(p => p.id),
51+
},
52+
success: true,
53+
};
54+
} else {
55+
return { item: null, success: false };
56+
}
4257
}) as FrameworkRouteHandler,
4358
});
4459

@@ -56,21 +71,46 @@ export const createGETDatasourcesRoute = (libs: ServerLibs) => ({
5671
},
5772
},
5873
},
59-
handler: async (request: FrameworkRequest<any>): Promise<ReturnTypeList<Datasource>> => {
74+
handler: async (
75+
request: FrameworkRequest<any>
76+
): Promise<ReturnTypeList<Datasource & { policies: string[] }>> => {
6077
// TODO fix for types that broke in TS 3.7
6178
const query: {
6279
page: string;
6380
perPage: string;
6481
kuery: string;
6582
showInactive: string;
6683
} = request.query as any;
84+
6785
const { items, total, page, perPage } = await libs.datasources.list(request.user, {
6886
page: parseInt(query.page, 10),
6987
perPage: parseInt(query.perPage, 10),
7088
kuery: query.kuery,
7189
});
7290

73-
return { list: items, success: true, total, page, perPage };
91+
const list: Array<Datasource & { policies: string[] }> = [];
92+
93+
// TODO: this could be optimized so that it is not sequentially blocking
94+
for (const ds of items) {
95+
const policies = await libs.policy.list(request.user, {
96+
kuery: `policies.datasources:"${ds.id}"`,
97+
page: 1,
98+
perPage: 10000,
99+
withDatasources: false,
100+
});
101+
list.push({
102+
...ds,
103+
policies: policies.items.map(p => p.id),
104+
});
105+
}
106+
107+
return {
108+
list,
109+
success: true,
110+
total,
111+
page,
112+
perPage,
113+
};
74114
},
75115
});
76116

x-pack/legacy/plugins/ingest/server/rest_api/policy/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export const createGETPoliciesRoute = (libs: ServerLibs) => ({
6767
page: parseInt(query.page, 10),
6868
perPage: parseInt(query.perPage, 10),
6969
kuery: query.kuery,
70+
withDatasources: true,
7071
});
7172

7273
return { list: items, success: true, total, page, perPage };

0 commit comments

Comments
 (0)