Skip to content

Commit

Permalink
Feat: add status and board filters for scheds page
Browse files Browse the repository at this point in the history
  • Loading branch information
alexVasylenko committed Jan 25, 2023
1 parent 0cbbb42 commit edfaac7
Show file tree
Hide file tree
Showing 12 changed files with 287 additions and 24 deletions.
9 changes: 9 additions & 0 deletions querybook/server/logic/schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
TaskRunRecord,
)
from models.datadoc import DataDoc
from models.board import BoardItem

DATADOC_SCHEDULE_PREFIX = "run_data_doc_"

Expand Down Expand Up @@ -194,6 +195,14 @@ def get_scheduled_data_docs_by_user(
if "name" in filters:
query = query.filter(DataDoc.title.contains(filters.get("name")))

if filters.get("status") is not None:
query = query.filter(TaskSchedule.enabled == filters.get("status"))

if filters.get("board_ids"):
query = query.join(BoardItem, BoardItem.data_doc_id == DataDoc.id).filter(
BoardItem.parent_board_id.in_(filters.get("board_ids"))
)

count = query.count()
docs_with_schedules = query.offset(offset).limit(limit).all()
docs_with_schedules_and_records = get_task_run_record_run_with_schedule(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,7 @@ import { useField, useFormikContext } from 'formik';
import React, { useMemo } from 'react';

import { SimpleField } from 'ui/FormikField/SimpleField';

interface OptionsType {
value: string;
key: string;
hidden?: boolean;
}
import { OptionsType } from 'const/options';

export const EnvironmentSelection = ({
options = [],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React, { useMemo } from 'react';
import { useSelector } from 'react-redux';
import { IStoreState } from 'redux/store/types';
import { SimpleField } from 'ui/FormikField/SimpleField';
import { IBoard } from 'const/board';
import { IOption } from 'lib/utils/react-select';
import { OptionTypeBase } from 'react-select';

export interface IDataDocBoardsSelectProps {
onChange: (params: OptionTypeBase[]) => void;
value: IOption<number>[];
label?: string;
name: string;
}

export const DataDocBoardsSelect: React.FC<IDataDocBoardsSelectProps> = ({
onChange,
value,
label,
name,
}) => {
const boardById: Record<string, IBoard> = useSelector(
(state: IStoreState) => state.board.boardById
);

const boardOptions: IOption<number>[] = useMemo(() => {
return Object.values(boardById).map((board) => ({
value: board.id,
label: board.name,
}));
}, [boardById]);

const selectedBoards: IOption<number>[] = useMemo(
() =>
boardOptions.filter((board) =>
value.map((v) => v.value).includes(board.value)
),
[]
);

return (
<SimpleField
label={label}
name={name}
value={value}
defaultValue={selectedBoards}
options={boardOptions}
onChange={onChange}
optionSelector={(v: IOption<number>) => v}
closeMenuOnSelect={false}
hideSelectedOptions={false}
isMulti
type="react-select"
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React, { useEffect } from 'react';
import { Formik } from 'formik';
import { debounce } from 'lodash';
import { useDispatch } from 'react-redux';
import { OptionTypeBase } from 'react-select';
import { Popover } from 'ui/Popover/Popover';
import { SimpleField } from 'ui/FormikField/SimpleField';
import { DataDocBoardsSelect } from './DataDocBoardsSelect';
import { IScheduledDocFilters } from 'redux/scheduledDataDoc/types';
import { fetchBoards } from 'redux/board/action';
import { UpdateFiltersType, StatusType } from 'const/schedFiltersType';

const enabledOptions = [
{ key: 'all', value: 'All' },
{ key: 'enabled', value: 'Enabled' },
{ key: 'disabled', value: 'Disabled' },
];

export const DataDocSchedsFilters: React.FC<{
setShowSearchFilter: (arg: boolean) => void;
updateFilters: (arg: UpdateFiltersType) => void;
filterButton: HTMLAnchorElement | null;
filters: IScheduledDocFilters;
}> = ({ setShowSearchFilter, filters, updateFilters, filterButton }) => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchBoards());
}, []);
const handleUpdateStatus = React.useCallback((value: StatusType) => {
updateFilters({
key: 'status',
value,
});
}, []);

const handleUpdateList = React.useCallback(
debounce((params: OptionTypeBase[]) => {
updateFilters({
key: 'board_ids',
value: params,
});
}, 500),
[]
);
return (
<Popover
layout={['bottom', 'right']}
onHide={() => {
setShowSearchFilter(false);
}}
anchor={filterButton}
>
<div className="DataTableNavigatorSearchFilter">
<div className="DataDocScheduleList_select-wrapper">
<Formik
initialValues={{
status: '',
board_ids: [],
}}
onSubmit={() => undefined} // Just for fixing ts
>
{({}) => {
return (
<>
<SimpleField
label="Status"
type="select"
name="status"
options={enabledOptions}
onChange={handleUpdateStatus}
value={filters.status}
/>
<DataDocBoardsSelect
label="Lists"
name="board_ids"
value={filters.board_ids}
onChange={handleUpdateList}
/>
</>
);
}}
</Formik>
</div>
</div>
</Popover>
);
};
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import React, { useEffect, useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';

import React, {
useEffect,
useMemo,
useState,
useRef,
useCallback,
} from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { Dispatch, IStoreState } from 'redux/store/types';
import { getScheduledDocs } from 'redux/scheduledDataDoc/action';
import { IScheduledDocFilters } from 'redux/scheduledDataDoc/types';
import { Dispatch, IStoreState } from 'redux/store/types';
import { Checkbox } from 'ui/Checkbox/Checkbox';
import { Container } from 'ui/Container/Container';
import { DebouncedInput } from 'ui/DebouncedInput/DebouncedInput';
import { Pagination } from 'ui/Pagination/Pagination';
import { PrettyNumber } from 'ui/PrettyNumber/PrettyNumber';
import { AccentText, EmptyText } from 'ui/StyledText/StyledText';
import { IconButton } from 'ui/Button/IconButton';

import { DataDocScheduleItem } from './DataDocScheduleItem';
import { DataDocSchedsFilters } from './DataDocSchedsFilters';
import { UpdateFiltersType } from 'const/schedFiltersType';

import './DataDocScheduleList.scss';

Expand All @@ -24,34 +32,54 @@ function useDataDocScheduleFiltersAndPagination() {
} = useSelector((state: IStoreState) => state.scheduledDocs);

const [docName, setDocName] = useState(initFilters.name ?? '');
const [scheduledOnly, setScheduledOnly] = useState(
initFilters.scheduled_only ?? false
);

const [extraFilters, setExtraFilters] = useState<IScheduledDocFilters>({
status: initFilters.status ?? null,
board_ids: initFilters.board_ids ?? [],
scheduled_only: initFilters.scheduled_only ?? false,
});

const updateFilters = useCallback(({ key, value }: UpdateFiltersType) => {
setExtraFilters((state) => ({
...state,
[key]: value,
}));
}, []);

const filters: IScheduledDocFilters = useMemo(() => {
const _filters: IScheduledDocFilters = {};
if (docName) {
_filters.name = docName;
}
if (scheduledOnly) {

if (extraFilters.scheduled_only) {
_filters.scheduled_only = true;
}

if (extraFilters.status !== null) {
_filters.status = extraFilters.status;
}

if (extraFilters.board_ids) {
_filters.board_ids = extraFilters.board_ids;
}

return _filters;
}, [docName, scheduledOnly]);
}, [docName, extraFilters]);

const [page, setPage] = useState(initPage);
const [pageSize, setPageSize] = useState(initPageSize);

return {
filters,
setDocName,
setScheduledOnly,

numberOfResults,
page,
setPage,
pageSize,
setPageSize,
updateFilters,
};
}

Expand Down Expand Up @@ -92,7 +120,7 @@ const DataDocScheduleList: React.FC = () => {

filters,
setDocName,
setScheduledOnly,
updateFilters,
} = useDataDocScheduleFiltersAndPagination();

const dataDocsWithSchedule = useDataDocWithSchedules(
Expand All @@ -102,6 +130,24 @@ const DataDocScheduleList: React.FC = () => {
);

const totalPages = Math.ceil(numberOfResults / pageSize);
const [showSearchFilter, setShowSearchFilter] = useState(false);
const filterButtonRef = useRef<HTMLAnchorElement>();

const handleUpdateScheduledOnly = React.useCallback((value: boolean) => {
updateFilters({
key: 'scheduled_only',
value,
});
}, []);

const searchFiltersPickerDOM = showSearchFilter && (
<DataDocSchedsFilters
filters={filters}
updateFilters={updateFilters}
setShowSearchFilter={setShowSearchFilter}
filterButton={filterButtonRef?.current}
/>
);

return (
<Container>
Expand All @@ -116,11 +162,23 @@ const DataDocScheduleList: React.FC = () => {
}}
/>
</div>

<IconButton
ref={filterButtonRef}
className="mr8"
size={'18px'}
noPadding
onClick={() => {
setShowSearchFilter(true);
}}
icon="Sliders"
/>
{searchFiltersPickerDOM}
<div>
<Checkbox
title="Scheduled DataDocs Only"
value={filters.scheduled_only}
onChange={setScheduledOnly}
onChange={handleUpdateScheduledOnly}
/>
</div>
</div>
Expand Down
5 changes: 5 additions & 0 deletions querybook/webapp/const/options.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface OptionsType {
value: string;
key: string;
hidden?: boolean;
}
8 changes: 8 additions & 0 deletions querybook/webapp/const/schedFiltersType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { OptionTypeBase } from 'react-select';

export type StatusType = 'all' | 'enabled' | 'disabled';

export type UpdateFiltersType =
| { key: 'status'; value: StatusType }
| { key: 'scheduled_only'; value: boolean }
| { key: 'board_ids'; value: OptionTypeBase[] };
24 changes: 23 additions & 1 deletion querybook/webapp/redux/scheduledDataDoc/action.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
import { DataDocScheduleResource } from 'resource/dataDoc';
import { IOption } from 'lib/utils/react-select';

import { IScheduledDoc, IScheduledDocFilters, ThunkResult } from './types';
import { StatusType } from 'const/schedFiltersType';

function reformatBoardIds(boardIds: IOption<number>[]): number[] | null {
if (boardIds.length) {
return boardIds.map((board) => board.value);
}

return null;
}

function reformatStatus(status: StatusType): boolean | null {
if (status === 'all') {
return null;
}

return status === 'enabled';
}

export function getScheduledDocs({
paginationPage,
Expand All @@ -25,7 +43,11 @@ export function getScheduledDocs({
envId,
limit: pageSize,
offset: page * pageSize,
filters,
filters: {
...filters,
status: reformatStatus(filters.status),
board_ids: reformatBoardIds(filters.board_ids),
},
});

dispatch({
Expand Down
1 change: 1 addition & 0 deletions querybook/webapp/redux/scheduledDataDoc/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const initialState: Readonly<IScheduledDataDocState> = {
pageSize: 20,
numberOfResults: 0,
filters: {
status: 'all',
scheduled_only: true,
},
};
Expand Down
Loading

0 comments on commit edfaac7

Please sign in to comment.