-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Endpoint] Policy List UI route and initial view #56918
Changes from 3 commits
7b91e2f
4822fd2
91db958
9e29674
9a45a8c
5cc2f9d
ad57e4c
515099e
c2f1769
ab82e1d
e656b0c
e3675c1
01a5e2e
8c66c60
a735e16
c04f61f
1cb9d2c
8e18b5a
0492ff9
f296fd5
ee6aa46
438cb77
5d09b57
da416d4
d7c9ea4
a1b5a77
cd5488d
5d276d1
78bc8b4
8812f32
31676c0
13920fd
2d58030
546a193
b14f88a
15193b1
1fc8d65
04974e1
adfa203
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
interface ServerReturnedPolicyListData { | ||
type: 'serverReturnedPolicyListData'; | ||
payload: { | ||
policyItems: object[]; | ||
// tbd... | ||
}; | ||
} | ||
|
||
interface UserPaginatedPolicyListTable { | ||
type: 'userPaginatedPolicyListTable'; | ||
payload: { | ||
pageSize: number; | ||
pageIndex: number; | ||
}; | ||
} | ||
|
||
export type PolicyListAction = ServerReturnedPolicyListData | UserPaginatedPolicyListTable; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
export { policyListReducer } from './reducer'; | ||
export { PolicyListAction } from './action'; | ||
export { policyListMiddlewareFactory } from './middleware'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
import { MiddlewareFactory } from '../../types'; | ||
|
||
export const policyListMiddlewareFactory: MiddlewareFactory = coreStart => { | ||
return ({ getState, dispatch }) => next => async action => { | ||
next(action); | ||
|
||
if ( | ||
(action.type === 'userNavigatedToPage' && action.payload === 'policyListPage') || | ||
action.type === 'userPaginatedPolicyListTable' | ||
) { | ||
// load data from API | ||
// Refactor tracked via: https://github.com/elastic/endpoint-app-team/issues/150 | ||
} | ||
}; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
import { Reducer } from 'redux'; | ||
import { PolicyListState } from '../../types'; | ||
import { AppAction } from '../action'; | ||
|
||
const initialPolicyListState = (): PolicyListState => { | ||
return { | ||
policyItems: [], | ||
pageIndex: 0, | ||
pageSize: 0, | ||
total: 0, | ||
}; | ||
}; | ||
|
||
export const policyListReducer: Reducer<PolicyListState, AppAction> = ( | ||
state = initialPolicyListState(), | ||
action | ||
) => { | ||
if (action.type === 'serverReturnedPolicyListData') { | ||
return { | ||
...state, | ||
policyItems: action.payload.policyItems, | ||
}; | ||
} | ||
|
||
if (action.type === 'userPaginatedPolicyListTable') { | ||
return { | ||
...state, | ||
...action.payload, | ||
}; | ||
} | ||
|
||
if (action.type === 'userNavigatedFromPage' && action.payload === 'policyListPage') { | ||
return initialPolicyListState(); | ||
} | ||
|
||
return state; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
import { PolicyListState } from '../../types'; | ||
|
||
export const selectPolicyItems = (state: PolicyListState) => state.policyItems; | ||
|
||
export const selectPageIndex = (state: PolicyListState) => state.pageIndex; | ||
|
||
export const selectPageSize = (state: PolicyListState) => state.pageSize; | ||
|
||
export const selectTotal = (state: PolicyListState) => state.total; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,4 +11,9 @@ interface UserNavigatedToPage { | |
readonly payload: PageId; | ||
} | ||
|
||
export type RoutingAction = UserNavigatedToPage; | ||
interface UserNavigatedFromPage { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @peluja1012 would like your feedback here if you get a chance. I added this Routing action, which is dispatched when the component that used There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is good. Though in our next PR we are adding a "routing" middleware, which keeps track of url changes. In the alerts page, we removed |
||
readonly type: 'userNavigatedFromPage'; | ||
readonly payload: PageId; | ||
} | ||
|
||
export type RoutingAction = UserNavigatedToPage | UserNavigatedFromPage; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
export * from './policy_list'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
import { useSelector } from 'react-redux'; | ||
import { GlobalState, PolicyListState } from '../../types'; | ||
|
||
export function usePolicyListSelector<TSelected>(selector: (state: PolicyListState) => TSelected) { | ||
return useSelector((state: GlobalState) => selector(state.policyList)); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
import React, { useCallback, useMemo } from 'react'; | ||
import { | ||
EuiPage, | ||
EuiPageBody, | ||
EuiPageContent, | ||
EuiPageContentBody, | ||
EuiPageContentHeader, | ||
EuiPageContentHeaderSection, | ||
EuiTitle, | ||
EuiBasicTable, | ||
} from '@elastic/eui'; | ||
import { i18n } from '@kbn/i18n'; | ||
import { FormattedMessage } from '@kbn/i18n/react'; | ||
import { useDispatch } from 'react-redux'; | ||
import { usePageId } from '../use_page_id'; | ||
import { | ||
selectPageIndex, | ||
selectPageSize, | ||
selectPolicyItems, | ||
selectTotal, | ||
} from '../../store/policy_list/selectors'; | ||
import { usePolicyListSelector } from './policy_hooks'; | ||
import { PolicyListAction } from '../../store/policy_list'; | ||
|
||
interface TTableChangeCallbackArguments { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I kind of like that some types initial letter alludes the type. When I'm I will rename it to remove the initial |
||
page: { index: number; size: number }; | ||
} | ||
|
||
export const PolicyList = React.memo(() => { | ||
usePageId('policyListPage'); | ||
|
||
const dispatch = useDispatch<(action: PolicyListAction) => void>(); | ||
const policyItems = usePolicyListSelector(selectPolicyItems); | ||
const pageIndex = usePolicyListSelector(selectPageIndex); | ||
const pageSize = usePolicyListSelector(selectPageSize); | ||
const totalItemCount = usePolicyListSelector(selectTotal); | ||
const loading = true; | ||
|
||
const paginationSetup = useMemo(() => { | ||
return { | ||
pageIndex, | ||
pageSize, | ||
totalItemCount, | ||
pageSizeOptions: [10, 20, 50], | ||
hidePerPageOptions: false, | ||
}; | ||
}, [pageIndex, pageSize, totalItemCount]); | ||
|
||
const handleTableChange = useCallback( | ||
({ page: { index, size } }: TTableChangeCallbackArguments) => { | ||
dispatch({ | ||
type: 'userPaginatedPolicyListTable', | ||
payload: { | ||
pageIndex: index, | ||
pageSize: size, | ||
}, | ||
}); | ||
}, | ||
[dispatch] | ||
); | ||
|
||
const columns = useMemo( | ||
() => [ | ||
{ | ||
field: 'name', | ||
name: i18n.translate('xpack.endpoint.policyList.nameField', { | ||
defaultMessage: 'Policy Name', | ||
}), | ||
}, | ||
{ | ||
field: 'total', | ||
name: i18n.translate('xpack.endpoint.policyList.totalField', { | ||
defaultMessage: 'Total', | ||
}), | ||
}, | ||
{ | ||
field: 'pending', | ||
name: i18n.translate('xpack.endpoint.policyList.pendingField', { | ||
defaultMessage: 'Pending', | ||
}), | ||
}, | ||
{ | ||
field: 'Failed', | ||
name: i18n.translate('xpack.endpoint.policyList.failedField', { | ||
defaultMessage: 'Failed', | ||
}), | ||
}, | ||
{ | ||
field: 'created_by', | ||
name: i18n.translate('xpack.endpoint.policyList.createdByField', { | ||
defaultMessage: 'Created By', | ||
}), | ||
}, | ||
{ | ||
field: 'created', | ||
name: i18n.translate('xpack.endpoint.policyList.createdField', { | ||
defaultMessage: 'Created', | ||
}), | ||
}, | ||
{ | ||
field: 'updated_by', | ||
name: i18n.translate('xpack.endpoint.policyList.updatedByField', { | ||
defaultMessage: 'Last Updated By', | ||
}), | ||
}, | ||
{ | ||
field: 'updated', | ||
name: i18n.translate('xpack.endpoint.policyList.updatedField', { | ||
defaultMessage: 'Last Updated', | ||
}), | ||
}, | ||
], | ||
[] | ||
); | ||
|
||
return ( | ||
<EuiPage> | ||
<EuiPageBody> | ||
<EuiPageContent> | ||
<EuiPageContentHeader> | ||
<EuiPageContentHeaderSection> | ||
<EuiTitle> | ||
<h2 data-test-subj="policyViewTitle"> | ||
<FormattedMessage | ||
id="xpack.endpoint.policyList.viewTitle" | ||
defaultMessage="Policies" | ||
/> | ||
</h2> | ||
</EuiTitle> | ||
</EuiPageContentHeaderSection> | ||
</EuiPageContentHeader> | ||
<EuiPageContentBody> | ||
<EuiBasicTable | ||
items={policyItems} | ||
columns={columns} | ||
loading={loading} | ||
pagination={paginationSetup} | ||
onChange={handleTableChange} | ||
/> | ||
</EuiPageContentBody> | ||
</EuiPageContent> | ||
</EuiPageBody> | ||
</EuiPage> | ||
); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice