Skip to content

Commit

Permalink
Lay plumbing for filtering based on tags
Browse files Browse the repository at this point in the history
  • Loading branch information
kpollich committed Apr 28, 2022
1 parent f9745fc commit c43d60c
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ export const SearchAndFilterBar: React.FunctionComponent<{
onSelectedStatusChange: (selectedStatus: string[]) => void;
showUpgradeable: boolean;
onShowUpgradeableChange: (showUpgradeable: boolean) => void;
tags: string[];
selectedTags: string[];
onSelectedTagsChange: (selectedTags: string[]) => void;
}> = ({
agentPolicies,
draftKuery,
Expand All @@ -78,14 +81,19 @@ export const SearchAndFilterBar: React.FunctionComponent<{
onSelectedStatusChange,
showUpgradeable,
onShowUpgradeableChange,
tags,
selectedTags,
onSelectedTagsChange,
}) => {
const [isEnrollmentFlyoutOpen, setIsEnrollmentFlyoutOpen] = useState<boolean>(false);

// Policies state for filtering
const [isAgentPoliciesFilterOpen, setIsAgentPoliciesFilterOpen] = useState<boolean>(false);

// Status for filtering
const [isStatusFilterOpen, setIsStatutsFilterOpen] = useState<boolean>(false);
const [isStatusFilterOpen, setIsStatusFilterOpen] = useState<boolean>(false);

const [isTagsFilterOpen, setIsTagsFilterOpen] = useState<boolean>(false);

// Add a agent policy id to current search
const addAgentPolicyFilter = (policyId: string) => {
Expand All @@ -99,6 +107,14 @@ export const SearchAndFilterBar: React.FunctionComponent<{
);
};

const addTagsFilter = (tag: string) => {
onSelectedTagsChange([...selectedTags, tag]);
};

const removeTagsFilter = (tag: string) => {
onSelectedTagsChange(selectedTags.filter((t) => t !== tag));
};

return (
<>
{isEnrollmentFlyoutOpen ? (
Expand Down Expand Up @@ -131,7 +147,7 @@ export const SearchAndFilterBar: React.FunctionComponent<{
button={
<EuiFilterButton
iconType="arrowDown"
onClick={() => setIsStatutsFilterOpen(!isStatusFilterOpen)}
onClick={() => setIsStatusFilterOpen(!isStatusFilterOpen)}
isSelected={isStatusFilterOpen}
hasActiveFilters={selectedStatus.length > 0}
disabled={agentPolicies.length === 0}
Expand All @@ -144,7 +160,7 @@ export const SearchAndFilterBar: React.FunctionComponent<{
</EuiFilterButton>
}
isOpen={isStatusFilterOpen}
closePopover={() => setIsStatutsFilterOpen(false)}
closePopover={() => setIsStatusFilterOpen(false)}
panelPaddingSize="none"
>
<div className="euiFilterSelect__items">
Expand All @@ -165,6 +181,45 @@ export const SearchAndFilterBar: React.FunctionComponent<{
))}
</div>
</EuiPopover>
<EuiPopover
ownFocus
button={
<EuiFilterButton
iconType="arrowDown"
onClick={() => setIsTagsFilterOpen(!isTagsFilterOpen)}
isSelected={isTagsFilterOpen}
hasActiveFilters={selectedTags.length > 0}
disabled={tags.length === 0}
data-test-subj="agentList.tagsFilter"
>
<FormattedMessage
id="xpack.fleet.agentList.tagsFilterText"
defaultMessage="Tags"
/>
</EuiFilterButton>
}
isOpen={isTagsFilterOpen}
closePopover={() => setIsTagsFilterOpen(false)}
panelPaddingSize="none"
>
<div className="euiFilterSelect__items">
{tags.map((tag, index) => (
<EuiFilterSelectItem
checked={selectedTags.includes(tag) ? 'on' : undefined}
key={index}
onClick={() => {
if (selectedTags.includes(tag)) {
removeTagsFilter(tag);
} else {
addTagsFilter(tag);
}
}}
>
{tag}
</EuiFilterSelectItem>
))}
</div>
</EuiPopover>
<EuiPopover
ownFocus
button={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ interface Props {

const MAX_TAGS_TO_DISPLAY = 3;

export const Labels: React.FunctionComponent<Props> = ({ tags }) => {
export const Tags: React.FunctionComponent<Props> = ({ tags }) => {
return (
<>
{tags.length > MAX_TAGS_TO_DISPLAY ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ import { agentFlyoutContext } from '..';
import { AgentTableHeader } from './components/table_header';
import type { SelectionMode } from './components/bulk_actions';
import { SearchAndFilterBar } from './components/search_and_filter_bar';
import { Labels } from './components/labels';
import { Tags } from './components/tags';

const MOCK_TAGS = [
'linux',
Expand Down Expand Up @@ -200,14 +200,21 @@ export const AgentListPage: React.FunctionComponent<{}> = () => {
// Status for filtering
const [selectedStatus, setSelectedStatus] = useState<string[]>([]);

const [selectedTags, setSelectedTags] = useState<string[]>([]);

const isUsingFilter =
search.trim() || selectedAgentPolicies.length || selectedStatus.length || showUpgradeable;
search.trim() ||
selectedAgentPolicies.length ||
selectedStatus.length ||
selectedTags.length ||
showUpgradeable;

const clearFilters = useCallback(() => {
setDraftKuery('');
setSearch('');
setSelectedAgentPolicies([]);
setSelectedStatus([]);
setSelectedTags([]);
setShowUpgradeable(false);
}, [setSearch, setDraftKuery, setSelectedAgentPolicies, setSelectedStatus, setShowUpgradeable]);

Expand Down Expand Up @@ -237,6 +244,11 @@ export const AgentListPage: React.FunctionComponent<{}> = () => {
.map((agentPolicy) => `"${agentPolicy}"`)
.join(' or ')})`;
}

if (selectedTags.length) {
kueryBuilder = `${kueryBuilder} and ${AGENTS_PREFIX}.tags : (${selectedTags.join(' or ')})`;
}

if (selectedStatus.length) {
const kueryStatus = selectedStatus
.map((status) => {
Expand Down Expand Up @@ -266,7 +278,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => {
}

return kueryBuilder;
}, [selectedStatus, selectedAgentPolicies, search]);
}, [search, selectedAgentPolicies, selectedTags, selectedStatus]);

const showInactive = useMemo(() => {
return selectedStatus.includes('inactive');
Expand All @@ -280,6 +292,8 @@ export const AgentListPage: React.FunctionComponent<{}> = () => {
const [totalAgents, setTotalAgents] = useState(0);
const [totalInactiveAgents, setTotalInactiveAgents] = useState(0);

const allTags = Array.from(new Set(agents.flatMap((agent) => agent.tags ?? [])));

// Request to fetch agents and agent status
const currentRequestRef = useRef<number>(0);
const fetchData = useCallback(() => {
Expand Down Expand Up @@ -328,7 +342,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => {

setAgents(
agentsRequest.data.items.map((item) => {
// TEMP: Mock tags data for building out label UI
// TEMP: Mock tags data for building out tags UI
item.tags = sampleSize(MOCK_TAGS, Math.floor(Math.random() * MOCK_TAGS.length));
return item;
})
Expand Down Expand Up @@ -430,10 +444,10 @@ export const AgentListPage: React.FunctionComponent<{}> = () => {
{
field: 'tags',
width: '240px',
name: i18n.translate('xpack.fleet.agentList.labelColumnTitle', {
defaultMessage: 'Label',
name: i18n.translate('xpack.fleet.agentList.tagsColumnTitle', {
defaultMessage: 'Tags',
}),
render: (tags: string[], agent: any) => <Labels tags={tags} />,
render: (tags: string[], agent: any) => <Tags tags={tags} />,
},
{
field: 'policy_id',
Expand Down Expand Up @@ -622,6 +636,9 @@ export const AgentListPage: React.FunctionComponent<{}> = () => {
onSelectedStatusChange={setSelectedStatus}
showUpgradeable={showUpgradeable}
onShowUpgradeableChange={setShowUpgradeable}
tags={allTags}
selectedTags={selectedTags}
onSelectedTagsChange={setSelectedTags}
/>
<EuiSpacer size="m" />

Expand Down

0 comments on commit c43d60c

Please sign in to comment.