Skip to content

Commit

Permalink
[ui] Include a Backfills tab on the new runs feed
Browse files Browse the repository at this point in the history
  • Loading branch information
bengotow committed Dec 11, 2024
1 parent 5b628db commit dcbdd35
Show file tree
Hide file tree
Showing 18 changed files with 264 additions and 218 deletions.
4 changes: 2 additions & 2 deletions js_modules/dagster-ui/packages/ui-core/client.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const ContentRoot = memo(() => {
<Route path="/runs/b/:backfillId" key="1">
<RunsFeedBackfillPage />
</Route>,
<Route path={['/runs', '/runs/scheduled']} exact key="2">
<Route path={['/runs', '/runs/scheduled', '/backfills']} exact key="2">
<RunsFeedRoot />
</Route>,
]}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions js_modules/dagster-ui/packages/ui-core/src/graphql/types.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {Link} from 'react-router-dom';

import {gql} from '../apollo-client';
import {BACKFILL_TABLE_FRAGMENT, BackfillTable} from './backfill/BackfillTable';
import {useBulkActionStatusFilter} from './useBulkActionStatusFilter';
import {PythonErrorInfo} from '../app/PythonErrorInfo';
import {useStateWithStorage} from '../hooks/useStateWithStorage';
import {
Expand All @@ -29,39 +30,9 @@ import {useQueryPersistedState} from '../hooks/useQueryPersistedState';
import {DaemonNotRunningAlert, useIsBackfillDaemonHealthy} from '../partitions/BackfillMessaging';
import {useCursorPaginatedQuery} from '../runs/useCursorPaginatedQuery';
import {useFilters} from '../ui/BaseFilters';
import {useStaticSetFilter} from '../ui/BaseFilters/useStaticSetFilter';

const PAGE_SIZE = 10;

const labelForBackfillStatus = (key: BulkActionStatus) => {
switch (key) {
case BulkActionStatus.CANCELED:
return 'Canceled';
case BulkActionStatus.CANCELING:
return 'Canceling';
case BulkActionStatus.COMPLETED:
return 'Completed';
case BulkActionStatus.FAILED:
return 'Failed';
case BulkActionStatus.REQUESTED:
return 'In progress';
case BulkActionStatus.COMPLETED_SUCCESS:
return 'Success';
case BulkActionStatus.COMPLETED_FAILED:
return 'Failed';
}
};

const backfillStatusValues = Object.keys(BulkActionStatus).map((key) => {
const status = key as BulkActionStatus;
const label = labelForBackfillStatus(status);
return {
label,
value: status,
match: [status, label],
};
});

export const InstanceBackfills = () => {
useTrackPageView();
useDocumentTitle('Overview | Backfills');
Expand All @@ -70,18 +41,8 @@ export const InstanceBackfills = () => {
encode: (vals) => ({status: vals.size ? Array.from(vals).join(',') : undefined}),
decode: (qs) => new Set((qs.status?.split(',') as BulkActionStatus[]) || []),
});
const statusFilter = useStaticSetFilter<BulkActionStatus>({
name: 'Status',
icon: 'status',
allValues: backfillStatusValues,
allowMultipleSelections: false,
closeOnSelect: true,
renderLabel: ({value}) => <div>{labelForBackfillStatus(value)}</div>,
getStringValue: (status) => labelForBackfillStatus(status),
state: statusState,
onStateChanged: setStatusState,
});

const statusFilter = useBulkActionStatusFilter(statusState, setStatusState);
const {button, activeFiltersJsx} = useFilters({filters: [statusFilter]});

const {queryResult, paginationProps} = useCursorPaginatedQuery<
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {BulkActionStatus} from '../graphql/types';
import {useStaticSetFilter} from '../ui/BaseFilters/useStaticSetFilter';

const labelForBackfillStatus = (key: BulkActionStatus) => {
switch (key) {
case BulkActionStatus.CANCELED:
return 'Canceled';
case BulkActionStatus.CANCELING:
return 'Canceling';
case BulkActionStatus.COMPLETED:
return 'Completed';
case BulkActionStatus.FAILED:
return 'Failed';
case BulkActionStatus.REQUESTED:
return 'In progress';
case BulkActionStatus.COMPLETED_SUCCESS:
return 'Success';
case BulkActionStatus.COMPLETED_FAILED:
return 'Failed';
}
};

export function useBulkActionStatusFilter(
state: Set<BulkActionStatus> | BulkActionStatus[],
onStateChanged: (state: Set<BulkActionStatus>) => void,
) {
const backfillStatusValues = Object.keys(BulkActionStatus).map((key) => {
const status = key as BulkActionStatus;
const label = labelForBackfillStatus(status);
return {
label,
value: status,
match: [status, label],
};
});

const statusFilter = useStaticSetFilter<BulkActionStatus>({
name: 'Status',
icon: 'status',
allValues: backfillStatusValues,
allowMultipleSelections: false,
closeOnSelect: true,
renderLabel: ({value}) => <div>{labelForBackfillStatus(value)}</div>,
getStringValue: (status) => labelForBackfillStatus(status),
state,
onStateChanged,
});

return statusFilter;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import {Box, ButtonLink, Tag, TokenizingFieldValue, tokenToString} from '@dagster-io/ui-components';
import {
Box,
ButtonLink,
Checkbox,
Tag,
TokenizingFieldValue,
tokenToString,
} from '@dagster-io/ui-components';
import {useCallback, useMemo} from 'react';
import {useParams} from 'react-router-dom';

Expand All @@ -11,11 +18,11 @@ import {
useQueryRefreshAtInterval,
} from '../app/QueryRefresh';
import {useTrackPageView} from '../app/analytics';
import {RunsFilter} from '../graphql/types';
import {RunsFeedView, RunsFilter} from '../graphql/types';
import {useQueryPersistedState} from '../hooks/useQueryPersistedState';
import {DagsterTag} from '../runs/RunTag';
import {RunsQueryRefetchContext} from '../runs/RunUtils';
import {RunsFeedError} from '../runs/RunsFeedError';
import {useIncludeRunsFromBackfillsOption} from '../runs/RunsFeedRoot';
import {RunsFeedTable} from '../runs/RunsFeedTable';
import {
RunFilterToken,
Expand Down Expand Up @@ -59,7 +66,10 @@ export const PipelineRunsFeedRoot = (props: {repoAddress?: RepoAddress}) => {
].filter(Boolean) as TokenizingFieldValue[];
}, [isJob, pipelineName, snapshotId]);

const includeRunsFromBackfills = useIncludeRunsFromBackfillsOption();
const [view, setView] = useQueryPersistedState<RunsFeedView>({
queryKey: 'view',
defaults: {view: RunsFeedView.ROOTS},
});

const runsFilter: RunsFilter = useMemo(() => {
const allTokens = [...filterTokens, ...permanentTokens];
Expand All @@ -83,11 +93,7 @@ export const PipelineRunsFeedRoot = (props: {repoAddress?: RepoAddress}) => {
[filterTokens, setFilterTokens],
);

const {entries, paginationProps, queryResult} = useRunsFeedEntries(
runsFilter,
'all',
includeRunsFromBackfills.value,
);
const {entries, paginationProps, queryResult} = useRunsFeedEntries(runsFilter, 'all', view);

const refreshState = useQueryRefreshAtInterval(queryResult, FIFTEEN_SECONDS);

Expand All @@ -105,7 +111,13 @@ export const PipelineRunsFeedRoot = (props: {repoAddress?: RepoAddress}) => {
padding={{right: 16}}
>
{button}
{includeRunsFromBackfills.element}
<Checkbox
label={<span>Show runs within backfills</span>}
checked={view === RunsFeedView.RUNS}
onChange={() => {
setView(view === RunsFeedView.RUNS ? RunsFeedView.ROOTS : RunsFeedView.RUNS);
}}
/>
<div style={{flex: 1}} />
<QueryRefreshCountdown refreshState={refreshState} />
</Box>
Expand Down
45 changes: 17 additions & 28 deletions js_modules/dagster-ui/packages/ui-core/src/runs/RunsFeedRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
useQueryRefreshAtInterval,
} from '../app/QueryRefresh';
import {useTrackPageView} from '../app/analytics';
import {RunsFeedView} from '../graphql/types';
import {useQueryPersistedState} from '../hooks/useQueryPersistedState';
import {Loading} from '../ui/Loading';

Expand All @@ -36,33 +37,17 @@ const filters: RunFilterTokenType[] = [
'status',
];

export function useIncludeRunsFromBackfillsOption() {
const [value, setValue] = useQueryPersistedState<boolean>({
queryKey: 'show_runs_within_backfills',
defaults: {show_runs_within_backfills: false},
});

return {
value,
setValue,
element: (
<Checkbox
label={<span>Show runs within backfills</span>}
checked={value}
onChange={() => {
setValue(!value);
}}
/>
),
};
}
export const RunsFeedRoot = () => {
useTrackPageView();

const [filterTokens, setFilterTokens] = useQueryPersistedRunFilters();
const filter = runsFilterForSearchTokens(filterTokens);
const [view, setView] = useQueryPersistedState<RunsFeedView>({
queryKey: 'view',
defaults: {view: RunsFeedView.ROOTS},
});

const currentTab = useSelectedRunsFeedTab(filterTokens);
const currentTab = useSelectedRunsFeedTab(filterTokens, view);
const staticStatusTags = currentTab !== 'all';

const [statusTokens, nonStatusTokens] = partition(
Expand Down Expand Up @@ -104,16 +89,12 @@ export const RunsFeedRoot = () => {
enabledFilters: filters,
});

const includeRunsFromBackfills = useIncludeRunsFromBackfillsOption();
const {tabs, queryResult: runQueryResult} = useRunsFeedTabs(
filter,
includeRunsFromBackfills.value,
);
const {tabs, queryResult: runQueryResult} = useRunsFeedTabs(filter, view);

const {entries, paginationProps, queryResult, scheduledQueryResult} = useRunsFeedEntries(
filter,
currentTab,
includeRunsFromBackfills.value,
view,
);
const refreshState = useQueryRefreshAtInterval(
currentTab === 'scheduled' ? scheduledQueryResult : queryResult,
Expand All @@ -126,7 +107,15 @@ export const RunsFeedRoot = () => {
const actionBarComponents = (
<Box flex={{direction: 'row', gap: 8, alignItems: 'center'}}>
{button}
{includeRunsFromBackfills.element}

<Checkbox
label={<span>Show runs within backfills</span>}
checked={currentTab === 'queued' || view === RunsFeedView.RUNS}
disabled={currentTab === 'queued' || currentTab === 'backfills'}
onChange={() => {
setView(view === RunsFeedView.RUNS ? RunsFeedView.ROOTS : RunsFeedView.RUNS);
}}
/>
</Box>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
} from './types/RunsFeedTableEntryFragment.types';
import {useRunsFeedEntries} from './useRunsFeedEntries';
import {FIFTEEN_SECONDS, useQueryRefreshAtInterval} from '../app/QueryRefresh';
import {RunsFilter} from '../graphql/types';
import {RunsFeedView, RunsFilter} from '../graphql/types';
import {useSelectionReducer} from '../hooks/useSelectionReducer';
import {CheckAllBox} from '../ui/CheckAllBox';
import {IndeterminateLoadingBar} from '../ui/IndeterminateLoadingBar';
Expand Down Expand Up @@ -238,7 +238,11 @@ export const RunsFeedTableWithFilters = ({
RunsFeedTableProps,
'actionBarComponents' | 'belowActionBarComponents' | 'emptyState' | 'hideTags' | 'scroll'
>) => {
const {entries, paginationProps, queryResult} = useRunsFeedEntries(filter, 'all', true);
const {entries, paginationProps, queryResult} = useRunsFeedEntries(
filter,
'all',
RunsFeedView.RUNS,
);
const refreshState = useQueryRefreshAtInterval(queryResult, FIFTEEN_SECONDS);

function content() {
Expand Down
Loading

0 comments on commit dcbdd35

Please sign in to comment.