From 87fbdea6213f2e764be0a87ad2a0364aee081730 Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Fri, 16 Feb 2024 00:28:22 -0500 Subject: [PATCH 01/10] so far --- .../src/components/CollapsibleSection.tsx | 37 ++ .../src/components/VirtualizedTable.tsx | 2 +- .../packages/ui-components/src/index.ts | 1 + .../src/asset-data/AssetLiveDataProvider.tsx | 2 +- .../src/assets/AssetFeatureContext.tsx | 2 +- .../packages/ui-core/src/assets/AssetTabs.tsx | 1 - .../packages/ui-core/src/assets/AssetView.tsx | 1 - .../asset-checks/AssetCheckStatusTag.tsx | 2 +- .../src/assets/asset-checks/AssetChecks.tsx | 364 ++++++++++++++---- .../assets/asset-checks/AssetChecksBanner.tsx | 9 +- .../ui-core/src/assets/asset-checks/util.tsx | 61 +++ .../src/nav/useRepositoryLocationReload.tsx | 11 +- 12 files changed, 403 insertions(+), 90 deletions(-) create mode 100644 js_modules/dagster-ui/packages/ui-components/src/components/CollapsibleSection.tsx create mode 100644 js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/util.tsx diff --git a/js_modules/dagster-ui/packages/ui-components/src/components/CollapsibleSection.tsx b/js_modules/dagster-ui/packages/ui-components/src/components/CollapsibleSection.tsx new file mode 100644 index 0000000000000..692f0525c2c0e --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-components/src/components/CollapsibleSection.tsx @@ -0,0 +1,37 @@ +import React from 'react'; + +import {Box} from './Box'; +import {Icon} from './Icon'; + +export const CollapsibleSection = ({ + header, + headerWrapperProps, + children, + isInitiallyCollapsed = false, +}: { + header: React.ReactNode; + headerWrapperProps?: React.ComponentProps; + children: React.ReactNode; + isInitiallyCollapsed?: boolean; +}) => { + const [isCollapsed, setIsCollapsed] = React.useState(isInitiallyCollapsed); + return ( + + { + setIsCollapsed(!isCollapsed); + headerWrapperProps?.onClick?.(); + }} + > + +
{header}
+
+ {isCollapsed ? null : children} +
+ ); +}; diff --git a/js_modules/dagster-ui/packages/ui-components/src/components/VirtualizedTable.tsx b/js_modules/dagster-ui/packages/ui-components/src/components/VirtualizedTable.tsx index 327670c149937..0261036dab8ed 100644 --- a/js_modules/dagster-ui/packages/ui-components/src/components/VirtualizedTable.tsx +++ b/js_modules/dagster-ui/packages/ui-components/src/components/VirtualizedTable.tsx @@ -52,7 +52,7 @@ export const Inner = styled.div.attrs(({$totalHeight}) => ({ width: 100%; `; -type RowProps = {$height: number; $start: number}; +export type RowProps = {$height: number; $start: number}; export const Row = styled.div.attrs(({$height, $start}) => ({ style: { diff --git a/js_modules/dagster-ui/packages/ui-components/src/index.ts b/js_modules/dagster-ui/packages/ui-components/src/index.ts index 03a4b26a3d10f..980788b9ac15f 100644 --- a/js_modules/dagster-ui/packages/ui-components/src/index.ts +++ b/js_modules/dagster-ui/packages/ui-components/src/index.ts @@ -6,6 +6,7 @@ export * from './components/Button'; export * from './components/ButtonGroup'; export * from './components/ButtonLink'; export * from './components/Checkbox'; +export * from './components/CollapsibleSection'; export * from './components/ConfigEditorDialog'; export * from './components/ConfigEditorWithSchema'; export * from './components/ConfigTypeSchema'; diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-data/AssetLiveDataProvider.tsx b/js_modules/dagster-ui/packages/ui-core/src/asset-data/AssetLiveDataProvider.tsx index 4056f45884c88..8f05021cef6b1 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-data/AssetLiveDataProvider.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-data/AssetLiveDataProvider.tsx @@ -58,7 +58,7 @@ export function useAssetsLiveData( thread: LiveDataThreadID = 'default', ) { return factory.useLiveData( - assetKeys.map((key) => tokenForAssetKey(key)), + React.useMemo(() => assetKeys.map((key) => tokenForAssetKey(key)), [assetKeys]), thread, ); } diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetFeatureContext.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetFeatureContext.tsx index fda68e80cbf45..be61f66d26d46 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetFeatureContext.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetFeatureContext.tsx @@ -14,7 +14,7 @@ export type AssetViewFeatureInput = { type AssetFeatureContextType = { tabBuilder: (input: AssetTabConfigInput) => AssetTabConfig[]; renderFeatureView: (input: AssetViewFeatureInput) => React.ReactNode; - AssetChecksBanner: React.ComponentType>; + AssetChecksBanner: React.ComponentType<{onClose: () => void}>; }; export const AssetFeatureContext = React.createContext({ diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetTabs.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetTabs.tsx index 9b4aacf695f25..b517bcf89fd0a 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetTabs.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetTabs.tsx @@ -75,7 +75,6 @@ export const buildAssetTabMap = (input: AssetTabConfigInput): Record} + icon={} label="Not evaluated" /> ); diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetChecks.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetChecks.tsx index a207e48063123..737af9575ab0f 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetChecks.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetChecks.tsx @@ -1,28 +1,42 @@ import {gql, useQuery} from '@apollo/client'; -import {Body2, Box, Tag} from '@dagster-io/ui-components'; -import {useContext} from 'react'; +import { + Body2, + Box, + Caption, + CollapsibleSection, + Colors, + Icon, + NonIdealState, + Subtitle1, + Subtitle2, + TextInput, + useViewport, +} from '@dagster-io/ui-components'; +import {RowProps} from '@dagster-io/ui-components/src/components/VirtualizedTable'; +import {useVirtualizer} from '@tanstack/react-virtual'; +import React, {useContext} from 'react'; import {Link} from 'react-router-dom'; +import styled from 'styled-components'; -import { - AgentUpgradeRequired, - AssetCheckDetailModal, - MigrationRequired, - NeedsUserCodeUpgrade, - NoChecks, -} from './AssetCheckDetailModal'; +import {AssetCheckStatusTag} from './AssetCheckStatusTag'; import { EXECUTE_CHECKS_BUTTON_ASSET_NODE_FRAGMENT, EXECUTE_CHECKS_BUTTON_CHECK_FRAGMENT, ExecuteChecksButton, } from './ExecuteChecksButton'; -import {ASSET_CHECK_TABLE_FRAGMENT, VirtualizedAssetCheckTable} from './VirtualizedAssetCheckTable'; +import {ASSET_CHECK_TABLE_FRAGMENT} from './VirtualizedAssetCheckTable'; import {AssetChecksQuery, AssetChecksQueryVariables} from './types/AssetChecks.types'; +import {ExecuteChecksButtonCheckFragment} from './types/ExecuteChecksButton.types'; +import {assetCheckStatusDescription, getCheckIcon} from './util'; import {FIFTEEN_SECONDS, useQueryRefreshAtInterval} from '../../app/QueryRefresh'; +import {COMMON_COLLATOR} from '../../app/Util'; import {Timestamp} from '../../app/time/Timestamp'; import {useQueryPersistedState} from '../../hooks/useQueryPersistedState'; -import {LoadingSpinner} from '../../ui/Loading'; +import {useStateWithStorage} from '../../hooks/useStateWithStorage'; +import {linkToRunEvent} from '../../runs/RunUtils'; +import {Container, Inner, Row} from '../../ui/VirtualizedTable'; +import {numberFormatter} from '../../ui/formatters'; import {AssetFeatureContext} from '../AssetFeatureContext'; -import {assetDetailsPathForKey} from '../assetDetailsPathForKey'; import {AssetKey} from '../types'; export const AssetChecks = ({ @@ -38,93 +52,291 @@ export const AssetChecks = ({ const {data} = queryResult; useQueryRefreshAtInterval(queryResult, FIFTEEN_SECONDS); - const [openCheck, setOpenCheck] = useQueryPersistedState({ + const [selectedCheckName, setSelectedCheckName] = useQueryPersistedState({ queryKey: 'checkDetail', }); - function content() { - if (!data) { - return ; - } - const assetNode = data.assetNodeOrError; + function executeButton(check?: ExecuteChecksButtonCheckFragment) { + const assetNode = data?.assetNodeOrError; if (assetNode?.__typename !== 'AssetNode') { return ; } - const result = assetNode.assetChecksOrError; - if (result.__typename === 'AssetCheckNeedsMigrationError') { - return ; - } - if (result.__typename === 'AssetCheckNeedsUserCodeUpgrade') { - return ; - } - if (result.__typename === 'AssetCheckNeedsAgentUpgradeError') { - return ; - } - const checks = result.checks; - if (!checks.length) { - return ; + const checksOrError = assetNode.assetChecksOrError; + if (checksOrError?.__typename !== 'AssetChecks') { + return ; } return ( - <> - setOpenCheck(undefined)} - /> - - + ); } - function executeAllButton() { - const assetNode = data?.assetNodeOrError; - if (assetNode?.__typename !== 'AssetNode') { - return ; + const {AssetChecksBanner} = useContext(AssetFeatureContext); + + const [didDismissAssetChecksBanner, setDidDismissAssetChecksBanner] = useStateWithStorage( + 'asset-checks-experimental-banner', + (json) => !!json, + ); + + const checks = React.useMemo(() => { + if (data?.assetNodeOrError.__typename !== 'AssetNode') { + return []; } - const checksOrError = assetNode.assetChecksOrError; - if (checksOrError?.__typename !== 'AssetChecks') { - return ; + if (data.assetNodeOrError.assetChecksOrError.__typename !== 'AssetChecks') { + return []; + } + return [...data.assetNodeOrError.assetChecksOrError.checks].sort((a, b) => + COMMON_COLLATOR.compare(a.name, b.name), + ); + }, [data]); + + const [searchValue, setSearchValue] = React.useState(''); + + const filteredChecks = React.useMemo(() => { + return checks.filter((check) => check.name.toLowerCase().includes(searchValue.toLowerCase())); + }, [checks, searchValue]); + + React.useEffect(() => {}, []); + + const containerRef = React.useRef(null); + + const rowVirtualizer = useVirtualizer({ + count: filteredChecks.length, + getScrollElement: () => containerRef.current, + estimateSize: () => 48, + overscan: 10, + }); + + const totalHeight = rowVirtualizer.getTotalSize(); + const items = rowVirtualizer.getVirtualItems(); + + const selectedCheck = React.useMemo(() => { + if (!selectedCheckName) { + return checks[0]; } - return ; + return checks.find((check) => check.name === selectedCheckName) ?? checks[0]; + }, [selectedCheckName, checks]); + + if (!data) { + return null; } - const {AssetChecksBanner} = useContext(AssetFeatureContext); + if (!checks.length || !selectedCheck) { + return ( + + + + Asset checks can verify properties of a data asset, e.g. that there are no null + values in a particular column. + + + Learn more about asset checks + + + } + /> + + ); + } + + const lastExecution = selectedCheck.executionForLatestMaterialization; + const targetMaterialization = lastExecution?.evaluation?.targetMaterialization; return ( -
- - - - - - Latest materialization: - - {lastMaterializationTimestamp ? ( - + {didDismissAssetChecksBanner ? null : ( + + { + setDidDismissAssetChecksBanner(true); + }} + /> + + )} + + + + + Checks {checks.length ? <>({numberFormatter.format(checks.length)}) : null} + + {executeButton()} + + + setSearchValue(e.target.value)} + placeholder="Filter checks" + /> + + + + {items.map(({index, size, start}) => { + const check = filteredChecks[index]!; + return ( + { + setSelectedCheckName(check.name); + }} + > + + + + {getCheckIcon(check)} + + {check.name} + + + + {assetCheckStatusDescription(check)} + + + + + ); + })} + + + + + + + + + + {selectedCheck.name} + + {executeButton(selectedCheck)} + + + About} + headerWrapperProps={headerWrapperProps} + > + +
+ + Evaluation Result +
+ +
+
+ {lastExecution ? ( + + Timestamp + + + + + ) : null} + {targetMaterialization ? ( + + Target materialization + + + + + ) : null} +
+
+
+ Latest execution} + headerWrapperProps={headerWrapperProps} + > + + About + + + Execution history} + headerWrapperProps={headerWrapperProps} > - - - - - ) : ( - None - )} + + About + + +
- {executeAllButton()}
- {content()} -
+ ); }; +const FixedScrollContainer = ({children}: {children: React.ReactNode}) => { + // This is kind of hacky but basically the height of the parent of this element is dynamic (its parent has flex grow) + // but we don't want it to grow with the content inside of this node, instead we want it only to grow with the content of our sibling node. + // This will effectively give us a height of 0 + const {viewport, containerProps} = useViewport(); + return ( + +
+ {children} +
+
+ ); +}; + +const CheckRow = styled(Row)<{$selected: boolean} & RowProps>` + padding: 5px 8px 5px 12px; + cursor: pointer; + border-radius: 8px; + &:hover { + background: ${Colors.backgroundBlue()}; + } + ${({$selected}) => ($selected ? `background: ${Colors.backgroundBlue()};` : '')} +`; + +const headerWrapperProps: React.ComponentProps = { + border: 'bottom', + padding: {vertical: 12}, + style: { + cursor: 'pointer', + }, +}; + export const ASSET_CHECKS_QUERY = gql` query AssetChecksQuery($assetKey: AssetKeyInput!) { assetNodeOrError(assetKey: $assetKey) { diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetChecksBanner.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetChecksBanner.tsx index b9cb838bf0d29..8e5ed5ed1f115 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetChecksBanner.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetChecksBanner.tsx @@ -1,17 +1,12 @@ import {Alert, Colors, Icon} from '@dagster-io/ui-components'; -export const AssetChecksBanner = () => { +export const AssetChecksBanner = ({onClose}: {onClose: () => void}) => { return ( } - description={ - - You can learn more about this new feature and provide feedback{' '} - here. - - } + onClose={onClose} /> ); }; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/util.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/util.tsx new file mode 100644 index 0000000000000..6659d9c6c05ec --- /dev/null +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/util.tsx @@ -0,0 +1,61 @@ +import {Colors, Icon, Spinner} from '@dagster-io/ui-components'; + +import {ExecuteChecksButtonCheckFragment} from './types/ExecuteChecksButton.types'; +import {AssetCheckTableFragment} from './types/VirtualizedAssetCheckTable.types'; +import {assertUnreachable} from '../../app/Util'; +import {AssetCheckExecutionResolvedStatus, AssetCheckSeverity} from '../../graphql/types'; + +export function assetCheckStatusDescription( + check: AssetCheckTableFragment & ExecuteChecksButtonCheckFragment, +) { + const lastExecution = check.executionForLatestMaterialization; + if (!lastExecution) { + return 'Not evaluated'; + } + const status = lastExecution.status; + const date = lastExecution.timestamp; + switch (status) { + case AssetCheckExecutionResolvedStatus.EXECUTION_FAILED: + return 'Execution failed'; + case AssetCheckExecutionResolvedStatus.FAILED: + return 'Failed'; + case AssetCheckExecutionResolvedStatus.IN_PROGRESS: + return 'In progress'; + case AssetCheckExecutionResolvedStatus.SKIPPED: + return 'Skipped'; + case AssetCheckExecutionResolvedStatus.SUCCEEDED: + return 'Succeeded'; + default: + assertUnreachable(status); + } +} + +export function getCheckIcon( + check: AssetCheckTableFragment & ExecuteChecksButtonCheckFragment, +): React.ReactNode { + const lastExecution = check.executionForLatestMaterialization; + if (!lastExecution) { + return ; + } + const status = lastExecution.status; + const isWarning = lastExecution.evaluation?.severity === AssetCheckSeverity.WARN; + switch (status) { + case AssetCheckExecutionResolvedStatus.EXECUTION_FAILED: + return ( + + ); + case AssetCheckExecutionResolvedStatus.FAILED: + if (isWarning) { + return ; + } + return ; + case AssetCheckExecutionResolvedStatus.IN_PROGRESS: + return ; + case AssetCheckExecutionResolvedStatus.SKIPPED: + return ; + case AssetCheckExecutionResolvedStatus.SUCCEEDED: + return ; + default: + assertUnreachable(status); + } +} diff --git a/js_modules/dagster-ui/packages/ui-core/src/nav/useRepositoryLocationReload.tsx b/js_modules/dagster-ui/packages/ui-core/src/nav/useRepositoryLocationReload.tsx index 7993cd82c19be..f54411a9c7014 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/nav/useRepositoryLocationReload.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/nav/useRepositoryLocationReload.tsx @@ -1,7 +1,7 @@ import {ApolloClient, ApolloError, gql, useApolloClient, useQuery} from '@apollo/client'; // eslint-disable-next-line no-restricted-imports import {Intent} from '@blueprintjs/core'; -import {useCallback, useMemo, useReducer} from 'react'; +import React, {useCallback, useMemo, useReducer} from 'react'; import { ReloadRepositoryLocationMutation, @@ -95,6 +95,14 @@ export const useRepositoryLocationReload = ({ const invalidateConfigs = useInvalidateConfigsForRepo(); + console.log('rerender'); + React.useLayoutEffect(() => { + console.log('first render'); + return () => { + console.log('remove'); + }; + }, []); + const {startPolling, stopPolling} = useQuery< RepositoryLocationStatusQuery, RepositoryLocationStatusQueryVariables @@ -172,6 +180,7 @@ export const useRepositoryLocationReload = ({ // Otherwise, we have no errors left. dispatch({type: 'finish-polling'}); stopPolling(); + console.log('show1'); // On success, show the successful toast, hide the dialog (if open), and reset Apollo. await showSharedToaster({ From 1e8f5ec92e45dd5494ebcbaf52b99bcdfdb69092 Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Tue, 20 Feb 2024 23:57:01 -0500 Subject: [PATCH 02/10] asset checks revamp --- .../types/SidebarAssetInfo.types.ts | 10 + .../asset-checks/AssetCheckDetailModal.tsx | 188 ----------------- .../src/assets/asset-checks/AssetChecks.tsx | 199 ++++++++++++++---- .../asset-checks/types/AssetChecks.types.ts | 6 + .../types/ExecuteChecksButton.types.ts | 6 + .../src/assets/types/AssetView.types.ts | 2 - 6 files changed, 182 insertions(+), 229 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/types/SidebarAssetInfo.types.ts b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/types/SidebarAssetInfo.types.ts index fe566b10cbf02..14004d05a1560 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/types/SidebarAssetInfo.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/types/SidebarAssetInfo.types.ts @@ -15660,6 +15660,11 @@ export type SidebarAssetFragment = { | null; } | null; + dependencies: Array<{ + __typename: 'AssetDependency'; + inputName: string; + asset: {__typename: 'AssetNode'; assetKey: {__typename: 'AssetKey'; path: Array}}; + }>; }; export type SidebarAssetQueryVariables = Types.Exact<{ @@ -31415,6 +31420,11 @@ export type SidebarAssetQuery = { | null; } | null; + dependencies: Array<{ + __typename: 'AssetDependency'; + inputName: string; + asset: {__typename: 'AssetNode'; assetKey: {__typename: 'AssetKey'; path: Array}}; + }>; } | {__typename: 'AssetNotFoundError'}; }; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetCheckDetailModal.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetCheckDetailModal.tsx index d9c7a110b904f..93b188ef25a5d 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetCheckDetailModal.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetCheckDetailModal.tsx @@ -4,177 +4,16 @@ import { Box, Button, Colors, - CursorHistoryControls, Dialog, DialogBody, DialogFooter, Mono, NonIdealState, - Spinner, - Table, } from '@dagster-io/ui-components'; import {useState} from 'react'; -import {Link} from 'react-router-dom'; -import {AssetCheckStatusTag} from './AssetCheckStatusTag'; -import { - AssetCheckDetailsQuery, - AssetCheckDetailsQueryVariables, -} from './types/AssetCheckDetailModal.types'; -import {FIFTEEN_SECONDS, useQueryRefreshAtInterval} from '../../app/QueryRefresh'; -import {useTrackPageView} from '../../app/analytics'; -import {AssetKeyInput} from '../../graphql/types'; -import {useDocumentTitle} from '../../hooks/useDocumentTitle'; import {METADATA_ENTRY_FRAGMENT, MetadataEntries} from '../../metadata/MetadataEntry'; import {MetadataEntryFragment} from '../../metadata/types/MetadataEntry.types'; -import {linkToRunEvent} from '../../runs/RunUtils'; -import {useCursorPaginatedQuery} from '../../runs/useCursorPaginatedQuery'; -import {TimestampDisplay} from '../../schedules/TimestampDisplay'; - -export const AssetCheckDetailModal = ({ - assetKey, - checkName, - onClose, -}: { - assetKey: AssetKeyInput; - checkName: string | undefined | null; - onClose: () => void; -}) => { - return ( - - {checkName ? : null} - - ); -}; - -const PAGE_SIZE = 5; - -const AssetCheckDetailModalImpl = ({ - assetKey, - checkName, -}: { - assetKey: AssetKeyInput; - checkName: string; -}) => { - useTrackPageView(); - useDocumentTitle(`Asset Check | ${checkName}`); - - const {queryResult, paginationProps} = useCursorPaginatedQuery< - AssetCheckDetailsQuery, - AssetCheckDetailsQueryVariables - >({ - query: ASSET_CHECK_DETAILS_QUERY, - variables: { - assetKey, - checkName, - }, - nextCursorForResult: (data) => { - if (!data) { - return undefined; - } - return data.assetCheckExecutions[PAGE_SIZE - 1]?.id.toString(); - }, - getResultArray: (data) => { - if (!data) { - return []; - } - return data.assetCheckExecutions || []; - }, - pageSize: PAGE_SIZE, - }); - - // TODO - in a follow up PR we should have some kind of queryRefresh context that can merge all of the uses of queryRefresh. - useQueryRefreshAtInterval(queryResult, FIFTEEN_SECONDS); - - const executions = queryResult.data?.assetCheckExecutions; - - const runHistory = () => { - if (!executions) { - return ( - - - - ); - } - - if (!executions.length) { - return ; - } - return ( -
- - - - - - - - - - - {executions.map((execution) => { - return ( - - - - - - - ); - })} - -
TimestampTarget materializationResultEvaluation metadata
- {execution.evaluation?.timestamp ? ( - - - - ) : ( - - )} - - {execution.evaluation?.targetMaterialization ? ( - - - - ) : ( - ' - ' - )} - - - - -
-
- -
-
- ); - }; - - if (!executions) { - return ( - - - - ); - } - return {runHistory()}; -}; export function MetadataCell({metadataEntries}: {metadataEntries?: MetadataEntryFragment[]}) { const [showMetadata, setShowMetadata] = useState(false); @@ -336,33 +175,6 @@ export function NoChecks() { ); } -function NoExecutions() { - return ( - - - - No executions found. Materialize this asset and the check will run automatically. - - {/* - Learn more about Asset Checks - - */} - - } - /> - - ); -} - const InlineableTypenames: MetadataEntryFragment['__typename'][] = [ 'BoolMetadataEntry', 'FloatMetadataEntry', diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetChecks.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetChecks.tsx index 737af9575ab0f..7f9c550214779 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetChecks.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetChecks.tsx @@ -5,10 +5,13 @@ import { Caption, CollapsibleSection, Colors, + CursorHistoryControls, Icon, NonIdealState, + Spinner, Subtitle1, Subtitle2, + Table, TextInput, useViewport, } from '@dagster-io/ui-components'; @@ -18,6 +21,7 @@ import React, {useContext} from 'react'; import {Link} from 'react-router-dom'; import styled from 'styled-components'; +import {ASSET_CHECK_DETAILS_QUERY, MetadataCell} from './AssetCheckDetailModal'; import {AssetCheckStatusTag} from './AssetCheckStatusTag'; import { EXECUTE_CHECKS_BUTTON_ASSET_NODE_FRAGMENT, @@ -25,18 +29,25 @@ import { ExecuteChecksButton, } from './ExecuteChecksButton'; import {ASSET_CHECK_TABLE_FRAGMENT} from './VirtualizedAssetCheckTable'; +import { + AssetCheckDetailsQuery, + AssetCheckDetailsQueryVariables, +} from './types/AssetCheckDetailModal.types'; import {AssetChecksQuery, AssetChecksQueryVariables} from './types/AssetChecks.types'; -import {ExecuteChecksButtonCheckFragment} from './types/ExecuteChecksButton.types'; import {assetCheckStatusDescription, getCheckIcon} from './util'; import {FIFTEEN_SECONDS, useQueryRefreshAtInterval} from '../../app/QueryRefresh'; import {COMMON_COLLATOR} from '../../app/Util'; import {Timestamp} from '../../app/time/Timestamp'; +import {AssetKeyInput} from '../../graphql/types'; import {useQueryPersistedState} from '../../hooks/useQueryPersistedState'; import {useStateWithStorage} from '../../hooks/useStateWithStorage'; import {linkToRunEvent} from '../../runs/RunUtils'; +import {useCursorPaginatedQuery} from '../../runs/useCursorPaginatedQuery'; +import {TimestampDisplay} from '../../schedules/TimestampDisplay'; import {Container, Inner, Row} from '../../ui/VirtualizedTable'; import {numberFormatter} from '../../ui/formatters'; import {AssetFeatureContext} from '../AssetFeatureContext'; +import {PAGE_SIZE} from '../AutoMaterializePolicyPage/useEvaluationsQueryResult'; import {AssetKey} from '../types'; export const AssetChecks = ({ @@ -56,30 +67,8 @@ export const AssetChecks = ({ queryKey: 'checkDetail', }); - function executeButton(check?: ExecuteChecksButtonCheckFragment) { - const assetNode = data?.assetNodeOrError; - if (assetNode?.__typename !== 'AssetNode') { - return ; - } - const checksOrError = assetNode.assetChecksOrError; - if (checksOrError?.__typename !== 'AssetChecks') { - return ; - } - return ( - - ); - } - - const {AssetChecksBanner} = useContext(AssetFeatureContext); - - const [didDismissAssetChecksBanner, setDidDismissAssetChecksBanner] = useStateWithStorage( - 'asset-checks-experimental-banner', - (json) => !!json, - ); + const assetNode = + data?.assetNodeOrError.__typename === 'AssetNode' ? data.assetNodeOrError : null; const checks = React.useMemo(() => { if (data?.assetNodeOrError.__typename !== 'AssetNode') { @@ -93,6 +82,13 @@ export const AssetChecks = ({ ); }, [data]); + const {AssetChecksBanner} = useContext(AssetFeatureContext); + + const [didDismissAssetChecksBanner, setDidDismissAssetChecksBanner] = useStateWithStorage( + 'asset-checks-experimental-banner', + (json) => !!json, + ); + const [searchValue, setSearchValue] = React.useState(''); const filteredChecks = React.useMemo(() => { @@ -124,11 +120,12 @@ export const AssetChecks = ({ return null; } - if (!checks.length || !selectedCheck) { + if (!checks.length || !selectedCheck || !assetNode) { return ( @@ -170,7 +167,7 @@ export const AssetChecks = ({ Checks {checks.length ? <>({numberFormatter.format(checks.length)}) : null} - {executeButton()} + {selectedCheck.name} - {executeButton(selectedCheck)} + About} headerWrapperProps={headerWrapperProps} > - + + + {selectedCheck.description ?? ( + No description provided + )} + + {/* {selectedCheck.dependencies?.length ? ( + + {assetNode.dependencies.map((dep) => { + const key = dep.asset.assetKey; + return ( + + {displayNameForAssetKey(key)} + + ); + })} + + ) : ( + No dependencies + )} */} + + + Latest execution} + headerWrapperProps={headerWrapperProps} + > +
Evaluation Result @@ -282,20 +305,16 @@ export const AssetChecks = ({
- Latest execution} - headerWrapperProps={headerWrapperProps} - > - - About - - Execution history} headerWrapperProps={headerWrapperProps} > - - About + + {lastExecution ? ( + + ) : ( + No execution history + )}
@@ -305,6 +324,108 @@ export const AssetChecks = ({ ); }; +const CheckExecutions = ({assetKey, checkName}: {assetKey: AssetKeyInput; checkName: string}) => { + const {queryResult, paginationProps} = useCursorPaginatedQuery< + AssetCheckDetailsQuery, + AssetCheckDetailsQueryVariables + >({ + query: ASSET_CHECK_DETAILS_QUERY, + variables: { + assetKey, + checkName, + }, + nextCursorForResult: (data) => { + if (!data) { + return undefined; + } + return data.assetCheckExecutions[PAGE_SIZE - 1]?.id.toString(); + }, + getResultArray: (data) => { + if (!data) { + return []; + } + return data.assetCheckExecutions || []; + }, + pageSize: PAGE_SIZE, + }); + + // TODO - in a follow up PR we should have some kind of queryRefresh context that can merge all of the uses of queryRefresh. + useQueryRefreshAtInterval(queryResult, FIFTEEN_SECONDS); + + const executions = queryResult.data?.assetCheckExecutions; + + const runHistory = () => { + if (!executions) { + return; + } + return ( +
+ + + + + + + + + + + {executions.map((execution) => { + return ( + + + + + + + ); + })} + +
Evaluation ResultTimestampTarget materializationMetadata
+ + + {execution.evaluation?.timestamp ? ( + + + + ) : ( + + )} + + {execution.evaluation?.targetMaterialization ? ( + + + + ) : ( + ' - ' + )} + + +
+
+ +
+
+ ); + }; + + if (!executions) { + return ( + + + + ); + } + return {runHistory()}; +}; + const FixedScrollContainer = ({children}: {children: React.ReactNode}) => { // This is kind of hacky but basically the height of the parent of this element is dynamic (its parent has flex grow) // but we don't want it to grow with the content inside of this node, instead we want it only to grow with the content of our sibling node. diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/types/AssetChecks.types.ts b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/types/AssetChecks.types.ts index 3c73a7c2fb723..9798dfae1d604 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/types/AssetChecks.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/types/AssetChecks.types.ts @@ -13,6 +13,7 @@ export type AssetChecksQuery = { __typename: 'AssetNode'; id: string; jobNames: Array; + description: string | null; assetChecksOrError: | {__typename: 'AssetCheckNeedsAgentUpgradeError'} | {__typename: 'AssetCheckNeedsMigrationError'; message: string} @@ -182,6 +183,11 @@ export type AssetChecksQuery = { }>; }; assetKey: {__typename: 'AssetKey'; path: Array}; + dependencies: Array<{ + __typename: 'AssetDependency'; + inputName: string; + asset: {__typename: 'AssetNode'; assetKey: {__typename: 'AssetKey'; path: Array}}; + }>; repository: { __typename: 'Repository'; id: string; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/types/ExecuteChecksButton.types.ts b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/types/ExecuteChecksButton.types.ts index 297b028ca5c0c..8d4e4685edd8f 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/types/ExecuteChecksButton.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/types/ExecuteChecksButton.types.ts @@ -12,7 +12,13 @@ export type ExecuteChecksButtonAssetNodeFragment = { __typename: 'AssetNode'; id: string; jobNames: Array; + description: string | null; assetKey: {__typename: 'AssetKey'; path: Array}; + dependencies: Array<{ + __typename: 'AssetDependency'; + inputName: string; + asset: {__typename: 'AssetNode'; assetKey: {__typename: 'AssetKey'; path: Array}}; + }>; repository: { __typename: 'Repository'; id: string; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetView.types.ts b/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetView.types.ts index f962d210f0b1a..590bd0a86b808 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetView.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetView.types.ts @@ -22,7 +22,6 @@ export type AssetViewDefinitionQuery = { __typename: 'AssetNode'; id: string; groupName: string | null; - hasAssetChecks: boolean; description: string | null; graphName: string | null; opNames: Array; @@ -15844,7 +15843,6 @@ export type AssetViewDefinitionNodeFragment = { __typename: 'AssetNode'; id: string; groupName: string | null; - hasAssetChecks: boolean; description: string | null; graphName: string | null; opNames: Array; From 2f1ff454ec0a9173e3b8adedf9c132981f22c952 Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Wed, 21 Feb 2024 00:00:12 -0500 Subject: [PATCH 03/10] rm console.logs --- .../ui-core/src/nav/useRepositoryLocationReload.tsx | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/nav/useRepositoryLocationReload.tsx b/js_modules/dagster-ui/packages/ui-core/src/nav/useRepositoryLocationReload.tsx index f54411a9c7014..7993cd82c19be 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/nav/useRepositoryLocationReload.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/nav/useRepositoryLocationReload.tsx @@ -1,7 +1,7 @@ import {ApolloClient, ApolloError, gql, useApolloClient, useQuery} from '@apollo/client'; // eslint-disable-next-line no-restricted-imports import {Intent} from '@blueprintjs/core'; -import React, {useCallback, useMemo, useReducer} from 'react'; +import {useCallback, useMemo, useReducer} from 'react'; import { ReloadRepositoryLocationMutation, @@ -95,14 +95,6 @@ export const useRepositoryLocationReload = ({ const invalidateConfigs = useInvalidateConfigsForRepo(); - console.log('rerender'); - React.useLayoutEffect(() => { - console.log('first render'); - return () => { - console.log('remove'); - }; - }, []); - const {startPolling, stopPolling} = useQuery< RepositoryLocationStatusQuery, RepositoryLocationStatusQueryVariables @@ -180,7 +172,6 @@ export const useRepositoryLocationReload = ({ // Otherwise, we have no errors left. dispatch({type: 'finish-polling'}); stopPolling(); - console.log('show1'); // On success, show the successful toast, hide the dialog (if open), and reset Apollo. await showSharedToaster({ From 9948bd69d7298835318bd134d13c528550f9b32c Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Wed, 21 Feb 2024 18:42:35 -0500 Subject: [PATCH 04/10] update fixtures --- .../AssetViewDefinition.fixtures.ts | 267 ++++++++---------- .../src/assets/__tests__/AssetView.test.tsx | 55 +++- .../src/live-data-provider/LiveDataThread.tsx | 1 + 3 files changed, 166 insertions(+), 157 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/__fixtures__/AssetViewDefinition.fixtures.ts b/js_modules/dagster-ui/packages/ui-core/src/assets/__fixtures__/AssetViewDefinition.fixtures.ts index 34a0be26f7753..9c71aaaf8669b 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/__fixtures__/AssetViewDefinition.fixtures.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/__fixtures__/AssetViewDefinition.fixtures.ts @@ -1,28 +1,24 @@ -import {MockedResponse} from '@apollo/client/testing'; - -import {AssetGraphQuery} from '../../asset-graph/types/useAssetGraphData.types'; -import {ASSET_GRAPH_QUERY} from '../../asset-graph/useAssetGraphData'; -import {buildMaterializationEvent} from '../../graphql/types'; +import { + buildAsset, + buildAssetKey, + buildAssetNode, + buildMaterializationEvent, + buildRepository, + buildRepositoryLocation, + buildResourceRequirement, +} from '../../graphql/types'; import {ASSET_VIEW_DEFINITION_QUERY} from '../AssetView'; import {buildQueryMock} from '../AutoMaterializePolicyPage/__fixtures__/AutoMaterializePolicyPage.fixtures'; -import {AssetViewDefinitionQuery} from '../types/AssetView.types'; +import { + AssetViewDefinitionQuery, + AssetViewDefinitionQueryVariables, +} from '../types/AssetView.types'; export const LatestMaterializationTimestamp = '1671568270073'; - -export const AssetGraphEmpty: MockedResponse = { - request: { - query: ASSET_GRAPH_QUERY, - variables: {}, - }, - result: { - data: { - __typename: 'Query', - assetNodes: [], - }, - }, -}; - -export const AssetViewDefinitionNonSDA: MockedResponse = buildQueryMock({ +export const AssetViewDefinitionNonSDA = buildQueryMock< + AssetViewDefinitionQuery, + AssetViewDefinitionQueryVariables +>({ query: ASSET_VIEW_DEFINITION_QUERY, variables: { assetKey: {path: ['non_sda_asset']}, @@ -45,140 +41,109 @@ export const AssetViewDefinitionNonSDA: MockedResponse }, }); -export const AssetViewDefinitionSourceAsset: MockedResponse = { - request: { - query: ASSET_VIEW_DEFINITION_QUERY, - variables: { - assetKey: {path: ['observable_source_asset']}, - }, +export const AssetViewDefinitionSourceAsset = buildQueryMock< + AssetViewDefinitionQuery, + AssetViewDefinitionQueryVariables +>({ + query: ASSET_VIEW_DEFINITION_QUERY, + variables: { + assetKey: {path: ['observable_source_asset']}, }, - result: { - data: { - __typename: 'Query', - assetOrError: { + data: { + assetOrError: buildAsset({ + id: 'test.py.repo.["observable_source_asset"]', + key: buildAssetKey({ + path: ['observable_source_asset'], + }), + assetMaterializations: [], + definition: buildAssetNode({ + hasAssetChecks: false, id: 'test.py.repo.["observable_source_asset"]', - key: { - path: ['observable_source_asset'], - __typename: 'AssetKey', - }, - assetMaterializations: [], - definition: { - hasAssetChecks: false, - id: 'test.py.repo.["observable_source_asset"]', - groupName: 'GROUP3', - backfillPolicy: null, - partitionDefinition: null, - partitionKeysByDimension: [], - repository: { - id: '4d0b1967471d9a4682ccc97d12c1c508d0d9c2e1', - name: 'repo', - location: { - id: 'test.py', - name: 'test.py', - __typename: 'RepositoryLocation', - }, - __typename: 'Repository', - }, - __typename: 'AssetNode', - description: null, - graphName: null, - opNames: [], - opVersion: null, - jobNames: ['__ASSET_JOB'], - configField: null, - autoMaterializePolicy: null, - freshnessPolicy: null, - hasMaterializePermission: true, - computeKind: null, - isPartitioned: false, - isObservable: true, - isExecutable: true, - isSource: true, - assetKey: { - path: ['observable_source_asset'], - __typename: 'AssetKey', - }, - metadataEntries: [], - type: null, - requiredResources: [ - { - __typename: 'ResourceRequirement', - resourceKey: 'foo', - }, - ], - targetingInstigators: [], - }, - __typename: 'Asset', - }, - }, + groupName: 'GROUP3', + backfillPolicy: null, + partitionDefinition: null, + + partitionKeysByDimension: [], + repository: buildRepository({ + id: '4d0b1967471d9a4682ccc97d12c1c508d0d9c2e1', + name: 'repo', + location: buildRepositoryLocation({ + id: 'test.py', + name: 'test.py', + }), + }), + description: null, + graphName: null, + opNames: [], + opVersion: null, + jobNames: ['__ASSET_JOB'], + configField: null, + autoMaterializePolicy: null, + freshnessPolicy: null, + hasMaterializePermission: true, + computeKind: null, + isPartitioned: false, + isObservable: true, + isExecutable: true, + isSource: true, + metadataEntries: [], + type: null, + requiredResources: [buildResourceRequirement({resourceKey: 'foo'})], + targetingInstigators: [], + }), + }), }, -}; +}); -export const AssetViewDefinitionSDA: MockedResponse = { - request: { - query: ASSET_VIEW_DEFINITION_QUERY, - variables: { - assetKey: {path: ['sda_asset']}, - }, +export const AssetViewDefinitionSDA = buildQueryMock< + AssetViewDefinitionQuery, + AssetViewDefinitionQueryVariables +>({ + query: ASSET_VIEW_DEFINITION_QUERY, + variables: { + assetKey: {path: ['sda_asset']}, }, - result: { - data: { - __typename: 'Query', - assetOrError: { + data: { + assetOrError: buildAsset({ + id: 'test.py.repo.["sda_asset"]', + key: buildAssetKey({ + path: ['sda_asset'], + }), + assetMaterializations: [], + definition: buildAssetNode({ + hasAssetChecks: false, id: 'test.py.repo.["sda_asset"]', - key: { - path: ['sda_asset'], - __typename: 'AssetKey', - }, - assetMaterializations: [], - definition: { - hasAssetChecks: false, - id: 'test.py.repo.["sda_asset"]', - groupName: 'GROUP3', - backfillPolicy: null, - partitionDefinition: null, - partitionKeysByDimension: [], - repository: { - id: '4d0b1967471d9a4682ccc97d12c1c508d0d9c2e1', - name: 'repo', - location: { - id: 'test.py', - name: 'test.py', - __typename: 'RepositoryLocation', - }, - __typename: 'Repository', - }, - __typename: 'AssetNode', - description: null, - graphName: null, - opNames: [], - opVersion: null, - jobNames: ['__ASSET_JOB'], - configField: null, - autoMaterializePolicy: null, - freshnessPolicy: null, - hasMaterializePermission: true, - computeKind: null, - isPartitioned: false, - isObservable: false, - isExecutable: true, - isSource: false, - assetKey: { - path: ['sda_asset'], - __typename: 'AssetKey', - }, - metadataEntries: [], - type: null, - requiredResources: [ - { - __typename: 'ResourceRequirement', - resourceKey: 'foo', - }, - ], - targetingInstigators: [], - }, - __typename: 'Asset', - }, - }, + groupName: 'GROUP3', + backfillPolicy: null, + partitionDefinition: null, + partitionKeysByDimension: [], + repository: buildRepository({ + id: '4d0b1967471d9a4682ccc97d12c1c508d0d9c2e1', + name: 'repo', + location: buildRepositoryLocation({ + id: 'test.py', + name: 'test.py', + }), + }), + description: null, + graphName: null, + opNames: [], + opVersion: null, + jobNames: ['__ASSET_JOB'], + configField: null, + autoMaterializePolicy: null, + freshnessPolicy: null, + hasMaterializePermission: true, + computeKind: null, + isPartitioned: false, + isObservable: false, + isExecutable: true, + isSource: false, + metadataEntries: [], + type: null, + requiredResources: [buildResourceRequirement({resourceKey: 'foo'})], + targetingInstigators: [], + }), + }), }, -}; +}); diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/AssetView.test.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/AssetView.test.tsx index 00f3abd1f2ded..f9c4fa04b1e5e 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/AssetView.test.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/AssetView.test.tsx @@ -2,10 +2,28 @@ import {MockedProvider} from '@apollo/client/testing'; import {act, render, screen, waitFor} from '@testing-library/react'; import {MemoryRouter} from 'react-router-dom'; -import {AssetKeyInput} from '../../graphql/types'; +import { + ASSETS_GRAPH_LIVE_QUERY, + AssetLiveDataProvider, +} from '../../asset-data/AssetLiveDataProvider'; +import { + AssetGraphLiveQuery, + AssetGraphLiveQueryVariables, +} from '../../asset-data/types/AssetLiveDataProvider.types'; +import { + AssetGraphQuery, + AssetGraphQueryVariables, +} from '../../asset-graph/types/useAssetGraphData.types'; +import {ASSET_GRAPH_QUERY} from '../../asset-graph/useAssetGraphData'; +import { + AssetKeyInput, + buildAssetKey, + buildAssetLatestInfo, + buildAssetNode, +} from '../../graphql/types'; +import {buildQueryMock} from '../../testing/mocking'; import {AssetView} from '../AssetView'; import { - AssetGraphEmpty, AssetViewDefinitionNonSDA, AssetViewDefinitionSDA, AssetViewDefinitionSourceAsset, @@ -20,20 +38,45 @@ jest.mock('../../graph/asyncGraphLayout', () => ({})); jest.mock('../AssetPartitions', () => ({AssetPartitions: () =>
})); jest.mock('../AssetEvents', () => ({AssetEvents: () =>
})); +function mockLiveData(key: string) { + const assetKey = {path: [key]}; + return buildQueryMock({ + query: ASSETS_GRAPH_LIVE_QUERY, + variables: { + assetKeys: [assetKey], + }, + data: { + assetNodes: [buildAssetNode({assetKey: buildAssetKey(assetKey)})], + assetsLatestInfo: [buildAssetLatestInfo({assetKey: buildAssetKey(assetKey)})], + }, + }); +} + describe('AssetView', () => { const Test = ({path, assetKey}: {path: string; assetKey: AssetKeyInput}) => { return ( ({ + query: ASSET_GRAPH_QUERY, + variables: {}, + data: { + assetNodes: [buildAssetNode()], + }, + }), ]} > - - - + + + + + ); }; diff --git a/js_modules/dagster-ui/packages/ui-core/src/live-data-provider/LiveDataThread.tsx b/js_modules/dagster-ui/packages/ui-core/src/live-data-provider/LiveDataThread.tsx index e576979e91c3c..e5e945559e8d6 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/live-data-provider/LiveDataThread.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/live-data-provider/LiveDataThread.tsx @@ -84,6 +84,7 @@ export class LiveDataThread { this._batchedQueryKeys(); }; try { + console.log('fetching', {keys}); const data = await this.queryKeys(keys); this.manager._updateFetchedKeys(keys, data); doNextFetch(); From ce778555398791bcf8182316b8e7d6645d9ebef8 Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Wed, 21 Feb 2024 18:43:38 -0500 Subject: [PATCH 05/10] . --- .../packages/ui-core/src/live-data-provider/LiveDataThread.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/live-data-provider/LiveDataThread.tsx b/js_modules/dagster-ui/packages/ui-core/src/live-data-provider/LiveDataThread.tsx index e5e945559e8d6..e576979e91c3c 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/live-data-provider/LiveDataThread.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/live-data-provider/LiveDataThread.tsx @@ -84,7 +84,6 @@ export class LiveDataThread { this._batchedQueryKeys(); }; try { - console.log('fetching', {keys}); const data = await this.queryKeys(keys); this.manager._updateFetchedKeys(keys, data); doNextFetch(); From 75b4e481626c3f6659858f15d20432131bd5ce2d Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Wed, 21 Feb 2024 18:46:55 -0500 Subject: [PATCH 06/10] more builders --- .../__fixtures__/AssetViewDefinition.fixtures.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/__fixtures__/AssetViewDefinition.fixtures.ts b/js_modules/dagster-ui/packages/ui-core/src/assets/__fixtures__/AssetViewDefinition.fixtures.ts index 9c71aaaf8669b..55f5a937d4490 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/__fixtures__/AssetViewDefinition.fixtures.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/__fixtures__/AssetViewDefinition.fixtures.ts @@ -24,20 +24,18 @@ export const AssetViewDefinitionNonSDA = buildQueryMock< assetKey: {path: ['non_sda_asset']}, }, data: { - assetOrError: { + assetOrError: buildAsset({ id: '["non_sda_asset"]', - key: { + key: buildAssetKey({ path: ['non_sda_asset'], - __typename: 'AssetKey', - }, + }), assetMaterializations: [ buildMaterializationEvent({ timestamp: LatestMaterializationTimestamp, }), ], definition: null, - __typename: 'Asset', - }, + }), }, }); From 1e3fcedb18101dd16a6eb7761d2ca3eae4a7cfc5 Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Wed, 21 Feb 2024 19:36:44 -0500 Subject: [PATCH 07/10] update fixtures --- .../src/assets/__fixtures__/AssetViewDefinition.fixtures.ts | 2 -- .../ui-core/src/assets/__tests__/buildAssetTabs.test.tsx | 2 -- 2 files changed, 4 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/__fixtures__/AssetViewDefinition.fixtures.ts b/js_modules/dagster-ui/packages/ui-core/src/assets/__fixtures__/AssetViewDefinition.fixtures.ts index 55f5a937d4490..f7437fa397a26 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/__fixtures__/AssetViewDefinition.fixtures.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/__fixtures__/AssetViewDefinition.fixtures.ts @@ -55,7 +55,6 @@ export const AssetViewDefinitionSourceAsset = buildQueryMock< }), assetMaterializations: [], definition: buildAssetNode({ - hasAssetChecks: false, id: 'test.py.repo.["observable_source_asset"]', groupName: 'GROUP3', backfillPolicy: null, @@ -109,7 +108,6 @@ export const AssetViewDefinitionSDA = buildQueryMock< }), assetMaterializations: [], definition: buildAssetNode({ - hasAssetChecks: false, id: 'test.py.repo.["sda_asset"]', groupName: 'GROUP3', backfillPolicy: null, diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/buildAssetTabs.test.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/buildAssetTabs.test.tsx index 22e9ed65c46c6..9a277685d9029 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/buildAssetTabs.test.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/buildAssetTabs.test.tsx @@ -32,7 +32,6 @@ const autoMaterializePolicy = buildAutoMaterializePolicy({ describe('buildAssetTabs', () => { const definitionWithPartition: AssetViewDefinitionNodeFragment = buildAssetNode({ id: 'dagster_test.toys.repo.auto_materialize_repo_2.["eager_downstream_3_partitioned"]', - hasAssetChecks: false, groupName: 'default', partitionDefinition: buildPartitionDefinition({ description: 'Daily, starting 2023-02-01 UTC.', @@ -139,7 +138,6 @@ describe('buildAssetTabs', () => { const definitionWithoutPartition: AssetViewDefinitionNodeFragment = { id: 'dagster_test.toys.repo.auto_materialize_repo_1.["lazy_downstream_1"]', groupName: 'default', - hasAssetChecks: false, partitionDefinition: null, partitionKeysByDimension: [], repository: { From 39fe49f2bbd8b9bb9d02b953efbc08e9bc6037c2 Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Fri, 23 Feb 2024 06:37:11 -0500 Subject: [PATCH 08/10] update test --- .../ui-core/src/assets/__tests__/buildAssetTabs.test.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/buildAssetTabs.test.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/buildAssetTabs.test.tsx index 9a277685d9029..d850a6da0469f 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/buildAssetTabs.test.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/buildAssetTabs.test.tsx @@ -277,6 +277,7 @@ describe('buildAssetTabs', () => { expect(tabKeys).toEqual([ 'partitions', 'events', + 'checks', 'plots', 'definition', 'lineage', @@ -290,7 +291,7 @@ describe('buildAssetTabs', () => { params, }); const tabKeys = tabList.map(({id}) => id); - expect(tabKeys).toEqual(['partitions', 'events', 'plots', 'definition', 'lineage']); + expect(tabKeys).toEqual(['partitions', 'events', 'checks', 'plots', 'definition', 'lineage']); }); it('hides partitions tab if no partitions', () => { @@ -299,7 +300,7 @@ describe('buildAssetTabs', () => { params, }); const tabKeys = tabList.map(({id}) => id); - expect(tabKeys).toEqual(['events', 'plots', 'definition', 'lineage', 'automation']); + expect(tabKeys).toEqual(['events', 'checks', 'plots', 'definition', 'lineage', 'automation']); }); it('hides partitions and auto-materialize tabs if no partitions or auto-materializing', () => { @@ -308,6 +309,6 @@ describe('buildAssetTabs', () => { params, }); const tabKeys = tabList.map(({id}) => id); - expect(tabKeys).toEqual(['events', 'plots', 'definition', 'lineage']); + expect(tabKeys).toEqual(['events', 'checks', 'plots', 'definition', 'lineage']); }); }); From a781779c551bc7c94135e7ed5c72608e589e6726 Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Fri, 23 Feb 2024 07:04:03 -0500 Subject: [PATCH 09/10] regenerate graphql --- .../src/asset-graph/types/SidebarAssetInfo.types.ts | 10 ---------- .../src/assets/asset-checks/types/AssetChecks.types.ts | 6 ------ .../asset-checks/types/ExecuteChecksButton.types.ts | 6 ------ 3 files changed, 22 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/types/SidebarAssetInfo.types.ts b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/types/SidebarAssetInfo.types.ts index 14004d05a1560..fe566b10cbf02 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/asset-graph/types/SidebarAssetInfo.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/asset-graph/types/SidebarAssetInfo.types.ts @@ -15660,11 +15660,6 @@ export type SidebarAssetFragment = { | null; } | null; - dependencies: Array<{ - __typename: 'AssetDependency'; - inputName: string; - asset: {__typename: 'AssetNode'; assetKey: {__typename: 'AssetKey'; path: Array}}; - }>; }; export type SidebarAssetQueryVariables = Types.Exact<{ @@ -31420,11 +31415,6 @@ export type SidebarAssetQuery = { | null; } | null; - dependencies: Array<{ - __typename: 'AssetDependency'; - inputName: string; - asset: {__typename: 'AssetNode'; assetKey: {__typename: 'AssetKey'; path: Array}}; - }>; } | {__typename: 'AssetNotFoundError'}; }; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/types/AssetChecks.types.ts b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/types/AssetChecks.types.ts index 9798dfae1d604..3c73a7c2fb723 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/types/AssetChecks.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/types/AssetChecks.types.ts @@ -13,7 +13,6 @@ export type AssetChecksQuery = { __typename: 'AssetNode'; id: string; jobNames: Array; - description: string | null; assetChecksOrError: | {__typename: 'AssetCheckNeedsAgentUpgradeError'} | {__typename: 'AssetCheckNeedsMigrationError'; message: string} @@ -183,11 +182,6 @@ export type AssetChecksQuery = { }>; }; assetKey: {__typename: 'AssetKey'; path: Array}; - dependencies: Array<{ - __typename: 'AssetDependency'; - inputName: string; - asset: {__typename: 'AssetNode'; assetKey: {__typename: 'AssetKey'; path: Array}}; - }>; repository: { __typename: 'Repository'; id: string; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/types/ExecuteChecksButton.types.ts b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/types/ExecuteChecksButton.types.ts index 8d4e4685edd8f..297b028ca5c0c 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/types/ExecuteChecksButton.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/types/ExecuteChecksButton.types.ts @@ -12,13 +12,7 @@ export type ExecuteChecksButtonAssetNodeFragment = { __typename: 'AssetNode'; id: string; jobNames: Array; - description: string | null; assetKey: {__typename: 'AssetKey'; path: Array}; - dependencies: Array<{ - __typename: 'AssetDependency'; - inputName: string; - asset: {__typename: 'AssetNode'; assetKey: {__typename: 'AssetKey'; path: Array}}; - }>; repository: { __typename: 'Repository'; id: string; From 80bcf6e4ecc9123a813d7f4259807aff3adcc4dd Mon Sep 17 00:00:00 2001 From: Marco Salazar Date: Fri, 23 Feb 2024 07:21:10 -0500 Subject: [PATCH 10/10] feedback --- .../ui-core/src/assets/asset-checks/AssetChecks.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetChecks.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetChecks.tsx index 7f9c550214779..94490d470b7a5 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetChecks.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/asset-checks/AssetChecks.tsx @@ -95,8 +95,6 @@ export const AssetChecks = ({ return checks.filter((check) => check.name.toLowerCase().includes(searchValue.toLowerCase())); }, [checks, searchValue]); - React.useEffect(() => {}, []); - const containerRef = React.useRef(null); const rowVirtualizer = useVirtualizer({ @@ -273,7 +271,7 @@ export const AssetChecks = ({ >
- + Evaluation Result
{lastExecution ? ( - + Timestamp ) : null} {targetMaterialization ? ( - + Target materialization