Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

switch tick filters to contained set rather than every permutation #23781

Merged
merged 1 commit into from
Aug 21, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 71 additions & 55 deletions js_modules/dagster-ui/packages/ui-core/src/instigation/TickHistory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ import 'chartjs-adapter-date-fns';
import {gql, useQuery} from '@apollo/client';
import {
Box,
Button,
ButtonLink,
Caption,
Checkbox,
Colors,
CursorHistoryControls,
FontFamily,
Icon,
IconWrapper,
Menu,
MenuItem,
NonIdealState,
Select,
Spinner,
Subheading,
Table,
Expand Down Expand Up @@ -55,24 +58,22 @@ Chart.register(zoomPlugin);
type InstigationTick = HistoryTickFragment;

const PAGE_SIZE = 25;
interface ShownStatusState {
[InstigationTickStatus.SUCCESS]: boolean;
[InstigationTickStatus.FAILURE]: boolean;
[InstigationTickStatus.STARTED]: boolean;
[InstigationTickStatus.SKIPPED]: boolean;

enum TickStatusDisplay {
ALL,
FAILED,
SUCCESS,
}

const DEFAULT_SHOWN_STATUS_STATE = {
[InstigationTickStatus.SUCCESS]: true,
[InstigationTickStatus.FAILURE]: true,
[InstigationTickStatus.STARTED]: true,
[InstigationTickStatus.SKIPPED]: true,
};
const STATUS_TEXT_MAP = {
[InstigationTickStatus.SUCCESS]: 'Requested',
[InstigationTickStatus.FAILURE]: 'Failed',
[InstigationTickStatus.STARTED]: 'In progress',
[InstigationTickStatus.SKIPPED]: 'Skipped',
const STATUS_DISPLAY_MAP = {
[TickStatusDisplay.ALL]: [
InstigationTickStatus.SUCCESS,
InstigationTickStatus.FAILURE,
InstigationTickStatus.STARTED,
InstigationTickStatus.SKIPPED,
],
[TickStatusDisplay.FAILED]: [InstigationTickStatus.FAILURE],
[TickStatusDisplay.SUCCESS]: [InstigationTickStatus.SUCCESS],
};

export const TicksTable = ({
Expand All @@ -88,33 +89,15 @@ export const TicksTable = ({
setTimerange?: (range?: [number, number]) => void;
setParentStatuses?: (statuses?: InstigationTickStatus[]) => void;
}) => {
const [shownStates, setShownStates] = useQueryPersistedState<ShownStatusState>({
encode: (states) => {
const queryState = {};
Object.keys(states).map((state) => {
(queryState as any)[state.toLowerCase()] = String(states[state as keyof typeof states]);
});
return queryState;
},
decode: (queryState) => {
const status: ShownStatusState = {...DEFAULT_SHOWN_STATUS_STATE};
Object.keys(DEFAULT_SHOWN_STATUS_STATE).forEach((state) => {
if (state.toLowerCase() in queryState) {
(status as any)[state] = !(queryState[state.toLowerCase()] === 'false');
}
});

return status;
},
const [tickStatus, setTickStatus] = useQueryPersistedState<TickStatusDisplay>({
queryKey: 'status',
defaults: {status: TickStatusDisplay.ALL},
});

const instigationSelector = {...repoAddressToSelector(repoAddress), name};
const statuses = React.useMemo(
() =>
Object.keys(shownStates)
.filter((status) => shownStates[status as keyof typeof shownStates])
.map((status) => status as InstigationTickStatus),
[shownStates],
() => STATUS_DISPLAY_MAP[tickStatus] || STATUS_DISPLAY_MAP[TickStatusDisplay.ALL],
[tickStatus],
);

const {queryResult, paginationProps} = useCursorPaginatedQuery<
Expand Down Expand Up @@ -205,20 +188,10 @@ export const TicksTable = ({

const {instigationType} = data.instigationStateOrError;

if (!ticks.length && statuses.length === Object.keys(DEFAULT_SHOWN_STATUS_STATE).length) {
if (!ticks.length && tickStatus === TickStatusDisplay.ALL) {
return null;
}

const StatusFilter = ({status}: {status: InstigationTickStatus}) => (
<Checkbox
label={STATUS_TEXT_MAP[status]}
checked={shownStates[status]}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setShownStates({...shownStates, [status]: e.target.checked});
}}
/>
);

return (
<>
{logTick ? (
Expand All @@ -232,10 +205,7 @@ export const TicksTable = ({
<Box flex={{direction: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
{tabs}
<Box flex={{direction: 'row', gap: 16}}>
<StatusFilter status={InstigationTickStatus.STARTED} />
<StatusFilter status={InstigationTickStatus.SUCCESS} />
<StatusFilter status={InstigationTickStatus.FAILURE} />
<StatusFilter status={InstigationTickStatus.SKIPPED} />
<StatusFilter status={tickStatus} onChange={setTickStatus} />
</Box>
</Box>
</Box>
Expand Down Expand Up @@ -277,6 +247,52 @@ export const TicksTable = ({
);
};

const StatusFilter = ({
status,
onChange,
}: {
status: TickStatusDisplay;
onChange: (value: TickStatusDisplay) => void;
}) => {
const items = [
{key: TickStatusDisplay.ALL, label: 'All ticks'},
{key: TickStatusDisplay.SUCCESS, label: 'Requested'},
{key: TickStatusDisplay.FAILED, label: 'Failed'},
];
const activeItem = items.find(({key}) => key === status);
return (
<Select<(typeof items)[0]>
popoverProps={{position: 'bottom-right'}}
filterable={false}
activeItem={activeItem}
items={items}
itemRenderer={(item, props) => {
return (
<MenuItem
active={props.modifiers.active}
onClick={props.handleClick}
key={item.key}
text={item.label}
style={{width: '300px'}}
/>
);
}}
itemListRenderer={({renderItem, filteredItems}) => {
const renderedItems = filteredItems.map(renderItem).filter(Boolean);
return <Menu>{renderedItems}</Menu>;
}}
onItemSelect={(item) => onChange(item.key)}
>
<Button
rightIcon={<Icon name="arrow_drop_down" />}
style={{minWidth: '200px', display: 'flex', justifyContent: 'space-between'}}
>
{activeItem?.label}
</Button>
</Select>
);
};

export const TickHistoryTimeline = ({
name,
repoAddress,
Expand Down