mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 08:55:24 +00:00
Schedules page: Action cell (Update and delete a global scheduled query) (#1525)
* Create and edit modal component * Update e2e test for update and delete global scheduled query
This commit is contained in:
parent
dea00479d7
commit
c934f3e172
1
changes/issue-1525-schedule-action-dropdown
Normal file
1
changes/issue-1525-schedule-action-dropdown
Normal file
@ -0,0 +1 @@
|
||||
* Users can update and remove a global scheduled query with an Action dropdown
|
@ -4,7 +4,7 @@ describe("Query flow", () => {
|
||||
cy.login();
|
||||
});
|
||||
|
||||
it("Create, check, edit, and delete a query successfully", () => {
|
||||
it("Create, check, edit, and delete a query successfully and create, edit, and delete a global scheduled query successfully", () => {
|
||||
cy.visit("/queries/manage");
|
||||
|
||||
cy.findByRole("button", { name: /create new query/i }).click();
|
||||
@ -83,16 +83,38 @@ describe("Query flow", () => {
|
||||
|
||||
cy.findByText(/query all window crashes/i).should("exist");
|
||||
|
||||
// Checkbox won't check so can't test remove schedule
|
||||
// cy.get("tbody").get(".table-checkbox__input").click();
|
||||
cy.wait(1000); // eslint-disable-line cypress/no-unnecessary-waiting
|
||||
cy.findByText(/actions/i).click();
|
||||
cy.findByText(/edit/i).click();
|
||||
|
||||
// cy.findByRole("button", { name: /remove query/i }).click();
|
||||
cy.get(
|
||||
".schedule-editor-modal__form-field--frequency > .dropdown__select"
|
||||
).click();
|
||||
|
||||
// cy.get(".remove-scheduled-query-modal__btn-wrap")
|
||||
// .contains("button", /remove/i)
|
||||
// .click();
|
||||
cy.findByText(/every 6 hours/i).click();
|
||||
|
||||
// cy.findByText(/query all window crashes/i).should("not.exist");
|
||||
cy.findByText(/show advanced options/i).click();
|
||||
|
||||
cy.findByText(/ignore removals/i).click();
|
||||
cy.findByText(/snapshot/i).click();
|
||||
|
||||
cy.get(".schedule-editor-modal__form-field--shard > .input-field")
|
||||
.click()
|
||||
.type("{selectall}{backspace}10");
|
||||
|
||||
cy.get(".schedule-editor-modal__btn-wrap")
|
||||
.contains("button", /schedule/i)
|
||||
.click();
|
||||
|
||||
cy.wait(1000); // eslint-disable-line cypress/no-unnecessary-waiting
|
||||
cy.findByText(/actions/i).click();
|
||||
cy.findByText(/remove/i).click();
|
||||
|
||||
cy.get(".remove-scheduled-query-modal__btn-wrap")
|
||||
.contains("button", /remove/i)
|
||||
.click();
|
||||
|
||||
cy.findByText(/query all window crashes/i).should("not.exist");
|
||||
// End Test Schedules
|
||||
|
||||
cy.visit("/queries/manage");
|
||||
|
@ -48,11 +48,37 @@
|
||||
|
||||
&:last-child {
|
||||
border-right: none;
|
||||
width: 180px;
|
||||
max-width: 140px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.Select.is-focused:not(.is-open) > .Select-control {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.Select.is-open {
|
||||
.Select-arrow {
|
||||
margin-top: 6px;
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
}
|
||||
|
||||
.Select-arrow {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.Select-control:hover {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.Select-placeholder {
|
||||
font-size: 14px;
|
||||
margin-top: 2px;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.active-selection {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
&__ex {
|
||||
text-decoration: none;
|
||||
padding-left: $pad-xsmall;
|
||||
|
||||
.button::after {
|
||||
content: url("../assets/images/icon-close-fleet-blue-16x16@2x.png");
|
||||
@ -37,10 +38,16 @@
|
||||
font-size: $large;
|
||||
font-weight: $regular;
|
||||
text-align: left;
|
||||
padding-bottom: 15px;
|
||||
padding-bottom: $pad-xsmall;
|
||||
border-bottom: 1px solid $ui-fleet-blue-15;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
span {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
&__modal_container {
|
||||
|
@ -7,8 +7,10 @@ export default PropTypes.shape({
|
||||
shard: PropTypes.number,
|
||||
query: PropTypes.string.isRequired,
|
||||
query_id: PropTypes.number.isRequired,
|
||||
removed: PropTypes.bool,
|
||||
snapshot: PropTypes.bool,
|
||||
removed: PropTypes.bool.isRequired,
|
||||
snapshot: PropTypes.bool.isRequired,
|
||||
version: PropTypes.string,
|
||||
platform: PropTypes.string,
|
||||
});
|
||||
|
||||
export interface IGlobalScheduledQuery {
|
||||
@ -20,4 +22,6 @@ export interface IGlobalScheduledQuery {
|
||||
query_id: number;
|
||||
removed: boolean;
|
||||
snapshot: boolean;
|
||||
version?: string;
|
||||
platform?: string;
|
||||
}
|
||||
|
@ -5,30 +5,4 @@
|
||||
@include sticky-settings-description;
|
||||
padding-bottom: $pad-medium;
|
||||
}
|
||||
|
||||
.Select.is-focused:not(.is-open) > .Select-control {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.Select.is-open {
|
||||
.Select-arrow {
|
||||
margin-top: 6px;
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
}
|
||||
|
||||
.Select-arrow {
|
||||
margin-top: $pad-xsmall;
|
||||
}
|
||||
|
||||
.Select-control:hover {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.Select-placeholder {
|
||||
font-size: $x-small;
|
||||
margin-top: $pad-xxsmall;
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@
|
||||
border-radius: 6px 0;
|
||||
|
||||
&:last-child {
|
||||
min-width: 100px;
|
||||
min-width: 80px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -124,30 +124,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.Select.is-focused:not(.is-open) > .Select-control {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.Select.is-open {
|
||||
.Select-arrow {
|
||||
margin-top: 6px;
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
}
|
||||
|
||||
.Select-arrow {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.Select-control:hover {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.Select-placeholder {
|
||||
font-size: 14px;
|
||||
margin-top: 2px;
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ import React, { useState, useCallback, useEffect } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
import { push } from "react-router-redux";
|
||||
// @ts-ignore
|
||||
import deepDifference from "utilities/deep_difference";
|
||||
import { IQuery } from "interfaces/query";
|
||||
import { IGlobalScheduledQuery } from "interfaces/global_scheduled_query";
|
||||
// @ts-ignore
|
||||
@ -22,6 +24,7 @@ const baseClass = "manage-schedule-page";
|
||||
|
||||
const renderTable = (
|
||||
onRemoveScheduledQueryClick: React.MouseEventHandler<HTMLButtonElement>,
|
||||
onEditScheduledQueryClick: React.MouseEventHandler<HTMLButtonElement>,
|
||||
allGlobalScheduledQueriesList: IGlobalScheduledQuery[],
|
||||
allGlobalScheduledQueriesError: any,
|
||||
toggleScheduleEditorModal: () => void
|
||||
@ -33,6 +36,7 @@ const renderTable = (
|
||||
return (
|
||||
<ScheduleListWrapper
|
||||
onRemoveScheduledQueryClick={onRemoveScheduledQueryClick}
|
||||
onEditScheduledQueryClick={onEditScheduledQueryClick}
|
||||
allGlobalScheduledQueriesList={allGlobalScheduledQueriesList}
|
||||
toggleScheduleEditorModal={toggleScheduleEditorModal}
|
||||
/>
|
||||
@ -89,8 +93,13 @@ const ManageSchedulePage = (): JSX.Element => {
|
||||
setShowRemoveScheduledQueryModal,
|
||||
] = useState(false);
|
||||
const [selectedQueryIds, setSelectedQueryIds] = useState([]);
|
||||
const [
|
||||
selectedScheduledQuery,
|
||||
setSelectedScheduledQuery,
|
||||
] = useState<IGlobalScheduledQuery>();
|
||||
|
||||
const toggleScheduleEditorModal = useCallback(() => {
|
||||
setSelectedScheduledQuery(undefined); // create modal renders
|
||||
setShowScheduleEditorModal(!showScheduleEditorModal);
|
||||
}, [showScheduleEditorModal, setShowScheduleEditorModal]);
|
||||
|
||||
@ -98,11 +107,16 @@ const ManageSchedulePage = (): JSX.Element => {
|
||||
setShowRemoveScheduledQueryModal(!showRemoveScheduledQueryModal);
|
||||
}, [showRemoveScheduledQueryModal, setShowRemoveScheduledQueryModal]);
|
||||
|
||||
const onRemoveScheduledQueryClick = (selectedTableQueryIds: any) => {
|
||||
const onRemoveScheduledQueryClick = (selectedTableQueryIds: any): any => {
|
||||
toggleRemoveScheduledQueryModal();
|
||||
setSelectedQueryIds(selectedTableQueryIds);
|
||||
};
|
||||
|
||||
const onEditScheduledQueryClick = (selectedQuery: any): void => {
|
||||
toggleScheduleEditorModal();
|
||||
setSelectedScheduledQuery(selectedQuery); // edit modal renders
|
||||
};
|
||||
|
||||
const onRemoveScheduledQuerySubmit = useCallback(() => {
|
||||
const promises = selectedQueryIds.map((id: number) => {
|
||||
return dispatch(globalScheduledQueryActions.destroy({ id }));
|
||||
@ -131,22 +145,50 @@ const ManageSchedulePage = (): JSX.Element => {
|
||||
}, [dispatch, selectedQueryIds, toggleRemoveScheduledQueryModal]);
|
||||
|
||||
const onAddScheduledQuerySubmit = useCallback(
|
||||
(formData: IFormData) => {
|
||||
dispatch(globalScheduledQueryActions.create({ ...formData }))
|
||||
.then(() => {
|
||||
dispatch(
|
||||
renderFlash(
|
||||
"success",
|
||||
`Successfully added ${formData.name} to the schedule.`
|
||||
)
|
||||
);
|
||||
dispatch(globalScheduledQueryActions.loadAll());
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(
|
||||
renderFlash("error", "Could not schedule query. Please try again.")
|
||||
);
|
||||
});
|
||||
(formData: IFormData, editQuery: IGlobalScheduledQuery | undefined) => {
|
||||
if (editQuery) {
|
||||
const updatedAttributes = deepDifference(formData, editQuery);
|
||||
|
||||
dispatch(
|
||||
globalScheduledQueryActions.update(editQuery, updatedAttributes)
|
||||
)
|
||||
.then(() => {
|
||||
dispatch(
|
||||
renderFlash(
|
||||
"success",
|
||||
`Successfully updated ${formData.name} in the schedule.`
|
||||
)
|
||||
);
|
||||
dispatch(globalScheduledQueryActions.loadAll());
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(
|
||||
renderFlash(
|
||||
"error",
|
||||
"Could not update scheduled query. Please try again."
|
||||
)
|
||||
);
|
||||
});
|
||||
} else {
|
||||
dispatch(globalScheduledQueryActions.create({ ...formData }))
|
||||
.then(() => {
|
||||
dispatch(
|
||||
renderFlash(
|
||||
"success",
|
||||
`Successfully added ${formData.name} to the schedule.`
|
||||
)
|
||||
);
|
||||
dispatch(globalScheduledQueryActions.loadAll());
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(
|
||||
renderFlash(
|
||||
"error",
|
||||
"Could not schedule query. Please try again."
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
toggleScheduleEditorModal();
|
||||
},
|
||||
[dispatch, toggleScheduleEditorModal]
|
||||
@ -194,6 +236,7 @@ const ManageSchedulePage = (): JSX.Element => {
|
||||
<div>
|
||||
{renderTable(
|
||||
onRemoveScheduledQueryClick,
|
||||
onEditScheduledQueryClick,
|
||||
allGlobalScheduledQueriesList,
|
||||
allGlobalScheduledQueriesError,
|
||||
toggleScheduleEditorModal
|
||||
@ -204,6 +247,7 @@ const ManageSchedulePage = (): JSX.Element => {
|
||||
onCancel={toggleScheduleEditorModal}
|
||||
onScheduleSubmit={onAddScheduledQuerySubmit}
|
||||
allQueries={allQueriesList}
|
||||
editQuery={selectedScheduledQuery}
|
||||
/>
|
||||
)}
|
||||
{showRemoveScheduledQueryModal && (
|
||||
|
@ -1,4 +1,6 @@
|
||||
import React, { useState, useCallback } from "react";
|
||||
/* This component is used for both creating and editing global scheduled queries */
|
||||
|
||||
import React, { useState, useCallback, useEffect } from "react";
|
||||
|
||||
import { pull } from "lodash";
|
||||
// @ts-ignore
|
||||
@ -35,17 +37,32 @@ interface IFormData {
|
||||
interface IScheduleEditorModalProps {
|
||||
allQueries: IQuery[];
|
||||
onCancel: () => void;
|
||||
onScheduleSubmit: (formData: IFormData) => void;
|
||||
onScheduleSubmit: (
|
||||
formData: IFormData,
|
||||
editQuery: IGlobalScheduledQuery | undefined
|
||||
) => void;
|
||||
editQuery?: IGlobalScheduledQuery;
|
||||
}
|
||||
interface INoQueryOption {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const generateLoggingType = (query: IGlobalScheduledQuery) => {
|
||||
if (query.snapshot) {
|
||||
return "snapshot";
|
||||
}
|
||||
if (query.removed) {
|
||||
return "differential";
|
||||
}
|
||||
return "differential_ignore_removals";
|
||||
};
|
||||
|
||||
const ScheduleEditorModal = ({
|
||||
onCancel,
|
||||
onScheduleSubmit,
|
||||
allQueries,
|
||||
editQuery,
|
||||
}: IScheduleEditorModalProps): JSX.Element => {
|
||||
const [showAdvancedOptions, setShowAdvancedOptions] = useState<boolean>(
|
||||
false
|
||||
@ -53,19 +70,23 @@ const ScheduleEditorModal = ({
|
||||
const [selectedQuery, setSelectedQuery] = useState<
|
||||
IGlobalScheduledQuery | INoQueryOption
|
||||
>();
|
||||
const [selectedFrequency, setSelectedFrequency] = useState<number>(86400);
|
||||
const [selectedFrequency, setSelectedFrequency] = useState<number>(
|
||||
editQuery ? editQuery.interval : 86400
|
||||
);
|
||||
const [
|
||||
selectedPlatformOptions,
|
||||
setSelectedPlatformOptions,
|
||||
] = useState<string>("");
|
||||
] = useState<string>(editQuery?.platform || "");
|
||||
const [selectedLoggingType, setSelectedLoggingType] = useState<string>(
|
||||
"snapshot"
|
||||
editQuery ? generateLoggingType(editQuery) : "snapshot"
|
||||
);
|
||||
const [
|
||||
selectedMinOsqueryVersionOptions,
|
||||
setSelectedMinOsqueryVersionOptions,
|
||||
] = useState<string>("");
|
||||
const [selectedShard, setSelectedShard] = useState<string>("");
|
||||
] = useState<string>(editQuery?.version || "");
|
||||
const [selectedShard, setSelectedShard] = useState<string>(
|
||||
editQuery?.shard ? editQuery?.shard.toString() : ""
|
||||
);
|
||||
|
||||
const createQueryDropdownOptions = () => {
|
||||
const queryOptions = allQueries.map((q) => {
|
||||
@ -137,28 +158,51 @@ const ScheduleEditorModal = ({
|
||||
);
|
||||
|
||||
const onFormSubmit = () => {
|
||||
onScheduleSubmit({
|
||||
shard: parseInt(selectedShard, 10),
|
||||
interval: selectedFrequency,
|
||||
query_id: selectedQuery?.id,
|
||||
name: selectedQuery?.name,
|
||||
logging_type: selectedLoggingType,
|
||||
platform: selectedPlatformOptions,
|
||||
version: selectedMinOsqueryVersionOptions,
|
||||
});
|
||||
const query_id = () => {
|
||||
if (editQuery) {
|
||||
return editQuery.id;
|
||||
}
|
||||
return selectedQuery?.id;
|
||||
};
|
||||
|
||||
const name = () => {
|
||||
if (editQuery) {
|
||||
return editQuery.name;
|
||||
}
|
||||
return selectedQuery?.name;
|
||||
};
|
||||
|
||||
onScheduleSubmit(
|
||||
{
|
||||
shard: parseInt(selectedShard, 10),
|
||||
interval: selectedFrequency,
|
||||
query_id: query_id(),
|
||||
name: name(),
|
||||
logging_type: selectedLoggingType,
|
||||
platform: selectedPlatformOptions,
|
||||
version: selectedMinOsqueryVersionOptions,
|
||||
},
|
||||
editQuery
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal title={"Schedule editor"} onExit={onCancel} className={baseClass}>
|
||||
<Modal
|
||||
title={editQuery?.name || "Schedule editor"}
|
||||
onExit={onCancel}
|
||||
className={baseClass}
|
||||
>
|
||||
<form className={`${baseClass}__form`}>
|
||||
<Dropdown
|
||||
searchable
|
||||
options={createQueryDropdownOptions()}
|
||||
onChange={onChangeSelectQuery}
|
||||
placeholder={"Select query"}
|
||||
value={selectedQuery?.id}
|
||||
wrapperClassName={`${baseClass}__select-query-dropdown-wrapper`}
|
||||
/>
|
||||
{!editQuery && (
|
||||
<Dropdown
|
||||
searchable
|
||||
options={createQueryDropdownOptions()}
|
||||
onChange={onChangeSelectQuery}
|
||||
placeholder={"Select query"}
|
||||
value={selectedQuery?.id}
|
||||
wrapperClassName={`${baseClass}__select-query-dropdown-wrapper`}
|
||||
/>
|
||||
)}
|
||||
<Dropdown
|
||||
searchable={false}
|
||||
options={FREQUENCY_DROPDOWN_OPTIONS}
|
||||
@ -244,7 +288,7 @@ const ScheduleEditorModal = ({
|
||||
type="button"
|
||||
variant="brand"
|
||||
onClick={onFormSubmit}
|
||||
disabled={!selectedQuery}
|
||||
disabled={!selectedQuery && !editQuery}
|
||||
>
|
||||
Schedule
|
||||
</Button>
|
||||
|
@ -12,7 +12,7 @@ import { IGlobalScheduledQuery } from "interfaces/global_scheduled_query";
|
||||
import globalScheduledQueryActions from "redux/nodes/entities/global_scheduled_queries/actions";
|
||||
|
||||
import TableContainer from "components/TableContainer";
|
||||
import generateTableHeaders from "./ScheduleTableConfig";
|
||||
import { generateTableHeaders, generateDataSet } from "./ScheduleTableConfig";
|
||||
// @ts-ignore
|
||||
import scheduleSvg from "../../../../../../assets/images/schedule.svg";
|
||||
|
||||
@ -21,6 +21,7 @@ const noScheduleClass = "no-schedule";
|
||||
|
||||
interface IScheduleListWrapperProps {
|
||||
onRemoveScheduledQueryClick: any;
|
||||
onEditScheduledQueryClick: any;
|
||||
allGlobalScheduledQueriesList: IGlobalScheduledQuery[];
|
||||
toggleScheduleEditorModal: any;
|
||||
}
|
||||
@ -38,6 +39,7 @@ const ScheduleListWrapper = (props: IScheduleListWrapperProps): JSX.Element => {
|
||||
onRemoveScheduledQueryClick,
|
||||
allGlobalScheduledQueriesList,
|
||||
toggleScheduleEditorModal,
|
||||
onEditScheduledQueryClick,
|
||||
} = props;
|
||||
const dispatch = useDispatch();
|
||||
const { MANAGE_PACKS } = paths;
|
||||
@ -77,7 +79,21 @@ const ScheduleListWrapper = (props: IScheduleListWrapperProps): JSX.Element => {
|
||||
);
|
||||
};
|
||||
|
||||
const tableHeaders = generateTableHeaders();
|
||||
const onActionSelection = (
|
||||
action: string,
|
||||
global_scheduled_query: IGlobalScheduledQuery
|
||||
): void => {
|
||||
switch (action) {
|
||||
case "edit":
|
||||
onEditScheduledQueryClick(global_scheduled_query);
|
||||
break;
|
||||
default:
|
||||
onRemoveScheduledQueryClick([global_scheduled_query.id]);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const tableHeaders = generateTableHeaders(onActionSelection);
|
||||
const loadingTableData = useSelector(
|
||||
(state: IRootState) => state.entities.global_scheduled_queries.isLoading
|
||||
);
|
||||
@ -102,7 +118,7 @@ const ScheduleListWrapper = (props: IScheduleListWrapperProps): JSX.Element => {
|
||||
<TableContainer
|
||||
resultsTitle={"queries"}
|
||||
columns={tableHeaders}
|
||||
data={allGlobalScheduledQueriesList}
|
||||
data={generateDataSet(allGlobalScheduledQueriesList)}
|
||||
isLoading={loadingTableData}
|
||||
defaultSortHeader={"query"}
|
||||
defaultSortDirection={"desc"}
|
||||
|
@ -7,6 +7,8 @@ import { secondsToDhms } from "fleet/helpers";
|
||||
// @ts-ignore
|
||||
import Checkbox from "components/forms/fields/Checkbox";
|
||||
import TextCell from "components/TableContainer/DataTable/TextCell";
|
||||
import DropdownCell from "components/TableContainer/DataTable/DropdownCell";
|
||||
import { IDropdownOption } from "interfaces/dropdownOption";
|
||||
import { IGlobalScheduledQuery } from "interfaces/global_scheduled_query";
|
||||
|
||||
interface IHeaderProps {
|
||||
@ -38,10 +40,22 @@ interface IDataColumn {
|
||||
disableHidden?: boolean;
|
||||
disableSortBy?: boolean;
|
||||
}
|
||||
interface IGlobalScheduledQueryTableData {
|
||||
name: string;
|
||||
interval: number;
|
||||
actions: IDropdownOption[];
|
||||
id: number;
|
||||
type: string;
|
||||
}
|
||||
|
||||
// NOTE: cellProps come from react-table
|
||||
// more info here https://react-table.tanstack.com/docs/api/useTable#cell-properties
|
||||
const generateTableHeaders = (): IDataColumn[] => {
|
||||
const generateTableHeaders = (
|
||||
actionSelectHandler: (
|
||||
value: string,
|
||||
global_scheduled_query: IGlobalScheduledQuery
|
||||
) => void
|
||||
): IDataColumn[] => {
|
||||
return [
|
||||
{
|
||||
id: "selection",
|
||||
@ -65,10 +79,10 @@ const generateTableHeaders = (): IDataColumn[] => {
|
||||
disableHidden: true,
|
||||
},
|
||||
{
|
||||
title: "Query name",
|
||||
Header: "Query name",
|
||||
title: "Query",
|
||||
Header: "Query",
|
||||
disableSortBy: true,
|
||||
accessor: "query_name",
|
||||
accessor: "name",
|
||||
Cell: (cellProps: ICellProps): JSX.Element => (
|
||||
<TextCell value={cellProps.cell.value} />
|
||||
),
|
||||
@ -82,7 +96,64 @@ const generateTableHeaders = (): IDataColumn[] => {
|
||||
<TextCell value={secondsToDhms(cellProps.cell.value)} />
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Actions",
|
||||
Header: "",
|
||||
disableSortBy: true,
|
||||
accessor: "actions",
|
||||
Cell: (cellProps) => (
|
||||
<DropdownCell
|
||||
options={cellProps.cell.value}
|
||||
onChange={(value: string) =>
|
||||
actionSelectHandler(value, cellProps.row.original)
|
||||
}
|
||||
placeholder={"Actions"}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
export default generateTableHeaders;
|
||||
const generateActionDropdownOptions = (): IDropdownOption[] => {
|
||||
const dropdownOptions = [
|
||||
{
|
||||
label: "Edit",
|
||||
disabled: false,
|
||||
value: "edit",
|
||||
},
|
||||
{
|
||||
label: "Remove",
|
||||
disabled: false,
|
||||
value: "remove",
|
||||
},
|
||||
];
|
||||
return dropdownOptions;
|
||||
};
|
||||
|
||||
const enhanceGlobalScheduledQueryData = (
|
||||
global_scheduled_queries: IGlobalScheduledQuery[]
|
||||
): IGlobalScheduledQueryTableData[] => {
|
||||
return global_scheduled_queries.map((global_scheduled_query) => {
|
||||
return {
|
||||
name: global_scheduled_query.name,
|
||||
interval: global_scheduled_query.interval,
|
||||
actions: generateActionDropdownOptions(),
|
||||
id: global_scheduled_query.id,
|
||||
query_id: global_scheduled_query.query_id,
|
||||
snapshot: global_scheduled_query.snapshot,
|
||||
removed: global_scheduled_query.removed,
|
||||
platform: global_scheduled_query.platform,
|
||||
version: global_scheduled_query.version,
|
||||
shard: global_scheduled_query.shard,
|
||||
type: "global_scheduled_query",
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const generateDataSet = (
|
||||
global_scheduled_queries: IGlobalScheduledQuery[]
|
||||
): IGlobalScheduledQueryTableData[] => {
|
||||
return [...enhanceGlobalScheduledQueryData(global_scheduled_queries)];
|
||||
};
|
||||
|
||||
export { generateTableHeaders, generateDataSet };
|
||||
|
@ -12,10 +12,6 @@
|
||||
background-color: $ui-off-white;
|
||||
border-bottom: 1px solid $ui-fleet-blue-15;
|
||||
|
||||
th + th {
|
||||
border-left: 1px solid $ui-fleet-blue-15;
|
||||
}
|
||||
|
||||
th {
|
||||
font-size: $x-small;
|
||||
font-weight: $bold;
|
||||
@ -32,11 +28,18 @@
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
width: 37%;
|
||||
width: 20%;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
&:nth-last-child(2) {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
width: 150px;
|
||||
border-top-right-radius: 6px;
|
||||
border-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user