Skip to content

Commit

Permalink
Introduce numeric search field in table filters
Browse files Browse the repository at this point in the history
  • Loading branch information
wweellddeerr committed Oct 16, 2024
1 parent 0a200a4 commit a0c65b5
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 23 deletions.
65 changes: 65 additions & 0 deletions web/html/src/components/table/NumericSearchField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { useState } from "react";

import { Select } from "components/input";

type Matcher = {
label: string;
value: string;
};

const matchers: Matcher[] = [
{ label: t("less than"), value: "<" },
{ label: t("less than or equal to"), value: "<=" },
{ label: t("equal to"), value: "=" },
{ label: t("greater than or equal to"), value: ">=" },
{ label: t("greater than"), value: ">" },
{ label: t("not equal to"), value: "!=" },
];

const resultingCriteria = (matcher: string, value: string) => {
return matcher && value && value.trim() !== "" ? matcher + value : null;
};

export const NumericSearchField = ({ name, criteria, onSearch }) => {
let criteriaMatcher = "";
let criteriaValue = "";
if (criteria) {
criteriaMatcher = matchers.find((it) => criteria.startsWith(it.value))?.value ?? "=";
criteriaValue = criteria.includes(criteriaMatcher) ? criteria.split(criteriaMatcher)[1] : criteria;
}

const [matcher, setMatcher] = useState<string>(criteriaMatcher);
const [value, setValue] = useState<string>(criteriaValue);

const handleMatcherChange = (selectedMatcher: string) => {
setMatcher(selectedMatcher);
onSearch(resultingCriteria(selectedMatcher, value));
};
const handleValueChange = (newValue: string) => {
setValue(newValue);
onSearch(resultingCriteria(matcher, newValue));
};
return (
<div className="row">
<div className="col-sm-6">
<Select
name="matcher"
placeholder={t("Matcher")}
defaultValue={matcher}
options={matchers}
onChange={(_name: string | undefined, value: string) => handleMatcherChange(value)}
/>
</div>

<div className="col">
<input
className="form-control"
value={value || ""}
type="number"
onChange={(e) => handleValueChange(e.target.value)}
name={name}
/>
</div>
</div>
);
};
11 changes: 7 additions & 4 deletions web/html/src/components/table/SelectSearchField.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from "react";
import { useEffect, useState } from "react";

import { Select } from "components/input";

