Skip to content

Commit

Permalink
Feat: add enable and list filters for Scheds
Browse files Browse the repository at this point in the history
  • Loading branch information
alexVasylenko committed Nov 10, 2022
1 parent 0cbbb42 commit 458bae3
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 27 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 "status" in filters:
query = query.filter(TaskSchedule.enabled == filters.get("status"))

if filters.get("list_ids"):
query = query.join(BoardItem, BoardItem.data_doc_id == DataDoc.id).filter(
BoardItem.parent_board_id.in_(filters.get("list_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
153 changes: 140 additions & 13 deletions querybook/webapp/components/DataDocScheduleList/DataDocScheduleList.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,41 @@
import React, { useEffect, useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';

import React, {
useEffect,
useMemo,
useState,
useRef,
useCallback,
} from 'react';
import { debounce } from 'lodash';
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 { Popover } from 'ui/Popover/Popover';
import { fetchBoards } from 'redux/board/action';
import { queryDataDocFiltersSelector } from 'redux/dataDoc/selector';

import { DataDocScheduleItem } from './DataDocScheduleItem';
import Select, { OptionTypeBase } from 'react-select';
import { makeReactSelectStyle } from 'lib/utils/react-select';
import { makeSelectOptions, Select as SimpleSelect } from 'ui/Select/Select';
import { DataDocScheduleSelectionList } from './DataDocScheduleSelectionList';

import './DataDocScheduleList.scss';

const enabledOptions = [
{ key: '', value: 'All' },
{ key: true, value: 'Enabled' },
{ key: false, value: 'Disabled' },
];

function useDataDocScheduleFiltersAndPagination() {
const {
page: initPage,
Expand All @@ -24,34 +45,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: null,
list_ids: [],
scheduled_only: initFilters.scheduled_only ?? false,
});

const updateFilters = useCallback((params) => {
setExtraFilters((state) => ({
...state,
...params,
}));
}, []);

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.list_ids) {
_filters.list_ids = extraFilters.list_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 All @@ -66,7 +107,10 @@ function useDataDocWithSchedules(
getScheduledDocs({
paginationPage: page,
paginationPageSize: pageSize,
paginationFilter: filters,
paginationFilter: {
...filters,
list_ids: filters.list_ids?.map((l) => l.value),
},
})
);
}, [page, pageSize, filters, dispatch]);
Expand All @@ -92,7 +136,7 @@ const DataDocScheduleList: React.FC = () => {

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

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

const totalPages = Math.ceil(numberOfResults / pageSize);
const [showSearchFilter, setShowSearchFilter] = useState(false);
const filterButtonRef = useRef();
const dispatch = useDispatch();
const boards = useSelector(queryDataDocFiltersSelector);
useEffect(() => {
dispatch(fetchBoards());
}, []);

const handleUpdateList = React.useCallback(
debounce((params: OptionTypeBase[]) => {
updateFilters({
list_ids: params,
});
}, 500),
[]
);

const handleUpdateStatus = React.useCallback(
({ target: { value } }: { target: { value: string } }) => {
updateFilters({
status: value === '' ? null : value === 'true',
});
},
[]
);

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

const reactSelectStyle = makeReactSelectStyle(true);

const searchFiltersPickerDOM = showSearchFilter && (
<Popover
layout={['bottom', 'right']}
onHide={() => {
setShowSearchFilter(false);
}}
anchor={filterButtonRef.current}
>
<div className="DataTableNavigatorSearchFilter">
<div className="DataDocScheduleList_select-wrapper">
<DataDocScheduleSelectionList label="Status">
<SimpleSelect
value={filters.status}
onChange={handleUpdateStatus}
>
{makeSelectOptions(enabledOptions)}
</SimpleSelect>
</DataDocScheduleSelectionList>
<DataDocScheduleSelectionList label="Lists">
<Select
styles={reactSelectStyle}
label="Lists"
value={filters.list_ids}
options={boards}
onChange={handleUpdateList}
closeMenuOnSelect={false}
hideSelectedOptions={false}
isMulti
/>
</DataDocScheduleSelectionList>
</div>
</div>
</Popover>
);

return (
<Container>
Expand All @@ -116,11 +231,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
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import {
FormFieldLabelSection,
FormFieldInputSection,
} from 'ui/Form/FormField';

export const DataDocScheduleSelectionList = ({ label, children }) => {
return (
<div className="FormField">
<FormFieldLabelSection>{label}</FormFieldLabelSection>
<FormFieldInputSection>{children}</FormFieldInputSection>
</div>
);
};
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;
}
9 changes: 9 additions & 0 deletions querybook/webapp/redux/dataDoc/selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,12 @@ export const queryCellSelector = createSelector(dataDocCellsSelector, (cells) =>
};
})
);