Expand All @@ -15,9 +15,12 @@ export const SelectSearchField = ({ label, criteria, options, onSearch }) => {
const allOptions = [ALL_OPTION].concat(options);

// Avoid invalid value selected when changing field.
if (!allOptions.some((it) => it.value === searchValue)) {
handleSearchValueChange(ALL_OPTION.value);
}
useEffect(() => {
if (!allOptions.some((it) => it.value === searchValue)) {
setSearchValue(ALL_OPTION.value);
onSearch?.("");
}
}, [searchValue, allOptions, onSearch]);

return (
<Select
Expand Down
34 changes: 32 additions & 2 deletions web/html/src/components/table/TableFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,34 @@ import { Select } from "components/input";
import { Form } from "components/input/form/Form";
import { SelectSearchField } from "components/table/SelectSearchField";

const renderSearchField = ({ filterOptions, field, criteria, onSearch, placeholder, name }) => {
import { NumericSearchField } from "./NumericSearchField";

export enum FilterOptionType {
TEXT,
SELECT,
NUMERIC,
}

type FilterOption = {
label: string;
value: string;
type?: FilterOptionType;
filterOptions?: Array<any>;
};

type SearchFieldProps = {
filterOptions: Array<FilterOption>;
field: any;
criteria: any;
onSearch: any;
placeholder: any;
name: any;
};

const renderSearchField = (props: SearchFieldProps) => {
const { filterOptions, field, criteria, onSearch, placeholder, name } = props;
const selectedOption = filterOptions.find((it) => it.value === field);
if (selectedOption?.filterOptions) {
if (selectedOption?.type === FilterOptionType.SELECT) {
return (
<SelectSearchField
label={selectedOption.label}
Expand All @@ -16,6 +41,11 @@ const renderSearchField = ({ filterOptions, field, criteria, onSearch, placehold
/>
);
}

if (selectedOption?.type === FilterOptionType.NUMERIC) {
return <NumericSearchField name={name} criteria={criteria} onSearch={onSearch} />;
}

return (
<div className="form-group">
<input
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { FilterOptionType } from "components/table/TableFilter";

// Value options for filtering by Target Type in recurring actions list
const ORG_OPTION = { value: "ORG", label: t("Organization") };
const GROUP_OPTION = { value: "GROUP", label: t("Group") };
Expand All @@ -10,9 +12,29 @@ const CUSTOM_STATE_OPTION = { value: "CUSTOM_STATE", label: t("Custom State") };
export const ACTION_TYPE_OPTIONS = [CUSTOM_STATE_OPTION, HIGHSTATE_OPTION];

// Field options for filtering in recurring actions list.
const SCHEDULE_NAME_OPTION = { value: "schedule_name", label: t("Schedule Name") };
const TARGET_NAME_OPTION = { value: "target_name", label: t("Target Name") };
export const TARGET_TYPE_OPTION = { value: "target_type", label: t("Target Type"), filterOptions: TARGET_TYPE_OPTIONS };
export const ACTION_TYPE_OPTION = { value: "action_type", label: t("Action Type"), filterOptions: ACTION_TYPE_OPTIONS };
const SCHEDULE_NAME_OPTION = {
value: "schedule_name",
label: t("Schedule Name"),
type: FilterOptionType.TEXT,
};

const TARGET_NAME_OPTION = {
value: "target_name",
label: t("Target Name"),
type: FilterOptionType.TEXT,
};

const TARGET_TYPE_OPTION = {
value: "target_type",
label: t("Target Type"),
type: FilterOptionType.SELECT,
filterOptions: TARGET_TYPE_OPTIONS,
};
export const ACTION_TYPE_OPTION = {
value: "action_type",
label: t("Action Type"),
type: FilterOptionType.SELECT,
filterOptions: ACTION_TYPE_OPTIONS,
};

export const SEARCH_FIELD_OPTIONS = [SCHEDULE_NAME_OPTION, TARGET_TYPE_OPTION, TARGET_NAME_OPTION, ACTION_TYPE_OPTION];
36 changes: 23 additions & 13 deletions web/html/src/manager/systems/list-filter.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TableFilter } from "components/table/TableFilter";
import { FilterOptionType, TableFilter } from "components/table/TableFilter";

const SYSTEM_KIND_OPTIONS = [
{ value: "mgr_server", label: t("Manager Server") },
Expand Down Expand Up @@ -38,18 +38,28 @@ const YES_NO_OPTIONS = [
];

const allListOptions = [
{ value: "server_name", label: t("System") },
{ value: "system_kind", label: t("System Kind"), filterOptions: SYSTEM_KIND_OPTIONS },
{ value: "status_type", label: t("Updates"), filterOptions: STATUS_TYPE_OPTIONS },
{ value: "total_errata_count", label: t("Patches") },
{ value: "outdated_packages", label: t("Packages") },
{ value: "extra_pkg_count", label: t("Extra Packages") },
{ value: "config_files_with_differences", label: t("Config Diffs") },
{ value: "channel_labels", label: t("Base Channel") },
{ value: "entitlement_level", label: t("System Type"), filterOptions: SYSTEM_TYPE_OPTIONS },
{ value: "requires_reboot", label: t("Requires Reboot"), filterOptions: YES_NO_OPTIONS },
{ value: "created_days", label: t("Registered Days") },
{ value: "group_count", label: t("Groups") },
{ value: "server_name", label: t("System"), type: FilterOptionType.TEXT },
{ value: "system_kind", label: t("System Kind"), type: FilterOptionType.SELECT, filterOptions: SYSTEM_KIND_OPTIONS },
{ value: "status_type", label: t("Updates"), type: FilterOptionType.SELECT, filterOptions: STATUS_TYPE_OPTIONS },
{ value: "total_errata_count", label: t("Patches"), type: FilterOptionType.NUMERIC },
{ value: "outdated_packages", label: t("Packages"), type: FilterOptionType.NUMERIC },
{ value: "extra_pkg_count", label: t("Extra Packages"), type: FilterOptionType.NUMERIC },
{ value: "config_files_with_differences", label: t("Config Diffs"), type: FilterOptionType.NUMERIC },
{ value: "channel_labels", label: t("Base Channel"), type: FilterOptionType.TEXT },
{
value: "entitlement_level",
label: t("System Type"),
type: FilterOptionType.SELECT,
filterOptions: SYSTEM_TYPE_OPTIONS,
},
{
value: "requires_reboot",
label: t("Requires Reboot"),
type: FilterOptionType.SELECT,
filterOptions: YES_NO_OPTIONS,
},
{ value: "created_days", label: t("Registered Days"), type: FilterOptionType.NUMERIC },
{ value: "group_count", label: t("Groups"), type: FilterOptionType.NUMERIC },
];

const virtualSystemsListOptions = [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Introduce numeric search field in table filters

0 comments on commit a0c65b5

Please sign in to comment.