export const queryDataDocFiltersSelector = createSelector(
(state: IStoreState) => state.board.boardById,
(boardById) =>
Object.values(boardById).map((board) => ({
value: board.id,
label: board.name,
}))
);
8 changes: 6 additions & 2 deletions querybook/webapp/redux/scheduledDataDoc/action.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { DataDocScheduleResource } from 'resource/dataDoc';

import { IScheduledDoc, IScheduledDocFilters, ThunkResult } from './types';
import {
IScheduledDoc,
ITransformedScheduledDocFilters,
ThunkResult,
} from './types';

export function getScheduledDocs({
paginationPage,
Expand All @@ -9,7 +13,7 @@ export function getScheduledDocs({
}: {
paginationPage?: number;
paginationPageSize?: number;
paginationFilter?: IScheduledDocFilters;
paginationFilter?: ITransformedScheduledDocFilters;
}): ThunkResult<Promise<IScheduledDoc[]>> {
return async (dispatch, getState) => {
const envId = getState().environment.currentEnvironmentId;
Expand Down
18 changes: 15 additions & 3 deletions querybook/webapp/redux/scheduledDataDoc/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,23 @@ import { IDataDoc } from 'const/datadoc';
import { ITaskSchedule, ITaskStatusRecord } from 'const/schedule';

import { IStoreState } from '../store/types';
import { OptionsType } from 'const/options';

export interface IScheduledDocFilters {
interface IBasicScheduledDocFilters {
name?: string;
scheduled_only?: boolean;
status?: boolean;
}

export interface IScheduledDocFilters extends IBasicScheduledDocFilters {
list_ids?: OptionsType[];
}

export interface ITransformedScheduledDocFilters
extends IBasicScheduledDocFilters {
list_ids?: string[];
}

export interface IScheduledDoc {
doc: IDataDoc;
last_record?: ITaskStatusRecord;
Expand All @@ -26,7 +38,7 @@ export interface IReceiveDocWithScheduleAction extends Action {
total: number;
page: number;
pageSize: number;
filters: IScheduledDocFilters;
filters: ITransformedScheduledDocFilters;
};
}

Expand All @@ -50,5 +62,5 @@ export interface IScheduledDataDocState {
numberOfResults: number;
page: number;
pageSize: number;
filters: IScheduledDocFilters;
filters: ITransformedScheduledDocFilters;
}
4 changes: 2 additions & 2 deletions querybook/webapp/resource/dataDoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import dataDocSocket from 'lib/data-doc/datadoc-socketio';
import ds from 'lib/datasource';
import {
IScheduledDoc,
IScheduledDocFilters,
ITransformedScheduledDocFilters,
} from 'redux/scheduledDataDoc/types';

export const DataDocResource = {
Expand Down Expand Up @@ -188,7 +188,7 @@ export const DataDocScheduleResource = {
envId: number;
limit: number;
offset: number;
filters: IScheduledDocFilters;
filters: ITransformedScheduledDocFilters;
}) =>
ds.fetch<{ docs: IScheduledDoc[]; count: number }>(
'/datadoc/scheduled/',
Expand Down
2 changes: 1 addition & 1 deletion querybook/webapp/ui/Form/FormField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export const FormField: React.FunctionComponent<IFormFieldProps> = ({
);
};

const FormFieldLabelSection: React.FunctionComponent<
export const FormFieldLabelSection: React.FunctionComponent<
IFormFieldSectionProps
> = ({ children, className = '' }) => (
<AccentText
Expand Down

0 comments on commit 458bae3

Please sign in to comment.