From c59f8e3d61ef9ec825eb2cd5a6d6e65622ae14f3 Mon Sep 17 00:00:00 2001 From: Andrew Sikowitz Date: Wed, 29 Oct 2025 12:04:42 -0700 Subject: [PATCH 01/11] initial removal --- datahub-web-react/src/CustomThemeProvider.tsx | 6 +- datahub-web-react/src/app/ProtectedRoutes.tsx | 14 +-- datahub-web-react/src/app/SearchRoutes.tsx | 50 ++--------- .../components/AnalyticsPage.tsx | 16 ++-- .../entity/shared/entityForm/FormByEntity.tsx | 9 +- .../tabs/Properties/AddPropertyButton.tsx | 10 +-- .../src/app/onboarding/OnboardingTour.tsx | 4 +- .../src/app/settingsV2/Preferences.tsx | 86 +------------------ .../src/app/settingsV2/SettingsPage.tsx | 4 +- .../src/app/useBuildEntityRegistry.ts | 7 +- datahub-web-react/src/app/useSetAppTheme.tsx | 6 +- .../src/app/useShowNavBarRedesign.tsx | 4 +- 12 files changed, 31 insertions(+), 185 deletions(-) diff --git a/datahub-web-react/src/CustomThemeProvider.tsx b/datahub-web-react/src/CustomThemeProvider.tsx index fc0b091b7723fe..4b547030aca41d 100644 --- a/datahub-web-react/src/CustomThemeProvider.tsx +++ b/datahub-web-react/src/CustomThemeProvider.tsx @@ -1,7 +1,6 @@ import React, { useState } from 'react'; import { ThemeProvider } from 'styled-components'; -import { useIsThemeV2 } from '@app/useIsThemeV2'; import { useCustomThemeId } from '@app/useSetAppTheme'; import themes from '@conf/theme/themes'; import { Theme } from '@conf/theme/types'; @@ -12,12 +11,9 @@ interface Props { } const CustomThemeProvider = ({ children }: Props) => { - // Note: AppConfigContext not provided yet, so both of these calls rely on the DEFAULT_APP_CONFIG - const isThemeV2 = useIsThemeV2(); const customThemeId = useCustomThemeId(); - // Note: If custom theme id is a json file, it will only be loaded later in useSetAppTheme - const defaultTheme = isThemeV2 ? themes.themeV2 : themes.themeV1; + const defaultTheme = themes.themeV2; const customTheme = customThemeId ? themes[customThemeId] : null; const [theme, setTheme] = useState(customTheme ?? defaultTheme); diff --git a/datahub-web-react/src/app/ProtectedRoutes.tsx b/datahub-web-react/src/app/ProtectedRoutes.tsx index 3cadb9c1d3e4b1..e69cd36f51021b 100644 --- a/datahub-web-react/src/app/ProtectedRoutes.tsx +++ b/datahub-web-react/src/app/ProtectedRoutes.tsx @@ -6,7 +6,6 @@ import styled from 'styled-components'; import DataHubTitle from '@app/DataHubTitle'; import EmbedRoutes from '@app/EmbedRoutes'; import { SearchRoutes } from '@app/SearchRoutes'; -import { HomePage } from '@app/home/HomePage'; import { HomePage as HomePageV2 } from '@app/homeV2/HomePage'; import { IntroduceYourself } from '@app/homeV2/introduce/IntroduceYourself'; import { useSetUserPersona } from '@app/homeV2/persona/useUserPersona'; @@ -14,7 +13,7 @@ import { HomePage as HomePageV3 } from '@app/homeV3/HomePage'; import { useShowHomePageRedesign } from '@app/homeV3/context/hooks/useShowHomePageRedesign'; import { useSetUserTitle } from '@app/identity/user/useUserTitle'; import { OnboardingContextProvider } from '@app/onboarding/OnboardingContextProvider'; -import { useIsThemeV2, useSetThemeIsV2 } from '@app/useIsThemeV2'; +import { useSetThemeIsV2 } from '@app/useIsThemeV2'; import { useSetAppTheme } from '@app/useSetAppTheme'; import { useSetNavBarRedesignEnabled } from '@app/useShowNavBarRedesign'; import { NEW_ROUTE_MAP, PageRoutes } from '@conf/Global'; @@ -34,16 +33,9 @@ export const ProtectedRoutes = (): JSX.Element => { useSetUserTitle(); useSetNavBarRedesignEnabled(); - const isThemeV2 = useIsThemeV2(); const showHomepageRedesign = useShowHomePageRedesign(); + const FinalHomePage = showHomepageRedesign ? HomePageV3 : HomePageV2; - let FinalHomePage; - - if (isThemeV2) { - FinalHomePage = showHomepageRedesign ? HomePageV3 : HomePageV2; - } else { - FinalHomePage = HomePage; - } const location = useLocation(); const history = useHistory(); @@ -57,7 +49,7 @@ export const ProtectedRoutes = (): JSX.Element => { return ( - + } /> } /> diff --git a/datahub-web-react/src/app/SearchRoutes.tsx b/datahub-web-react/src/app/SearchRoutes.tsx index dbb741782a5f93..8fc2e9c27518e7 100644 --- a/datahub-web-react/src/app/SearchRoutes.tsx +++ b/datahub-web-react/src/app/SearchRoutes.tsx @@ -6,22 +6,14 @@ import { ManageApplications } from '@app/applications/ManageApplications'; import { BrowseResultsPage } from '@app/browse/BrowseResultsPage'; import { BusinessAttributes } from '@app/businessAttribute/BusinessAttributes'; import { useUserContext } from '@app/context/useUserContext'; -import DomainRoutes from '@app/domain/DomainRoutes'; -import { ManageDomainsPage } from '@app/domain/ManageDomainsPage'; import DomainRoutesV2 from '@app/domainV2/DomainRoutes'; import { ManageDomainsPage as ManageDomainsPageV2 } from '@app/domainV2/ManageDomainsPage'; -import { EntityPage } from '@app/entity/EntityPage'; import { EntityPage as EntityPageV2 } from '@app/entityV2/EntityPage'; -import GlossaryRoutes from '@app/glossary/GlossaryRoutes'; import GlossaryRoutesV2 from '@app/glossaryV2/GlossaryRoutes'; import StructuredProperties from '@app/govern/structuredProperties/StructuredProperties'; -import { ManageIngestionPage } from '@app/ingest/ManageIngestionPage'; import { ManageIngestionPage as ManageIngestionPageV2 } from '@app/ingestV2/ManageIngestionPage'; -import { SearchPage } from '@app/search/SearchPage'; -import { SearchablePage } from '@app/search/SearchablePage'; import { SearchPage as SearchPageV2 } from '@app/searchV2/SearchPage'; import { SearchablePage as SearchablePageV2 } from '@app/searchV2/SearchablePage'; -import { SettingsPage } from '@app/settings/SettingsPage'; import { SettingsPage as SettingsPageV2 } from '@app/settingsV2/SettingsPage'; import { NoPageFound } from '@app/shared/NoPageFound'; import { ManageTags } from '@app/tags/ManageTags'; @@ -32,7 +24,6 @@ import { useIsNestedDomainsEnabled, } from '@app/useAppConfig'; import { useEntityRegistry } from '@app/useEntityRegistry'; -import { useIsThemeV2 } from '@app/useIsThemeV2'; import { PageRoutes } from '@conf/Global'; /** @@ -46,8 +37,6 @@ export const SearchRoutes = (): JSX.Element => { ? entityRegistry.getEntitiesForSearchRoutes() : entityRegistry.getNonGlossaryEntities(); const { config, loaded } = useAppConfig(); - const isThemeV2 = useIsThemeV2(); - const FinalSearchablePage = isThemeV2 ? SearchablePageV2 : SearchablePage; const businessAttributesFlag = useBusinessAttributesFlag(); const appConfigContextLoaded = useIsAppConfigContextLoaded(); @@ -64,25 +53,16 @@ export const SearchRoutes = (): JSX.Element => { const showAnalytics = (config?.analyticsConfig?.enabled && me && me?.platformPrivileges?.viewAnalytics) || false; return ( - + {entities.map((entity) => ( - isThemeV2 ? ( - - ) : ( - - ) - } + render={() => } /> ))} - (isThemeV2 ? : )} - /> + } /> } /> {showTags ? } /> : null} } /> @@ -97,27 +77,13 @@ export const SearchRoutes = (): JSX.Element => { /> } /> } /> - {isNestedDomainsEnabled && ( - (isThemeV2 ? : )} - /> - )} - {!isNestedDomainsEnabled && ( - (isThemeV2 ? : )} - /> - )} + {isNestedDomainsEnabled && } />} + {!isNestedDomainsEnabled && } />} - {!showIngestV2 && } />} {showIngestV2 && } />} - (isThemeV2 ? : )} /> - (isThemeV2 ? : )} - /> + } /> + } /> {showStructuredProperties && ( } /> )} @@ -135,6 +101,6 @@ export const SearchRoutes = (): JSX.Element => { /> {me.loaded && loaded && } - + ); }; diff --git a/datahub-web-react/src/app/analyticsDashboard/components/AnalyticsPage.tsx b/datahub-web-react/src/app/analyticsDashboard/components/AnalyticsPage.tsx index ccd17a69051452..21cf0a40fa66bf 100644 --- a/datahub-web-react/src/app/analyticsDashboard/components/AnalyticsPage.tsx +++ b/datahub-web-react/src/app/analyticsDashboard/components/AnalyticsPage.tsx @@ -9,15 +9,14 @@ import { useUserContext } from '@app/context/useUserContext'; import { ANTD_GRAY } from '@app/entity/shared/constants'; import filterSearchQuery from '@app/search/utils/filterSearchQuery'; import { Message } from '@app/shared/Message'; -import { useIsThemeV2 } from '@app/useIsThemeV2'; import { useShowNavBarRedesign } from '@src/app/useShowNavBarRedesign'; import { useGetAnalyticsChartsQuery, useGetMetadataAnalyticsChartsQuery } from '@graphql/analytics.generated'; import { useListDomainsQuery } from '@graphql/domain.generated'; import { useGetHighlightsQuery } from '@graphql/highlights.generated'; -const PageContainer = styled.div<{ isV2: boolean; $isShowNavBarRedesign?: boolean }>` - background-color: ${(props) => (props.isV2 ? '#fff' : 'inherit')}; +const PageContainer = styled.div<{ $isShowNavBarRedesign?: boolean }>` + background-color: #fff; ${(props) => props.$isShowNavBarRedesign && ` @@ -29,12 +28,12 @@ const PageContainer = styled.div<{ isV2: boolean; $isShowNavBarRedesign?: boolea ${(props) => !props.$isShowNavBarRedesign && ` - margin-right: ${props.isV2 ? '24px' : '0'}; - margin-bottom: ${props.isV2 ? '24px' : '0'}; + margin-right: 24px; + margin-bottom: 24px; `} border-radius: ${(props) => { - if (props.isV2 && props.$isShowNavBarRedesign) return props.theme.styles['border-radius-navbar-redesign']; - return props.isV2 ? '8px' : '0'; + if (props.$isShowNavBarRedesign) return props.theme.styles['border-radius-navbar-redesign']; + return '8px'; }}; `; @@ -75,7 +74,6 @@ const StyledSearchBar = styled(Input)` `; export const AnalyticsPage = () => { - const isV2 = useIsThemeV2(); const isShowNavBarRedesign = useShowNavBarRedesign(); const me = useUserContext(); const canManageDomains = me?.platformPrivileges?.createDomains; @@ -118,7 +116,7 @@ export const AnalyticsPage = () => { const isLoading = highlightLoading || chartLoading || domainLoading || metadataAnalyticsLoading; return ( - + {isLoading && } {highlightError && ( diff --git a/datahub-web-react/src/app/entity/shared/entityForm/FormByEntity.tsx b/datahub-web-react/src/app/entity/shared/entityForm/FormByEntity.tsx index 3cdbdf298eef6b..24fd4ce825c862 100644 --- a/datahub-web-react/src/app/entity/shared/entityForm/FormByEntity.tsx +++ b/datahub-web-react/src/app/entity/shared/entityForm/FormByEntity.tsx @@ -9,7 +9,6 @@ import { useEntityFormContext } from '@app/entity/shared/entityForm/EntityFormCo import Form from '@app/entity/shared/entityForm/Form'; import ProgressBar from '@app/entity/shared/entityForm/ProgressBar'; import { useEntityRegistry } from '@app/useEntityRegistry'; -import { useIsThemeV2 } from '@app/useIsThemeV2'; const ContentWrapper = styled.div` background-color: ${ANTD_GRAY_V2[1]}; @@ -36,15 +35,9 @@ export default function FormByEntity({ formUrn }: Props) { const { entityType } = useEntityContext(); const entityRegistry = useEntityRegistry(); const sidebarSections = entityRegistry.getSidebarSections(selectedEntity?.type || entityType); - const isV2 = useIsThemeV2(); - // Used for v2 - removes repeated entity header (we use EntityInfo in this component) - // SidebarEntityHeader is always the first index in sidebarSections, so remove it here - // TODO (OBS-677): remove this logic once we get form info into V2 sidebar const cleanedSidebarSections = sidebarSections.slice(1); - - // Conditional sections based on theme version - const sections = isV2 ? cleanedSidebarSections : sidebarSections; + const sections = cleanedSidebarSections; return ( ` +const AddButton = styled.div<{ isV1Drawer?: boolean }>` border-radius: 200px; - background-color: ${(props) => - props.isThemeV2 ? props.theme.styles['primary-color'] : REDESIGN_COLORS.LINK_HOVER_BLUE}; + background-color: ${(props) => props.theme.styles['primary-color']}; width: ${(props) => (props.isV1Drawer ? '24px' : '32px')}; height: ${(props) => (props.isV1Drawer ? '24px' : '32px')}; display: flex; @@ -82,7 +79,6 @@ interface Props { const AddPropertyButton = ({ fieldUrn, refetch, fieldProperties, isV1Drawer }: Props) => { const [searchQuery, setSearchQuery] = useState(''); const { entityData, entityType } = useEntityData(); - const isThemeV2 = useIsThemeV2(); const me = useUserContext(); const entityRegistry = useEntityRegistry(); const [isEditModalVisible, setIsEditModalVisible] = useState(false); @@ -194,7 +190,7 @@ const AddPropertyButton = ({ fieldUrn, refetch, fieldProperties, isV1Drawer }: P )} > - + diff --git a/datahub-web-react/src/app/onboarding/OnboardingTour.tsx b/datahub-web-react/src/app/onboarding/OnboardingTour.tsx index 6726daeb0e9984..4f756c52fb0ec6 100644 --- a/datahub-web-react/src/app/onboarding/OnboardingTour.tsx +++ b/datahub-web-react/src/app/onboarding/OnboardingTour.tsx @@ -8,7 +8,6 @@ import { REDESIGN_COLORS } from '@app/entityV2/shared/constants'; import OnboardingContext from '@app/onboarding/OnboardingContext'; import useShouldSkipOnboardingTour from '@app/onboarding/useShouldSkipOnboardingTour'; import { convertStepId, getConditionalStepIdsToAdd, getStepsToRender } from '@app/onboarding/utils'; -import { useIsThemeV2 } from '@app/useIsThemeV2'; import { EducationStepsContext } from '@providers/EducationStepsContext'; import { useBatchUpdateStepStatesMutation } from '@graphql/step.generated'; @@ -21,10 +20,9 @@ type Props = { export const OnboardingTour = ({ stepIds }: Props) => { const { educationSteps, setEducationSteps, educationStepIdsAllowlist } = useContext(EducationStepsContext); const userUrn = useUserContext()?.user?.urn; - const isThemeV2 = useIsThemeV2(); const { isTourOpen, tourReshow, setTourReshow, setIsTourOpen } = useContext(OnboardingContext); const location = useLocation(); - const accentColor = isThemeV2 ? REDESIGN_COLORS.BACKGROUND_PURPLE : '#5cb7b7'; + const accentColor = REDESIGN_COLORS.BACKGROUND_PURPLE; useEffect(() => { function handleKeyDown(e) { diff --git a/datahub-web-react/src/app/settingsV2/Preferences.tsx b/datahub-web-react/src/app/settingsV2/Preferences.tsx index dc434075e837cf..69902efc1e5736 100644 --- a/datahub-web-react/src/app/settingsV2/Preferences.tsx +++ b/datahub-web-react/src/app/settingsV2/Preferences.tsx @@ -3,14 +3,10 @@ import { message } from 'antd'; import React from 'react'; import styled from 'styled-components'; -import analytics, { EventType } from '@app/analytics'; import { useUserContext } from '@app/context/useUserContext'; import { useAppConfig } from '@app/useAppConfig'; -import { useIsThemeV2, useIsThemeV2EnabledForUser, useIsThemeV2Toggleable } from '@app/useIsThemeV2'; import { useUpdateApplicationsSettingsMutation } from '@graphql/app.generated'; -import { useUpdateUserSettingMutation } from '@graphql/me.generated'; -import { UserSetting } from '@types'; const Page = styled.div` width: 100%; @@ -70,22 +66,13 @@ const DescriptionText = styled.div` `; export const Preferences = () => { - // Current User Urn - const { user, refetchUser } = useUserContext(); - const isThemeV2 = useIsThemeV2(); - const [isThemeV2Toggleable] = useIsThemeV2Toggleable(); - const [isThemeV2EnabledForUser] = useIsThemeV2EnabledForUser(); const userContext = useUserContext(); const appConfig = useAppConfig(); - const showSimplifiedHomepage = !!user?.settings?.appearance?.showSimplifiedHomepage; - const applicationsEnabled = appConfig.config?.visualConfig?.application?.showApplicationInNavigation ?? false; - const [updateUserSettingMutation] = useUpdateUserSettingMutation(); const [updateApplicationsSettingsMutation] = useUpdateApplicationsSettingsMutation(); - const showSimplifiedHomepageSetting = !isThemeV2; const canManageApplicationAppearance = userContext?.platformPrivileges?.manageFeatures; return ( @@ -96,77 +83,6 @@ export const Preferences = () => { - {showSimplifiedHomepageSetting && ( - - - - Show simplified homepage - - Limits entity browse cards on homepage to Domains, Charts, Datasets, Dashboards and - Glossary Terms - - - { - await updateUserSettingMutation({ - variables: { - input: { - name: UserSetting.ShowSimplifiedHomepage, - value: !showSimplifiedHomepage, - }, - }, - }); - analytics.event({ - type: showSimplifiedHomepage - ? EventType.ShowStandardHomepageEvent - : EventType.ShowSimplifiedHomepageEvent, - }); - message.success({ content: 'Setting updated!', duration: 2 }); - refetchUser?.(); - }} - /> - - - )} - {isThemeV2Toggleable && ( - <> - - - - Try New User Experience - - Enable an early preview of the new DataHub UX - a complete makeover for your app - with a sleek new design and advanced features. - - - { - await updateUserSettingMutation({ - variables: { - input: { - name: UserSetting.ShowThemeV2, - value: !isThemeV2EnabledForUser, - }, - }, - }); - // clicking this button toggles, so event is whatever is opposite to what isThemeV2EnabledForUser currently is - analytics.event({ - type: isThemeV2EnabledForUser - ? EventType.RevertV2ThemeEvent - : EventType.ShowV2ThemeEvent, - }); - message.success({ content: 'Setting updated!', duration: 2 }); - refetchUser?.(); - }} - /> - - - - )} {canManageApplicationAppearance && ( @@ -195,7 +111,7 @@ export const Preferences = () => { )} - {!showSimplifiedHomepageSetting && !isThemeV2Toggleable && !canManageApplicationAppearance && ( + {!canManageApplicationAppearance && (
No appearance settings found.
)} diff --git a/datahub-web-react/src/app/settingsV2/SettingsPage.tsx b/datahub-web-react/src/app/settingsV2/SettingsPage.tsx index d45ec45ef82905..81808d6d342ca1 100644 --- a/datahub-web-react/src/app/settingsV2/SettingsPage.tsx +++ b/datahub-web-react/src/app/settingsV2/SettingsPage.tsx @@ -20,7 +20,6 @@ import NavBarMenu from '@app/homeV2/layout/navBarRedesign/NavBarMenu'; import { NavBarMenuItemTypes, NavBarMenuItems } from '@app/homeV2/layout/navBarRedesign/types'; import { DEFAULT_PATH, PATHS } from '@app/settingsV2/settingsPaths'; import { useAppConfig } from '@app/useAppConfig'; -import { useIsThemeV2 } from '@app/useIsThemeV2'; import { useShowNavBarRedesign } from '@app/useShowNavBarRedesign'; import { Button, colors } from '@src/alchemy-components'; @@ -86,7 +85,6 @@ export const SettingsPage = () => { const history = useHistory(); const subscriptionsEnabled = false; const me = useUserContext(); - const isThemeV2 = useIsThemeV2(); const isShowNavBarRedesign = useShowNavBarRedesign(); const { config } = useAppConfig(); @@ -246,7 +244,7 @@ export const SettingsPage = () => { Settings Manage your settings - {isThemeV2 && !isShowNavBarRedesign && ( + {!isShowNavBarRedesign && ( - - - } - > -
{ - setCreateButtonEnabled(!form.getFieldsError().some((field) => field.errors.length > 0)); - }} - > - {isNestedDomainsEnabled && ( - Parent (optional)}> - - - )} - Name}> - - - - - {SUGGESTED_DOMAIN_NAMES.map((name) => { - return ( - { - form.setFieldsValue({ - name, - }); - setCreateButtonEnabled(true); - }} - > - {name} - - ); - })} - - - Description} - help="You can always change the description later." - > - - - - - - Advanced Options} key="1"> - Domain Id} - help="By default, a random UUID will be generated to uniquely identify this domain. If - you'd like to provide a custom id instead to more easily keep track of this domain, - you may provide it here. Be careful, you cannot easily change the domain id after - creation." - > - ({ - validator(_, value) { - if (value && validateCustomUrnId(value)) { - return Promise.resolve(); - } - return Promise.reject(new Error('Please enter a valid Domain id')); - }, - }), - ]} - > - - - - - -
- - ); -} diff --git a/datahub-web-react/src/app/domain/DomainItemMenu.tsx b/datahub-web-react/src/app/domain/DomainItemMenu.tsx deleted file mode 100644 index 99ccd357b0cabc..00000000000000 --- a/datahub-web-react/src/app/domain/DomainItemMenu.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { DeleteOutlined } from '@ant-design/icons'; -import { Dropdown, Menu, Modal, message } from 'antd'; -import React from 'react'; - -import { MenuIcon } from '@app/entity/shared/EntityDropdown/EntityDropdown'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useDeleteDomainMutation } from '@graphql/domain.generated'; -import { EntityType } from '@types'; - -type Props = { - urn: string; - name: string; - onDelete?: () => void; -}; - -export default function DomainItemMenu({ name, urn, onDelete }: Props) { - const entityRegistry = useEntityRegistry(); - const [deleteDomainMutation] = useDeleteDomainMutation(); - - const deleteDomain = () => { - deleteDomainMutation({ - variables: { - urn, - }, - }) - .then(({ errors }) => { - if (!errors) { - message.success('Deleted Domain!'); - onDelete?.(); - } - }) - .catch(() => { - message.destroy(); - message.error({ content: `Failed to delete Domain!: An unknown error occurred.`, duration: 3 }); - }); - }; - - const onConfirmDelete = () => { - Modal.confirm({ - title: `Delete Domain '${name}'`, - content: `Are you sure you want to remove this ${entityRegistry.getEntityName(EntityType.Domain)}?`, - onOk() { - deleteDomain(); - }, - onCancel() {}, - okText: 'Yes', - maskClosable: true, - closable: true, - }); - }; - - const items = [ - { - key: 0, - label: ( - -  Delete - - ), - }, - ]; - - return ( - - - - ); -} diff --git a/datahub-web-react/src/app/domain/DomainListColumns.tsx b/datahub-web-react/src/app/domain/DomainListColumns.tsx deleted file mode 100644 index 10368d6b3cfaa7..00000000000000 --- a/datahub-web-react/src/app/domain/DomainListColumns.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { Tag, Tooltip, Typography } from 'antd'; -import React from 'react'; -import { Link } from 'react-router-dom'; -import styled from 'styled-components'; - -import DomainItemMenu from '@app/domain/DomainItemMenu'; -import AvatarsGroup from '@app/shared/avatar/AvatarsGroup'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { Maybe, Ownership } from '@types'; - -interface DomainEntry { - name: string; - entities: string; - urn: string; - ownership?: Maybe; - url: string; -} - -const AvatarGroupWrapper = styled.div` - margin-right: 10px; - display: inline-block; -`; - -const DomainNameContainer = styled.div` - margin-left: 16px; - margin-right: 16px; - display: inline; -`; - -export function DomainListMenuColumn(handleDelete: (urn: string) => void) { - return (record: DomainEntry) => ( - handleDelete(record.urn)} /> - ); -} - -export function DomainNameColumn(logoIcon: JSX.Element) { - return (record: DomainEntry) => ( - - - {logoIcon} - - {record.name} - - - {record.entities} entities - - - - ); -} - -export function DomainOwnersColumn(ownership: Maybe) { - const entityRegistry = useEntityRegistry(); - - if (!ownership) { - return null; - } - - const { owners } = ownership; - if (!owners || owners.length === 0) { - return null; - } - return ( - - - - ); -} diff --git a/datahub-web-react/src/app/domain/DomainRoutes.tsx b/datahub-web-react/src/app/domain/DomainRoutes.tsx deleted file mode 100644 index 46c90c30bc3140..00000000000000 --- a/datahub-web-react/src/app/domain/DomainRoutes.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React, { useState } from 'react'; -import { Route, Switch } from 'react-router-dom'; -import styled from 'styled-components/macro'; - -import { DomainsContext } from '@app/domain/DomainsContext'; -import ManageDomainsPageV2 from '@app/domain/nestedDomains/ManageDomainsPageV2'; -import ManageDomainsSidebar from '@app/domain/nestedDomains/ManageDomainsSidebar'; -import { EntityPage } from '@app/entity/EntityPage'; -import { GenericEntityProperties } from '@app/entity/shared/types'; -import { useEntityRegistry } from '@app/useEntityRegistry'; -import { PageRoutes } from '@conf/Global'; - -import { EntityType } from '@types'; - -const ContentWrapper = styled.div` - display: flex; - flex: 1; - overflow: hidden; -`; - -export default function DomainRoutes() { - const entityRegistry = useEntityRegistry(); - const [entityData, setEntityData] = useState(null); - const [parentDomainsToUpdate, setParentDomainsToUpdate] = useState([]); - - return ( - - - - - } - /> - } /> - - - - ); -} diff --git a/datahub-web-react/src/app/domain/DomainSearch.tsx b/datahub-web-react/src/app/domain/DomainSearch.tsx deleted file mode 100644 index 975e7d3aac7f9c..00000000000000 --- a/datahub-web-react/src/app/domain/DomainSearch.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import { LoadingOutlined } from '@ant-design/icons'; -import React, { useRef, useState } from 'react'; -import styled from 'styled-components/macro'; - -import DomainSearchResultItem from '@app/domain/DomainSearchResultItem'; -import { SearchBar } from '@app/search/SearchBar'; -import ClickOutside from '@app/shared/ClickOutside'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useGetSearchResultsForMultipleQuery } from '@graphql/search.generated'; -import { EntityType } from '@types'; - -const DomainSearchWrapper = styled.div` - position: relative; -`; - -const ResultsWrapper = styled.div` - background-color: white; - border-radius: 5px; - box-shadow: - 0 3px 6px -4px rgb(0 0 0 / 12%), - 0 6px 16px 0 rgb(0 0 0 / 8%), - 0 9px 28px 8px rgb(0 0 0 / 5%); - max-height: 380px; - overflow: auto; - padding: 8px; - position: absolute; - max-height: 210px; - overflow: auto; - width: calc(100% - 24px); - left: 12px; - top: 45px; - z-index: 1; -`; - -const LoadingWrapper = styled.div` - display: flex; - align-items: center; - justify-content: center; - height: 350px; - font-size: 30px; -`; - -function DomainSearch() { - const [query, setQuery] = useState(''); - const [isSearchBarFocused, setIsSearchBarFocused] = useState(false); - const entityRegistry = useEntityRegistry(); - const { data, loading } = useGetSearchResultsForMultipleQuery({ - variables: { - input: { - types: [EntityType.Domain], - query, - start: 0, - count: 50, - }, - }, - }); - - const searchResults = data?.searchAcrossEntities?.searchResults; - const timerRef = useRef(-1); - - const handleQueryChange = (q: string) => { - window.clearTimeout(timerRef.current); - timerRef.current = window.setTimeout(() => { - setQuery(q); - }, 250); - }; - - const renderLoadingIndicator = () => ( - - - - ); - - const renderSearchResults = () => ( - - {searchResults?.map((result) => ( - setIsSearchBarFocused(false)} - /> - ))} - - ); - - return ( - - setIsSearchBarFocused(false)}> - null} - onQueryChange={(q) => handleQueryChange(q)} - entityRegistry={entityRegistry} - onFocus={() => setIsSearchBarFocused(true)} - /> - {loading && renderLoadingIndicator()} - {!loading && isSearchBarFocused && !!searchResults?.length && renderSearchResults()} - - - ); -} - -export default DomainSearch; diff --git a/datahub-web-react/src/app/domain/DomainSearchResultItem.tsx b/datahub-web-react/src/app/domain/DomainSearchResultItem.tsx deleted file mode 100644 index 96e92ce525d9d6..00000000000000 --- a/datahub-web-react/src/app/domain/DomainSearchResultItem.tsx +++ /dev/null @@ -1,70 +0,0 @@ -// Create a new component called SearchResultItem.js -import React from 'react'; -import Highlight from 'react-highlighter'; -import { Link } from 'react-router-dom'; -import styled from 'styled-components/macro'; - -import DomainIcon from '@app/domain/DomainIcon'; -import { getParentDomains } from '@app/domain/utils'; -import { IconStyleType } from '@app/entity/Entity'; -import EntityRegistry from '@app/entity/EntityRegistry'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import ParentEntities from '@app/search/filters/ParentEntities'; - -import { Entity, EntityType } from '@types'; - -type Props = { - entity: Entity; - entityRegistry: EntityRegistry; - query: string; - onResultClick: () => void; -}; - -const SearchResult = styled(Link)` - color: #262626; - display: flex; - align-items: center; - gap: 8px; - height: 100%; - padding: 6px 8px; - width: 100%; - &:hover { - background-color: ${ANTD_GRAY[3]}; - color: #262626; - } -`; - -const IconWrapper = styled.span``; - -const highlightMatchStyle = { - fontWeight: 'bold', - background: 'none', - padding: 0, -}; - -function DomainSearchResultItem({ entity, entityRegistry, query, onResultClick }: Props) { - return ( - - - {entity.type === EntityType.Domain ? ( - - ) : ( - entityRegistry.getIcon(entity.type, 12, IconStyleType.ACCENT) - )} - -
- - - {entityRegistry.getDisplayName(entity.type, entity)} - -
-
- ); -} - -export default DomainSearchResultItem; diff --git a/datahub-web-react/src/app/domain/DomainsContext.tsx b/datahub-web-react/src/app/domain/DomainsContext.tsx index da88ed1f3d582f..3a93fed0dfc683 100644 --- a/datahub-web-react/src/app/domain/DomainsContext.tsx +++ b/datahub-web-react/src/app/domain/DomainsContext.tsx @@ -2,14 +2,14 @@ import React, { useContext } from 'react'; import { GenericEntityProperties } from '@app/entity/shared/types'; -export interface DomainsContextType { +interface DomainsContextType { entityData: GenericEntityProperties | null; setEntityData: (entityData: GenericEntityProperties | null) => void; parentDomainsToUpdate: string[]; setParentDomainsToUpdate: (values: string[]) => void; } -export const DomainsContext = React.createContext({ +const DomainsContext = React.createContext({ entityData: null, setEntityData: () => {}, parentDomainsToUpdate: [], // used to tell domains to refetch their children count after updates (create, move, delete) diff --git a/datahub-web-react/src/app/domain/DomainsList.tsx b/datahub-web-react/src/app/domain/DomainsList.tsx deleted file mode 100644 index 8787a67d68c322..00000000000000 --- a/datahub-web-react/src/app/domain/DomainsList.tsx +++ /dev/null @@ -1,213 +0,0 @@ -import { PlusOutlined } from '@ant-design/icons'; -import { Button, Empty, Pagination, Typography } from 'antd'; -import * as QueryString from 'query-string'; -import { AlignType } from 'rc-table/lib/interface'; -import React, { useEffect, useState } from 'react'; -import { useLocation } from 'react-router'; -import styled from 'styled-components'; - -import CreateDomainModal from '@app/domain/CreateDomainModal'; -import DomainIcon from '@app/domain/DomainIcon'; -import { DomainListMenuColumn, DomainNameColumn, DomainOwnersColumn } from '@app/domain/DomainListColumns'; -import { addToListDomainsCache, removeFromListDomainsCache } from '@app/domain/utils'; -import { StyledTable } from '@app/entity/shared/components/styled/StyledTable'; -import TabToolbar from '@app/entity/shared/components/styled/TabToolbar'; -import { getElasticCappedTotalValueText } from '@app/entity/shared/constants'; -import { OnboardingTour } from '@app/onboarding/OnboardingTour'; -import { DOMAINS_CREATE_DOMAIN_ID, DOMAINS_INTRO_ID } from '@app/onboarding/config/DomainsOnboardingConfig'; -import { SearchBar } from '@app/search/SearchBar'; -import { Message } from '@app/shared/Message'; -import { scrollToTop } from '@app/shared/searchUtils'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useListDomainsQuery } from '@graphql/domain.generated'; -import { EntityType } from '@types'; - -const DomainsContainer = styled.div``; - -export const DomainsPaginationContainer = styled.div` - display: flex; - justify-content: center; - padding: 12px; - padding-left: 16px; - border-bottom: 1px solid; - border-color: ${(props) => props.theme.styles['border-color-base']}; - display: flex; - justify-content: space-between; - align-items: center; -`; - -const PaginationInfo = styled(Typography.Text)` - padding: 0px; -`; - -const DEFAULT_PAGE_SIZE = 25; - -export const DomainsList = () => { - const entityRegistry = useEntityRegistry(); - const location = useLocation(); - const params = QueryString.parse(location.search, { arrayFormat: 'comma' }); - const paramsQuery = (params?.query as string) || undefined; - const [query, setQuery] = useState(undefined); - useEffect(() => setQuery(paramsQuery), [paramsQuery]); - - const [page, setPage] = useState(1); - const [isCreatingDomain, setIsCreatingDomain] = useState(false); - - const pageSize = DEFAULT_PAGE_SIZE; - const start = (page - 1) * pageSize; - - const { loading, error, data, client, refetch } = useListDomainsQuery({ - variables: { - input: { - start, - count: pageSize, - query, - }, - }, - fetchPolicy: query && query.length > 0 ? 'no-cache' : 'cache-first', - }); - - const totalDomains = data?.listDomains?.total || 0; - const lastResultIndex = start + pageSize > totalDomains ? totalDomains : start + pageSize; - const domains = data?.listDomains?.domains || []; - - const onChangePage = (newPage: number) => { - scrollToTop(); - setPage(newPage); - }; - - const handleDelete = (urn: string) => { - removeFromListDomainsCache(client, urn, page, pageSize); - setTimeout(() => { - refetch?.(); - }, 2000); - }; - - const allColumns = [ - { - title: 'Name', - dataIndex: '', - key: 'name', - sorter: (sourceA, sourceB) => { - return sourceA.name.localeCompare(sourceB.name); - }, - render: DomainNameColumn( - , - ), - }, - { - title: 'Owners', - dataIndex: 'ownership', - width: '10%', - key: 'ownership', - render: DomainOwnersColumn, - }, - { - title: '', - dataIndex: '', - width: '5%', - align: 'right' as AlignType, - key: 'menu', - render: DomainListMenuColumn(handleDelete), - }, - ]; - - const tableData = domains.map((domain) => { - const displayName = entityRegistry.getDisplayName(EntityType.Domain, domain); - const totalEntitiesText = getElasticCappedTotalValueText(domain.entities?.total || 0); - const url = entityRegistry.getEntityUrl(EntityType.Domain, domain.urn); - - return { - urn: domain.urn, - name: displayName, - entities: totalEntitiesText, - ownership: domain.ownership, - url, - }; - }); - - return ( - <> - {!data && loading && } - {error && } - - - - - null} - onQueryChange={(q) => setQuery(q && q.length > 0 ? q : undefined)} - entityRegistry={entityRegistry} - hideRecommendations - /> - - }} - /> - - - - {lastResultIndex > 0 ? (page - 1) * pageSize + 1 : 0} - {lastResultIndex} - - of {totalDomains} - - - - - {isCreatingDomain && ( - setIsCreatingDomain(false)} - onCreate={(urn, _, name, description) => { - addToListDomainsCache( - client, - { - urn, - properties: { - name, - description: description || null, - }, - ownership: null, - entities: null, - displayProperties: null, - institutionalMemory: null, - }, - pageSize, - ); - setTimeout(() => refetch(), 2000); - }} - /> - )} - - - ); -}; diff --git a/datahub-web-react/src/app/domain/EmptyDomainDescription.tsx b/datahub-web-react/src/app/domain/EmptyDomainDescription.tsx deleted file mode 100644 index b232aa3780c7c5..00000000000000 --- a/datahub-web-react/src/app/domain/EmptyDomainDescription.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components/macro'; - -import { ANTD_GRAY } from '@app/entity/shared/constants'; - -const StyledParagraph = styled(Typography.Paragraph)` - text-align: justify; - text-justify: inter-word; - margin: 40px 0; - font-size: 15px; -`; - -function EmptyDomainDescription() { - return ( - <> - - Welcome to your Data Domains! It looks like this space - is ready to be transformed into a well-organized data universe. Start by creating your first domain - a - high-level category for your data assets. - - - Create Nested Domains: Want to dive deeper? You can - also create nested domains to add granularity and structure. Just like nesting Russian dolls, its all - about refining your organization. - - - Build Data Products: Once your domains are set, go a - step further! Organize your data assets into data products to realize a data mesh architecture. Data - products empower you to treat data as a product, making it more accessible and manageable. - - - Ready to embark on this data adventure? Click the Create Domain button to begin shaping your data - landscape! - - - ); -} - -export default EmptyDomainDescription; diff --git a/datahub-web-react/src/app/domain/EmptyDomainsSection.tsx b/datahub-web-react/src/app/domain/EmptyDomainsSection.tsx deleted file mode 100644 index cffde970b4749e..00000000000000 --- a/datahub-web-react/src/app/domain/EmptyDomainsSection.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { PlusOutlined } from '@ant-design/icons'; -import { Button, Empty, Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components/macro'; - -import { ANTD_GRAY } from '@app/entity/shared/constants'; - -const EmptyDomainContainer = styled.div` - display: flex; - justify-content: center; - align-items: center; -`; - -const StyledEmpty = styled(Empty)` - width: 35vw; - @media screen and (max-width: 1300px) { - width: 50vw; - } - @media screen and (max-width: 896px) { - overflow-y: auto; - max-height: 75vh; - &::-webkit-scrollbar { - width: 5px; - background: #d6d6d6; - } - } - padding: 60px 40px; - .ant-empty-image { - display: none; - } -`; - -const StyledButton = styled(Button)` - margin: 18px 8px 0 0; -`; - -const IconContainer = styled.span` - color: ${ANTD_GRAY[7]}; - font-size: 40px; -`; - -interface Props { - title?: string; - setIsCreatingDomain: React.Dispatch>; - description?: React.ReactNode; - icon?: React.ReactNode; -} - -function EmptyDomainsSection(props: Props) { - const { title, description, setIsCreatingDomain, icon } = props; - return ( - - - {icon} - {title} - {description} - - } - > - setIsCreatingDomain(true)}> - Create Domain - - - - ); -} - -export default EmptyDomainsSection; diff --git a/datahub-web-react/src/app/domain/ManageDomainsPage.tsx b/datahub-web-react/src/app/domain/ManageDomainsPage.tsx deleted file mode 100644 index d662377b5b51ba..00000000000000 --- a/datahub-web-react/src/app/domain/ManageDomainsPage.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { Typography } from 'antd'; -import React, { useState } from 'react'; -import styled from 'styled-components'; - -import { DomainsContext } from '@app/domain/DomainsContext'; -import { DomainsList } from '@app/domain/DomainsList'; -import { GenericEntityProperties } from '@app/entity/shared/types'; - -const PageContainer = styled.div` - padding-top: 20px; -`; - -const PageHeaderContainer = styled.div` - && { - padding-left: 24px; - } -`; - -const PageTitle = styled(Typography.Title)` - && { - margin-bottom: 12px; - } -`; - -const ListContainer = styled.div``; - -export const ManageDomainsPage = () => { - const [entityData, setEntityData] = useState(null); - const [parentDomainsToUpdate, setParentDomainsToUpdate] = useState([]); - - return ( - - - - Domains - - View your DataHub Domains. Take administrative actions. - - - - - - - - ); -}; diff --git a/datahub-web-react/src/app/domain/nestedDomains/DomainsSidebarHeader.tsx b/datahub-web-react/src/app/domain/nestedDomains/DomainsSidebarHeader.tsx deleted file mode 100644 index 7e723e31837d1d..00000000000000 --- a/datahub-web-react/src/app/domain/nestedDomains/DomainsSidebarHeader.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { PlusOutlined } from '@ant-design/icons'; -import { useApolloClient } from '@apollo/client'; -import { Button } from 'antd'; -import React, { useState } from 'react'; -import { Link } from 'react-router-dom'; -import styled from 'styled-components'; - -import CreateDomainModal from '@app/domain/CreateDomainModal'; -import { useDomainsContext } from '@app/domain/DomainsContext'; -import DomainsTitle from '@app/domain/nestedDomains/DomainsTitle'; -import { updateListDomainsCache } from '@app/domain/utils'; -import { ANTD_GRAY, ANTD_GRAY_V2 } from '@app/entity/shared/constants'; -import { PageRoutes } from '@conf/Global'; - -const HeaderWrapper = styled.div` - border-bottom: 1px solid ${ANTD_GRAY[4]}; - padding: 16px; - font-size: 20px; - display: flex; - align-items: center; - justify-content: space-between; -`; - -const StyledButton = styled(Button)` - box-shadow: none; - border-color: ${ANTD_GRAY_V2[6]}; -`; - -const StyledLink = styled(Link)` - color: inherit; - - &:hover { - color: inherit; - } -`; - -export default function DomainsSidebarHeader() { - const { setParentDomainsToUpdate } = useDomainsContext(); - const [isCreatingDomain, setIsCreatingDomain] = useState(false); - const client = useApolloClient(); - - return ( - - - - - } onClick={() => setIsCreatingDomain(true)} /> - {isCreatingDomain && ( - setIsCreatingDomain(false)} - onCreate={(urn, id, name, description, parentDomain) => { - updateListDomainsCache(client, urn, id, name, description, parentDomain); - if (parentDomain) setParentDomainsToUpdate([parentDomain]); - }} - /> - )} - - ); -} diff --git a/datahub-web-react/src/app/domain/nestedDomains/DomainsTitle.tsx b/datahub-web-react/src/app/domain/nestedDomains/DomainsTitle.tsx deleted file mode 100644 index ea6a93a445ce7e..00000000000000 --- a/datahub-web-react/src/app/domain/nestedDomains/DomainsTitle.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import DomainIcon from '@app/domain/DomainIcon'; - -const IconWrapper = styled.span` - margin-right: 10px; -`; - -export default function DomainsTitle() { - return ( - - - - - Domains - - ); -} diff --git a/datahub-web-react/src/app/domain/nestedDomains/ManageDomainsPageV2.tsx b/datahub-web-react/src/app/domain/nestedDomains/ManageDomainsPageV2.tsx deleted file mode 100644 index 3d7d3187f515c3..00000000000000 --- a/datahub-web-react/src/app/domain/nestedDomains/ManageDomainsPageV2.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { PlusOutlined } from '@ant-design/icons'; -import { useApolloClient } from '@apollo/client'; -import { Button } from 'antd'; -import React, { useEffect, useState } from 'react'; -import styled from 'styled-components/macro'; - -import CreateDomainModal from '@app/domain/CreateDomainModal'; -import { useDomainsContext } from '@app/domain/DomainsContext'; -import DomainsTitle from '@app/domain/nestedDomains/DomainsTitle'; -import RootDomains from '@app/domain/nestedDomains/RootDomains'; -import { updateListDomainsCache } from '@app/domain/utils'; -import { ANTD_GRAY_V2 } from '@app/entity/shared/constants'; -import { OnboardingTour } from '@app/onboarding/OnboardingTour'; -import { DOMAINS_CREATE_DOMAIN_ID, DOMAINS_INTRO_ID } from '@app/onboarding/config/DomainsOnboardingConfig'; - -const PageWrapper = styled.div` - background-color: ${ANTD_GRAY_V2[1]}; - flex: 1; - display: flex; - flex-direction: column; - overflow: hidden; -`; - -const Header = styled.div` - display: flex; - justify-content: space-between; - padding: 32px 24px; - font-size: 30px; - align-items: center; -`; - -export default function ManageDomainsPageV2() { - const { setEntityData, setParentDomainsToUpdate } = useDomainsContext(); - const [isCreatingDomain, setIsCreatingDomain] = useState(false); - const client = useApolloClient(); - - useEffect(() => { - setEntityData(null); - }, [setEntityData]); - - return ( - - -
- - -
- - {isCreatingDomain && ( - setIsCreatingDomain(false)} - onCreate={(urn, id, name, description, parentDomain) => { - updateListDomainsCache(client, urn, id, name, description, parentDomain); - if (parentDomain) setParentDomainsToUpdate([parentDomain]); - }} - /> - )} -
- ); -} diff --git a/datahub-web-react/src/app/domain/nestedDomains/ManageDomainsSidebar.tsx b/datahub-web-react/src/app/domain/nestedDomains/ManageDomainsSidebar.tsx deleted file mode 100644 index a9f2a55941657a..00000000000000 --- a/datahub-web-react/src/app/domain/nestedDomains/ManageDomainsSidebar.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React, { useState } from 'react'; - -import DomainSearch from '@app/domain/DomainSearch'; -import DomainsSidebarHeader from '@app/domain/nestedDomains/DomainsSidebarHeader'; -import DomainNavigator from '@app/domain/nestedDomains/domainNavigator/DomainNavigator'; -import { ProfileSidebarResizer } from '@app/entity/shared/containers/profile/sidebar/ProfileSidebarResizer'; -import { MAX_BROWSER_WIDTH, MIN_BROWSWER_WIDTH } from '@app/glossary/BusinessGlossaryPage'; -import { SidebarWrapper } from '@app/shared/sidebar/components'; - -export default function ManageDomainsSidebar() { - const [browserWidth, setBrowserWith] = useState(window.innerWidth * 0.2); - - return ( - <> - - - - - - - setBrowserWith(Math.min(Math.max(width, MIN_BROWSWER_WIDTH), MAX_BROWSER_WIDTH)) - } - initialSize={browserWidth} - isSidebarOnLeft - /> - - ); -} diff --git a/datahub-web-react/src/app/domain/nestedDomains/RootDomains.tsx b/datahub-web-react/src/app/domain/nestedDomains/RootDomains.tsx deleted file mode 100644 index fda3912e70ce96..00000000000000 --- a/datahub-web-react/src/app/domain/nestedDomains/RootDomains.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { ReadOutlined } from '@ant-design/icons'; -import React from 'react'; -import styled from 'styled-components'; - -import EmptyDomainDescription from '@app/domain/EmptyDomainDescription'; -import EmptyDomainsSection from '@app/domain/EmptyDomainsSection'; -import useListDomains from '@app/domain/useListDomains'; -import { ResultWrapper } from '@app/search/SearchResultList'; -import { Message } from '@app/shared/Message'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { EntityType } from '@types'; - -const DomainsWrapper = styled.div` - overflow: auto; - padding: 0 28px 16px 28px; -`; - -interface Props { - setIsCreatingDomain: React.Dispatch>; -} -export default function RootDomains({ setIsCreatingDomain }: Props) { - const entityRegistry = useEntityRegistry(); - const { loading, error, data, sortedDomains } = useListDomains({}); - - return ( - <> - {!data && loading && } - {error && } - {!loading && (!data || !data?.listDomains?.domains?.length) && ( - } - title="Organize your data" - description={} - setIsCreatingDomain={setIsCreatingDomain} - /> - )} - - {sortedDomains?.map((domain) => ( - - {entityRegistry.renderSearchResult(EntityType.Domain, { entity: domain, matchedFields: [] })} - - ))} - - - ); -} diff --git a/datahub-web-react/src/app/domain/utils.ts b/datahub-web-react/src/app/domain/utils.ts index 9bb6ad994e6e3e..a22d0ea4a75dae 100644 --- a/datahub-web-react/src/app/domain/utils.ts +++ b/datahub-web-react/src/app/domain/utils.ts @@ -14,7 +14,7 @@ import { Entity, EntityType } from '@types'; /** * Add an entry to the list domains cache. */ -export const addToListDomainsCache = (client, newDomain, pageSize, parentDomain?: string) => { +const addToListDomainsCache = (client, newDomain, pageSize, parentDomain?: string) => { // Read the data from our cache for this query. const currData: ListDomainsQuery | null = client.readQuery({ query: ListDomainsDocument, diff --git a/datahub-web-react/src/app/domainV2/DomainsList.tsx b/datahub-web-react/src/app/domainV2/DomainsList.tsx index 38835f2c83c006..4c5e13041bb99e 100644 --- a/datahub-web-react/src/app/domainV2/DomainsList.tsx +++ b/datahub-web-react/src/app/domainV2/DomainsList.tsx @@ -31,6 +31,7 @@ export const DomainsPaginationContainer = styled.div` padding: 12px; padding-left: 16px; border-bottom: 1px solid; + border-color: ${(props) => props.theme.styles['border-color-base']}; display: flex; justify-content: space-between; align-items: center; diff --git a/datahub-web-react/src/app/entity/Access/RoleEntity.tsx b/datahub-web-react/src/app/entity/Access/RoleEntity.tsx deleted file mode 100644 index 5f9c7d8f51a3f1..00000000000000 --- a/datahub-web-react/src/app/entity/Access/RoleEntity.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { TagFilled, TagOutlined } from '@ant-design/icons'; -import * as React from 'react'; -import styled from 'styled-components'; - -import RoleEntityProfile from '@app/entity/Access/RoleEntityProfile'; -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { urlEncodeUrn } from '@app/entity/shared/utils'; -import DefaultPreviewCard from '@app/preview/DefaultPreviewCard'; - -import { useGetExternalRoleQuery } from '@graphql/accessrole.generated'; -import { EntityType, Role, SearchResult } from '@types'; - -const PreviewTagIcon = styled(TagOutlined)` - font-size: 20px; -`; -// /** -// * Definition of the DataHub Access Role entity. -// */ -export class RoleEntity implements Entity { - type: EntityType = EntityType.Role; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => false; - - isLineageEnabled = () => false; - - getAutoCompleteFieldName = () => 'name'; - - getPathName: () => string = () => 'role'; - - getCollectionName: () => string = () => 'Roles'; - - getEntityName: () => string = () => 'Role'; - - useEntityQuery = useGetExternalRoleQuery; - - renderProfile: (urn: string) => JSX.Element = (_) => ; - - renderPreview = (_: PreviewType, data: Role) => ( - } - type="Role" - typeIcon={this.icon(14, IconStyleType.ACCENT)} - /> - ); - - renderSearch = (result: SearchResult) => { - return this.renderPreview(PreviewType.SEARCH, result.entity as Role); - }; - - displayName = (data: Role) => { - return data.properties?.name || data.urn; - }; - - getOverridePropertiesFromEntity = (data: Role) => { - return { - name: data.properties?.name, - }; - }; - - getGenericEntityProperties = (role: Role) => { - return getDataForEntityType({ data: role, entityType: this.type, getOverrideProperties: (data) => data }); - }; - - supportedCapabilities = () => { - return new Set([EntityCapabilityType.OWNERS]); - }; - - getGraphName = () => { - return 'roleEntity'; - }; -} diff --git a/datahub-web-react/src/app/entity/Access/RoleEntityProfile.tsx b/datahub-web-react/src/app/entity/Access/RoleEntityProfile.tsx deleted file mode 100644 index 0d75fcc833da4e..00000000000000 --- a/datahub-web-react/src/app/entity/Access/RoleEntityProfile.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { grey } from '@ant-design/colors'; -import { Divider, Typography } from 'antd'; -import React from 'react'; -import { useParams } from 'react-router'; -import styled from 'styled-components'; - -import { decodeUrn } from '@app/entity/shared/utils'; -import { Message } from '@app/shared/Message'; - -import { useGetExternalRoleQuery } from '@graphql/accessrole.generated'; - -const PageContainer = styled.div` - padding: 32px 100px; -`; - -const LoadingMessage = styled(Message)` - margin-top: 10%; -`; - -type RolePageParams = { - urn: string; -}; - -const TitleLabel = styled(Typography.Text)` - &&& { - color: ${grey[2]}; - font-size: 12px; - display: block; - line-height: 20px; - font-weight: 700; - } -`; - -const DescriptionLabel = styled(Typography.Text)` - &&& { - text-align: left; - font-weight: bold; - font-size: 14px; - line-height: 28px; - color: rgb(38, 38, 38); - } -`; - -const TitleText = styled(Typography.Text)` - &&& { - color: ${grey[10]}; - font-weight: 700; - font-size: 20px; - line-height: 28px; - display: inline-block; - margin: 0px 7px; - } -`; - -const { Paragraph } = Typography; - -export default function RoleEntityProfile() { - const { urn: encodedUrn } = useParams(); - const urn = decodeUrn(encodedUrn); - const { data, loading } = useGetExternalRoleQuery({ variables: { urn } }); - - return ( - - {loading && } - Role - {data?.role?.properties?.name} - - {/* Role Description */} - About - - {data?.role?.properties?.description} - - - ); -} diff --git a/datahub-web-react/src/app/entity/application/ApplicationEntitiesTab.tsx b/datahub-web-react/src/app/entity/application/ApplicationEntitiesTab.tsx deleted file mode 100644 index 38944d16e3c9ac..00000000000000 --- a/datahub-web-react/src/app/entity/application/ApplicationEntitiesTab.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { SearchCardContext } from '@app/entityV2/shared/SearchCardContext'; -import { EmbeddedListSearchSection } from '@app/entityV2/shared/components/styled/search/EmbeddedListSearchSection'; -import { UnionType } from '@app/searchV2/utils/constants'; - -export function ApplicationEntitiesTab() { - const { urn } = useEntityData(); - - const fixedOrFilters = [ - { - field: 'applications', - values: [urn], - }, - ]; - - return ( - - - - ); -} diff --git a/datahub-web-react/src/app/entity/application/ApplicationEntity.tsx b/datahub-web-react/src/app/entity/application/ApplicationEntity.tsx deleted file mode 100644 index b7144b0c399b7e..00000000000000 --- a/datahub-web-react/src/app/entity/application/ApplicationEntity.tsx +++ /dev/null @@ -1,259 +0,0 @@ -import { - AppstoreOutlined, - FileDoneOutlined, - FileOutlined, - ReadOutlined, - UnorderedListOutlined, -} from '@ant-design/icons'; -import { ListBullets } from '@phosphor-icons/react'; -import * as React from 'react'; - -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entityV2/Entity'; -import { ApplicationEntitiesTab } from '@app/entityV2/application/ApplicationEntitiesTab'; -import { ApplicationSummaryTab } from '@app/entityV2/application/ApplicationSummaryTab'; -import { Preview } from '@app/entityV2/application/preview/Preview'; -import { EntityMenuItems } from '@app/entityV2/shared/EntityDropdown/EntityMenuActions'; -import { TYPE_ICON_CLASS_NAME } from '@app/entityV2/shared/components/subtypes'; -import { EntityProfileTab } from '@app/entityV2/shared/constants'; -import { EntityProfile } from '@app/entityV2/shared/containers/profile/EntityProfile'; -import { SidebarAboutSection } from '@app/entityV2/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import { SidebarDomainSection } from '@app/entityV2/shared/containers/profile/sidebar/Domain/SidebarDomainSection'; -import { SidebarOwnerSection } from '@app/entityV2/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import SidebarEntityHeader from '@app/entityV2/shared/containers/profile/sidebar/SidebarEntityHeader'; -import { SidebarGlossaryTermsSection } from '@app/entityV2/shared/containers/profile/sidebar/SidebarGlossaryTermsSection'; -import { SidebarTagsSection } from '@app/entityV2/shared/containers/profile/sidebar/SidebarTagsSection'; -import StatusSection from '@app/entityV2/shared/containers/profile/sidebar/shared/StatusSection'; -import { getDataForEntityType } from '@app/entityV2/shared/containers/profile/utils'; -import SidebarNotesSection from '@app/entityV2/shared/sidebarSection/SidebarNotesSection'; -import SidebarStructuredProperties from '@app/entityV2/shared/sidebarSection/SidebarStructuredProperties'; -import { DocumentationTab } from '@app/entityV2/shared/tabs/Documentation/DocumentationTab'; -import { PropertiesTab } from '@app/entityV2/shared/tabs/Properties/PropertiesTab'; - -import { useGetApplicationQuery } from '@graphql/application.generated'; -import { Application, EntityType, SearchResult } from '@types'; - -const headerDropdownItems = new Set([EntityMenuItems.SHARE, EntityMenuItems.DELETE, EntityMenuItems.EDIT]); - -type ApplicationWithChildren = Application & { - children?: { - total: number; - } | null; -}; - -/** - * Definition of the DataHub Application entity. - */ -export class ApplicationEntity implements Entity { - type: EntityType = EntityType.Application; - - icon = (fontSize?: number, styleType?: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ( - - ); - } - - if (styleType === IconStyleType.SVG) { - return ( - - ); - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => true; - - isLineageEnabled = () => false; - - getAutoCompleteFieldName = () => 'name'; - - getPathName = () => 'application'; - - getEntityName = () => 'Application'; - - getCollectionName = () => 'Applications'; - - useEntityQuery = useGetApplicationQuery; - - renderProfile = (urn: string) => ( - { - return !loading ? entityData?.children?.total : undefined; - }, - component: ApplicationEntitiesTab, - icon: AppstoreOutlined, - }, - { - name: 'Properties', - component: PropertiesTab, - icon: UnorderedListOutlined, - }, - ]} - sidebarSections={this.getSidebarSections()} - sidebarTabs={this.getSidebarTabs()} - /> - ); - - getSidebarSections = () => [ - { - component: SidebarEntityHeader, - }, - { - component: SidebarAboutSection, - }, - { - component: SidebarNotesSection, - }, - { - component: SidebarOwnerSection, - }, - { - component: SidebarDomainSection, - properties: { - updateOnly: true, - }, - }, - { - component: SidebarTagsSection, - }, - { - component: SidebarGlossaryTermsSection, - }, - { - component: SidebarStructuredProperties, - }, - { - component: StatusSection, - }, - ]; - - getSidebarTabs = () => [ - { - name: 'Properties', - component: PropertiesTab, - description: 'View additional properties about this asset', - icon: ListBullets, - }, - ]; - - renderPreview = (previewType: PreviewType, data: any) => { - const genericProperties = this.getGenericEntityProperties(data); - return ( - - ); - }; - - renderSearch = (result: SearchResult) => { - const data = result.entity as Application; - const genericProperties = this.getGenericEntityProperties(data); - return ( - - ); - }; - - displayName = (data: Application) => { - return data?.properties?.name || data.urn; - }; - - getOverridePropertiesFromEntity = (data: Application) => { - const name = data?.properties?.name; - const externalUrl = data?.properties?.externalUrl; - const entityCount = (data as ApplicationWithChildren)?.children?.total || undefined; - const parentDomains = { - domains: (data?.domain && [data?.domain?.domain]) || [], - count: (data?.domain && 1) || 0, - }; - return { - name, - externalUrl, - entityCount, - parentDomains, - }; - }; - - getGenericEntityProperties = (data: Application) => { - return getDataForEntityType({ - data, - entityType: this.type, - getOverrideProperties: this.getOverridePropertiesFromEntity, - }); - }; - - supportedCapabilities = () => { - return new Set([ - EntityCapabilityType.OWNERS, - EntityCapabilityType.GLOSSARY_TERMS, - EntityCapabilityType.TAGS, - EntityCapabilityType.DOMAINS, - ]); - }; - - getGraphName = () => { - return 'application'; - }; -} diff --git a/datahub-web-react/src/app/entity/application/ApplicationSummaryTab.tsx b/datahub-web-react/src/app/entity/application/ApplicationSummaryTab.tsx deleted file mode 100644 index 06b3d927794563..00000000000000 --- a/datahub-web-react/src/app/entity/application/ApplicationSummaryTab.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; - -import { AssetsSection } from '@app/entityV2/application/AssetsSections'; -import { SummaryTabWrapper } from '@app/entityV2/shared/summary/HeaderComponents'; -import SummaryAboutSection from '@app/entityV2/shared/summary/SummaryAboutSection'; - -export const ApplicationSummaryTab = () => { - return ( - - - - - ); -}; diff --git a/datahub-web-react/src/app/entity/application/AssetsSections.tsx b/datahub-web-react/src/app/entity/application/AssetsSections.tsx deleted file mode 100644 index 2ad0f4dd056e2f..00000000000000 --- a/datahub-web-react/src/app/entity/application/AssetsSections.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import { AppstoreOutlined } from '@ant-design/icons'; -import { Button } from 'antd'; -import React from 'react'; -import { useHistory } from 'react-router'; -import styled from 'styled-components'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import ContentSectionLoading from '@app/entityV2/domain/summary/ContentSectionLoading'; -import { - getContentsSummary, - getDomainEntitiesFilterUrl, - navigateToDomainEntities, -} from '@app/entityV2/shared/containers/profile/sidebar/Domain/utils'; -import { SummaryTabHeaderTitle, SummaryTabHeaderWrapper } from '@app/entityV2/shared/summary/HeaderComponents'; -import { getContentTypeIcon } from '@app/entityV2/shared/summary/IconComponents'; -import { HorizontalList } from '@app/entityV2/shared/summary/ListComponents'; -import { pluralize } from '@app/shared/textUtil'; -import { EntityCountCard } from '@app/sharedV2/cards/EntityCountCard'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useGetSearchResultsForMultipleQuery } from '@graphql/search.generated'; - -const AssetsSectionWrapper = styled.div` - flex: 1; - min-width: 100px; -`; - -export const StyledHeaderWrapper = styled(SummaryTabHeaderWrapper)` - margin-bottom: 8px; -`; - -export const AssetsSection = () => { - const history = useHistory(); - const entityRegistry = useEntityRegistry(); - const { urn, entityType } = useEntityData(); - - const { data, loading } = useGetSearchResultsForMultipleQuery({ - skip: !urn, - variables: { - input: { - types: [], - query: '', - orFilters: [{ and: [{ field: 'applications', values: [urn] }] }], - count: 1000, - }, - }, - fetchPolicy: 'cache-first', - }); - - const contentsSummary = data?.searchAcrossEntities && getContentsSummary(data.searchAcrossEntities); - const contentsCount = contentsSummary?.total || 0; - const hasContents = contentsCount > 0; - - if (!hasContents) { - return null; - } - - return ( - - - } title={`Assets (${contentsCount})`} /> - - - {loading && } - - - {!loading && - contentsSummary?.types?.map((summary) => { - const { type, count, entityType: summaryEntityType } = summary; - const typeName = ( - type || - entityRegistry.getEntityName(summaryEntityType) || - summaryEntityType - ).toLocaleLowerCase(); - const link = getDomainEntitiesFilterUrl( - urn, - entityType, - entityRegistry, - [summary.entityType], - summary.type ? [summary.type] : undefined, - ); - return ( - - ); - })} - - - ); -}; diff --git a/datahub-web-react/src/app/entity/application/preview/Preview.tsx b/datahub-web-react/src/app/entity/application/preview/Preview.tsx deleted file mode 100644 index 3d0d594988b110..00000000000000 --- a/datahub-web-react/src/app/entity/application/preview/Preview.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import React from 'react'; - -import { GenericEntityProperties } from '@app/entity/shared/types'; -import { EntityMenuActions, IconStyleType, PreviewType } from '@app/entityV2/Entity'; -import { EntityMenuItems } from '@app/entityV2/shared/EntityDropdown/EntityMenuActions'; -import DefaultPreviewCard from '@app/previewV2/DefaultPreviewCard'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { Domain, EntityPath, EntityType, GlobalTags, GlossaryTerms, Owner } from '@types'; - -interface Props { - urn: string; - data: GenericEntityProperties | null; - name: string; - description?: string | null; - owners?: Array | null; - domain?: Domain | null; - globalTags?: GlobalTags | null; - glossaryTerms?: GlossaryTerms | null; - entityCount?: number; - externalUrl?: string | null; - degree?: number; - paths?: EntityPath[]; - headerDropdownItems?: Set; - previewType: PreviewType; - actions?: EntityMenuActions; -} - -export const Preview = ({ - urn, - data, - name, - description, - owners, - globalTags, - domain, - glossaryTerms, - entityCount, - externalUrl, - degree, - paths, - headerDropdownItems, - previewType, - actions, -}: Props): JSX.Element => { - const entityRegistry = useEntityRegistry(); - - return ( - - ); -}; diff --git a/datahub-web-react/src/app/entity/businessAttribute/BusinessAttributeEntity.tsx b/datahub-web-react/src/app/entity/businessAttribute/BusinessAttributeEntity.tsx deleted file mode 100644 index d2cad8f094c425..00000000000000 --- a/datahub-web-react/src/app/entity/businessAttribute/BusinessAttributeEntity.tsx +++ /dev/null @@ -1,160 +0,0 @@ -import { GlobalOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { Preview } from '@app/entity/businessAttribute/preview/Preview'; -import { BusinessAttributeDataTypeSection } from '@app/entity/businessAttribute/profile/BusinessAttributeDataTypeSection'; -import BusinessAttributeRelatedEntity from '@app/entity/businessAttribute/profile/BusinessAttributeRelatedEntity'; -import { EntityMenuItems } from '@app/entity/shared/EntityDropdown/EntityDropdown'; -import { EntityProfile } from '@app/entity/shared/containers/profile/EntityProfile'; -import { SidebarAboutSection } from '@app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import { SidebarOwnerSection } from '@app/entity/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import { SidebarTagsSection } from '@app/entity/shared/containers/profile/sidebar/SidebarTagsSection'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { DocumentationTab } from '@app/entity/shared/tabs/Documentation/DocumentationTab'; -import { PropertiesTab } from '@app/entity/shared/tabs/Properties/PropertiesTab'; -import { PageRoutes } from '@conf/Global'; - -import { useGetBusinessAttributeQuery } from '@graphql/businessAttribute.generated'; -import { BusinessAttribute, EntityType, SearchResult } from '@types'; - -/** - * Definition of datahub Business Attribute Entity - */ -/* eslint-disable @typescript-eslint/no-unused-vars */ -export class BusinessAttributeEntity implements Entity { - type: EntityType = EntityType.BusinessAttribute; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - if (styleType === IconStyleType.SVG) { - // TODO: Update the returned path value to the correct svg icon path - return ( - - ); - } - - return ( - - ); - }; - - displayName = (data: BusinessAttribute) => { - return data?.properties?.name || data?.urn; - }; - - getPathName = () => 'business-attribute'; - - getEntityName = () => 'Business Attribute'; - - getCollectionName = () => 'Business Attributes'; - - getGraphName = () => 'businessAttribute'; - - getCustomCardUrlPath = () => PageRoutes.BUSINESS_ATTRIBUTE; - - isBrowseEnabled = () => false; - - isLineageEnabled = () => false; - - isSearchEnabled = () => true; - - getOverridePropertiesFromEntity = (data: BusinessAttribute) => { - return { - name: data.properties?.name, - }; - }; - - getGenericEntityProperties = (data: BusinessAttribute) => { - return getDataForEntityType({ - data, - entityType: this.type, - getOverrideProperties: this.getOverridePropertiesFromEntity, - }); - }; - - renderPreview = (previewType: PreviewType, data: BusinessAttribute) => { - return ( - - ); - }; - - renderProfile = (urn: string) => { - return ( - - ); - }; - - renderSearch = (result: SearchResult) => { - return this.renderPreview(PreviewType.SEARCH, result.entity as BusinessAttribute); - }; - - supportedCapabilities = () => { - return new Set([ - EntityCapabilityType.OWNERS, - EntityCapabilityType.TAGS, - EntityCapabilityType.GLOSSARY_TERMS, - EntityCapabilityType.BUSINESS_ATTRIBUTES, - ]); - }; -} diff --git a/datahub-web-react/src/app/entity/businessAttribute/profile/BusinessAttributeDataTypeSection.tsx b/datahub-web-react/src/app/entity/businessAttribute/profile/BusinessAttributeDataTypeSection.tsx deleted file mode 100644 index badfb718833b63..00000000000000 --- a/datahub-web-react/src/app/entity/businessAttribute/profile/BusinessAttributeDataTypeSection.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { EditOutlined } from '@ant-design/icons'; -import { Button, Select, message } from 'antd'; -import React, { useEffect, useState } from 'react'; -import styled from 'styled-components'; - -import { SchemaFieldDataType } from '@app/businessAttribute/businessAttributeUtils'; -import { useEntityData, useRefetch } from '@app/entity/shared/EntityContext'; -import { SidebarHeader } from '@app/entity/shared/containers/profile/sidebar/SidebarHeader'; - -import { useUpdateBusinessAttributeMutation } from '@graphql/businessAttribute.generated'; - -interface Props { - readOnly?: boolean; -} - -const DataTypeSelect = styled(Select)` - && { - width: 100%; - margin-top: 1em; - margin-bottom: 1em; - } -`; -// Ensures that any newly added datatype is automatically included in the user dropdown. -const DATA_TYPES = Object.values(SchemaFieldDataType); -export const BusinessAttributeDataTypeSection = ({ readOnly }: Props) => { - const { urn, entityData } = useEntityData(); - const [originalDescription, setOriginalDescription] = useState(null); - const [isEditing, setEditing] = useState(false); - const refetch = useRefetch(); - - useEffect(() => { - if (entityData?.properties?.businessAttributeDataType) { - setOriginalDescription(entityData?.properties?.businessAttributeDataType); - } - }, [entityData]); - - const [updateBusinessAttribute] = useUpdateBusinessAttributeMutation(); - - const handleChange = (value) => { - if (value === originalDescription) { - setEditing(false); - return; - } - - updateBusinessAttribute({ variables: { urn, input: { type: value } } }) - .then(() => { - setEditing(false); - setOriginalDescription(value); - message.success({ content: 'Data Type Updated', duration: 2 }); - refetch(); - }) - .catch((e: unknown) => { - message.destroy(); - if (e instanceof Error) { - message.error({ content: `Failed to update Data Type: \n ${e.message || ''}`, duration: 3 }); - } - }); - }; - - // Toggle editing mode - const handleEditClick = () => { - setEditing(!isEditing); - }; - - return ( -
- - - - ) - } - /> - {originalDescription} - {isEditing && ( - - {DATA_TYPES.map((dataType: SchemaFieldDataType) => ( - - {dataType} - - ))} - - )} -
- ); -}; - -export default BusinessAttributeDataTypeSection; diff --git a/datahub-web-react/src/app/entity/businessAttribute/profile/BusinessAttributeRelatedEntity.tsx b/datahub-web-react/src/app/entity/businessAttribute/profile/BusinessAttributeRelatedEntity.tsx deleted file mode 100644 index 7cce43befb9c8e..00000000000000 --- a/datahub-web-react/src/app/entity/businessAttribute/profile/BusinessAttributeRelatedEntity.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import * as React from 'react'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { EmbeddedListSearchSection } from '@app/entity/shared/components/styled/search/EmbeddedListSearchSection'; -import { UnionType } from '@app/search/utils/constants'; - -export default function BusinessAttributeRelatedEntity() { - const { entityData } = useEntityData(); - - const entityUrn = entityData?.urn; - - const fixedOrFilters = - (entityUrn && [ - { - field: 'businessAttribute', - values: [entityUrn], - }, - ]) || - []; - - entityData?.isAChildren?.relationships?.forEach((businessAttribute) => { - const childUrn = businessAttribute.entity?.urn; - - if (childUrn) { - fixedOrFilters.push({ - field: 'businessAttributes', - values: [childUrn], - }); - } - }); - - return ( - - ); -} diff --git a/datahub-web-react/src/app/entity/chart/ChartEntity.tsx b/datahub-web-react/src/app/entity/chart/ChartEntity.tsx deleted file mode 100644 index 1e6a3427ee5291..00000000000000 --- a/datahub-web-react/src/app/entity/chart/ChartEntity.tsx +++ /dev/null @@ -1,297 +0,0 @@ -import { LineChartOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { ChartQueryTab } from '@app/entity/chart/ChartQueryTab'; -import { ChartPreview } from '@app/entity/chart/preview/ChartPreview'; -import { ChartStatsSummarySubHeader } from '@app/entity/chart/profile/stats/ChartStatsSummarySubHeader'; -import { EntityMenuItems } from '@app/entity/shared/EntityDropdown/EntityDropdown'; -import { EntityProfile } from '@app/entity/shared/containers/profile/EntityProfile'; -import { SidebarAboutSection } from '@app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import DataProductSection from '@app/entity/shared/containers/profile/sidebar/DataProduct/DataProductSection'; -import { SidebarDomainSection } from '@app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection'; -import { SidebarOwnerSection } from '@app/entity/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import { SidebarTagsSection } from '@app/entity/shared/containers/profile/sidebar/SidebarTagsSection'; -import SidebarStructuredPropsSection from '@app/entity/shared/containers/profile/sidebar/StructuredProperties/SidebarStructuredPropsSection'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import EmbeddedProfile from '@app/entity/shared/embed/EmbeddedProfile'; -import { DocumentationTab } from '@app/entity/shared/tabs/Documentation/DocumentationTab'; -import { EmbedTab } from '@app/entity/shared/tabs/Embed/EmbedTab'; -import { ChartDashboardsTab } from '@app/entity/shared/tabs/Entity/ChartDashboardsTab'; -import { InputFieldsTab } from '@app/entity/shared/tabs/Entity/InputFieldsTab'; -import { IncidentTab } from '@app/entity/shared/tabs/Incident/IncidentTab'; -import { LineageTab } from '@app/entity/shared/tabs/Lineage/LineageTab'; -import { PropertiesTab } from '@app/entity/shared/tabs/Properties/PropertiesTab'; -import { GenericEntityProperties } from '@app/entity/shared/types'; -import { getDataProduct } from '@app/entity/shared/utils'; -import { LOOKER_URN } from '@app/ingest/source/builder/constants'; -import { MatchedFieldList } from '@app/search/matches/MatchedFieldList'; -import { matchedInputFieldRenderer } from '@app/search/matches/matchedInputFieldRenderer'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; - -import { GetChartQuery, useGetChartQuery, useUpdateChartMutation } from '@graphql/chart.generated'; -import { Chart, EntityType, LineageDirection, SearchResult } from '@types'; - -/** - * Definition of the DataHub Chart entity. - */ -export class ChartEntity implements Entity { - type: EntityType = EntityType.Chart; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - if (styleType === IconStyleType.SVG) { - return ( - - ); - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => true; - - isLineageEnabled = () => true; - - getAutoCompleteFieldName = () => 'title'; - - getGraphName = () => 'chart'; - - getPathName = () => 'chart'; - - getEntityName = () => 'Chart'; - - getCollectionName = () => 'Charts'; - - useEntityQuery = useGetChartQuery; - - getSidebarSections = () => [ - { - component: SidebarAboutSection, - }, - { - component: SidebarOwnerSection, - }, - { - component: SidebarTagsSection, - properties: { - hasTags: true, - hasTerms: true, - }, - }, - { - component: SidebarDomainSection, - }, - { - component: DataProductSection, - }, - { - component: SidebarStructuredPropsSection, - }, - ]; - - renderProfile = (urn: string) => ( - (chart?.chart?.query?.rawQuery && true) || false, - enabled: (_, chart: GetChartQuery) => (chart?.chart?.query?.rawQuery && true) || false, - }, - }, - { - name: 'Documentation', - component: DocumentationTab, - }, - { - name: 'Fields', - component: InputFieldsTab, - display: { - visible: (_, chart: GetChartQuery) => (chart?.chart?.inputFields?.fields?.length || 0) > 0, - enabled: (_, chart: GetChartQuery) => (chart?.chart?.inputFields?.fields?.length || 0) > 0, - }, - }, - { - name: 'Preview', - component: EmbedTab, - display: { - visible: (_, chart: GetChartQuery) => - !!chart?.chart?.embed?.renderUrl && chart?.chart?.platform?.urn === LOOKER_URN, - enabled: (_, chart: GetChartQuery) => - !!chart?.chart?.embed?.renderUrl && chart?.chart?.platform?.urn === LOOKER_URN, - }, - }, - { - name: 'Lineage', - component: LineageTab, - properties: { - defaultDirection: LineageDirection.Upstream, - }, - }, - { - name: 'Dashboards', - component: ChartDashboardsTab, - display: { - visible: (_, _1) => true, - enabled: (_, chart: GetChartQuery) => (chart?.chart?.dashboards?.total || 0) > 0, - }, - }, - { - name: 'Properties', - component: PropertiesTab, - }, - { - name: 'Incidents', - component: IncidentTab, - getDynamicName: (_, chart) => { - const activeIncidentCount = chart?.chart?.activeIncidents?.total; - return `Incidents${(activeIncidentCount && ` (${activeIncidentCount})`) || ''}`; - }, - }, - ]} - sidebarSections={this.getSidebarSections()} - /> - ); - - getOverridePropertiesFromEntity = (chart?: Chart | null): GenericEntityProperties => { - // TODO: Get rid of this once we have correctly formed platform coming back. - const name = chart?.properties?.name; - const subTypes = chart?.subTypes; - const externalUrl = chart?.properties?.externalUrl; - return { - name, - externalUrl, - entityTypeOverride: subTypes ? capitalizeFirstLetterOnly(subTypes.typeNames?.[0]) : '', - }; - }; - - renderPreview = (_: PreviewType, data: Chart) => { - const genericProperties = this.getGenericEntityProperties(data); - return ( - - ); - }; - - renderSearch = (result: SearchResult) => { - const data = result.entity as Chart; - const genericProperties = this.getGenericEntityProperties(data); - return ( - matchedInputFieldRenderer(matchedField, data)} - /> - } - degree={(result as any).degree} - paths={(result as any).paths} - health={data.health} - /> - ); - }; - - getLineageVizConfig = (entity: Chart) => { - return { - urn: entity.urn, - name: entity.properties?.name || entity.urn, - type: EntityType.Chart, - icon: entity?.platform?.properties?.logoUrl || undefined, - platform: entity?.platform, - subtype: entity?.subTypes?.typeNames?.[0] || undefined, - health: entity?.health || undefined, - }; - }; - - displayName = (data: Chart) => { - return data.properties?.name || data.urn; - }; - - getGenericEntityProperties = (data: Chart) => { - return getDataForEntityType({ - data, - entityType: this.type, - getOverrideProperties: this.getOverridePropertiesFromEntity, - }); - }; - - supportedCapabilities = () => { - return new Set([ - EntityCapabilityType.OWNERS, - EntityCapabilityType.GLOSSARY_TERMS, - EntityCapabilityType.TAGS, - EntityCapabilityType.DOMAINS, - EntityCapabilityType.DEPRECATION, - EntityCapabilityType.SOFT_DELETE, - EntityCapabilityType.DATA_PRODUCTS, - ]); - }; - - renderEmbeddedProfile = (urn: string) => ( - - ); -} diff --git a/datahub-web-react/src/app/entity/chart/ChartQueryTab.tsx b/datahub-web-react/src/app/entity/chart/ChartQueryTab.tsx deleted file mode 100644 index 02bd34aa1d2ffc..00000000000000 --- a/datahub-web-react/src/app/entity/chart/ChartQueryTab.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { Typography } from 'antd'; -import React from 'react'; -import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; -import styled from 'styled-components'; - -import { useBaseEntity } from '@app/entity/shared/EntityContext'; -import { InfoItem } from '@app/entity/shared/components/styled/InfoItem'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; - -import { GetChartQuery } from '@graphql/chart.generated'; - -const InfoSection = styled.div` - border-bottom: 1px solid ${ANTD_GRAY[4.5]}; - padding: 16px 20px; -`; - -const InfoItemContainer = styled.div<{ justifyContent }>` - display: flex; - position: relative; - justify-content: ${(props) => props.justifyContent}; - padding: 12px 2px; -`; - -const InfoItemContent = styled.div` - padding-top: 8px; -`; - -const QueryText = styled(Typography.Paragraph)` - margin-top: 20px; - background-color: ${ANTD_GRAY[2]}; -`; - -// NOTE: Yes, using `!important` is a shame. However, the SyntaxHighlighter is applying styles directly -// to the component, so there's no way around this -const NestedSyntax = styled(SyntaxHighlighter)` - background-color: transparent !important; - border: none !important; -`; - -export function ChartQueryTab() { - const baseEntity = useBaseEntity(); - const query = baseEntity?.chart?.query?.rawQuery || 'UNKNOWN'; - const type = baseEntity?.chart?.query?.type || 'UNKNOWN'; - - return ( - <> - - Details - - - {type.toUpperCase()} - - - - - Query - - {query} - - - - ); -} diff --git a/datahub-web-react/src/app/entity/chart/preview/ChartPreview.tsx b/datahub-web-react/src/app/entity/chart/preview/ChartPreview.tsx deleted file mode 100644 index a8a13a6b7ef48c..00000000000000 --- a/datahub-web-react/src/app/entity/chart/preview/ChartPreview.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import React from 'react'; - -import { IconStyleType, PreviewType } from '@app/entity/Entity'; -import { ChartStatsSummary as ChartStatsSummaryView } from '@app/entity/chart/shared/ChartStatsSummary'; -import DefaultPreviewCard from '@app/preview/DefaultPreviewCard'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { - AccessLevel, - ChartStatsSummary, - Container, - DataProduct, - Deprecation, - Domain, - EntityPath, - EntityType, - GlobalTags, - GlossaryTerms, - Health, - Owner, - ParentContainersResult, - SearchInsight, -} from '@types'; - -export const ChartPreview = ({ - urn, - name, - description, - platform, - platformInstanceId, - access, - owners, - tags, - glossaryTerms, - domain, - dataProduct, - container, - insights, - logoUrl, - deprecation, - statsSummary, - lastUpdatedMs, - createdMs, - externalUrl, - parentContainers, - snippet, - degree, - paths, - subType, - health, - previewType, -}: { - urn: string; - platform?: string; - platformInstanceId?: string; - name?: string; - description?: string | null; - access?: AccessLevel | null; - owners?: Array | null; - tags?: GlobalTags; - glossaryTerms?: GlossaryTerms | null; - domain?: Domain | null; - dataProduct?: DataProduct | null; - container?: Container | null; - insights?: Array | null; - logoUrl?: string | null; - deprecation?: Deprecation | null; - statsSummary?: ChartStatsSummary | null; - lastUpdatedMs?: number | null; - createdMs?: number | null; - externalUrl?: string | null; - parentContainers?: ParentContainersResult | null; - snippet?: React.ReactNode | null; - degree?: number; - paths?: EntityPath[]; - subType?: string | null; - health?: Health[] | null; - previewType?: PreviewType; -}): JSX.Element => { - const entityRegistry = useEntityRegistry(); - - return ( - - } - degree={degree} - paths={paths} - health={health || undefined} - previewType={previewType} - /> - ); -}; diff --git a/datahub-web-react/src/app/entity/chart/profile/stats/ChartStatsSummarySubHeader.tsx b/datahub-web-react/src/app/entity/chart/profile/stats/ChartStatsSummarySubHeader.tsx deleted file mode 100644 index 336fb1f1d0ec4b..00000000000000 --- a/datahub-web-react/src/app/entity/chart/profile/stats/ChartStatsSummarySubHeader.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; - -import { ChartStatsSummary } from '@app/entity/chart/shared/ChartStatsSummary'; -import { useBaseEntity } from '@app/entity/shared/EntityContext'; - -import { GetChartQuery } from '@graphql/chart.generated'; -import { ChartStatsSummary as ChartStatsSummaryObj } from '@types'; - -export const ChartStatsSummarySubHeader = () => { - const result = useBaseEntity(); - const chart = result?.chart; - const maybeStatsSummary = chart?.statsSummary as ChartStatsSummaryObj; - const viewCount = maybeStatsSummary?.viewCount; - const uniqueUserCountLast30Days = maybeStatsSummary?.uniqueUserCountLast30Days; - const lastUpdatedMs = chart?.properties?.lastModified?.time; - const createdMs = chart?.properties?.created?.time; - - return ( - - ); -}; diff --git a/datahub-web-react/src/app/entity/chart/shared/ChartStatsSummary.tsx b/datahub-web-react/src/app/entity/chart/shared/ChartStatsSummary.tsx deleted file mode 100644 index d5cf88b4a848d9..00000000000000 --- a/datahub-web-react/src/app/entity/chart/shared/ChartStatsSummary.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { ClockCircleOutlined, EyeOutlined, QuestionCircleOutlined, TeamOutlined } from '@ant-design/icons'; -import { Popover, Tooltip } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import ExpandingStat from '@app/entity/dataset/shared/ExpandingStat'; -import { StatsSummary } from '@app/entity/shared/components/styled/StatsSummary'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { formatNumberWithoutAbbreviation } from '@app/shared/formatNumber'; -import { toLocalDateTimeString, toRelativeTimeString } from '@app/shared/time/timeUtils'; -import { countFormatter, needsFormatting } from '@utils/formatter'; - -const StatText = styled.span` - color: ${ANTD_GRAY[8]}; -`; - -const HelpIcon = styled(QuestionCircleOutlined)` - color: ${ANTD_GRAY[7]}; - padding-left: 4px; -`; - -type Props = { - chartCount?: number | null; - viewCount?: number | null; - uniqueUserCountLast30Days?: number | null; - lastUpdatedMs?: number | null; - createdMs?: number | null; -}; - -export const ChartStatsSummary = ({ - chartCount, - viewCount, - uniqueUserCountLast30Days, - lastUpdatedMs, - createdMs, -}: Props) => { - const statsViews = [ - (!!chartCount && ( - ( - - {isExpanded ? formatNumberWithoutAbbreviation(chartCount) : countFormatter(chartCount)}{' '} - charts - - )} - /> - )) || - undefined, - (!!viewCount && ( - - - {formatNumberWithoutAbbreviation(viewCount)} views - - )) || - undefined, - (!!uniqueUserCountLast30Days && ( - - - {formatNumberWithoutAbbreviation(uniqueUserCountLast30Days)} unique users - - )) || - undefined, - (!!lastUpdatedMs && ( - - {createdMs &&
Created on {toLocalDateTimeString(createdMs)}.
} -
- Changed on {toLocalDateTimeString(lastUpdatedMs)}.{' '} - - - -
- - } - > - - - Changed {toRelativeTimeString(lastUpdatedMs)} - -
- )) || - undefined, - ].filter((stat) => stat !== undefined); - - return <>{statsViews.length > 0 && }; -}; diff --git a/datahub-web-react/src/app/entity/container/ContainerEntitiesTab.tsx b/datahub-web-react/src/app/entity/container/ContainerEntitiesTab.tsx deleted file mode 100644 index ac3864fc0caf3a..00000000000000 --- a/datahub-web-react/src/app/entity/container/ContainerEntitiesTab.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { EmbeddedListSearchSection } from '@app/entity/shared/components/styled/search/EmbeddedListSearchSection'; -import { UnionType } from '@app/search/utils/constants'; - -export const ContainerEntitiesTab = () => { - const { urn } = useEntityData(); - - const fixedFilter = { - field: 'container', - values: [urn], - }; - - return ( - - ); -}; diff --git a/datahub-web-react/src/app/entity/container/ContainerEntity.tsx b/datahub-web-react/src/app/entity/container/ContainerEntity.tsx deleted file mode 100644 index d851d27c6c2a86..00000000000000 --- a/datahub-web-react/src/app/entity/container/ContainerEntity.tsx +++ /dev/null @@ -1,235 +0,0 @@ -import { FolderOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { ContainerEntitiesTab } from '@app/entity/container/ContainerEntitiesTab'; -import { Preview } from '@app/entity/container/preview/Preview'; -import { EntityProfile } from '@app/entity/shared/containers/profile/EntityProfile'; -import { SidebarAboutSection } from '@app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import DataProductSection from '@app/entity/shared/containers/profile/sidebar/DataProduct/DataProductSection'; -import { SidebarDomainSection } from '@app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection'; -import { SidebarOwnerSection } from '@app/entity/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import { SidebarTagsSection } from '@app/entity/shared/containers/profile/sidebar/SidebarTagsSection'; -import SidebarStructuredPropsSection from '@app/entity/shared/containers/profile/sidebar/StructuredProperties/SidebarStructuredPropsSection'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import EmbeddedProfile from '@app/entity/shared/embed/EmbeddedProfile'; -import AccessManagement from '@app/entity/shared/tabs/Dataset/AccessManagement/AccessManagement'; -import { DocumentationTab } from '@app/entity/shared/tabs/Documentation/DocumentationTab'; -import { PropertiesTab } from '@app/entity/shared/tabs/Properties/PropertiesTab'; -import { getDataProduct } from '@app/entity/shared/utils'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; -import { useAppConfig } from '@app/useAppConfig'; - -import { GetContainerQuery, useGetContainerQuery } from '@graphql/container.generated'; -import { Container, EntityType, SearchResult } from '@types'; - -/** - * Definition of the DataHub Container entity. - */ -export class ContainerEntity implements Entity { - type: EntityType = EntityType.Container; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - if (styleType === IconStyleType.SVG) { - return ( - - ); - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => false; - - isLineageEnabled = () => false; - - getAutoCompleteFieldName = () => 'name'; - - getGraphName = () => 'container'; - - getPathName = () => 'container'; - - getEntityName = () => 'Container'; - - getCollectionName = () => 'Containers'; - - useEntityQuery = useGetContainerQuery; - - appconfig = useAppConfig; - - renderProfile = (urn: string) => ( - { - return ( - this.appconfig().config.featureFlags.showAccessManagement && - !!container?.container?.access - ); - }, - enabled: (_, container: GetContainerQuery) => { - const accessAspect = container?.container?.access; - const rolesList = accessAspect?.roles; - return !!accessAspect && !!rolesList && rolesList.length > 0; - }, - }, - }, - { - name: 'Properties', - component: PropertiesTab, - }, - ]} - sidebarSections={this.getSidebarSections()} - /> - ); - - getSidebarSections = () => [ - { - component: SidebarAboutSection, - }, - { - component: SidebarOwnerSection, - }, - { - component: SidebarTagsSection, - properties: { - hasTags: true, - hasTerms: true, - }, - }, - { - component: SidebarDomainSection, - }, - { - component: DataProductSection, - }, - { - component: SidebarStructuredPropsSection, - }, - // TODO: Add back once entity-level recommendations are complete. - // { - // component: SidebarRecommendationsSection, - // }, - ]; - - renderPreview = (_: PreviewType, data: Container) => { - const genericProperties = this.getGenericEntityProperties(data); - return ( - - ); - }; - - renderSearch = (result: SearchResult) => { - const data = result.entity as Container; - const genericProperties = this.getGenericEntityProperties(data); - return ( - - ); - }; - - displayName = (data: Container) => { - return data?.properties?.name || data?.properties?.qualifiedName || data?.urn; - }; - - getOverridePropertiesFromEntity = (data: Container) => { - return { - name: this.displayName(data), - externalUrl: data.properties?.externalUrl, - entityCount: data.entities?.total, - }; - }; - - getGenericEntityProperties = (data: Container) => { - return getDataForEntityType({ - data, - entityType: this.type, - getOverrideProperties: this.getOverridePropertiesFromEntity, - }); - }; - - supportedCapabilities = () => { - return new Set([ - EntityCapabilityType.OWNERS, - EntityCapabilityType.GLOSSARY_TERMS, - EntityCapabilityType.TAGS, - EntityCapabilityType.DOMAINS, - EntityCapabilityType.SOFT_DELETE, - EntityCapabilityType.DATA_PRODUCTS, - ]); - }; - - renderEmbeddedProfile = (urn: string) => ( - - ); -} diff --git a/datahub-web-react/src/app/entity/container/preview/Preview.tsx b/datahub-web-react/src/app/entity/container/preview/Preview.tsx deleted file mode 100644 index 746171354f5d59..00000000000000 --- a/datahub-web-react/src/app/entity/container/preview/Preview.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { IconStyleType } from '@app/entity/Entity'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import DefaultPreviewCard from '@app/preview/DefaultPreviewCard'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { - Container, - DataProduct, - Deprecation, - Domain, - EntityPath, - EntityType, - GlobalTags, - GlossaryTerms, - Owner, - ParentContainersResult, - SearchInsight, - SubTypes, -} from '@types'; - -const StatText = styled(Typography.Text)` - color: ${ANTD_GRAY[8]}; -`; - -export const Preview = ({ - urn, - name, - platformName, - platformLogo, - platformInstanceId, - description, - owners, - tags, - glossaryTerms, - insights, - subTypes, - logoComponent, - container, - entityCount, - domain, - dataProduct, - parentContainers, - externalUrl, - deprecation, - degree, - paths, -}: { - urn: string; - name: string; - platformName?: string; - platformLogo?: string | null; - platformInstanceId?: string; - description?: string | null; - owners?: Array | null; - tags?: GlobalTags | null; - glossaryTerms?: GlossaryTerms | null; - insights?: Array | null; - subTypes?: SubTypes | null; - logoComponent?: JSX.Element; - container?: Container | null; - entityCount?: number; - domain?: Domain | null; - dataProduct?: DataProduct | null; - deprecation?: Deprecation | null; - parentContainers?: ParentContainersResult | null; - externalUrl?: string | null; - degree?: number; - paths?: EntityPath[]; -}): JSX.Element => { - const entityRegistry = useEntityRegistry(); - const typeName = capitalizeFirstLetterOnly(subTypes?.typeNames?.[0]) || 'Container'; - return ( - - {entityCount} {entityCount === 1 ? 'entity' : 'entities'} - , - ]) || - undefined - } - degree={degree} - paths={paths} - /> - ); -}; diff --git a/datahub-web-react/src/app/entity/dashboard/DashboardEntity.tsx b/datahub-web-react/src/app/entity/dashboard/DashboardEntity.tsx deleted file mode 100644 index 64409b5bfb854e..00000000000000 --- a/datahub-web-react/src/app/entity/dashboard/DashboardEntity.tsx +++ /dev/null @@ -1,305 +0,0 @@ -import { DashboardFilled, DashboardOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { DashboardPreview } from '@app/entity/dashboard/preview/DashboardPreview'; -import { DashboardStatsSummarySubHeader } from '@app/entity/dashboard/profile/DashboardStatsSummarySubHeader'; -import { EntityMenuItems } from '@app/entity/shared/EntityDropdown/EntityDropdown'; -import { EntityProfile } from '@app/entity/shared/containers/profile/EntityProfile'; -import { SidebarAboutSection } from '@app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import DataProductSection from '@app/entity/shared/containers/profile/sidebar/DataProduct/DataProductSection'; -import { SidebarDomainSection } from '@app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection'; -import { SidebarOwnerSection } from '@app/entity/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import { SidebarTagsSection } from '@app/entity/shared/containers/profile/sidebar/SidebarTagsSection'; -import SidebarStructuredPropsSection from '@app/entity/shared/containers/profile/sidebar/StructuredProperties/SidebarStructuredPropsSection'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import EmbeddedProfile from '@app/entity/shared/embed/EmbeddedProfile'; -import { DocumentationTab } from '@app/entity/shared/tabs/Documentation/DocumentationTab'; -import { EmbedTab } from '@app/entity/shared/tabs/Embed/EmbedTab'; -import { DashboardChartsTab } from '@app/entity/shared/tabs/Entity/DashboardChartsTab'; -import { DashboardDatasetsTab } from '@app/entity/shared/tabs/Entity/DashboardDatasetsTab'; -import { IncidentTab } from '@app/entity/shared/tabs/Incident/IncidentTab'; -import { LineageTab } from '@app/entity/shared/tabs/Lineage/LineageTab'; -import { PropertiesTab } from '@app/entity/shared/tabs/Properties/PropertiesTab'; -import { GenericEntityProperties } from '@app/entity/shared/types'; -import { getDataProduct } from '@app/entity/shared/utils'; -import { LOOKER_URN } from '@app/ingest/source/builder/constants'; -import { MatchedFieldList } from '@app/search/matches/MatchedFieldList'; -import { matchedInputFieldRenderer } from '@app/search/matches/matchedInputFieldRenderer'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; - -import { GetDashboardQuery, useGetDashboardQuery, useUpdateDashboardMutation } from '@graphql/dashboard.generated'; -import { Dashboard, EntityType, LineageDirection, OwnershipType, SearchResult } from '@types'; - -/** - * Definition of the DataHub Dashboard entity. - */ -export class DashboardEntity implements Entity { - type: EntityType = EntityType.Dashboard; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - if (styleType === IconStyleType.SVG) { - return ( - - ); - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => true; - - isLineageEnabled = () => true; - - getAutoCompleteFieldName = () => 'title'; - - getPathName = () => 'dashboard'; - - getEntityName = () => 'Dashboard'; - - getCollectionName = () => 'Dashboards'; - - useEntityQuery = useGetDashboardQuery; - - getSidebarSections = () => [ - { - component: SidebarAboutSection, - }, - { - component: SidebarOwnerSection, - properties: { - defaultOwnerType: OwnershipType.TechnicalOwner, - }, - }, - { - component: SidebarTagsSection, - properties: { - hasTags: true, - hasTerms: true, - }, - }, - { - component: SidebarDomainSection, - }, - { - component: DataProductSection, - }, - { - component: SidebarStructuredPropsSection, - }, - ]; - - renderProfile = (urn: string) => ( - - (dashboard?.dashboard?.charts?.total || 0) > 0 || - (dashboard?.dashboard?.datasets?.total || 0) === 0, - enabled: (_, dashboard: GetDashboardQuery) => (dashboard?.dashboard?.charts?.total || 0) > 0, - }, - }, - { - name: 'Datasets', - component: DashboardDatasetsTab, - display: { - visible: (_, dashboard: GetDashboardQuery) => (dashboard?.dashboard?.datasets?.total || 0) > 0, - enabled: (_, dashboard: GetDashboardQuery) => (dashboard?.dashboard?.datasets?.total || 0) > 0, - }, - }, - { - name: 'Documentation', - component: DocumentationTab, - }, - { - name: 'Preview', - component: EmbedTab, - display: { - visible: (_, dashboard: GetDashboardQuery) => - !!dashboard?.dashboard?.embed?.renderUrl && - dashboard?.dashboard?.platform?.urn === LOOKER_URN, - enabled: (_, dashboard: GetDashboardQuery) => - !!dashboard?.dashboard?.embed?.renderUrl && - dashboard?.dashboard?.platform?.urn === LOOKER_URN, - }, - }, - { - name: 'Lineage', - component: LineageTab, - properties: { - defaultDirection: LineageDirection.Upstream, - }, - }, - { - name: 'Properties', - component: PropertiesTab, - }, - { - name: 'Incidents', - component: IncidentTab, - getDynamicName: (_, dashboard) => { - const activeIncidentCount = dashboard?.dashboard?.activeIncidents?.total; - return `Incidents${(activeIncidentCount && ` (${activeIncidentCount})`) || ''}`; - }, - }, - ]} - sidebarSections={this.getSidebarSections()} - /> - ); - - getOverridePropertiesFromEntity = (dashboard?: Dashboard | null): GenericEntityProperties => { - // TODO: Get rid of this once we have correctly formed platform coming back. - const name = dashboard?.properties?.name; - const externalUrl = dashboard?.properties?.externalUrl; - const subTypes = dashboard?.subTypes; - return { - name, - externalUrl, - entityTypeOverride: subTypes ? capitalizeFirstLetterOnly(subTypes.typeNames?.[0]) : '', - }; - }; - - renderPreview = (_: PreviewType, data: Dashboard) => { - const genericProperties = this.getGenericEntityProperties(data); - return ( - - ); - }; - - renderSearch = (result: SearchResult) => { - const data = result.entity as Dashboard; - const genericProperties = this.getGenericEntityProperties(data); - - return ( - matchedInputFieldRenderer(matchedField, data)} - matchSuffix="on a contained chart" - /> - } - subtype={data.subTypes?.typeNames?.[0]} - degree={(result as any).degree} - paths={(result as any).paths} - health={data.health} - /> - ); - }; - - getLineageVizConfig = (entity: Dashboard) => { - return { - urn: entity.urn, - name: entity.properties?.name || entity.urn, - type: EntityType.Dashboard, - subtype: entity?.subTypes?.typeNames?.[0] || undefined, - icon: entity?.platform?.properties?.logoUrl || undefined, - platform: entity?.platform, - health: entity?.health || undefined, - }; - }; - - displayName = (data: Dashboard) => { - return data.properties?.name || data.urn; - }; - - getGenericEntityProperties = (data: Dashboard) => { - return getDataForEntityType({ - data, - entityType: this.type, - getOverrideProperties: this.getOverridePropertiesFromEntity, - }); - }; - - supportedCapabilities = () => { - return new Set([ - EntityCapabilityType.OWNERS, - EntityCapabilityType.GLOSSARY_TERMS, - EntityCapabilityType.TAGS, - EntityCapabilityType.DOMAINS, - EntityCapabilityType.DEPRECATION, - EntityCapabilityType.SOFT_DELETE, - EntityCapabilityType.DATA_PRODUCTS, - ]); - }; - - getGraphName = () => this.getPathName(); - - renderEmbeddedProfile = (urn: string) => ( - - ); -} diff --git a/datahub-web-react/src/app/entity/dashboard/preview/DashboardPreview.tsx b/datahub-web-react/src/app/entity/dashboard/preview/DashboardPreview.tsx deleted file mode 100644 index d4dbe48d6e5ba9..00000000000000 --- a/datahub-web-react/src/app/entity/dashboard/preview/DashboardPreview.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import React from 'react'; - -import { IconStyleType, PreviewType } from '@app/entity/Entity'; -import { DashboardStatsSummary as DashboardStatsSummaryView } from '@app/entity/dashboard/shared/DashboardStatsSummary'; -import DefaultPreviewCard from '@app/preview/DefaultPreviewCard'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { - AccessLevel, - Container, - DashboardStatsSummary, - DataProduct, - Deprecation, - Domain, - EntityPath, - EntityType, - GlobalTags, - GlossaryTerms, - Health, - Owner, - ParentContainersResult, - SearchInsight, -} from '@types'; - -export const DashboardPreview = ({ - urn, - platform, - platformInstanceId, - name, - subtype, - description, - access, - owners, - tags, - glossaryTerms, - domain, - dataProduct, - container, - insights, - logoUrl, - chartCount, - statsSummary, - lastUpdatedMs, - createdMs, - externalUrl, - parentContainers, - deprecation, - snippet, - degree, - paths, - health, - previewType, -}: { - urn: string; - platform?: string; - platformInstanceId?: string; - name?: string; - subtype?: string | null; - description?: string | null; - access?: AccessLevel | null; - owners?: Array | null; - tags?: GlobalTags; - glossaryTerms?: GlossaryTerms | null; - domain?: Domain | null; - dataProduct?: DataProduct | null; - container?: Container | null; - deprecation?: Deprecation | null; - insights?: Array | null; - logoUrl?: string | null; - chartCount?: number | null; - statsSummary?: DashboardStatsSummary | null; - lastUpdatedMs?: number | null; - createdMs?: number | null; - externalUrl?: string | null; - parentContainers?: ParentContainersResult | null; - snippet?: React.ReactNode | null; - degree?: number; - paths?: EntityPath[]; - health?: Health[] | null; - previewType?: PreviewType; -}): JSX.Element => { - const entityRegistry = useEntityRegistry(); - - return ( - - } - degree={degree} - paths={paths} - health={health || undefined} - previewType={previewType} - /> - ); -}; diff --git a/datahub-web-react/src/app/entity/dashboard/profile/DashboardStatsSummarySubHeader.tsx b/datahub-web-react/src/app/entity/dashboard/profile/DashboardStatsSummarySubHeader.tsx deleted file mode 100644 index 9bd5771c0b567b..00000000000000 --- a/datahub-web-react/src/app/entity/dashboard/profile/DashboardStatsSummarySubHeader.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; - -import { DashboardStatsSummary } from '@app/entity/dashboard/shared/DashboardStatsSummary'; -import { useBaseEntity } from '@app/entity/shared/EntityContext'; - -import { GetDashboardQuery } from '@graphql/dashboard.generated'; -import { DashboardStatsSummary as DashboardStatsSummaryObj } from '@types'; - -export const DashboardStatsSummarySubHeader = () => { - const result = useBaseEntity(); - const dashboard = result?.dashboard; - const maybeStatsSummary = dashboard?.statsSummary as DashboardStatsSummaryObj; - const chartCount = dashboard?.charts?.total; - const viewCount = maybeStatsSummary?.viewCount; - const uniqueUserCountLast30Days = maybeStatsSummary?.uniqueUserCountLast30Days; - const lastUpdatedMs = dashboard?.properties?.lastModified?.time; - const createdMs = dashboard?.properties?.created?.time; - - return ( - - ); -}; diff --git a/datahub-web-react/src/app/entity/dashboard/shared/DashboardStatsSummary.tsx b/datahub-web-react/src/app/entity/dashboard/shared/DashboardStatsSummary.tsx deleted file mode 100644 index 48f6488cb1c418..00000000000000 --- a/datahub-web-react/src/app/entity/dashboard/shared/DashboardStatsSummary.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { ClockCircleOutlined, EyeOutlined, QuestionCircleOutlined, TeamOutlined } from '@ant-design/icons'; -import { Popover, Tooltip } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import ExpandingStat from '@app/entity/dataset/shared/ExpandingStat'; -import { StatsSummary } from '@app/entity/shared/components/styled/StatsSummary'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { formatNumberWithoutAbbreviation } from '@app/shared/formatNumber'; -import { toLocalDateTimeString, toRelativeTimeString } from '@app/shared/time/timeUtils'; -import { countFormatter, needsFormatting } from '@utils/formatter'; - -const StatText = styled.span` - color: ${ANTD_GRAY[8]}; - @media (min-width: 1024px) { - white-space: nowrap; -`; - -const HelpIcon = styled(QuestionCircleOutlined)` - color: ${ANTD_GRAY[7]}; - padding-left: 4px; -`; - -type Props = { - chartCount?: number | null; - viewCount?: number | null; - uniqueUserCountLast30Days?: number | null; - lastUpdatedMs?: number | null; - createdMs?: number | null; -}; - -export const DashboardStatsSummary = ({ - chartCount, - viewCount, - uniqueUserCountLast30Days, - lastUpdatedMs, - createdMs, -}: Props) => { - const statsViews = [ - (!!chartCount && ( - ( - - {isExpanded ? formatNumberWithoutAbbreviation(chartCount) : countFormatter(chartCount)}{' '} - charts - - )} - /> - )) || - undefined, - (!!viewCount && ( - - - {formatNumberWithoutAbbreviation(viewCount)} views - - )) || - undefined, - (!!uniqueUserCountLast30Days && ( - - - {formatNumberWithoutAbbreviation(uniqueUserCountLast30Days)} unique users - - )) || - undefined, - (!!lastUpdatedMs && ( - - {createdMs &&
Created on {toLocalDateTimeString(createdMs)}.
} -
- Changed on {toLocalDateTimeString(lastUpdatedMs)}.{' '} - - - -
- - } - > - - - Changed {toRelativeTimeString(lastUpdatedMs)} - -
- )) || - undefined, - ].filter((stat) => stat !== undefined); - - return <>{statsViews.length > 0 && }; -}; diff --git a/datahub-web-react/src/app/entity/dataContract/DataContractEntity.tsx b/datahub-web-react/src/app/entity/dataContract/DataContractEntity.tsx deleted file mode 100644 index afe7efe7e3251f..00000000000000 --- a/datahub-web-react/src/app/entity/dataContract/DataContractEntity.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { FileOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, IconStyleType } from '@app/entity/Entity'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { TYPE_ICON_CLASS_NAME } from '@src/app/shared/constants'; -import { DataContract, EntityType } from '@src/types.generated'; - -/** - * Definition of the DataHub DataContract entity. - */ -export class DataContractEntity implements Entity { - type: EntityType = EntityType.DataContract; - - icon = (fontSize?: number, styleType?: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => false; - - isLineageEnabled = () => false; - - getAutoCompleteFieldName = () => 'name'; - - getGraphName = () => 'dataContract'; - - getPathName = () => 'dataContracts'; - - getEntityName = () => 'Data Contract'; - - getCollectionName = () => 'Data Contracts'; - - renderProfile = () => Not Implemented; - - getSidebarSections = () => []; - - getSidebarTabs = () => []; - - getOverridePropertiesFromEntity = () => {}; - - renderPreview = () => { - return Not Implemented; - }; - - renderSearch = () => { - return Not Implemented; - }; - - displayName = () => { - return 'Data Contract'; - }; - - getGenericEntityProperties = (data: DataContract) => { - return getDataForEntityType({ - data, - entityType: this.type, - getOverrideProperties: (newData) => newData, - }); - }; - - supportedCapabilities = () => { - return new Set([]); - }; -} diff --git a/datahub-web-react/src/app/entity/dataFlow/DataFlowEntity.tsx b/datahub-web-react/src/app/entity/dataFlow/DataFlowEntity.tsx deleted file mode 100644 index 5ab90424f7a9b8..00000000000000 --- a/datahub-web-react/src/app/entity/dataFlow/DataFlowEntity.tsx +++ /dev/null @@ -1,217 +0,0 @@ -import { ShareAltOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { Preview } from '@app/entity/dataFlow/preview/Preview'; -import { EntityMenuItems } from '@app/entity/shared/EntityDropdown/EntityDropdown'; -import { EntityProfile } from '@app/entity/shared/containers/profile/EntityProfile'; -import { SidebarAboutSection } from '@app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import DataProductSection from '@app/entity/shared/containers/profile/sidebar/DataProduct/DataProductSection'; -import { SidebarDomainSection } from '@app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection'; -import { SidebarOwnerSection } from '@app/entity/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import { SidebarTagsSection } from '@app/entity/shared/containers/profile/sidebar/SidebarTagsSection'; -import SidebarStructuredPropsSection from '@app/entity/shared/containers/profile/sidebar/StructuredProperties/SidebarStructuredPropsSection'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { DocumentationTab } from '@app/entity/shared/tabs/Documentation/DocumentationTab'; -import { DataFlowJobsTab } from '@app/entity/shared/tabs/Entity/DataFlowJobsTab'; -import { IncidentTab } from '@app/entity/shared/tabs/Incident/IncidentTab'; -import { PropertiesTab } from '@app/entity/shared/tabs/Properties/PropertiesTab'; -import { GenericEntityProperties } from '@app/entity/shared/types'; -import { getDataProduct } from '@app/entity/shared/utils'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; - -import { useGetDataFlowQuery, useUpdateDataFlowMutation } from '@graphql/dataFlow.generated'; -import { DataFlow, EntityType, OwnershipType, SearchResult } from '@types'; - -/** - * Definition of the DataHub DataFlow entity. - */ -export class DataFlowEntity implements Entity { - type: EntityType = EntityType.DataFlow; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => true; - - isLineageEnabled = () => false; - - getAutoCompleteFieldName = () => 'name'; - - getGraphName = () => 'dataFlow'; - - getPathName = () => 'pipelines'; - - getEntityName = () => 'Pipeline'; - - getCollectionName = () => 'Pipelines'; - - useEntityQuery = useGetDataFlowQuery; - - renderProfile = (urn: string) => ( - { - const activeIncidentCount = dataFlow?.dataFlow?.activeIncidents?.total; - return `Incidents${(activeIncidentCount && ` (${activeIncidentCount})`) || ''}`; - }, - }, - ]} - sidebarSections={this.getSidebarSections()} - /> - ); - - getSidebarSections = () => [ - { - component: SidebarAboutSection, - }, - { - component: SidebarOwnerSection, - properties: { - defaultOwnerType: OwnershipType.TechnicalOwner, - }, - }, - { - component: SidebarTagsSection, - properties: { - hasTags: true, - hasTerms: true, - }, - }, - { - component: SidebarDomainSection, - }, - { - component: DataProductSection, - }, - { - component: SidebarStructuredPropsSection, - }, - ]; - - getOverridePropertiesFromEntity = (dataFlow?: DataFlow | null): GenericEntityProperties => { - // TODO: Get rid of this once we have correctly formed platform coming back. - const name = dataFlow?.properties?.name; - const externalUrl = dataFlow?.properties?.externalUrl; - return { - name, - externalUrl, - }; - }; - - renderPreview = (_: PreviewType, data: DataFlow) => { - const genericProperties = this.getGenericEntityProperties(data); - return ( - - ); - }; - - renderSearch = (result: SearchResult) => { - const data = result.entity as DataFlow; - const genericProperties = this.getGenericEntityProperties(data); - return ( - - ); - }; - - displayName = (data: DataFlow) => { - return data.properties?.name || data.urn; - }; - - getGenericEntityProperties = (data: DataFlow) => { - return getDataForEntityType({ - data, - entityType: this.type, - getOverrideProperties: this.getOverridePropertiesFromEntity, - }); - }; - - supportedCapabilities = () => { - return new Set([ - EntityCapabilityType.OWNERS, - EntityCapabilityType.GLOSSARY_TERMS, - EntityCapabilityType.TAGS, - EntityCapabilityType.DOMAINS, - EntityCapabilityType.DEPRECATION, - EntityCapabilityType.SOFT_DELETE, - EntityCapabilityType.DATA_PRODUCTS, - ]); - }; -} diff --git a/datahub-web-react/src/app/entity/dataFlow/preview/Preview.tsx b/datahub-web-react/src/app/entity/dataFlow/preview/Preview.tsx deleted file mode 100644 index 850b0d5cadb4bc..00000000000000 --- a/datahub-web-react/src/app/entity/dataFlow/preview/Preview.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { IconStyleType } from '@app/entity/Entity'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import DefaultPreviewCard from '@app/preview/DefaultPreviewCard'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { - DataProduct, - Deprecation, - Domain, - EntityPath, - EntityType, - GlobalTags, - Health, - Owner, - ParentContainersResult, - SearchInsight, -} from '@types'; - -const StatText = styled(Typography.Text)` - color: ${ANTD_GRAY[8]}; -`; - -export const Preview = ({ - urn, - name, - platformInstanceId, - description, - platformName, - platformLogo, - owners, - globalTags, - domain, - dataProduct, - externalUrl, - snippet, - insights, - jobCount, - deprecation, - degree, - paths, - health, - parentContainers, -}: { - urn: string; - name: string; - platformInstanceId?: string; - description?: string | null; - platformName?: string; - platformLogo?: string | null; - owners?: Array | null; - domain?: Domain | null; - dataProduct?: DataProduct | null; - globalTags?: GlobalTags | null; - deprecation?: Deprecation | null; - externalUrl?: string | null; - snippet?: React.ReactNode | null; - insights?: Array | null; - jobCount?: number | null; - degree?: number; - paths?: EntityPath[]; - health?: Health[] | null; - parentContainers?: ParentContainersResult | null; -}): JSX.Element => { - const entityRegistry = useEntityRegistry(); - return ( - - {jobCount} {entityRegistry.getCollectionName(EntityType.DataJob)} - , - ]) || - undefined - } - degree={degree} - paths={paths} - health={health || undefined} - parentContainers={parentContainers} - /> - ); -}; diff --git a/datahub-web-react/src/app/entity/dataJob/DataJobEntity.tsx b/datahub-web-react/src/app/entity/dataJob/DataJobEntity.tsx deleted file mode 100644 index c86ff0761fca5c..00000000000000 --- a/datahub-web-react/src/app/entity/dataJob/DataJobEntity.tsx +++ /dev/null @@ -1,268 +0,0 @@ -import { ConsoleSqlOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { DataFlowEntity } from '@app/entity/dataFlow/DataFlowEntity'; -import { Preview } from '@app/entity/dataJob/preview/Preview'; -import { RunsTab } from '@app/entity/dataJob/tabs/RunsTab'; -import { EntityMenuItems } from '@app/entity/shared/EntityDropdown/EntityDropdown'; -import { EntityProfile } from '@app/entity/shared/containers/profile/EntityProfile'; -import { SidebarAboutSection } from '@app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import DataProductSection from '@app/entity/shared/containers/profile/sidebar/DataProduct/DataProductSection'; -import { SidebarDomainSection } from '@app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection'; -import { SidebarOwnerSection } from '@app/entity/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import { SidebarTagsSection } from '@app/entity/shared/containers/profile/sidebar/SidebarTagsSection'; -import SidebarStructuredPropsSection from '@app/entity/shared/containers/profile/sidebar/StructuredProperties/SidebarStructuredPropsSection'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { DocumentationTab } from '@app/entity/shared/tabs/Documentation/DocumentationTab'; -import { DataJobFlowTab } from '@app/entity/shared/tabs/Entity/DataJobFlowTab'; -import { IncidentTab } from '@app/entity/shared/tabs/Incident/IncidentTab'; -import { LineageTab } from '@app/entity/shared/tabs/Lineage/LineageTab'; -import { PropertiesTab } from '@app/entity/shared/tabs/Properties/PropertiesTab'; -import { GenericEntityProperties } from '@app/entity/shared/types'; -import { getDataProduct } from '@app/entity/shared/utils'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; - -import { GetDataJobQuery, useGetDataJobQuery, useUpdateDataJobMutation } from '@graphql/dataJob.generated'; -import { DataJob, EntityType, OwnershipType, SearchResult } from '@types'; - -const getDataJobPlatformName = (data?: DataJob): string => { - return ( - data?.dataFlow?.platform?.properties?.displayName || - capitalizeFirstLetterOnly(data?.dataFlow?.platform?.name) || - '' - ); -}; - -/** - * Definition of the DataHub DataJob entity. - */ -export class DataJobEntity implements Entity { - type: EntityType = EntityType.DataJob; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => false; - - isLineageEnabled = () => true; - - getAutoCompleteFieldName = () => 'name'; - - getGraphName = () => 'dataJob'; - - getPathName = () => 'tasks'; - - getEntityName = () => 'Task'; - - getCollectionName = () => 'Tasks'; - - useEntityQuery = useGetDataJobQuery; - - renderProfile = (urn: string) => ( - true, - enabled: (_, dataJob: GetDataJobQuery) => (dataJob?.dataJob?.runs?.total || 0) !== 0, - }, - }, - { - name: 'Incidents', - component: IncidentTab, - getDynamicName: (_, dataJob) => { - const activeIncidentCount = dataJob?.dataJob?.activeIncidents?.total; - return `Incidents${(activeIncidentCount && ` (${activeIncidentCount})`) || ''}`; - }, - }, - ]} - sidebarSections={this.getSidebarSections()} - /> - ); - - getSidebarSections = () => [ - { - component: SidebarAboutSection, - }, - { - component: SidebarOwnerSection, - properties: { - defaultOwnerType: OwnershipType.TechnicalOwner, - }, - }, - { - component: SidebarTagsSection, - properties: { - hasTags: true, - hasTerms: true, - }, - }, - { - component: SidebarDomainSection, - }, - { - component: DataProductSection, - }, - { - component: SidebarStructuredPropsSection, - }, - ]; - - getOverridePropertiesFromEntity = (dataJob?: DataJob | null): GenericEntityProperties => { - // TODO: Get rid of this once we have correctly formed platform coming back. - const name = dataJob?.properties?.name; - const externalUrl = dataJob?.properties?.externalUrl; - return { - name, - externalUrl, - platform: dataJob?.dataFlow?.platform, - }; - }; - - renderPreview = (_: PreviewType, data: DataJob) => { - const genericProperties = this.getGenericEntityProperties(data); - return ( - - ); - }; - - renderSearch = (result: SearchResult) => { - const data = result.entity as DataJob; - const genericProperties = this.getGenericEntityProperties(data); - return ( - - ); - }; - - getExpandedNameForDataJob = (entity: DataJob): string => { - const name = this.displayName(entity); - const flowName = entity?.dataFlow ? new DataFlowEntity().displayName(entity?.dataFlow) : undefined; - - // if we have no name, just return blank. this should not happen, so dont try & construct a name - if (!name) { - return ''; - } - - // if we have a flow name, return the full name of flow.task - if (flowName) { - return `${flowName}.${name}`; - } - - // otherwise, just return the task name (same as non-expanded) - return name; - }; - - getLineageVizConfig = (entity: DataJob) => { - return { - urn: entity?.urn, - name: this.displayName(entity), - expandedName: this.getExpandedNameForDataJob(entity), - type: EntityType.DataJob, - icon: entity?.dataFlow?.platform?.properties?.logoUrl || undefined, - platform: entity?.dataFlow?.platform, - health: entity?.health || undefined, - }; - }; - - displayName = (data: DataJob) => { - return data.properties?.name || data.urn; - }; - - getGenericEntityProperties = (data: DataJob) => { - return getDataForEntityType({ - data, - entityType: this.type, - getOverrideProperties: this.getOverridePropertiesFromEntity, - }); - }; - - supportedCapabilities = () => { - return new Set([ - EntityCapabilityType.OWNERS, - EntityCapabilityType.GLOSSARY_TERMS, - EntityCapabilityType.TAGS, - EntityCapabilityType.DOMAINS, - EntityCapabilityType.DEPRECATION, - EntityCapabilityType.SOFT_DELETE, - EntityCapabilityType.DATA_PRODUCTS, - ]); - }; -} diff --git a/datahub-web-react/src/app/entity/dataJob/preview/Preview.tsx b/datahub-web-react/src/app/entity/dataJob/preview/Preview.tsx deleted file mode 100644 index 686b6040cce86f..00000000000000 --- a/datahub-web-react/src/app/entity/dataJob/preview/Preview.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import { ClockCircleOutlined } from '@ant-design/icons'; -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { IconStyleType } from '@app/entity/Entity'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import DefaultPreviewCard from '@app/preview/DefaultPreviewCard'; -import { toRelativeTimeString } from '@app/shared/time/timeUtils'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { - DataProduct, - Deprecation, - Domain, - EntityPath, - EntityType, - GlobalTags, - Health, - Owner, - ParentContainersResult, - SearchInsight, -} from '@types'; - -const StatText = styled(Typography.Text)` - color: ${ANTD_GRAY[8]}; -`; - -export const Preview = ({ - urn, - name, - subType, - description, - platformName, - platformLogo, - platformInstanceId, - owners, - domain, - dataProduct, - deprecation, - globalTags, - snippet, - insights, - lastRunTimeMs, - externalUrl, - degree, - paths, - health, - parentContainers, -}: { - urn: string; - name: string; - subType?: string | null; - description?: string | null; - platformName: string; - platformLogo?: string | null; - platformInstanceId?: string; - owners?: Array | null; - domain?: Domain | null; - dataProduct?: DataProduct | null; - deprecation?: Deprecation | null; - globalTags?: GlobalTags | null; - snippet?: React.ReactNode | null; - insights?: Array | null; - lastRunTimeMs?: number | null; - externalUrl?: string | null; - degree?: number; - paths?: EntityPath[]; - health?: Health[] | null; - parentContainers?: ParentContainersResult | null; -}): JSX.Element => { - const entityRegistry = useEntityRegistry(); - return ( - - - Last run {toRelativeTimeString(lastRunTimeMs)} - , - ]) || - undefined - } - degree={degree} - paths={paths} - health={health || undefined} - parentContainers={parentContainers} - /> - ); -}; diff --git a/datahub-web-react/src/app/entity/dataJob/tabs/RunsTab.tsx b/datahub-web-react/src/app/entity/dataJob/tabs/RunsTab.tsx deleted file mode 100644 index 7ac08b1176df38..00000000000000 --- a/datahub-web-react/src/app/entity/dataJob/tabs/RunsTab.tsx +++ /dev/null @@ -1,167 +0,0 @@ -import { DeliveredProcedureOutlined } from '@ant-design/icons'; -import { Pagination, Table, Tooltip, Typography } from 'antd'; -import React, { useState } from 'react'; -import styled from 'styled-components'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { - getExecutionRequestStatusDisplayColor, - getExecutionRequestStatusDisplayText, - getExecutionRequestStatusIcon, -} from '@app/ingest/source/utils'; -import { CompactEntityNameList } from '@app/recommendations/renderer/component/CompactEntityNameList'; -import { scrollToTop } from '@app/shared/searchUtils'; - -import { useGetDataJobRunsQuery } from '@graphql/dataJob.generated'; -import { DataProcessInstanceRunResultType, DataProcessRunStatus } from '@types'; - -import LoadingSvg from '@images/datahub-logo-color-loading_pendulum.svg?react'; - -const ExternalUrlLink = styled.a` - font-size: 16px; - color: ${ANTD_GRAY[8]}; -`; - -const PaginationControlContainer = styled.div` - padding-top: 16px; - padding-bottom: 16px; - text-align: center; -`; - -const LoadingText = styled.div` - margin-top: 18px; - font-size: 12px; -`; - -const LoadingContainer = styled.div` - padding-top: 40px; - padding-bottom: 40px; - width: 100%; - text-align: center; -`; - -function getStatusForStyling(status: DataProcessRunStatus, resultType: DataProcessInstanceRunResultType) { - if (status === 'COMPLETE') { - if (resultType === 'SKIPPED') { - return 'CANCELLED'; - } - return resultType; - } - return 'RUNNING'; -} - -const columns = [ - { - title: 'Time', - dataIndex: 'time', - key: 'time', - render: (value) => ( - {new Date(Number(value)).toLocaleString()} - ), - }, - { - title: 'Run ID', - dataIndex: 'name', - key: 'name', - }, - { - title: 'Status', - dataIndex: 'status', - key: 'status', - render: (status: any, row) => { - const statusForStyling = getStatusForStyling(status, row?.resultType); - const Icon = getExecutionRequestStatusIcon(statusForStyling); - const text = getExecutionRequestStatusDisplayText(statusForStyling); - const color = getExecutionRequestStatusDisplayColor(statusForStyling); - return ( - <> -
- {Icon && } - - {text || 'N/A'} - -
- - ); - }, - }, - { - title: 'Inputs', - dataIndex: 'inputs', - key: 'inputs', - render: (inputs) => , - }, - { - title: 'Outputs', - dataIndex: 'outputs', - key: 'outputs', - render: (outputs) => , - }, - { - title: '', - dataIndex: 'externalUrl', - key: 'externalUrl', - render: (externalUrl) => - externalUrl && ( - - - - - - ), - }, -]; - -const PAGE_SIZE = 20; - -export const RunsTab = () => { - const { urn } = useEntityData(); - const [page, setPage] = useState(1); - - const { loading, data } = useGetDataJobRunsQuery({ - variables: { urn, start: (page - 1) * PAGE_SIZE, count: PAGE_SIZE }, - }); - const runs = data && data?.dataJob?.runs?.runs; - - const tableData = runs - ?.filter((run) => run) - .map((run) => ({ - time: run?.created?.time, - name: run?.name, - status: run?.state?.[0]?.status, - resultType: run?.state?.[0]?.result?.resultType, - inputs: run?.inputs?.relationships?.map((relationship) => relationship.entity), - outputs: run?.outputs?.relationships?.map((relationship) => relationship.entity), - externalUrl: run?.externalUrl, - })); - if (loading) { - return ( - - - Fetching runs... - - ); - } - - const onChangePage = (newPage: number) => { - scrollToTop(); - setPage(newPage); - }; - - return ( - <> - - - - - - ); -}; diff --git a/datahub-web-react/src/app/entity/dataPlatform/DataPlatformEntity.tsx b/datahub-web-react/src/app/entity/dataPlatform/DataPlatformEntity.tsx deleted file mode 100644 index 8b3dbb864d6a5c..00000000000000 --- a/datahub-web-react/src/app/entity/dataPlatform/DataPlatformEntity.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { DatabaseOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { GenericEntityProperties } from '@app/entity/shared/types'; - -import { useGetDataPlatformQuery } from '@graphql/dataPlatform.generated'; -import { DataPlatform, EntityType, SearchResult } from '@types'; - -const getDisplayName = (data?: DataPlatform): string => { - return data?.properties?.displayName || data?.name || ''; -}; - -/** - * Definition of the DataHub DataJob entity. - */ -export class DataPlatformEntity implements Entity { - type: EntityType = EntityType.DataPlatform; - - icon = (fontSize: number, _styleType: IconStyleType, color?: string) => { - return ( - - ); - }; - - isSearchEnabled = () => false; - - isBrowseEnabled = () => false; - - isLineageEnabled = () => false; - - // Currently unused. - getAutoCompleteFieldName = () => 'name'; - - // Currently unused. - getPathName = () => 'platform'; - - // Currently unused. - getEntityName = () => 'Data Platform'; - - // Currently unused. - getCollectionName = () => 'Data Platforms'; - - useEntityQuery = useGetDataPlatformQuery; - - // Currently unused. - renderProfile = (_: string) => <>; - - // Currently unused. - renderPreview = (_: PreviewType, _1: DataPlatform) => <>; - - // Currently unused. - renderSearch = (_: SearchResult) => <>; - - displayName = (data: DataPlatform) => { - return getDisplayName(data); - }; - - getGenericEntityProperties = (data: DataPlatform) => { - return { - ...data, - entityType: this.type, - name: getDisplayName(data), - platform: data, - } as GenericEntityProperties; - }; - - supportedCapabilities = () => { - return new Set([]); - }; - - getGraphName = () => { - return 'dataPlatform'; - }; -} diff --git a/datahub-web-react/src/app/entity/dataPlatformInstance/DataPlatformInstanceEntity.tsx b/datahub-web-react/src/app/entity/dataPlatformInstance/DataPlatformInstanceEntity.tsx deleted file mode 100644 index 684fb2cea0c541..00000000000000 --- a/datahub-web-react/src/app/entity/dataPlatformInstance/DataPlatformInstanceEntity.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import * as React from 'react'; - -import { Entity } from '@app/entity/Entity'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { GenericEntityProperties } from '@app/entity/shared/types'; - -import { DataPlatformInstance, EntityType } from '@types'; - -/** - * Definition of the DataHub DataPlatformInstance entity. - * Most of this still needs to be filled out. - */ -export class DataPlatformInstanceEntity implements Entity { - type: EntityType = EntityType.DataPlatformInstance; - - icon = () => { - return <>; - }; - - isSearchEnabled = () => false; - - isBrowseEnabled = () => false; - - isLineageEnabled = () => false; - - getAutoCompleteFieldName = () => 'name'; - - getPathName = () => 'dataPlatformInstance'; - - getEntityName = () => 'Data Platform Instance'; - - getCollectionName = () => 'Data Platform Instances'; - - renderProfile = () => <>; - - getOverridePropertiesFromEntity = (): GenericEntityProperties => { - return {}; - }; - - renderPreview = () => { - return <>; - }; - - renderSearch = () => { - return <>; - }; - - displayName = (data: DataPlatformInstance) => { - return data?.instanceId || data.urn; - }; - - getGenericEntityProperties = (data: DataPlatformInstance) => { - return getDataForEntityType({ - data, - entityType: this.type, - getOverrideProperties: this.getOverridePropertiesFromEntity, - }); - }; - - supportedCapabilities = () => { - return new Set([]); - }; - - getGraphName = () => { - return 'dataPlatformInstance'; - }; -} diff --git a/datahub-web-react/src/app/entity/dataProcessInstance/DataProcessInstanceEntity.tsx b/datahub-web-react/src/app/entity/dataProcessInstance/DataProcessInstanceEntity.tsx deleted file mode 100644 index 2b038801dc62f2..00000000000000 --- a/datahub-web-react/src/app/entity/dataProcessInstance/DataProcessInstanceEntity.tsx +++ /dev/null @@ -1,223 +0,0 @@ -import { ApiOutlined } from '@ant-design/icons'; -import React from 'react'; - -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { Preview } from '@app/entity/dataProcessInstance/preview/Preview'; -import SummaryTab from '@app/entity/dataProcessInstance/profile/DataProcessInstanceSummary'; -import { EntityMenuItems } from '@app/entity/shared/EntityDropdown/EntityDropdown'; -import { EntityProfile } from '@app/entity/shared/containers/profile/EntityProfile'; -import { SidebarAboutSection } from '@app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import DataProductSection from '@app/entity/shared/containers/profile/sidebar/DataProduct/DataProductSection'; -import { SidebarDomainSection } from '@app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection'; -import { SidebarOwnerSection } from '@app/entity/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import { SidebarTagsSection } from '@app/entity/shared/containers/profile/sidebar/SidebarTagsSection'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { LineageTab } from '@app/entity/shared/tabs/Lineage/LineageTab'; -import { PropertiesTab } from '@app/entity/shared/tabs/Properties/PropertiesTab'; -import { GenericEntityProperties } from '@app/entity/shared/types'; -import { getDataProduct } from '@app/entity/shared/utils'; - -import { GetDataProcessInstanceQuery, useGetDataProcessInstanceQuery } from '@graphql/dataProcessInstance.generated'; -import { DataProcessInstance, EntityType, Entity as GraphQLEntity, OwnershipType, SearchResult } from '@types'; - -const getParentEntities = (data: DataProcessInstance): GraphQLEntity[] => { - const parentEntity = data?.relationships?.relationships?.find( - (rel) => rel.type === 'InstanceOf' && rel.entity?.type === EntityType.DataJob, - ); - - if (!parentEntity || !parentEntity.entity) { - return []; - } - - // First cast to unknown, then to Entity with proper type - return [parentEntity.entity]; -}; - -/** - * Definition of the DataHub DataProcessInstance entity. - */ -export class DataProcessInstanceEntity implements Entity { - type: EntityType = EntityType.DataProcessInstance; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - return ( - - ); - }; - - isSearchEnabled = () => false; - - isBrowseEnabled = () => false; - - isLineageEnabled = () => true; - - getAutoCompleteFieldName = () => 'name'; - - getPathName = () => 'dataProcessInstance'; - - getEntityName = () => 'Process Instance'; - - getGraphName = () => 'dataProcessInstance'; - - getCollectionName = () => 'Process Instances'; - - useEntityQuery = useGetDataProcessInstanceQuery; - - renderProfile = (urn: string) => ( - - ); - - getSidebarSections = () => [ - { - component: SidebarAboutSection, - }, - { - component: SidebarOwnerSection, - properties: { - defaultOwnerType: OwnershipType.TechnicalOwner, - }, - }, - { - component: SidebarTagsSection, - properties: { - hasTags: true, - hasTerms: true, - }, - }, - { - component: SidebarDomainSection, - }, - { - component: DataProductSection, - }, - ]; - - getOverridePropertiesFromEntity = (processInstance?: DataProcessInstance | null): GenericEntityProperties => { - return { - name: processInstance && this.displayName(processInstance), - platform: (processInstance as GetDataProcessInstanceQuery['dataProcessInstance'])?.optionalPlatform, - }; - }; - - renderPreview = (_: PreviewType, data: DataProcessInstance) => { - const genericProperties = this.getGenericEntityProperties(data); - const parentEntities = getParentEntities(data); - return ( - - ); - }; - - renderSearch = (result: SearchResult) => { - const data = result.entity as DataProcessInstance; - const genericProperties = this.getGenericEntityProperties(data); - const parentEntities = getParentEntities(data); - - return ( - - ); - }; - - getLineageVizConfig = (entity: DataProcessInstance) => { - const properties = this.getGenericEntityProperties(entity); - return { - urn: entity?.urn, - name: this.displayName(entity), - type: EntityType.DataProcessInstance, - subtype: entity?.subTypes?.typeNames?.[0], - icon: properties?.platform?.properties?.logoUrl ?? undefined, - platform: properties?.platform ?? undefined, - container: entity?.container, - }; - }; - - displayName = (data: DataProcessInstance) => { - return data.properties?.name || data.urn; - }; - - getGenericEntityProperties = (data: DataProcessInstance) => { - return getDataForEntityType({ - data, - entityType: this.type, - getOverrideProperties: this.getOverridePropertiesFromEntity, - }); - }; - - supportedCapabilities = () => { - return new Set([ - EntityCapabilityType.OWNERS, - EntityCapabilityType.GLOSSARY_TERMS, - EntityCapabilityType.TAGS, - EntityCapabilityType.DOMAINS, - EntityCapabilityType.DEPRECATION, - EntityCapabilityType.SOFT_DELETE, - EntityCapabilityType.DATA_PRODUCTS, - ]); - }; -} diff --git a/datahub-web-react/src/app/entity/dataProcessInstance/preview/Preview.tsx b/datahub-web-react/src/app/entity/dataProcessInstance/preview/Preview.tsx deleted file mode 100644 index 42e8e71f2f9a96..00000000000000 --- a/datahub-web-react/src/app/entity/dataProcessInstance/preview/Preview.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import React from 'react'; - -import { IconStyleType } from '@app/entity/Entity'; -import DefaultPreviewCard from '@app/preview/DefaultPreviewCard'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { - Container, - DataProcessRunEvent, - DataProduct, - Deprecation, - Domain, - EntityPath, - EntityType, - Entity as GeneratedEntity, - GlobalTags, - Health, - Owner, - ParentContainersResult, - SearchInsight, -} from '@types'; - -export const Preview = ({ - urn, - name, - subType, - description, - platformName, - platformLogo, - platformInstanceId, - container, - owners, - domain, - dataProduct, - deprecation, - globalTags, - snippet, - insights, - externalUrl, - degree, - paths, - health, - parentEntities, - parentContainers, - lastRunEvent, -}: { - urn: string; - name: string; - subType?: string | null; - description?: string | null; - platformName?: string; - platformLogo?: string | null; - platformInstanceId?: string; - container?: Container; - owners?: Array | null; - domain?: Domain | null; - dataProduct?: DataProduct | null; - deprecation?: Deprecation | null; - globalTags?: GlobalTags | null; - snippet?: React.ReactNode | null; - insights?: Array | null; - externalUrl?: string | null; - degree?: number; - paths?: EntityPath[]; - health?: Health[] | null; - parentEntities?: Array | null; - parentContainers?: ParentContainersResult | null; - lastRunEvent?: DataProcessRunEvent | null; -}): JSX.Element => { - const entityRegistry = useEntityRegistry(); - return ( - - ); -}; diff --git a/datahub-web-react/src/app/entity/dataProduct/DataProductEntitiesTab.tsx b/datahub-web-react/src/app/entity/dataProduct/DataProductEntitiesTab.tsx deleted file mode 100644 index 6f5cdc369e2b96..00000000000000 --- a/datahub-web-react/src/app/entity/dataProduct/DataProductEntitiesTab.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; - -import generateUseListDataProductAssets from '@app/entity/dataProduct/generateUseListDataProductAssets'; -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { EmbeddedListSearchSection } from '@app/entity/shared/components/styled/search/EmbeddedListSearchSection'; - -export function DataProductEntitiesTab() { - const { urn } = useEntityData(); - - return ( - - ); -} diff --git a/datahub-web-react/src/app/entity/dataProduct/DataProductEntity.tsx b/datahub-web-react/src/app/entity/dataProduct/DataProductEntity.tsx deleted file mode 100644 index 14d7f332571e9e..00000000000000 --- a/datahub-web-react/src/app/entity/dataProduct/DataProductEntity.tsx +++ /dev/null @@ -1,204 +0,0 @@ -import { FileDoneOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { DataProductEntitiesTab } from '@app/entity/dataProduct/DataProductEntitiesTab'; -import { Preview } from '@app/entity/dataProduct/preview/Preview'; -import { EntityMenuItems } from '@app/entity/shared/EntityDropdown/EntityDropdown'; -import { EntityProfile } from '@app/entity/shared/containers/profile/EntityProfile'; -import { SidebarAboutSection } from '@app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import { SidebarViewDefinitionSection } from '@app/entity/shared/containers/profile/sidebar/Dataset/View/SidebarViewDefinitionSection'; -import { SidebarDomainSection } from '@app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection'; -import { SidebarOwnerSection } from '@app/entity/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import { SidebarTagsSection } from '@app/entity/shared/containers/profile/sidebar/SidebarTagsSection'; -import SidebarStructuredPropsSection from '@app/entity/shared/containers/profile/sidebar/StructuredProperties/SidebarStructuredPropsSection'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { EntityActionItem } from '@app/entity/shared/entity/EntityActions'; -import { DocumentationTab } from '@app/entity/shared/tabs/Documentation/DocumentationTab'; -import { PropertiesTab } from '@app/entity/shared/tabs/Properties/PropertiesTab'; - -import { useGetDataProductQuery } from '@graphql/dataProduct.generated'; -import { GetDatasetQuery } from '@graphql/dataset.generated'; -import { DataProduct, EntityType, OwnershipType, SearchResult } from '@types'; - -/** - * Definition of the DataHub Data Product entity. - */ -export class DataProductEntity implements Entity { - type: EntityType = EntityType.DataProduct; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - if (styleType === IconStyleType.SVG) { - return ( - - ); - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => true; - - isLineageEnabled = () => false; - - getAutoCompleteFieldName = () => 'name'; - - getPathName = () => 'dataProduct'; - - getEntityName = () => 'Data Product'; - - getCollectionName = () => 'Data Products'; - - useEntityQuery = useGetDataProductQuery; - - renderProfile = (urn: string) => ( - - ); - - getSidebarSections = () => [ - { - component: SidebarAboutSection, - }, - { - component: SidebarOwnerSection, - properties: { - defaultOwnerType: OwnershipType.TechnicalOwner, - }, - }, - { - component: SidebarViewDefinitionSection, - display: { - // to do - change when we have a GetDataProductQuery - visible: (_, dataset: GetDatasetQuery) => (dataset?.dataset?.viewProperties?.logic && true) || false, - }, - }, - { - component: SidebarTagsSection, - properties: { - hasTags: true, - hasTerms: true, - }, - }, - { - component: SidebarDomainSection, - properties: { - updateOnly: true, - }, - }, - { - component: SidebarStructuredPropsSection, - }, - ]; - - renderPreview = (_: PreviewType, data: DataProduct) => { - return ( - - ); - }; - - renderSearch = (result: SearchResult) => { - const data = result.entity as DataProduct; - return ( - - ); - }; - - displayName = (data: DataProduct) => { - return data?.properties?.name || data.urn; - }; - - getOverridePropertiesFromEntity = (data: DataProduct) => { - const name = data?.properties?.name; - const externalUrl = data?.properties?.externalUrl; - const entityCount = data?.entities?.total || undefined; - return { - name, - externalUrl, - entityCount, - }; - }; - - getGenericEntityProperties = (data: DataProduct) => { - return getDataForEntityType({ - data, - entityType: this.type, - getOverrideProperties: this.getOverridePropertiesFromEntity, - }); - }; - - supportedCapabilities = () => { - return new Set([ - EntityCapabilityType.OWNERS, - EntityCapabilityType.GLOSSARY_TERMS, - EntityCapabilityType.TAGS, - EntityCapabilityType.DOMAINS, - ]); - }; - - getGraphName = () => { - return 'dataProduct'; - }; -} diff --git a/datahub-web-react/src/app/entity/dataProduct/generateUseListDataProductAssets.ts b/datahub-web-react/src/app/entity/dataProduct/generateUseListDataProductAssets.ts deleted file mode 100644 index 931f2fcc87fdb4..00000000000000 --- a/datahub-web-react/src/app/entity/dataProduct/generateUseListDataProductAssets.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { GetSearchResultsParams } from '@app/entity/shared/components/styled/search/types'; - -import { useListDataProductAssetsQuery } from '@graphql/search.generated'; - -export default function generateUseListDataProductAssets({ urn }: { urn: string }) { - return (params: GetSearchResultsParams) => { - const { - variables: { input }, - } = params; - - const { data, loading, error, refetch } = useListDataProductAssetsQuery({ - variables: { urn, input }, - }); - - return { - data: data?.listDataProductAssets, - loading, - error, - refetch: (refetchParams: GetSearchResultsParams['variables']) => { - return refetch({ urn, input: refetchParams.input }).then((res) => res.data.listDataProductAssets); - }, - }; - }; -} diff --git a/datahub-web-react/src/app/entity/dataProduct/preview/Preview.tsx b/datahub-web-react/src/app/entity/dataProduct/preview/Preview.tsx deleted file mode 100644 index 29e07bd0430b94..00000000000000 --- a/datahub-web-react/src/app/entity/dataProduct/preview/Preview.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import React from 'react'; - -import { IconStyleType } from '@app/entity/Entity'; -import DefaultPreviewCard from '@app/preview/DefaultPreviewCard'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { Domain, EntityPath, EntityType, GlobalTags, GlossaryTerms, Owner } from '@types'; - -interface Props { - urn: string; - name: string; - description?: string | null; - owners?: Array | null; - domain?: Domain | null; - globalTags?: GlobalTags | null; - glossaryTerms?: GlossaryTerms | null; - entityCount?: number; - externalUrl?: string | null; - degree?: number; - paths?: EntityPath[]; -} - -export const Preview = ({ - urn, - name, - description, - owners, - globalTags, - domain, - glossaryTerms, - entityCount, - externalUrl, - degree, - paths, -}: Props): JSX.Element => { - const entityRegistry = useEntityRegistry(); - - return ( - - ); -}; diff --git a/datahub-web-react/src/app/entity/dataset/DatasetEntity.tsx b/datahub-web-react/src/app/entity/dataset/DatasetEntity.tsx deleted file mode 100644 index 2a473ae405ca28..00000000000000 --- a/datahub-web-react/src/app/entity/dataset/DatasetEntity.tsx +++ /dev/null @@ -1,409 +0,0 @@ -import { DatabaseFilled, DatabaseOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { Preview } from '@app/entity/dataset/preview/Preview'; -import { OperationsTab } from '@app/entity/dataset/profile/OperationsTab'; -import { DatasetStatsSummarySubHeader } from '@app/entity/dataset/profile/stats/stats/DatasetStatsSummarySubHeader'; -import { getLastUpdatedMs } from '@app/entity/dataset/shared/utils'; -import { EntityMenuItems } from '@app/entity/shared/EntityDropdown/EntityDropdown'; -import { EntityProfile } from '@app/entity/shared/containers/profile/EntityProfile'; -import { SidebarAboutSection } from '@app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import DataProductSection from '@app/entity/shared/containers/profile/sidebar/DataProduct/DataProductSection'; -import { SidebarViewDefinitionSection } from '@app/entity/shared/containers/profile/sidebar/Dataset/View/SidebarViewDefinitionSection'; -import { SidebarDomainSection } from '@app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection'; -import { SidebarOwnerSection } from '@app/entity/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import { SidebarSiblingsSection } from '@app/entity/shared/containers/profile/sidebar/SidebarSiblingsSection'; -import { SidebarTagsSection } from '@app/entity/shared/containers/profile/sidebar/SidebarTagsSection'; -import SidebarStructuredPropsSection from '@app/entity/shared/containers/profile/sidebar/StructuredProperties/SidebarStructuredPropsSection'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import EmbeddedProfile from '@app/entity/shared/embed/EmbeddedProfile'; -import AccessManagement from '@app/entity/shared/tabs/Dataset/AccessManagement/AccessManagement'; -import { GovernanceTab } from '@app/entity/shared/tabs/Dataset/Governance/GovernanceTab'; -import QueriesTab from '@app/entity/shared/tabs/Dataset/Queries/QueriesTab'; -import { RelationshipsTab } from '@app/entity/shared/tabs/Dataset/Relationship/RelationshipsTab'; -import { SchemaTab } from '@app/entity/shared/tabs/Dataset/Schema/SchemaTab'; -import StatsTab from '@app/entity/shared/tabs/Dataset/Stats/StatsTab'; -import { ValidationsTab } from '@app/entity/shared/tabs/Dataset/Validations/ValidationsTab'; -import ViewDefinitionTab from '@app/entity/shared/tabs/Dataset/View/ViewDefinitionTab'; -import { DocumentationTab } from '@app/entity/shared/tabs/Documentation/DocumentationTab'; -import { EmbedTab } from '@app/entity/shared/tabs/Embed/EmbedTab'; -import { IncidentTab } from '@app/entity/shared/tabs/Incident/IncidentTab'; -import { LineageTab } from '@app/entity/shared/tabs/Lineage/LineageTab'; -import { PropertiesTab } from '@app/entity/shared/tabs/Properties/PropertiesTab'; -import { GenericEntityProperties } from '@app/entity/shared/types'; -import { getDataProduct } from '@app/entity/shared/utils'; -import { MatchedFieldList } from '@app/search/matches/MatchedFieldList'; -import { matchedFieldPathsRenderer } from '@app/search/matches/matchedFieldPathsRenderer'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; -import { useAppConfig } from '@app/useAppConfig'; - -import { GetDatasetQuery, useGetDatasetQuery, useUpdateDatasetMutation } from '@graphql/dataset.generated'; -import { Dataset, DatasetProperties, EntityType, OwnershipType, SearchResult } from '@types'; - -const SUBTYPES = { - VIEW: 'view', -}; - -/** - * Definition of the DataHub Dataset entity. - */ -export class DatasetEntity implements Entity { - type: EntityType = EntityType.Dataset; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - if (styleType === IconStyleType.SVG) { - return ( - - ); - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - appconfig = useAppConfig; - - isBrowseEnabled = () => true; - - isLineageEnabled = () => true; - - getAutoCompleteFieldName = () => 'name'; - - getPathName = () => 'dataset'; - - getGraphName = () => 'dataset'; - - getEntityName = () => 'Dataset'; - - getCollectionName = () => 'Datasets'; - - useEntityQuery = useGetDatasetQuery; - - renderProfile = (urn: string) => ( - false, - enabled: (_, _2) => false, - }, - }, - { - name: 'View Definition', - component: ViewDefinitionTab, - display: { - visible: (_, dataset: GetDatasetQuery) => - !!dataset?.dataset?.viewProperties?.logic || - !!dataset?.dataset?.subTypes?.typeNames - ?.map((t) => t.toLocaleLowerCase()) - .includes(SUBTYPES.VIEW.toLocaleLowerCase()), - enabled: (_, dataset: GetDatasetQuery) => !!dataset?.dataset?.viewProperties?.logic, - }, - }, - { - name: 'Documentation', - component: DocumentationTab, - }, - { - name: 'Preview', - component: EmbedTab, - display: { - visible: (_, dataset: GetDatasetQuery) => !!dataset?.dataset?.embed?.renderUrl, - enabled: (_, dataset: GetDatasetQuery) => !!dataset?.dataset?.embed?.renderUrl, - }, - }, - { - name: 'Lineage', - component: LineageTab, - }, - { - name: 'Access', - component: AccessManagement, - display: { - visible: (_, _1) => this.appconfig().config.featureFlags.showAccessManagement, - enabled: (_, dataset: GetDatasetQuery) => { - const accessAspect = dataset?.dataset?.access; - const rolesList = accessAspect?.roles; - return !!accessAspect && !!rolesList && rolesList.length > 0; - }, - }, - }, - { - name: 'Properties', - component: PropertiesTab, - }, - { - name: 'Queries', - component: QueriesTab, - display: { - visible: (_, _1) => true, - enabled: (_, _2) => true, - }, - }, - { - name: 'Stats', - component: StatsTab, - display: { - visible: (_, _1) => true, - enabled: (_, dataset: GetDatasetQuery) => - (dataset?.dataset?.datasetProfiles?.length || 0) > 0 || - (dataset?.dataset?.usageStats?.buckets?.length || 0) > 0 || - (dataset?.dataset?.operations?.length || 0) > 0, - }, - }, - { - name: 'Quality', - component: ValidationsTab, - display: { - visible: (_, _1) => true, - enabled: (_, dataset: GetDatasetQuery) => { - return (dataset?.dataset?.assertions?.total || 0) > 0; - }, - }, - }, - { - name: 'Governance', - component: GovernanceTab, - display: { - visible: (_, _1) => true, - enabled: (_, dataset: GetDatasetQuery) => { - return dataset?.dataset?.testResults !== null; - }, - }, - }, - { - name: 'Runs', // TODO: Rename this to DatasetRunsTab. - component: OperationsTab, - display: { - visible: (_, dataset: GetDatasetQuery) => { - return (dataset?.dataset?.runs?.total || 0) > 0; - }, - enabled: (_, dataset: GetDatasetQuery) => { - return (dataset?.dataset?.runs?.total || 0) > 0; - }, - }, - }, - { - name: 'Incidents', - component: IncidentTab, - getDynamicName: (_, dataset) => { - const activeIncidentCount = dataset?.dataset?.activeIncidents?.total; - return `Incidents${(activeIncidentCount && ` (${activeIncidentCount})`) || ''}`; - }, - }, - ]} - sidebarSections={this.getSidebarSections()} - isNameEditable - /> - ); - - getSidebarSections = () => [ - { - component: SidebarAboutSection, - }, - { - component: SidebarOwnerSection, - properties: { - defaultOwnerType: OwnershipType.TechnicalOwner, - }, - }, - { - component: SidebarSiblingsSection, - display: { - visible: (_, dataset: GetDatasetQuery) => (dataset?.dataset?.siblingsSearch?.total || 0) > 0, - }, - }, - { - component: SidebarViewDefinitionSection, - display: { - visible: (_, dataset: GetDatasetQuery) => !!dataset?.dataset?.viewProperties?.logic, - }, - }, - { - component: SidebarTagsSection, - properties: { - hasTags: true, - hasTerms: true, - }, - }, - { - component: SidebarDomainSection, - }, - { - component: DataProductSection, - }, - { - component: SidebarStructuredPropsSection, - }, - // TODO: Add back once entity-level recommendations are complete. - // { - // component: SidebarRecommendationsSection, - // }, - ]; - - getOverridePropertiesFromEntity = (dataset?: Dataset | null): GenericEntityProperties => { - // if dataset has subTypes filled out, pick the most specific subtype and return it - const subTypes = dataset?.subTypes; - const extendedProperties: DatasetProperties | undefined | null = dataset?.properties && { - ...dataset?.properties, - qualifiedName: dataset?.properties?.qualifiedName || this.displayName(dataset), - }; - return { - name: dataset && this.displayName(dataset), - externalUrl: dataset?.properties?.externalUrl, - entityTypeOverride: subTypes ? capitalizeFirstLetterOnly(subTypes.typeNames?.[0]) : '', - properties: extendedProperties, - }; - }; - - renderPreview = (_: PreviewType, data: Dataset) => { - const genericProperties = this.getGenericEntityProperties(data); - return ( - - ); - }; - - renderSearch = (result: SearchResult) => { - const data = result.entity as Dataset; - const genericProperties = this.getGenericEntityProperties(data); - - return ( - platform.properties?.displayName || capitalizeFirstLetterOnly(platform.name), - )} - platformLogos={genericProperties?.siblingPlatforms?.map((platform) => platform.properties?.logoUrl)} - owners={data.ownership?.owners} - globalTags={data.globalTags} - domain={data.domain?.domain} - dataProduct={getDataProduct(genericProperties?.dataProduct)} - deprecation={data.deprecation} - glossaryTerms={data.glossaryTerms} - subtype={data.subTypes?.typeNames?.[0]} - container={data.container} - parentContainers={data.parentContainers} - snippet={} - insights={result.insights} - externalUrl={data.properties?.externalUrl} - statsSummary={data.statsSummary} - rowCount={(data as any).lastProfile?.length && (data as any).lastProfile[0].rowCount} - columnCount={(data as any).lastProfile?.length && (data as any).lastProfile[0].columnCount} - sizeInBytes={(data as any).lastProfile?.length && (data as any).lastProfile[0].sizeInBytes} - lastUpdatedMs={getLastUpdatedMs(data.properties, (data as any)?.lastOperation)} - health={data.health} - degree={(result as any).degree} - paths={(result as any).paths} - /> - ); - }; - - getLineageVizConfig = (entity: Dataset) => { - return { - urn: entity?.urn, - name: entity?.properties?.name || entity.name, - expandedName: entity?.properties?.qualifiedName || entity?.properties?.name || entity.name, - type: EntityType.Dataset, - subtype: entity?.subTypes?.typeNames?.[0] || undefined, - icon: entity?.platform?.properties?.logoUrl || undefined, - platform: entity?.platform, - health: entity?.health || undefined, - }; - }; - - displayName = (data: Dataset) => { - return data?.editableProperties?.name || data?.properties?.name || data.name || data.urn; - }; - - platformLogoUrl = (data: Dataset) => { - return data.platform.properties?.logoUrl || undefined; - }; - - getGenericEntityProperties = (data: Dataset) => { - return getDataForEntityType({ - data, - entityType: this.type, - getOverrideProperties: this.getOverridePropertiesFromEntity, - }); - }; - - supportedCapabilities = () => { - return new Set([ - EntityCapabilityType.OWNERS, - EntityCapabilityType.GLOSSARY_TERMS, - EntityCapabilityType.TAGS, - EntityCapabilityType.DOMAINS, - EntityCapabilityType.DEPRECATION, - EntityCapabilityType.SOFT_DELETE, - EntityCapabilityType.DATA_PRODUCTS, - ]); - }; - - renderEmbeddedProfile = (urn: string) => ( - - ); -} diff --git a/datahub-web-react/src/app/entity/dataset/preview/Preview.tsx b/datahub-web-react/src/app/entity/dataset/preview/Preview.tsx deleted file mode 100644 index cf489ada040877..00000000000000 --- a/datahub-web-react/src/app/entity/dataset/preview/Preview.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import React from 'react'; - -import { IconStyleType } from '@app/entity/Entity'; -import { DatasetStatsSummary as DatasetStatsSummaryView } from '@app/entity/dataset/shared/DatasetStatsSummary'; -import DefaultPreviewCard from '@app/preview/DefaultPreviewCard'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { - Container, - DataProduct, - DatasetStatsSummary, - Deprecation, - Domain, - EntityPath, - EntityType, - FabricType, - GlobalTags, - GlossaryTerms, - Health, - Maybe, - Owner, - ParentContainersResult, - SearchInsight, -} from '@types'; - -export const Preview = ({ - urn, - name, - origin, - description, - platformName, - platformLogo, - platformNames, - platformLogos, - platformInstanceId, - owners, - globalTags, - domain, - dataProduct, - deprecation, - snippet, - insights, - glossaryTerms, - subtype, - externalUrl, - container, - parentContainers, - rowCount, - columnCount, - sizeInBytes, - statsSummary, - lastUpdatedMs, - health, - degree, - paths, -}: { - urn: string; - name: string; - origin: FabricType; - description?: string | null; - platformName?: string; - platformLogo?: string | null; - platformNames?: (Maybe | undefined)[]; - platformLogos?: (Maybe | undefined)[]; - platformInstanceId?: string; - owners?: Array | null; - domain?: Domain | null; - dataProduct?: DataProduct | null; - deprecation?: Deprecation | null; - globalTags?: GlobalTags | null; - snippet?: React.ReactNode | null; - insights?: Array | null; - glossaryTerms?: GlossaryTerms | null; - subtype?: string | null; - externalUrl?: string | null; - container?: Container | null; - parentContainers?: ParentContainersResult | null; - rowCount?: number | null; - columnCount?: number | null; - sizeInBytes?: number | null; - statsSummary?: DatasetStatsSummary | null; - lastUpdatedMs?: number | null; - health?: Health[] | null; - degree?: number; - paths?: EntityPath[]; -}): JSX.Element => { - const entityRegistry = useEntityRegistry(); - return ( - - } - health={health || undefined} - degree={degree} - paths={paths} - /> - ); -}; diff --git a/datahub-web-react/src/app/entity/dataset/profile/Lineage.tsx b/datahub-web-react/src/app/entity/dataset/profile/Lineage.tsx index cc6f245dcbf105..d7c651da8679bb 100644 --- a/datahub-web-react/src/app/entity/dataset/profile/Lineage.tsx +++ b/datahub-web-react/src/app/entity/dataset/profile/Lineage.tsx @@ -9,7 +9,7 @@ import { useEntityRegistry } from '@app/useEntityRegistry'; import { DownstreamEntityRelationships, EntityType, UpstreamEntityRelationships } from '@types'; -export type Props = { +type Props = { upstreamLineage?: UpstreamEntityRelationships | null; downstreamLineage?: DownstreamEntityRelationships | null; }; diff --git a/datahub-web-react/src/app/entity/dataset/profile/OperationsTab.tsx b/datahub-web-react/src/app/entity/dataset/profile/OperationsTab.tsx deleted file mode 100644 index c443efb704486b..00000000000000 --- a/datahub-web-react/src/app/entity/dataset/profile/OperationsTab.tsx +++ /dev/null @@ -1,243 +0,0 @@ -import { DeliveredProcedureOutlined } from '@ant-design/icons'; -import { Pagination, Table, Tooltip, Typography } from 'antd'; -import React, { useState } from 'react'; -import styled from 'styled-components'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { notEmpty } from '@app/entity/shared/utils'; -import { - getExecutionRequestStatusDisplayColor, - getExecutionRequestStatusDisplayText, - getExecutionRequestStatusIcon, -} from '@app/ingest/source/utils'; -import { CompactEntityNameList } from '@app/recommendations/renderer/component/CompactEntityNameList'; -import { formatDuration } from '@app/shared/formatDuration'; -import { scrollToTop } from '@app/shared/searchUtils'; - -import { GetDatasetRunsQuery, useGetDatasetRunsQuery } from '@graphql/dataset.generated'; -import { DataProcessInstanceRunResultType, DataProcessRunStatus, EntityType, RelationshipDirection } from '@types'; - -import LoadingSvg from '@images/datahub-logo-color-loading_pendulum.svg?react'; - -const ExternalUrlLink = styled.a` - font-size: 16px; - color: ${ANTD_GRAY[8]}; -`; - -const PaginationControlContainer = styled.div` - padding-top: 16px; - padding-bottom: 16px; - text-align: center; -`; - -const LoadingText = styled.div` - margin-top: 18px; - font-size: 12px; -`; - -const LoadingContainer = styled.div` - padding-top: 40px; - padding-bottom: 40px; - width: 100%; - text-align: center; -`; - -function getStatusForStyling(status: DataProcessRunStatus, resultType: DataProcessInstanceRunResultType) { - if (status === 'COMPLETE') { - if (resultType === 'SKIPPED') { - return 'CANCELLED'; - } - return resultType; - } - return 'RUNNING'; -} - -const columns = [ - { - title: 'Time', - dataIndex: 'time', - key: 'time', - render: (value) => ( - {new Date(Number(value)).toLocaleString()} - ), - }, - { - title: 'Duration', - dataIndex: 'duration', - key: 'duration', - render: (durationMs: number) => formatDuration(durationMs), - }, - { - title: 'Run ID', - dataIndex: 'name', - key: 'name', - }, - { - title: 'Task', - dataIndex: 'parentTemplate', - key: 'parentTemplate', - render: (parentTemplate) => , - }, - { - title: 'Status', - dataIndex: 'status', - key: 'status', - render: (status: any, row) => { - const statusForStyling = getStatusForStyling(status, row?.resultType); - const Icon = getExecutionRequestStatusIcon(statusForStyling); - const text = getExecutionRequestStatusDisplayText(statusForStyling); - const color = getExecutionRequestStatusDisplayColor(statusForStyling); - return ( - <> -
- {Icon && } - - {text || 'N/A'} - -
- - ); - }, - }, - { - title: 'Inputs', - dataIndex: 'inputs', - key: 'inputs', - render: (inputs) => , - }, - { - title: 'Outputs', - dataIndex: 'outputs', - key: 'outputs', - render: (outputs) => , - }, - { - title: '', - dataIndex: 'externalUrl', - key: 'externalUrl', - render: (externalUrl) => - externalUrl && ( - - - - - - ), - }, -]; - -const PAGE_SIZE = 20; - -export const OperationsTab = () => { - const { urn, entityData } = useEntityData(); - const [page, setPage] = useState(1); - - // Fetch data across all siblings. - const allUrns = [ - urn, - ...(entityData?.siblingsSearch?.searchResults || []).map((sibling) => sibling.entity.urn).filter(notEmpty), - ]; - const loadings: boolean[] = []; - const datas: GetDatasetRunsQuery[] = []; - allUrns.forEach((entityUrn) => { - // Because there's a consistent number and order of the urns, - // this usage of a hook within a loop should be safe. - // eslint-disable-next-line react-hooks/rules-of-hooks - const { loading, data } = useGetDatasetRunsQuery({ - variables: { - urn: entityUrn, - start: (page - 1) * PAGE_SIZE, - count: PAGE_SIZE, - direction: RelationshipDirection.Outgoing, - }, - }); - loadings.push(loading); - if (data) { - datas.push(data); - } - }); - - const loading = loadings.some((loadingEntry) => loadingEntry); - - // Merge the runs data from all entities. - // If there's more than one entity contributing to the data, then we can't do pagination. - let canPaginate = true; - let dataRuns: NonNullable['runs'] | undefined; - if (datas.length > 0) { - let numWithRuns = 0; - for (let i = 0; i < datas.length; i++) { - if (datas[i]?.dataset?.runs?.total) { - numWithRuns++; - } - - if (dataRuns && dataRuns.runs) { - dataRuns.runs.push(...(datas[i]?.dataset?.runs?.runs || [])); - dataRuns.total = (dataRuns.total ?? 0) + (datas[i]?.dataset?.runs?.total ?? 0); - } else { - dataRuns = JSON.parse(JSON.stringify(datas[i]?.dataset?.runs)); - } - } - - if (numWithRuns > 1) { - canPaginate = false; - } - } - - // This also sorts the runs data across all entities. - const runs = dataRuns?.runs?.sort((a, b) => (b?.created?.time ?? 0) - (a?.created?.time ?? 0)); - - const tableData = runs - ?.filter((run) => run) - .map((run) => ({ - time: run?.created?.time, - name: run?.name, - status: run?.state?.[0]?.status, - resultType: run?.state?.[0]?.result?.resultType, - duration: run?.state?.[0]?.durationMillis, - inputs: run?.inputs?.relationships?.map((relationship) => relationship.entity), - outputs: run?.outputs?.relationships?.map((relationship) => relationship.entity), - externalUrl: run?.externalUrl, - parentTemplate: run?.parentTemplate?.relationships?.[0]?.entity, - })); - - // If the table contains jobs, we need to show the job-related columns. Otherwise we can simplify the table. - const containsJobs = tableData?.some((run) => run.parentTemplate?.type !== EntityType.Dataset); - const simplifiedColumns = containsJobs - ? columns - : columns.filter((column) => !['name', 'inputs', 'outputs'].includes(column.key)); - - const onChangePage = (newPage: number) => { - scrollToTop(); - setPage(newPage); - }; - - // TODO: Much of this file is duplicated from RunsTab.tsx. We should refactor this to share code. - return ( - <> - {loading && ( - - - Fetching runs... - - )} - {!loading && ( - <> -
- {canPaginate && ( - - - - )} - - )} - - ); -}; diff --git a/datahub-web-react/src/app/entity/dataset/profile/UsageFacepile.tsx b/datahub-web-react/src/app/entity/dataset/profile/UsageFacepile.tsx index 7cd58d287eac67..2556336de62703 100644 --- a/datahub-web-react/src/app/entity/dataset/profile/UsageFacepile.tsx +++ b/datahub-web-react/src/app/entity/dataset/profile/UsageFacepile.tsx @@ -7,7 +7,7 @@ import getAvatarColor from '@app/shared/avatar/getAvatarColor'; import { UserUsageCounts } from '@types'; -export type Props = { +type Props = { users?: (UserUsageCounts | null)[] | null; maxNumberDisplayed?: number; }; diff --git a/datahub-web-react/src/app/entity/dataset/profile/schema/components/SchemaVersionSummary.tsx b/datahub-web-react/src/app/entity/dataset/profile/schema/components/SchemaVersionSummary.tsx index 2a27a41a8cf387..ade15ec68d255f 100644 --- a/datahub-web-react/src/app/entity/dataset/profile/schema/components/SchemaVersionSummary.tsx +++ b/datahub-web-react/src/app/entity/dataset/profile/schema/components/SchemaVersionSummary.tsx @@ -21,7 +21,7 @@ type Props = { diffSummary: SchemaDiffSummary; }; -export default function SchemaVersionSummary({ diffSummary }: Props) { +function SchemaVersionSummary({ diffSummary }: Props) { return (
    diff --git a/datahub-web-react/src/app/entity/dataset/profile/schema/components/TypeIcon.tsx b/datahub-web-react/src/app/entity/dataset/profile/schema/components/TypeIcon.tsx deleted file mode 100644 index df54db34b8b5c8..00000000000000 --- a/datahub-web-react/src/app/entity/dataset/profile/schema/components/TypeIcon.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import { - CalendarOutlined, - FieldBinaryOutlined, - FieldTimeOutlined, - NumberOutlined, - QuestionCircleOutlined, - UnderlineOutlined, - UnorderedListOutlined, -} from '@ant-design/icons'; -import { Tooltip, Typography } from 'antd'; -import React, { FC } from 'react'; -import { VscFileBinary, VscSymbolString } from 'react-icons/vsc'; -import styled from 'styled-components'; - -import { capitalizeFirstLetter } from '@app/shared/textUtil'; - -import { SchemaFieldDataType } from '@types'; - -const TypeIconContainer = styled.div` - display: flex; - flex-direction: column; - justify-content: center; - text-align: center; - margin-top: 2.5px; - width: 40px; -`; - -const TypeSubtitle = styled(Typography.Text)<{ hasicon?: string }>` - font-size: 8px; - text-align: center; - ${(props) => (props.hasicon ? '' : 'margin-top: 4px;')} -`; - -const IconSpan = styled.span` - font-size: 18px; -`; - -const DATA_TYPE_ICON_MAP: Record | null; size: number; text: string }> = - { - [SchemaFieldDataType.Boolean]: { - icon: FieldBinaryOutlined, - size: 18, - text: 'Boolean', - }, - [SchemaFieldDataType.Fixed]: { icon: FieldBinaryOutlined, size: 18, text: 'Fixed' }, - [SchemaFieldDataType.String]: { - icon: () => ( - - - - ), - size: 20, - text: 'String', - }, - [SchemaFieldDataType.Bytes]: { - icon: () => ( - - - - ), - size: 18, - text: 'Bytes', - }, - [SchemaFieldDataType.Number]: { icon: NumberOutlined, size: 14, text: 'Number' }, - [SchemaFieldDataType.Date]: { icon: CalendarOutlined, size: 18, text: 'Date' }, - [SchemaFieldDataType.Time]: { icon: FieldTimeOutlined, size: 18, text: 'Time' }, - [SchemaFieldDataType.Enum]: { icon: UnorderedListOutlined, size: 18, text: 'Enum' }, - [SchemaFieldDataType.Null]: { icon: QuestionCircleOutlined, size: 16, text: '' }, - [SchemaFieldDataType.Map]: { icon: null, size: 0, text: 'Map' }, - [SchemaFieldDataType.Array]: { icon: UnorderedListOutlined, size: 14, text: 'Array' }, - [SchemaFieldDataType.Union]: { icon: UnderlineOutlined, size: 14, text: 'Union' }, - [SchemaFieldDataType.Struct]: { icon: null, size: 0, text: 'Struct' }, - }; - -const truncate = (length: number, input?: string | null) => { - if (!input) return ''; - if (input.length > length) { - return `${input.substring(0, length)}...`; - } - return input; -}; - -type Props = { - type: SchemaFieldDataType; - nativeDataType: string | null | undefined; -}; - -export default function TypeIcon({ type, nativeDataType }: Props) { - const { icon: Icon, size, text } = DATA_TYPE_ICON_MAP[type]; - - // if unable to match type to DataHub, display native type info by default - const nativeFallback = type === SchemaFieldDataType.Null; - - // eslint-disable-next-line react/prop-types - const NativeDataTypeTooltip = ({ children }) => - nativeDataType ? ( - - {children} - - ) : ( - <>{children} - ); - - return ( - - - {Icon && } - - {nativeFallback ? truncate(250, nativeDataType) : text} - - - - ); -} diff --git a/datahub-web-react/src/app/entity/dataset/profile/schema/utils/types.ts b/datahub-web-react/src/app/entity/dataset/profile/schema/utils/types.ts index 0b43ef2f113ea7..78281d9b9e0238 100644 --- a/datahub-web-react/src/app/entity/dataset/profile/schema/utils/types.ts +++ b/datahub-web-react/src/app/entity/dataset/profile/schema/utils/types.ts @@ -10,7 +10,7 @@ export interface ExtendedSchemaFields extends SchemaField { parent?: ExtendedSchemaFields; } -export enum SchemaViewType { +enum SchemaViewType { NORMAL, BLAME, } diff --git a/datahub-web-react/src/app/entity/dataset/profile/schema/utils/utils.ts b/datahub-web-react/src/app/entity/dataset/profile/schema/utils/utils.ts index 1d90ee772529dd..f7c5a178cb9e4c 100644 --- a/datahub-web-react/src/app/entity/dataset/profile/schema/utils/utils.ts +++ b/datahub-web-react/src/app/entity/dataset/profile/schema/utils/utils.ts @@ -13,7 +13,7 @@ import { SchemaField, } from '@types'; -export function convertEditableSchemaMeta( +function convertEditableSchemaMeta( editableSchemaMeta?: Array, fields?: Array, ): Array { @@ -33,7 +33,7 @@ export function convertEditableSchemaMeta( return updatedFields; } -export function convertEditableSchemaMetadataForUpdate( +function convertEditableSchemaMetadataForUpdate( editableSchemaMetadata: EditableSchemaMetadata | null | undefined, ): EditableSchemaMetadataUpdate { return { @@ -132,7 +132,7 @@ export function groupByFieldPath( return outputRows; } -export function diffMarkdown(oldStr: string, newStr: string) { +function diffMarkdown(oldStr: string, newStr: string) { const diffArray = diff.diffChars(oldStr || '', newStr || ''); return diffArray .map((diffOne) => { @@ -188,7 +188,7 @@ export function getRawSchema(schema: PlatformSchema | undefined | null, showKeyS } // Get diff summary between two versions and prepare to visualize description diff changes -export function getDiffSummary( +function getDiffSummary( currentVersionRows?: Array, previousVersionRows?: Array, options: { showKeySchema: boolean } = { showKeySchema: false }, diff --git a/datahub-web-react/src/app/entity/dataset/profile/stats/Stats.tsx b/datahub-web-react/src/app/entity/dataset/profile/stats/Stats.tsx deleted file mode 100644 index 73e507ce58c7b1..00000000000000 --- a/datahub-web-react/src/app/entity/dataset/profile/stats/Stats.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { Radio } from 'antd'; -import React, { useState } from 'react'; - -import HistoricalStatsView from '@app/entity/dataset/profile/stats/historical/HistoricalStatsView'; -import LatestStatsView from '@app/entity/dataset/profile/stats/snapshot/LatestStatsView'; - -import { DatasetProfile } from '@types'; - -export type Props = { - urn: string; - profile: DatasetProfile; -}; - -enum ViewType { - LATEST, - HISTORICAL, -} - -export default function Stats({ urn, profile }: Props) { - /** - * Determines which view should be visible: latest or historical. - */ - const [view, setView] = useState(ViewType.LATEST); - - const onChangeView = (e) => { - setView(e.target.value); - }; - - const toggleView = ( - - Latest - Historical - - ); - - return ( - <> - {view === ViewType.LATEST && } - {view === ViewType.HISTORICAL && } - - ); -} diff --git a/datahub-web-react/src/app/entity/dataset/profile/stats/StatsSection.tsx b/datahub-web-react/src/app/entity/dataset/profile/stats/StatsSection.tsx index 32244ee67cc374..b5855f29524e93 100644 --- a/datahub-web-react/src/app/entity/dataset/profile/stats/StatsSection.tsx +++ b/datahub-web-react/src/app/entity/dataset/profile/stats/StatsSection.tsx @@ -14,7 +14,7 @@ const ThinDivider = styled(Divider)` margin-bottom: 8px; `; -export type Props = { +type Props = { children: React.ReactNode; title: string; rightFloatView?: React.ReactNode; diff --git a/datahub-web-react/src/app/entity/dataset/profile/stats/historical/HistoricalStatsView.tsx b/datahub-web-react/src/app/entity/dataset/profile/stats/historical/HistoricalStatsView.tsx deleted file mode 100644 index c1ec9ff63b5c68..00000000000000 --- a/datahub-web-react/src/app/entity/dataset/profile/stats/historical/HistoricalStatsView.tsx +++ /dev/null @@ -1,291 +0,0 @@ -import { Affix, Row, Select, Typography } from 'antd'; -import React, { ReactNode, useEffect, useState } from 'react'; -import styled from 'styled-components'; - -import StatsSection from '@app/entity/dataset/profile/stats/StatsSection'; -import ProfilingRunsChart from '@app/entity/dataset/profile/stats/historical/charts/ProfilingRunsChart'; -import StatChart from '@app/entity/dataset/profile/stats/historical/charts/StatChart'; -import { Message } from '@app/shared/Message'; -import { TimeWindowSize, getFixedLookbackWindow } from '@app/shared/time/timeUtils'; - -import { useGetDataProfilesLazyQuery } from '@graphql/dataset.generated'; -import { DatasetProfile, DateInterval } from '@types'; - -const HeaderRow = styled(Row)` - padding-top: 24px; - padding-bottom: 28px; - background-color: white; -`; - -const SubHeaderText = styled(Typography.Text)` - color: gray; - font-size: 16px; -`; - -const EmbeddedSelect = styled(Select)` - padding-left: 8px; -`; - -const isPresent = (val: any) => { - return val !== undefined && val !== null; -}; - -/** - * Extracts a set of points used to render charts from a list of Dataset Profiles + - * a particular numeric statistic name to extract. Note that the stat *must* be numeric for this utility to work. - */ -const extractChartValuesFromTableProfiles = (profiles: Array, statName: string) => { - return profiles - .filter((profile) => isPresent(profile[statName])) - .map((profile) => ({ - timeMs: profile.timestampMillis, - value: profile[statName] as number, - })); -}; - -/** - * Extracts a set of field-specific points used to render charts from a list of Dataset Profiles + - * a particular numeric statistic name to extract. Note that the stat *must* be numeric for this utility to work. - */ -const extractChartValuesFromFieldProfiles = (profiles: Array, fieldPath: string, statName: string) => { - return profiles - .filter((profile) => profile.fieldProfiles) - .map((profile) => { - const fieldProfiles = profile.fieldProfiles - ?.filter((field) => field.fieldPath === fieldPath) - .filter((field) => field[statName] !== null && field[statName] !== undefined); - - if (fieldProfiles?.length === 1) { - const fieldProfile = fieldProfiles[0]; - return { - timeMs: profile.timestampMillis, - value: fieldProfile[statName], - }; - } - return null; - }) - .filter((value) => value !== null); -}; - -const computeChartTickInterval = (windowSize: TimeWindowSize): DateInterval => { - switch (windowSize.interval) { - case DateInterval.Day: - return DateInterval.Hour; - case DateInterval.Week: - return DateInterval.Day; - case DateInterval.Month: - return DateInterval.Week; - case DateInterval.Year: - return DateInterval.Month; - default: - throw new Error(`Unrecognized DateInterval provided ${windowSize.interval}`); - } -}; - -const computeAllFieldPaths = (profiles: Array): Set => { - const uniqueFieldPaths = new Set(); - profiles.forEach((profile) => { - const fieldProfiles = profile.fieldProfiles || []; - fieldProfiles.forEach((fieldProfile) => { - uniqueFieldPaths.add(fieldProfile.fieldPath); - }); - }); - return uniqueFieldPaths; -}; - -/** - * Change this to add or modify the lookback windows that are selectable via the UI. - */ -const LOOKBACK_WINDOWS = [ - { text: '1 day', windowSize: { interval: DateInterval.Day, count: 1 } }, - { text: '1 week', windowSize: { interval: DateInterval.Week, count: 1 } }, - { text: '1 month', windowSize: { interval: DateInterval.Month, count: 1 } }, - { text: '3 months', windowSize: { interval: DateInterval.Month, count: 3 } }, - { text: '1 year', windowSize: { interval: DateInterval.Year, count: 1 } }, -]; - -const DEFAULT_LOOKBACK_WINDOW = '3 months'; - -const getLookbackWindowSize = (text: string) => { - for (let i = 0; i < LOOKBACK_WINDOWS.length; i++) { - const window = LOOKBACK_WINDOWS[i]; - if (window.text === text) { - return window.windowSize; - } - } - throw new Error(`Unrecognized lookback window size ${text} provided`); -}; - -export type Props = { - urn: string; - toggleView: ReactNode; -}; - -export default function HistoricalStatsView({ urn, toggleView }: Props) { - const [getDataProfiles, { data: profilesData, loading: profilesLoading }] = useGetDataProfilesLazyQuery({ - fetchPolicy: 'cache-first', - }); - - /** - * Perform initial fetch of default lookback window stats. - */ - useEffect(() => { - getDataProfiles({ - variables: { urn, ...getFixedLookbackWindow(getLookbackWindowSize(DEFAULT_LOOKBACK_WINDOW)) }, - }); - }, [urn, getDataProfiles]); - - /** - * Determines which fixed lookback window is used to display historical statistics. See above for valid options. - */ - const [selectedLookbackWindow, setSelectedLookbackWindow] = useState(DEFAULT_LOOKBACK_WINDOW); - const selectedWindowSize = getLookbackWindowSize(selectedLookbackWindow); - const selectedWindow = getFixedLookbackWindow(selectedWindowSize); - - /** - * Determines which field path is highlighted in column stats. Defaults to none. - */ - const [selectedFieldPath, setSelectedFieldPath] = useState(''); - - /** - * Change handlers. - */ - const onChangeSelectedLookbackWindow = (text) => { - const newWindowSize = getLookbackWindowSize(text); - const newTimeWindow = getFixedLookbackWindow(newWindowSize); - getDataProfiles({ - variables: { urn, ...newTimeWindow }, - }); - setSelectedLookbackWindow(text); - }; - - const onChangeSelectedFieldPath = (value) => { - setSelectedFieldPath(value); - }; - - const graphTickInterval = computeChartTickInterval(selectedWindowSize); - const graphDateRange = { - start: selectedWindow.startTime.toString(), - end: selectedWindow.endTime.toString(), - }; - - const profiles = profilesData?.dataset?.datasetProfiles || []; - const allFieldPaths = Array.from(computeAllFieldPaths(profiles)); - - if (selectedFieldPath === '' && allFieldPaths.length > 0) { - // Set initially selected field path. - setSelectedFieldPath(allFieldPaths[0]); - } - - const columnSelectView = ( - - Viewing stats for column - - {allFieldPaths.map((fieldPath) => ( - {fieldPath} - ))} - - - ); - - /** - * Compute Table Stat chart data. - */ - const rowCountChartValues = extractChartValuesFromTableProfiles(profiles, 'rowCount'); - const columnCountChartValues = extractChartValuesFromTableProfiles(profiles, 'columnCount'); - - /** - * Compute Column Stat chart data. - */ - const nullCountChartValues: Array = extractChartValuesFromFieldProfiles( - profiles, - selectedFieldPath, - 'nullCount', - ); - const nullPercentageChartValues: Array = extractChartValuesFromFieldProfiles( - profiles, - selectedFieldPath, - 'nullProportion', - ); - const distinctCountChartValues: Array = extractChartValuesFromFieldProfiles( - profiles, - selectedFieldPath, - 'uniqueCount', - ); - const distinctPercentageChartValues: Array = extractChartValuesFromFieldProfiles( - profiles, - selectedFieldPath, - 'uniqueProportion', - ); - - return ( - <> - {profilesLoading && } - - -
    - Profiling History - - Viewing profiling history for the past - - {LOOKBACK_WINDOWS.map((lookbackWindow) => ( - {lookbackWindow.text} - ))} - - -
    - {toggleView} -
    -
    - - - - - - - - - - - - - - - - - - - - - ); -} diff --git a/datahub-web-react/src/app/entity/dataset/profile/stats/historical/charts/ProfilingRunsChart.tsx b/datahub-web-react/src/app/entity/dataset/profile/stats/historical/charts/ProfilingRunsChart.tsx deleted file mode 100644 index f88454c30756df..00000000000000 --- a/datahub-web-react/src/app/entity/dataset/profile/stats/historical/charts/ProfilingRunsChart.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { Button, Col, Modal, Table, Typography } from 'antd'; -import React, { useState } from 'react'; -import styled from 'styled-components'; - -import DataProfileView from '@app/entity/dataset/profile/stats/snapshot/SnapshotStatsView'; - -import { DatasetProfile } from '@types'; - -export const ChartTable = styled(Table)` - margin: 12px; - box-shadow: ${(props) => props.theme.styles['box-shadow']}; -`; - -export type Props = { - profiles: Array; -}; - -export default function ProfilingRunsChart({ profiles }: Props) { - const [showModal, setShowModal] = useState(false); - const [selectedProfileIndex, setSelectedProfileIndex] = useState(-1); - - const showProfileModal = (index: number) => { - setSelectedProfileIndex(index); - setShowModal(true); - }; - - const onClose = () => { - setShowModal(false); - setSelectedProfileIndex(-1); - }; - - const tableData = profiles.map((profile) => { - const profileDate = new Date(profile.timestampMillis); - return { - timestamp: `${profileDate.toLocaleDateString()} at ${profileDate.toLocaleTimeString()}`, - rowCount: profile.rowCount?.toString() || 'unknown', - columnCount: profile.columnCount?.toString() || 'unknown', - }; - }); - - const tableColumns = [ - { - title: 'Recent Profiles', - key: 'Recent Profiles', - dataIndex: 'timestamp', - render: (title, record, index) => { - return ( - - ); - }, - }, - { - title: 'Row Count', - key: 'Row Count', - dataIndex: 'rowCount', - }, - { - title: 'Column Count', - key: 'Column Count', - dataIndex: 'columnCount', - }, - ]; - - const selectedProfile = (selectedProfileIndex >= 0 && profiles[selectedProfileIndex]) || undefined; - const profileModalTitle = - selectedProfile && - `Showing profile from ${new Date(selectedProfile?.timestampMillis).toLocaleDateString()} at ${new Date( - selectedProfile?.timestampMillis, - ).toLocaleTimeString()}`; - - return ( - <> - {selectedProfile && ( - - - - )} -
- - - - ); -} diff --git a/datahub-web-react/src/app/entity/dataset/profile/stats/historical/charts/StatChart.tsx b/datahub-web-react/src/app/entity/dataset/profile/stats/historical/charts/StatChart.tsx deleted file mode 100644 index 3a8866ad62d651..00000000000000 --- a/datahub-web-react/src/app/entity/dataset/profile/stats/historical/charts/StatChart.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { Col, Divider, Typography } from 'antd'; -import React, { useMemo } from 'react'; -import styled from 'styled-components'; - -import { ChartCard } from '@app/analyticsDashboard/components/ChartCard'; -import { ChartContainer } from '@app/analyticsDashboard/components/ChartContainer'; -import { TimeSeriesChart } from '@app/analyticsDashboard/components/TimeSeriesChart'; - -import { DateInterval, DateRange } from '@types'; - -const ChartTitle = styled(Typography.Title)` - && { - margin-bottom: 20px; - text-align: left; - width: 100%; - } -`; - -const ThinDivider = styled(Divider)` - margin: 0px; - padding: 0px; -`; - -type Point = { - timeMs: number; - value: number; -}; - -export type Props = { - title: string; - values: Array; - tickInterval: DateInterval; - dateRange: DateRange; -}; - -/** - * Change these to change the chart axis & line colors - * TODO: Add this to the theme config. - */ -const DEFAULT_LINE_COLOR = '#20d3bd'; -const DEFAULT_AXIS_COLOR = '#D8D8D8'; -const DEFAULT_AXIS_WIDTH = 2; - -/** - * Time Series Chart with a single line. - */ -export default function StatChart({ title, values, tickInterval: interval, dateRange }: Props) { - const timeSeriesData = useMemo( - () => - values - .sort((a, b) => a.timeMs - b.timeMs) - .map((value) => { - const dateStr = new Date(value.timeMs).toISOString(); - return { - x: dateStr, - y: value.value, - }; - }), - [values], - ); - - const chartData = { - title, - lines: [ - { - name: 'line_1', - data: timeSeriesData, - }, - ], - interval, - dateRange, - }; - - return ( - <> - - - - {chartData.title} - - - - - - - ); -} diff --git a/datahub-web-react/src/app/entity/dataset/profile/stats/snapshot/LatestStatsView.tsx b/datahub-web-react/src/app/entity/dataset/profile/stats/snapshot/LatestStatsView.tsx deleted file mode 100644 index 3b422ca47ce79b..00000000000000 --- a/datahub-web-react/src/app/entity/dataset/profile/stats/snapshot/LatestStatsView.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { Affix, Row, Typography } from 'antd'; -import React, { ReactNode } from 'react'; -import styled from 'styled-components'; - -import DataProfileView from '@app/entity/dataset/profile/stats/snapshot/SnapshotStatsView'; - -import { DatasetProfile } from '@types'; - -const HeaderRow = styled(Row)` - padding-top: 24px; - padding-bottom: 28px; - background-color: white; -`; - -export type Props = { - profile: DatasetProfile; - toggleView: ReactNode; -}; - -export default function LatestStatsView({ profile, toggleView }: Props) { - const reportedAtDate = new Date(profile.timestampMillis); - return ( - <> - - -
- Latest Stats - - Reported on {reportedAtDate.toLocaleDateString()} at {reportedAtDate.toLocaleTimeString()} - -
- {toggleView} -
-
- - - ); -} diff --git a/datahub-web-react/src/app/entity/dataset/profile/stats/snapshot/SnapshotStatsView.tsx b/datahub-web-react/src/app/entity/dataset/profile/stats/snapshot/SnapshotStatsView.tsx index 2b44f340117356..cfe6906d4ccacb 100644 --- a/datahub-web-react/src/app/entity/dataset/profile/stats/snapshot/SnapshotStatsView.tsx +++ b/datahub-web-react/src/app/entity/dataset/profile/stats/snapshot/SnapshotStatsView.tsx @@ -20,7 +20,7 @@ const decimalToPercentStr = (decimal: number, precision: number): string => { return `${(decimal * 100).toFixed(precision)}%`; }; -export type Props = { +type Props = { profile: DatasetProfile; }; diff --git a/datahub-web-react/src/app/entity/dataset/profile/stories/documentation.ts b/datahub-web-react/src/app/entity/dataset/profile/stories/documentation.ts deleted file mode 100644 index 345d33faddfec0..00000000000000 --- a/datahub-web-react/src/app/entity/dataset/profile/stories/documentation.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { EntityType } from '@types'; - -export const sampleDocs = [ - { - url: 'https://www.google.com', - description: 'This doc spans the internet web', - author: { urn: 'urn:li:corpuser:1', username: '1', type: EntityType.CorpUser }, - created: { - time: 0, - actor: 'urn:li:corpuser:1', - }, - }, -]; diff --git a/datahub-web-react/src/app/entity/dataset/profile/stories/lineageEntities.ts b/datahub-web-react/src/app/entity/dataset/profile/stories/lineageEntities.ts index 3583ca1a8e2dc0..a44be98c3dc0a6 100644 --- a/datahub-web-react/src/app/entity/dataset/profile/stories/lineageEntities.ts +++ b/datahub-web-react/src/app/entity/dataset/profile/stories/lineageEntities.ts @@ -1,6 +1,6 @@ import { EntityType, FabricType, PlatformNativeType } from '@types'; -export const sampleUpstreamEntities = [ +const sampleUpstreamEntities = [ { name: 'Upstream HiveDataset', type: EntityType.Dataset, @@ -43,7 +43,7 @@ export const sampleUpstreamEntities = [ }, ]; -export const sampleDownstreamEntities = [ +const sampleDownstreamEntities = [ { name: 'Downstream HiveDataset', type: EntityType.Dataset, diff --git a/datahub-web-react/src/app/entity/dataset/profile/stories/sampleSchema.ts b/datahub-web-react/src/app/entity/dataset/profile/stories/sampleSchema.ts index 9ce31ac0469f91..41166a5da7c9eb 100644 --- a/datahub-web-react/src/app/entity/dataset/profile/stories/sampleSchema.ts +++ b/datahub-web-react/src/app/entity/dataset/profile/stories/sampleSchema.ts @@ -3,11 +3,11 @@ import { dataset3 } from '@src/Mocks'; import { EntityType, Schema, SchemaField, SchemaFieldDataType, SchemaMetadata } from '@types'; // Extending the schema type with an option for tags -export type TaggedSchemaField = { +type TaggedSchemaField = { tags: Tag[]; } & SchemaField; -export type Tag = { +type Tag = { name: string; value?: string; color: string; diff --git a/datahub-web-react/src/app/entity/domain/DataProductsTab/CreateDataProductModal.tsx b/datahub-web-react/src/app/entity/domain/DataProductsTab/CreateDataProductModal.tsx deleted file mode 100644 index 97e922c65e535c..00000000000000 --- a/datahub-web-react/src/app/entity/domain/DataProductsTab/CreateDataProductModal.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { Button, Modal, message } from 'antd'; -import React, { useState } from 'react'; - -import DataProductBuilderForm from '@app/entity/domain/DataProductsTab/DataProductBuilderForm'; -import { DataProductBuilderState } from '@app/entity/domain/DataProductsTab/types'; - -import { useCreateDataProductMutation } from '@graphql/dataProduct.generated'; -import { DataProduct, Domain } from '@types'; - -export const MODAL_WIDTH = '75vw'; - -export const MODAL_BODY_STYLE = { - overflow: 'auto', - width: '80vw', - maxWidth: 800, -}; - -const DEFAULT_STATE = { - name: '', -}; - -type Props = { - domain: Domain; - onClose: () => void; - onCreateDataProduct: (dataProduct: DataProduct) => void; -}; - -export default function CreateDataProductModal({ domain, onCreateDataProduct, onClose }: Props) { - const [builderState, updateBuilderState] = useState(DEFAULT_STATE); - const [createDataProductMutation] = useCreateDataProductMutation(); - - function createDataProduct() { - createDataProductMutation({ - variables: { - input: { - domainUrn: domain.urn, - id: builderState.id, - properties: { - name: builderState.name, - description: builderState.description || undefined, - }, - }, - }, - }) - .then(({ data, errors }) => { - if (!errors) { - message.success('Created Data Product!'); - if (data?.createDataProduct) { - const updateDataProduct = { ...data.createDataProduct, domain: { domain } }; - onCreateDataProduct(updateDataProduct as DataProduct); - } - onClose(); - } - }) - .catch((error) => { - onClose(); - message.destroy(); - message.error({ content: `Failed to create Data Product: ${error.message}.` }); - }); - } - - return ( - - - - - } - > - - - ); -} diff --git a/datahub-web-react/src/app/entity/domain/DataProductsTab/DataProductAdvancedOption.tsx b/datahub-web-react/src/app/entity/domain/DataProductsTab/DataProductAdvancedOption.tsx deleted file mode 100644 index 70907084ee7934..00000000000000 --- a/datahub-web-react/src/app/entity/domain/DataProductsTab/DataProductAdvancedOption.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { Collapse, Form, Input, Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { DataProductBuilderFormProps } from '@app/entity/domain/DataProductsTab/types'; -import { validateCustomUrnId } from '@app/shared/textUtil'; - -const FormItem = styled(Form.Item)` - .ant-form-item-label { - padding-bottom: 2px; - } -`; - -const FormItemWithMargin = styled(FormItem)` - margin-bottom: 16px; -`; - -const FormItemNoMargin = styled(FormItem)` - margin-bottom: 0; -`; - -const AdvancedLabel = styled(Typography.Text)` - color: #373d44; -`; - -export function DataProductAdvancedOption({ builderState, updateBuilderState }: DataProductBuilderFormProps) { - function updateDataProductId(id: string) { - updateBuilderState({ - ...builderState, - id, - }); - } - - return ( - - Advanced Options} key="1"> - Data Product Id} - help="By default, a random UUID will be generated to uniquely identify this data product. If - you'd like to provide a custom id instead to more easily keep track of this data product, - you may provide it here. Be careful, you cannot easily change the data product id after - creation." - > - ({ - validator(_, value) { - if (value && validateCustomUrnId(value)) { - return Promise.resolve(); - } - return Promise.reject(new Error('Please enter a valid Data product id')); - }, - }), - ]} - > - updateDataProductId(e.target.value)} - /> - - - - - ); -} diff --git a/datahub-web-react/src/app/entity/domain/DataProductsTab/DataProductBuilderForm.tsx b/datahub-web-react/src/app/entity/domain/DataProductsTab/DataProductBuilderForm.tsx deleted file mode 100644 index 758942bf9366eb..00000000000000 --- a/datahub-web-react/src/app/entity/domain/DataProductsTab/DataProductBuilderForm.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { Form, Input, Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { DataProductAdvancedOption } from '@app/entity/domain/DataProductsTab/DataProductAdvancedOption'; -import { DataProductBuilderFormProps } from '@app/entity/domain/DataProductsTab/types'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { Editor as MarkdownEditor } from '@app/entity/shared/tabs/Documentation/components/editor/Editor'; - -const StyledEditor = styled(MarkdownEditor)` - border: 1px solid ${ANTD_GRAY[4]}; -`; - -export default function DataProductBuilderForm({ builderState, updateBuilderState }: DataProductBuilderFormProps) { - function updateName(name: string) { - updateBuilderState({ - ...builderState, - name, - }); - } - - function updateDescription(description: string) { - updateBuilderState({ - ...builderState, - description, - }); - } - - return ( -
- Name} - required - > - updateName(e.target.value)} - placeholder="Revenue Dashboards" - /> - - Description}> - - - - - ); -} diff --git a/datahub-web-react/src/app/entity/domain/DataProductsTab/DataProductResult.tsx b/datahub-web-react/src/app/entity/domain/DataProductsTab/DataProductResult.tsx deleted file mode 100644 index b0170d7b064753..00000000000000 --- a/datahub-web-react/src/app/entity/domain/DataProductsTab/DataProductResult.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import { DeleteOutlined, EditOutlined } from '@ant-design/icons'; -import { Button, Dropdown, Modal, message } from 'antd'; -import React, { useState } from 'react'; -import styled from 'styled-components'; - -import { PreviewType } from '@app/entity/Entity'; -import EditDataProductModal from '@app/entity/domain/DataProductsTab/EditDataProductModal'; -import { MenuIcon } from '@app/entity/shared/EntityDropdown/EntityDropdown'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useDeleteDataProductMutation } from '@graphql/dataProduct.generated'; -import { DataProduct, EntityType } from '@types'; - -const ResultWrapper = styled.div` - background-color: white; - border-radius: 8px; - max-width: 1200px; - margin: 0 auto 8px auto; - padding: 8px 16px; - display: flex; - width: 100%; -`; - -const StyledButton = styled(Button)` - border: none; - box-shadow: none; - outline: none; - height: 18px; - width: 18px; - padding: 0; - - svg { - height: 14px; - width: 14px; - } -`; - -const ButtonsWrapper = styled.div` - margin-left: 16px; - display: flex; -`; - -const StyledMenuIcon = styled(MenuIcon)` - margin-left: 8px; - height: 18px; - width: 18px; -`; - -const PreviewWrapper = styled.div` - max-width: 94%; - flex: 1; -`; - -const MenuItem = styled.div``; - -interface Props { - dataProduct: DataProduct; - onUpdateDataProduct: (dataProduct: DataProduct) => void; - setDeletedDataProductUrns: React.Dispatch>; -} - -export default function DataProductResult({ dataProduct, onUpdateDataProduct, setDeletedDataProductUrns }: Props) { - const entityRegistry = useEntityRegistry(); - const [isEditModalVisible, setIsEditModalVisible] = useState(false); - const [deleteDataProductMutation] = useDeleteDataProductMutation(); - - function deleteDataProduct() { - deleteDataProductMutation({ variables: { urn: dataProduct.urn } }) - .then(() => { - message.success('Deleted Data Product'); - setDeletedDataProductUrns((currentUrns) => [...currentUrns, dataProduct.urn]); - }) - .catch(() => { - message.destroy(); - message.error({ content: 'Failed to delete Data Product. An unexpected error occurred' }); - }); - } - - function onRemove() { - Modal.confirm({ - title: `Delete ${entityRegistry.getDisplayName(EntityType.DataProduct, dataProduct)}`, - content: `Are you sure you want to delete this Data Product?`, - onOk() { - deleteDataProduct(); - }, - onCancel() {}, - okText: 'Yes', - maskClosable: true, - closable: true, - }); - } - - const items = [ - { - key: '0', - label: ( - -  Delete - - ), - }, - ]; - - return ( - <> - - - {entityRegistry.renderPreview(EntityType.DataProduct, PreviewType.SEARCH, dataProduct)} - - - } onClick={() => setIsEditModalVisible(true)} /> - - - - - - {isEditModalVisible && ( - setIsEditModalVisible(false)} - onUpdateDataProduct={onUpdateDataProduct} - /> - )} - - ); -} diff --git a/datahub-web-react/src/app/entity/domain/DataProductsTab/DataProductsTab.tsx b/datahub-web-react/src/app/entity/domain/DataProductsTab/DataProductsTab.tsx deleted file mode 100644 index 148b5642bbadc5..00000000000000 --- a/datahub-web-react/src/app/entity/domain/DataProductsTab/DataProductsTab.tsx +++ /dev/null @@ -1,165 +0,0 @@ -import { LoadingOutlined, PlusOutlined } from '@ant-design/icons'; -import { Button, Empty, Pagination } from 'antd'; -import * as QueryString from 'query-string'; -import React, { useState } from 'react'; -import { useLocation } from 'react-router'; -import styled from 'styled-components'; - -import { DomainsPaginationContainer } from '@app/domain/DomainsList'; -import CreateDataProductModal from '@app/entity/domain/DataProductsTab/CreateDataProductModal'; -import DataProductResult from '@app/entity/domain/DataProductsTab/DataProductResult'; -import { useEntityData } from '@app/entity/shared/EntityContext'; -import TabToolbar from '@app/entity/shared/components/styled/TabToolbar'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { SearchBar } from '@app/search/SearchBar'; -import { DOMAINS_FILTER_NAME } from '@app/search/utils/constants'; -import { scrollToTop } from '@app/shared/searchUtils'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useGetSearchResultsForMultipleQuery } from '@graphql/search.generated'; -import { DataProduct, Domain, EntityType } from '@types'; - -const DataProductsPaginationWrapper = styled(DomainsPaginationContainer)` - justify-content: center; -`; - -const ResultsWrapper = styled.div` - flex: 1; - background-color: ${ANTD_GRAY[2]}; - padding: 16px; - overflow: auto; -`; - -const StyledLoading = styled(LoadingOutlined)` - font-size: 32px; -`; - -const LoadingWrapper = styled.div` - display: flex; - justify-content: center; - margin-top: 25%; -`; - -const DEFAULT_PAGE_SIZE = 10; - -export default function DataProductsTab() { - const { entityData } = useEntityData(); - const entityRegistry = useEntityRegistry(); - const location = useLocation(); - const params = QueryString.parse(location.search, { arrayFormat: 'comma' }); - const paramsQuery = (params?.query as string) || undefined; - const [query, setQuery] = useState(paramsQuery); - const [page, setPage] = useState(1); - const [isCreateModalVisible, setIsCreateModalVisible] = useState(false); - const [createdDataProducts, setCreatedDataProducts] = useState([]); - const [editedDataProducts, setEditedDataProducts] = useState([]); - const [deletedDataProductUrns, setDeletedDataProductUrns] = useState([]); - - const start = (page - 1) * DEFAULT_PAGE_SIZE; - const domainUrn = entityData?.urn || ''; - - const { data, loading } = useGetSearchResultsForMultipleQuery({ - skip: !domainUrn, - variables: { - input: { - types: [EntityType.DataProduct], - query: query || '', - start, - count: DEFAULT_PAGE_SIZE, - orFilters: [{ and: [{ field: DOMAINS_FILTER_NAME, values: [domainUrn] }] }], - searchFlags: { skipCache: true }, - }, - }, - fetchPolicy: 'no-cache', - }); - const totalResults = data?.searchAcrossEntities?.total || 0; - const searchResults = data?.searchAcrossEntities?.searchResults?.map((r) => r.entity) || []; - const dataProducts = [...createdDataProducts, ...searchResults]; - const displayedDataProducts = dataProducts - .map( - (dataProduct) => - editedDataProducts.find((editedDataProduct) => editedDataProduct.urn === dataProduct.urn) || - dataProduct, - ) - .filter((dataProduct) => !deletedDataProductUrns.includes(dataProduct.urn)); - - const onChangePage = (newPage: number) => { - scrollToTop(); - setPage(newPage); - }; - - function onCreateDataProduct(dataProduct: DataProduct) { - setCreatedDataProducts([dataProduct, ...createdDataProducts]); - } - - function onUpdateDataProduct(dataProduct: DataProduct) { - setEditedDataProducts([dataProduct, ...editedDataProducts]); - } - - return ( - <> - - - null} - onQueryChange={(q) => setQuery(q && q.length > 0 ? q : undefined)} - entityRegistry={entityRegistry} - hideRecommendations - /> - - - {!loading && !displayedDataProducts.length && ( - - )} - {loading && ( - - - - )} - {!loading && - displayedDataProducts.map((dataProduct) => ( - - ))} - - - - - {isCreateModalVisible && ( - setIsCreateModalVisible(false)} - /> - )} - - ); -} diff --git a/datahub-web-react/src/app/entity/domain/DataProductsTab/EditDataProductModal.tsx b/datahub-web-react/src/app/entity/domain/DataProductsTab/EditDataProductModal.tsx deleted file mode 100644 index 57f21a8bcd0724..00000000000000 --- a/datahub-web-react/src/app/entity/domain/DataProductsTab/EditDataProductModal.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { Button, Modal, message } from 'antd'; -import React, { useState } from 'react'; - -import { MODAL_BODY_STYLE, MODAL_WIDTH } from '@app/entity/domain/DataProductsTab/CreateDataProductModal'; -import DataProductBuilderForm from '@app/entity/domain/DataProductsTab/DataProductBuilderForm'; -import { DataProductBuilderState } from '@app/entity/domain/DataProductsTab/types'; - -import { useUpdateDataProductMutation } from '@graphql/dataProduct.generated'; -import { DataProduct } from '@types'; - -type Props = { - dataProduct: DataProduct; - onClose: () => void; - onUpdateDataProduct: (dataProduct: DataProduct) => void; -}; - -export default function EditDataProductModal({ dataProduct, onUpdateDataProduct, onClose }: Props) { - const [builderState, updateBuilderState] = useState({ - name: dataProduct.properties?.name || '', - description: dataProduct.properties?.description || '', - }); - const [updateDataProductMutation] = useUpdateDataProductMutation(); - - function updateDataProduct() { - updateDataProductMutation({ - variables: { - urn: dataProduct.urn, - input: { - name: builderState.name, - description: builderState.description || undefined, - }, - }, - }) - .then(({ data, errors }) => { - if (!errors) { - message.success('Updates Data Product!'); - if (data?.updateDataProduct) { - onUpdateDataProduct(data.updateDataProduct as DataProduct); - } - onClose(); - } - }) - .catch(() => { - onClose(); - message.destroy(); - message.error({ content: 'Failed to update Data Product. An unexpected error occurred' }); - }); - } - - return ( - - - - - } - > - - - ); -} diff --git a/datahub-web-react/src/app/entity/domain/DataProductsTab/types.ts b/datahub-web-react/src/app/entity/domain/DataProductsTab/types.ts deleted file mode 100644 index 2015b97f1433b7..00000000000000 --- a/datahub-web-react/src/app/entity/domain/DataProductsTab/types.ts +++ /dev/null @@ -1,10 +0,0 @@ -export type DataProductBuilderState = { - name: string; - id?: string; - description?: string; -}; - -export type DataProductBuilderFormProps = { - builderState: DataProductBuilderState; - updateBuilderState: (newState: DataProductBuilderState) => void; -}; diff --git a/datahub-web-react/src/app/entity/domain/DomainEntitiesTab.tsx b/datahub-web-react/src/app/entity/domain/DomainEntitiesTab.tsx deleted file mode 100644 index 213f407d4e6d5f..00000000000000 --- a/datahub-web-react/src/app/entity/domain/DomainEntitiesTab.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { EmbeddedListSearchSection } from '@app/entity/shared/components/styled/search/EmbeddedListSearchSection'; -import { UnionType } from '@app/search/utils/constants'; - -import { EntityType } from '@types'; - -export const DomainEntitiesTab = () => { - const { urn, entityType } = useEntityData(); - - let fixedFilter; - // Set a fixed filter corresponding to the current entity urn. - if (entityType === EntityType.Domain) { - fixedFilter = { - field: 'domains', - values: [urn], - }; - } - - return ( - - ); -}; diff --git a/datahub-web-react/src/app/entity/domain/DomainEntity.tsx b/datahub-web-react/src/app/entity/domain/DomainEntity.tsx deleted file mode 100644 index b20b9f45e0c225..00000000000000 --- a/datahub-web-react/src/app/entity/domain/DomainEntity.tsx +++ /dev/null @@ -1,172 +0,0 @@ -import * as React from 'react'; - -import DomainIcon from '@app/domain/DomainIcon'; -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import DataProductsTab from '@app/entity/domain/DataProductsTab/DataProductsTab'; -import { DomainEntitiesTab } from '@app/entity/domain/DomainEntitiesTab'; -import { Preview } from '@app/entity/domain/preview/Preview'; -import { EntityMenuItems } from '@app/entity/shared/EntityDropdown/EntityDropdown'; -import { EntityProfileTab } from '@app/entity/shared/constants'; -import { EntityProfile } from '@app/entity/shared/containers/profile/EntityProfile'; -import { SidebarAboutSection } from '@app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import { SidebarOwnerSection } from '@app/entity/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import SidebarStructuredPropsSection from '@app/entity/shared/containers/profile/sidebar/StructuredProperties/SidebarStructuredPropsSection'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { EntityActionItem } from '@app/entity/shared/entity/EntityActions'; -import { DocumentationTab } from '@app/entity/shared/tabs/Documentation/DocumentationTab'; -import { PropertiesTab } from '@app/entity/shared/tabs/Properties/PropertiesTab'; - -import { useGetDomainQuery } from '@graphql/domain.generated'; -import { Domain, EntityType, SearchResult } from '@types'; - -/** - * Definition of the DataHub Domain entity. - */ -export class DomainEntity implements Entity { - type: EntityType = EntityType.Domain; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - if (styleType === IconStyleType.SVG) { - return ( - - ); - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => false; - - isLineageEnabled = () => false; - - getAutoCompleteFieldName = () => 'name'; - - getGraphName = () => 'domain'; - - getPathName = () => 'domain'; - - getEntityName = () => 'Domain'; - - getCollectionName = () => 'Domains'; - - useEntityQuery = useGetDomainQuery; - - renderProfile = (urn: string) => ( - - ); - - getSidebarSections = () => [ - { - component: SidebarAboutSection, - }, - { - component: SidebarOwnerSection, - }, - { - component: SidebarStructuredPropsSection, - }, - ]; - - renderPreview = (_: PreviewType, data: Domain) => { - return ( - - ); - }; - - renderSearch = (result: SearchResult) => { - const data = result.entity as Domain; - return ( - - ); - }; - - displayName = (data: Domain) => { - return data?.properties?.name || data?.id || data.urn; - }; - - getOverridePropertiesFromEntity = (data: Domain) => { - return { - name: data.properties?.name, - }; - }; - - getGenericEntityProperties = (data: Domain) => { - return getDataForEntityType({ - data, - entityType: this.type, - getOverrideProperties: this.getOverridePropertiesFromEntity, - }); - }; - - supportedCapabilities = () => { - // TODO.. Determine whether SOFT_DELETE should go into here. - return new Set([EntityCapabilityType.OWNERS]); - }; -} diff --git a/datahub-web-react/src/app/entity/domain/preview/DomainEntitiesSnippet.tsx b/datahub-web-react/src/app/entity/domain/preview/DomainEntitiesSnippet.tsx deleted file mode 100644 index 2d46e05db3743b..00000000000000 --- a/datahub-web-react/src/app/entity/domain/preview/DomainEntitiesSnippet.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { DatabaseOutlined, FileDoneOutlined } from '@ant-design/icons'; -import { VerticalDivider } from '@remirror/react'; -import React from 'react'; -import styled from 'styled-components'; - -import DomainIcon from '@app/domain/DomainIcon'; -import { ANTD_GRAY_V2 } from '@app/entity/shared/constants'; -import { pluralize } from '@app/shared/textUtil'; -import { useHoverEntityTooltipContext } from '@src/app/recommendations/HoverEntityTooltipContext'; - -import { SearchResultFields_Domain_Fragment } from '@graphql/search.generated'; - -const Wrapper = styled.div` - color: ${ANTD_GRAY_V2[8]}; - font-size: 12px; - display: flex; - align-items: center; - line-height: 20px; - - svg { - margin-right: 4px; - } -`; - -const StyledDivider = styled(VerticalDivider)` - &&& { - margin: 0 8px; - } -`; - -interface Props { - domain: SearchResultFields_Domain_Fragment; -} - -export default function DomainEntitiesSnippet({ domain }: Props) { - const { entityCount } = useHoverEntityTooltipContext(); - const subDomainCount = domain.children?.total || 0; - const dataProductCount = domain.dataProducts?.total || 0; - - return ( - - {!!entityCount && ( - <> - {entityCount} {entityCount === 1 ? 'entity' : 'entities'} - - - )} - {subDomainCount} {pluralize(subDomainCount, 'sub-domain')} - - {dataProductCount} {pluralize(dataProductCount, 'data product')} - - ); -} diff --git a/datahub-web-react/src/app/entity/domain/preview/Preview.tsx b/datahub-web-react/src/app/entity/domain/preview/Preview.tsx deleted file mode 100644 index 01d6e7c90c8de8..00000000000000 --- a/datahub-web-react/src/app/entity/domain/preview/Preview.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import React from 'react'; - -import DomainIcon from '@app/domain/DomainIcon'; -import DomainEntitiesSnippet from '@app/entity/domain/preview/DomainEntitiesSnippet'; -import DefaultPreviewCard from '@app/preview/DefaultPreviewCard'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { Domain, EntityType, Owner, SearchInsight } from '@types'; - -export const Preview = ({ - domain, - urn, - name, - description, - owners, - insights, - logoComponent, -}: { - domain: Domain; - urn: string; - name: string; - description?: string | null; - owners?: Array | null; - insights?: Array | null; - logoComponent?: JSX.Element; -}): JSX.Element => { - const entityRegistry = useEntityRegistry(); - return ( - - } - owners={owners} - insights={insights} - logoComponent={logoComponent} - parentEntities={domain.parentDomains?.domains} - snippet={} - /> - ); -}; diff --git a/datahub-web-react/src/app/entity/ermodelrelationships/ERModelRelationshipEntity.tsx b/datahub-web-react/src/app/entity/ermodelrelationships/ERModelRelationshipEntity.tsx deleted file mode 100644 index d2217acebc57be..00000000000000 --- a/datahub-web-react/src/app/entity/ermodelrelationships/ERModelRelationshipEntity.tsx +++ /dev/null @@ -1,157 +0,0 @@ -import '@app/entity/ermodelrelationships/preview/ERModelRelationshipAction.less'; - -import { DatabaseFilled, DatabaseOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { ERModelRelationshipPreviewCard } from '@app/entity/ermodelrelationships/preview/ERModelRelationshipPreviewCard'; -import ERModelRelationshipSidebarCardinality from '@app/entity/ermodelrelationships/profile/sidebar/ERModelRelationshipSidebarCardinality'; -import { EntityProfile } from '@app/entity/shared/containers/profile/EntityProfile'; -import { SidebarAboutSection } from '@app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import { SidebarOwnerSection } from '@app/entity/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import { SidebarTagsSection } from '@app/entity/shared/containers/profile/sidebar/SidebarTagsSection'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { DocumentationTab } from '@app/entity/shared/tabs/Documentation/DocumentationTab'; -import { ERModelRelationshipTab } from '@app/entity/shared/tabs/ERModelRelationship/ERModelRelationshipTab'; -import { PropertiesTab } from '@app/entity/shared/tabs/Properties/PropertiesTab'; -import { GenericEntityProperties } from '@app/entity/shared/types'; - -import { - useGetErModelRelationshipQuery, - useUpdateErModelRelationshipMutation, -} from '@graphql/ermodelrelationship.generated'; -import { EntityType, ErModelRelationship, OwnershipType, SearchResult } from '@types'; - -import ermodelrelationshipIcon from '@images/ermodelrelationshipIcon.svg'; - -/** - * Definition of the DataHub ErModelRelationship entity. - */ - -export class ERModelRelationshipEntity implements Entity { - type: EntityType = EntityType.ErModelRelationship; - - icon = (fontSize: number, styleType: IconStyleType) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - if (styleType === IconStyleType.SVG) { - return ( - - ); - } - - return ; - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => false; - - isLineageEnabled = () => false; - - getAutoCompleteFieldName = () => 'name'; - - getPathName = () => 'erModelRelationship'; - - getCollectionName = () => 'ER Model Relationships'; - - getEntityName = () => 'ER-Model-Relationship'; - - getGraphName = () => 'erModelRelationship'; - - renderProfile = (urn: string) => ( - - ); - - getOverridePropertiesFromEntity = (_ermodelrelation?: ErModelRelationship | null): GenericEntityProperties => { - return {}; - }; - - renderPreview = (_: PreviewType, data: ErModelRelationship) => { - return ( - <> - - {data.properties?.name || data.editableProperties?.name || ''} - - } - description={data?.editableProperties?.description || ''} - owners={data.ownership?.owners} - glossaryTerms={data?.glossaryTerms || undefined} - globalTags={data?.tags} - cardinality={data?.properties?.cardinality} - /> - - ); - }; - - renderSearch = (result: SearchResult) => { - return this.renderPreview(PreviewType.SEARCH, result.entity as ErModelRelationship); - }; - - displayName = (data: ErModelRelationship) => { - return data.properties?.name || data.editableProperties?.name || data.urn; - }; - - getGenericEntityProperties = (data: ErModelRelationship) => { - return getDataForEntityType({ - data, - entityType: this.type, - getOverrideProperties: this.getOverridePropertiesFromEntity, - }); - }; - - supportedCapabilities = () => { - return new Set([]); - }; -} diff --git a/datahub-web-react/src/app/entity/ermodelrelationships/preview/ERModelRelationshipPreviewCard.tsx b/datahub-web-react/src/app/entity/ermodelrelationships/preview/ERModelRelationshipPreviewCard.tsx deleted file mode 100644 index deecd613e5fe0d..00000000000000 --- a/datahub-web-react/src/app/entity/ermodelrelationships/preview/ERModelRelationshipPreviewCard.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { Card, Collapse } from 'antd'; -import React from 'react'; - -import { IconStyleType } from '@app/entity/Entity'; -import ERModelSidebarPreviewCard from '@app/preview/ERModelSidebarPreviewCard'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { EntityType, ErModelRelationshipCardinality, GlobalTags, GlossaryTerms, Owner } from '@types'; - -import ermodelrelationshipIcon from '@images/ermodelrelationshipIcon.svg'; - -const { Panel } = Collapse; - -export const ERModelRelationshipPreviewCard = ({ - urn, - name, - owners, - description, - globalTags, - glossaryTerms, - cardinality, -}: { - urn: string; - name: string | any; - description: string | any; - globalTags?: GlobalTags | null; - glossaryTerms?: GlossaryTerms | null; - owners?: Array | null; - cardinality?: ErModelRelationshipCardinality | null; -}): JSX.Element => { - const entityRegistry = useEntityRegistry(); - const getERModelRelationHeader = (): JSX.Element => { - return ( -
- - } - tags={globalTags || undefined} - glossaryTerms={glossaryTerms || undefined} - owners={owners} - type={entityRegistry.getEntityName(EntityType.ErModelRelationship)} - typeIcon={entityRegistry.getIcon(EntityType.ErModelRelationship, 14, IconStyleType.ACCENT)} - titleSizePx={18} - cardinality={cardinality} - /> -
- ); - }; - - return ( - <> - - - - - ); -}; diff --git a/datahub-web-react/src/app/entity/glossaryNode/ChildrenTab.tsx b/datahub-web-react/src/app/entity/glossaryNode/ChildrenTab.tsx deleted file mode 100644 index 816d5558acc9d3..00000000000000 --- a/datahub-web-react/src/app/entity/glossaryNode/ChildrenTab.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import { sortGlossaryNodes } from '@app/entity/glossaryNode/utils'; -import { sortGlossaryTerms } from '@app/entity/glossaryTerm/utils'; -import { useEntityData } from '@app/entity/shared/EntityContext'; -import useGlossaryChildren from '@app/entityV2/glossaryNode/useGlossaryChildren'; -import EmptyGlossarySection from '@app/glossary/EmptyGlossarySection'; -import GlossaryEntitiesList from '@app/glossary/GlossaryEntitiesList'; -import { useEntityRegistry } from '@app/useEntityRegistry'; -import Loading from '@src/app/shared/Loading'; - -import { EntityType, GlossaryNode, GlossaryTerm } from '@types'; - -const ChildrenTabWrapper = styled.div` - height: 100%; - overflow: auto; - padding-bottom: 10px; -`; - -const LoadingWrapper = styled.div` - height: 100px; - display: flex; - align-items: center; - justify-content: center; -`; - -function ChildrenTab() { - const { entityData } = useEntityData(); - const entityRegistry = useEntityRegistry(); - const entityUrn = entityData?.urn; - const { scrollRef, data, loading } = useGlossaryChildren({ entityUrn }); - - if (!entityData) return <>; - - const childNodes = data - .filter((child) => child.type === EntityType.GlossaryNode) - .sort((nodeA, nodeB) => sortGlossaryNodes(entityRegistry, nodeA, nodeB)); - const childTerms = data - .filter((child) => child.type === EntityType.GlossaryTerm) - .sort((termA, termB) => sortGlossaryTerms(entityRegistry, termA, termB)); - - const hasTermsOrNodes = !!childNodes?.length || !!childTerms?.length; - - if (hasTermsOrNodes) { - return ( - - - {loading && ( - - - - )} -
- - ); - } - - return ; -} - -export default ChildrenTab; diff --git a/datahub-web-react/src/app/entity/glossaryNode/GlossaryNodeEntity.tsx b/datahub-web-react/src/app/entity/glossaryNode/GlossaryNodeEntity.tsx deleted file mode 100644 index b2e3a3dca0b5ec..00000000000000 --- a/datahub-web-react/src/app/entity/glossaryNode/GlossaryNodeEntity.tsx +++ /dev/null @@ -1,180 +0,0 @@ -import { FolderFilled, FolderOutlined } from '@ant-design/icons'; -import React from 'react'; - -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import ChildrenTab from '@app/entity/glossaryNode/ChildrenTab'; -import { Preview } from '@app/entity/glossaryNode/preview/Preview'; -import { EntityMenuItems } from '@app/entity/shared/EntityDropdown/EntityDropdown'; -import { EntityProfile } from '@app/entity/shared/containers/profile/EntityProfile'; -import { SidebarAboutSection } from '@app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import { SidebarOwnerSection } from '@app/entity/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import SidebarStructuredPropsSection from '@app/entity/shared/containers/profile/sidebar/StructuredProperties/SidebarStructuredPropsSection'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { DocumentationTab } from '@app/entity/shared/tabs/Documentation/DocumentationTab'; -import { PropertiesTab } from '@app/entity/shared/tabs/Properties/PropertiesTab'; -import SummaryTab from '@app/entityV2/summary/SummaryTab'; -import { useShowAssetSummaryPage } from '@app/entityV2/summary/useShowAssetSummaryPage'; - -import { useGetGlossaryNodeQuery } from '@graphql/glossaryNode.generated'; -import { EntityType, GlossaryNode, SearchResult } from '@types'; - -class GlossaryNodeEntity implements Entity { - type: EntityType = EntityType.GlossaryNode; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => false; - - getAutoCompleteFieldName = () => 'name'; - - isLineageEnabled = () => false; - - getPathName = () => 'glossaryNode'; - - getCollectionName = () => 'Term Groups'; - - getEntityName = () => 'Term Group'; - - useEntityQuery = useGetGlossaryNodeQuery; - - renderProfile = (urn: string) => { - return ( - - ); - }; - - getSidebarSections = () => [ - { - component: SidebarAboutSection, - properties: { - hideLinksButton: true, - }, - }, - { - component: SidebarOwnerSection, - }, - { - component: SidebarStructuredPropsSection, - }, - ]; - - getProfileTabs = () => { - const showSummaryTab = useShowAssetSummaryPage(); - - return [ - ...(showSummaryTab - ? [ - { - name: 'Summary', - component: SummaryTab, - }, - ] - : []), - { - name: 'Contents', - component: ChildrenTab, - }, - ...(!showSummaryTab - ? [ - { - name: 'Documentation', - component: DocumentationTab, - properties: { - hideLinksButton: true, - }, - }, - ] - : []), - { - name: 'Properties', - component: PropertiesTab, - }, - ]; - }; - - displayName = (data: GlossaryNode) => { - return data.properties?.name || data.urn; - }; - - getOverridePropertiesFromEntity = (data: GlossaryNode) => { - return { - name: this.displayName(data), - }; - }; - - renderSearch = (result: SearchResult) => { - return this.renderPreview(PreviewType.SEARCH, result.entity as GlossaryNode); - }; - - renderPreview = (_: PreviewType, data: GlossaryNode) => { - return ( - - ); - }; - - platformLogoUrl = (_: GlossaryNode) => { - return undefined; - }; - - getGenericEntityProperties = (glossaryNode: GlossaryNode) => { - return getDataForEntityType({ - data: glossaryNode, - entityType: this.type, - getOverrideProperties: (data) => data, - }); - }; - - supportedCapabilities = () => { - return new Set([ - EntityCapabilityType.OWNERS, - EntityCapabilityType.DEPRECATION, - EntityCapabilityType.SOFT_DELETE, - ]); - }; - - getGraphName = () => this.getPathName(); -} - -export default GlossaryNodeEntity; diff --git a/datahub-web-react/src/app/entity/glossaryNode/preview/Preview.tsx b/datahub-web-react/src/app/entity/glossaryNode/preview/Preview.tsx deleted file mode 100644 index 90fd8bc6e8270d..00000000000000 --- a/datahub-web-react/src/app/entity/glossaryNode/preview/Preview.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { FolderOutlined } from '@ant-design/icons'; -import React from 'react'; - -import DefaultPreviewCard from '@app/preview/DefaultPreviewCard'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { EntityType, Owner, ParentNodesResult } from '@types'; - -export const Preview = ({ - urn, - name, - description, - owners, - parentNodes, -}: { - urn: string; - name: string; - description?: string | null; - owners?: Array | null; - parentNodes?: ParentNodesResult | null; -}): JSX.Element => { - const entityRegistry = useEntityRegistry(); - return ( - } - type={entityRegistry.getEntityName(EntityType.GlossaryNode)} - parentEntities={parentNodes?.nodes} - /> - ); -}; diff --git a/datahub-web-react/src/app/entity/glossaryTerm/GlossaryTermEntity.tsx b/datahub-web-react/src/app/entity/glossaryTerm/GlossaryTermEntity.tsx deleted file mode 100644 index d33836b26ddb5f..00000000000000 --- a/datahub-web-react/src/app/entity/glossaryTerm/GlossaryTermEntity.tsx +++ /dev/null @@ -1,190 +0,0 @@ -import { BookFilled, BookOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { Preview } from '@app/entity/glossaryTerm/preview/Preview'; -import GlossaryRelatedEntity from '@app/entity/glossaryTerm/profile/GlossaryRelatedEntity'; -import GlossayRelatedTerms from '@app/entity/glossaryTerm/profile/GlossaryRelatedTerms'; -import { EntityMenuItems } from '@app/entity/shared/EntityDropdown/EntityDropdown'; -import { EntityProfile } from '@app/entity/shared/containers/profile/EntityProfile'; -import { SidebarAboutSection } from '@app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import { SidebarDomainSection } from '@app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection'; -import { SidebarOwnerSection } from '@app/entity/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import SidebarStructuredPropsSection from '@app/entity/shared/containers/profile/sidebar/StructuredProperties/SidebarStructuredPropsSection'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { EntityActionItem } from '@app/entity/shared/entity/EntityActions'; -import { SchemaTab } from '@app/entity/shared/tabs/Dataset/Schema/SchemaTab'; -import { DocumentationTab } from '@app/entity/shared/tabs/Documentation/DocumentationTab'; -import { PropertiesTab } from '@app/entity/shared/tabs/Properties/PropertiesTab'; -import { GenericEntityProperties } from '@app/entity/shared/types'; -import { PageRoutes } from '@conf/Global'; - -import { GetGlossaryTermQuery, useGetGlossaryTermQuery } from '@graphql/glossaryTerm.generated'; -import { EntityType, GlossaryTerm, SearchResult } from '@types'; - -/** - * Definition of the DataHub Dataset entity. - */ -export class GlossaryTermEntity implements Entity { - type: EntityType = EntityType.GlossaryTerm; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => true; - - getAutoCompleteFieldName = () => 'name'; - - isLineageEnabled = () => false; - - getPathName = () => 'glossaryTerm'; - - getCollectionName = () => 'Glossary Terms'; - - getEntityName = () => 'Glossary Term'; - - useEntityQuery = useGetGlossaryTermQuery; - - getCustomCardUrlPath = () => PageRoutes.GLOSSARY; - - renderProfile = (urn) => { - return ( - - glossaryTerm?.glossaryTerm?.schemaMetadata !== null, - enabled: (_, glossaryTerm: GetGlossaryTermQuery) => - glossaryTerm?.glossaryTerm?.schemaMetadata !== null, - }, - }, - { - name: 'Related Terms', - component: GlossayRelatedTerms, - }, - { - name: 'Properties', - component: PropertiesTab, - }, - ]} - sidebarSections={this.getSidebarSections()} - getOverrideProperties={this.getOverridePropertiesFromEntity} - /> - ); - }; - - getSidebarSections = () => [ - { - component: SidebarAboutSection, - }, - { - component: SidebarOwnerSection, - }, - { - component: SidebarDomainSection, - properties: { - hideOwnerType: true, - }, - }, - { - component: SidebarStructuredPropsSection, - }, - ]; - - getOverridePropertiesFromEntity = (glossaryTerm?: GlossaryTerm | null): GenericEntityProperties => { - // if dataset has subTypes filled out, pick the most specific subtype and return it - return { - customProperties: glossaryTerm?.properties?.customProperties, - }; - }; - - renderSearch = (result: SearchResult) => { - return this.renderPreview(PreviewType.SEARCH, result.entity as GlossaryTerm); - }; - - renderPreview = (previewType: PreviewType, data: GlossaryTerm) => { - return ( - - ); - }; - - displayName = (data: GlossaryTerm) => { - return data.properties?.name || data.name || data.urn; - }; - - platformLogoUrl = (_: GlossaryTerm) => { - return undefined; - }; - - getGenericEntityProperties = (glossaryTerm: GlossaryTerm) => { - return getDataForEntityType({ - data: glossaryTerm, - entityType: this.type, - getOverrideProperties: (data) => data, - }); - }; - - supportedCapabilities = () => { - return new Set([ - EntityCapabilityType.OWNERS, - EntityCapabilityType.DEPRECATION, - EntityCapabilityType.SOFT_DELETE, - ]); - }; - - getGraphName = () => this.getPathName(); -} diff --git a/datahub-web-react/src/app/entity/glossaryTerm/profile/GlossaryRelatedEntity.tsx b/datahub-web-react/src/app/entity/glossaryTerm/profile/GlossaryRelatedEntity.tsx deleted file mode 100644 index 2dd49439b90d1a..00000000000000 --- a/datahub-web-react/src/app/entity/glossaryTerm/profile/GlossaryRelatedEntity.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import * as React from 'react'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { EmbeddedListSearchSection } from '@app/entity/shared/components/styled/search/EmbeddedListSearchSection'; -import { UnionType } from '@app/search/utils/constants'; - -export default function GlossaryRelatedEntity() { - const { entityData } = useEntityData(); - - const entityUrn = entityData?.urn; - - const fixedOrFilters = - (entityUrn && [ - { - field: 'glossaryTerms', - values: [entityUrn], - }, - { - field: 'fieldGlossaryTerms', - values: [entityUrn], - }, - ]) || - []; - - entityData?.isAChildren?.relationships?.forEach((term) => { - const childUrn = term.entity?.urn; - - if (childUrn) { - fixedOrFilters.push({ - field: 'glossaryTerms', - values: [childUrn], - }); - - fixedOrFilters.push({ - field: 'fieldGlossaryTerms', - values: [childUrn], - }); - } - }); - - return ( - - ); -} diff --git a/datahub-web-react/src/app/entity/glossaryTerm/profile/GlossaryRelatedTermsResult.tsx b/datahub-web-react/src/app/entity/glossaryTerm/profile/GlossaryRelatedTermsResult.tsx index 52a08e44bb56bc..1538445abedd32 100644 --- a/datahub-web-react/src/app/entity/glossaryTerm/profile/GlossaryRelatedTermsResult.tsx +++ b/datahub-web-react/src/app/entity/glossaryTerm/profile/GlossaryRelatedTermsResult.tsx @@ -19,7 +19,7 @@ export enum RelatedTermTypes { isAChildren = 'Inherited by', } -export type Props = { +type Props = { glossaryRelatedTermType: string; glossaryRelatedTermResult: Array; }; diff --git a/datahub-web-react/src/app/entity/glossaryTerm/profile/GlossarySidebarAboutSection.tsx b/datahub-web-react/src/app/entity/glossaryTerm/profile/GlossarySidebarAboutSection.tsx deleted file mode 100644 index 0565cbf95b70ef..00000000000000 --- a/datahub-web-react/src/app/entity/glossaryTerm/profile/GlossarySidebarAboutSection.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { useEntityData, useRouteToTab } from '@app/entity/shared/EntityContext'; -import StripMarkdownText from '@app/entity/shared/components/styled/StripMarkdownText'; -import { SidebarHeader } from '@app/entity/shared/containers/profile/sidebar/SidebarHeader'; - -const DescriptionTypography = styled(Typography.Paragraph)` - max-width: 65ch; -`; - -export default function GlossarySidebarAboutSection() { - const { entityData }: any = useEntityData(); - const description = entityData?.glossaryTermInfo?.definition; - const source = entityData?.glossaryTermInfo?.sourceRef; - const sourceUrl = entityData?.glossaryTermInfo?.sourceUrl; - const routeToTab = useRouteToTab(); - - return ( -
- - {description && ( - - routeToTab({ tabName: 'Documentation' })}> - Read More - - } - > - {description} - - - )} - - - {source && ( - - {sourceUrl ? ( - - {source} - - ) : ( - { - source, - } - )} - - )} -
- ); -} diff --git a/datahub-web-react/src/app/entity/glossaryTerm/profile/SchemaView.tsx b/datahub-web-react/src/app/entity/glossaryTerm/profile/SchemaView.tsx deleted file mode 100644 index e004c9d1c597a3..00000000000000 --- a/datahub-web-react/src/app/entity/glossaryTerm/profile/SchemaView.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { Empty, Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -export type Props = { - rawSchema: string | null; -}; - -const Content = styled.div` - margin-left: 32px; - flex-grow: 1; -`; - -export default function SchemaView({ rawSchema }: Props) { - return ( - <> - {rawSchema && rawSchema.length > 0 ? ( - -
-                        {rawSchema}
-                    
-
- ) : ( - - - - )} - - ); -} diff --git a/datahub-web-react/src/app/entity/group/EditGroupDescriptionModal.tsx b/datahub-web-react/src/app/entity/group/EditGroupDescriptionModal.tsx deleted file mode 100644 index e477588c373c32..00000000000000 --- a/datahub-web-react/src/app/entity/group/EditGroupDescriptionModal.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { Button, Form, Modal } from 'antd'; -import React, { useState } from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { Editor } from '@app/entity/shared/tabs/Documentation/components/editor/Editor'; - -type Props = { - onClose: () => void; - onSaveAboutMe: () => void; - setStagedDescription: (des: string) => void; - stagedDescription: string | undefined; -}; -const StyledEditor = styled(Editor)` - border: 1px solid ${ANTD_GRAY[4]}; -`; - -export default function EditGroupDescriptionModal({ - onClose, - onSaveAboutMe, - setStagedDescription, - stagedDescription, -}: Props) { - const [form] = Form.useForm(); - const [aboutText, setAboutText] = useState(stagedDescription); - - function updateDescription(description: string) { - setAboutText(aboutText); - setStagedDescription(description); - } - - const saveDescription = () => { - onSaveAboutMe(); - onClose(); - }; - - return ( - - - - - } - > -
- -
- -
-
- -
- ); -} diff --git a/datahub-web-react/src/app/entity/group/Group.tsx b/datahub-web-react/src/app/entity/group/Group.tsx deleted file mode 100644 index 26bc5fcc885a01..00000000000000 --- a/datahub-web-react/src/app/entity/group/Group.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { TeamOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, IconStyleType, PreviewType } from '@app/entity/Entity'; -import GroupProfile from '@app/entity/group/GroupProfile'; -import { Preview } from '@app/entity/group/preview/Preview'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; - -import { CorpGroup, EntityType, SearchResult } from '@types'; - -/** - * Definition of the DataHub CorpGroup entity. - */ -export class GroupEntity implements Entity { - type: EntityType = EntityType.CorpGroup; - - // TODO: update icons for UserGroup - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => false; - - isLineageEnabled = () => false; - - getAutoCompleteFieldName = () => 'name'; - - getGraphName: () => string = () => 'corpGroup'; - - getPathName: () => string = () => 'group'; - - getEntityName = () => 'Group'; - - getCollectionName: () => string = () => 'Groups'; - - renderProfile: (urn: string) => JSX.Element = (_) => ; - - renderPreview = (_: PreviewType, data: CorpGroup) => ( - - ); - - renderSearch = (result: SearchResult) => { - return this.renderPreview(PreviewType.SEARCH, result.entity as CorpGroup); - }; - - displayName = (data: CorpGroup) => { - return data.properties?.displayName || data.info?.displayName || data.name || data.urn; - }; - - getGenericEntityProperties = (group: CorpGroup) => { - return getDataForEntityType({ data: group, entityType: this.type, getOverrideProperties: (data) => data }); - }; - - supportedCapabilities = () => { - return new Set([]); - }; -} diff --git a/datahub-web-react/src/app/entity/group/GroupAssets.tsx b/datahub-web-react/src/app/entity/group/GroupAssets.tsx deleted file mode 100644 index 0951cd2a05f56d..00000000000000 --- a/datahub-web-react/src/app/entity/group/GroupAssets.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import { EmbeddedListSearchSection } from '@app/entity/shared/components/styled/search/EmbeddedListSearchSection'; -import { UnionType } from '@app/search/utils/constants'; - -const GroupAssetsWrapper = styled.div` - height: calc(100vh - 114px); -`; - -type Props = { - urn: string; -}; - -export const GroupAssets = ({ urn }: Props) => { - return ( - - - - ); -}; diff --git a/datahub-web-react/src/app/entity/group/GroupEditModal.tsx b/datahub-web-react/src/app/entity/group/GroupEditModal.tsx deleted file mode 100644 index b74c565e017b4b..00000000000000 --- a/datahub-web-react/src/app/entity/group/GroupEditModal.tsx +++ /dev/null @@ -1,150 +0,0 @@ -import { Button, Form, Input, Modal, Typography, message } from 'antd'; -import React, { useEffect, useState } from 'react'; - -import { useEnterKeyListener } from '@app/shared/useEnterKeyListener'; - -import { useUpdateCorpGroupPropertiesMutation } from '@graphql/group.generated'; - -type PropsData = { - email: string | undefined; - slack: string | undefined; - urn: string | undefined; - photoUrl: string | undefined; -}; - -type Props = { - open: boolean; - onClose: () => void; - onSave: () => void; - editModalData: PropsData; -}; -/** Regex Validations */ -export const USER_NAME_REGEX = new RegExp('^[a-zA-Z ]*$'); - -export default function GroupEditModal({ open, onClose, onSave, editModalData }: Props) { - const [updateCorpGroupPropertiesMutation] = useUpdateCorpGroupPropertiesMutation(); - const [form] = Form.useForm(); - - const [saveButtonEnabled, setSaveButtonEnabled] = useState(true); - const [data, setData] = useState({ - slack: editModalData.slack, - email: editModalData.email, - urn: editModalData.urn, - photoUrl: editModalData.photoUrl, - }); - - useEffect(() => { - setData({ ...editModalData }); - }, [editModalData]); - - // save changes function - const onSaveChanges = () => { - updateCorpGroupPropertiesMutation({ - variables: { - urn: editModalData?.urn || '', - input: { - email: data.email, - slack: data.slack, - pictureLink: data.photoUrl, - }, - }, - }) - .then(() => { - message.success({ - content: `Changes saved.`, - duration: 3, - }); - onSave(); // call the refetch function once save - // clear the values from edit profile form - setData({ - email: '', - slack: '', - urn: '', - photoUrl: '', - }); - }) - .catch((e) => { - message.destroy(); - message.error({ content: `Failed to Save changes!: \n ${e.message || ''}`, duration: 3 }); - }); - onClose(); - }; - - // Handle the Enter press - useEnterKeyListener({ - querySelectorToExecuteClick: '#editGroupButton', - }); - - return ( - - - - - } - > -
- setSaveButtonEnabled(form.getFieldsError().some((field) => field.errors.length > 0)) - } - > - Email} - rules={[ - { - type: 'email', - message: 'Please enter valid email', - }, - { whitespace: true }, - { min: 2, max: 50 }, - ]} - hasFeedback - > - setData({ ...data, email: event.target.value })} - /> - - Slack Channel} - rules={[{ whitespace: true }, { min: 2, max: 50 }]} - hasFeedback - > - setData({ ...data, slack: event.target.value })} - /> - - - Image URL} - rules={[{ whitespace: true }, { type: 'url', message: 'not valid url' }]} - hasFeedback - > - setData({ ...data, photoUrl: event.target.value })} - /> - - -
- ); -} diff --git a/datahub-web-react/src/app/entity/group/GroupInfoSideBar.tsx b/datahub-web-react/src/app/entity/group/GroupInfoSideBar.tsx deleted file mode 100644 index b174ef4da216d6..00000000000000 --- a/datahub-web-react/src/app/entity/group/GroupInfoSideBar.tsx +++ /dev/null @@ -1,381 +0,0 @@ -import { EditOutlined, LockOutlined, MailOutlined, SlackOutlined } from '@ant-design/icons'; -import { Button, Col, Divider, Row, Space, Tooltip, Typography, message } from 'antd'; -import React, { useEffect, useState } from 'react'; -import { useHistory, useRouteMatch } from 'react-router-dom'; -import styled from 'styled-components'; - -import { useUserContext } from '@app/context/useUserContext'; -import EditGroupDescriptionModal from '@app/entity/group/EditGroupDescriptionModal'; -import GroupEditModal from '@app/entity/group/GroupEditModal'; -import GroupMembersSideBarSection from '@app/entity/group/GroupMembersSideBarSection'; -import GroupOwnerSideBarSection from '@app/entity/group/GroupOwnerSideBarSection'; -import { - AboutSection, - EditButton, - EmptyValue, - GroupsSection, - SideBar, - SideBarSubSection, - SocialDetails, -} from '@app/entity/shared/SidebarStyledComponents'; -import StripMarkdownText, { removeMarkdown } from '@app/entity/shared/components/styled/StripMarkdownText'; -import { REDESIGN_COLORS } from '@app/entity/shared/constants'; -import { Editor } from '@app/entity/shared/tabs/Documentation/components/editor/Editor'; -import { useBrowserTitle } from '@app/shared/BrowserTabTitleContext'; -import CustomAvatar from '@app/shared/avatar/CustomAvatar'; - -import { useUpdateCorpGroupPropertiesMutation } from '@graphql/group.generated'; -import { useUpdateNameMutation } from '@graphql/mutations.generated'; -import { EntityRelationshipsResult, Ownership } from '@types'; - -type SideBarData = { - photoUrl: string | undefined; - avatarName: string | undefined; - name: string | undefined; - email: string | undefined; - slack: string | undefined; - aboutText: string | undefined; - groupMemberRelationships: EntityRelationshipsResult; - groupOwnerShip: Ownership; - isExternalGroup: boolean; - externalGroupType: string | undefined; - urn: string; -}; - -type Props = { - sideBarData: SideBarData; - refetch: () => Promise; -}; - -const AVATAR_STYLE = { margin: '3px 5px 3px 0px' }; - -const TITLES = { - about: 'About', - members: 'Members ', - editGroup: 'Edit Group', -}; - -const GroupNameHeader = styled(Row)` - font-size: 20px; - line-height: 28px; - color: #262626; - margin: 16px 16px 8px 8px; - display: flex; - align-items: center; - justify-content: center; - min-height: 100px; -`; - -const GroupTitle = styled(Typography.Title)` - max-width: 260px; - word-wrap: break-word; - width: 140px; - - &&& { - margin-bottom: 0; - word-break: break-all; - margin-left: 10px; - } - - .ant-typography-edit { - font-size: 16px; - margin-left: 10px; - } -`; - -const EditIcon = styled(EditOutlined)` - cursor: pointer; - color: ${REDESIGN_COLORS.BLUE}; -`; -const AddNewDescription = styled(Button)` - display: none; - margin: -4px; - width: 140px; -`; - -const StyledViewer = styled(Editor)` - padding-right: 8px; - display: block; - - .remirror-editor.ProseMirror { - padding: 0; - } -`; - -const DescriptionContainer = styled.div` - position: relative; - display: flex; - flex-direction: column; - width: 100%; - text-align:left; - font-weight: normal; - font - min-height: 22px; - - &:hover ${AddNewDescription} { - display: block; - } - & ins.diff { - background-color: #b7eb8f99; - text-decoration: none; - &:hover { - background-color: #b7eb8faa; - } - } - & del.diff { - background-color: #ffa39e99; - text-decoration: line-through; - &: hover { - background-color: #ffa39eaa; - } - } -`; - -const ExpandedActions = styled.div` - height: 10px; -`; -const ReadLessText = styled(Typography.Link)` - margin-right: 4px; -`; - -/** - * Responsible for reading & writing users. - */ -export default function GroupInfoSidebar({ sideBarData, refetch }: Props) { - const { - avatarName, - name, - aboutText, - groupMemberRelationships, - email, - photoUrl, - slack, - urn, - isExternalGroup, - externalGroupType, - groupOwnerShip: ownership, - } = sideBarData; - const [updateCorpGroupPropertiesMutation] = useUpdateCorpGroupPropertiesMutation(); - const { url } = useRouteMatch(); - const history = useHistory(); - - const { updateTitle } = useBrowserTitle(); - - useEffect(() => { - // You can use the title and updateTitle function here - // For example, updating the title when the component mounts - if (name) { - updateTitle(`Group | ${name}`); - } - // // Don't forget to clean up the title when the component unmounts - return () => { - if (name) { - // added to condition for rerendering issue - updateTitle(''); - } - }; - }, [name, updateTitle]); - - /* eslint-disable @typescript-eslint/no-unused-vars */ - const [editGroupModal, showEditGroupModal] = useState(false); - const me = useUserContext(); - const canEditGroup = me?.platformPrivileges?.manageIdentities; - const [groupTitle, setGroupTitle] = useState(name); - const [expanded, setExpanded] = useState(false); - const [isUpdatingDescription, SetIsUpdatingDescription] = useState(false); - const [stagedDescription, setStagedDescription] = useState(aboutText); - - const [updateName] = useUpdateNameMutation(); - const overLimit = removeMarkdown(aboutText || '').length > 80; - const ABBREVIATED_LIMIT = 80; - - useEffect(() => { - setStagedDescription(aboutText); - }, [aboutText]); - - useEffect(() => { - setGroupTitle(groupTitle); - }, [groupTitle]); - - // Update Group Title - // eslint-disable-next-line @typescript-eslint/no-shadow - const handleTitleUpdate = async (name: string) => { - setGroupTitle(name); - await updateName({ variables: { input: { name, urn } } }) - .then(() => { - message.success({ content: 'Name Updated', duration: 2 }); - refetch(); - }) - .catch((e: unknown) => { - message.destroy(); - if (e instanceof Error) { - message.error({ content: `Failed to update name: \n ${e.message || ''}`, duration: 3 }); - } - }); - }; - - const getEditModalData = { - urn, - email, - slack, - photoUrl, - }; - - // About Text save - const onSaveAboutMe = () => { - updateCorpGroupPropertiesMutation({ - variables: { - urn: urn || '', - input: { - description: stagedDescription, - }, - }, - }) - .then(() => { - message.success({ - content: `Changes saved.`, - duration: 3, - }); - refetch(); - }) - .catch((e) => { - message.destroy(); - message.error({ content: `Failed to Save changes!: \n ${e.message || ''}`, duration: 3 }); - }); - }; - return ( - <> - - - -
- - - - - {groupTitle} - - - - {isExternalGroup && ( - - - - )} - - - - - - - {email || } - - - - - - {slack || } - - - - - - {TITLES.about} - - SetIsUpdatingDescription(true)} data-testid="edit-icon" /> - - - - - {(aboutText && expanded) || !overLimit ? ( - <> - {/* Read only viewer for displaying group description */} - - - {overLimit && ( - { - setExpanded(false); - }} - > - Read Less - - )} - - - ) : ( - <> - {/* Display abbreviated description with option to read more */} - - { - setExpanded(true); - }} - > - Read More - - - } - shouldWrap - > - {aboutText} - - - )} - - {/* Modal for updating group description */} - {isUpdatingDescription && ( - { - SetIsUpdatingDescription(false); - setStagedDescription(aboutText); - }} - onSaveAboutMe={onSaveAboutMe} - setStagedDescription={setStagedDescription} - stagedDescription={stagedDescription} - /> - )} - - - - - - - history.replace(`${url}/members`)} - /> - - - {canEditGroup && ( - - - - )} - - {/* Modal */} - showEditGroupModal(false)} - onSave={() => { - refetch(); - }} - editModalData={getEditModalData} - /> - - ); -} diff --git a/datahub-web-react/src/app/entity/group/GroupMembers.tsx b/datahub-web-react/src/app/entity/group/GroupMembers.tsx deleted file mode 100644 index 956c57b154386b..00000000000000 --- a/datahub-web-react/src/app/entity/group/GroupMembers.tsx +++ /dev/null @@ -1,245 +0,0 @@ -import { MoreOutlined, UserAddOutlined, UserDeleteOutlined } from '@ant-design/icons'; -import { Button, Col, Dropdown, Empty, MenuProps, Modal, Pagination, Row, Typography, message } from 'antd'; -import React, { useState } from 'react'; -import { Link } from 'react-router-dom'; -import styled from 'styled-components'; - -import { AddGroupMembersModal } from '@app/entity/group/AddGroupMembersModal'; -import { CustomAvatar } from '@app/shared/avatar'; -import { scrollToTop } from '@app/shared/searchUtils'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useGetAllGroupMembersQuery, useRemoveGroupMembersMutation } from '@graphql/group.generated'; -import { CorpUser, EntityType } from '@types'; - -const ADD_MEMBER_STYLE = { - backGround: '#ffffff', - boxShadow: '0px 2px 6px rgba(0, 0, 0, 0.05)', -}; -const AVATAR_STYLE = { margin: '5px 5px 5px 0' }; - -/** - * Styled Components - */ -const AddMember = styled(Button)` - padding: 13px 13px 30px 30px; - cursor: pointer; - - &&& .anticon.anticon-user-add { - margin-right: 6px; - } -`; - -const AddMemberText = styled(Typography.Text)` - font-family: Manrope; - font-style: normal; - font-weight: 500; - font-size: 12px; - line-height: 20px; -`; - -const MemberNameSection = styled.div` - font-size: 20px; - line-height: 28px; - color: #262626; - display: flex; - align-items: center; - justify-content: start; - padding-left: 12px; -`; - -const GroupMemberWrapper = styled.div` - height: calc(100vh - 217px); - overflow-y: auto; - - & .groupMemberRow { - margin: 0 19px; - } -`; - -const MemberColumn = styled(Col)` - padding: 19px 0 19px 0; - border-bottom: 1px solid #f0f0f0; -`; - -const MemberEditIcon = styled.div` - font-size: 22px; - float: right; -`; - -const Name = styled.span` - font-weight: bold; - font-size: 14px; - line-height: 22px; - color: #262626; - margin-left: 8px; -`; - -const NoGroupMembers = styled(Empty)` - padding: 40px; -`; - -type Props = { - urn: string; - pageSize: number; - isExternalGroup: boolean; - onChangeMembers?: () => void; -}; - -export default function GroupMembers({ urn, pageSize, isExternalGroup, onChangeMembers }: Props) { - const entityRegistry = useEntityRegistry(); - - const [page, setPage] = useState(1); - /* eslint-disable @typescript-eslint/no-unused-vars */ - const [isEditingMembers, setIsEditingMembers] = useState(false); - const start = (page - 1) * pageSize; - const { data: membersData, refetch } = useGetAllGroupMembersQuery({ - variables: { urn, start, count: pageSize }, - }); - const [removeGroupMembersMutation] = useRemoveGroupMembersMutation(); - - const onChangeMembersPage = (newPage: number) => { - scrollToTop(); - setPage(newPage); - }; - - const removeGroupMember = (userUrn: string) => { - removeGroupMembersMutation({ - variables: { - groupUrn: urn, - userUrns: [userUrn], - }, - }) - .then(({ errors }) => { - if (!errors) { - message.success({ content: 'Removed Group Member!', duration: 2 }); - onChangeMembers?.(); - // Hack to deal with eventual consistency - setTimeout(() => { - // Reload the page. - refetch(); - }, 2000); - } - }) - .catch((e) => { - message.destroy(); - message.error({ content: `Failed to remove group member: \n ${e.message || ''}`, duration: 3 }); - }); - }; - - const onClickEditMembers = () => { - setIsEditingMembers(true); - }; - - const onAddMembers = () => { - onChangeMembers?.(); - setTimeout(() => { - // Reload the page. - refetch(); - }, 3000); - }; - - const onRemoveMember = (memberEntity: CorpUser) => { - const memberName = entityRegistry.getDisplayName(EntityType.CorpUser, memberEntity); - Modal.confirm({ - title: `Confirm Group Member Removal`, - content: `Are you sure you want to remove ${memberName} user from the group?`, - onOk() { - removeGroupMember(memberEntity?.urn); - }, - onCancel() {}, - okText: 'Yes', - maskClosable: true, - closable: true, - }); - }; - - const relationships = membersData && membersData.corpGroup?.relationships; - const total = relationships?.total || 0; - const groupMembers = relationships?.relationships?.map((rel) => rel.entity as CorpUser) || []; - - const getItems = (userEntity: CorpUser): MenuProps['items'] => { - return [ - { - key: 'make', - disabled: true, - label: ( - - Make owner - - ), - }, - { - key: 'remove', - disabled: isExternalGroup, - onClick: () => onRemoveMember(userEntity), - label: ( - - Remove from Group - - ), - }, - ]; - }; - - return ( - <> - - - - Add Member - - - - {groupMembers.length === 0 && } - {groupMembers && - groupMembers.map((item) => { - const entityUrn = entityRegistry.getEntityUrl(EntityType.CorpUser, item.urn); - return ( - - - - - - {entityRegistry.getDisplayName(EntityType.CorpUser, item)} - - - - - - - - - - - - ); - })} - - - - - {isEditingMembers && ( - setIsEditingMembers(false)} - /> - )} - - ); -} diff --git a/datahub-web-react/src/app/entity/group/GroupMembersSideBarSection.tsx b/datahub-web-react/src/app/entity/group/GroupMembersSideBarSection.tsx deleted file mode 100644 index 1a7d4465da8a70..00000000000000 --- a/datahub-web-react/src/app/entity/group/GroupMembersSideBarSection.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { Tag, Tooltip } from 'antd'; -import React from 'react'; -import { Link } from 'react-router-dom'; -import styled from 'styled-components'; - -import { - DisplayCount, - EmptyValue, - GroupSectionHeader, - GroupSectionTitle, - GroupsSeeMoreText, - TagsSection, -} from '@app/entity/shared/SidebarStyledComponents'; -import { CustomAvatar } from '@app/shared/avatar'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { CorpUser, EntityRelationship, EntityType } from '@types'; - -const TITLE = 'Members'; - -const MemberTag = styled(Tag)` - padding: 2px; - padding-right: 6px; - margin-bottom: 8px; - display: inline-flex; - align-items: center; -`; - -type Props = { - total: number; - relationships: Array; - onSeeMore: () => void; -}; - -export default function GroupMembersSideBarSection({ total, relationships, onSeeMore }: Props) { - const entityRegistry = useEntityRegistry(); - - return ( - <> - - {TITLE} - {total} - - - {relationships.length === 0 && } - {relationships.length > 0 && - relationships.map((item) => { - const user = item.entity as CorpUser; - const name = entityRegistry.getDisplayName(EntityType.CorpUser, user); - return ( - - - - {name.length > 15 ? ( - {`${name.substring(0, 15)}..`} - ) : ( - {name} - )} - - - ); - })} - {relationships.length > 15 && ( -
- {`+${ - relationships.length - 15 - } more`} -
- )} -
- - ); -} diff --git a/datahub-web-react/src/app/entity/group/GroupOwnerSideBarSection.tsx b/datahub-web-react/src/app/entity/group/GroupOwnerSideBarSection.tsx deleted file mode 100644 index 2ad254adb08274..00000000000000 --- a/datahub-web-react/src/app/entity/group/GroupOwnerSideBarSection.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { PlusOutlined } from '@ant-design/icons'; -import { Button, Typography } from 'antd'; -import React, { useState } from 'react'; -import styled from 'styled-components'; - -import { DisplayCount, GroupSectionHeader, GroupSectionTitle } from '@app/entity/shared/SidebarStyledComponents'; -import { ExpandedOwner } from '@app/entity/shared/components/styled/ExpandedOwner/ExpandedOwner'; -import { EditOwnersModal } from '@app/entity/shared/containers/profile/sidebar/Ownership/EditOwnersModal'; - -import { EntityType, Ownership } from '@types'; - -const TITLE = 'Owners'; - -const SectionWrapper = styled.div``; - -const OwnersWrapper = styled.div` - display: flex; - gap: 6px; - flex-wrap: wrap; - margin-bottom: 8px; -`; - -const AddOwnerButton = styled(Button)``; - -type Props = { - ownership: Ownership; - refetch: () => Promise; - urn: string; -}; - -export default function GroupOwnerSideBarSection({ urn, ownership, refetch }: Props) { - const [showAddModal, setShowAddModal] = useState(false); - const ownersEmpty = !ownership?.owners?.length; - - return ( - <> - - {TITLE} - {ownership?.owners?.length || ''} - - - - {ownership && - ownership?.owners?.map((owner) => ( - - ))} - - {ownersEmpty && ( - No group owners added yet. - )} - {ownersEmpty && ( - setShowAddModal(true)}> - - Add Owners - - )} - {!ownersEmpty && ( - setShowAddModal(true)}> - - Add Owners - - )} - - {showAddModal && ( - { - setShowAddModal(false); - }} - /> - )} - - ); -} diff --git a/datahub-web-react/src/app/entity/group/GroupProfile.tsx b/datahub-web-react/src/app/entity/group/GroupProfile.tsx deleted file mode 100644 index ec41a78f2a5f93..00000000000000 --- a/datahub-web-react/src/app/entity/group/GroupProfile.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import { Col, Row } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { GroupAssets } from '@app/entity/group/GroupAssets'; -import GroupInfoSidebar from '@app/entity/group/GroupInfoSideBar'; -import GroupMembers from '@app/entity/group/GroupMembers'; -import NonExistentEntityPage from '@app/entity/shared/entity/NonExistentEntityPage'; -import { decodeUrn } from '@app/entity/shared/utils'; -import { Message } from '@app/shared/Message'; -import { RoutedTabs } from '@app/shared/RoutedTabs'; -import useUserParams from '@app/shared/entitySearch/routingUtils/useUserParams'; -import { ErrorSection } from '@app/shared/error/ErrorSection'; - -import { useGetGroupQuery } from '@graphql/group.generated'; -import { EntityRelationshipsResult, OriginType, Ownership } from '@types'; - -const messageStyle = { marginTop: '10%' }; - -export enum TabType { - Assets = 'Owner Of', - Members = 'Members', -} - -const ENABLED_TAB_TYPES = [TabType.Assets, TabType.Members]; - -const MEMBER_PAGE_SIZE = 15; - -/** - * Styled Components - */ -const GroupProfileWrapper = styled.div` - &&& .ant-tabs-nav { - margin: 0; - } -`; - -const Content = styled.div` - color: #262626; - height: calc(100vh - 60px); - - &&& .ant-tabs > .ant-tabs-nav .ant-tabs-nav-wrap { - padding-left: 15px; - } -`; - -/** - * Responsible for reading & writing groups. - */ -export default function GroupProfile() { - const { urn: encodedUrn } = useUserParams(); - const urn = encodedUrn && decodeUrn(encodedUrn); - const { loading, error, data, refetch } = useGetGroupQuery({ variables: { urn, membersCount: MEMBER_PAGE_SIZE } }); - - const groupMemberRelationships = data?.corpGroup?.relationships as EntityRelationshipsResult; - const isExternalGroup: boolean = data?.corpGroup?.origin?.type === OriginType.External; - const externalGroupType: string = data?.corpGroup?.origin?.externalType || 'outside DataHub'; - - const getTabs = () => { - return [ - { - name: TabType.Assets, - path: TabType.Assets.toLocaleLowerCase(), - content: , - display: { - enabled: () => true, - }, - }, - { - name: TabType.Members, - path: TabType.Members.toLocaleLowerCase(), - content: ( - { - setTimeout(() => refetch(), 2000); - }} - /> - ), - display: { - enabled: () => true, - }, - }, - ].filter((tab) => ENABLED_TAB_TYPES.includes(tab.name)); - }; - - const defaultTabPath = getTabs() && getTabs()?.length > 0 ? getTabs()[0].path : ''; - const onTabChange = () => null; - - // Side bar data - const sideBarData = { - photoUrl: data?.corpGroup?.editableProperties?.pictureLink || undefined, - avatarName: - data?.corpGroup?.properties?.displayName || - data?.corpGroup?.name || - data?.corpGroup?.info?.displayName || - undefined, - name: - data?.corpGroup?.properties?.displayName || - data?.corpGroup?.name || - data?.corpGroup?.info?.displayName || - undefined, - email: data?.corpGroup?.editableProperties?.email || data?.corpGroup?.properties?.email || undefined, - slack: data?.corpGroup?.editableProperties?.slack || data?.corpGroup?.properties?.slack || undefined, - aboutText: - data?.corpGroup?.editableProperties?.description || data?.corpGroup?.properties?.description || undefined, - groupMemberRelationships: groupMemberRelationships as EntityRelationshipsResult, - groupOwnerShip: data?.corpGroup?.ownership as Ownership, - isExternalGroup, - externalGroupType, - urn, - }; - - if (data?.corpGroup?.exists === false) { - return ; - } - return ( - <> - {error && } - {loading && } - {data && data?.corpGroup && ( - - -
- - - - - - - - - - )} - - ); -} diff --git a/datahub-web-react/src/app/entity/group/preview/Preview.tsx b/datahub-web-react/src/app/entity/group/preview/Preview.tsx deleted file mode 100644 index 3899ceba911bf9..00000000000000 --- a/datahub-web-react/src/app/entity/group/preview/Preview.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import { Tag, Typography } from 'antd'; -import React from 'react'; -import { Link } from 'react-router-dom'; -import styled from 'styled-components'; - -import { IconStyleType } from '@app/entity/Entity'; -import NoMarkdownViewer from '@app/entity/shared/components/styled/StripMarkdownText'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import SearchTextHighlighter from '@app/search/matches/SearchTextHighlighter'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { EntityType } from '@types'; - -const PreviewContainer = styled.div` - margin-bottom: 4px; - display: flex; - width: 100%; - justify-content: space-between; - align-items: center; -`; - -const PlatformInfo = styled.div` - margin-bottom: 8px; - display: flex; - align-items: center; - height: 24px; -`; - -const TitleContainer = styled.div` - margin-bottom: 8px; -`; - -const PreviewImage = styled.div` - max-height: 18px; - width: auto; - object-fit: contain; - margin-right: 10px; - background-color: transparent; -`; - -const EntityTitle = styled(Typography.Text)` - &&& { - margin-bottom: 0; - font-size: 16px; - font-weight: 600; - vertical-align: middle; - } -`; - -const PlatformText = styled(Typography.Text)` - font-size: 12px; - line-height: 20px; - font-weight: 700; - color: ${ANTD_GRAY[7]}; -`; - -const DescriptionContainer = styled.div` - margin-top: 5px; -`; - -const MemberCountContainer = styled.span` - margin-left: 12px; - margin-right: 12px; -`; - -export const Preview = ({ - urn, - name, - description, - membersCount, -}: { - urn: string; - name: string; - description?: string | null; - membersCount?: number; -}): JSX.Element => { - const entityRegistry = useEntityRegistry(); - const url = entityRegistry.getEntityUrl(EntityType.CorpGroup, urn); - - return ( - -
- - - - - {entityRegistry.getIcon(EntityType.CorpGroup, 20, IconStyleType.HIGHLIGHT)} - - {entityRegistry.getEntityName(EntityType.CorpGroup)} - - - {name ? : urn} - - {membersCount} members - - - - - {description && description.length > 0 && ( - - } - > - {description} - - - )} -
-
- ); -}; diff --git a/datahub-web-react/src/app/entity/mlFeature/MLFeatureEntity.tsx b/datahub-web-react/src/app/entity/mlFeature/MLFeatureEntity.tsx deleted file mode 100644 index b6aa4edfe6da40..00000000000000 --- a/datahub-web-react/src/app/entity/mlFeature/MLFeatureEntity.tsx +++ /dev/null @@ -1,217 +0,0 @@ -import { DotChartOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { Preview } from '@app/entity/mlFeature/preview/Preview'; -import { EntityMenuItems } from '@app/entity/shared/EntityDropdown/EntityDropdown'; -import { EntityProfile } from '@app/entity/shared/containers/profile/EntityProfile'; -import { SidebarAboutSection } from '@app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import DataProductSection from '@app/entity/shared/containers/profile/sidebar/DataProduct/DataProductSection'; -import { SidebarDomainSection } from '@app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection'; -import { SidebarOwnerSection } from '@app/entity/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import { SidebarTagsSection } from '@app/entity/shared/containers/profile/sidebar/SidebarTagsSection'; -import SidebarStructuredPropsSection from '@app/entity/shared/containers/profile/sidebar/StructuredProperties/SidebarStructuredPropsSection'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { DocumentationTab } from '@app/entity/shared/tabs/Documentation/DocumentationTab'; -import { IncidentTab } from '@app/entity/shared/tabs/Incident/IncidentTab'; -import { LineageTab } from '@app/entity/shared/tabs/Lineage/LineageTab'; -import { FeatureTableTab } from '@app/entity/shared/tabs/ML/MlFeatureFeatureTableTab'; -import { PropertiesTab } from '@app/entity/shared/tabs/Properties/PropertiesTab'; -import { GenericEntityProperties } from '@app/entity/shared/types'; -import { getDataProduct } from '@app/entity/shared/utils'; - -import { useGetMlFeatureQuery } from '@graphql/mlFeature.generated'; -import { EntityType, MlFeature, OwnershipType, SearchResult } from '@types'; - -/** - * Definition of the DataHub MLFeature entity. - */ -export class MLFeatureEntity implements Entity { - type: EntityType = EntityType.Mlfeature; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => false; - - isLineageEnabled = () => true; - - getAutoCompleteFieldName = () => 'name'; - - getGraphName = () => 'mlFeature'; - - getPathName = () => 'features'; - - getEntityName = () => 'Feature'; - - getCollectionName = () => 'Features'; - - useEntityQuery = useGetMlFeatureQuery; - - getOverridePropertiesFromEntity = (feature?: MlFeature | null): GenericEntityProperties => { - return { - // eslint-disable-next-line - platform: feature?.['featureTables']?.relationships?.[0]?.entity?.platform, - }; - }; - - renderProfile = (urn: string) => ( - { - const activeIncidentCount = mlFeature?.mlFeature?.activeIncidents?.total; - return `Incidents${(activeIncidentCount && ` (${activeIncidentCount})`) || ''}`; - }, - }, - ]} - sidebarSections={this.getSidebarSections()} - /> - ); - - getSidebarSections = () => [ - { - component: SidebarAboutSection, - }, - { - component: SidebarOwnerSection, - properties: { - defaultOwnerType: OwnershipType.TechnicalOwner, - }, - }, - { - component: SidebarTagsSection, - properties: { - hasTags: true, - hasTerms: true, - }, - }, - { - component: SidebarDomainSection, - }, - { - component: DataProductSection, - }, - { - component: SidebarStructuredPropsSection, - }, - ]; - - renderPreview = (previewType: PreviewType, data: MlFeature) => { - const genericProperties = this.getGenericEntityProperties(data); - // eslint-disable-next-line - const platform = data?.['featureTables']?.relationships?.[0]?.entity?.platform; - return ( - - ); - }; - - renderSearch = (result: SearchResult) => { - const data = result.entity as MlFeature; - const genericProperties = this.getGenericEntityProperties(data); - // eslint-disable-next-line - const platform = data?.['featureTables']?.relationships?.[0]?.entity?.platform; - return ( - - ); - }; - - displayName = (data: MlFeature) => { - return data.name || data.urn; - }; - - getGenericEntityProperties = (mlFeature: MlFeature) => { - return getDataForEntityType({ - data: mlFeature, - entityType: this.type, - getOverrideProperties: this.getOverridePropertiesFromEntity, - }); - }; - - getLineageVizConfig = (entity: MlFeature) => { - return { - urn: entity.urn, - name: entity.name, - type: EntityType.Mlfeature, - // eslint-disable-next-line - icon: entity?.['featureTables']?.relationships?.[0]?.entity?.platform?.properties?.logoUrl || undefined, - // eslint-disable-next-line - platform: entity?.['featureTables']?.relationships?.[0]?.entity?.platform, - }; - }; - - supportedCapabilities = () => { - return new Set([ - EntityCapabilityType.OWNERS, - EntityCapabilityType.GLOSSARY_TERMS, - EntityCapabilityType.TAGS, - EntityCapabilityType.DOMAINS, - EntityCapabilityType.DEPRECATION, - EntityCapabilityType.SOFT_DELETE, - EntityCapabilityType.DATA_PRODUCTS, - ]); - }; -} diff --git a/datahub-web-react/src/app/entity/mlFeature/preview/Preview.tsx b/datahub-web-react/src/app/entity/mlFeature/preview/Preview.tsx deleted file mode 100644 index 0f5a92deb9168c..00000000000000 --- a/datahub-web-react/src/app/entity/mlFeature/preview/Preview.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react'; - -import { IconStyleType, PreviewType } from '@app/entity/Entity'; -import DefaultPreviewCard from '@app/preview/DefaultPreviewCard'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { DataPlatform, DataProduct, EntityPath, EntityType, Owner } from '@types'; - -export const Preview = ({ - urn, - name, - platformInstanceId, - featureNamespace, - description, - dataProduct, - owners, - platform, - degree, - paths, - previewType, -}: { - urn: string; - name: string; - featureNamespace: string; - platformInstanceId?: string; - description?: string | null; - dataProduct?: DataProduct | null; - owners?: Array | null; - platform?: DataPlatform | null | undefined; - degree?: number; - paths?: EntityPath[]; - previewType: PreviewType; -}): JSX.Element => { - const entityRegistry = useEntityRegistry(); - return ( - - ); -}; diff --git a/datahub-web-react/src/app/entity/mlFeatureTable/MLFeatureTableEntity.tsx b/datahub-web-react/src/app/entity/mlFeatureTable/MLFeatureTableEntity.tsx deleted file mode 100644 index f3639e985935f7..00000000000000 --- a/datahub-web-react/src/app/entity/mlFeatureTable/MLFeatureTableEntity.tsx +++ /dev/null @@ -1,198 +0,0 @@ -import { DotChartOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { Preview } from '@app/entity/mlFeatureTable/preview/Preview'; -import Sources from '@app/entity/mlFeatureTable/profile/Sources'; -import MlFeatureTableFeatures from '@app/entity/mlFeatureTable/profile/features/MlFeatureTableFeatures'; -import { EntityMenuItems } from '@app/entity/shared/EntityDropdown/EntityDropdown'; -import { EntityProfile } from '@app/entity/shared/containers/profile/EntityProfile'; -import { SidebarAboutSection } from '@app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import DataProductSection from '@app/entity/shared/containers/profile/sidebar/DataProduct/DataProductSection'; -import { SidebarDomainSection } from '@app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection'; -import { SidebarOwnerSection } from '@app/entity/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import { SidebarTagsSection } from '@app/entity/shared/containers/profile/sidebar/SidebarTagsSection'; -import SidebarStructuredPropsSection from '@app/entity/shared/containers/profile/sidebar/StructuredProperties/SidebarStructuredPropsSection'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { DocumentationTab } from '@app/entity/shared/tabs/Documentation/DocumentationTab'; -import { PropertiesTab } from '@app/entity/shared/tabs/Properties/PropertiesTab'; -import { GenericEntityProperties } from '@app/entity/shared/types'; -import { getDataProduct } from '@app/entity/shared/utils'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; - -import { useGetMlFeatureTableQuery } from '@graphql/mlFeatureTable.generated'; -import { EntityType, MlFeatureTable, OwnershipType, SearchResult } from '@types'; - -/** - * Definition of the DataHub MLFeatureTable entity. - */ -export class MLFeatureTableEntity implements Entity { - type: EntityType = EntityType.MlfeatureTable; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => true; - - isLineageEnabled = () => true; - - getAutoCompleteFieldName = () => 'name'; - - getGraphName = () => 'mlFeatureTable'; - - getPathName = () => 'featureTables'; - - getEntityName = () => 'Feature Table'; - - getCollectionName = () => 'Feature Tables'; - - getOverridePropertiesFromEntity = (_?: MlFeatureTable | null): GenericEntityProperties => { - return {}; - }; - - useEntityQuery = useGetMlFeatureTableQuery; - - getSidebarSections = () => [ - { - component: SidebarAboutSection, - }, - { - component: SidebarOwnerSection, - properties: { - defaultOwnerType: OwnershipType.TechnicalOwner, - }, - }, - { - component: SidebarTagsSection, - properties: { - hasTags: true, - hasTerms: true, - }, - }, - { - component: SidebarDomainSection, - }, - { - component: DataProductSection, - }, - { - component: SidebarStructuredPropsSection, - }, - ]; - - renderProfile = (urn: string) => ( - - ); - - renderPreview = (_: PreviewType, data: MlFeatureTable) => { - const genericProperties = this.getGenericEntityProperties(data); - return ( - - ); - }; - - renderSearch = (result: SearchResult) => { - const data = result.entity as MlFeatureTable; - const genericProperties = this.getGenericEntityProperties(data); - return ( - - ); - }; - - getLineageVizConfig = (entity: MlFeatureTable) => { - return { - urn: entity.urn, - name: entity.name, - type: EntityType.MlfeatureTable, - icon: entity.platform.properties?.logoUrl || undefined, - platform: entity.platform, - }; - }; - - displayName = (data: MlFeatureTable) => { - return data.name || data.urn; - }; - - getGenericEntityProperties = (mlFeatureTable: MlFeatureTable) => { - return getDataForEntityType({ - data: mlFeatureTable, - entityType: this.type, - getOverrideProperties: (data) => data, - }); - }; - - supportedCapabilities = () => { - return new Set([ - EntityCapabilityType.OWNERS, - EntityCapabilityType.GLOSSARY_TERMS, - EntityCapabilityType.TAGS, - EntityCapabilityType.DOMAINS, - EntityCapabilityType.DEPRECATION, - EntityCapabilityType.SOFT_DELETE, - EntityCapabilityType.DATA_PRODUCTS, - ]); - }; -} diff --git a/datahub-web-react/src/app/entity/mlFeatureTable/preview/Preview.tsx b/datahub-web-react/src/app/entity/mlFeatureTable/preview/Preview.tsx deleted file mode 100644 index dcdad78f5a04dd..00000000000000 --- a/datahub-web-react/src/app/entity/mlFeatureTable/preview/Preview.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import React from 'react'; - -import { IconStyleType } from '@app/entity/Entity'; -import DefaultPreviewCard from '@app/preview/DefaultPreviewCard'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { DataProduct, EntityPath, EntityType, Owner } from '@types'; - -export const Preview = ({ - urn, - name, - description, - owners, - logoUrl, - platformName, - dataProduct, - platformInstanceId, - degree, - paths, -}: { - urn: string; - name: string; - description?: string | null; - owners?: Array | null; - logoUrl?: string | null; - platformName?: string | null; - dataProduct?: DataProduct | null; - platformInstanceId?: string; - degree?: number; - paths?: EntityPath[]; -}): JSX.Element => { - const entityRegistry = useEntityRegistry(); - return ( - - ); -}; diff --git a/datahub-web-react/src/app/entity/mlFeatureTable/profile/MLFeatureTableHeader.tsx b/datahub-web-react/src/app/entity/mlFeatureTable/profile/MLFeatureTableHeader.tsx deleted file mode 100644 index 4bfa562c39062f..00000000000000 --- a/datahub-web-react/src/app/entity/mlFeatureTable/profile/MLFeatureTableHeader.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { Image, Row, Space, Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import MarkdownViewer from '@app/entity/shared/components/legacy/MarkdownViewer'; -import CompactContext from '@app/shared/CompactContext'; -import { AvatarsGroup } from '@app/shared/avatar'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { MlFeatureTable } from '@types'; - -const HeaderInfoItem = styled.div` - display: inline-block; - text-align: left; - width: 125px; - vertical-align: top; -`; - -const PlatformName = styled(Typography.Text)` - font-size: 16px; -`; -const PreviewImage = styled(Image)` - max-height: 20px; - padding-top: 3px; - width: auto; - object-fit: contain; -`; - -export type Props = { - mlFeatureTable: MlFeatureTable; -}; - -export default function MLFeatureTableHeader({ mlFeatureTable: { platform, description, ownership } }: Props) { - const entityRegistry = useEntityRegistry(); - const isCompact = React.useContext(CompactContext); - - const platformName = platform.properties?.displayName || capitalizeFirstLetterOnly(platform.name); - - return ( - <> - - - {platform ? ( - -
- - Platform - -
- - {platform.properties?.logoUrl ? ( - - ) : null} - {platformName} - -
- ) : null} -
- - -
- - ); -} diff --git a/datahub-web-react/src/app/entity/mlFeatureTable/profile/Sources.tsx b/datahub-web-react/src/app/entity/mlFeatureTable/profile/Sources.tsx deleted file mode 100644 index 3c21eced46f0dc..00000000000000 --- a/datahub-web-react/src/app/entity/mlFeatureTable/profile/Sources.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { List, Typography } from 'antd'; -import React, { useMemo } from 'react'; -import styled from 'styled-components'; - -import { PreviewType } from '@app/entity/Entity'; -import { useBaseEntity } from '@app/entity/shared/EntityContext'; -import { notEmpty } from '@app/entity/shared/utils'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { GetMlFeatureTableQuery } from '@graphql/mlFeatureTable.generated'; -import { Dataset, EntityType } from '@types'; - -const ViewRawButtonContainer = styled.div` - display: flex; - justify-content: flex-end; -`; - -export default function SourcesView() { - const entityRegistry = useEntityRegistry(); - const baseEntity = useBaseEntity(); - const featureTable = baseEntity?.mlFeatureTable; - - const features = useMemo( - () => - featureTable?.properties && - (featureTable?.properties?.mlFeatures || featureTable?.properties?.mlPrimaryKeys) - ? [ - ...(featureTable?.properties?.mlPrimaryKeys || []), - ...(featureTable?.properties?.mlFeatures || []), - ].filter(notEmpty) - : [], - [featureTable?.properties], - ); - - const sources = useMemo( - () => - features?.reduce((accumulator: Array, feature) => { - if (feature.__typename === 'MLFeature' && feature.properties?.sources) { - // eslint-disable-next-line array-callback-return - feature.properties?.sources?.map((source: Dataset | null) => { - if (source && accumulator.findIndex((dataset) => dataset.urn === source?.urn) === -1) { - accumulator.push(source); - } - }); - } else if (feature.__typename === 'MLPrimaryKey' && feature.properties?.sources) { - // eslint-disable-next-line array-callback-return - feature.properties?.sources?.map((source: Dataset | null) => { - if (source && accumulator.findIndex((dataset) => dataset.urn === source?.urn) === -1) { - accumulator.push(source); - } - }); - } - return accumulator; - }, []), - [features], - ); - - return ( - <> -
- - { - // ToDo: uncomment below these after refactored Lineage to support dynamic entities - /* */ - } - -
- Sources} - renderItem={(item) => ( - - {entityRegistry.renderPreview(item?.type || EntityType.Dataset, PreviewType.PREVIEW, item)} - - )} - /> - - ); -} diff --git a/datahub-web-react/src/app/entity/mlFeatureTable/profile/features/MlFeatureDataTypeIcon.tsx b/datahub-web-react/src/app/entity/mlFeatureTable/profile/features/MlFeatureDataTypeIcon.tsx deleted file mode 100644 index 7f72f206129a4c..00000000000000 --- a/datahub-web-react/src/app/entity/mlFeatureTable/profile/features/MlFeatureDataTypeIcon.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { - AudioOutlined, - ClockCircleOutlined, - FieldBinaryOutlined, - FieldStringOutlined, - FileImageOutlined, - LineChartOutlined, - NumberOutlined, - OrderedListOutlined, - QuestionOutlined, - StopOutlined, - UnorderedListOutlined, - VideoCameraOutlined, -} from '@ant-design/icons'; -import { Tooltip, Typography } from 'antd'; -import React, { FC } from 'react'; -import { VscFileBinary } from 'react-icons/vsc'; -import styled from 'styled-components'; - -import { capitalizeFirstLetter } from '@app/shared/textUtil'; - -import { MlFeatureDataType } from '@types'; - -const TypeIconContainer = styled.div` - display: flex; - flex-direction: column; - justify-content: center; - text-align: center; - margin-top: 2.5px; - width: 70px; -`; - -const TypeSubtitle = styled(Typography.Text)<{ hasicon?: string }>` - font-size: 8px; - text-align: center; - text-transform: uppercase; - ${(props) => (props.hasicon ? '' : 'margin-top: 4px;')} -`; - -const IconSpan = styled.span` - font-size: 18px; -`; - -const DATA_TYPE_ICON_MAP: Record | null; size: number; text: string }> = { - [MlFeatureDataType.Byte]: { - icon: () => ( - - - - ), - size: 18, - text: 'Byte', - }, - [MlFeatureDataType.Time]: { icon: ClockCircleOutlined, size: 18, text: 'Time' }, - [MlFeatureDataType.Set]: { icon: UnorderedListOutlined, size: 18, text: 'Set' }, - [MlFeatureDataType.Unknown]: { icon: QuestionOutlined, size: 16, text: 'Unknown' }, - [MlFeatureDataType.Map]: { icon: UnorderedListOutlined, size: 14, text: 'Map' }, - [MlFeatureDataType.Useless]: { icon: StopOutlined, size: 18, text: 'Useless' }, - [MlFeatureDataType.Nominal]: { icon: NumberOutlined, size: 14, text: 'Nominal' }, - [MlFeatureDataType.Ordinal]: { icon: OrderedListOutlined, size: 18, text: 'Ordinal' }, - [MlFeatureDataType.Binary]: { icon: FieldBinaryOutlined, size: 16, text: 'Binary' }, - [MlFeatureDataType.Count]: { icon: NumberOutlined, size: 14, text: 'Count' }, - [MlFeatureDataType.Interval]: { icon: ClockCircleOutlined, size: 16, text: 'Interval' }, - [MlFeatureDataType.Image]: { icon: FileImageOutlined, size: 16, text: 'Image' }, - [MlFeatureDataType.Video]: { icon: VideoCameraOutlined, size: 16, text: 'Video' }, - [MlFeatureDataType.Audio]: { icon: AudioOutlined, size: 16, text: 'Audio' }, - [MlFeatureDataType.Text]: { icon: FieldStringOutlined, size: 18, text: 'Text' }, - [MlFeatureDataType.Sequence]: { icon: OrderedListOutlined, size: 16, text: 'Sequence' }, - [MlFeatureDataType.Continuous]: { icon: LineChartOutlined, size: 16, text: 'Continuous' }, -}; - -type Props = { - dataType?: MlFeatureDataType; -}; - -export default function MlFeatureDataTypeIcon({ dataType }: Props) { - const { icon: Icon, size, text } = DATA_TYPE_ICON_MAP[dataType || MlFeatureDataType.Unknown]; - - // eslint-disable-next-line react/prop-types - const NativeDataTypeTooltip = ({ children }) => ( - - {children} - - ); - - return ( - - - {Icon && } - - {text} - - - - ); -} diff --git a/datahub-web-react/src/app/entity/mlFeatureTable/profile/features/MlFeatureTableFeatures.tsx b/datahub-web-react/src/app/entity/mlFeatureTable/profile/features/MlFeatureTableFeatures.tsx deleted file mode 100644 index cb7a92a204daf0..00000000000000 --- a/datahub-web-react/src/app/entity/mlFeatureTable/profile/features/MlFeatureTableFeatures.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; - -import TableOfMlFeatures from '@app/entity/mlFeatureTable/profile/features/TableOfMlFeatures'; -import { useBaseEntity } from '@app/entity/shared/EntityContext'; -import { notEmpty } from '@app/entity/shared/utils'; - -import { GetMlFeatureTableQuery } from '@graphql/mlFeatureTable.generated'; -import { MlFeature, MlPrimaryKey } from '@types'; - -export default function MlFeatureTableFeatures() { - const baseEntity = useBaseEntity(); - const featureTable = baseEntity?.mlFeatureTable; - - const features = ( - featureTable?.properties && (featureTable?.properties?.mlFeatures || featureTable?.properties?.mlPrimaryKeys) - ? [ - ...(featureTable?.properties?.mlPrimaryKeys || []), - ...(featureTable?.properties?.mlFeatures || []), - ].filter(notEmpty) - : [] - ) as Array; - - return ; -} diff --git a/datahub-web-react/src/app/entity/mlFeatureTable/profile/features/TableOfMlFeatures.tsx b/datahub-web-react/src/app/entity/mlFeatureTable/profile/features/TableOfMlFeatures.tsx deleted file mode 100644 index 5c8d6a2df2e35f..00000000000000 --- a/datahub-web-react/src/app/entity/mlFeatureTable/profile/features/TableOfMlFeatures.tsx +++ /dev/null @@ -1,161 +0,0 @@ -import { CheckSquareOutlined } from '@ant-design/icons'; -import { Table, Typography } from 'antd'; -import { AlignType } from 'rc-table/lib/interface'; -import React, { useState } from 'react'; -import { Link } from 'react-router-dom'; -import styled from 'styled-components'; - -import SchemaDescriptionField from '@app/entity/dataset/profile/schema/components/SchemaDescriptionField'; -import MlFeatureDataTypeIcon from '@app/entity/mlFeatureTable/profile/features/MlFeatureDataTypeIcon'; -import { useRefetch } from '@app/entity/shared/EntityContext'; -import TagTermGroup from '@app/shared/tags/TagTermGroup'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useUpdateDescriptionMutation } from '@graphql/mutations.generated'; -import { MlFeature, MlFeatureDataType, MlPrimaryKey } from '@types'; - -const FeaturesContainer = styled.div` - margin-bottom: 100px; -`; - -const defaultColumns = [ - { - title: 'Type', - dataIndex: 'dataType', - key: 'dataType', - width: 100, - align: 'left' as AlignType, - render: (dataType: MlFeatureDataType) => { - return ; - }, - }, -]; - -type Props = { - features: Array; -}; - -export default function TableOfMlFeatures({ features }: Props) { - const refetch = useRefetch(); - const [updateDescription] = useUpdateDescriptionMutation(); - const entityRegistry = useEntityRegistry(); - - const [tagHoveredIndex, setTagHoveredIndex] = useState(undefined); - const [expandedRows, setExpandedRows] = useState({}); - - const onTagTermCell = (record: any, rowIndex: number | undefined) => ({ - onMouseEnter: () => { - setTagHoveredIndex(`${record.urn}-${rowIndex}`); - }, - onMouseLeave: () => { - setTagHoveredIndex(undefined); - }, - }); - - const nameColumn = { - title: 'Name', - dataIndex: 'name', - key: 'name', - width: 100, - render: (name: string, feature: MlFeature | MlPrimaryKey) => ( - - {name} - - ), - }; - - const descriptionColumn = { - title: 'Description', - dataIndex: 'description', - key: 'description', - render: (_, feature: MlFeature | MlPrimaryKey, index: number) => ( - { - setExpandedRows((prev) => ({ ...prev, [index]: expanded })); - }} - expanded={!!expandedRows[index]} - description={feature?.editableProperties?.description || feature?.properties?.description || ''} - original={feature?.properties?.description} - isEdited={!!feature?.editableProperties?.description} - onUpdate={(updatedDescription) => - updateDescription({ - variables: { - input: { - description: updatedDescription, - resourceUrn: feature.urn, - }, - }, - }).then(refetch) - } - /> - ), - width: 300, - }; - - const tagColumn = { - width: 125, - title: 'Tags', - dataIndex: 'tags', - key: 'tags', - render: (_, feature: MlFeature | MlPrimaryKey, rowIndex: number) => ( - setTagHoveredIndex(undefined)} - entityUrn={feature.urn} - entityType={feature.type} - refetch={refetch} - /> - ), - onCell: onTagTermCell, - }; - - const termColumn = { - width: 125, - title: 'Terms', - dataIndex: 'glossaryTerms', - key: 'glossaryTerms', - render: (_, feature: MlFeature | MlPrimaryKey, rowIndex: number) => ( - setTagHoveredIndex(undefined)} - entityUrn={feature.urn} - entityType={feature.type} - refetch={refetch} - /> - ), - onCell: onTagTermCell, - }; - - const primaryKeyColumn = { - title: 'Primary Key', - dataIndex: 'primaryKey', - key: 'primaryKey', - render: (_: any, record: MlFeature | MlPrimaryKey) => - record.__typename === 'MLPrimaryKey' ? : null, - width: 50, - }; - - const allColumns = [...defaultColumns, nameColumn, descriptionColumn, tagColumn, termColumn, primaryKeyColumn]; - - return ( - - {features && features.length > 0 && ( -
`${record.dataType}-${record.name}`} - expandable={{ defaultExpandAllRows: true, expandRowByClick: true }} - pagination={false} - /> - )} - - ); -} diff --git a/datahub-web-react/src/app/entity/mlModel/MLModelEntity.tsx b/datahub-web-react/src/app/entity/mlModel/MLModelEntity.tsx deleted file mode 100644 index e9e9d137be9ebb..00000000000000 --- a/datahub-web-react/src/app/entity/mlModel/MLModelEntity.tsx +++ /dev/null @@ -1,184 +0,0 @@ -import { CodeSandboxOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { Preview } from '@app/entity/mlModel/preview/Preview'; -import MLModelGroupsTab from '@app/entity/mlModel/profile/MLModelGroupsTab'; -import MLModelSummary from '@app/entity/mlModel/profile/MLModelSummary'; -import MlModelFeaturesTab from '@app/entity/mlModel/profile/MlModelFeaturesTab'; -import { EntityMenuItems } from '@app/entity/shared/EntityDropdown/EntityDropdown'; -import { EntityProfile } from '@app/entity/shared/containers/profile/EntityProfile'; -import { SidebarAboutSection } from '@app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import DataProductSection from '@app/entity/shared/containers/profile/sidebar/DataProduct/DataProductSection'; -import { SidebarDomainSection } from '@app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection'; -import { SidebarOwnerSection } from '@app/entity/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import { SidebarTagsSection } from '@app/entity/shared/containers/profile/sidebar/SidebarTagsSection'; -import SidebarStructuredPropsSection from '@app/entity/shared/containers/profile/sidebar/StructuredProperties/SidebarStructuredPropsSection'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { DocumentationTab } from '@app/entity/shared/tabs/Documentation/DocumentationTab'; -import { IncidentTab } from '@app/entity/shared/tabs/Incident/IncidentTab'; -import { PropertiesTab } from '@app/entity/shared/tabs/Properties/PropertiesTab'; -import { GenericEntityProperties } from '@app/entity/shared/types'; - -import { useGetMlModelQuery } from '@graphql/mlModel.generated'; -import { EntityType, MlModel, OwnershipType, SearchResult } from '@types'; - -/** - * Definition of the DataHub MlModel entity. - */ -export class MLModelEntity implements Entity { - type: EntityType = EntityType.Mlmodel; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => true; - - isLineageEnabled = () => true; - - getAutoCompleteFieldName = () => 'name'; - - getGraphName = () => 'mlModel'; - - getPathName = () => 'mlModels'; - - getEntityName = () => 'ML Model'; - - getCollectionName = () => 'ML Models'; - - getOverridePropertiesFromEntity = (mlModel?: MlModel | null): GenericEntityProperties => { - return { - externalUrl: mlModel?.properties?.externalUrl, - }; - }; - - useEntityQuery = useGetMlModelQuery; - - getSidebarSections = () => [ - { - component: SidebarAboutSection, - }, - { - component: SidebarOwnerSection, - properties: { - defaultOwnerType: OwnershipType.TechnicalOwner, - }, - }, - { - component: SidebarTagsSection, - properties: { - hasTags: true, - hasTerms: true, - }, - }, - { - component: SidebarDomainSection, - }, - { - component: DataProductSection, - }, - { - component: SidebarStructuredPropsSection, - }, - ]; - - renderProfile = (urn: string) => ( - { - const activeIncidentCount = mlModel?.mlModel?.activeIncidents?.total; - return `Incidents${(activeIncidentCount && ` (${activeIncidentCount})`) || ''}`; - }, - }, - ]} - sidebarSections={this.getSidebarSections()} - /> - ); - - renderPreview = (_: PreviewType, data: MlModel) => { - return ; - }; - - renderSearch = (result: SearchResult) => { - const data = result.entity as MlModel; - return ; - }; - - getLineageVizConfig = (entity: MlModel) => { - return { - urn: entity.urn, - // eslint-disable-next-line @typescript-eslint/dot-notation - name: entity.properties?.['propertiesName'] || entity.name, - type: EntityType.Mlmodel, - icon: entity.platform?.properties?.logoUrl || undefined, - platform: entity.platform, - }; - }; - - displayName = (data: MlModel) => { - return data.properties?.name || data.name || data.urn; - }; - - getGenericEntityProperties = (mlModel: MlModel) => { - return getDataForEntityType({ data: mlModel, entityType: this.type, getOverrideProperties: (data) => data }); - }; - - supportedCapabilities = () => { - return new Set([ - EntityCapabilityType.OWNERS, - EntityCapabilityType.GLOSSARY_TERMS, - EntityCapabilityType.TAGS, - EntityCapabilityType.DOMAINS, - EntityCapabilityType.DEPRECATION, - EntityCapabilityType.SOFT_DELETE, - EntityCapabilityType.DATA_PRODUCTS, - ]); - }; -} diff --git a/datahub-web-react/src/app/entity/mlModel/preview/Preview.tsx b/datahub-web-react/src/app/entity/mlModel/preview/Preview.tsx deleted file mode 100644 index 0ee5698658846c..00000000000000 --- a/datahub-web-react/src/app/entity/mlModel/preview/Preview.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; - -import { IconStyleType } from '@app/entity/Entity'; -import { getDataProduct } from '@app/entity/shared/utils'; -import DefaultPreviewCard from '@app/preview/DefaultPreviewCard'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { EntityPath, EntityType, MlModel } from '@types'; - -export const Preview = ({ - model, - degree, - paths, -}: { - model: MlModel; - degree?: number; - paths?: EntityPath[]; -}): JSX.Element => { - const entityRegistry = useEntityRegistry(); - const genericProperties = entityRegistry.getGenericEntityProperties(EntityType.Mlmodel, model); - - return ( - - ); -}; diff --git a/datahub-web-react/src/app/entity/mlModel/profile/MLModelGroupsTab.tsx b/datahub-web-react/src/app/entity/mlModel/profile/MLModelGroupsTab.tsx deleted file mode 100644 index fda5a50ea42f20..00000000000000 --- a/datahub-web-react/src/app/entity/mlModel/profile/MLModelGroupsTab.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { Space, Table, Typography } from 'antd'; -import { ColumnsType } from 'antd/es/table'; -import Link from 'antd/lib/typography/Link'; -import React from 'react'; -import styled from 'styled-components'; - -import { useBaseEntity } from '@app/entity/shared/EntityContext'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { GetMlModelQuery } from '@graphql/mlModel.generated'; -import { EntityType, MlModelGroup } from '@types'; - -const TabContent = styled.div` - padding: 16px; -`; - -export default function MLModelGroupsTab() { - const baseEntity = useBaseEntity(); - const model = baseEntity?.mlModel; - - const entityRegistry = useEntityRegistry(); - - const propertyTableColumns: ColumnsType = [ - { - title: 'Group', - dataIndex: 'name', - render: (name, record) => { - return ( - - {record.properties?.name || name} - - ); - }, - }, - { - title: 'Description', - dataIndex: 'description', - }, - ]; - - return ( - - - Groups -
- - - ); -} diff --git a/datahub-web-react/src/app/entity/mlModel/profile/MLModelSummary.tsx b/datahub-web-react/src/app/entity/mlModel/profile/MLModelSummary.tsx deleted file mode 100644 index 7e7652b30b650b..00000000000000 --- a/datahub-web-react/src/app/entity/mlModel/profile/MLModelSummary.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import { Space, Table, Typography } from 'antd'; -import React from 'react'; -import { Link } from 'react-router-dom'; -import styled from 'styled-components'; - -import { Pill } from '@components/components/Pills'; - -import { useBaseEntity } from '@app/entity/shared/EntityContext'; -import { InfoItem } from '@app/entity/shared/components/styled/InfoItem'; -import { notEmpty } from '@app/entity/shared/utils'; -import { TimestampPopover } from '@app/sharedV2/TimestampPopover'; -import { useEntityRegistry } from '@app/useEntityRegistry'; -import { colors } from '@src/alchemy-components/theme'; - -import { GetMlModelQuery } from '@graphql/mlModel.generated'; -import { EntityType, MlHyperParam, MlMetric } from '@types'; - -const TabContent = styled.div` - padding: 16px; -`; - -const InfoItemContainer = styled.div<{ justifyContent }>` - display: flex; - position: relative; - justify-content: ${(props) => props.justifyContent}; - padding: 0px 2px; -`; - -const InfoItemContent = styled.div` - padding-top: 8px; - width: 100px; - overflow-wrap: break-word; -`; - -const JobLink = styled(Link)` - color: ${colors.blue[700]}; - &:hover { - text-decoration: underline; - } -`; - -export default function MLModelSummary() { - const baseEntity = useBaseEntity(); - const model = baseEntity?.mlModel; - const entityRegistry = useEntityRegistry(); - - const propertyTableColumns = [ - { - title: 'Name', - dataIndex: 'name', - width: 450, - }, - { - title: 'Value', - dataIndex: 'value', - }, - ]; - - const renderTrainingJobs = () => { - const trainingJobs = - model?.trainedBy?.relationships?.map((relationship) => relationship.entity).filter(notEmpty) || []; - - if (trainingJobs.length === 0) return '-'; - - return ( -
- {trainingJobs.map((job, index) => { - const { urn, name } = job as { urn: string; name?: string }; - return ( - - - {name || urn} - - {index < trainingJobs.length - 1 && ', '} - - ); - })} -
- ); - }; - - return ( - - - Model Details - - - {model?.versionProperties?.version?.versionTag} - - - - - - - - - {model?.properties?.created?.actor || '-'} - - - - - - {model?.versionProperties?.aliases?.map((alias) => ( - - ))} - - - - {renderTrainingJobs()} - - - Training Metrics -
- Hyper Parameters -
- - - ); -} diff --git a/datahub-web-react/src/app/entity/mlModel/profile/MlModelFeaturesTab.tsx b/datahub-web-react/src/app/entity/mlModel/profile/MlModelFeaturesTab.tsx deleted file mode 100644 index cac4135307f722..00000000000000 --- a/datahub-web-react/src/app/entity/mlModel/profile/MlModelFeaturesTab.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; - -import TableOfMlFeatures from '@app/entity/mlFeatureTable/profile/features/TableOfMlFeatures'; -import { useBaseEntity } from '@app/entity/shared/EntityContext'; - -import { GetMlModelQuery } from '@graphql/mlModel.generated'; -import { MlFeature, MlPrimaryKey } from '@types'; - -export default function MlModelFeaturesTab() { - const entity = useBaseEntity() as GetMlModelQuery; - - const model = entity && entity.mlModel; - const features = model?.features?.relationships?.map((relationship) => relationship.entity) as Array< - MlFeature | MlPrimaryKey - >; - - return ; -} diff --git a/datahub-web-react/src/app/entity/mlModelGroup/MLModelGroupEntity.tsx b/datahub-web-react/src/app/entity/mlModelGroup/MLModelGroupEntity.tsx deleted file mode 100644 index d3448c96e3a558..00000000000000 --- a/datahub-web-react/src/app/entity/mlModelGroup/MLModelGroupEntity.tsx +++ /dev/null @@ -1,167 +0,0 @@ -import { CodeSandboxOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { Preview } from '@app/entity/mlModelGroup/preview/Preview'; -import ModelGroupModels from '@app/entity/mlModelGroup/profile/ModelGroupModels'; -import { EntityMenuItems } from '@app/entity/shared/EntityDropdown/EntityDropdown'; -import { EntityProfile } from '@app/entity/shared/containers/profile/EntityProfile'; -import { SidebarAboutSection } from '@app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import DataProductSection from '@app/entity/shared/containers/profile/sidebar/DataProduct/DataProductSection'; -import { SidebarDomainSection } from '@app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection'; -import { SidebarOwnerSection } from '@app/entity/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import { SidebarTagsSection } from '@app/entity/shared/containers/profile/sidebar/SidebarTagsSection'; -import SidebarStructuredPropsSection from '@app/entity/shared/containers/profile/sidebar/StructuredProperties/SidebarStructuredPropsSection'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { DocumentationTab } from '@app/entity/shared/tabs/Documentation/DocumentationTab'; -import { PropertiesTab } from '@app/entity/shared/tabs/Properties/PropertiesTab'; -import { GenericEntityProperties } from '@app/entity/shared/types'; - -import { useGetMlModelGroupQuery } from '@graphql/mlModelGroup.generated'; -import { EntityType, MlModelGroup, OwnershipType, SearchResult } from '@types'; - -/** - * Definition of the DataHub MlModelGroup entity. - */ -export class MLModelGroupEntity implements Entity { - type: EntityType = EntityType.MlmodelGroup; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => true; - - isLineageEnabled = () => true; - - getAutoCompleteFieldName = () => 'name'; - - getGraphName = () => 'mlModelGroup'; - - getPathName = () => 'mlModelGroup'; - - getEntityName = () => 'ML Group'; - - getCollectionName = () => 'ML Groups'; - - getOverridePropertiesFromEntity = (_?: MlModelGroup | null): GenericEntityProperties => { - return {}; - }; - - useEntityQuery = useGetMlModelGroupQuery; - - getSidebarSections = () => [ - { - component: SidebarAboutSection, - }, - { - component: SidebarOwnerSection, - properties: { - defaultOwnerType: OwnershipType.TechnicalOwner, - }, - }, - { - component: SidebarTagsSection, - properties: { - hasTags: true, - hasTerms: true, - }, - }, - { - component: SidebarDomainSection, - }, - { - component: DataProductSection, - }, - { - component: SidebarStructuredPropsSection, - }, - ]; - - renderProfile = (urn: string) => ( - - ); - - renderPreview = (_: PreviewType, data: MlModelGroup) => { - return ; - }; - - renderSearch = (result: SearchResult) => { - const data = result.entity as MlModelGroup; - return ; - }; - - getLineageVizConfig = (entity: MlModelGroup) => { - return { - urn: entity.urn, - // eslint-disable-next-line @typescript-eslint/dot-notation - name: entity.properties?.['propertiesName'] || entity.name, - type: EntityType.MlmodelGroup, - icon: entity.platform?.properties?.logoUrl || undefined, - platform: entity.platform, - }; - }; - - displayName = (data: MlModelGroup) => { - return data.properties?.name || data.name || data.urn; - }; - - getGenericEntityProperties = (mlModelGroup: MlModelGroup) => { - return getDataForEntityType({ - data: mlModelGroup, - entityType: this.type, - getOverrideProperties: (data) => data, - }); - }; - - supportedCapabilities = () => { - return new Set([ - EntityCapabilityType.OWNERS, - EntityCapabilityType.GLOSSARY_TERMS, - EntityCapabilityType.TAGS, - EntityCapabilityType.DOMAINS, - EntityCapabilityType.DEPRECATION, - EntityCapabilityType.SOFT_DELETE, - EntityCapabilityType.DATA_PRODUCTS, - ]); - }; -} diff --git a/datahub-web-react/src/app/entity/mlModelGroup/preview/Preview.tsx b/datahub-web-react/src/app/entity/mlModelGroup/preview/Preview.tsx deleted file mode 100644 index fb7cb6587fa344..00000000000000 --- a/datahub-web-react/src/app/entity/mlModelGroup/preview/Preview.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React from 'react'; - -import { getDataProduct } from '@app/entity/shared/utils'; -import DefaultPreviewCard from '@app/preview/DefaultPreviewCard'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { EntityPath, EntityType, MlModelGroup } from '@types'; - -export const Preview = ({ - group, - degree, - paths, -}: { - group: MlModelGroup; - degree?: number; - paths?: EntityPath[]; -}): JSX.Element => { - const entityRegistry = useEntityRegistry(); - const genericProperties = entityRegistry.getGenericEntityProperties(EntityType.MlmodelGroup, group); - return ( - - ); -}; diff --git a/datahub-web-react/src/app/entity/mlModelGroup/profile/ModelGroupModels.tsx b/datahub-web-react/src/app/entity/mlModelGroup/profile/ModelGroupModels.tsx deleted file mode 100644 index 22a2f93ed2ff6c..00000000000000 --- a/datahub-web-react/src/app/entity/mlModelGroup/profile/ModelGroupModels.tsx +++ /dev/null @@ -1,188 +0,0 @@ -import { Table, Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { useBaseEntity } from '@app/entity/shared/EntityContext'; -import { EmptyTab } from '@app/entity/shared/components/styled/EmptyTab'; -import { InfoItem } from '@app/entity/shared/components/styled/InfoItem'; -import { notEmpty } from '@app/entity/shared/utils'; -import { TimestampPopover } from '@app/sharedV2/TimestampPopover'; -import { useEntityRegistry } from '@app/useEntityRegistry'; -import { Pill } from '@src/alchemy-components/components/Pills'; -import { colors } from '@src/alchemy-components/theme'; - -import { GetMlModelGroupQuery } from '@graphql/mlModelGroup.generated'; -import { EntityType } from '@types'; - -const InfoItemContainer = styled.div<{ justifyContent }>` - display: flex; - position: relative; - justify-content: ${(props) => props.justifyContent}; - padding: 12px 2px 20px 2px; -`; - -const InfoItemContent = styled.div` - padding-top: 8px; - width: 100px; -`; - -const NameContainer = styled.div` - display: flex; - align-items: center; -`; - -const NameLink = styled.a` - font-weight: 700; - color: inherit; - font-size: 0.9rem; - - &:hover { - color: ${colors.blue[400]} !important; - } -`; - -const TagContainer = styled.div` - display: inline-flex; - margin-left: 0px; - margin-top: 3px; - flex-wrap: wrap; - margin-right: 8px; - backgroundcolor: white; - gap: 5px; -`; - -const StyledTable = styled(Table)` - &&& .ant-table-cell { - padding: 16px; - } -` as typeof Table; - -const ModelsContainer = styled.div` - width: 100%; - padding: 20px; -`; - -const VersionContainer = styled.div` - display: flex; - align-items: center; -`; - -export default function MLGroupModels() { - const baseEntity = useBaseEntity(); - const entityRegistry = useEntityRegistry(); - const modelGroup = baseEntity?.mlModelGroup; - - const models = - baseEntity?.mlModelGroup?.incoming?.relationships - ?.map((relationship) => relationship.entity) - .filter(notEmpty) || []; - - const columns = [ - { - title: 'Name', - dataIndex: 'name', - key: 'name', - width: 300, - render: (_: any, record) => ( - - - {record?.properties?.propertiesName || record?.name} - - - ), - }, - { - title: 'Version', - key: 'version', - width: 70, - render: (_: any, record: any) => ( - {record.versionProperties?.version?.versionTag || '-'} - ), - }, - { - title: 'Created At', - key: 'createdAt', - width: 150, - render: (_: any, record: any) => ( - - ), - }, - { - title: 'Aliases', - key: 'aliases', - width: 200, - render: (_: any, record: any) => { - const aliases = record.versionProperties?.aliases || []; - - return ( - - {aliases.map((alias) => ( - - ))} - - ); - }, - }, - { - title: 'Properties', - key: 'properties', - width: 200, - render: (_: any, record: any) => { - const tags = record.properties?.tags || []; - - return ( - - {tags.map((tag) => ( - - ))} - - ); - }, - }, - { - title: 'Description', - dataIndex: 'description', - key: 'description', - width: 300, - render: (_: any, record: any) => { - const editableDesc = record.editableProperties?.description; - const originalDesc = record.description; - - return {editableDesc || originalDesc || '-'}; - }, - }, - ]; - - return ( - - Model Group Details - - - - - - - - {modelGroup?.properties?.created?.actor && ( - - {modelGroup.properties.created?.actor} - - )} - - Models - , - }} - /> - - ); -} diff --git a/datahub-web-react/src/app/entity/mlPrimaryKey/MLPrimaryKeyEntity.tsx b/datahub-web-react/src/app/entity/mlPrimaryKey/MLPrimaryKeyEntity.tsx deleted file mode 100644 index 2ca67e208e0fbb..00000000000000 --- a/datahub-web-react/src/app/entity/mlPrimaryKey/MLPrimaryKeyEntity.tsx +++ /dev/null @@ -1,204 +0,0 @@ -import { DotChartOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { Preview } from '@app/entity/mlPrimaryKey/preview/Preview'; -import { EntityProfile } from '@app/entity/shared/containers/profile/EntityProfile'; -import { SidebarAboutSection } from '@app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import DataProductSection from '@app/entity/shared/containers/profile/sidebar/DataProduct/DataProductSection'; -import { SidebarDomainSection } from '@app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection'; -import { SidebarOwnerSection } from '@app/entity/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import { SidebarTagsSection } from '@app/entity/shared/containers/profile/sidebar/SidebarTagsSection'; -import SidebarStructuredPropsSection from '@app/entity/shared/containers/profile/sidebar/StructuredProperties/SidebarStructuredPropsSection'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { DocumentationTab } from '@app/entity/shared/tabs/Documentation/DocumentationTab'; -import { LineageTab } from '@app/entity/shared/tabs/Lineage/LineageTab'; -import { FeatureTableTab } from '@app/entity/shared/tabs/ML/MlPrimaryKeyFeatureTableTab'; -import { PropertiesTab } from '@app/entity/shared/tabs/Properties/PropertiesTab'; -import { GenericEntityProperties } from '@app/entity/shared/types'; -import { getDataProduct } from '@app/entity/shared/utils'; - -import { useGetMlPrimaryKeyQuery } from '@graphql/mlPrimaryKey.generated'; -import { EntityType, MlPrimaryKey, OwnershipType, SearchResult } from '@types'; - -/** - * Definition of the DataHub MLPrimaryKey entity. - */ -export class MLPrimaryKeyEntity implements Entity { - type: EntityType = EntityType.MlprimaryKey; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => false; - - isLineageEnabled = () => true; - - getAutoCompleteFieldName = () => 'name'; - - getGraphName = () => 'mlPrimaryKey'; - - getPathName = () => 'mlPrimaryKeys'; - - getEntityName = () => 'ML Primary Key'; - - getCollectionName = () => 'ML Primary Keys'; - - getOverridePropertiesFromEntity = (key?: MlPrimaryKey | null): GenericEntityProperties => { - return { - // eslint-disable-next-line - platform: key?.['featureTables']?.relationships?.[0]?.entity?.platform, - }; - }; - - useEntityQuery = useGetMlPrimaryKeyQuery; - - renderProfile = (urn: string) => ( - - ); - - getSidebarSections = () => [ - { - component: SidebarAboutSection, - }, - { - component: SidebarOwnerSection, - properties: { - defaultOwnerType: OwnershipType.TechnicalOwner, - }, - }, - { - component: SidebarTagsSection, - properties: { - hasTags: true, - hasTerms: true, - }, - }, - { - component: SidebarDomainSection, - }, - { - component: DataProductSection, - }, - { - component: SidebarStructuredPropsSection, - }, - ]; - - renderPreview = (_: PreviewType, data: MlPrimaryKey) => { - const genericProperties = this.getGenericEntityProperties(data); - // eslint-disable-next-line - const platform = data?.['featureTables']?.relationships?.[0]?.entity?.platform; - return ( - - ); - }; - - renderSearch = (result: SearchResult) => { - const data = result.entity as MlPrimaryKey; - const genericProperties = this.getGenericEntityProperties(data); - // eslint-disable-next-line - const platform = data?.['featureTables']?.relationships?.[0]?.entity?.platform; - return ( - - ); - }; - - displayName = (data: MlPrimaryKey) => { - return data.name || data.urn; - }; - - getGenericEntityProperties = (mlPrimaryKey: MlPrimaryKey) => { - return getDataForEntityType({ - data: mlPrimaryKey, - entityType: this.type, - getOverrideProperties: this.getOverridePropertiesFromEntity, - }); - }; - - getLineageVizConfig = (entity: MlPrimaryKey) => { - return { - urn: entity.urn, - name: entity.name, - type: EntityType.MlprimaryKey, - // eslint-disable-next-line - icon: entity?.['featureTables']?.relationships?.[0]?.entity?.platform?.properties?.logoUrl || undefined, - // eslint-disable-next-line - platform: entity?.['featureTables']?.relationships?.[0]?.entity?.platform?.name, - }; - }; - - supportedCapabilities = () => { - return new Set([ - EntityCapabilityType.OWNERS, - EntityCapabilityType.GLOSSARY_TERMS, - EntityCapabilityType.TAGS, - EntityCapabilityType.DOMAINS, - EntityCapabilityType.DEPRECATION, - EntityCapabilityType.SOFT_DELETE, - EntityCapabilityType.DATA_PRODUCTS, - ]); - }; -} diff --git a/datahub-web-react/src/app/entity/mlPrimaryKey/preview/Preview.tsx b/datahub-web-react/src/app/entity/mlPrimaryKey/preview/Preview.tsx deleted file mode 100644 index 70fb631b2f5c8e..00000000000000 --- a/datahub-web-react/src/app/entity/mlPrimaryKey/preview/Preview.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import React from 'react'; - -import { IconStyleType } from '@app/entity/Entity'; -import DefaultPreviewCard from '@app/preview/DefaultPreviewCard'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { DataPlatform, DataProduct, EntityPath, EntityType, Owner } from '@types'; - -export const Preview = ({ - urn, - name, - featureNamespace, - description, - owners, - platform, - dataProduct, - platformInstanceId, - degree, - paths, -}: { - urn: string; - name: string; - featureNamespace: string; - description?: string | null; - owners?: Array | null; - platform?: DataPlatform | null | undefined; - dataProduct?: DataProduct | null; - platformInstanceId?: string; - degree?: number; - paths?: EntityPath[]; -}): JSX.Element => { - const entityRegistry = useEntityRegistry(); - return ( - - ); -}; diff --git a/datahub-web-react/src/app/entity/ownership/ManageOwnership.tsx b/datahub-web-react/src/app/entity/ownership/ManageOwnership.tsx deleted file mode 100644 index ccc27e948c8e09..00000000000000 --- a/datahub-web-react/src/app/entity/ownership/ManageOwnership.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components/macro'; - -import { OwnershipList } from '@app/entity/ownership/OwnershipList'; - -const PageContainer = styled.div` - padding-top: 20px; - width: 100%; - display: flex; - flex-direction: column; - overflow: auto; -`; - -const PageHeaderContainer = styled.div` - && { - padding-left: 24px; - } -`; - -const PageTitle = styled(Typography.Title)` - && { - margin-bottom: 12px; - } -`; - -const ListContainer = styled.div` - display: flex; - flex-direction: column; - overflow: auto; -`; - -/** - * Component used for displaying the 'Manage Ownership' experience. - */ -export const ManageOwnership = () => { - return ( - - - Manage Ownership - - Create, edit, and remove custom Ownership Types. - - - - - - - ); -}; diff --git a/datahub-web-react/src/app/entity/ownership/OwnershipBuilderModal.tsx b/datahub-web-react/src/app/entity/ownership/OwnershipBuilderModal.tsx deleted file mode 100644 index 42bf0da7b57d14..00000000000000 --- a/datahub-web-react/src/app/entity/ownership/OwnershipBuilderModal.tsx +++ /dev/null @@ -1,227 +0,0 @@ -import { Button, Form, Input, Modal, Typography, message, notification } from 'antd'; -import React, { useEffect, useState } from 'react'; -import styled from 'styled-components/macro'; - -import { OwnershipTypeBuilderState } from '@app/entity/ownership/table/types'; - -import { useCreateOwnershipTypeMutation, useUpdateOwnershipTypeMutation } from '@graphql/ownership.generated'; -import { OwnershipTypeEntity } from '@types'; - -const NAME_INPUT_TEST_ID = 'ownership-type-name-input'; -const DESCRIPTION_INPUT_TEST_ID = 'ownership-type-description-input'; - -const TitleContainer = styled.div` - display: flex; - justify-content: space-between; -`; - -const TitleText = styled(Typography.Text)` - font-size: 16px; - font-weight: 700; -`; - -const FormItemContainer = styled.div` - display: flex; - flex-direction: column; -`; - -const FormItemTitle = styled(Typography.Text)` - margin-bottom: 8px; - font-weight: 700; -`; - -const StyledFormItem = styled(Form.Item)` - margin-bottom: 8px; -`; - -const SaveButtonContainer = styled.div` - width: 100%; - display: flex; - justify-content: right; -`; - -const CancelButton = styled(Button)` - margin-right: 12px; -`; - -type Props = { - isOpen: boolean; - onClose: () => void; - refetch: () => void; - ownershipType?: OwnershipTypeEntity; -}; - -export const OwnershipBuilderModal = ({ isOpen, onClose, refetch, ownershipType }: Props) => { - // State - const [ownershipTypeBuilderState, setOwnershipTypeBuilderState] = useState({ - name: ownershipType?.info?.name || ownershipType?.urn || '', - description: ownershipType?.info?.description || '', - }); - const setName = (name: string) => { - setOwnershipTypeBuilderState({ ...ownershipTypeBuilderState, name }); - }; - const setDescription = (description: string) => { - setOwnershipTypeBuilderState({ ...ownershipTypeBuilderState, description }); - }; - const [form] = Form.useForm(); - form.setFieldsValue(ownershipTypeBuilderState); - - // Side effects - useEffect(() => { - if (ownershipType) { - const ownershipTypeName = ownershipType?.info?.name || ownershipType?.urn; - const ownershipTypeDescription = ownershipType?.info?.description || ''; - setOwnershipTypeBuilderState({ - name: ownershipTypeName, - description: ownershipTypeDescription, - }); - } else { - setOwnershipTypeBuilderState({ - name: '', - description: '', - }); - } - }, [ownershipType]); - - // Queries - const [createOwnershipTypeMutation] = useCreateOwnershipTypeMutation(); - const [updateOwnershipTypeMutation] = useUpdateOwnershipTypeMutation(); - - const onCreateOwnershipType = () => { - if (ownershipTypeBuilderState.name) { - createOwnershipTypeMutation({ - variables: { - input: { - name: ownershipTypeBuilderState.name, - description: ownershipTypeBuilderState.description, - }, - }, - }) - .then(() => { - setName(''); - setDescription(''); - onClose(); - notification.success({ - message: `Success`, - description: 'Successfully created ownership type.', - placement: 'bottomLeft', - duration: 3, - }); - setTimeout(() => { - refetch(); - }, 3000); - }) - .catch((e: unknown) => { - message.destroy(); - if (e instanceof Error) { - message.error({ - content: `Failed to create ownership type`, - duration: 3, - }); - } - }); - } - }; - - const onUpdateOwnershipType = () => { - if (ownershipType) { - updateOwnershipTypeMutation({ - variables: { - urn: ownershipType?.urn || '', - input: { - name: ownershipTypeBuilderState.name, - description: ownershipTypeBuilderState.description, - }, - }, - }) - .then(() => { - setName(''); - setDescription(''); - onClose(); - notification.success({ - message: `Success`, - description: 'Successfully updated ownership type.', - placement: 'bottomLeft', - duration: 3, - }); - setTimeout(() => { - refetch(); - }, 3000); - }) - .catch((e: unknown) => { - message.destroy(); - if (e instanceof Error) { - message.error({ - content: `Failed to update ownership type`, - duration: 3, - }); - } - }); - } - }; - - const onUpsert = ownershipType ? onUpdateOwnershipType : onCreateOwnershipType; - const titleText = ownershipType ? 'Edit ownership type' : 'Add a new ownership type'; - return ( - - {titleText} - - } - footer={null} - > -
- - Name - - { - setName(e.target.value); - }} - /> - - - - Description - - { - setDescription(e.target.value); - }} - /> - - - - - - Cancel - - - -
- ); -}; diff --git a/datahub-web-react/src/app/entity/ownership/OwnershipList.tsx b/datahub-web-react/src/app/entity/ownership/OwnershipList.tsx deleted file mode 100644 index 617ed303d6b248..00000000000000 --- a/datahub-web-react/src/app/entity/ownership/OwnershipList.tsx +++ /dev/null @@ -1,134 +0,0 @@ -import { PlusOutlined } from '@ant-design/icons'; -import { Button, Pagination, message } from 'antd'; -import React, { useState } from 'react'; -import styled from 'styled-components/macro'; - -import { OwnershipBuilderModal } from '@app/entity/ownership/OwnershipBuilderModal'; -import { OwnershipTable } from '@app/entity/ownership/table/OwnershipTable'; -import TabToolbar from '@app/entity/shared/components/styled/TabToolbar'; -import { SearchBar } from '@app/search/SearchBar'; -import { Message } from '@app/shared/Message'; -import { scrollToTop } from '@app/shared/searchUtils'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useListOwnershipTypesQuery } from '@graphql/ownership.generated'; -import { OwnershipTypeEntity } from '@types'; - -const PaginationContainer = styled.div` - display: flex; - justify-content: center; -`; - -const StyledPagination = styled(Pagination)` - margin: 40px; -`; - -const searchBarStyle = { - maxWidth: 220, - padding: 0, -}; - -const searchBarInputStyle = { - height: 32, - fontSize: 12, -}; - -/** - * This component renders a paginated, searchable list of Ownership Types. - */ -export const OwnershipList = () => { - /** - * Context - */ - const entityRegistry = useEntityRegistry(); - - /** - * State - */ - const [page, setPage] = useState(1); - const [showOwnershipBuilder, setShowOwnershipBuilder] = useState(false); - const [ownershipType, setOwnershipType] = useState(undefined); - const [query, setQuery] = useState(undefined); - - /** - * Queries - */ - const pageSize = 10; - const start: number = (page - 1) * pageSize; - const { data, loading, error, refetch } = useListOwnershipTypesQuery({ - variables: { - input: { - start, - count: pageSize, - query, - }, - }, - }); - const totalOwnershipTypes = data?.listOwnershipTypes?.total || 0; - const ownershipTypes = - data?.listOwnershipTypes?.ownershipTypes?.filter((type) => type.urn !== 'urn:li:ownershipType:none') || []; - - const onClickCreateOwnershipType = () => { - setShowOwnershipBuilder(true); - }; - - const onCloseModal = () => { - setShowOwnershipBuilder(false); - setOwnershipType(undefined); - }; - - const onChangePage = (newPage: number) => { - scrollToTop(); - setPage(newPage); - }; - - return ( - <> - {!data && loading && } - {error && - message.error({ - content: `Failed to load Ownership Types! An unexpected error occurred.`, - duration: 3, - })} - - - null} - onQueryChange={(q) => setQuery(q.length > 0 ? q : undefined)} - entityRegistry={entityRegistry} - /> - - - {totalOwnershipTypes >= pageSize && ( - - - - )} - - - ); -}; diff --git a/datahub-web-react/src/app/entity/ownership/table/ActionsColumn.tsx b/datahub-web-react/src/app/entity/ownership/table/ActionsColumn.tsx deleted file mode 100644 index 31613811691d96..00000000000000 --- a/datahub-web-react/src/app/entity/ownership/table/ActionsColumn.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import { CopyOutlined, DeleteOutlined, EditOutlined, MoreOutlined } from '@ant-design/icons'; -import { Dropdown, MenuProps, Popconfirm, Typography, message, notification } from 'antd'; -import React from 'react'; -import styled from 'styled-components/macro'; - -import { useDeleteOwnershipTypeMutation } from '@graphql/ownership.generated'; -import { OwnershipTypeEntity } from '@types'; - -const DROPDOWN_TEST_ID = 'ownership-table-dropdown'; -const EDIT_OWNERSHIP_TYPE_TEST_ID = 'edit-ownership-type'; -const DELETE_OWNERSHIP_TYPE_TEST_ID = 'delete-ownership-type'; - -const StyledDropdown = styled(Dropdown)``; - -const MenuButtonContainer = styled.div` - display: flex; - justify-content: center; - align-items: center; -`; - -const MenuButtonText = styled(Typography.Text)` - font-size: 14px; - font-weight: 400; - margin-left: 8px; -`; - -const StyledMoreOutlined = styled(MoreOutlined)` - width: 20px; - &&& { - padding-left: 0px; - padding-right: 0px; - font-size: 18px; - } - :hover { - cursor: pointer; - } -`; - -type Props = { - ownershipType: OwnershipTypeEntity; - setIsOpen: (isOpen: boolean) => void; - setOwnershipType: (ownershipType: OwnershipTypeEntity) => void; - refetch: () => void; -}; - -export const ActionsColumn = ({ ownershipType, setIsOpen, setOwnershipType, refetch }: Props) => { - const editOnClick = () => { - setIsOpen(true); - setOwnershipType(ownershipType); - }; - - const onCopy = () => { - navigator.clipboard.writeText(ownershipType.urn); - }; - - const [deleteOwnershipTypeMutation] = useDeleteOwnershipTypeMutation(); - - const onDelete = () => { - deleteOwnershipTypeMutation({ - variables: { - urn: ownershipType.urn, - }, - }) - .then(() => { - notification.success({ - message: `Success`, - description: 'You have deleted an ownership type.', - placement: 'bottomLeft', - duration: 3, - }); - setTimeout(() => { - refetch(); - }, 3000); - }) - .catch((e: unknown) => { - message.destroy(); - if (e instanceof Error) { - message.error({ - content: `Failed to delete an ownership type`, - duration: 3, - }); - } - }); - }; - - const items: MenuProps['items'] = [ - { - key: 'edit', - icon: ( - - - Edit - - ), - }, - { - key: 'delete', - icon: ( - Are you sure you want to delete this ownership type?} - placement="left" - onCancel={() => {}} - onConfirm={onDelete} - okText="Yes" - cancelText="No" - > - - - Delete - - - ), - }, - { - key: 'copy', - icon: ( - - - Copy Urn - - ), - }, - ]; - - const onClick: MenuProps['onClick'] = (e) => { - const key = e.key as string; - if (key === 'edit') { - editOnClick(); - } else if (key === 'copy') { - onCopy(); - } - }; - - const menuProps: MenuProps = { - items, - onClick, - }; - - return ( - - - - ); -}; diff --git a/datahub-web-react/src/app/entity/ownership/table/DescriptionColumn.tsx b/datahub-web-react/src/app/entity/ownership/table/DescriptionColumn.tsx deleted file mode 100644 index e53c37b778c132..00000000000000 --- a/datahub-web-react/src/app/entity/ownership/table/DescriptionColumn.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components/macro'; - -import { OwnershipTypeEntity } from '@types'; - -const DescriptionText = styled(Typography.Text)` - font-size: 14px; - font-weight: 400; -`; - -type Props = { - ownershipType: OwnershipTypeEntity; -}; - -export const DescriptionColumn = ({ ownershipType }: Props) => { - const description = ownershipType?.info?.description || ''; - - return {description}; -}; diff --git a/datahub-web-react/src/app/entity/ownership/table/NameColumn.tsx b/datahub-web-react/src/app/entity/ownership/table/NameColumn.tsx deleted file mode 100644 index 4358dac1557d53..00000000000000 --- a/datahub-web-react/src/app/entity/ownership/table/NameColumn.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components/macro'; - -import { OwnershipTypeEntity } from '@types'; - -const NameText = styled(Typography.Text)` - font-size: 14px; - font-weight: 700; -`; - -type Props = { - ownershipType: OwnershipTypeEntity; -}; - -export const NameColumn = ({ ownershipType }: Props) => { - const name = ownershipType?.info?.name || ownershipType?.urn; - - return {name}; -}; diff --git a/datahub-web-react/src/app/entity/ownership/table/OwnershipTable.tsx b/datahub-web-react/src/app/entity/ownership/table/OwnershipTable.tsx deleted file mode 100644 index 9430899f9e8d71..00000000000000 --- a/datahub-web-react/src/app/entity/ownership/table/OwnershipTable.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { Empty } from 'antd'; -import React from 'react'; - -import { ActionsColumn } from '@app/entity/ownership/table/ActionsColumn'; -import { DescriptionColumn } from '@app/entity/ownership/table/DescriptionColumn'; -import { NameColumn } from '@app/entity/ownership/table/NameColumn'; -import { StyledTable } from '@app/entity/shared/components/styled/StyledTable'; - -import { OwnershipTypeEntity } from '@types'; - -type Props = { - ownershipTypes: OwnershipTypeEntity[]; - setIsOpen: (isOpen: boolean) => void; - setOwnershipType: (ownershipType: OwnershipTypeEntity) => void; - refetch: () => void; -}; - -export const OwnershipTable = ({ ownershipTypes, setIsOpen, setOwnershipType, refetch }: Props) => { - const tableColumns = [ - { - title: 'Name', - dataIndex: 'name', - sorter: (a: any, b: any) => a?.info?.name?.localeCompare(b?.info?.name), - key: 'name', - render: (_, record: any) => , - }, - { - title: 'Description', - dataIndex: 'description', - key: 'description', - render: (_, record: any) => , - }, - { - dataIndex: 'actions', - key: 'actions', - render: (_, record: any) => ( - - ), - }, - ]; - - const getRowKey = (ownershipType: OwnershipTypeEntity) => { - return ownershipType?.info?.name || ownershipType.urn; - }; - - return ( - , - }} - pagination={false} - /> - ); -}; diff --git a/datahub-web-react/src/app/entity/ownership/table/types.ts b/datahub-web-react/src/app/entity/ownership/table/types.ts deleted file mode 100644 index 6d7f9bdcf760b7..00000000000000 --- a/datahub-web-react/src/app/entity/ownership/table/types.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * The object represents the state of the Ownership Type Builder form. - */ -export interface OwnershipTypeBuilderState { - /** - * The name of the Ownership Type. - */ - name: string; - - /** - * The description of the Ownership Type. - */ - description: string; -} diff --git a/datahub-web-react/src/app/entity/query/QueryEntity.tsx b/datahub-web-react/src/app/entity/query/QueryEntity.tsx deleted file mode 100644 index 33b1069d40dec6..00000000000000 --- a/datahub-web-react/src/app/entity/query/QueryEntity.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import { ConsoleSqlOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, IconStyleType } from '@app/entity/Entity'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { GenericEntityProperties } from '@app/entity/shared/types'; -import { TYPE_ICON_CLASS_NAME } from '@app/entityV2/shared/components/subtypes'; - -import { useGetQueryQuery } from '@graphql/query.generated'; -import { DataPlatform, EntityType, QueryEntity as Query } from '@types'; - -/** - * Definition of the DataHub DataPlatformInstance entity. - * Most of this still needs to be filled out. - */ -export class QueryEntity implements Entity { - type: EntityType = EntityType.Query; - - icon = (fontSize?: number, _styleType?: IconStyleType, color?: string) => { - return ( - - ); - }; - - isSearchEnabled = () => false; - - isBrowseEnabled = () => false; - - isLineageEnabled = () => false; - - getAutoCompleteFieldName = () => 'name'; - - getPathName = () => 'query'; - - getEntityName = () => 'Query'; - - getCollectionName = () => 'Queries'; - - useEntityQuery = useGetQueryQuery; - - renderProfile = (_urn: string) => { - return <>; - }; - - getOverridePropertiesFromEntity = (query?: Query | null): GenericEntityProperties => { - return { - name: query && this.displayName(query), - platform: query?.platform, - }; - }; - - renderEmbeddedProfile = (_: string) => <>; - - renderPreview = () => { - return <>; - }; - - renderSearch = () => { - return <>; - }; - - getLineageVizConfig = (query: Query) => { - // TODO: Set up types better here - const platform: DataPlatform | undefined = (query as any)?.queryPlatform; - return { - urn: query.urn, - name: query.properties?.name || query.urn, - type: EntityType.Query, - icon: platform?.properties?.logoUrl || undefined, - platform: platform || undefined, - }; - }; - - displayName = (data: Query) => { - return data?.properties?.name || (data?.properties?.source === 'SYSTEM' && 'System Query') || data?.urn; - }; - - getGenericEntityProperties = (data: Query) => { - return getDataForEntityType({ - data, - entityType: this.type, - getOverrideProperties: this.getOverridePropertiesFromEntity, - }); - }; - - supportedCapabilities = () => { - return new Set([]); - }; - - getGraphName = () => { - return 'query'; - }; -} diff --git a/datahub-web-react/src/app/entity/restricted/RestrictedEntity.tsx b/datahub-web-react/src/app/entity/restricted/RestrictedEntity.tsx deleted file mode 100644 index 348fe0fddd4dbf..00000000000000 --- a/datahub-web-react/src/app/entity/restricted/RestrictedEntity.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { QuestionOutlined } from '@ant-design/icons'; -import React from 'react'; - -import { Entity, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { RestrictedEntityProfile } from '@app/entity/restricted/RestrictedEntityProfile'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; - -import { EntityType, Restricted, SearchResult } from '@types'; - -import RestrictedIcon from '@images/restricted.svg'; - -/** - * Definition of the DataHub Data Product entity. - */ -export class RestrictedEntity implements Entity { - type: EntityType = EntityType.Restricted; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - return ( - - ); - }; - - isSearchEnabled = () => false; - - isBrowseEnabled = () => false; - - isLineageEnabled = () => true; - - getAutoCompleteFieldName = () => 'name'; - - getPathName = () => 'restricted'; - - getEntityName = () => 'Restricted'; - - getCollectionName = () => 'Restricted Assets'; - - renderProfile = (_: string) => ; - - renderPreview = (_: PreviewType, _data: Restricted) => { - return ; - }; - - renderSearch = (_result: SearchResult) => { - return ; - }; - - getLineageVizConfig = (entity: Restricted) => { - return { - urn: entity?.urn, - name: 'Restricted Asset', - type: EntityType.Restricted, - icon: RestrictedIcon, - }; - }; - - displayName = (_data: Restricted) => { - return 'Restricted Asset'; - }; - - getOverridePropertiesFromEntity = (_data: Restricted) => { - return {}; - }; - - getGenericEntityProperties = (data: Restricted) => { - return getDataForEntityType({ - data, - entityType: this.type, - getOverrideProperties: this.getOverridePropertiesFromEntity, - }); - }; - - supportedCapabilities = () => { - return new Set([]); - }; - - getGraphName = () => { - return 'restricted'; - }; -} diff --git a/datahub-web-react/src/app/entity/restricted/RestrictedEntityProfile.tsx b/datahub-web-react/src/app/entity/restricted/RestrictedEntityProfile.tsx deleted file mode 100644 index 1c9d50afcab4a6..00000000000000 --- a/datahub-web-react/src/app/entity/restricted/RestrictedEntityProfile.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import { EntityTitle } from '@app/entity/shared/containers/profile/header/EntityName'; -import { - LogoIcon, - PlatformContentWrapper, - PlatformText, - PreviewImage, -} from '@app/entity/shared/containers/profile/header/PlatformContent/PlatformContentView'; - -import RestrictedIcon from '@images/restricted.svg'; - -const SubHeader = styled.div` - margin-top: 8px; - font-size: 14px; -`; - -export function RestrictedEntityProfile() { - return ( - <> - - - - - Restricted - - Restricted Asset - This asset is Restricted. Please request access to see more. - - ); -} diff --git a/datahub-web-react/src/app/entity/schemaField/SchemaFieldPropertiesEntity.tsx b/datahub-web-react/src/app/entity/schemaField/SchemaFieldPropertiesEntity.tsx deleted file mode 100644 index 0cc5c4969de4c2..00000000000000 --- a/datahub-web-react/src/app/entity/schemaField/SchemaFieldPropertiesEntity.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { PicCenterOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { Preview } from '@app/entity/schemaField/preview/Preview'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; - -import { Dataset, EntityType, SchemaFieldEntity, SearchResult } from '@types'; - -export class SchemaFieldPropertiesEntity implements Entity { - type: EntityType = EntityType.SchemaField; - - icon = (fontSize: number, styleType: IconStyleType, color = '#BFBFBF') => ( - - ); - - isSearchEnabled = () => true; - - isBrowseEnabled = () => false; - - isLineageEnabled = () => false; - - getParentDataset = (parent) => { - return { - urn: parent?.urn, - name: parent?.name, - type: parent?.type, - platform: parent?.platfrom, - properties: parent?.properties, - } as Dataset; - }; - - // Currently unused. - getAutoCompleteFieldName = () => 'schemaField'; - - // Currently unused. - getPathName = () => 'schemaField'; - - getEntityName = () => 'Column'; - - getCollectionName = () => 'Columns'; - - // Currently unused. - renderProfile = (_: string) => <>; - - getGraphName = () => 'schemaField'; - - renderPreview = (previewType: PreviewType, data: SchemaFieldEntity) => { - const parent = data.parent as Dataset; - return ( - - ); - }; - - renderSearch = (result: SearchResult) => this.renderPreview(PreviewType.SEARCH, result.entity as SchemaFieldEntity); - - displayName = (data: SchemaFieldEntity) => data?.fieldPath || data.urn; - - getGenericEntityProperties = (data: SchemaFieldEntity) => - getDataForEntityType({ data, entityType: this.type, getOverrideProperties: (newData) => newData }); - - supportedCapabilities = () => new Set([]); -} diff --git a/datahub-web-react/src/app/entity/schemaField/preview/Preview.tsx b/datahub-web-react/src/app/entity/schemaField/preview/Preview.tsx deleted file mode 100644 index 75e6ef31081ff2..00000000000000 --- a/datahub-web-react/src/app/entity/schemaField/preview/Preview.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { PicCenterOutlined } from '@ant-design/icons'; -import React from 'react'; - -import { IconStyleType, PreviewType } from '@app/entity/Entity'; -import DefaultPreviewCard from '@app/preview/DefaultPreviewCard'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { Dataset, EntityType, Owner, ParentContainersResult } from '@types'; - -export const Preview = ({ - datasetUrn, - name, - description, - owners, - previewType, - parentContainers, - platformName, - platformLogo, - platformInstanceId, - parentDataset, -}: { - datasetUrn: string; - name: string; - description?: string | null; - owners?: Array | null; - previewType: PreviewType; - parentContainers?: ParentContainersResult | null; - platformName?: string; - platformLogo?: string | null; - platformInstanceId?: string; - parentDataset?: Dataset; -}): JSX.Element => { - const entityRegistry = useEntityRegistry(); - - const url = `${entityRegistry.getEntityUrl(EntityType.Dataset, datasetUrn)}/${encodeURIComponent( - 'Schema', - )}?schemaFilter=${encodeURIComponent(name)}`; - - return ( - } - type="Column" - typeIcon={entityRegistry.getIcon(EntityType.SchemaField, 14, IconStyleType.ACCENT)} - logoUrl={platformLogo || ''} - platform={platformName} - platformInstanceId={platformInstanceId} - parentContainers={parentContainers} - parentDataset={parentDataset} - /> - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/EntityContext.ts b/datahub-web-react/src/app/entity/shared/EntityContext.ts index b2bfe2aef3494a..4a6ea2c99ddf85 100644 --- a/datahub-web-react/src/app/entity/shared/EntityContext.ts +++ b/datahub-web-react/src/app/entity/shared/EntityContext.ts @@ -19,7 +19,6 @@ export const EntityContext = React.createContext({ entityState: { shouldRefetchContents: false, setShouldRefetchContents: () => {} }, }); -export default EntityContext; export function useEntityContext() { return useContext(EntityContext); @@ -55,7 +54,7 @@ export const useRefetch = () => { return refetch; }; -export const useLineageData = () => { +const useLineageData = () => { const { lineage } = useContext(EntityContext); return lineage; }; diff --git a/datahub-web-react/src/app/entity/shared/EntityDropdown/DomainParentSelect.tsx b/datahub-web-react/src/app/entity/shared/EntityDropdown/DomainParentSelect.tsx index 35b65666000049..02f9333ca3655a 100644 --- a/datahub-web-react/src/app/entity/shared/EntityDropdown/DomainParentSelect.tsx +++ b/datahub-web-react/src/app/entity/shared/EntityDropdown/DomainParentSelect.tsx @@ -21,7 +21,7 @@ const SearchResultContainer = styled.div` `; // filter out entity itself and its children -export function filterResultsForMove(entity: Domain, entityUrn: string) { +function filterResultsForMove(entity: Domain, entityUrn: string) { return ( entity.urn !== entityUrn && entity.__typename === 'Domain' && diff --git a/datahub-web-react/src/app/entity/shared/EntityDropdown/useDeleteGlossaryEntity.tsx b/datahub-web-react/src/app/entity/shared/EntityDropdown/useDeleteGlossaryEntity.tsx deleted file mode 100644 index e08fccc3c830c4..00000000000000 --- a/datahub-web-react/src/app/entity/shared/EntityDropdown/useDeleteGlossaryEntity.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { Modal, message } from 'antd'; -import { useState } from 'react'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useDeleteGlossaryEntityMutation } from '@graphql/glossary.generated'; - -function useDeleteGlossaryEntity() { - const [hasBeenDeleted, setHasBeenDeleted] = useState(false); - const { entityData, urn: entityDataUrn, entityType } = useEntityData(); - const entityRegistry = useEntityRegistry(); - - const [deleteGlossaryEntity] = useDeleteGlossaryEntityMutation(); - - function handleDeleteGlossaryEntity() { - deleteGlossaryEntity({ - variables: { - urn: entityDataUrn, - }, - }) - .catch((e) => { - message.destroy(); - message.error({ content: `Failed to delete: \n ${e.message || ''}`, duration: 3 }); - }) - .finally(() => { - message.loading({ - content: 'Deleting...', - duration: 2, - }); - setTimeout(() => { - setHasBeenDeleted(true); - message.success({ - content: `Deleted ${entityRegistry.getEntityName(entityType)}!`, - duration: 2, - }); - }, 2000); - }); - } - - function onDeleteEntity() { - Modal.confirm({ - title: `Delete ${entityRegistry.getDisplayName(entityType, entityData)}`, - content: `Are you sure you want to remove this ${entityRegistry.getEntityName(entityType)}?`, - onOk() { - handleDeleteGlossaryEntity(); - }, - onCancel() {}, - okText: 'Yes', - maskClosable: true, - closable: true, - }); - } - - return { onDeleteEntity, hasBeenDeleted }; -} - -export default useDeleteGlossaryEntity; diff --git a/datahub-web-react/src/app/entity/shared/EntityGroups.tsx b/datahub-web-react/src/app/entity/shared/EntityGroups.tsx deleted file mode 100644 index bc857048736dca..00000000000000 --- a/datahub-web-react/src/app/entity/shared/EntityGroups.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { Tag } from 'antd'; -import React from 'react'; -import { Link } from 'react-router-dom'; - -import { EmptyValue, GroupsSeeMoreText, Tags, TagsSection } from '@app/entity/shared/SidebarStyledComponents'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { EntityRelationship, EntityType } from '@types'; - -type Props = { - readMore: boolean; - setReadMore: (readMore: boolean) => void; - groupMemberRelationships: Array; -}; - -/** - * EntityGroups- to display the groups category in sidebar section - */ -export default function EntityGroups({ readMore, setReadMore, groupMemberRelationships }: Props) { - const entityRegistry = useEntityRegistry(); - - return ( - - {groupMemberRelationships?.length === 0 && } - {!readMore && - groupMemberRelationships?.slice(0, 2).map((item) => { - if (!item?.entity?.urn) return null; - const entityUrn = entityRegistry.getEntityUrl(EntityType.CorpGroup, item?.entity?.urn); - return ( - - - {entityRegistry.getDisplayName(EntityType.CorpGroup, item.entity)} - - - ); - })} - {readMore && - groupMemberRelationships?.length > 2 && - groupMemberRelationships?.map((item) => { - if (!item?.entity?.urn) return null; - const entityUrn = entityRegistry.getEntityUrl(EntityType.CorpGroup, item.entity.urn); - return ( - - - {entityRegistry.getDisplayName(EntityType.CorpGroup, item.entity)} - - - ); - })} - {!readMore && groupMemberRelationships?.length > 2 && ( - setReadMore(!readMore)}> - {`+${groupMemberRelationships?.length - 2} more`} - - )} - - ); -} diff --git a/datahub-web-react/src/app/entity/shared/EntitySearchInput/EntitySearchInput.tsx b/datahub-web-react/src/app/entity/shared/EntitySearchInput/EntitySearchInput.tsx deleted file mode 100644 index a1a06daec87128..00000000000000 --- a/datahub-web-react/src/app/entity/shared/EntitySearchInput/EntitySearchInput.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { Select, Tag, Tooltip } from 'antd'; -import React from 'react'; - -import { EntitySearchInputResult } from '@app/entity/shared/EntitySearchInput/EntitySearchInputResult'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useGetSearchResultsForMultipleLazyQuery } from '@graphql/search.generated'; -import { EntityType } from '@types'; - -type Props = { - selectedUrns: string[]; - entityTypes: EntityType[]; - placeholder?: string; - mode?: 'multiple' | 'single'; - style?: any; - onChangeSelectedUrns: (newUrns: string[]) => void; -}; - -export const EntitySearchInput = ({ - selectedUrns, - entityTypes, - placeholder, - style, - mode, - onChangeSelectedUrns, -}: Props) => { - const entityRegistry = useEntityRegistry(); - const [searchResources, { data: resourcesSearchData }] = useGetSearchResultsForMultipleLazyQuery(); - const searchResults = resourcesSearchData?.searchAcrossEntities?.searchResults || []; - - const urnToSearchResultEntity = new Map(); - searchResults.forEach((result) => { - urnToSearchResultEntity[result.entity.urn] = { - urn: result.entity.urn, - type: result.entity.type, - displayName: entityRegistry.getDisplayName(result.entity.type, result.entity), - }; - }); - - const onSelect = (newUrn) => { - if (mode === 'single') { - onChangeSelectedUrns([newUrn]); - } else { - const newUrns = [...selectedUrns, newUrn]; - onChangeSelectedUrns(newUrns); - } - }; - - const onDeselect = (urn) => { - if (mode === 'single') { - onChangeSelectedUrns([]); - } else { - onChangeSelectedUrns(selectedUrns.filter((u) => u !== urn)); - } - }; - - const onSearch = (text: string) => { - searchResources({ - variables: { - input: { - types: entityTypes, - query: text, - start: 0, - count: 10, - }, - }, - }); - }; - - return ( - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/EntitySearchInput/EntitySearchInputResult.tsx b/datahub-web-react/src/app/entity/shared/EntitySearchInput/EntitySearchInputResult.tsx deleted file mode 100644 index 29bccfa4437556..00000000000000 --- a/datahub-web-react/src/app/entity/shared/EntitySearchInput/EntitySearchInputResult.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import { IconStyleType } from '@app/entity/Entity'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -type Props = { - entity: any; -}; - -const Container = styled.div` - display: flex; - justify-content: left; - align-items: center; - padding: 12px; -`; - -const IconContainer = styled.div` - margin-right: 8px; -`; - -export const EntitySearchInputResult = ({ entity }: Props) => { - const entityRegistry = useEntityRegistry(); - return ( - - {entityRegistry.getIcon(entity.type, 12, IconStyleType.ACCENT)} - {entityRegistry.getDisplayName(entity.type, entity)} - - ); -}; - -export default EntitySearchInputResult; diff --git a/datahub-web-react/src/app/entity/shared/SidebarStyledComponents.tsx b/datahub-web-react/src/app/entity/shared/SidebarStyledComponents.tsx deleted file mode 100644 index 8d66b17b0b8d71..00000000000000 --- a/datahub-web-react/src/app/entity/shared/SidebarStyledComponents.tsx +++ /dev/null @@ -1,202 +0,0 @@ -import styled from 'styled-components'; - -/** - * Styled Components- Users and Groups Side bar component - * Description: The following styles are used for User and Groups UI for sidebar. - */ - -export const SideBar = styled.div` - padding: 0 0 0 17px; - text-align: center; - - font-style: normal; - font-weight: bold; - height: calc(100vh - 60px); - position: relative; - - &&& .ant-avatar.ant-avatar-icon { - font-size: 46px !important; - } - - .divider-infoSection { - margin: 18px 0px 18px 0; - } - .divider-aboutSection { - margin: 23px 0px 11px 0; - } - .divider-groupsSection { - margin: 23px 0px 11px 0; - } -`; - -export const SideBarSubSection = styled.div` - height: calc(100vh - 135px); - overflow: auto; - padding-right: 18px; - &.fullView { - height: calc(100vh - 70px); - } - &::-webkit-scrollbar { - height: 12px; - width: 1px; - background: #d6d6d6; - } - &::-webkit-scrollbar-thumb { - background: #d6d6d6; - -webkit-border-radius: 1ex; - -webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.75); - } -`; - -export const EmptyValue = styled.div` - &:after { - content: 'None'; - color: #b7b7b7; - font-style: italic; - font-weight: 100; - } -`; - -export const Name = styled.div` - font-size: 20px; - line-height: 28px; - color: #262626; - margin: 13px 0 7px 0; -`; - -export const UserDetails = styled.div` - font-size: 14px; - line-height: 35px; - font-weight: 400; - line-height: 28px; - text-align: center; -`; - -export const TitleRole = styled.div` - font-size: 14px; - line-height: 22px; - color: #595959; - margin-bottom: 7px; -`; - -export const Team = styled.div` - font-size: 12px; - line-height: 20px; - font-weight: 400; - padding-bottom: 10px; - color: #8c8c8c; -`; - -export const SocialDetails = styled.div` - font-size: 12px; - line-height: 20px; - color: #262626; - text-align: left; - margin: 6px 0; -`; - -export const EditButton = styled.div` - bottom: 24px; - position: absolute; - right: 27px; - width: 80%; - left: 50%; - -webkit-transform: translateX(-50%); - -moz-transform: translateX(-50%); - transform: translateX(-50%); - - button { - width: 100%; - font-size: 12px; - line-height: 20px; - color: #262626; - } -`; - -export const AboutSection = styled.div` - text-align: left; - font-weight: bold; - font-size: 14px; - line-height: 22px; - color: #262626; -`; - -export const LocationSection = styled.div` - text-align: left; - font-weight: bold; - font-size: 14px; - line-height: 26px; - color: #262626; -`; - -export const LocationSectionText = styled.div` - text-align: left; - font-weight: normal; - font-size: 14px; - line-height: 26px; - margin-bottom: -10px; - color: #262626; -`; - -export const AboutSectionText = styled.div` - font-size: 12px; - font-weight: 100; - line-height: 15px; - padding: 5px 0; - - &&& .ant-typography { - margin-bottom: 0; - } - &&& .ant-typography-edit-content { - padding-left: 15px; - padding-top: 5px; - } -`; - -export const GroupsSection = styled.div` - text-align: left; - font-weight: bold; - font-size: 14px; - line-height: 22px; - color: #262626; -`; - -export const TagsSection = styled.div` - height: calc(75vh - 460px); - padding: 0px 5px 5px 0; -`; - -export const NoDataFound = styled.span` - font-size: 12px; - color: #262626; - font-weight: 100; -`; - -export const Tags = styled.div` - margin-top: 5px; -`; - -export const GroupsSeeMoreText = styled.span` - font-weight: 500; - font-size: 12px; - line-height: 20px; - color: #1890ff; - cursor: pointer; -`; - -export const DisplayCount = styled.span` - font-family: Manrope; - font-style: normal; - font-weight: 500; - font-size: 12px; - line-height: 20px; - color: #8c8c8c; -`; - -export const GroupSectionTitle = styled.span` - margin-right: 8px; -`; - -export const GroupSectionHeader = styled.div` - padding-bottom: 12px; -`; diff --git a/datahub-web-react/src/app/entity/shared/components/legacy/MarkdownViewer.tsx b/datahub-web-react/src/app/entity/shared/components/legacy/MarkdownViewer.tsx index ab52706eee32c8..57bc3ab91317fa 100644 --- a/datahub-web-react/src/app/entity/shared/components/legacy/MarkdownViewer.tsx +++ b/datahub-web-react/src/app/entity/shared/components/legacy/MarkdownViewer.tsx @@ -73,7 +73,7 @@ export const MarkdownView = styled(MDEditor.Markdown)` font-weight: 400; `; -export type Props = { +type Props = { source: string; limit?: number; // eslint-disable-next-line react/no-unused-prop-types diff --git a/datahub-web-react/src/app/entity/shared/components/legacy/Properties.tsx b/datahub-web-react/src/app/entity/shared/components/legacy/Properties.tsx index 075c458e0a49c9..78e37c2de082af 100644 --- a/datahub-web-react/src/app/entity/shared/components/legacy/Properties.tsx +++ b/datahub-web-react/src/app/entity/shared/components/legacy/Properties.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { StringMapEntry } from '@types'; -export type Props = { +type Props = { properties: StringMapEntry[]; }; diff --git a/datahub-web-react/src/app/entity/shared/components/legacy/UpdatableDescription.tsx b/datahub-web-react/src/app/entity/shared/components/legacy/UpdatableDescription.tsx deleted file mode 100644 index 70eb7a1ff78765..00000000000000 --- a/datahub-web-react/src/app/entity/shared/components/legacy/UpdatableDescription.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { FetchResult, MutationFunctionOptions } from '@apollo/client'; -import { Tag, message } from 'antd'; -import React, { useState } from 'react'; -import styled from 'styled-components'; - -import analytics, { EntityActionType, EventType } from '@app/analytics'; -import UpdateDescriptionModal from '@app/entity/shared/components/legacy/DescriptionModal'; -import MarkdownViewer from '@app/entity/shared/components/legacy/MarkdownViewer'; - -import { EntityType } from '@types'; - -const DescriptionText = styled(MarkdownViewer)` - ${(props) => (props.isCompact ? 'max-width: 377px;' : '')}; -`; - -const AddNewDescription = styled(Tag)` - cursor: pointer; -`; - -export type Props = { - isCompact?: boolean; - updateEntity: (options?: MutationFunctionOptions | undefined) => Promise; - updatedDescription?: string | null; - originalDescription?: string | null; - entityType: EntityType; - urn: string; -}; - -export default function UpdatableDescription({ - isCompact, - updateEntity, - updatedDescription, - originalDescription, - entityType, - urn, -}: Props) { - const [showAddDescModal, setShowAddDescModal] = useState(false); - const onSubmit = async (description: string | null) => { - message.loading({ content: 'Updating...' }); - try { - await updateEntity({ - variables: { urn, input: { editableProperties: { description: description || '' } } }, - }); - message.destroy(); - analytics.event({ - type: EventType.EntityActionEvent, - actionType: EntityActionType.UpdateDescription, - entityType, - entityUrn: urn, - }); - message.success({ content: 'Updated!', duration: 2 }); - } catch (e: unknown) { - message.destroy(); - if (e instanceof Error) message.error({ content: `Update Failed! \n ${e.message || ''}`, duration: 2 }); - } - setShowAddDescModal(false); - }; - - return ( - <> - {updatedDescription || originalDescription ? ( - <> - setShowAddDescModal(true)} - /> - {showAddDescModal && ( - setShowAddDescModal(false)} - onSubmit={onSubmit} - original={originalDescription || ''} - description={updatedDescription || ''} - /> - )} - - ) : ( - <> - setShowAddDescModal(true)}> - + Add Description - - {showAddDescModal && ( - setShowAddDescModal(false)} - onSubmit={onSubmit} - isAddDesc - /> - )} - - )} - - ); -} diff --git a/datahub-web-react/src/app/entity/shared/components/styled/SeeMore.tsx b/datahub-web-react/src/app/entity/shared/components/styled/SeeMore.tsx deleted file mode 100644 index 47c4ef085af3c0..00000000000000 --- a/datahub-web-react/src/app/entity/shared/components/styled/SeeMore.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { Button } from 'antd'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entity/shared/constants'; - -export const SeeMore = styled(Button)` - margin-top: -20px; - background-color: ${ANTD_GRAY[4]}; - padding: 8px; - border: none; - line-height: 8px; - height: 20px; -`; diff --git a/datahub-web-react/src/app/entity/shared/components/styled/StripMarkdownText.tsx b/datahub-web-react/src/app/entity/shared/components/styled/StripMarkdownText.tsx index 9ed9c8fbece407..1ba17a6e7a3521 100644 --- a/datahub-web-react/src/app/entity/shared/components/styled/StripMarkdownText.tsx +++ b/datahub-web-react/src/app/entity/shared/components/styled/StripMarkdownText.tsx @@ -11,7 +11,7 @@ const RemoveMarkdownContainer = styled.div<{ shouldWrap: boolean }>` text-overflow: ellipsis; `; -export type Props = { +type Props = { children: string | undefined | null; readMore?: JSX.Element; suffix?: JSX.Element; diff --git a/datahub-web-react/src/app/entity/shared/components/styled/StyledButton.tsx b/datahub-web-react/src/app/entity/shared/components/styled/StyledButton.tsx deleted file mode 100644 index b3e744a5aac728..00000000000000 --- a/datahub-web-react/src/app/entity/shared/components/styled/StyledButton.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { Button } from 'antd'; -import styled from 'styled-components'; - -export default styled(Button)` - padding-top: 5px; - padding-bottom: 5px; - padding-right: 16px; - padding-left: 16px; - box-shadow: 0px 0px 4px 0px #0000001a; - border: 1px solid #d9d9d9; - - font-size: 12px; - font-weight: 500; - line-height: 20px; - vertical-align: top; - border-radius: 5px; -`; diff --git a/datahub-web-react/src/app/entity/shared/components/styled/StyledMDEditor.tsx b/datahub-web-react/src/app/entity/shared/components/styled/StyledMDEditor.tsx deleted file mode 100644 index ca44fa319bf809..00000000000000 --- a/datahub-web-react/src/app/entity/shared/components/styled/StyledMDEditor.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import MDEditor from '@uiw/react-md-editor'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entity/shared/constants'; - -export default styled(MDEditor)` - height: calc(100% - 46px) !important; - z-index: 0; - box-shadow: none; - border-radius: 0; - font-weight: 400; - .w-md-editor-toolbar { - border-color: ${ANTD_GRAY[4]}; - background: white; - padding: 0 20px; - height: 46px !important; - li { - button { - height: 100%; - margin: 0 5px; - } - svg { - width: 16px; - height: 16px; - } - &.active > button { - color: ${(props) => props.theme.styles['primary-color']}; - background-color: ${ANTD_GRAY[3]}; - } - } - } - .w-md-editor-preview { - box-shadow: inset 1px 0 0 0 ${ANTD_GRAY[4]}; - } - .w-md-editor-content { - height: calc(100% - 46px) !important; - } -`; diff --git a/datahub-web-react/src/app/entity/shared/components/styled/search/EmbeddedListSearch.tsx b/datahub-web-react/src/app/entity/shared/components/styled/search/EmbeddedListSearch.tsx index a64b43280b2809..903f797d0afeff 100644 --- a/datahub-web-react/src/app/entity/shared/components/styled/search/EmbeddedListSearch.tsx +++ b/datahub-web-react/src/app/entity/shared/components/styled/search/EmbeddedListSearch.tsx @@ -50,7 +50,7 @@ function useWrappedSearchResults(params: GetSearchResultsParams) { } // the addFixedQuery checks and generate the query as per params pass to embeddedListSearch -export const addFixedQuery = (baseQuery: string, fixedQuery: string, emptyQuery: string) => { +const addFixedQuery = (baseQuery: string, fixedQuery: string, emptyQuery: string) => { let finalQuery = ``; if (baseQuery && fixedQuery) { finalQuery = baseQuery.includes(fixedQuery) ? `${baseQuery}` : `(*${baseQuery}*) AND (${fixedQuery})`; @@ -66,7 +66,7 @@ export const addFixedQuery = (baseQuery: string, fixedQuery: string, emptyQuery: // Simply remove the fields that were marked as fixed from the facets that the server // responds. -export const removeFixedFiltersFromFacets = (fixedFilters: FilterSet, facets: FacetMetadata[]) => { +const removeFixedFiltersFromFacets = (fixedFilters: FilterSet, facets: FacetMetadata[]) => { const fixedFields = fixedFilters.filters.map((filter) => filter.field); return facets.filter((facet) => !fixedFields.includes(facet.field)); }; diff --git a/datahub-web-react/src/app/entity/shared/components/styled/search/action/ActionDropdown.tsx b/datahub-web-react/src/app/entity/shared/components/styled/search/action/ActionDropdown.tsx index d64cd1758511b4..89b0dab81265d9 100644 --- a/datahub-web-react/src/app/entity/shared/components/styled/search/action/ActionDropdown.tsx +++ b/datahub-web-react/src/app/entity/shared/components/styled/search/action/ActionDropdown.tsx @@ -30,7 +30,7 @@ const DropdownWrapper = styled.div<{ margin-right: 12px; `; -export type Action = { +type Action = { title: React.ReactNode; onClick: () => void; }; diff --git a/datahub-web-react/src/app/entity/shared/components/styled/search/downloadAsCsvUtil.ts b/datahub-web-react/src/app/entity/shared/components/styled/search/downloadAsCsvUtil.ts index 5232bfe7e15651..7a230480c8cd4e 100644 --- a/datahub-web-react/src/app/entity/shared/components/styled/search/downloadAsCsvUtil.ts +++ b/datahub-web-react/src/app/entity/shared/components/styled/search/downloadAsCsvUtil.ts @@ -33,7 +33,7 @@ export const getSearchCsvDownloadHeader = (sampleResult?: SearchResultInterface) return result; }; -export const transformGenericEntityPropertiesToCsvRow = ( +const transformGenericEntityPropertiesToCsvRow = ( entityRegistry: EntityRegistry, properties: GenericEntityProperties | null, entityUrl: string, diff --git a/datahub-web-react/src/app/entity/shared/constants.ts b/datahub-web-react/src/app/entity/shared/constants.ts index ff6adf11d1690f..172ebac501db05 100644 --- a/datahub-web-react/src/app/entity/shared/constants.ts +++ b/datahub-web-react/src/app/entity/shared/constants.ts @@ -88,7 +88,7 @@ export const EMPTY_MESSAGES = { }, }; -export const ELASTIC_MAX_COUNT = 10000; +const ELASTIC_MAX_COUNT = 10000; export const getElasticCappedTotalValueText = (count: number) => { if (count === ELASTIC_MAX_COUNT) { @@ -112,7 +112,7 @@ export const DEFAULT_SYSTEM_ACTOR_URNS = ['urn:li:corpuser:__datahub_system', 'u export const VIEW_ENTITY_PAGE = 'VIEW_ENTITY_PAGE'; // only values for Domain Entity for custom configurable default tab -export enum EntityProfileTab { +enum EntityProfileTab { DOMAIN_ENTITIES_TAB = 'DOMAIN_ENTITIES_TAB', DOCUMENTATION_TAB = 'DOCUMENTATION_TAB', DATA_PRODUCTS_TAB = 'DATA_PRODUCTS_TAB', diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/EntityProfile.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/EntityProfile.tsx index 0855e31bb39faf..c37bbc72e694c1 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/EntityProfile.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/EntityProfile.tsx @@ -138,7 +138,7 @@ const defaultTabDisplayConfig = { enabled: (_, _1) => true, }; -export const DEFAULT_SIDEBAR_SECTION = { +const DEFAULT_SIDEBAR_SECTION = { visible: (_, _1) => true, }; diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/header/EntityCount.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/header/EntityCount.tsx index b30da68212648c..d3cfc24b794221 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/header/EntityCount.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/header/EntityCount.tsx @@ -4,7 +4,7 @@ import styled from 'styled-components'; import { ANTD_GRAY } from '@app/entity/shared/constants'; -export const EntityCountText = styled(Typography.Text)` +const EntityCountText = styled(Typography.Text)` display: inline-block; font-size: 12px; line-height: 20px; diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/header/EntityName.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/header/EntityName.tsx index ab7b29b6fcdafc..d9cdec0a2790a7 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/header/EntityName.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/header/EntityName.tsx @@ -9,7 +9,7 @@ import { useEntityRegistry } from '@app/useEntityRegistry'; import { useUpdateNameMutation } from '@graphql/mutations.generated'; -export const EntityTitle = styled(Typography.Title)` +const EntityTitle = styled(Typography.Title)` &&& { margin-bottom: 0; word-break: break-all; diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/header/PlatformContent/DatasetLink.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/header/PlatformContent/DatasetLink.tsx index 61b62308df5674..e31b3cf37e444f 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/header/PlatformContent/DatasetLink.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/header/PlatformContent/DatasetLink.tsx @@ -15,7 +15,7 @@ const DatasetText = styled(Typography.Text)` color: ${ANTD_GRAY[7]}; `; -export const DatasetIcon = styled.span` +const DatasetIcon = styled.span` color: ${ANTD_GRAY[7]}; margin-right: 4px; font-size: 12px; diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/header/PlatformContent/ParentNodesView.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/header/PlatformContent/ParentNodesView.tsx index 6daff61126f447..fb50d2bc3d0c2d 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/header/PlatformContent/ParentNodesView.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/header/PlatformContent/ParentNodesView.tsx @@ -55,7 +55,7 @@ interface Props { parentNodes?: GlossaryNode[] | null; } -export default function ParentNodesView({ parentNodes }: Props) { +function ParentNodesView({ parentNodes }: Props) { const entityRegistry = useEntityRegistry(); const { contentRef, isContentTruncated } = useContentTruncation(parentNodes); diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/header/PlatformContent/PlatformContentView.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/header/PlatformContent/PlatformContentView.tsx index df12a6b3018ca3..ff0ebfb04d00df 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/header/PlatformContent/PlatformContentView.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/header/PlatformContent/PlatformContentView.tsx @@ -17,20 +17,20 @@ import { useIsShowSeparateSiblingsEnabled } from '@app/useAppConfig'; import { Container, Dataset, Entity } from '@types'; -export const LogoIcon = styled.span` +const LogoIcon = styled.span` display: flex; gap: 4px; margin-right: 8px; `; -export const PreviewImage = styled(Image)` +const PreviewImage = styled(Image)` max-height: 17px; width: auto; object-fit: contain; background-color: transparent; `; -export const PlatformContentWrapper = styled.div` +const PlatformContentWrapper = styled.div` display: flex; align-items: center; margin: 0 8px 6px 0; @@ -38,7 +38,7 @@ export const PlatformContentWrapper = styled.div` flex: 1; `; -export const PlatformText = styled(Typography.Text)` +const PlatformText = styled(Typography.Text)` font-size: 12px; line-height: 20px; font-weight: 700; diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/header/utils.ts b/datahub-web-react/src/app/entity/shared/containers/profile/header/utils.ts index 85a4624941b444..22c9d1732fa13e 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/header/utils.ts +++ b/datahub-web-react/src/app/entity/shared/containers/profile/header/utils.ts @@ -4,7 +4,7 @@ import EntityRegistry from '@src/app/entity/EntityRegistry'; import { EntityType, StructuredPropertiesEntry } from '@types'; -export function getDisplayedEntityType( +function getDisplayedEntityType( entityData: GenericEntityProperties | null, entityRegistry: EntityRegistry, entityType: EntityType, @@ -17,7 +17,7 @@ export function getDisplayedEntityType( ); } -export function getEntityPlatforms(entityType: EntityType | null, entityData: GenericEntityProperties | null) { +function getEntityPlatforms(entityType: EntityType | null, entityData: GenericEntityProperties | null) { const platform = entityType === EntityType.SchemaField ? entityData?.parent?.platform : entityData?.platform; const platforms = entityType === EntityType.SchemaField ? entityData?.parent?.siblingPlatforms : entityData?.siblingPlatforms; diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection.tsx index 66c05720f4b034..f68fc60fa00206 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection.tsx @@ -55,4 +55,3 @@ export const SidebarAboutSection = ({ properties, readOnly }: Props) => { ); }; -export default SidebarAboutSection; diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Container/ContainerSelectModal.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Container/ContainerSelectModal.tsx index 8d9ddf8c676b4f..3c024af733594c 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Container/ContainerSelectModal.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Container/ContainerSelectModal.tsx @@ -30,7 +30,7 @@ const StyleTag = styled(Tag)` align-items: center; `; -export const PreviewImage = styled.img` +const PreviewImage = styled.img` max-height: 18px; width: auto; object-fit: contain; diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/DataProduct/DataProductSection.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/DataProduct/DataProductSection.tsx deleted file mode 100644 index 305c896b2c5029..00000000000000 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/DataProduct/DataProductSection.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import { EditOutlined } from '@ant-design/icons'; -import { Button, Modal, Typography, message } from 'antd'; -import React, { useEffect, useState } from 'react'; -import styled from 'styled-components'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { EMPTY_MESSAGES } from '@app/entity/shared/constants'; -import SetDataProductModal from '@app/entity/shared/containers/profile/sidebar/DataProduct/SetDataProductModal'; -import { SidebarHeader } from '@app/entity/shared/containers/profile/sidebar/SidebarHeader'; -import { DataProductLink } from '@app/shared/tags/DataProductLink'; - -import { useBatchSetDataProductMutation } from '@graphql/dataProduct.generated'; -import { DataProduct } from '@types'; - -const EmptyText = styled(Typography.Paragraph)` - &&& { - border-top: none; - padding-top: 0; - } -`; - -interface Props { - readOnly?: boolean; -} - -export default function DataProductSection({ readOnly }: Props) { - const [isModalVisible, setIsModalVisible] = useState(false); - const { entityData, urn } = useEntityData(); - const [batchSetDataProductMutation] = useBatchSetDataProductMutation(); - const [dataProduct, setDataProduct] = useState(null); - const dataProductRelationships = entityData?.dataProduct?.relationships; - const siblingUrns: string[] = - entityData?.siblingsSearch?.searchResults?.map((sibling) => sibling.entity.urn || '') || []; - - useEffect(() => { - if (dataProductRelationships && dataProductRelationships.length > 0) { - setDataProduct(dataProductRelationships[0].entity as DataProduct); - } - }, [dataProductRelationships]); - - function removeDataProduct() { - batchSetDataProductMutation({ variables: { input: { resourceUrns: [urn, ...siblingUrns] } } }) - .then(() => { - message.success({ content: 'Removed Data Product.', duration: 2 }); - setDataProduct(null); - }) - .catch((e: unknown) => { - message.destroy(); - if (e instanceof Error) { - message.error({ - content: `Failed to remove data product. An unknown error occurred.`, - duration: 3, - }); - } - }); - } - - const onRemoveDataProduct = () => { - Modal.confirm({ - title: `Confirm Data Product Removal`, - content: `Are you sure you want to remove this data product?`, - onOk() { - removeDataProduct(); - }, - onCancel() {}, - okText: 'Yes', - maskClosable: true, - closable: true, - }); - }; - - return ( -
- - {dataProduct && ( - { - e.preventDefault(); - onRemoveDataProduct(); - }} - fontSize={12} - /> - )} - {!dataProduct && ( - <> - - {EMPTY_MESSAGES.dataProduct.title}. {EMPTY_MESSAGES.dataProduct.description} - - {!readOnly && ( - - )} - - )} - {isModalVisible && ( - setIsModalVisible(false)} - setDataProduct={setDataProduct} - /> - )} -
- ); -} diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Dataset/View/SidebarViewDefinitionSection.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Dataset/View/SidebarViewDefinitionSection.tsx deleted file mode 100644 index a52e2cb599634e..00000000000000 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Dataset/View/SidebarViewDefinitionSection.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { Button, Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { useBaseEntity, useRouteToTab } from '@app/entity/shared/EntityContext'; -import { InfoItem } from '@app/entity/shared/components/styled/InfoItem'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { SidebarHeader } from '@app/entity/shared/containers/profile/sidebar/SidebarHeader'; - -import { GetDatasetQuery } from '@graphql/dataset.generated'; - -const HeaderInfoBody = styled(Typography.Text)` - font-size: 16px; - color: ${ANTD_GRAY[9]}; -`; - -const HeaderContainer = styled.div` - justify-content: space-between; - display: flex; -`; - -const StatsButton = styled(Button)` - margin-top: -4px; -`; - -const InfoRow = styled.div` - padding-top: 12px; - padding-bottom: 12px; -`; - -const INFO_ITEM_WIDTH_PX = '150px'; - -export const SidebarViewDefinitionSection = () => { - const baseEntity = useBaseEntity(); - - const materialized = baseEntity?.dataset?.viewProperties?.materialized; - const language = baseEntity?.dataset?.viewProperties?.language || 'UNKNOWN'; - - const routeToTab = useRouteToTab(); - - return ( -
- - - routeToTab({ tabName: 'View Definition' })} type="link"> - See View Definition > - - - - - {materialized ? 'True' : 'False'} - - - {language.toUpperCase()} - - -
- ); -}; diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection.tsx deleted file mode 100644 index 631671d468a6d0..00000000000000 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { EditOutlined } from '@ant-design/icons'; -import { Button, Modal, Typography, message } from 'antd'; -import React, { useState } from 'react'; -import styled from 'styled-components'; - -import { useEntityData, useMutationUrn, useRefetch } from '@app/entity/shared/EntityContext'; -import { EMPTY_MESSAGES } from '@app/entity/shared/constants'; -import { SetDomainModal } from '@app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal'; -import { SidebarHeader } from '@app/entity/shared/containers/profile/sidebar/SidebarHeader'; -import { ENTITY_PROFILE_DOMAINS_ID } from '@app/onboarding/config/EntityProfileOnboardingConfig'; -import { DomainLink } from '@app/shared/tags/DomainLink'; - -import { useUnsetDomainMutation } from '@graphql/mutations.generated'; - -const StyledButton = styled(Button)` - display: block; - margin-bottom: 8px; -`; - -const ContentWrapper = styled.div<{ displayInline: boolean }>` - ${(props) => - props.displayInline && - ` - display: flex; - align-items: center; - `} -`; - -interface PropertiesProps { - updateOnly?: boolean; -} - -interface Props { - readOnly?: boolean; - properties?: PropertiesProps; -} - -export const SidebarDomainSection = ({ readOnly, properties }: Props) => { - const updateOnly = properties?.updateOnly; - const { entityData } = useEntityData(); - const refetch = useRefetch(); - const urn = useMutationUrn(); - const [unsetDomainMutation] = useUnsetDomainMutation(); - const [showModal, setShowModal] = useState(false); - const domain = entityData?.domain?.domain; - - const removeDomain = (urnToRemoveFrom) => { - unsetDomainMutation({ variables: { entityUrn: urnToRemoveFrom } }) - .then(() => { - message.success({ content: 'Removed Domain.', duration: 2 }); - refetch?.(); - }) - .catch((e: unknown) => { - message.destroy(); - if (e instanceof Error) { - message.error({ content: `Failed to remove domain: \n ${e.message || ''}`, duration: 3 }); - } - }); - }; - - const onRemoveDomain = (urnToRemoveFrom) => { - Modal.confirm({ - title: `Confirm Domain Removal`, - content: `Are you sure you want to remove this domain?`, - onOk() { - removeDomain(urnToRemoveFrom); - }, - onCancel() {}, - okText: 'Yes', - maskClosable: true, - closable: true, - }); - }; - - return ( -
-
- - - {domain && ( - { - e.preventDefault(); - onRemoveDomain(entityData?.domain?.associatedUrn); - }} - fontSize={12} - /> - )} - {(!domain || !!updateOnly) && ( - <> - {!domain && ( - - {EMPTY_MESSAGES.domain.title}. {EMPTY_MESSAGES.domain.description} - - )} - {!readOnly && ( - setShowModal(true)}> - Set Domain - - )} - - )} - - {showModal && ( - { - setShowModal(false); - }} - /> - )} -
-
- ); -}; diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/FormInfo/utils.ts b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/FormInfo/utils.ts index 44447ddd7fe250..1d97ca2e8f6df7 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/FormInfo/utils.ts +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/FormInfo/utils.ts @@ -44,7 +44,7 @@ function getCompletedFieldPromptsFromPrompt(prompt: FormPromptAssociation, relev * Note: we pass in an optional set of prompt IDs to choose from in order to get completed * field prompts for a certain set of entity prompts id we choose. */ -export function getCompletedFieldPromptsFromForm( +function getCompletedFieldPromptsFromForm( formAssociation: FormAssociation, relevantFieldFormPromptIds?: Set, ) { @@ -69,7 +69,7 @@ export function getCompletedFieldPromptsFromForm( * For each prompt, get their list of completedFieldPrompts * Takes in an optional list of relevant prompt IDs to filter results down. */ -export function getCompletedFieldPromptAssociations( +function getCompletedFieldPromptAssociations( entityData: GenericEntityProperties | null, relevantFieldFormPromptIds?: Set, ) { @@ -94,7 +94,7 @@ export function getCompletedFieldPromptAssociations( * For a given form, gets a list of the completed field prompt associations which live * as children to top level prompt associations for each schema field. */ -export function getCompletedFieldPromptAssociationsForForm( +function getCompletedFieldPromptAssociationsForForm( formUrn: string, entityData: GenericEntityProperties | null, relevantFieldFormPromptIds?: Set, @@ -254,12 +254,12 @@ export function getFormVerification(formUrn: string, entityData: GenericEntityPr return entityData?.forms?.verifications?.find((verification) => verification.form.urn === formUrn); } -export function getVerificationForms(entityData: GenericEntityProperties | null) { +function getVerificationForms(entityData: GenericEntityProperties | null) { const formAssociations = getFormAssociations(entityData); return formAssociations.filter((formAssociation) => formAssociation.form.info.type === FormType.Verification); } -export function areAllFormsVerified(formAssociations: FormAssociation[], entityData: GenericEntityProperties | null) { +function areAllFormsVerified(formAssociations: FormAssociation[], entityData: GenericEntityProperties | null) { return formAssociations.every((formAssociation) => !!getFormVerification(formAssociation.form.urn, entityData)); } @@ -316,7 +316,7 @@ export function getVerificationAuditStamp(entityData: GenericEntityProperties | return getMostRecentVerificationAuditStamp(entityData); } -export function getBulkByQuestionPrompts(formUrn: string, entityData: GenericEntityProperties | null) { +function getBulkByQuestionPrompts(formUrn: string, entityData: GenericEntityProperties | null) { const formAssociation = getFormAssociation(formUrn, entityData); return ( formAssociation?.form?.info?.prompts?.filter((prompt) => !SCHEMA_FIELD_PROMPT_TYPES.includes(prompt.type)) || [] diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/HeaderAndTabs.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/HeaderAndTabs.tsx deleted file mode 100644 index e1fa4129c2df1e..00000000000000 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/HeaderAndTabs.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import React, { useCallback, useState } from 'react'; -import styled from 'styled-components'; - -let isResizing = false; - -export type Props = { - children: React.ReactNode; -}; - -const ResizableDiv = styled.div<{ width }>` - width: ${(props) => props.width}px; - min-width: 440px; - display: flex; - justify-content: space-between; -`; - -const HeaderAndTabs = ({ children }: Props) => { - const initialWidth = 70 / (100 / document.documentElement.clientWidth); - - const [sidebarWidth, setSidebarWidth] = useState(initialWidth); - - const cbHandleMouseMove = useCallback((e) => { - const offsetRight = e.clientX - document.body.offsetLeft; - - const minWidthVw = 70; - const minWidthPx = minWidthVw / (100 / document.documentElement.clientWidth); - - const maxWidthVw = 98; - const maxWidthPx = maxWidthVw / (100 / document.documentElement.clientWidth); - - if (offsetRight > minWidthPx && offsetRight < maxWidthPx) { - setSidebarWidth(offsetRight); - } - }, []); - - const cbHandleMouseUp = useCallback( - (_) => { - if (!isResizing) { - return; - } - isResizing = false; - document.removeEventListener('mousemove', cbHandleMouseMove); - document.removeEventListener('mouseup', cbHandleMouseUp); - }, - [cbHandleMouseMove], - ); - - function handleMousedown(e) { - e.stopPropagation(); - e.preventDefault(); - // we will only add listeners when needed, and remove them afterward - document.addEventListener('mousemove', cbHandleMouseMove); - document.addEventListener('mouseup', cbHandleMouseUp); - isResizing = true; - } - - return ( - - {children} - {/* eslint-disable jsx-a11y/no-static-element-interactions */} -
- header -
-
- ); -}; - -export default HeaderAndTabs; diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/LdapFormItem.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/LdapFormItem.tsx deleted file mode 100644 index c0c1ed4f1653dd..00000000000000 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/LdapFormItem.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { AutoComplete, Form } from 'antd'; -import { FormInstance } from 'antd/es/form/Form'; -import React, { useState } from 'react'; - -import { useGetAutoCompleteResultsLazyQuery } from '@graphql/search.generated'; -import { EntityType } from '@types'; - -const OWNER_SEARCH_PLACEHOLDER = 'Search an LDAP'; - -type Props = { - form: FormInstance; -}; - -export const LdapFormItem = ({ form }: Props) => { - const [getOwnerAutoCompleteResults, { data: searchOwnerSuggestionsData }] = useGetAutoCompleteResultsLazyQuery(); - const [ownerQuery, setOwnerQuery] = useState(''); - - const onSelectSuggestion = (ldap: string) => { - setOwnerQuery(ldap); - }; - - const onChangeOwnerQuery = async (query: string) => { - const row = await form.validateFields(); - - if (query && query.trim() !== '') { - getOwnerAutoCompleteResults({ - variables: { - input: { - type: row.type, - query, - field: row.type === EntityType.CorpUser ? 'ldap' : 'name', - }, - }, - }); - } - setOwnerQuery(query); - }; - - return ( - - ({ - value: suggestion, - }))) || - [] - } - value={ownerQuery} - onSelect={onSelectSuggestion} - onSearch={onChangeOwnerQuery} - placeholder={OWNER_SEARCH_PLACEHOLDER} - /> - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/ownershipUtils.ts b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/ownershipUtils.ts index 9c617cb166f64e..9f381de4b80dbb 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/ownershipUtils.ts +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/ownershipUtils.ts @@ -4,7 +4,7 @@ import { OwnershipType, OwnershipTypeEntity } from '@types'; * A mapping from OwnershipType to it's display name & description. In the future, * we intend to make this configurable. */ -export const OWNERSHIP_DISPLAY_TYPES = [ +const OWNERSHIP_DISPLAY_TYPES = [ { type: OwnershipType.TechnicalOwner, name: 'Technical Owner', diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/ProfileSidebar.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/ProfileSidebar.tsx index 625d5ac9d33d41..14eebddd5552e0 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/ProfileSidebar.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/ProfileSidebar.tsx @@ -5,8 +5,8 @@ import { EntitySidebar } from '@app/entity/shared/containers/profile/sidebar/Ent import { ProfileSidebarResizer } from '@app/entity/shared/containers/profile/sidebar/ProfileSidebarResizer'; import { EntitySidebarSection } from '@app/entity/shared/types'; -export const MAX_SIDEBAR_WIDTH = 800; -export const MIN_SIDEBAR_WIDTH = 200; +const MAX_SIDEBAR_WIDTH = 800; +const MIN_SIDEBAR_WIDTH = 200; const Sidebar = styled.div<{ $width: number; backgroundColor?: string }>` max-height: 100%; diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Recommendations/SidebarEntityRecommendations.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Recommendations/SidebarEntityRecommendations.tsx deleted file mode 100644 index d8fd8a637eadb7..00000000000000 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Recommendations/SidebarEntityRecommendations.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import { SidebarHeader } from '@app/entity/shared/containers/profile/sidebar/SidebarHeader'; -import { RecommendationModule } from '@app/recommendations/RecommendationModule'; -import { RecommendationDisplayType } from '@app/recommendations/types'; - -import { useListRecommendationsQuery } from '@graphql/recommendations.generated'; -import { EntityType, RecommendationModule as RecommendationModuleType, ScenarioType } from '@types'; - -const RecommendationsContainer = styled.div``; - -const RecommendationContainer = styled.div` - margin-bottom: 20px; -`; - -export const SidebarEntityRecommendations = ({ - userUrn, - entityUrn, - entityType, -}: { - userUrn: string; - entityUrn: string; - entityType: EntityType; -}) => { - const scenario = ScenarioType.EntityProfile; - const { data } = useListRecommendationsQuery({ - variables: { - input: { - userUrn, - requestContext: { - scenario, - entityRequestContext: { - urn: entityUrn, - type: entityType, - }, - }, - limit: 3, - }, - }, - }); - const recommendationModules = data?.listRecommendations?.modules; - return ( - - {recommendationModules && - recommendationModules.map((module) => ( - - - - - ))} - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Recommendations/SidebarRecommendationsSection.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Recommendations/SidebarRecommendationsSection.tsx deleted file mode 100644 index a5b4bbb571a43d..00000000000000 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Recommendations/SidebarRecommendationsSection.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import { useUserContext } from '@app/context/useUserContext'; -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { SidebarEntityRecommendations } from '@app/entity/shared/containers/profile/sidebar/Recommendations/SidebarEntityRecommendations'; - -const RecommendationsContainer = styled.div``; - -export const SidebarRecommendationsSection = () => { - const { urn, entityType } = useEntityData(); - const authenticatedUserUrn = useUserContext()?.user?.urn; - return ( - - {authenticatedUserUrn && ( - - )} - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/SidebarSiblingsSection.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/SidebarSiblingsSection.tsx deleted file mode 100644 index d4b18b1c64fef9..00000000000000 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/SidebarSiblingsSection.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import { useDataNotCombinedWithSiblings, useEntityData } from '@app/entity/shared/EntityContext'; -import { SidebarHeader } from '@app/entity/shared/containers/profile/sidebar/SidebarHeader'; -import { - SEPARATE_SIBLINGS_URL_PARAM, - stripSiblingsFromEntity, - useIsSeparateSiblingsMode, -} from '@app/entity/shared/siblingUtils'; -import { CompactEntityNameList } from '@app/recommendations/renderer/component/CompactEntityNameList'; -import { useIsShowSeparateSiblingsEnabled } from '@app/useAppConfig'; - -import { GetDatasetQuery } from '@graphql/dataset.generated'; -import { Dataset, Entity } from '@types'; - -const EntityListContainer = styled.div` - margin-left: -8px; -`; - -export const SidebarSiblingsSection = () => { - const { entityData } = useEntityData(); - const dataNotCombinedWithSiblings = useDataNotCombinedWithSiblings(); - - const showSeparateSiblings = useIsShowSeparateSiblingsEnabled(); - const isHideSiblingMode = useIsSeparateSiblingsMode(); - - if (!entityData) { - return <>; - } - - // showSeparateSiblings disables the combined view, but with this flag on we show siblings in the sidebar to navigate to them - if (!showSeparateSiblings && isHideSiblingMode) { - return ( -
- - - - -
- ); - } - - const siblingEntities = entityData?.siblingsSearch?.searchResults?.map((r) => r.entity) || []; - const entityDataWithoutSiblings = stripSiblingsFromEntity(dataNotCombinedWithSiblings.dataset); - - const allSiblingsInGroup = showSeparateSiblings - ? (siblingEntities as Dataset[]) - : ([...siblingEntities, entityDataWithoutSiblings] as Dataset[]); - - const allSiblingsInGroupThatExist = allSiblingsInGroup.filter((sibling) => sibling.exists); - - if (!allSiblingsInGroupThatExist.length) { - return <>; - } - - // you are always going to be in the sibling group, so if the sibling group is just you do not render. - // The less than case is likely not neccessary but just there as a safety case for unexpected scenarios - if (!showSeparateSiblings && allSiblingsInGroupThatExist.length <= 1) { - return <>; - } - - return ( -
- - - - -
- ); -}; diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/utils.ts b/datahub-web-react/src/app/entity/shared/containers/profile/utils.ts index d515b05e9f8f9d..3a494b9f2cd1ad 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/utils.ts +++ b/datahub-web-react/src/app/entity/shared/containers/profile/utils.ts @@ -105,7 +105,7 @@ export function getEntityPath( }${tabParamsString}`; } -export function useEntityPath(entityType: EntityType, urn: string, tabName?: string, tabParams?: Record) { +function useEntityPath(entityType: EntityType, urn: string, tabName?: string, tabParams?: Record) { const isLineageMode = useIsLineageMode(); const isHideSiblingMode = useIsSeparateSiblingsMode(); const entityRegistry = useEntityRegistry(); diff --git a/datahub-web-react/src/app/entity/shared/embed/EmbeddedHeader.tsx b/datahub-web-react/src/app/entity/shared/embed/EmbeddedHeader.tsx deleted file mode 100644 index 5e5daac2af5d7d..00000000000000 --- a/datahub-web-react/src/app/entity/shared/embed/EmbeddedHeader.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import { ArrowRightOutlined } from '@ant-design/icons'; -import { Image, Typography } from 'antd'; -import Link from 'antd/lib/typography/Link'; -import React from 'react'; -import styled, { useTheme } from 'styled-components/macro'; - -import { EventType } from '@app/analytics'; -import analytics from '@app/analytics/analytics'; -import { IconStyleType } from '@app/entity/Entity'; -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { getDisplayedEntityType } from '@app/entity/shared/containers/profile/header/PlatformContent/PlatformContentContainer'; -import { useAppConfig } from '@app/useAppConfig'; -import { useEntityRegistry } from '@app/useEntityRegistry'; -import { DEFAULT_APP_CONFIG } from '@src/appConfigContext'; -import { resolveRuntimePath } from '@utils/runtimeBasePath'; - -const HeaderWrapper = styled.div` - display: flex; -`; - -const LogoImage = styled(Image)` - display: inline-block; - height: 40px; - width: auto; -`; - -const EntityContent = styled.div` - margin-left: 16px; - display: flex; - flex-direction: column; - justify-content: space-between; -`; - -const EntityTypeWrapper = styled.div` - font-size: 12px; - color: ${ANTD_GRAY[8]}; -`; - -const TypeIcon = styled.span` - margin-right: 5px; -`; - -const EntityName = styled(Typography.Text)` - font-size: 16px; - font-weight: 700; - line-height: 24px; -`; - -const StyledLink = styled(Link)` - font-size: 10px; - font-weight: 700; - line-height: 22px; - margin-left: 8px; -`; - -const EntityNameWrapper = styled.div` - display: flex; - align-items: baseline; -`; - -export default function EmbeddedHeader() { - const entityRegistry = useEntityRegistry(); - const { entityData, entityType, urn } = useEntityData(); - const appConfig = useAppConfig(); - const themeConfig = useTheme(); - - function trackClickViewInDataHub() { - analytics.event({ - type: EventType.EmbedProfileViewInDataHubEvent, - entityType, - entityUrn: entityData?.urn || '', - }); - } - - const typeIcon = entityRegistry.getIcon(entityType, 12, IconStyleType.ACCENT, ANTD_GRAY[8]); - const displayedEntityType = getDisplayedEntityType(entityData, entityRegistry, entityType); - const entityName = entityRegistry.getDisplayName(entityType, entityData); - const logoUrl = - appConfig.config !== DEFAULT_APP_CONFIG - ? appConfig.config.visualConfig.logoUrl || themeConfig.assets.logoUrl - : undefined; - - return ( - - - - - {typeIcon} - {displayedEntityType} - - - - {entityName} - - - view in DataHub - - - - - ); -} diff --git a/datahub-web-react/src/app/entity/shared/embed/EmbeddedProfile.tsx b/datahub-web-react/src/app/entity/shared/embed/EmbeddedProfile.tsx deleted file mode 100644 index 4b1f7b7d511b7f..00000000000000 --- a/datahub-web-react/src/app/entity/shared/embed/EmbeddedProfile.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { LoadingOutlined } from '@ant-design/icons'; -import { QueryHookOptions, QueryResult } from '@apollo/client'; -import { Divider } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { EntityContext } from '@app/entity/shared/EntityContext'; -import { SidebarAboutSection } from '@app/entity/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection'; -import DataProductSection from '@app/entity/shared/containers/profile/sidebar/DataProduct/DataProductSection'; -import { SidebarDomainSection } from '@app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection'; -import { SidebarOwnerSection } from '@app/entity/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection'; -import { SidebarTagsSection } from '@app/entity/shared/containers/profile/sidebar/SidebarTagsSection'; -import useGetDataForProfile from '@app/entity/shared/containers/profile/useGetDataForProfile'; -import EmbeddedHeader from '@app/entity/shared/embed/EmbeddedHeader'; -import UpstreamHealth from '@app/entity/shared/embed/UpstreamHealth/UpstreamHealth'; -import NonExistentEntityPage from '@app/entity/shared/entity/NonExistentEntityPage'; -import { GenericEntityProperties } from '@app/entity/shared/types'; - -import { EntityType, Exact } from '@types'; - -const LoadingWrapper = styled.div` - display: flex; - align-items: center; - justify-content: center; - height: 85vh; - font-size: 50px; -`; - -const StyledDivider = styled(Divider)` - margin: 12px 0; -`; - -interface Props { - urn: string; - entityType: EntityType; - useEntityQuery: ( - baseOptions: QueryHookOptions< - T, - Exact<{ - urn: string; - }> - >, - ) => QueryResult< - T, - Exact<{ - urn: string; - }> - >; - getOverrideProperties: (T) => GenericEntityProperties; -} - -export default function EmbeddedProfile({ urn, entityType, getOverrideProperties, useEntityQuery }: Props) { - const { entityData, dataPossiblyCombinedWithSiblings, dataNotCombinedWithSiblings, loading, refetch } = - useGetDataForProfile({ urn, entityType, useEntityQuery, getOverrideProperties }); - - if (entityData?.exists === false) { - return ; - } - - const readOnly = false; - - return ( - {}, - refetch, - lineage: undefined, - }} - > - {loading && ( - - - - )} - {!loading && entityData && ( - <> - - - - - - - - - - - - - - - )} - - ); -} diff --git a/datahub-web-react/src/app/entity/shared/embed/UpstreamHealth/FailingAssertions.tsx b/datahub-web-react/src/app/entity/shared/embed/UpstreamHealth/FailingAssertions.tsx deleted file mode 100644 index 3ed9fd08cf1fc0..00000000000000 --- a/datahub-web-react/src/app/entity/shared/embed/UpstreamHealth/FailingAssertions.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import FailingEntity from '@app/entity/shared/embed/UpstreamHealth/FailingEntity'; -import { UpstreamSummary, getNumAssertionsFailing } from '@app/entity/shared/embed/UpstreamHealth/utils'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -const FailingSectionWrapper = styled.div` - margin: 5px 0 0 34px; - font-size: 14px; - color: black; -`; - -const FailingDataWrapper = styled.div` - margin-left: 20px; -`; - -interface Props { - upstreamSummary: UpstreamSummary; -} - -export default function FailingAssertions({ upstreamSummary }: Props) { - const { datasetsWithFailingAssertions } = upstreamSummary; - const entityRegistry = useEntityRegistry(); - - return ( - - {datasetsWithFailingAssertions.length} data source{datasetsWithFailingAssertions.length > 1 && 's'} with - failing assertions - - {datasetsWithFailingAssertions.map((dataset) => { - const totalNumAssertions = dataset.assertions?.assertions?.length; - const numAssertionsFailing = getNumAssertionsFailing(dataset); - - return ( - - ); - })} - - - ); -} diff --git a/datahub-web-react/src/app/entity/shared/embed/UpstreamHealth/FailingEntity.tsx b/datahub-web-react/src/app/entity/shared/embed/UpstreamHealth/FailingEntity.tsx deleted file mode 100644 index 34473f2d30ebb2..00000000000000 --- a/datahub-web-react/src/app/entity/shared/embed/UpstreamHealth/FailingEntity.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { red } from '@ant-design/colors'; -import Icon from '@ant-design/icons/lib/components/Icon'; -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import ExternalLink from '@images/link-out.svg?react'; - -const DatasetWrapper = styled.div` - display: flex; - align-items: center; - margin-top: 3px; -`; - -const AssertionsSummaryWrapper = styled.span` - font-size: 10px; - font-weight: 700; - line-height: 13px; - color: ${red[7]}; - border: 1px solid ${red[7]}; - border-radius: 8px; - margin-left: 5px; - padding: 0 3px; - letter-spacing: 0.2px; -`; - -const StyledLink = styled(Typography.Link)` - align-items: center; - display: flex; - img { - margin-right: 3px; - } -`; - -const StyledIcon = styled(Icon)` - margin-right: 3px; -`; - -interface Props { - link: string; - displayName: string; - contentText: string; -} - -export default function FailingEntity({ link, displayName, contentText }: Props) { - return ( - - - - {displayName} - - {contentText} - - ); -} diff --git a/datahub-web-react/src/app/entity/shared/embed/UpstreamHealth/FailingInputs.tsx b/datahub-web-react/src/app/entity/shared/embed/UpstreamHealth/FailingInputs.tsx deleted file mode 100644 index fd998d79528482..00000000000000 --- a/datahub-web-react/src/app/entity/shared/embed/UpstreamHealth/FailingInputs.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { orange } from '@ant-design/colors'; -import { DownOutlined, WarningFilled } from '@ant-design/icons'; -import React, { useState } from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import FailingAssertions from '@app/entity/shared/embed/UpstreamHealth/FailingAssertions'; -import { UpstreamSummary } from '@app/entity/shared/embed/UpstreamHealth/utils'; - -const TextWrapper = styled.span` - font-size: 16px; - line-height: 24px; - margin-left: 8px; -`; - -const StyledWarning = styled(WarningFilled)` - color: ${orange[5]}; - font-size: 14px; -`; - -const FailingDetailsWrapper = styled.span` - font-size: 14px; - color: ${ANTD_GRAY[8]}; - margin-left: 8px; - &:hover { - cursor: pointer; - color: $ ${(props) => props.theme.styles['primary-color']}; - } -`; - -const StyledArrow = styled(DownOutlined)<{ isOpen: boolean }>` - font-size: 12px; - margin-left: 3px; - ${(props) => - props.isOpen && - ` - transform: rotate(180deg); - padding-top: 1px; - `} -`; - -interface Props { - upstreamSummary: UpstreamSummary; -} - -export default function FailingInputs({ upstreamSummary }: Props) { - const [areFailingDetailsVisible, setAreFailingDetailsVisible] = useState(false); - - return ( -
- - Some data inputs are not healthy - setAreFailingDetailsVisible(!areFailingDetailsVisible)}> - view details - - {areFailingDetailsVisible && } -
- ); -} diff --git a/datahub-web-react/src/app/entity/shared/embed/UpstreamHealth/UpstreamHealth.tsx b/datahub-web-react/src/app/entity/shared/embed/UpstreamHealth/UpstreamHealth.tsx deleted file mode 100644 index 90387b4c90b280..00000000000000 --- a/datahub-web-react/src/app/entity/shared/embed/UpstreamHealth/UpstreamHealth.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import { green } from '@ant-design/colors'; -import { CheckCircleFilled, LoadingOutlined } from '@ant-design/icons'; -import Icon from '@ant-design/icons/lib/components/Icon'; -import React from 'react'; -import styled from 'styled-components'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import FailingInputs from '@app/entity/shared/embed/UpstreamHealth/FailingInputs'; -import { extractUpstreamSummary } from '@app/entity/shared/embed/UpstreamHealth/utils'; - -import { useSearchAcrossLineageQuery } from '@graphql/search.generated'; -import { Entity, EntityType, FilterOperator, LineageDirection } from '@types'; - -import SubtractIcon from '@images/subtractIcon.svg?react'; - -const LoadingWrapper = styled.div` - display: flex; - align-items: center; - justify-content: center; - font-size: 16px; -`; - -const TextWrapper = styled.span` - font-size: 16px; - line-height: 24px; - margin-left: 8px; -`; - -const UnknownText = styled.span` - font-size: 14px; - line-height: 20px; - margin-left: 8px; -`; - -const StyledIcon = styled(Icon)` - color: ${ANTD_GRAY[7]}; -`; - -const StyledCheck = styled(CheckCircleFilled)` - color: ${green[6]}; - font-size: 14px; -`; - -export default function UpstreamHealth() { - const { entityData } = useEntityData(); - const { data, loading } = useSearchAcrossLineageQuery({ - variables: { - input: { - urn: entityData?.urn || '', - query: '*', - types: [EntityType.Dataset], - start: 0, - count: 1000, - direction: LineageDirection.Upstream, - orFilters: [{ and: [{ field: 'degree', condition: FilterOperator.Equal, values: ['1', '2', '3+'] }] }], - }, - includeAssertions: true, - }, - }); - - const upstreams: Entity[] | undefined = data?.searchAcrossLineage?.searchResults?.map((result) => result.entity); - const upstreamSummary = extractUpstreamSummary(upstreams || []); - const { passingUpstreams, failingUpstreams } = upstreamSummary; - - if (loading) { - return ( - - - - ); - } - - if (!data) return null; - - if (failingUpstreams > 0) { - return ; - } - - if (passingUpstreams > 0) { - return ( -
- - All data inputs are healthy -
- ); - } - - return ( -
- - Unknown data input health -
- ); -} diff --git a/datahub-web-react/src/app/entity/shared/embed/UpstreamHealth/utils.ts b/datahub-web-react/src/app/entity/shared/embed/UpstreamHealth/utils.ts index a3b22bedd4bc9c..9d862596b5dd83 100644 --- a/datahub-web-react/src/app/entity/shared/embed/UpstreamHealth/utils.ts +++ b/datahub-web-react/src/app/entity/shared/embed/UpstreamHealth/utils.ts @@ -19,7 +19,7 @@ function getAssertionsSummary(dataset: Dataset) { return { numAssertionsPassing, numAssertionsFailing }; } -export interface UpstreamSummary { +interface UpstreamSummary { passingUpstreams: number; failingUpstreams: number; datasetsWithFailingAssertions: Dataset[]; diff --git a/datahub-web-react/src/app/entity/shared/entityForm/EntityFormContext.tsx b/datahub-web-react/src/app/entity/shared/entityForm/EntityFormContext.tsx index d8d43fe0ec76eb..6c0b39ac75dd49 100644 --- a/datahub-web-react/src/app/entity/shared/entityForm/EntityFormContext.tsx +++ b/datahub-web-react/src/app/entity/shared/entityForm/EntityFormContext.tsx @@ -8,7 +8,7 @@ export enum FormView { BY_ENTITY, } -export type EntityFormContextType = { +type EntityFormContextType = { formUrn: string; isInFormContext: boolean; entityData: GenericEntityProperties | undefined; @@ -27,7 +27,7 @@ export type EntityFormContextType = { isVerificationType: boolean; }; -export const DEFAULT_CONTEXT = { +const DEFAULT_CONTEXT = { formUrn: '', isInFormContext: false, entityData: undefined, diff --git a/datahub-web-react/src/app/entity/shared/entityForm/FormHeader/components.ts b/datahub-web-react/src/app/entity/shared/entityForm/FormHeader/components.ts deleted file mode 100644 index 9d2b386ab9afef..00000000000000 --- a/datahub-web-react/src/app/entity/shared/entityForm/FormHeader/components.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { ArrowLeftOutlined, ArrowRightOutlined } from '@ant-design/icons'; -import styled from 'styled-components'; - -import { ANTD_GRAY_V2 } from '@app/entity/shared/constants'; - -import BackgroundDots from '@images/background_dots.svg'; - -export const BulkNavigationWrapper = styled.div<{ $hideBackground?: boolean }>` - padding: 16px 68px 16px 24px; - background-color: ${ANTD_GRAY_V2[10]}; - display: flex; - justify-content: flex-end; - ${(props) => - !props.$hideBackground && - ` - background-image: url(${BackgroundDots}); - background-position: right; - background-repeat: no-repeat; - `} -`; - -export const NavigationWrapper = styled.div<{ isHidden: boolean }>` - font-size: 20px; - color: white; - display: flex; - flex-wrap: nowrap; - ${(props) => props.isHidden && 'opacity: 0;'} -`; - -export const ArrowLeft = styled(ArrowLeftOutlined)` - margin-right: 24px; - cursor: pointer; -`; - -export const ArrowRight = styled(ArrowRightOutlined)` - margin-left: 24px; - cursor: pointer; -`; diff --git a/datahub-web-react/src/app/entity/shared/siblingUtils.ts b/datahub-web-react/src/app/entity/shared/siblingUtils.ts index bb385b6fb3a897..616fabaedf9016 100644 --- a/datahub-web-react/src/app/entity/shared/siblingUtils.ts +++ b/datahub-web-react/src/app/entity/shared/siblingUtils.ts @@ -369,7 +369,7 @@ function customMerge(isPrimary, key) { }; } -export const getEntitySiblingData = (baseEntity: T): Maybe => { +const getEntitySiblingData = (baseEntity: T): Maybe => { if (!baseEntity) { return null; } @@ -436,7 +436,7 @@ const combineEntityWithSiblings = (entity: GenericEntityProperties) => { return combinedBaseEntity; }; -export function combineEntityData(entityValue: T, siblingValue: T, isPrimary: boolean) { +function combineEntityData(entityValue: T, siblingValue: T, isPrimary: boolean) { if (!entityValue) return siblingValue; if (!siblingValue) return entityValue; @@ -476,7 +476,7 @@ type CombinedEntityResult = combinedEntity: CombinedEntity; }; -export function combineSiblingsForEntity(entity: Entity, visitedSiblingUrns: Set): CombinedEntityResult { +function combineSiblingsForEntity(entity: Entity, visitedSiblingUrns: Set): CombinedEntityResult { if (visitedSiblingUrns.has(entity.urn)) return { skipped: true }; const combinedEntity: CombinedEntity = { entity: combineEntityWithSiblings({ ...entity }) }; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/AccessManagement/AccessButtonHelpers.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/AccessManagement/AccessButtonHelpers.tsx index 196f2f1a3da0ba..47e185c6c0b59f 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/AccessManagement/AccessButtonHelpers.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/AccessManagement/AccessButtonHelpers.tsx @@ -7,13 +7,13 @@ import { ANTD_GRAY, REDESIGN_COLORS } from '@app/entity/shared/constants'; /** * Tooltip message for when user already has access */ -export const ACCESS_GRANTED_TOOLTIP = 'You already have access to this role'; +const ACCESS_GRANTED_TOOLTIP = 'You already have access to this role'; /** * Styled button component for access management actions. * Supports both enabled (request) and disabled (granted) states. */ -export const AccessButton = styled(Button)` +const AccessButton = styled(Button)` background-color: ${REDESIGN_COLORS.BLUE}; color: ${ANTD_GRAY[1]}; width: 80px; @@ -56,7 +56,7 @@ export interface RoleAccessData { * Handles the click event for access request buttons. * Only opens the URL if the user doesn't already have access. */ -export const handleAccessButtonClick = (hasAccess: boolean, url?: string) => (e: React.MouseEvent) => { +const handleAccessButtonClick = (hasAccess: boolean, url?: string) => (e: React.MouseEvent) => { if (!hasAccess && url) { e.preventDefault(); window.open(url); @@ -98,9 +98,9 @@ export const renderAccessButton = (roleData: RoleAccessData): React.ReactElement /** * Determines the button text based on access status */ -export const getAccessButtonText = (hasAccess: boolean): string => (hasAccess ? 'Granted' : 'Request'); +const getAccessButtonText = (hasAccess: boolean): string => (hasAccess ? 'Granted' : 'Request'); /** * Determines if the button should be disabled */ -export const isAccessButtonDisabled = (hasAccess: boolean): boolean => hasAccess; +const isAccessButtonDisabled = (hasAccess: boolean): boolean => hasAccess; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/AccessManagement/AccessManagerDescription.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/AccessManagement/AccessManagerDescription.tsx index 06b55b67c6ee79..527a97ce5ef41c 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/AccessManagement/AccessManagerDescription.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/AccessManagement/AccessManagerDescription.tsx @@ -2,7 +2,7 @@ import { Typography } from 'antd'; import React, { useState } from 'react'; import styled from 'styled-components'; -export type Props = { +type Props = { description: any; }; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Governance/TestResultsSummary.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Governance/TestResultsSummary.tsx index 2403755f23338f..7cdf79bb79de95 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Governance/TestResultsSummary.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Governance/TestResultsSummary.tsx @@ -29,7 +29,7 @@ const SummaryTitle = styled(Typography.Title)` } `; -export type TestsSummary = { +type TestsSummary = { failing: number; passing: number; total: number; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/CopyQuery.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/CopyQuery.tsx index 76d3b4ad4fab03..e8e1f967a66f74 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/CopyQuery.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/CopyQuery.tsx @@ -2,7 +2,7 @@ import { CheckOutlined, CopyOutlined } from '@ant-design/icons'; import { Button, Tooltip } from 'antd'; import React, { useState } from 'react'; -export type Props = { +type Props = { query: string; showCopyText?: boolean; style?: any; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/EmptyQueries.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/EmptyQueries.tsx index d2abc190b38b33..6cf24e6d1e200e 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/EmptyQueries.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/EmptyQueries.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { EmptyTab } from '@app/entity/shared/components/styled/EmptyTab'; -export type Props = { +type Props = { message?: string; readOnly?: boolean; onClickAddQuery: () => void; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/Query.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/Query.tsx index d83d3940f4bcc1..be29e106cb4364 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/Query.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/Query.tsx @@ -4,7 +4,7 @@ import QueryBuilderModal from '@app/entity/shared/tabs/Dataset/Queries/QueryBuil import QueryCard from '@app/entity/shared/tabs/Dataset/Queries/QueryCard'; import QueryModal from '@app/entity/shared/tabs/Dataset/Queries/QueryModal'; -export type Props = { +type Props = { urn?: string; query: string; title?: string; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCard.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCard.tsx index 3ed4ebf13d5a79..ca61cdebbd16d9 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCard.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCard.tsx @@ -17,7 +17,7 @@ const Card = styled.div` margin-bottom: 20px; `; -export type Props = { +type Props = { urn?: string; query: string; title?: string; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardDetails.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardDetails.tsx index d4d492433c5782..27d26dfa19b680 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardDetails.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardDetails.tsx @@ -68,7 +68,7 @@ const EmptyText = styled.div` } `; -export type Props = { +type Props = { urn?: string; title?: string; description?: string; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardDetailsMenu.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardDetailsMenu.tsx index 64280a3451a2bb..a7e2217006dd51 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardDetailsMenu.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardDetailsMenu.tsx @@ -12,7 +12,7 @@ const StyledMoreOutlined = styled(MoreOutlined)` font-size: 14px; `; -export type Props = { +type Props = { urn: string; onDeleted?: (urn: string) => void; index?: number; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardEditButton.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardEditButton.tsx index 79451ec9ebf064..9ef76bbb4587af 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardEditButton.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardEditButton.tsx @@ -10,7 +10,7 @@ const EditQueryActionButton = styled(Button)` } `; -export type Props = { +type Props = { onClickEdit?: () => void; index?: number; }; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardHeader.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardHeader.tsx index 4e8ee364b63e32..8d0203e41590c4 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardHeader.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardHeader.tsx @@ -22,7 +22,7 @@ const ExpandButton = styled(Button)` margin-left: 8px; `; -export type Props = { +type Props = { query: string; focused: boolean; onClickExpand?: (newQuery) => void; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardQuery.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardQuery.tsx index e89846dbd36459..70da9d01bbacfe 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardQuery.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/QueryCardQuery.tsx @@ -25,7 +25,7 @@ const NestedSyntax = styled(SyntaxHighlighter)` } !important; `; -export type Props = { +type Props = { query: string; showDetails: boolean; onClickExpand?: (newQuery) => void; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/utils/constants.ts b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/utils/constants.ts index 025705abc580ea..112cdc5a505d92 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/utils/constants.ts +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Queries/utils/constants.ts @@ -16,6 +16,6 @@ export const DEFAULT_MAX_RECENT_QUERIES = 9; */ export const MAX_ROWS_BEFORE_DEBOUNCE = 50; export const HALF_SECOND_IN_MS = 500; -export const ONE_SECOND_IN_MS = 1000; +const ONE_SECOND_IN_MS = 1000; export const ADD_UNAUTHORIZED_MESSAGE = 'You are not authorized to add Queries to this entity.'; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Relationship/RelationshipsTab.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Relationship/RelationshipsTab.tsx deleted file mode 100644 index e6494b012420b2..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Relationship/RelationshipsTab.tsx +++ /dev/null @@ -1,283 +0,0 @@ -import '@app/entity/shared/tabs/Dataset/Relationship/RelationshipsTab.less'; - -import { ExclamationCircleFilled, LoadingOutlined, PlusOutlined } from '@ant-design/icons'; -import { Icon } from '@components'; -import { Button, Card, Divider, Empty, Input, Modal, Pagination } from 'antd'; -import React, { useCallback, useEffect, useState } from 'react'; -import styled from 'styled-components'; - -import { useBaseEntity } from '@app/entity/shared/EntityContext'; -import { CreateERModelRelationModal } from '@app/entity/shared/components/styled/ERModelRelationship/CreateERModelRelationModal'; -import { ERModelRelationPreview } from '@app/entity/shared/components/styled/ERModelRelationship/ERModelRelationPreview'; -import { SearchSelectModal } from '@app/entity/shared/components/styled/search/SearchSelectModal'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { useGetEntityWithSchema } from '@app/entity/shared/tabs/Dataset/Schema/useGetEntitySchema'; -import { useEntityRegistry } from '@src/app/useEntityRegistry'; - -import { GetDatasetQuery, useGetDatasetLazyQuery, useGetDatasetSchemaLazyQuery } from '@graphql/dataset.generated'; -import { useGetSearchResultsQuery } from '@graphql/search.generated'; -import { EntityType, ErModelRelationship } from '@types'; - -import closeIcon from '@images/close_dark.svg'; - -const StyledPagination = styled(Pagination)` - margin: 0px; - padding: 0px; - padding-left: 400px; -`; -const StyledInput = styled(Input)` - border-radius: 70px; - border: 1px solid rgba(0, 0, 0, 0.12); - max-width: 416px; - height: 40px !important; -`; -const ThinDivider = styled(Divider)` - height: 1px; - width: 520px !important; - background: #f0f0f0; - margin-left: -70px; - margin-bottom: 0px; -`; -const NoERModelRelations = styled(Empty)` - color: ${ANTD_GRAY[6]}; - padding-top: 60px; -`; -export const RelationshipsTab = () => { - const [pageSize, setPageSize] = useState(10); - const [currentPage, setCurrentPage] = useState(0); - const [filterText, setFilterText] = useState(''); - const baseEntity = useBaseEntity(); - // Dynamically load the schema + editable schema information. - const { entityWithSchema } = useGetEntityWithSchema(); - const [modalVisible, setModalVisible] = useState(false); - const [ermodelrelationModalVisible, setermodelrelationModalVisible] = useState(false); - const entityRegistry = useEntityRegistry(); - const entityName = entityRegistry.getEntityName(EntityType.ErModelRelationship); - const tabs = [ - { - key: 'ermodelrelationsTab', - tab: entityRegistry.getCollectionName(EntityType.ErModelRelationship), - }, - ]; - const { - data: ermodelrelations, - loading: loadingERModelRelation, - error: errorERModelRelation, - refetch, - } = useGetSearchResultsQuery({ - variables: { - input: { - type: EntityType.ErModelRelationship, - query: `${filterText ? `${filterText}` : ''}`, - orFilters: [ - { - and: [ - { - field: 'source', - values: [baseEntity?.dataset?.urn || ''], - }, - ], - }, - { - and: [ - { - field: 'destination', - values: [baseEntity?.dataset?.urn || ''], - }, - ], - }, - ], - start: currentPage * pageSize, - count: pageSize, // all matched ermodelrelations - }, - }, - }); - const totalResults = ermodelrelations?.search?.total || 0; - let ermodelrelationData: ErModelRelationship[] = []; - if (loadingERModelRelation) { - ermodelrelationData = [{}] as ErModelRelationship[]; - } - - if ( - !loadingERModelRelation && - ermodelrelations?.search && - ermodelrelations?.search?.searchResults?.length > 0 && - !errorERModelRelation - ) { - ermodelrelationData = ermodelrelations.search.searchResults.map((r) => r.entity as ErModelRelationship); - } - - const contentListNoTitle: Record = { - ermodelrelationsTab: - ermodelrelationData.length > 0 && !loadingERModelRelation ? ( - ermodelrelationData.map((record) => { - return ( - <> -
- - -
- - ); - }) - ) : ( - <> - {!loadingERModelRelation && ( -
- -
- )} - {loadingERModelRelation && ( -
- {entityName} -
- )} - - ), - }; - const [activeTabKey, setActiveTabKey] = useState('ermodelrelationsTab'); - const onTabChange = (key: string) => { - setActiveTabKey(key); - }; - const [table2LazySchema, setTable2LazySchema] = useState(undefined as any); - const [getTable2LazySchema] = useGetDatasetSchemaLazyQuery({ - onCompleted: (data) => { - setTable2LazySchema(data); - }, - }); - const [table2LazyDataset, setTable2LazyDataset] = useState(undefined as any); - const [getTable2LazyDataset] = useGetDatasetLazyQuery({ - onCompleted: (data) => { - setTable2LazyDataset(data); - }, - }); - - const schemaIssueModal = useCallback(() => { - Modal.error({ - title: `Schema error`, - className: 'schema-modal', - content: ( -
- -

- A schema was not ingested for the dataset selected. {entityName} cannot be created. -

- -
- ), - onOk() {}, - okText: 'Ok', - icon: , - closeIcon: , - maskClosable: true, - closable: true, - }); - }, [entityName]); - useEffect(() => { - if ( - table2LazySchema?.dataset !== undefined && - table2LazySchema?.dataset?.schemaMetadata?.fields === undefined - ) { - schemaIssueModal(); - } - if ( - table2LazySchema?.dataset !== undefined && - table2LazySchema?.dataset?.schemaMetadata?.fields !== undefined - ) { - setermodelrelationModalVisible(false); - setModalVisible(true); - } - }, [table2LazySchema, schemaIssueModal]); - return ( - <> - {ermodelrelationModalVisible && ( - { - await getTable2LazySchema({ - variables: { - urn: selectedDataSet[0] || '', - }, - }); - await getTable2LazyDataset({ - variables: { - urn: selectedDataSet[0] || '', - }, - }); - }} - onCancel={() => setermodelrelationModalVisible(false)} - fixedEntityTypes={[EntityType.Dataset]} - singleSelect - hideToolbar - /> - )} - {baseEntity !== undefined && ( - { - setModalVisible(false); - }} - refetch={refetch} - entityName={entityName} - /> - )} - { - onTabChange(key); - }} - > -
- setFilterText(e.target.value)} - allowClear - autoFocus - prefix={} - /> - -
{' '} -
-
- {contentListNoTitle[activeTabKey]} - {totalResults >= 1 && ( - setCurrentPage(page - 1)} - showSizeChanger={totalResults > 10} - onShowSizeChange={(_currNum, newNum) => setPageSize(newNum)} - pageSizeOptions={['10', '20', '50', '100']} - /> - )} -
- - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Schema/SchemaTable.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Schema/SchemaTable.tsx index bf7db18c755afb..9007a9ac9f7a12 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Schema/SchemaTable.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Schema/SchemaTable.tsx @@ -67,7 +67,7 @@ const TableContainer = styled.div` } `; -export type Props = { +type Props = { rows: Array; schemaMetadata: SchemaMetadata | undefined | null; editableSchemaMetadata?: EditableSchemaMetadata | null; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Schema/components/MenuColumn.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Schema/components/MenuColumn.tsx index 1d231386645afc..e149eabfdca9d5 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Schema/components/MenuColumn.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Schema/components/MenuColumn.tsx @@ -16,7 +16,7 @@ export const ImpactAnalysisIcon = styled(VscGraphLeft)` font-size: 18px; `; -export const CopyOutlinedIcon = styled(CopyOutlined)` +const CopyOutlinedIcon = styled(CopyOutlined)` transform: scaleX(-1); font-size: 16px; `; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Schema/components/SchemaFieldDrawer/FieldProperties.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Schema/components/SchemaFieldDrawer/FieldProperties.tsx index 83db77a094f85c..c1030de23d3ccb 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Schema/components/SchemaFieldDrawer/FieldProperties.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Schema/components/SchemaFieldDrawer/FieldProperties.tsx @@ -11,19 +11,19 @@ import { useEntityData } from '@src/app/entity/shared/EntityContext'; import { SchemaField, SearchResult, StdDataType } from '@types'; -export const PropertyTitle = styled.div` +const PropertyTitle = styled.div` font-size: 14px; font-weight: 700; margin-bottom: 4px; `; -export const PropertyWrapper = styled.div` +const PropertyWrapper = styled.div` margin-bottom: 12px; display: flex; justify-content: space-between; `; -export const PropertiesWrapper = styled.div` +const PropertiesWrapper = styled.div` padding-left: 16px; `; @@ -31,7 +31,7 @@ export const StyledList = styled.ul` padding-left: 24px; `; -export const Header = styled.div` +const Header = styled.div` font-size: 16px; font-weight: 600; margin-bottom: 16px; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Schema/utils/useTagsAndTermsRendererFeatureTable.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Schema/utils/useTagsAndTermsRendererFeatureTable.tsx deleted file mode 100644 index 20fdec4d03ff7f..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Schema/utils/useTagsAndTermsRendererFeatureTable.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import React from 'react'; - -import { pathMatchesNewPath } from '@app/entity/dataset/profile/schema/utils/utils'; -import { useEntityData, useRefetch } from '@app/entity/shared/EntityContext'; -import TagTermGroup from '@app/shared/tags/TagTermGroup'; - -import { EditableSchemaMetadata, EntityType, GlobalTags, SchemaField } from '@types'; - -export default function useTagsAndTermsRendererFeatureTable( - editableSchemaMetadata: EditableSchemaMetadata | null | undefined, - tagHoveredIndex: string | undefined, - setTagHoveredIndex: (index: string | undefined) => void, - options: { showTags: boolean; showTerms: boolean }, -) { - const { urn } = useEntityData(); - const refetch = useRefetch(); - - const tagAndTermRender = (tags: GlobalTags, record: SchemaField, rowIndex: number | undefined) => { - const relevantEditableFieldInfo = editableSchemaMetadata?.editableSchemaFieldInfo?.find( - (candidateEditableFieldInfo) => pathMatchesNewPath(candidateEditableFieldInfo.fieldPath, record.fieldPath), - ); - - return ( -
- setTagHoveredIndex(undefined)} - entityUrn={urn} - entityType={EntityType.Dataset} - entitySubresource={record.fieldPath} - refetch={refetch} - /> -
- ); - }; - return tagAndTermRender; -} diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Stats/StatsSection.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Stats/StatsSection.tsx deleted file mode 100644 index 32244ee67cc374..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Stats/StatsSection.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Divider, Row, Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -const Section = styled.div` - padding-top: 24px; - padding-bottom: 40px; - margin-bottom: 20px; - width: 100%; -`; - -const ThinDivider = styled(Divider)` - margin-top: 8px; - margin-bottom: 8px; -`; - -export type Props = { - children: React.ReactNode; - title: string; - rightFloatView?: React.ReactNode; -}; - -export default function StatsSection({ children, title, rightFloatView }: Props) { - return ( -
- - {title} - {rightFloatView || } - - - {children} -
- ); -} diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Stats/historical/HistoricalStats.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Stats/historical/HistoricalStats.tsx index 743b531b0de43c..d2afbd83681e6c 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Stats/historical/HistoricalStats.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Stats/historical/HistoricalStats.tsx @@ -110,7 +110,7 @@ const getLookbackWindowSize = (window: LookbackWindow) => { return window.windowSize; }; -export type Props = { +type Props = { urn: string; lookbackWindow: LookbackWindow; }; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Stats/historical/charts/ProfilingRunsChart.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Stats/historical/charts/ProfilingRunsChart.tsx index 0cd9654e7e8b3e..33e649df93aa27 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Stats/historical/charts/ProfilingRunsChart.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Stats/historical/charts/ProfilingRunsChart.tsx @@ -8,11 +8,11 @@ import { formatBytes, formatNumberWithoutAbbreviation } from '@app/shared/format import { DatasetProfile } from '@types'; -export const ChartTable = styled(Table)` +const ChartTable = styled(Table)` margin-top: 16px; `; -export type Props = { +type Props = { profiles: Array; }; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Stats/historical/charts/StatChart.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Stats/historical/charts/StatChart.tsx index f4568bc344f50b..455fd51690b7f2 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Stats/historical/charts/StatChart.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Stats/historical/charts/StatChart.tsx @@ -30,7 +30,7 @@ type AxisConfig = { formatter: (tick: number) => string; }; -export type Props = { +type Props = { title: string; values: Array; tickInterval: DateInterval; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/Assertions.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/Assertions.tsx deleted file mode 100644 index a07bfe74c78daf..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/Assertions.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import React, { useState } from 'react'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { combineEntityDataWithSiblings, useIsSeparateSiblingsMode } from '@app/entity/shared/siblingUtils'; -import { DatasetAssertionsList } from '@app/entity/shared/tabs/Dataset/Validations/DatasetAssertionsList'; -import { DatasetAssertionsSummary } from '@app/entity/shared/tabs/Dataset/Validations/DatasetAssertionsSummary'; -import { sortAssertions } from '@app/entity/shared/tabs/Dataset/Validations/assertionUtils'; - -import { useGetDatasetContractQuery } from '@graphql/contract.generated'; -import { useGetDatasetAssertionsQuery } from '@graphql/dataset.generated'; -import { Assertion, AssertionResultType } from '@types'; - -/** - * Returns a status summary for the assertions associated with a Dataset. - */ -const getAssertionsStatusSummary = (assertions: Array) => { - const summary = { - failedRuns: 0, - succeededRuns: 0, - totalRuns: 0, - erroredRuns: 0, - totalAssertions: assertions.length, - }; - assertions.forEach((assertion) => { - if ((assertion.runEvents?.runEvents?.length || 0) > 0) { - const mostRecentRun = assertion.runEvents?.runEvents?.[0]; - const resultType = mostRecentRun?.result?.type; - if (AssertionResultType.Success === resultType) { - summary.succeededRuns++; - } - if (AssertionResultType.Failure === resultType) { - summary.failedRuns++; - } - if (AssertionResultType.Error === resultType) { - summary.erroredRuns++; - } - if (AssertionResultType.Init !== resultType) { - summary.totalRuns++; // only count assertions for which there is one completed run event, ignoring INIT statuses! - } - } - }); - return summary; -}; - -/** - * Component used for rendering the Validations Tab on the Dataset Page. - * - * TODO: Note that only the legacy DATASET assertions are supported for viewing as of today. - */ -export const Assertions = () => { - const { urn, entityData } = useEntityData(); - const { data, refetch } = useGetDatasetAssertionsQuery({ variables: { urn }, fetchPolicy: 'cache-first' }); - const isHideSiblingMode = useIsSeparateSiblingsMode(); - - const combinedData = isHideSiblingMode ? data : combineEntityDataWithSiblings(data); - const [removedUrns, setRemovedUrns] = useState([]); - - const { data: contractData } = useGetDatasetContractQuery({ - variables: { urn }, - fetchPolicy: 'cache-first', - }); - const contract = contractData?.dataset?.contract as any; - const assertions = - (combinedData && combinedData.dataset?.assertions?.assertions?.map((assertion) => assertion as Assertion)) || - []; - const filteredAssertions = assertions.filter((assertion) => !removedUrns.includes(assertion.urn)); - - // Pre-sort the list of assertions based on which has been most recently executed. - assertions.sort(sortAssertions); - - return ( - <> - - {entityData && ( - { - // Hack to deal with eventual consistency. - setRemovedUrns([...removedUrns, assertionUrn]); - setTimeout(() => refetch(), 3000); - }} - contract={contract} - /> - )} - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/BooleanTimeline.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/BooleanTimeline.tsx deleted file mode 100644 index a5ff0c66e8cf0f..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/BooleanTimeline.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import { AxisBottom } from '@visx/axis'; -import { Group } from '@visx/group'; -import { scaleUtc } from '@visx/scale'; -import { Bar } from '@visx/shape'; -import { Popover } from 'antd'; -import React, { useMemo } from 'react'; - -import { ANTD_GRAY } from '@app/entity/shared/constants'; - -export type BooleanResult = { - result: boolean; - title: React.ReactNode; - content: React.ReactNode; -}; - -export type BooleanDataPoint = { - time: number; - result: BooleanResult; -}; - -export type TimeRange = { - startMs: number; - endMs: number; -}; - -type Props = { - data: Array; - timeRange: TimeRange; - width: number; -}; - -const SUCCESS_COLOR_HEX = '#52C41A'; -const FAILURE_COLOR_HEX = '#F5222D'; - -/** - * True / false results displayed on a horizontal timeline. - */ -export const BooleanTimeline = ({ data, timeRange, width }: Props) => { - const yMax = 60; - const left = 0; - - const xScale = useMemo( - () => - scaleUtc({ - domain: [new Date(timeRange.startMs), new Date(timeRange.endMs + 600000)], - range: [0, width], - }), - [timeRange, width], - ); - - const transformedData = data.map((result, i) => { - return { - index: i, - title: result.result.title, - content: result.result.content, - result: result.result.result, - time: result.time, - }; - }); - - return ( - <> - - - {transformedData.map((d) => { - const barWidth = 8; - const barHeight = 18; - const barX = xScale(new Date(d.time)); - const barY = yMax - barHeight; - const fillColor = d.result ? SUCCESS_COLOR_HEX : FAILURE_COLOR_HEX; - return ( - - - - ); - })} - - v.toLocaleDateString('en-us', { month: 'short', day: 'numeric' })} - tickLabelProps={(_) => ({ - fontSize: 11, - angle: 0, - textAnchor: 'middle', - })} - /> - - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/DatasetAssertionDescription.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/DatasetAssertionDescription.tsx deleted file mode 100644 index 47f6910901ea24..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/DatasetAssertionDescription.tsx +++ /dev/null @@ -1,372 +0,0 @@ -import { Button, Popover, Typography } from 'antd'; -import React, { useState } from 'react'; -import styled from 'styled-components'; - -import { DatasetAssertionLogicModal } from '@app/entity/shared/tabs/Dataset/Validations/DatasetAssertionLogicModal'; -import { getFormattedParameterValue } from '@app/entity/shared/tabs/Dataset/Validations/assertionUtils'; -import { decodeSchemaField } from '@app/lineage/utils/columnLineageUtils'; - -import { - AssertionStdAggregation, - AssertionStdOperator, - AssertionStdParameters, - DatasetAssertionInfo, - DatasetAssertionScope, - SchemaFieldRef, -} from '@types'; - -const ViewLogicButton = styled(Button)` - padding: 0px; - margin: 0px; -`; - -type Props = { - description?: string; - assertionInfo: DatasetAssertionInfo; -}; - -/** - * Returns the React Component to render for the aggregation portion of the Assertion Description - * for Assertions on Dataset Schemas. - * - * Schema assertions require an aggregation. - */ -const getSchemaAggregationText = ( - aggregation: AssertionStdAggregation | undefined | null, - fields: Array | undefined | null, -) => { - switch (aggregation) { - case AssertionStdAggregation.ColumnCount: - return Dataset column count is; - case AssertionStdAggregation.Columns: - return Dataset columns are; - case AssertionStdAggregation.Native: { - const fieldNames = fields?.map((field) => decodeSchemaField(field.path)) || []; - return ( - - Dataset columns {JSON.stringify(fieldNames)} are - - ); - } - default: - console.error(`Unsupported schema aggregation assertion ${aggregation} provided.`); - return Dataset columns are; - } -}; - -/** - * Returns the React Component to render for the aggregation portion of the Assertion Description - * for Assertions on Dataset Rows - * - * Row assertions require an aggregation. - */ -const getRowsAggregationText = (aggregation: AssertionStdAggregation | undefined | null) => { - switch (aggregation) { - case AssertionStdAggregation.RowCount: - return Dataset row count is; - case AssertionStdAggregation.Native: - return Dataset rows are; - default: - console.error(`Unsupported Dataset Rows Aggregation ${aggregation} provided`); - return Dataset rows are; - } -}; - -/** - * Returns the React Component to render for the aggregation portion of the Assertion Description - * for Assertions on Dataset Columns - */ -const getColumnAggregationText = ( - aggregation: AssertionStdAggregation | undefined | null, - field: SchemaFieldRef | undefined, -) => { - let columnText = decodeSchemaField(field?.path || ''); - if (field === undefined) { - columnText = 'undefined'; - console.error(`Invalid field provided for Dataset Assertion with scope Column ${JSON.stringify(field)}`); - } - switch (aggregation) { - // Hybrid Aggregations - case AssertionStdAggregation.UniqueCount: { - return ( - - Unique value count for column {columnText} is - - ); - } - case AssertionStdAggregation.UniquePropotion: { - return ( - - Unique value proportion for column {columnText} is - - ); - } - case AssertionStdAggregation.NullCount: { - return ( - - Null count for column {columnText} is - - ); - } - case AssertionStdAggregation.NullProportion: { - return ( - - Null proportion for column {columnText} is - - ); - } - // Numeric Aggregations - case AssertionStdAggregation.Min: { - return ( - - Minimum value for column {columnText} is - - ); - } - case AssertionStdAggregation.Max: { - return ( - - Maximum value for column {columnText} is - - ); - } - case AssertionStdAggregation.Mean: { - return ( - - Mean value for column {columnText} is - - ); - } - case AssertionStdAggregation.Median: { - return ( - - Median value for column {columnText} is - - ); - } - case AssertionStdAggregation.Stddev: { - return ( - - Standard deviation for column {columnText} is - - ); - } - // Native Aggregations - case AssertionStdAggregation.Native: { - return ( - - Column {columnText} values are - - ); - } - default: - // No aggregation on the column at hand. Treat the column as a set of values. - return ( - - Column {columnText} values are - - ); - } -}; - -/** - * Returns the React Component to render for the aggregation portion of the Assertion Description - */ -const getAggregationText = ( - scope: DatasetAssertionScope, - aggregation: AssertionStdAggregation | undefined | null, - fields: Array | undefined | null, -) => { - switch (scope) { - case DatasetAssertionScope.DatasetSchema: - return getSchemaAggregationText(aggregation, fields); - case DatasetAssertionScope.DatasetRows: - return getRowsAggregationText(aggregation); - case DatasetAssertionScope.DatasetColumn: - return getColumnAggregationText(aggregation, fields?.length === 1 ? fields[0] : undefined); - default: - console.error(`Unsupported Dataset Assertion scope ${scope} provided`); - return 'Dataset is'; - } -}; - -/** - * Returns the React Component to render for the operator portion of the Assertion Description - */ -const getOperatorText = ( - op: AssertionStdOperator, - parameters: AssertionStdParameters | undefined, - nativeType: string | undefined, -) => { - switch (op) { - // Hybrid Operators - case AssertionStdOperator.Between: { - return ( - - between{' '} - {getFormattedParameterValue(parameters?.minValue)} - and {getFormattedParameterValue(parameters?.maxValue)} - - ); - } - case AssertionStdOperator.EqualTo: { - const operatorText = 'equal to'; - return ( - - {operatorText}{' '} - {getFormattedParameterValue(parameters?.value)} - - ); - } - case AssertionStdOperator.Contain: { - const operatorText = 'contains'; - return ( - - {operatorText}{' '} - {getFormattedParameterValue(parameters?.value)} - - ); - } - case AssertionStdOperator.In: { - const operatorText = 'in'; - return ( - - {operatorText}{' '} - {getFormattedParameterValue(parameters?.value)} - - ); - } - case AssertionStdOperator.NotNull: { - const operatorText = 'not null'; - return {operatorText}; - } - // Numeric Operators - case AssertionStdOperator.GreaterThan: { - const operatorText = 'greater than'; - return ( - - {operatorText}{' '} - {getFormattedParameterValue(parameters?.value)} - - ); - } - case AssertionStdOperator.GreaterThanOrEqualTo: { - const operatorText = 'greater than or equal to'; - return ( - - {operatorText}{' '} - {getFormattedParameterValue(parameters?.value)} - - ); - } - case AssertionStdOperator.LessThan: { - const operatorText = 'less than'; - return ( - - {operatorText}{' '} - {getFormattedParameterValue(parameters?.value)} - - ); - } - case AssertionStdOperator.LessThanOrEqualTo: { - const operatorText = 'less than or equal to'; - return ( - - {operatorText}{' '} - {getFormattedParameterValue(parameters?.value)} - - ); - } - // String Operators - case AssertionStdOperator.StartWith: { - const operatorText = 'starts with'; - return ( - - {operatorText}{' '} - {getFormattedParameterValue(parameters?.value)} - - ); - } - case AssertionStdOperator.EndWith: { - const operatorText = 'ends with'; - return ( - - {operatorText}{' '} - {getFormattedParameterValue(parameters?.value)} - - ); - } - case AssertionStdOperator.Native: { - return ( - - passing assertion {nativeType} - - ); - } - default: - return ( - - passing operator{' '} - - {op} with value ${getFormattedParameterValue(parameters?.value)} - - - ); - } -}; - -const TOOLTIP_MAX_WIDTH = 440; - -/** - * A human-readable description of an Assertion. - * - * For example, Column 'X' values are in [1, 2, 3] - */ -export const DatasetAssertionDescription = ({ description, assertionInfo }: Props) => { - const { scope, aggregation, fields, operator, parameters, nativeType, nativeParameters, logic } = assertionInfo; - const [isLogicVisible, setIsLogicVisible] = useState(false); - /** - * Build a description component from a) input (aggregation, inputs) b) the operator text - */ - const descriptionFragment = ( - <> - {description || ( - - {getAggregationText(scope, aggregation, fields)}{' '} - {getOperatorText(operator, parameters || undefined, nativeType || undefined)} - - )} - - ); - - return ( - Details} - content={ - <> - type: {nativeType || 'N/A'} - {nativeParameters?.map((parameter) => ( -
- {parameter.key}: {parameter.value} -
- ))} - - } - > -
{descriptionFragment}
- {logic && ( -
- setIsLogicVisible(true)} type="link"> - View Logic - -
- )} - setIsLogicVisible(false)} - /> -
- ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/DatasetAssertionDetails.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/DatasetAssertionDetails.tsx deleted file mode 100644 index 885147b434fe65..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/DatasetAssertionDetails.tsx +++ /dev/null @@ -1,231 +0,0 @@ -import { Tooltip, Typography } from 'antd'; -import { SelectValue } from 'antd/lib/select'; -import React, { useEffect, useState } from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import PrefixedSelect from '@app/entity/shared/tabs/Dataset/Stats/historical/shared/PrefixedSelect'; -import { LOOKBACK_WINDOWS } from '@app/entity/shared/tabs/Dataset/Stats/lookbackWindows'; -import { BooleanTimeline } from '@app/entity/shared/tabs/Dataset/Validations/BooleanTimeline'; -import { DatasetAssertionResultDetails } from '@app/entity/shared/tabs/Dataset/Validations/DatasetAssertionResultDetails'; -import { - getResultColor, - getResultIcon, - getResultText, -} from '@app/entity/shared/tabs/Dataset/Validations/assertionUtils'; -import { formatNumber } from '@app/shared/formatNumber'; -import { getFixedLookbackWindow, getLocaleTimezone } from '@app/shared/time/timeUtils'; - -import { useGetAssertionRunsLazyQuery } from '@graphql/assertion.generated'; -import { AssertionResultType, AssertionRunStatus } from '@types'; - -const RESULT_CHART_WIDTH_PX = 800; - -const LastEvaluatedAtLabel = styled.div` - padding: 0; - margin: 0; - display: flex; - align-items: center; - color: ${ANTD_GRAY[7]}; -`; - -const AssertionResultIcon = styled.span` - margin-right: 8px; -`; - -const AssertionResultDetailsContainer = styled.div` - margin-bottom: 4px; -`; - -const ContentContainer = styled.div` - width: 100%; - padding-left: 52px; -`; - -const EvaluationsDetails = styled.div` - width: ${RESULT_CHART_WIDTH_PX}px; - padding-top: 12px; -`; - -const EvaluationsHeader = styled.div` - display: flex; - justify-content: space-between; -`; - -const EvaluationsSummary = styled.div` - width: 260px; - display: flex; - align-items: center; - justify-content: left; -`; - -const EvaluationDateRange = styled(Typography.Text)` - margin-right: 20px; -`; - -const SucceededEvaluationsCount = styled.span` - margin-right: 12px; -`; - -const FailedEvaluationsCount = styled.span` - margin-right: 12px; -`; - -type Props = { - urn: string; - lastEvaluatedAtMillis?: number | undefined; -}; - -export const DatasetAssertionDetails = ({ urn, lastEvaluatedAtMillis }: Props) => { - const [getAssertionRuns, { data }] = useGetAssertionRunsLazyQuery({ fetchPolicy: 'cache-first' }); - - /** - * Set default window for fetching assertion history. - */ - const [lookbackWindow, setLookbackWindow] = useState(LOOKBACK_WINDOWS.WEEK); - useEffect(() => { - getAssertionRuns({ - variables: { assertionUrn: urn, ...getFixedLookbackWindow(lookbackWindow.windowSize) }, - }); - }, [urn, lookbackWindow, getAssertionRuns]); - - /** - * Invoked when user selects new lookback window (e.g. 1 year) - */ - const onChangeLookbackWindow = (value: SelectValue) => { - const newLookbackWindow = Object.values(LOOKBACK_WINDOWS).filter((window) => window.text === value?.valueOf()); - setLookbackWindow(newLookbackWindow[0]); - }; - const selectedWindow = getFixedLookbackWindow(lookbackWindow.windowSize); - const selectedWindowTimeRange = { - startMs: selectedWindow.startTime, - endMs: selectedWindow.endTime, - }; - - const completeAssertionRunEvents = - data?.assertion?.runEvents?.runEvents?.filter((runEvent) => runEvent.status === AssertionRunStatus.Complete) || - []; - - /** - * Last evaluated timestamp - */ - const lastEvaluatedAt = lastEvaluatedAtMillis - ? new Date(lastEvaluatedAtMillis) - : completeAssertionRunEvents.length > 0 && new Date(completeAssertionRunEvents[0].timestampMillis); - const localeTimezone = getLocaleTimezone(); - const lastEvaluatedTimeLocal = - (lastEvaluatedAt && - `Last evaluated on ${lastEvaluatedAt.toLocaleDateString()} at ${lastEvaluatedAt.toLocaleTimeString()} (${localeTimezone})`) || - 'No evaluations found'; - const lastEvaluatedTimeGMT = lastEvaluatedAt && lastEvaluatedAt.toUTCString(); - - /** - * Start and end date bounds for Chart - */ - const startDate = new Date(selectedWindowTimeRange.startMs).toLocaleDateString('en-us', { - month: 'short', - day: 'numeric', - }); - const endDate = new Date(selectedWindowTimeRange.endMs).toLocaleDateString('en-us', { - month: 'short', - day: 'numeric', - }); - - /** - * Success / Failure summary - */ - const succeededCount = data?.assertion?.runEvents?.succeeded; - const failedCount = data?.assertion?.runEvents?.failed; - - /** - * Data for the chart of assertion results. - */ - const assertionResultsChartData = - completeAssertionRunEvents.map((runEvent) => { - const { result } = runEvent; - const resultTime = new Date(runEvent.timestampMillis); - const localTime = resultTime.toLocaleString(); - const gmtTime = resultTime.toUTCString(); - - /** - * Create a "result" to render in the timeline chart. - */ - return { - time: runEvent.timestampMillis, - result: { - result: result?.type !== AssertionResultType.Failure, - title: ( - <> - {/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */} - {getResultIcon(result!.type)} - {/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */} - {getResultText(result!.type)} - - ), - content: ( - <> - {result && ( - - - - )} -
- - {localTime} - -
- - ), - }, - }; - }) || []; - - return ( - -
- Evaluations - - {lastEvaluatedTimeLocal} - - - - - - {startDate} - {endDate} - -
- - - {formatNumber(succeededCount)} - {' '} - passed - - - - {formatNumber(failedCount)} - {' '} - failed - -
-
- window.text)} - value={lookbackWindow.text} - setValue={onChangeLookbackWindow} - /> -
- -
-
-
- ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/DatasetAssertionLogicModal.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/DatasetAssertionLogicModal.tsx deleted file mode 100644 index fc783468dfa831..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/DatasetAssertionLogicModal.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Button, Modal } from 'antd'; -import React from 'react'; - -import Query from '@app/entity/shared/tabs/Dataset/Queries/Query'; - -export type AssertionsSummary = { - totalAssertions: number; - totalRuns: number; - failedRuns: number; - succeededRuns: number; -}; - -type Props = { - logic: string; - open: boolean; - onClose: () => void; -}; - -export const DatasetAssertionLogicModal = ({ logic, open, onClose }: Props) => { - return ( - Close}> - - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/DatasetAssertionResultDetails.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/DatasetAssertionResultDetails.tsx deleted file mode 100644 index 1edde5647f9d2f..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/DatasetAssertionResultDetails.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Typography } from 'antd'; -import React from 'react'; - -import { AssertionResult } from '@types'; - -type Props = { - result: AssertionResult; -}; - -export const DatasetAssertionResultDetails = ({ result }: Props) => { - const maybeActualValue = result.actualAggValue; - const maybeUnexpectedCount = result.unexpectedCount; - const maybeRowCount = result.rowCount; - const maybeNativeResults = result.nativeResults; - return ( - <> - {maybeActualValue !== null && maybeActualValue !== undefined && ( -
- Actual: {maybeActualValue} -
- )} - {maybeUnexpectedCount !== null && maybeUnexpectedCount !== undefined && ( -
- Invalid Count: {maybeUnexpectedCount} -
- )} - {maybeRowCount !== null && maybeRowCount !== undefined && ( -
- Row Count: {maybeRowCount} -
- )} - {maybeNativeResults && ( -
- {maybeNativeResults.map((entry) => ( -
- {entry.key}: {entry.value} -
- ))} -
- )} - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/DatasetAssertionsList.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/DatasetAssertionsList.tsx deleted file mode 100644 index f230591069cc0f..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/DatasetAssertionsList.tsx +++ /dev/null @@ -1,316 +0,0 @@ -import { - AuditOutlined, - DeleteOutlined, - DownOutlined, - MoreOutlined, - RightOutlined, - StopOutlined, -} from '@ant-design/icons'; -import { Button, Checkbox, Dropdown, Empty, Image, Modal, Tag, Tooltip, Typography, message } from 'antd'; -import React from 'react'; -import { Link } from 'react-router-dom'; -import styled from 'styled-components'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { StyledTable } from '@app/entity/shared/components/styled/StyledTable'; -import { REDESIGN_COLORS } from '@app/entity/shared/constants'; -import { DatasetAssertionDescription } from '@app/entity/shared/tabs/Dataset/Validations/DatasetAssertionDescription'; -import { DatasetAssertionDetails } from '@app/entity/shared/tabs/Dataset/Validations/DatasetAssertionDetails'; -import { - getResultColor, - getResultIcon, - getResultText, -} from '@app/entity/shared/tabs/Dataset/Validations/assertionUtils'; -import { isAssertionPartOfContract } from '@app/entity/shared/tabs/Dataset/Validations/contract/utils'; -import CopyUrnMenuItem from '@app/shared/share/items/CopyUrnMenuItem'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useDeleteAssertionMutation } from '@graphql/assertion.generated'; -import { Assertion, AssertionRunStatus, DataContract, EntityType } from '@types'; - -const ResultContainer = styled.div` - display: flex; - align-items: center; - justify-content: left; -`; - -const ResultTypeText = styled(Typography.Text)` - margin-left: 8px; -`; - -const ActionButtonContainer = styled.div` - display: flex; - justify-content: right; - align-items: center; -`; - -const PlatformContainer = styled.div` - margin-right: 8px; -`; - -const StyledMoreOutlined = styled(MoreOutlined)` - font-size: 18px; -`; - -const AssertionSelectCheckbox = styled(Checkbox)` - margin-right: 12px; -`; - -const DataContractLogo = styled(AuditOutlined)` - margin-left: 8px; - font-size: 16px; - color: ${REDESIGN_COLORS.BLUE}; -`; - -const AssertionDescriptionContainer = styled.div` - display: flex; - justify-content: right; - align-items: center; -`; - -type Props = { - assertions: Array; - onDelete?: (urn: string) => void; - contract?: DataContract; - // required for enabling menu/actions - showMenu?: boolean; - onSelect?: (assertionUrn: string) => void; - // required for enabling selection logic - showSelect?: boolean; - selectedUrns?: string[]; -}; - -/** - * A list of assertions displaying their most recent run status, their human-readable - * description, and platform. - * - * Currently this component supports rendering Dataset Assertions only. - */ -export const DatasetAssertionsList = ({ - assertions, - onDelete, - showMenu = true, - showSelect, - onSelect, - selectedUrns, - contract, -}: Props) => { - const entityData = useEntityData(); - const [deleteAssertionMutation] = useDeleteAssertionMutation(); - const entityRegistry = useEntityRegistry(); - - const deleteAssertion = async (urn: string) => { - try { - await deleteAssertionMutation({ - variables: { urn }, - }); - message.success({ content: 'Removed assertion.', duration: 2 }); - } catch (e: unknown) { - message.destroy(); - if (e instanceof Error) { - message.error({ content: `Failed to remove assertion: \n ${e.message || ''}`, duration: 3 }); - } - } - onDelete?.(urn); - }; - - const onDeleteAssertion = (urn: string) => { - Modal.confirm({ - title: `Confirm Assertion Removal`, - content: `Are you sure you want to remove this assertion from the dataset?`, - onOk() { - deleteAssertion(urn); - }, - onCancel() {}, - okText: 'Yes', - maskClosable: true, - closable: true, - }); - }; - - const assertionsTableData = assertions.map((assertion) => ({ - urn: assertion.urn, - type: assertion.info?.type, - platform: assertion.platform, - datasetAssertionInfo: assertion.info?.datasetAssertion, - description: assertion.info?.description, - lastExecTime: assertion.runEvents?.runEvents?.length && assertion.runEvents.runEvents[0].timestampMillis, - lastExecResult: - assertion.runEvents?.runEvents?.length && - assertion.runEvents.runEvents[0].status === AssertionRunStatus.Complete && - assertion.runEvents.runEvents[0].result?.type, - })); - - const assertionMenuItems = (urn: string) => { - return [ - { - key: 1, - label: , - }, - ]; - }; - - const assertionsTableCols = [ - { - title: '', - dataIndex: '', - key: '', - render: (_, record: any) => { - const executionDate = record.lastExecTime && new Date(record.lastExecTime); - const localTime = executionDate && `${executionDate.toLocaleDateString()}`; - const resultColor = (record.lastExecResult && getResultColor(record.lastExecResult)) || 'default'; - const resultText = (record.lastExecResult && getResultText(record.lastExecResult)) || 'No Evaluations'; - const resultIcon = (record.lastExecResult && getResultIcon(record.lastExecResult)) || ; - const selected = selectedUrns?.some((selectedUrn) => selectedUrn === record.urn); - const isPartOfContract = contract && isAssertionPartOfContract(record, contract); - - const { description } = record; - return ( - - {showSelect ? ( - e.stopPropagation()} - onChange={() => onSelect?.(record.urn as string)} - /> - ) : undefined} -
- - - {resultIcon} - {resultText} - - -
- {record.datasetAssertionInfo ? ( - - ) : ( - - {description ?? 'No description provided'} - - )} - - {(isPartOfContract && entityData?.urn && ( - - Part of Data Contract{' '} - - View - - - } - > - - - - - )) || - undefined} -
- ); - }, - }, - { - title: '', - dataIndex: '', - key: '', - render: (_, record: any) => { - return ( - showMenu && ( - - - - {(record.platform.properties?.logoUrl && ( - - )) || ( - - {record.platform.properties?.displayName || - capitalizeFirstLetterOnly(record.platform.name)} - - )} - - - - - - - - ) - ); - }, - }, - ]; - - return ( - <> - , - }} - expandable={ - showSelect - ? {} - : { - defaultExpandAllRows: false, - expandRowByClick: true, - expandedRowRender: (record) => { - return ( - - ); - }, - expandIcon: ({ expanded, onExpand, record }: any) => - expanded ? ( - onExpand(record, e)} /> - ) : ( - onExpand(record, e)} /> - ), - } - } - onRow={(record) => { - return { - onClick: (_) => { - if (showSelect) { - onSelect?.(record.urn as string); - } - }, - }; - }} - showHeader={false} - pagination={false} - /> - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/DatasetAssertionsSummary.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/DatasetAssertionsSummary.tsx deleted file mode 100644 index 81e07d4225f576..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/DatasetAssertionsSummary.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { CheckCircleFilled, CloseCircleFilled, StopOutlined } from '@ant-design/icons'; -import { Tooltip, Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entity/shared/constants'; - -const SummaryHeader = styled.div` - width: 100%; - padding-left: 40px; - padding-top: 20px; - padding-bottom: 20px; - display: flex; - align-items: center; - border-bottom: 1px solid ${ANTD_GRAY[4.5]}; -`; - -const SummaryContainer = styled.div``; - -const SummaryMessage = styled.div` - display: inline-block; - margin-left: 20px; -`; - -const SummaryTitle = styled(Typography.Title)` - && { - padding-bottom: 0px; - margin-bottom: 0px; - } -`; - -export type AssertionsSummary = { - totalAssertions: number; - totalRuns: number; - failedRuns: number; - succeededRuns: number; -}; - -type Props = { - summary: AssertionsSummary; -}; - -const SUCCESS_COLOR_HEX = '#52C41A'; -const FAILURE_COLOR_HEX = '#F5222D'; - -const getSummaryIcon = (summary: AssertionsSummary) => { - if (summary.totalRuns === 0) { - return ; - } - if (summary.succeededRuns === summary.totalRuns) { - return ; - } - return ; -}; - -const getSummaryMessage = (summary: AssertionsSummary) => { - if (summary.totalRuns === 0) { - return 'No assertions have run'; - } - if (summary.succeededRuns === summary.totalRuns) { - return 'All assertions have passed'; - } - if (summary.failedRuns === summary.totalRuns) { - return 'All assertions have failed'; - } - return 'Some assertions have failed'; -}; - -export const DatasetAssertionsSummary = ({ summary }: Props) => { - const summaryIcon = getSummaryIcon(summary); - const summaryMessage = getSummaryMessage(summary); - const subtitleMessage = `${summary.succeededRuns} successful assertions, ${summary.failedRuns} failed assertions`; - return ( - - - -
- {summaryIcon} - - {summaryMessage} - {subtitleMessage} - -
-
-
-
- ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/FieldAssertionDescription.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/FieldAssertionDescription.tsx deleted file mode 100644 index 65ec918895634f..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/FieldAssertionDescription.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { Typography } from 'antd'; -import React from 'react'; - -import { - getFieldDescription, - getFieldOperatorDescription, - getFieldParametersDescription, - getFieldTransformDescription, -} from '@app/entity/shared/tabs/Dataset/Validations/fieldDescriptionUtils'; - -import { FieldAssertionInfo } from '@types'; - -type Props = { - assertionInfo: FieldAssertionInfo; -}; - -/** - * A human-readable description of a Field Assertion. - */ -export const FieldAssertionDescription = ({ assertionInfo }: Props) => { - const field = getFieldDescription(assertionInfo); - const operator = getFieldOperatorDescription(assertionInfo); - const transform = getFieldTransformDescription(assertionInfo); - const parameters = getFieldParametersDescription(assertionInfo); - - return ( - - {transform} - {transform ? ' of ' : ''} - {field} {operator} {parameters} - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/SqlAssertionDescription.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/SqlAssertionDescription.tsx deleted file mode 100644 index 4eb652aa904df4..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/SqlAssertionDescription.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { Typography } from 'antd'; -import React from 'react'; - -import { AssertionInfo } from '@types'; - -type Props = { - assertionInfo: AssertionInfo; -}; - -/** - * A human-readable description of a SQL Assertion. - */ -export const SqlAssertionDescription = ({ assertionInfo }: Props) => { - const { description } = assertionInfo; - - return {description}; -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/ValidationsTab.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/ValidationsTab.tsx deleted file mode 100644 index ae1a3148cf7d7b..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/ValidationsTab.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import { AuditOutlined, FileProtectOutlined } from '@ant-design/icons'; -import { Button } from 'antd'; -import React, { useEffect } from 'react'; -import { useHistory, useLocation } from 'react-router'; -import styled from 'styled-components'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import TabToolbar from '@app/entity/shared/components/styled/TabToolbar'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { Assertions } from '@app/entity/shared/tabs/Dataset/Validations/Assertions'; -import { DataContractTab } from '@app/entity/shared/tabs/Dataset/Validations/contract/DataContractTab'; -import { useGetValidationsTab } from '@app/entity/shared/tabs/Dataset/Validations/useGetValidationsTab'; -import { useAppConfig } from '@app/useAppConfig'; - -const TabTitle = styled.span` - margin-left: 4px; -`; - -const TabButton = styled(Button)<{ selected: boolean }>` - background-color: ${(props) => (props.selected && ANTD_GRAY[3]) || 'none'}; - margin-left: 4px; -`; - -enum TabPaths { - ASSERTIONS = 'List', - DATA_CONTRACT = 'Data Contract', -} - -const DEFAULT_TAB = TabPaths.ASSERTIONS; - -/** - * Component used for rendering the Entity Validations Tab. - */ -export const ValidationsTab = () => { - const { entityData } = useEntityData(); - const history = useHistory(); - const { pathname } = useLocation(); - const appConfig = useAppConfig(); - - const totalAssertions = (entityData as any)?.assertions?.total; - - const { selectedTab, basePath } = useGetValidationsTab(pathname, Object.values(TabPaths)); - - // If no tab was selected, select a default tab. - useEffect(() => { - if (!selectedTab) { - // Route to the default tab. - history.replace(`${basePath}/${DEFAULT_TAB}`); - } - }, [selectedTab, basePath, history]); - - /** - * The top-level Toolbar tabs to display. - */ - const tabs = [ - { - title: ( - <> - - Assertions ({totalAssertions}) - - ), - path: TabPaths.ASSERTIONS, - disabled: totalAssertions === 0, - content: , - }, - ]; - - if (appConfig.config.featureFlags?.dataContractsEnabled) { - // If contracts feature is enabled, add to list. - tabs.push({ - title: ( - <> - - - Data Contract - - ), - path: TabPaths.DATA_CONTRACT, - content: , - disabled: false, - }); - } - - return ( - <> - -
- {tabs.map((tab) => ( - history.replace(`${basePath}/${tab.path}`)} - > - {tab.title} - - ))} -
-
- {tabs.filter((tab) => tab.path === selectedTab).map((tab) => tab.content)} - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/VolumeAssertionDescription.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/VolumeAssertionDescription.tsx deleted file mode 100644 index 093a817c38ed91..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/VolumeAssertionDescription.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { Typography } from 'antd'; -import React from 'react'; - -import { - getIsRowCountChange, - getOperatorDescription, - getParameterDescription, - getValueChangeTypeDescription, - getVolumeTypeDescription, - getVolumeTypeInfo, -} from '@app/entity/shared/tabs/Dataset/Validations/utils'; - -import { IncrementingSegmentRowCountChange, RowCountChange, VolumeAssertionInfo } from '@types'; - -type Props = { - assertionInfo: VolumeAssertionInfo; -}; - -/** - * A human-readable description of a Volume Assertion. - */ -export const VolumeAssertionDescription = ({ assertionInfo }: Props) => { - const volumeType = assertionInfo.type; - const volumeTypeInfo = getVolumeTypeInfo(assertionInfo); - const volumeTypeDescription = getVolumeTypeDescription(volumeType); - const operatorDescription = volumeTypeInfo ? getOperatorDescription(volumeTypeInfo.operator) : ''; - const parameterDescription = volumeTypeInfo ? getParameterDescription(volumeTypeInfo.parameters) : ''; - const valueChangeTypeDescription = getIsRowCountChange(volumeType) - ? getValueChangeTypeDescription((volumeTypeInfo as RowCountChange | IncrementingSegmentRowCountChange).type) - : 'rows'; - - return ( -
- - Table {volumeTypeDescription} {operatorDescription} {parameterDescription} {valueChangeTypeDescription} - -
- ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/acrylTypes.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/acrylTypes.tsx index abb91d7de12040..ed2bcf907c1912 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/acrylTypes.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/acrylTypes.tsx @@ -1,6 +1,6 @@ import { Assertion, AssertionType } from '@types'; -export type AssertionStatusSummary = { +type AssertionStatusSummary = { passing: number; failing: number; erroring: number; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/assertionUtils.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/assertionUtils.tsx deleted file mode 100644 index 55d693a2ed52a5..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/assertionUtils.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import { CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons'; -import React from 'react'; - -import { - AssertionResultType, - AssertionStdParameter, - AssertionStdParameterType, - DatasetAssertionInfo, - StringMapEntry, -} from '@types'; - -/** - * Utility methods - */ -export const sortAssertions = (a, b) => { - if (!a.runEvents?.runEvents?.length) { - return 1; - } - if (!b.runEvents?.runEvents?.length) { - return -1; - } - return b.runEvents?.runEvents[0]?.timestampMillis - a.runEvents?.runEvents[0]?.timestampMillis; -}; - -/** - * Returns the display text assoociated with an AssertionResultType - */ -export const getResultText = (result: AssertionResultType) => { - switch (result) { - case AssertionResultType.Success: - return 'Passed'; - case AssertionResultType.Failure: - return 'Failed'; - default: - throw new Error(`Unsupported Assertion Result Type ${result} provided.`); - } -}; - -/** - * Returns the display color assoociated with an AssertionResultType - */ -const SUCCESS_COLOR_HEX = '#4db31b'; -const FAILURE_COLOR_HEX = '#F5222D'; -export const getResultColor = (result: AssertionResultType) => { - switch (result) { - case AssertionResultType.Success: - return SUCCESS_COLOR_HEX; - case AssertionResultType.Failure: - return FAILURE_COLOR_HEX; - default: - throw new Error(`Unsupported Assertion Result Type ${result} provided.`); - } -}; - -/** - * Returns the display icon assoociated with an AssertionResultType - */ -export const getResultIcon = (result: AssertionResultType) => { - const resultColor = getResultColor(result); - switch (result) { - case AssertionResultType.Success: - return ; - case AssertionResultType.Failure: - return ; - default: - throw new Error(`Unsupported Assertion Result Type ${result} provided.`); - } -}; - -/** - * Convert an array of StringMapEntry into a map, for easy retrieval. - */ -export const convertNativeParametersArrayToMap = (nativeParameters: Array | undefined) => { - if (nativeParameters) { - const map = new Map(); - nativeParameters.forEach((parameter) => { - map.set(parameter.key, parameter.value); - }); - return map; - } - return undefined; -}; - -/** - * Returns the value of an AssertionStdParameter suitable for display - */ -const MISSING_PARAMETER_VALUE = '?'; -export const getFormattedParameterValue = (parameter: AssertionStdParameter | undefined | null): React.ReactNode => { - if (parameter === null || parameter === undefined) { - return MISSING_PARAMETER_VALUE; - } - switch (parameter.type) { - case AssertionStdParameterType.Number: - return parseFloat(parameter.value as string).toLocaleString(); - case AssertionStdParameterType.String: - return parameter.value; - case AssertionStdParameterType.Set: - return parameter.value; - default: - return Number.isNaN(Number(parameter.value as any)) - ? parameter.value - : parseFloat(parameter.value as string).toLocaleString(); - } -}; - -/** - * Throws if an assertion has no input fields - */ -export const validateAssertionsHasInputFields = (info: DatasetAssertionInfo) => { - if (info.fields && info.fields.length === 1) { - return info.fields[0].path; - } - throw new Error('Failed to find field path(s) for column assertion.'); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/DataContractAssertionStatus.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/DataContractAssertionStatus.tsx deleted file mode 100644 index 7377d45acdf404..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/DataContractAssertionStatus.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { StopOutlined } from '@ant-design/icons'; -import { Tooltip } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { - StyledCheckOutlined, - StyledClockCircleOutlined, - StyledCloseOutlined, - StyledExclamationOutlined, -} from '@app/entity/shared/tabs/Dataset/Validations/shared/styledComponents'; - -import { Assertion, AssertionResultType } from '@types'; - -const StatusContainer = styled.div` - width: 100%; - display: flex; - justify-content: center; -`; - -type Props = { - assertion: Assertion; -}; - -export const DataContractAssertionStatus = ({ assertion }: Props) => { - const latestRun = (assertion.runEvents?.runEvents?.length && assertion.runEvents?.runEvents[0]) || undefined; - const latestResultType = latestRun?.result?.type || undefined; - - return ( - - {latestResultType === undefined && } - - {latestResultType === AssertionResultType.Success && } - - - {latestResultType === AssertionResultType.Failure && } - - - {latestResultType === AssertionResultType.Error && } - - - {latestResultType === AssertionResultType.Init && } - - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/DataContractSummary.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/DataContractSummary.tsx deleted file mode 100644 index a2191975533b88..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/DataContractSummary.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import { EditFilled } from '@ant-design/icons'; -import { Button, Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { - getContractSummaryIcon, - getContractSummaryMessage, - getContractSummaryTitle, -} from '@app/entity/shared/tabs/Dataset/Validations/contract/utils'; -import { AssertionStatusSummary } from '@app/entity/shared/tabs/Dataset/Validations/types'; - -import { DataContractState } from '@types'; - -const SummaryHeader = styled.div` - width: 100%; - padding-left: 40px; - padding-top: 20px; - padding-bottom: 20px; - display: flex; - align-items: center; - justify-content: space-between; - border-bottom: 1px solid ${ANTD_GRAY[4.5]}; -`; - -const SummaryContainer = styled.div``; - -const SummaryDescription = styled.div` - display: flex; - align-items: center; -`; - -const SummaryMessage = styled.div` - display: inline-block; - margin-left: 20px; -`; - -const SummaryTitle = styled(Typography.Title)` - && { - padding-bottom: 0px; - margin-bottom: 0px; - } -`; - -const Actions = styled.div` - margin: 12px; - margin-right: 20px; -`; - -const CreateButton = styled(Button)` - display: flex; - align-items: center; - gap: 0.3rem; - margin-right: 12px; - border-color: ${(props) => props.theme.styles['primary-color']}; - color: ${(props) => props.theme.styles['primary-color']}; - letter-spacing: 2px; - &&:hover { - color: white; - background-color: ${(props) => props.theme.styles['primary-color']}; - border-color: ${(props) => props.theme.styles['primary-color']}; - } -`; - -const EditIconStyle = styled(EditFilled)` - && { - font-size: 12px; - } -`; - -type Props = { - state: DataContractState; - summary: AssertionStatusSummary; - showContractBuilder: () => void; -}; - -export const DataContractSummary = ({ state, summary, showContractBuilder }: Props) => { - const summaryIcon = getContractSummaryIcon(state, summary); - const summaryTitle = getContractSummaryTitle(state, summary); - const summaryMessage = getContractSummaryMessage(state, summary); - return ( - - - - {summaryIcon} - - {summaryTitle} - {summaryMessage} - - - - - - - EDIT - - - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/DataContractSummaryFooter.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/DataContractSummaryFooter.tsx deleted file mode 100644 index f6ad73fcc1bc36..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/DataContractSummaryFooter.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { ArrowRightOutlined } from '@ant-design/icons'; -import { Button } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY, REDESIGN_COLORS } from '@app/entity/shared/constants'; -import { - StyledCheckOutlined, - StyledCloseOutlined, - StyledExclamationOutlined, -} from '@app/entity/shared/tabs/Dataset/Validations/shared/styledComponents'; -import { getAssertionsSummary } from '@app/entity/shared/tabs/Dataset/Validations/utils'; - -import { Assertion } from '@types'; - -const Container = styled.div` - display: flex; - align-items: center; - justify-content: space-between; -`; - -const StatusContainer = styled.div` - display: flex; - align-items: center; -`; - -const StatusText = styled.div` - color: ${ANTD_GRAY[8]}; - margin-left: 4px; -`; - -const ActionButton = styled(Button)` - color: ${REDESIGN_COLORS.BLUE}; -`; - -const StyledArrowRightOutlined = styled(ArrowRightOutlined)` - font-size: 8px; -`; - -type Props = { - assertions: Assertion[]; - passingText: string; - failingText: string; - errorText: string; - actionText?: string; - showAction?: boolean; -}; - -export const DataContractSummaryFooter = ({ - assertions, - actionText, - passingText, - errorText, - failingText, - showAction = true, -}: Props) => { - const summary = getAssertionsSummary(assertions); - const isFailing = summary.failing > 0; - const isPassing = summary.passing && summary.passing === summary.total; - const isErroring = summary.erroring > 0; - return ( - - - {(isFailing && ) || undefined} - {(isPassing && ) || undefined} - {(isErroring && !isFailing && ) || undefined} - - {(isFailing && failingText) || undefined} - {(isPassing && passingText) || undefined} - {(isErroring && errorText) || undefined} - - - {showAction && ( - - {actionText} - - - )} - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/DataContractTab.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/DataContractTab.tsx deleted file mode 100644 index 4f934faf355393..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/DataContractTab.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import React, { useState } from 'react'; -import styled from 'styled-components'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { DataContractEmptyState } from '@app/entity/shared/tabs/Dataset/Validations/contract/DataContractEmptyState'; -import { DataContractSummary } from '@app/entity/shared/tabs/Dataset/Validations/contract/DataContractSummary'; -import { DataQualityContractSummary } from '@app/entity/shared/tabs/Dataset/Validations/contract/DataQualityContractSummary'; -import { FreshnessContractSummary } from '@app/entity/shared/tabs/Dataset/Validations/contract/FreshnessContractSummary'; -import { SchemaContractSummary } from '@app/entity/shared/tabs/Dataset/Validations/contract/SchemaContractSummary'; -import { DataContractBuilderModal } from '@app/entity/shared/tabs/Dataset/Validations/contract/builder/DataContractBuilderModal'; -import { createBuilderState } from '@app/entity/shared/tabs/Dataset/Validations/contract/builder/utils'; -import { getAssertionsSummary } from '@app/entity/shared/tabs/Dataset/Validations/utils'; - -import { useGetDatasetContractQuery } from '@graphql/contract.generated'; -import { DataContractState } from '@types'; - -const Container = styled.div` - display: flex; -`; - -const LeftColumn = styled.div` - width: 50%; -`; - -const RightColumn = styled.div` - width: 50%; -`; - -/** - * Component used for rendering the Data Contract Tab on the Assertions parent tab. - */ -export const DataContractTab = () => { - const { urn } = useEntityData(); - - const { data, refetch } = useGetDatasetContractQuery({ - variables: { - urn, - }, - }); - const [showContractBuilder, setShowContractBuilder] = useState(false); - - const contract = data?.dataset?.contract; - const schemaContracts = data?.dataset?.contract?.properties?.schema || []; - const freshnessContracts = data?.dataset?.contract?.properties?.freshness || []; - const dataQualityContracts = data?.dataset?.contract?.properties?.dataQuality || []; - const schemaAssertions = schemaContracts.map((c) => c.assertion); - const freshnessAssertions = freshnessContracts.map((c) => c.assertion); - const dataQualityAssertions = dataQualityContracts.map((c) => c.assertion); - const assertionsSummary = getAssertionsSummary([ - ...schemaAssertions, - ...freshnessAssertions, - ...dataQualityAssertions, - ] as any); - const contractState = data?.dataset?.contract?.status?.state || DataContractState.Active; - const hasFreshnessContract = freshnessContracts && freshnessContracts?.length; - const hasSchemaContract = schemaContracts && schemaContracts?.length; - const hasDataQualityContract = dataQualityContracts && dataQualityContracts?.length; - const showLeftColumn = hasFreshnessContract || hasSchemaContract || undefined; - - const onContractUpdate = () => { - if (contract) { - // Contract exists, just refetch. - refetch(); - } else { - // no contract yet, wait for indxing, - setTimeout(() => refetch(), 3000); - } - setShowContractBuilder(false); - }; - - return ( - <> - {data?.dataset?.contract ? ( - <> - setShowContractBuilder(true)} - /> - - {showLeftColumn && ( - - {(hasFreshnessContract && ( - - )) || - undefined} - {(hasSchemaContract && ( - - )) || - undefined} - - )} - - {hasDataQualityContract ? ( - - ) : undefined} - - - - ) : ( - setShowContractBuilder(true)} /> - )} - {showContractBuilder && ( - setShowContractBuilder(false)} - onSubmit={onContractUpdate} - /> - )} - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/DataQualityContractSummary.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/DataQualityContractSummary.tsx deleted file mode 100644 index 536612ae166906..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/DataQualityContractSummary.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import { Table, Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { DatasetAssertionDescription } from '@app/entity/shared/tabs/Dataset/Validations/DatasetAssertionDescription'; -import { FieldAssertionDescription } from '@app/entity/shared/tabs/Dataset/Validations/FieldAssertionDescription'; -import { SqlAssertionDescription } from '@app/entity/shared/tabs/Dataset/Validations/SqlAssertionDescription'; -import { VolumeAssertionDescription } from '@app/entity/shared/tabs/Dataset/Validations/VolumeAssertionDescription'; -import { DataContractAssertionStatus } from '@app/entity/shared/tabs/Dataset/Validations/contract/DataContractAssertionStatus'; -import { DataContractSummaryFooter } from '@app/entity/shared/tabs/Dataset/Validations/contract/DataContractSummaryFooter'; - -import { Assertion, AssertionType, DataQualityContract, DatasetAssertionInfo } from '@types'; - -const TitleText = styled.div` - color: ${ANTD_GRAY[7]}; - margin-bottom: 20px; - letter-spacing: 1px; -`; - -const ColumnHeader = styled.div` - color: ${ANTD_GRAY[8]}; -`; - -const Container = styled.div` - padding: 28px; -`; - -const SummaryContainer = styled.div` - width: 100%; - display: flex; - align-items: center; -`; - -const StyledTable = styled(Table)` - width: 100%; - border-radius: 8px; - box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.1); -`; - -type Props = { - contracts: DataQualityContract[]; - showAction?: boolean; -}; - -export const DataQualityContractSummary = ({ contracts, showAction = false }: Props) => { - const assertions: Assertion[] = contracts?.map((contract) => contract.assertion); - - const columns = [ - { - title: () => ASSERTION, - render: (assertion: Assertion) => ( - <> - {assertion.info?.datasetAssertion && ( - - )} - {assertion.info?.volumeAssertion && ( - - )} - {assertion.info?.fieldAssertion && ( - - )} - {assertion.info?.sqlAssertion && } - {assertion.info?.type === AssertionType.Custom && ( - {assertion.info?.description} - )} - - ), - }, - { - title: () => STATUS, - render: (assertion: Assertion) => , - }, - ]; - - const data = (assertions || []).map((assertion) => ({ - ...assertion, - key: assertion.urn, - })); - - return ( - - DATA QUALITY - - ( - - )} - /> - - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/FreshnessContractSummary.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/FreshnessContractSummary.tsx deleted file mode 100644 index d9780856dad84f..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/FreshnessContractSummary.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import { ClockCircleOutlined } from '@ant-design/icons'; -import { Divider } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { DataContractSummaryFooter } from '@app/entity/shared/tabs/Dataset/Validations/contract/DataContractSummaryFooter'; -import { FreshnessScheduleSummary } from '@app/entity/shared/tabs/Dataset/Validations/contract/FreshnessScheduleSummary'; - -import { FreshnessContract } from '@types'; - -const Container = styled.div` - padding: 28px; -`; - -const TitleText = styled.div` - color: ${ANTD_GRAY[7]}; - margin-bottom: 20px; - letter-spacing: 1px; -`; - -const ThinDivider = styled(Divider)` - && { - padding: 0px; - margin: 0px; - } -`; - -const Header = styled.div` - color: ${ANTD_GRAY[8]}; - letter-spacing; 4px; - padding-top: 8px; - padding: 12px; - background-color: ${ANTD_GRAY[2]}; -`; - -const Body = styled.div` - padding: 12px; -`; - -const Footer = styled.div` - padding-top: 8px; - padding: 12px; - background-color: ${ANTD_GRAY[2]}; -`; - -const SummaryContainer = styled.div` - width: 100%; - border-radius: 8px; - box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.1); -`; - -type Props = { - contracts: FreshnessContract[]; - showAction?: boolean; -}; - -export const FreshnessContractSummary = ({ contracts, showAction = false }: Props) => { - // TODO: Support multiple per-asset contracts. - const firstContract = (contracts.length && contracts[0]) || undefined; - const assertionDefinition = firstContract?.assertion?.info?.freshnessAssertion?.schedule; - const evaluationSchedule = (firstContract?.assertion as any)?.monitor?.relationships[0]?.entity?.info - ?.assertionMonitor?.assertions[0]?.schedule; - - return ( - - FRESHNESS - -
- - UPDATE FREQUENCY -
- - {!assertionDefinition && <>No contract found :(} - - {assertionDefinition && ( - - )} - - - -
- -
-
-
- ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/FreshnessScheduleSummary.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/FreshnessScheduleSummary.tsx deleted file mode 100644 index e51918a95ee7d9..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/FreshnessScheduleSummary.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import cronstrue from 'cronstrue'; -import React from 'react'; - -import { capitalizeFirstLetter } from '@app/shared/textUtil'; - -import { CronSchedule, FreshnessAssertionSchedule, FreshnessAssertionScheduleType } from '@types'; - -type Props = { - definition: FreshnessAssertionSchedule; - evaluationSchedule?: CronSchedule; // When the assertion is run. -}; - -export const FreshnessScheduleSummary = ({ definition, evaluationSchedule }: Props) => { - let scheduleText = ''; - const cronStr = definition.cron?.cron ?? evaluationSchedule?.cron; - switch (definition.type) { - case FreshnessAssertionScheduleType.Cron: - scheduleText = cronStr - ? `${capitalizeFirstLetter(cronstrue.toString(cronStr))}.` - : `Unknown freshness schedule.`; - break; - case FreshnessAssertionScheduleType.SinceTheLastCheck: - scheduleText = cronStr - ? `Since the previous check, as of ${cronstrue.toString(cronStr).toLowerCase()}` - : 'Since the previous check'; - break; - case FreshnessAssertionScheduleType.FixedInterval: - scheduleText = `In the past ${ - definition.fixedInterval?.multiple - } ${definition.fixedInterval?.unit?.toLocaleLowerCase()}s${ - cronStr ? `, as of ${cronstrue.toString(cronStr).toLowerCase()}` : '' - }`; - break; - default: - break; - } - - return <>{scheduleText}; -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/SchemaContractSummary.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/SchemaContractSummary.tsx deleted file mode 100644 index 3f8315b4a30fc6..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/SchemaContractSummary.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { Table } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { DataContractSummaryFooter } from '@app/entity/shared/tabs/Dataset/Validations/contract/DataContractSummaryFooter'; - -import { SchemaContract } from '@types'; - -const TitleText = styled.div` - color: ${ANTD_GRAY[7]}; - margin-bottom: 20px; - letter-spacing: 1px; -`; - -const ColumnHeader = styled.div` - color: ${ANTD_GRAY[8]}; -`; - -const Container = styled.div` - padding: 28px; -`; - -const SummaryContainer = styled.div` - width: 100%; - display: flex; - align-items: center; -`; - -const StyledTable = styled(Table)` - width: 100%; - border-radius: 8px; - box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.1); - height: 100%; -`; - -type Props = { - contracts: SchemaContract[]; - showAction?: boolean; -}; - -export const SchemaContractSummary = ({ contracts, showAction = false }: Props) => { - const firstContract = (contracts.length && contracts[0]) || undefined; - const schemaMetadata = firstContract?.assertion?.info?.schemaAssertion?.schema; - - const columns = [ - { - title: () => NAME, - render: (field) => <>{field.fieldPath}, - }, - { - title: () => TYPE, - render: (field) => <>{field.type}, - }, - ]; - - const data = (schemaMetadata?.fields || []).map((field) => ({ - ...field, - key: field.fieldPath, - })); - - return ( - - SCHEMA - - ( - - )} - /> - - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/builder/DataContractAssertionGroupSelect.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/builder/DataContractAssertionGroupSelect.tsx deleted file mode 100644 index 8e4a3d8e3564f5..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/builder/DataContractAssertionGroupSelect.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { DatasetAssertionsList } from '@app/entity/shared/tabs/Dataset/Validations/DatasetAssertionsList'; -import { DataContractCategoryType } from '@app/entity/shared/tabs/Dataset/Validations/contract/builder/types'; - -import { Assertion } from '@types'; - -const Category = styled.div` - padding: 20px; - font-weight: bold; - font-size: 14px; - background-color: ${ANTD_GRAY[3]}; - border-radius: 4px; -`; - -const Hint = styled.span` - font-weight: normal; - font-size: 14px; - color: ${ANTD_GRAY[8]}; -`; - -type Props = { - category: DataContractCategoryType; - multiple?: boolean; - assertions: Assertion[]; - selectedUrns: string[]; - onSelect: (assertionUrn: string) => void; -}; - -/** - * Used for selecting the assertions that are part of a data contract - */ -export const DataContractAssertionGroupSelect = ({ - category, - assertions, - multiple = true, - selectedUrns, - onSelect, -}: Props) => { - return ( - <> - - {category} {!multiple ? `(Choose 1)` : ''} - - - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/builder/DataContractBuilder.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/builder/DataContractBuilder.tsx deleted file mode 100644 index f29a33b1605947..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/builder/DataContractBuilder.tsx +++ /dev/null @@ -1,182 +0,0 @@ -import { Button, message } from 'antd'; -import lodash from 'lodash'; -import React, { useState } from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { DataContractAssertionGroupSelect } from '@app/entity/shared/tabs/Dataset/Validations/contract/builder/DataContractAssertionGroupSelect'; -import { - DEFAULT_BUILDER_STATE, - DataContractBuilderState, - DataContractCategoryType, -} from '@app/entity/shared/tabs/Dataset/Validations/contract/builder/types'; -import { buildUpsertDataContractMutationVariables } from '@app/entity/shared/tabs/Dataset/Validations/contract/builder/utils'; -import { DATA_QUALITY_ASSERTION_TYPES } from '@app/entity/shared/tabs/Dataset/Validations/contract/utils'; -import { createAssertionGroups } from '@app/entity/shared/tabs/Dataset/Validations/utils'; - -import { useUpsertDataContractMutation } from '@graphql/contract.generated'; -import { useGetDatasetAssertionsQuery } from '@graphql/dataset.generated'; -import { Assertion, AssertionType, DataContract } from '@types'; - -const AssertionsSection = styled.div` - border: 0.5px solid ${ANTD_GRAY[4]}; -`; - -const HeaderText = styled.div` - padding: 16px 20px; - color: ${ANTD_GRAY[7]}; - font-size: 16px; -`; - -const ActionContainer = styled.div` - display: flex; - justify-content: space-between; - margin-top: 16px; -`; - -const CancelButton = styled(Button)` - margin-left: 12px; -`; - -const SaveButton = styled(Button)` - margin-right: 20px; -`; - -type Props = { - entityUrn: string; - initialState?: DataContractBuilderState; - onSubmit?: (contract: DataContract) => void; - onCancel?: () => void; -}; - -/** - * This component is a modal used for constructing new Data Contracts - * - * In order to build a data contract, we simply list all dataset assertions and allow the user to choose. - */ -export const DataContractBuilder = ({ entityUrn, initialState, onSubmit, onCancel }: Props) => { - const isEdit = !!initialState; - const [builderState, setBuilderState] = useState(initialState || DEFAULT_BUILDER_STATE); - const [upsertDataContractMutation] = useUpsertDataContractMutation(); - - // note that for contracts, we do not allow the use of sibling node assertions, for clarity. - const { data } = useGetDatasetAssertionsQuery({ - variables: { urn: entityUrn }, - fetchPolicy: 'cache-first', - }); - const assertionData = data?.dataset?.assertions?.assertions ?? []; - - const assertionGroups = createAssertionGroups(assertionData as Array); - const freshnessAssertions = - assertionGroups.find((group) => group.type === AssertionType.Freshness)?.assertions || []; - const schemaAssertions = assertionGroups.find((group) => group.type === AssertionType.DataSchema)?.assertions || []; - const dataQualityAssertions = assertionGroups - .filter((group) => DATA_QUALITY_ASSERTION_TYPES.has(group.type)) - .flatMap((group) => group.assertions || []); - - /** - * Upserts the Data Contract for an entity - */ - const upsertDataContract = () => { - return upsertDataContractMutation({ - variables: buildUpsertDataContractMutationVariables(entityUrn, builderState), - }) - .then(({ data: dataContract, errors }) => { - if (!errors) { - message.success({ - content: isEdit ? `Edited Data Contract` : `Created Data Contract!`, - duration: 3, - }); - onSubmit?.(dataContract?.upsertDataContract as DataContract); - } - }) - .catch(() => { - message.destroy(); - message.error({ content: 'Failed to create Data Contract! An unexpected error occurred' }); - }); - }; - - const onSelectDataAssertion = (assertionUrn: string, type: string) => { - const selected = builderState[type]?.some((c) => c.assertionUrn === assertionUrn); - if (selected) { - setBuilderState({ - ...builderState, - [type]: builderState[type]?.filter((c) => c.assertionUrn !== assertionUrn), - }); - } else { - setBuilderState({ - ...builderState, - [type]: [...(builderState[type] || []), { assertionUrn }], - }); - } - }; - - const editDisabled = - lodash.isEqual(builderState, initialState) || lodash.isEqual(builderState, DEFAULT_BUILDER_STATE); - - const hasAssertions = freshnessAssertions.length || schemaAssertions.length || dataQualityAssertions.length; - - const onSelectFreshnessOrSchemaAssertion = (assertionUrn: string, type: string) => { - const selected = builderState[type]?.assertionUrn === assertionUrn; - if (selected) { - setBuilderState({ - ...builderState, - [type]: undefined, - }); - } else { - setBuilderState({ - ...builderState, - [type]: { assertionUrn }, - }); - } - }; - - return ( - <> - {(hasAssertions && Select the assertions that will make up your contract.) || ( - Add a few assertions on this entity to create a data contract out of them. - )} - - {(freshnessAssertions.length && ( - onSelectFreshnessOrSchemaAssertion(selectedUrn, 'freshness')} - /> - )) || - undefined} - {(schemaAssertions.length && ( - onSelectFreshnessOrSchemaAssertion(selectedUrn, 'schema')} - /> - )) || - undefined} - {(dataQualityAssertions.length && ( - c.assertionUrn) || []} - onSelect={(selectedUrn: string) => onSelectDataAssertion(selectedUrn, 'dataQuality')} - /> - )) || - undefined} - - - Cancel -
- - Save - -
-
- - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/builder/DataContractBuilderModal.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/builder/DataContractBuilderModal.tsx deleted file mode 100644 index 44c1ba8afc74bc..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/builder/DataContractBuilderModal.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { Modal, Typography } from 'antd'; -import React from 'react'; - -import { DataContractBuilder } from '@app/entity/shared/tabs/Dataset/Validations/contract/builder/DataContractBuilder'; -import { DataContractBuilderState } from '@app/entity/shared/tabs/Dataset/Validations/contract/builder/types'; -import ClickOutside from '@app/shared/ClickOutside'; - -import { DataContract } from '@types'; - -const modalStyle = {}; -const modalBodyStyle = { - paddingRight: 0, - paddingLeft: 0, - paddingBottom: 20, - paddingTop: 0, - maxHeight: '70vh', - 'overflow-x': 'auto', -}; - -type Props = { - entityUrn: string; - initialState?: DataContractBuilderState; - onSubmit?: (contract: DataContract) => void; - onCancel?: () => void; -}; - -/** - * This component is a modal used for constructing new Data Contracts - */ -export const DataContractBuilderModal = ({ entityUrn, initialState, onSubmit, onCancel }: Props) => { - const isEditing = initialState !== undefined; - const titleText = isEditing ? 'Edit Data Contract' : 'New Data Contract'; - - const modalClosePopup = () => { - Modal.confirm({ - title: 'Exit Editor', - content: `Are you sure you want to exit the editor? All changes will be lost`, - onOk() { - onCancel?.(); - }, - onCancel() {}, - okText: 'Yes', - maskClosable: true, - closable: true, - }); - }; - - return ( - - {titleText}} - style={modalStyle} - bodyStyle={modalBodyStyle} - open - onCancel={onCancel} - > - - - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/builder/types.ts b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/builder/types.ts deleted file mode 100644 index d527837efd72ef..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/builder/types.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * The Data Contract Builder state - */ -export type DataContractBuilderState = { - /** - * The schema contract. In the UI, we only support defining a single schema contract. - */ - schema?: { - assertionUrn: string; - }; - - /** - * The freshness contract. In the UI, we only support defining a single freshness contract. - */ - freshness?: { - assertionUrn: string; - }; - - /** - * Data Quality contract. We cane define multiple data quality rules as part of the contract. - */ - dataQuality?: { - assertionUrn: string; - }[]; -}; - -export const DEFAULT_BUILDER_STATE = { - dataQuality: undefined, - schema: undefined, - freshness: undefined, -}; - -export enum DataContractCategoryType { - FRESHNESS = 'Freshness', - SCHEMA = 'Schema', - DATA_QUALITY = 'Data Quality', -} diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/builder/utils.ts b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/builder/utils.ts deleted file mode 100644 index 1cbe574ec18ceb..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/builder/utils.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { - DataContractBuilderState, - DataContractCategoryType, -} from '@app/entity/shared/tabs/Dataset/Validations/contract/builder/types'; - -import { DataContract } from '@types'; - -/** - * Creates a builder state instance from a Data Contract object. - */ -export const createBuilderState = (contract?: DataContract | null): DataContractBuilderState | undefined => { - if (contract) { - return { - schema: - (contract?.properties?.schema?.length && { - assertionUrn: contract?.properties?.schema[0]?.assertion?.urn, - }) || - undefined, - freshness: - (contract?.properties?.freshness?.length && { - assertionUrn: contract?.properties?.freshness[0]?.assertion?.urn, - }) || - undefined, - dataQuality: - contract?.properties?.dataQuality?.map((c) => ({ assertionUrn: c.assertion.urn })) || undefined, - }; - } - return undefined; -}; - -/** - * Constructs the input variables required for upserting a data contract using graphql - */ -export const buildUpsertDataContractMutationVariables = (entityUrn: string, state: DataContractBuilderState) => { - return { - input: { - entityUrn, - freshness: (state.freshness && [state.freshness]) || [], - schema: (state.schema && [state.schema]) || [], - dataQuality: state.dataQuality || [], - }, - }; -}; - -/** - * Constructs the input variables required for removing an assertion from a data contract using graphql. - */ -export const buildRemoveAssertionFromContractMutationVariables = ( - entityUrn: string, - assertionUrn: string, - contract?: DataContract, -) => { - return { - input: { - entityUrn, - freshness: contract?.properties?.freshness - ?.filter((c) => c.assertion.urn !== assertionUrn) - ?.map((c) => ({ - assertionUrn: c.assertion.urn, - })), - schema: contract?.properties?.schema - ?.filter((c) => c.assertion.urn !== assertionUrn) - ?.map((c) => ({ - assertionUrn: c.assertion.urn, - })), - dataQuality: contract?.properties?.dataQuality - ?.filter((c) => c.assertion.urn !== assertionUrn) - ?.map((c) => ({ - assertionUrn: c.assertion.urn, - })), - }, - }; -}; - -/** - * Constructs the input variables required for adding an assertion to a data contract using graphql. - */ -export const buildAddAssertionToContractMutationVariables = ( - category: DataContractCategoryType, - entityUrn: string, - assertionUrn: string, - contract?: DataContract, -) => { - const baseInput = { - entityUrn, - freshness: contract?.properties?.freshness?.map((c) => ({ - assertionUrn: c.assertion.urn, - })), - schema: contract?.properties?.schema?.map((c) => ({ - assertionUrn: c.assertion.urn, - })), - dataQuality: contract?.properties?.dataQuality?.map((c) => ({ - assertionUrn: c.assertion.urn, - })), - }; - - switch (category) { - case DataContractCategoryType.SCHEMA: - // Replace schema assertion. We only support 1 schema assertion at a time (currently). - return { - input: { - ...baseInput, - schema: [{ assertionUrn }], - }, - }; - case DataContractCategoryType.FRESHNESS: - // Replace freshness assertion. We only support 1 freshness assertion at a time (currently). - return { - input: { - ...baseInput, - freshness: [{ assertionUrn }], - }, - }; - case DataContractCategoryType.DATA_QUALITY: - return { - input: { - ...baseInput, - dataQuality: [...(baseInput.dataQuality || []), { assertionUrn }], - }, - }; - default: - throw new Error(`Unrecognized category type ${category} provided.`); - } -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/utils.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/utils.tsx deleted file mode 100644 index efa53dc33da9a6..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/contract/utils.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import { - CheckOutlined, - ClockCircleOutlined, - CloseOutlined, - ExclamationCircleFilled, - StopOutlined, -} from '@ant-design/icons'; -import React from 'react'; - -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { DataContractCategoryType } from '@app/entity/shared/tabs/Dataset/Validations/contract/builder/types'; -import { AssertionStatusSummary } from '@app/entity/shared/tabs/Dataset/Validations/types'; -import { - FAILURE_COLOR_HEX, - SUCCESS_COLOR_HEX, - WARNING_COLOR_HEX, -} from '@app/entity/shared/tabs/Dataset/Validations/utils'; - -import { Assertion, AssertionType, DataContract, DataContractState } from '@types'; - -export const getContractSummaryIcon = (state: DataContractState, summary: AssertionStatusSummary) => { - if (state === DataContractState.Pending) { - return ; - } - if (summary.total === 0) { - return ; - } - if (summary.passing === summary.total) { - return ; - } - if (summary.failing > 0) { - return ; - } - if (summary.erroring > 0) { - return ; - } - return ; -}; - -export const getContractSummaryTitle = (state: DataContractState, summary: AssertionStatusSummary) => { - if (state === DataContractState.Pending) { - return 'This contract is pending implementation'; - } - if (summary.total === 0) { - return 'This contract has not yet been validated'; - } - if (summary.passing === summary.total) { - return 'This dataset is meeting its contract'; - } - if (summary.failing > 0) { - return 'This dataset is not meeting its contract'; - } - if (summary.erroring > 0) { - return 'Unable to determine contract status'; - } - return 'This contract has not yet been validated'; -}; - -export const getContractSummaryMessage = (state: DataContractState, summary: AssertionStatusSummary) => { - if (state === DataContractState.Pending) { - return 'This may take some time. Come back later!'; - } - if (summary.total === 0) { - return 'No contract assertions have been run yet'; - } - if (summary.passing === summary.total) { - return 'All contract assertions are passing'; - } - if (summary.failing > 0) { - return 'Some contract assertions are failing'; - } - if (summary.erroring > 0) { - return 'Some contract assertions are completing with errors'; - } - return 'No contract assertions have been run yet'; -}; - -/** - * Returns true if a given assertion is part of a given contract, false otherwise. - */ -export const isAssertionPartOfContract = (assertion: Assertion, contract: DataContract) => { - if (contract.properties?.dataQuality?.some((c) => c.assertion.urn === assertion.urn)) { - return true; - } - if (contract.properties?.schema?.some((c) => c.assertion.urn === assertion.urn)) { - return true; - } - if (contract.properties?.freshness?.some((c) => c.assertion.urn === assertion.urn)) { - return true; - } - return false; -}; - -/** - * Retrieves the high level contract category - schema, freshness, or data quality - given an assertion - */ -export const getDataContractCategoryFromAssertion = (assertion: Assertion) => { - if ( - assertion.info?.type === AssertionType.Dataset || - assertion.info?.type === AssertionType.Volume || - assertion.info?.type === AssertionType.Field || - assertion.info?.type === AssertionType.Sql - ) { - return DataContractCategoryType.DATA_QUALITY; - } - if (assertion.info?.type === AssertionType.Freshness) { - return DataContractCategoryType.FRESHNESS; - } - if (assertion.info?.type === AssertionType.DataSchema) { - return DataContractCategoryType.SCHEMA; - } - return DataContractCategoryType.DATA_QUALITY; -}; - -export const DATA_QUALITY_ASSERTION_TYPES = new Set([ - AssertionType.Volume, - AssertionType.Sql, - AssertionType.Field, - AssertionType.Dataset, - AssertionType.Custom, -]); diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/fieldDescriptionUtils.ts b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/fieldDescriptionUtils.ts deleted file mode 100644 index cd6039a8494f97..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/fieldDescriptionUtils.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { formatNumberWithoutAbbreviation } from '@app/shared/formatNumber'; -import { parseMaybeStringAsFloatOrDefault } from '@app/shared/numberUtil'; - -import { - AssertionStdOperator, - AssertionStdParameters, - FieldAssertionInfo, - FieldAssertionType, - FieldMetricType, - FieldTransformType, -} from '@types'; - -const ASSERTION_OPERATOR_TO_DESCRIPTION: Record = { - [AssertionStdOperator.EqualTo]: 'Is equal to', - [AssertionStdOperator.NotEqualTo]: 'Is not equal to', - [AssertionStdOperator.Contain]: 'Contains', - [AssertionStdOperator.RegexMatch]: 'Matches', - [AssertionStdOperator.StartWith]: 'Starts with', - [AssertionStdOperator.EndWith]: 'Ends with', - [AssertionStdOperator.In]: 'Is in', - [AssertionStdOperator.NotIn]: 'Is not in', - - [AssertionStdOperator.IsFalse]: 'Is False', - [AssertionStdOperator.IsTrue]: 'Is True', - [AssertionStdOperator.Null]: 'Is NULL', - [AssertionStdOperator.NotNull]: 'Is not NULL', - - [AssertionStdOperator.GreaterThan]: 'Is greater than', - [AssertionStdOperator.GreaterThanOrEqualTo]: 'Is greater than or equal to', - [AssertionStdOperator.LessThan]: 'Is less than', - [AssertionStdOperator.LessThanOrEqualTo]: 'Is less than or equal to', - [AssertionStdOperator.Between]: 'Is within a range', - - [AssertionStdOperator.Native]: undefined, -}; - -const SUPPORTED_OPERATORS_FOR_FIELD_DESCRIPTION = [ - AssertionStdOperator.EqualTo, - AssertionStdOperator.Null, - AssertionStdOperator.NotNull, - AssertionStdOperator.NotEqualTo, - AssertionStdOperator.NotIn, - AssertionStdOperator.RegexMatch, - AssertionStdOperator.GreaterThan, - AssertionStdOperator.LessThan, - AssertionStdOperator.GreaterThanOrEqualTo, - AssertionStdOperator.LessThanOrEqualTo, - AssertionStdOperator.In, - AssertionStdOperator.Between, - AssertionStdOperator.Contain, - AssertionStdOperator.IsTrue, - AssertionStdOperator.IsFalse, -]; - -const getAssertionStdOperator = (operator: AssertionStdOperator) => { - if (!ASSERTION_OPERATOR_TO_DESCRIPTION[operator] || !SUPPORTED_OPERATORS_FOR_FIELD_DESCRIPTION.includes(operator)) { - throw new Error(`Unknown operator ${operator}`); - } - return ASSERTION_OPERATOR_TO_DESCRIPTION[operator]?.toLowerCase(); -}; - -export const getFieldMetricTypeReadableLabel = (metric: FieldMetricType) => { - switch (metric) { - case FieldMetricType.NullCount: - return 'Null count'; - case FieldMetricType.NullPercentage: - return 'Null percentage'; - case FieldMetricType.UniqueCount: - return 'Unique count'; - case FieldMetricType.UniquePercentage: - return 'Unique percentage'; - case FieldMetricType.MaxLength: - return 'Max length'; - case FieldMetricType.MinLength: - return 'Min length'; - case FieldMetricType.EmptyCount: - return 'Empty count'; - case FieldMetricType.EmptyPercentage: - return 'Empty percentage'; - case FieldMetricType.Max: - return 'Max'; - case FieldMetricType.Min: - return 'Min'; - case FieldMetricType.Mean: - return 'Average'; - case FieldMetricType.Median: - return 'Median'; - case FieldMetricType.NegativeCount: - return 'Negative count'; - case FieldMetricType.NegativePercentage: - return 'Negative percentage'; - case FieldMetricType.Stddev: - return 'Standard deviation'; - case FieldMetricType.ZeroCount: - return 'Zero count'; - case FieldMetricType.ZeroPercentage: - return 'Zero percentage'; - default: - throw new Error(`Unknown field metric type ${metric}`); - } -}; - -const getFieldTransformType = (transform: FieldTransformType) => { - switch (transform) { - case FieldTransformType.Length: - return 'Length'; - default: - throw new Error(`Unknown field transform type ${transform}`); - } -}; - -const getAssertionStdParameters = (parameters: AssertionStdParameters) => { - if (parameters.value) { - return formatNumberWithoutAbbreviation( - parseMaybeStringAsFloatOrDefault(parameters.value.value, parameters.value.value), - ); - } - if (parameters.minValue && parameters.maxValue) { - return `${formatNumberWithoutAbbreviation( - parseMaybeStringAsFloatOrDefault(parameters.minValue.value, parameters.minValue.value), - )} and ${formatNumberWithoutAbbreviation( - parseMaybeStringAsFloatOrDefault(parameters.maxValue.value, parameters.maxValue.value), - )}`; - } - return ''; -}; - -export const getFieldDescription = (assertionInfo: FieldAssertionInfo) => { - const { type, fieldValuesAssertion, fieldMetricAssertion } = assertionInfo; - switch (type) { - case FieldAssertionType.FieldValues: - return fieldValuesAssertion?.field?.path; - case FieldAssertionType.FieldMetric: - return fieldMetricAssertion?.field?.path; - default: - throw new Error(`Unknown field assertion type ${type}`); - } -}; - -export const getFieldOperatorDescription = (assertionInfo: FieldAssertionInfo) => { - const { type, fieldValuesAssertion, fieldMetricAssertion } = assertionInfo; - switch (type) { - case FieldAssertionType.FieldValues: - if (!fieldValuesAssertion?.operator) return ''; - return getAssertionStdOperator(fieldValuesAssertion.operator); - case FieldAssertionType.FieldMetric: - if (!fieldMetricAssertion?.operator) return ''; - return getAssertionStdOperator(fieldMetricAssertion.operator); - default: - throw new Error(`Unknown field assertion type ${type}`); - } -}; - -export const getFieldTransformDescription = (assertionInfo: FieldAssertionInfo) => { - const { type, fieldValuesAssertion, fieldMetricAssertion } = assertionInfo; - switch (type) { - case FieldAssertionType.FieldValues: - if (!fieldValuesAssertion?.transform?.type) return ''; - return getFieldTransformType(fieldValuesAssertion.transform.type); - case FieldAssertionType.FieldMetric: - if (!fieldMetricAssertion?.metric) return ''; - return getFieldMetricTypeReadableLabel(fieldMetricAssertion.metric); - default: - throw new Error(`Unknown field assertion type ${type}`); - } -}; - -export const getFieldParametersDescription = (assertionInfo: FieldAssertionInfo) => { - const { type, fieldValuesAssertion, fieldMetricAssertion } = assertionInfo; - switch (type) { - case FieldAssertionType.FieldValues: - if (!fieldValuesAssertion?.parameters) return ''; - return getAssertionStdParameters(fieldValuesAssertion.parameters); - case FieldAssertionType.FieldMetric: - if (!fieldMetricAssertion?.parameters) return ''; - return getAssertionStdParameters(fieldMetricAssertion.parameters); - default: - throw new Error(`Unknown field assertion type ${type}`); - } -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/shared/styledComponents.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/shared/styledComponents.tsx deleted file mode 100644 index 66661f224b7188..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/shared/styledComponents.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { CheckOutlined, ClockCircleOutlined, CloseOutlined, ExclamationCircleOutlined } from '@ant-design/icons'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { - FAILURE_COLOR_HEX, - SUCCESS_COLOR_HEX, - WARNING_COLOR_HEX, -} from '@app/entity/shared/tabs/Dataset/Validations/utils'; - -export const StyledCheckOutlined = styled(CheckOutlined)` - color: ${SUCCESS_COLOR_HEX}; - font-size: 16px; - margin-right: 4px; - margin-left: 4px; -`; - -export const StyledCloseOutlined = styled(CloseOutlined)` - color: ${FAILURE_COLOR_HEX}; - font-size: 16px; - margin-right: 4px; - margin-left: 4px; -`; - -export const StyledExclamationOutlined = styled(ExclamationCircleOutlined)` - color: ${WARNING_COLOR_HEX}; - font-size: 16px; - margin-right: 4px; - margin-left: 4px; -`; - -export const StyledClockCircleOutlined = styled(ClockCircleOutlined)` - color: ${ANTD_GRAY[6]}; - font-size: 16px; - margin-right: 4px; - margin-left: 4px; -`; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/types.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/types.tsx deleted file mode 100644 index abb91d7de12040..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/types.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Assertion, AssertionType } from '@types'; - -export type AssertionStatusSummary = { - passing: number; - failing: number; - erroring: number; - total: number; // Total assertions with at least 1 run. - totalAssertions: number; -}; - -/** - * A group of assertions related by their logical type or category. - */ -export type AssertionGroup = { - name: string; - icon: React.ReactNode; - description?: string; - assertions: Assertion[]; - summary: AssertionStatusSummary; - type: AssertionType; -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/useGetValidationsTab.ts b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/useGetValidationsTab.ts index 164e8e489e3465..7fcfd2f82aed27 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/useGetValidationsTab.ts +++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/useGetValidationsTab.ts @@ -5,7 +5,7 @@ */ const VALIDATION_TAB_NAME_REGEX_PATTERN = '^/[^/]+/[^/]+/[^/]+/([^/]+).*'; -export type SelectedTab = { +type SelectedTab = { basePath: string; selectedTab: string | undefined; }; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/utils.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/utils.tsx deleted file mode 100644 index 060fed7c19dde7..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Validations/utils.tsx +++ /dev/null @@ -1,380 +0,0 @@ -import { - ApiOutlined, - CheckOutlined, - ClockCircleOutlined, - CloseOutlined, - CodeOutlined, - ConsoleSqlOutlined, - ExclamationCircleOutlined, - ProjectOutlined, - TableOutlined, -} from '@ant-design/icons'; -import React from 'react'; -import styled from 'styled-components'; - -import { sortAssertions } from '@app/entity/shared/tabs/Dataset/Validations/assertionUtils'; -import { AssertionGroup, AssertionStatusSummary } from '@app/entity/shared/tabs/Dataset/Validations/types'; -import { formatNumberWithoutAbbreviation } from '@app/shared/formatNumber'; -import { parseMaybeStringAsFloatOrDefault } from '@app/shared/numberUtil'; - -import { - Assertion, - AssertionResultType, - AssertionStdOperator, - AssertionStdParameters, - AssertionType, - AssertionValueChangeType, - EntityType, - VolumeAssertionInfo, - VolumeAssertionType, -} from '@types'; - -export const SUCCESS_COLOR_HEX = '#52C41A'; -export const FAILURE_COLOR_HEX = '#F5222D'; -export const WARNING_COLOR_HEX = '#FA8C16'; - -const StyledClockCircleOutlined = styled(ClockCircleOutlined)` - && { - margin: 0px; - padding: 0px; - margin-right: 8px; - font-size: 14px; - } -`; - -const StyledTableOutlined = styled(TableOutlined)` - && { - margin: 0px; - padding: 0px; - margin-right: 8px; - font-size: 18px; - } -`; - -const StyledProjectOutlined = styled(ProjectOutlined)` - && { - margin: 0px; - padding: 0px; - margin-right: 8px; - font-size: 18px; - } -`; - -const StyledConsoleSqlOutlined = styled(ConsoleSqlOutlined)` - && { - margin: 0px; - padding: 0px; - margin-right: 8px; - font-size: 18px; - } -`; - -const StyledApiOutlined = styled(ApiOutlined)` - && { - margin: 0px; - padding: 0px; - margin-right: 8px; - font-size: 18px; - } -`; - -const StyledCheckOutlined = styled(CheckOutlined)` - && { - color: ${SUCCESS_COLOR_HEX}; - font-size: 14px; - padding: 0px; - margin: 0px; - } -`; - -const StyledCloseOutlined = styled(CloseOutlined)` - && { - color: ${FAILURE_COLOR_HEX}; - font-size: 14px; - padding: 0px; - margin: 0px; - } -`; - -const StyledExclamationOutlined = styled(ExclamationCircleOutlined)` - && { - color: ${WARNING_COLOR_HEX}; - font-size: 14px; - padding: 0px; - margin: 0px; - } -`; - -const StyledCodeOutlined = styled(CodeOutlined)` - && { - margin: 0px; - padding: 0px; - margin-right: 8px; - font-size: 18px; - } -`; - -export const ASSERTION_INFO = [ - { - name: 'Freshness', - description: 'Define & monitor your expectations about when this dataset should be updated', - icon: , - type: AssertionType.Freshness, - entityTypes: [EntityType.Dataset], - enabled: true, - visible: true, - }, - { - name: 'Volume', - description: 'Define & monitor your expectations about the size of this dataset', - icon: , - type: AssertionType.Volume, - entityTypes: [EntityType.Dataset], - enabled: true, - visible: true, - }, - { - name: 'Column', - description: 'Define & monitor your expectations about the values in a column', - icon: , - type: AssertionType.Field, - entityTypes: [EntityType.Dataset], - enabled: true, - visible: true, - requiresConnectionSupportedByMonitors: false, - }, - { - name: 'Schema', - description: "Define & monitor your expectations about the table's columns and their types", - icon: , - type: AssertionType.DataSchema, - entityTypes: [EntityType.Dataset], - enabled: true, - visible: true, - }, - { - name: 'Custom', - description: 'Define & monitor your expectations using custom SQL rules', - icon: , - type: AssertionType.Sql, - entityTypes: [EntityType.Dataset], - enabled: true, - visible: true, - requiresConnectionSupportedByMonitors: true, - }, - { - name: 'Other', - description: 'Assertions that are defined and maintained outside of DataHub.', - icon: , - type: AssertionType.Dataset, - entityTypes: [EntityType.Dataset], - enabled: false, - visible: false, - }, -]; - -const ASSERTION_TYPE_TO_INFO = new Map(); -ASSERTION_INFO.forEach((info) => { - ASSERTION_TYPE_TO_INFO.set(info.type, info); -}); - -const getAssertionGroupName = (type: AssertionType): string => { - return ASSERTION_TYPE_TO_INFO.has(type) ? ASSERTION_TYPE_TO_INFO.get(type).name : 'Unknown'; -}; - -const getAssertionGroupTypeIcon = (type: AssertionType) => { - return ASSERTION_TYPE_TO_INFO.has(type) ? ASSERTION_TYPE_TO_INFO.get(type).icon : undefined; -}; - -/** - * Returns a status summary for the assertions associated with a Dataset. - * - * @param assertions The assertions to extract the summary for - */ -export const getAssertionsSummary = (assertions: Assertion[]): AssertionStatusSummary => { - const summary = { - passing: 0, - failing: 0, - erroring: 0, - total: 0, - totalAssertions: assertions.length, - }; - assertions.forEach((assertion) => { - if ((assertion.runEvents?.runEvents?.length || 0) > 0) { - const mostRecentRun = assertion.runEvents?.runEvents?.[0]; - const resultType = mostRecentRun?.result?.type; - if (AssertionResultType.Success === resultType) { - summary.passing++; - } - if (AssertionResultType.Failure === resultType) { - summary.failing++; - } - if (AssertionResultType.Error === resultType) { - summary.erroring++; - } - if (AssertionResultType.Init !== resultType) { - summary.total++; // only count assertions for which there is one completed run event, ignoring INIT statuses! - } - } - }); - return summary; -}; - -// /** -// * Returns a list of assertion groups, where assertions are grouped -// * by their "type" or "category". Each group includes the assertions inside, along with -// * a summary of passing and failing assertions for the group. -// * -// * @param assertions The assertions to group -// */ -export const createAssertionGroups = (assertions: Array): AssertionGroup[] => { - // Pre-sort the list of assertions based on which has been most recently executed. - const newAssertions = [...assertions].sort(sortAssertions); - - const typeToAssertions = new Map(); - newAssertions - .filter((assertion) => assertion.info?.type) - .forEach((assertion) => { - const groupType = assertion.info?.type; - const groupedAssertions = typeToAssertions.get(groupType) || []; - groupedAssertions.push(assertion); - typeToAssertions.set(groupType, groupedAssertions); - }); - - // Now, create summary for each type and build the AssertionGroup object - const assertionGroups: AssertionGroup[] = []; - typeToAssertions.forEach((groupedAssertions, type) => { - const newGroup: AssertionGroup = { - name: getAssertionGroupName(type), - icon: getAssertionGroupTypeIcon(type), - assertions: groupedAssertions, - summary: getAssertionsSummary(groupedAssertions), - type, - }; - assertionGroups.push(newGroup); - }); - - return assertionGroups; -}; - -export const getAssertionGroupSummaryIcon = (summary: AssertionStatusSummary) => { - if (summary.total === 0) { - return null; - } - if (summary.passing === summary.total) { - return ; - } - if (summary.erroring > 0) { - return ; - } - return ; -}; - -export const getAssertionGroupSummaryMessage = (summary: AssertionStatusSummary) => { - if (summary.total === 0) { - return 'No assertions have run'; - } - if (summary.passing === summary.total) { - return 'All assertions are passing'; - } - if (summary.erroring > 0) { - return 'An error is preventing some assertions from running'; - } - if (summary.failing === summary.total) { - return 'All assertions are failing'; - } - return 'Some assertions are failing'; -}; - -export const getAssertionTypesForEntityType = (entityType: EntityType, monitorsConnectionForEntityExists: boolean) => { - return ASSERTION_INFO.filter((type) => type.entityTypes.includes(entityType)).map((type) => ({ - ...type, - enabled: type.enabled && (!type.requiresConnectionSupportedByMonitors || monitorsConnectionForEntityExists), - })); -}; - -type VolumeTypeField = - | 'rowCountTotal' - | 'rowCountChange' - | 'incrementingSegmentRowCountTotal' - | 'incrementingSegmentRowCountChange'; - -export const getPropertyFromVolumeType = (type: VolumeAssertionType) => { - switch (type) { - case VolumeAssertionType.RowCountTotal: - return 'rowCountTotal' as VolumeTypeField; - case VolumeAssertionType.RowCountChange: - return 'rowCountChange' as VolumeTypeField; - case VolumeAssertionType.IncrementingSegmentRowCountTotal: - return 'incrementingSegmentRowCountTotal' as VolumeTypeField; - case VolumeAssertionType.IncrementingSegmentRowCountChange: - return 'incrementingSegmentRowCountChange' as VolumeTypeField; - default: - throw new Error(`Unknown volume assertion type: ${type}`); - } -}; - -export const getVolumeTypeInfo = (volumeAssertion: VolumeAssertionInfo) => { - const result = volumeAssertion[getPropertyFromVolumeType(volumeAssertion.type)]; - if (!result) { - return undefined; - } - return result; -}; - -export const getIsRowCountChange = (type: VolumeAssertionType) => { - return [VolumeAssertionType.RowCountChange, VolumeAssertionType.IncrementingSegmentRowCountChange].includes(type); -}; - -export const getVolumeTypeDescription = (volumeType: VolumeAssertionType) => { - switch (volumeType) { - case VolumeAssertionType.RowCountTotal: - case VolumeAssertionType.IncrementingSegmentRowCountTotal: - return 'has'; - case VolumeAssertionType.RowCountChange: - case VolumeAssertionType.IncrementingSegmentRowCountChange: - return 'should grow by'; - default: - throw new Error(`Unknown volume type ${volumeType}`); - } -}; - -export const getOperatorDescription = (operator: AssertionStdOperator) => { - switch (operator) { - case AssertionStdOperator.GreaterThanOrEqualTo: - return 'at least'; - case AssertionStdOperator.LessThanOrEqualTo: - return 'at most'; - case AssertionStdOperator.Between: - return 'between'; - default: - throw new Error(`Unknown operator ${operator}`); - } -}; - -export const getValueChangeTypeDescription = (valueChangeType: AssertionValueChangeType) => { - switch (valueChangeType) { - case AssertionValueChangeType.Absolute: - return 'rows'; - case AssertionValueChangeType.Percentage: - return '%'; - default: - throw new Error(`Unknown value change type ${valueChangeType}`); - } -}; - -export const getParameterDescription = (parameters: AssertionStdParameters) => { - if (parameters.value) { - return formatNumberWithoutAbbreviation( - parseMaybeStringAsFloatOrDefault(parameters.value.value, parameters.value.value), - ); - } - if (parameters.minValue && parameters.maxValue) { - return `${formatNumberWithoutAbbreviation( - parseMaybeStringAsFloatOrDefault(parameters.minValue.value, parameters.minValue.value), - )} and ${formatNumberWithoutAbbreviation( - parseMaybeStringAsFloatOrDefault(parameters.maxValue.value, parameters.maxValue.value), - )}`; - } - throw new Error('Invalid assertion parameters provided'); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/View/ViewDefinitionTab.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/View/ViewDefinitionTab.tsx deleted file mode 100644 index 39ede18bd27c42..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/View/ViewDefinitionTab.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { Radio, Typography } from 'antd'; -import React, { useState } from 'react'; -import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; -import styled from 'styled-components'; - -import { useBaseEntity } from '@app/entity/shared/EntityContext'; -import { InfoItem } from '@app/entity/shared/components/styled/InfoItem'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { DBT_URN } from '@app/ingest/source/builder/constants'; - -import { GetDatasetQuery } from '@graphql/dataset.generated'; - -const InfoSection = styled.div` - border-bottom: 1px solid ${ANTD_GRAY[4.5]}; - padding: 16px 20px; -`; - -const InfoItemContainer = styled.div<{ justifyContent }>` - display: flex; - position: relative; - justify-content: ${(props) => props.justifyContent}; - padding: 12px 2px; -`; - -const InfoItemContent = styled.div` - padding-top: 8px; -`; - -const FormattingSelector = styled.div` - margin-top: 10px; -`; - -const QueryText = styled(Typography.Paragraph)` - margin-top: 15px; - background-color: ${ANTD_GRAY[2]}; - border-radius: 5px; -`; - -// NOTE: Yes, using `!important` is a shame. However, the SyntaxHighlighter is applying styles directly -// to the component, so there's no way around this -const NestedSyntax = styled(SyntaxHighlighter)` - background-color: transparent !important; - border: none !important; -`; - -export default function ViewDefinitionTab() { - const baseEntity = useBaseEntity(); - const logic = baseEntity?.dataset?.viewProperties?.logic || 'UNKNOWN'; - const formattedLogic = baseEntity?.dataset?.viewProperties?.formattedLogic; - const materialized = (baseEntity?.dataset?.viewProperties?.materialized && true) || false; - const language = baseEntity?.dataset?.viewProperties?.language || 'UNKNOWN'; - - const isDbt = baseEntity?.dataset?.platform?.urn === DBT_URN; - const formatOptions = isDbt ? ['Source', 'Compiled'] : ['Raw', 'Formatted']; - - const canShowFormatted = !!formattedLogic; - const [showFormatted, setShowFormatted] = useState(false); - - return ( - <> - - Details - - - {materialized ? 'True' : 'False'} - - - {language.toUpperCase()} - - - - - Logic - {canShowFormatted && ( - - setShowFormatted(e.target.value)} - value={showFormatted} - optionType="button" - /> - - )} - - {showFormatted ? formattedLogic : logic} - - - - ); -} diff --git a/datahub-web-react/src/app/entity/shared/tabs/Documentation/components/CompactMarkdownViewer.tsx b/datahub-web-react/src/app/entity/shared/tabs/Documentation/components/CompactMarkdownViewer.tsx index 8f056ae79824c8..c87e5bc71ad5f6 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Documentation/components/CompactMarkdownViewer.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Documentation/components/CompactMarkdownViewer.tsx @@ -89,7 +89,7 @@ const FixedLineHeightEditor = styled(CompactEditor)<{ customStyle?: React.CSSPro } `; -export type Props = { +type Props = { content: string; lineLimit?: number | null; fixedLineHeight?: boolean; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Documentation/components/editor/OnChangeMarkdown.tsx b/datahub-web-react/src/app/entity/shared/tabs/Documentation/components/editor/OnChangeMarkdown.tsx index f1e1759f497f09..2a4cdbfeffdc66 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Documentation/components/editor/OnChangeMarkdown.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Documentation/components/editor/OnChangeMarkdown.tsx @@ -2,7 +2,7 @@ import { DocChangedExtension } from '@remirror/core'; import { useExtensionEvent, useHelpers } from '@remirror/react'; import { useCallback } from 'react'; -export interface OnChangeMarkdownProps { +interface OnChangeMarkdownProps { onChange: (md: string) => void; } diff --git a/datahub-web-react/src/app/entity/shared/tabs/Documentation/components/editor/toolbar/CodeBlockToolbar.tsx b/datahub-web-react/src/app/entity/shared/tabs/Documentation/components/editor/toolbar/CodeBlockToolbar.tsx index 0b4da056bc74fc..7d5bf9f43cbfef 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Documentation/components/editor/toolbar/CodeBlockToolbar.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Documentation/components/editor/toolbar/CodeBlockToolbar.tsx @@ -54,7 +54,7 @@ const codeBlockPositioner = Positioner.create({ }, }); -export const CodeBlockMenu = () => { +const CodeBlockMenu = () => { const commands = useCommands(); const value = (useAttrs(true).codeBlock()?.language as string) ?? 'markup'; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Documentation/components/editor/toolbar/CommandButton.tsx b/datahub-web-react/src/app/entity/shared/tabs/Documentation/components/editor/toolbar/CommandButton.tsx index 8abde1480039e7..b309d48ae02f02 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Documentation/components/editor/toolbar/CommandButton.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Documentation/components/editor/toolbar/CommandButton.tsx @@ -3,7 +3,7 @@ import { useHelpers } from '@remirror/react'; import { Button, ButtonProps, Tooltip } from 'antd'; import React, { MouseEventHandler, useCallback } from 'react'; -export interface CommandButtonProps extends Omit { +interface CommandButtonProps extends Omit { active?: boolean; children?: React.ReactNode; commandName?: string; diff --git a/datahub-web-react/src/app/entity/shared/tabs/ERModelRelationship/ERModelRelationshipTab.tsx b/datahub-web-react/src/app/entity/shared/tabs/ERModelRelationship/ERModelRelationshipTab.tsx deleted file mode 100644 index 14e77f4cd70e35..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/ERModelRelationship/ERModelRelationshipTab.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import '@app/entity/shared/tabs/ERModelRelationship/ERModelRelationshipTab.less'; - -import { Divider } from 'antd'; -import React from 'react'; - -import { useEntityData, useRefetch } from '@app/entity/shared/EntityContext'; -import { ERModelRelationPreview } from '@app/entity/shared/components/styled/ERModelRelationship/ERModelRelationPreview'; - -export const ERModelRelationshipTab = () => { - const { entityData } = useEntityData(); - const refetch = useRefetch(); - const ermodelrelationView = (ermodelrelationData?: any): JSX.Element => { - return ( - - ); - }; - return ( - <> -
-
{ermodelrelationView(entityData)}
- -
- - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Embed/EmbedTab.tsx b/datahub-web-react/src/app/entity/shared/tabs/Embed/EmbedTab.tsx deleted file mode 100644 index 23bd630a93d0a9..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Embed/EmbedTab.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Empty } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; - -const EmbedContainer = styled.div` - width: 100%; - height: 100%; -`; - -const StyledIframe = styled.iframe` - width: 100%; - height: 100%; -`; - -const StyledEmpty = styled(Empty)` - margin-top: 28px; - font-size: 16px; - color: ${ANTD_GRAY[8]}; -`; - -export const EmbedTab = () => { - const { entityData } = useEntityData(); - const embedRenderUrl = entityData?.embed?.renderUrl; - return ( - - {(embedRenderUrl && ) || ( - - )} - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Entity/ChartDashboardsTab.tsx b/datahub-web-react/src/app/entity/shared/tabs/Entity/ChartDashboardsTab.tsx deleted file mode 100644 index 7119eaa840b55c..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Entity/ChartDashboardsTab.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; - -import { useBaseEntity } from '@app/entity/shared/EntityContext'; -import { EntityList } from '@app/entity/shared/tabs/Entity/components/EntityList'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { EntityType } from '@types'; - -export const ChartDashboardsTab = () => { - const entity = useBaseEntity() as any; - const chart = entity && entity.chart; - const dashboards = chart?.dashboards?.relationships?.map((relationship) => relationship.entity); - const entityRegistry = useEntityRegistry(); - const totalDashboards = chart?.dashboards?.total || 0; - const title = `Found in ${totalDashboards} ${ - totalDashboards === 1 - ? entityRegistry.getEntityName(EntityType.Dashboard) - : entityRegistry.getCollectionName(EntityType.Dashboard) - }`; - return ; -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Entity/DashboardChartsTab.tsx b/datahub-web-react/src/app/entity/shared/tabs/Entity/DashboardChartsTab.tsx deleted file mode 100644 index 9990862c37b8b8..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Entity/DashboardChartsTab.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; - -import { useBaseEntity } from '@app/entity/shared/EntityContext'; -import { EntityList } from '@app/entity/shared/tabs/Entity/components/EntityList'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { EntityType } from '@types'; - -export const DashboardChartsTab = () => { - const entity = useBaseEntity() as any; - const dashboard = entity && entity.dashboard; - const charts = dashboard?.charts?.relationships?.map((relationship) => relationship.entity); - const entityRegistry = useEntityRegistry(); - const totalCharts = dashboard?.charts?.total || 0; - const title = `Contains ${totalCharts} ${ - totalCharts === 1 - ? entityRegistry.getEntityName(EntityType.Chart) - : entityRegistry.getCollectionName(EntityType.Chart) - }`; - return ; -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Entity/DashboardDatasetsTab.tsx b/datahub-web-react/src/app/entity/shared/tabs/Entity/DashboardDatasetsTab.tsx deleted file mode 100644 index c2629c449bb636..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Entity/DashboardDatasetsTab.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; - -import { useBaseEntity } from '@app/entity/shared/EntityContext'; -import { EntityList } from '@app/entity/shared/tabs/Entity/components/EntityList'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { EntityType } from '@types'; - -export const DashboardDatasetsTab = () => { - const entity = useBaseEntity() as any; - const dashboard = entity && entity.dashboard; - const datasets = dashboard?.datasets?.relationships?.map((relationship) => relationship.entity); - const entityRegistry = useEntityRegistry(); - const totalDatasets = dashboard?.datasets?.total || 0; - const title = `Consumes ${totalDatasets} ${ - totalDatasets === 1 - ? entityRegistry.getEntityName(EntityType.Dataset) - : entityRegistry.getCollectionName(EntityType.Dataset) - }`; - return ; -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Entity/DataFlowJobsTab.tsx b/datahub-web-react/src/app/entity/shared/tabs/Entity/DataFlowJobsTab.tsx deleted file mode 100644 index 146f6efe94f798..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Entity/DataFlowJobsTab.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import React, { useState } from 'react'; - -import { EntityList } from '@app/entity/shared/tabs/Entity/components/EntityList'; -import { useEntityRegistry } from '@app/useEntityRegistry'; -import { SearchCfg } from '@src/conf'; - -import { useGetDataFlowChildJobsQuery } from '@graphql/dataFlow.generated'; -import { EntityType } from '@types'; - -interface Props { - properties?: { - urn: string; - }; -} - -export const DataFlowJobsTab = ({ properties = { urn: '' } }: Props) => { - const [page, setPage] = useState(1); - const [numResultsPerPage, setNumResultsPerPage] = useState(SearchCfg.RESULTS_PER_PAGE); - - const start: number = (page - 1) * numResultsPerPage; - - const { data, loading, error } = useGetDataFlowChildJobsQuery({ - variables: { - urn: properties.urn, - start, - count: numResultsPerPage, - }, - }); - - const onChangePage = (newPage: number) => { - setPage(newPage); - }; - - const dataFlow = data && data?.dataFlow; - const dataJobs = dataFlow?.childJobs?.relationships?.map((relationship) => relationship.entity); - const entityRegistry = useEntityRegistry(); - const totalJobs = dataFlow?.childJobs?.total || 0; - const pageSize = data?.dataFlow?.childJobs?.count || 0; - const pageStart = data?.dataFlow?.childJobs?.start || 0; - const lastResultIndex = pageStart + pageSize > totalJobs ? totalJobs : pageStart + pageSize; - const title = `Contains ${totalJobs} ${ - totalJobs === 1 - ? entityRegistry.getEntityName(EntityType.DataJob) - : entityRegistry.getCollectionName(EntityType.DataJob) - }`; - return ( - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Entity/InputFieldsTab.tsx b/datahub-web-react/src/app/entity/shared/tabs/Entity/InputFieldsTab.tsx deleted file mode 100644 index 7c4e7460c0889d..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Entity/InputFieldsTab.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { Empty } from 'antd'; -import React, { useMemo } from 'react'; -import styled from 'styled-components'; - -import { groupByFieldPath } from '@app/entity/dataset/profile/schema/utils/utils'; -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import SchemaTable from '@app/entity/shared/tabs/Dataset/Schema/SchemaTable'; -import SchemaEditableContext from '@app/shared/SchemaEditableContext'; - -import { SchemaField } from '@types'; - -const NoSchema = styled(Empty)` - color: ${ANTD_GRAY[6]}; - padding-top: 60px; -`; - -const SchemaTableContainer = styled.div` - overflow: auto; - height: 100%; -`; -export const InputFieldsTab = () => { - const { entityData } = useEntityData(); - const inputFields = entityData?.inputFields || undefined; - const ungroupedRows = inputFields?.fields?.map((field) => field?.schemaField) as SchemaField[]; - - const rows = useMemo(() => { - return groupByFieldPath(ungroupedRows, { showKeySchema: false }); - }, [ungroupedRows]); - - return ( - <> - - {rows && rows.length > 0 ? ( - <> - - - - - ) : ( - - )} - - - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Incident/components/IncidentSummary.tsx b/datahub-web-react/src/app/entity/shared/tabs/Incident/components/IncidentSummary.tsx index a08c072607dfc2..1bb94ffb031b41 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Incident/components/IncidentSummary.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Incident/components/IncidentSummary.tsx @@ -31,7 +31,7 @@ const SummaryTitle = styled(Typography.Title)` } `; -export type IncidentsSummary = { +type IncidentsSummary = { totalIncident: number; resolvedIncident: number; activeIncident: number; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Incident/incidentUtils.ts b/datahub-web-react/src/app/entity/shared/tabs/Incident/incidentUtils.ts index 6d68d56d45588d..cfa56ad9bb9085 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Incident/incidentUtils.ts +++ b/datahub-web-react/src/app/entity/shared/tabs/Incident/incidentUtils.ts @@ -40,10 +40,10 @@ export const getNameFromType = (type: IncidentType) => { export const SUCCESS_COLOR_HEX = '#52C41A'; export const FAILURE_COLOR_HEX = '#F5222D'; -export const WARNING_COLOR_HEX = '#FA8C16'; +const WARNING_COLOR_HEX = '#FA8C16'; // apollo caching -export const addOrUpdateIncidentInList = (existingIncidents, newIncidents) => { +const addOrUpdateIncidentInList = (existingIncidents, newIncidents) => { const incidents = [...existingIncidents]; let didUpdate = false; const updatedIncidents = incidents.map((incident) => { @@ -59,7 +59,7 @@ export const addOrUpdateIncidentInList = (existingIncidents, newIncidents) => { /** * Add an entry to the ListIncident cache. */ -export const updateListIncidentsCache = (client, urn, incident, pageSize) => { +const updateListIncidentsCache = (client, urn, incident, pageSize) => { // Read the data from our cache for this query. const currData: any = client.readQuery({ query: GetEntityIncidentsDocument, diff --git a/datahub-web-react/src/app/entity/shared/tabs/Lineage/LineageTable.tsx b/datahub-web-react/src/app/entity/shared/tabs/Lineage/LineageTable.tsx deleted file mode 100644 index 1120339a1a8da8..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/Lineage/LineageTable.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { List } from 'antd'; -import React from 'react'; -import VisiblitySensor from 'react-visibility-sensor'; -import styled from 'styled-components'; - -import { PreviewType } from '@app/entity/Entity'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { Entity } from '@types'; - -const LineageList = styled(List)` - padding-left: 40px; - padding-right: 40px; - margin-top: -1px; - .ant-list-items > .ant-list-item { - padding-right: 0px; - padding-left: 0px; - } - > .ant-list-header { - padding-right: 0px; - padding-left: 0px; - font-size: 14px; - font-weight: 600; - margin-left: -20px; - border-bottom: none; - padding-bottom: 0px; - padding-top: 15px; - } -` as typeof List; - -const ItemPlaceholder = styled.div` - min-height: 100px; - width: 100%; - background-color: ${ANTD_GRAY[2]}; -`; - -const ListItem = styled(List.Item)` - paddingtop: 20px; -`; -const TableTitle = styled.span` - font-size: 20px; -`; - -type Props = { - title: string; - data?: Entity[]; -}; - -export const LineageTable = ({ data, title }: Props) => { - const entityRegistry = useEntityRegistry(); - - return ( - {title}} - renderItem={(item) => ( - - - {({ isVisible }) => - isVisible && !!item.type ? ( - entityRegistry.renderPreview(item.type, PreviewType.PREVIEW, item) - ) : ( - - ) - } - - - )} - /> - ); -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/ML/MlFeatureFeatureTableTab.tsx b/datahub-web-react/src/app/entity/shared/tabs/ML/MlFeatureFeatureTableTab.tsx deleted file mode 100644 index 4d815a5184f63f..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/ML/MlFeatureFeatureTableTab.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; - -import { useBaseEntity } from '@app/entity/shared/EntityContext'; -import { EntityList } from '@app/entity/shared/tabs/Entity/components/EntityList'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { GetMlFeatureQuery } from '@graphql/mlFeature.generated'; -import { EntityType } from '@types'; - -export const FeatureTableTab = () => { - const entity = useBaseEntity() as GetMlFeatureQuery; - const entityRegistry = useEntityRegistry(); - - const feature = entity && entity.mlFeature; - const featureTables = feature?.featureTables?.relationships?.map((relationship) => relationship.entity); - - const title = `Part of ${entityRegistry.getEntityName(EntityType.MlfeatureTable)}`; - return ; -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/ML/MlPrimaryKeyFeatureTableTab.tsx b/datahub-web-react/src/app/entity/shared/tabs/ML/MlPrimaryKeyFeatureTableTab.tsx deleted file mode 100644 index f2054aa0560f8d..00000000000000 --- a/datahub-web-react/src/app/entity/shared/tabs/ML/MlPrimaryKeyFeatureTableTab.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; - -import { useBaseEntity } from '@app/entity/shared/EntityContext'; -import { EntityList } from '@app/entity/shared/tabs/Entity/components/EntityList'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { GetMlPrimaryKeyQuery } from '@graphql/mlPrimaryKey.generated'; -import { EntityType } from '@types'; - -export const FeatureTableTab = () => { - const entity = useBaseEntity() as GetMlPrimaryKeyQuery; - const entityRegistry = useEntityRegistry(); - - const feature = entity && entity.mlPrimaryKey; - const featureTables = feature?.featureTables?.relationships?.map((relationship) => relationship.entity); - - const title = `Part of ${entityRegistry.getEntityName(EntityType.MlfeatureTable)}`; - return ; -}; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Properties/Edit/EditColumn.tsx b/datahub-web-react/src/app/entity/shared/tabs/Properties/Edit/EditColumn.tsx index 711ebb8e3c9266..45db88d032a246 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Properties/Edit/EditColumn.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Properties/Edit/EditColumn.tsx @@ -12,7 +12,7 @@ import { ToastType, showToastMessage } from '@src/app/sharedV2/toastMessageUtils import { useRemoveStructuredPropertiesMutation } from '@src/graphql/structuredProperties.generated'; import { EntityType, StructuredPropertyEntity } from '@src/types.generated'; -export const MoreOptionsContainer = styled.div` +const MoreOptionsContainer = styled.div` display: flex; gap: 12px; justify-content: end; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Properties/useStructuredProperties.tsx b/datahub-web-react/src/app/entity/shared/tabs/Properties/useStructuredProperties.tsx index d4aa029d48cff2..d4a866ec37f9f5 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Properties/useStructuredProperties.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Properties/useStructuredProperties.tsx @@ -73,7 +73,7 @@ function getStructuredPropertyRows(entityData?: GenericEntityProperties | null) return structuredPropertyRows; } -export function findAllSubstrings(s: string): Array { +function findAllSubstrings(s: string): Array { const substrings: Array = []; for (let i = 0; i < s.length; i++) { @@ -85,7 +85,7 @@ export function findAllSubstrings(s: string): Array { return substrings; } -export function createParentPropertyRow(displayName: string, qualifiedName: string): PropertyRow { +function createParentPropertyRow(displayName: string, qualifiedName: string): PropertyRow { return { displayName, qualifiedName, @@ -149,7 +149,7 @@ export function identifyAndAddParentRows(rows?: Array): Array): Array { +function groupByParentProperty(rows?: Array): Array { /** * This function takes in an array of PropertyRow objects, representing parent and child properties. Parent properties * will not have values, but child properties will. It organizes the rows into the parent and child structure and diff --git a/datahub-web-react/src/app/entity/shared/types.ts b/datahub-web-react/src/app/entity/shared/types.ts index eda056f17efa54..a7ba51dece5dcd 100644 --- a/datahub-web-react/src/app/entity/shared/types.ts +++ b/datahub-web-react/src/app/entity/shared/types.ts @@ -201,7 +201,7 @@ export type SchemaContextType = { refetch?: () => Promise; }; -export type RequiredAndNotNull = { +type RequiredAndNotNull = { [P in keyof T]-?: Exclude; }; diff --git a/datahub-web-react/src/app/entity/shared/utils.ts b/datahub-web-react/src/app/entity/shared/utils.ts index 6074051e00ab02..4c96b3588a9c2b 100644 --- a/datahub-web-react/src/app/entity/shared/utils.ts +++ b/datahub-web-react/src/app/entity/shared/utils.ts @@ -46,7 +46,7 @@ export const decodeComma = (str: string) => { return str.replace(/%2C/g, ','); }; -export function notEmpty(value: TValue | null | undefined): value is TValue { +function notEmpty(value: TValue | null | undefined): value is TValue { return value !== null && value !== undefined; } @@ -125,7 +125,7 @@ export function getFineGrainedLineageWithSiblings( }); return fineGrainedLineages; } -export function getDataProduct(dataProductResult: Maybe | undefined) { +function getDataProduct(dataProductResult: Maybe | undefined) { if (dataProductResult?.relationships && dataProductResult.relationships.length > 0) { return dataProductResult.relationships[0].entity as DataProduct; } @@ -143,7 +143,7 @@ export function getStructuredPropertyValue(value: PropertyValue) { } // Utility for formatting any casing of type to the expected casing for the API -export function formatEntityType(type: string): string { +function formatEntityType(type: string): string { if (!type) return ''; switch (type.toLowerCase()) { diff --git a/datahub-web-react/src/app/entity/structuredProperty/StructuredPropertyEntity.tsx b/datahub-web-react/src/app/entity/structuredProperty/StructuredPropertyEntity.tsx deleted file mode 100644 index 580b6606856b3e..00000000000000 --- a/datahub-web-react/src/app/entity/structuredProperty/StructuredPropertyEntity.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import * as React from 'react'; -import styled from 'styled-components'; - -import { Entity, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { urlEncodeUrn } from '@app/entity/shared/utils'; -import DefaultPreviewCard from '@src/app/preview/DefaultPreviewCard'; -import { TYPE_ICON_CLASS_NAME } from '@src/app/shared/constants'; -import TableIcon from '@src/images/table-icon.svg?react'; - -import { EntityType, SearchResult, StructuredPropertyEntity as StructuredProperty } from '@types'; - -const PreviewPropIcon = styled(TableIcon)` - font-size: 20px; -`; - -/** - * Definition of the DataHub Structured Property entity. - */ -export class StructuredPropertyEntity implements Entity { - type: EntityType = EntityType.StructuredProperty; - - icon = (fontSize?: number, styleType?: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - return ( - - ); - }; - - isSearchEnabled = () => false; - - isBrowseEnabled = () => false; - - isLineageEnabled = () => false; - - getAutoCompleteFieldName = () => 'name'; - - getGraphName = () => 'structuredProperty'; - - getPathName: () => string = () => this.getGraphName(); - - getCollectionName: () => string = () => 'Structured Properties'; - - getEntityName: () => string = () => 'Structured Property'; - - renderProfile: (urn: string) => JSX.Element = (_urn) =>
; // not used right now - - renderPreview = (previewType: PreviewType, data: StructuredProperty) => ( - } - typeIcon={this.icon(14, IconStyleType.ACCENT)} - previewType={previewType} - /> - ); - - renderSearch = (result: SearchResult) => { - return this.renderPreview(PreviewType.SEARCH, result.entity as StructuredProperty); - }; - - displayName = (data: StructuredProperty) => { - return data.definition?.displayName || data.definition?.qualifiedName || data.urn; - }; - - getGenericEntityProperties = (entity: StructuredProperty) => { - return getDataForEntityType({ data: entity, entityType: this.type, getOverrideProperties: (data) => data }); - }; - - supportedCapabilities = () => { - return new Set([]); - }; -} diff --git a/datahub-web-react/src/app/entity/tag/Tag.tsx b/datahub-web-react/src/app/entity/tag/Tag.tsx deleted file mode 100644 index 19cde74db62882..00000000000000 --- a/datahub-web-react/src/app/entity/tag/Tag.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { TagFilled, TagOutlined } from '@ant-design/icons'; -import * as React from 'react'; -import styled from 'styled-components'; - -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import { urlEncodeUrn } from '@app/entity/shared/utils'; -import TagProfile from '@app/entity/tag/TagProfile'; -import DefaultPreviewCard from '@app/preview/DefaultPreviewCard'; - -import { useGetTagQuery } from '@graphql/tag.generated'; -import { EntityType, SearchResult, Tag } from '@types'; - -const PreviewTagIcon = styled(TagOutlined)` - font-size: 20px; -`; - -/** - * Definition of the DataHub Tag entity. - */ -export class TagEntity implements Entity { - type: EntityType = EntityType.Tag; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - return ( - - ); - }; - - isSearchEnabled = () => false; - - isBrowseEnabled = () => false; - - isLineageEnabled = () => false; - - getAutoCompleteFieldName = () => 'name'; - - getGraphName = () => 'tag'; - - getPathName: () => string = () => 'tag'; - - getCollectionName: () => string = () => 'Tags'; - - getEntityName: () => string = () => 'Tag'; - - useEntityQuery = useGetTagQuery; - - renderProfile: (urn: string) => JSX.Element = (_) => ; - - renderPreview = (previewType: PreviewType, data: Tag) => ( - } - type="Tag" - typeIcon={this.icon(14, IconStyleType.ACCENT)} - previewType={previewType} - /> - ); - - renderSearch = (result: SearchResult) => { - return this.renderPreview(PreviewType.SEARCH, result.entity as Tag); - }; - - displayName = (data: Tag) => { - return data.properties?.name || data.name || data.urn; - }; - - getGenericEntityProperties = (tag: Tag) => { - return getDataForEntityType({ data: tag, entityType: this.type, getOverrideProperties: (data) => data }); - }; - - supportedCapabilities = () => { - return new Set([EntityCapabilityType.OWNERS]); - }; -} diff --git a/datahub-web-react/src/app/entity/tag/TagProfile.tsx b/datahub-web-react/src/app/entity/tag/TagProfile.tsx deleted file mode 100644 index f86a8dbff1256c..00000000000000 --- a/datahub-web-react/src/app/entity/tag/TagProfile.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react'; -import { useParams } from 'react-router'; -import styled from 'styled-components'; - -import { decodeUrn } from '@app/entity/shared/utils'; -import { Message } from '@app/shared/Message'; -import TagStyleEntity from '@app/shared/TagStyleEntity'; - -import { useGetTagQuery } from '@graphql/tag.generated'; - -const PageContainer = styled.div` - padding: 32px 100px; -`; - -const LoadingMessage = styled(Message)` - margin-top: 10%; -`; - -type TagPageParams = { - urn: string; -}; - -/** - * Responsible for displaying metadata about a tag - */ -export default function TagProfile() { - const { urn: encodedUrn } = useParams(); - const urn = decodeUrn(encodedUrn); - const { loading } = useGetTagQuery({ variables: { urn } }); - - return ( - - {loading && } - - - ); -} diff --git a/datahub-web-react/src/app/entity/tag/__tests__/TagProfile.test.tsx b/datahub-web-react/src/app/entity/tag/__tests__/TagProfile.test.tsx deleted file mode 100644 index 4c88c0f4ef8de0..00000000000000 --- a/datahub-web-react/src/app/entity/tag/__tests__/TagProfile.test.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { MockedProvider } from '@apollo/client/testing'; -import { render, waitFor } from '@testing-library/react'; -import React from 'react'; -import { Route } from 'react-router'; - -import TagProfile from '@app/entity/tag/TagProfile'; -import { mocks } from '@src/Mocks'; -import TestPageContainer from '@utils/test-utils/TestPageContainer'; - -describe('TagProfile', () => { - it('renders tag details', async () => { - const { getByText, queryByText } = render( - - - } /> - - , - ); - - await waitFor(() => expect(queryByText('abc-sample-tag')).toBeInTheDocument()); - - expect(getByText('abc-sample-tag')).toBeInTheDocument(); - expect(getByText('sample tag description')).toBeInTheDocument(); - }); - - it('renders tag ownership', async () => { - const { queryByText } = render( - - - } /> - - , - ); - - await waitFor(() => expect(queryByText('abc-sample-tag')).not.toBeInTheDocument()); - }); - - it('renders stats', async () => { - const { queryByText } = render( - - - } /> - - , - ); - - await waitFor(() => expect(queryByText('abc-sample-tag')).not.toBeInTheDocument()); - - await waitFor(() => expect(queryByText('Loading')).not.toBeInTheDocument()); - }); -}); diff --git a/datahub-web-react/src/app/entity/user/User.tsx b/datahub-web-react/src/app/entity/user/User.tsx deleted file mode 100644 index 41a12c14fda287..00000000000000 --- a/datahub-web-react/src/app/entity/user/User.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { UserOutlined } from '@ant-design/icons'; -import * as React from 'react'; - -import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from '@app/entity/Entity'; -import { getDataForEntityType } from '@app/entity/shared/containers/profile/utils'; -import UserProfile from '@app/entity/user/UserProfile'; -import { Preview } from '@app/entity/user/preview/Preview'; - -import { CorpUser, EntityType, SearchResult } from '@types'; - -/** - * Definition of the DataHub Dataset entity. - */ -export class UserEntity implements Entity { - type: EntityType = EntityType.CorpUser; - - icon = (fontSize: number, styleType: IconStyleType, color?: string) => { - if (styleType === IconStyleType.TAB_VIEW) { - return ; - } - - if (styleType === IconStyleType.HIGHLIGHT) { - return ; - } - - return ( - - ); - }; - - isSearchEnabled = () => true; - - isBrowseEnabled = () => false; - - isLineageEnabled = () => false; - - getAutoCompleteFieldName = () => 'username'; - - getGraphName: () => string = () => 'corpuser'; - - getPathName: () => string = () => 'user'; - - getEntityName = () => 'Person'; - - getCollectionName: () => string = () => 'People'; - - renderProfile: (urn: string) => JSX.Element = (_) => ; - - renderPreview = (_: PreviewType, data: CorpUser) => ( - - ); - - renderSearch = (result: SearchResult) => { - return this.renderPreview(PreviewType.SEARCH, result.entity as CorpUser); - }; - - displayName = (data: CorpUser) => { - return ( - data.editableProperties?.displayName || - data.properties?.displayName || - data.properties?.fullName || - data.info?.displayName || // Deprecated info field - data.info?.fullName || // Deprecated info field - data.username || - data.urn - ); - }; - - getGenericEntityProperties = (user: CorpUser) => { - return getDataForEntityType({ data: user, entityType: this.type, getOverrideProperties: (data) => data }); - }; - - supportedCapabilities = () => { - return new Set([EntityCapabilityType.ROLES]); - }; -} diff --git a/datahub-web-react/src/app/entity/user/UserAssets.tsx b/datahub-web-react/src/app/entity/user/UserAssets.tsx deleted file mode 100644 index e2cea33a72ec2e..00000000000000 --- a/datahub-web-react/src/app/entity/user/UserAssets.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import { EmbeddedListSearchSection } from '@app/entity/shared/components/styled/search/EmbeddedListSearchSection'; -import { UnionType } from '@app/search/utils/constants'; -import useGetUserGroupUrns from '@src/app/entityV2/user/useGetUserGroupUrns'; - -const UserAssetsWrapper = styled.div` - height: calc(100vh - 114px); - overflow: auto; -`; - -type Props = { - urn: string; -}; - -export const UserAssets = ({ urn }: Props) => { - const { groupUrns, data, loading } = useGetUserGroupUrns(urn); - - if (!data || loading) return null; - - return ( - - - - ); -}; diff --git a/datahub-web-react/src/app/entity/user/UserEditProfileModal.tsx b/datahub-web-react/src/app/entity/user/UserEditProfileModal.tsx deleted file mode 100644 index aa93d1ddb7e9b9..00000000000000 --- a/datahub-web-react/src/app/entity/user/UserEditProfileModal.tsx +++ /dev/null @@ -1,252 +0,0 @@ -import { Button, Form, Input, Modal, Tooltip, Typography, message } from 'antd'; -import React, { useEffect, useState } from 'react'; - -import { useEnterKeyListener } from '@app/shared/useEnterKeyListener'; -import { useAppConfig } from '@app/useAppConfig'; - -import { useUpdateCorpUserPropertiesMutation } from '@graphql/user.generated'; - -type PropsData = { - name: string | undefined; - title: string | undefined; - image: string | undefined; - team: string | undefined; - email: string | undefined; - slack: string | undefined; - phone: string | undefined; - urn: string | undefined; -}; - -type Props = { - open: boolean; - onClose: () => void; - onSave: () => void; - editModalData: PropsData; -}; -/** Regex Validations */ -export const USER_NAME_REGEX = new RegExp('^[a-zA-Z ]*$'); - -export default function UserEditProfileModal({ open, onClose, onSave, editModalData }: Props) { - const { config } = useAppConfig(); - const { readOnlyModeEnabled } = config.featureFlags; - const [updateCorpUserPropertiesMutation] = useUpdateCorpUserPropertiesMutation(); - const [form] = Form.useForm(); - - const [saveButtonEnabled, setSaveButtonEnabled] = useState(true); - const [data, setData] = useState({ - name: editModalData.name, - title: editModalData.title, - image: editModalData.image, - team: editModalData.team, - email: editModalData.email, - slack: editModalData.slack, - phone: editModalData.phone, - urn: editModalData.urn, - }); - - useEffect(() => { - setData({ ...editModalData }); - }, [editModalData]); - - // save changes function - const onSaveChanges = () => { - updateCorpUserPropertiesMutation({ - variables: { - urn: editModalData?.urn || '', - input: { - displayName: data.name, - title: data.title, - pictureLink: data.image, - teams: data.team?.split(','), - email: data.email, - slack: data.slack, - phone: data.phone, - }, - }, - }) - .then(() => { - message.success({ - content: `Changes saved.`, - duration: 3, - }); - onSave(); // call the refetch function once save - // clear the values from edit profile form - setData({ - name: '', - title: '', - image: '', - team: '', - email: '', - slack: '', - phone: '', - urn: '', - }); - }) - .catch((e) => { - message.destroy(); - message.error({ content: `Failed to Save changes!: \n ${e.message || ''}`, duration: 3 }); - }); - onClose(); - }; - - // Handle the Enter press - useEnterKeyListener({ - querySelectorToExecuteClick: '#editUserButton', - }); - - return ( - - - - - } - > -
- setSaveButtonEnabled(form.getFieldsError().some((field) => field.errors.length > 0)) - } - > - Name} - rules={[ - { - required: true, - message: 'Enter a display name.', - }, - { whitespace: true }, - { min: 2, max: 50 }, - { - pattern: USER_NAME_REGEX, - message: '', - }, - ]} - hasFeedback - > - setData({ ...data, name: event.target.value })} - disabled={readOnlyModeEnabled} - /> - - Title/Role} - rules={[{ whitespace: true }, { min: 2, max: 50 }]} - hasFeedback - > - setData({ ...data, title: event.target.value })} - disabled={readOnlyModeEnabled} - /> - - - Image URL} - rules={[{ whitespace: true }, { type: 'url', message: 'not valid url' }]} - hasFeedback - > - setData({ ...data, image: event.target.value })} - disabled={readOnlyModeEnabled} - /> - - - Team} - rules={[{ whitespace: true }, { min: 2, max: 50 }]} - > - setData({ ...data, team: event.target.value })} - disabled={readOnlyModeEnabled} - /> - - Email} - rules={[ - { - required: true, - message: 'Enter your email', - }, - { - type: 'email', - message: 'Please enter valid email', - }, - { whitespace: true }, - { min: 2, max: 50 }, - ]} - hasFeedback - > - setData({ ...data, email: event.target.value })} - disabled={readOnlyModeEnabled} - /> - - Slack} - rules={[{ whitespace: true }, { min: 2, max: 50 }]} - hasFeedback - > - setData({ ...data, slack: event.target.value })} - disabled={readOnlyModeEnabled} - /> - - Phone} - rules={[ - { - pattern: new RegExp('^(?=.*[0-9])[- +()0-9]+$'), - message: 'not valid phone number', - }, - { - min: 5, - max: 15, - }, - ]} - hasFeedback - > - setData({ ...data, phone: event.target.value })} - disabled={readOnlyModeEnabled} - /> - - -
- ); -} diff --git a/datahub-web-react/src/app/entity/user/UserGroups.tsx b/datahub-web-react/src/app/entity/user/UserGroups.tsx deleted file mode 100644 index 55ef6f1ab526e0..00000000000000 --- a/datahub-web-react/src/app/entity/user/UserGroups.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import { Col, Pagination, Row, Tooltip } from 'antd'; -import React, { useState } from 'react'; -import { Link } from 'react-router-dom'; -import styled from 'styled-components'; - -import { scrollToTop } from '@app/shared/searchUtils'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useGetUserGroupsLazyQuery } from '@graphql/user.generated'; -import { CorpGroup, EntityRelationship, EntityType } from '@types'; - -type Props = { - urn: string; - initialRelationships?: Array | null; - pageSize: number; -}; - -const GroupsViewWrapper = styled.div` - height: calc(100vh - 173px); - overflow-y: auto; - - .user-group-pagination { - justify-content: center; - bottom: 24px; - position: absolute; - width: 100%; - left: 50%; - -webkit-transform: translateX(-50%); - -moz-transform: translateX(-50%); - -webkit-transform: translateX(-50%); - -ms-transform: translateX(-50%); - transform: translateX(-50%); - } -`; - -const GroupItemColumn = styled(Col)` - padding: 10px; -`; - -const GroupItem = styled.div` - border: 1px solid #eaeaea; - padding: 10px; - min-height: 107px; - max-height: 107px; - border-radius: 5px; - - .title-row { - padding: 9px 11px 9px 11px; - } - .description-row { - padding: 2px 13px; - } -`; - -const GroupTitle = styled.span` - font-size: 14px; - line-height: 22px; - font-weight: bold; - color: #262626; -`; - -const GroupMember = styled.span` - font-weight: 500; - font-size: 12px; - line-height: 23px; - color: #8c8c8c; - padding-left: 7px; -`; - -const GroupDescription = styled.span` - font-weight: 500; - font-size: 12px; - line-height: 20px; - color: #262626; - overflow: hidden; - text-overflow: ellipsis; - max-width: 100%; - height: 43px; -`; -export default function UserGroups({ urn, initialRelationships, pageSize }: Props) { - const [page, setPage] = useState(1); - const entityRegistry = useEntityRegistry(); - - const [getGroups, { data: groupsData }] = useGetUserGroupsLazyQuery(); - - const onChangeGroupsPage = (newPage: number) => { - scrollToTop(); - setPage(newPage); - const start = (newPage - 1) * pageSize; - getGroups({ variables: { urn, start, count: pageSize } }); - }; - - const relationships = groupsData ? groupsData.corpUser?.relationships?.relationships : initialRelationships; - const total = relationships?.length || 0; - const userGroups = relationships?.map((rel) => rel.entity as CorpGroup) || []; - - return ( - - - {userGroups && - userGroups.map((item) => { - return ( - - - - - {item.info?.displayName || item.name} - - {item.relationships?.total} - {item.relationships?.total === 1 ? ' member' : ' members'} - - - - - - {item.info?.description} - - - - - - - ); - })} - - - - - - ); -} diff --git a/datahub-web-react/src/app/entity/user/UserInfoSideBar.tsx b/datahub-web-react/src/app/entity/user/UserInfoSideBar.tsx deleted file mode 100644 index 102af7005dee35..00000000000000 --- a/datahub-web-react/src/app/entity/user/UserInfoSideBar.tsx +++ /dev/null @@ -1,223 +0,0 @@ -import { EditOutlined, MailOutlined, PhoneOutlined, SlackOutlined } from '@ant-design/icons'; -import { Button, Divider, Space, Tag, Typography, message } from 'antd'; -import React, { useEffect, useState } from 'react'; - -import { useUserContext } from '@app/context/useUserContext'; -import EntityGroups from '@app/entity/shared/EntityGroups'; -import { - AboutSection, - AboutSectionText, - EditButton, - EmptyValue, - GroupsSection, - LocationSection, - LocationSectionText, - Name, - SideBar, - SideBarSubSection, - SocialDetails, - Team, - TitleRole, - UserDetails, -} from '@app/entity/shared/SidebarStyledComponents'; -import UserEditProfileModal from '@app/entity/user/UserEditProfileModal'; -import { mapRoleIcon } from '@app/identity/user/UserUtils'; -import { useBrowserTitle } from '@app/shared/BrowserTabTitleContext'; -import CustomAvatar from '@app/shared/avatar/CustomAvatar'; -import { getCountryName } from '@src/app/shared/sidebar/components'; - -import { useUpdateCorpUserPropertiesMutation } from '@graphql/user.generated'; -import { DataHubRole, EntityRelationship } from '@types'; - -import GlobeIcon from '@images/Globe.svg'; - -const { Paragraph } = Typography; - -type SideBarData = { - photoUrl: string | undefined; - avatarName: string | undefined; - name: string | undefined; - role: string | undefined; - team: string | undefined; - email: string | undefined; - slack: string | undefined; - phone: string | undefined; - aboutText: string | undefined; - groupsDetails: Array; - urn: string | undefined; - dataHubRoles: Array; - countryCode: string | undefined; - username: string | undefined; -}; - -type Props = { - sideBarData: SideBarData; - refetch: () => void; -}; - -const AVATAR_STYLE = { marginTop: '14px' }; - -/** - * UserInfoSideBar- Sidebar section for users profiles. - */ -export default function UserInfoSideBar({ sideBarData, refetch }: Props) { - const { - name, - aboutText, - avatarName, - email, - groupsDetails, - phone, - photoUrl, - role, - slack, - team, - dataHubRoles, - urn, - countryCode, - username, - } = sideBarData; - - const [updateCorpUserPropertiesMutation] = useUpdateCorpUserPropertiesMutation(); - - const [groupSectionExpanded, setGroupSectionExpanded] = useState(false); - const [editProfileModal, showEditProfileModal] = useState(false); - /* eslint-disable @typescript-eslint/no-unused-vars */ - const me = useUserContext(); - const isProfileOwner = me?.user?.urn === urn; - - const { updateTitle } = useBrowserTitle(); - - useEffect(() => { - // You can use the title and updateTitle function here - // For example, updating the title when the component mounts - if (name) { - updateTitle(`User | ${name}`); - } - // // Don't forget to clean up the title when the component unmounts - return () => { - if (name) { - // added to condition for rerendering issue - updateTitle(''); - } - }; - }, [name, updateTitle]); - - const getEditModalData = { - urn, - name, - title: role, - team, - email, - image: photoUrl, - slack, - phone, - }; - - // About Text save - const onSaveAboutMe = (inputString) => { - updateCorpUserPropertiesMutation({ - variables: { - urn: urn || '', - input: { - aboutMe: inputString, - }, - }, - }) - .then(() => { - message.success({ - content: `Changes saved.`, - duration: 3, - }); - refetch(); - }) - .catch((e) => { - message.destroy(); - message.error({ content: `Failed to Save changes!: \n ${e.message || ''}`, duration: 3 }); - }); - }; - const dataHubRoleName = dataHubRoles && dataHubRoles.length > 0 && (dataHubRoles[0]?.entity as DataHubRole).name; - - const maybeCountryName = getCountryName(countryCode ?? ''); - return ( - <> - - - - {name || } - {username || } - {role && {role}} - {team && {team}} - {dataHubRoleName && {dataHubRoleName}} - - - - - {email || } - - - - - - {slack || } - - - - - - {phone || } - - - - {maybeCountryName != null ? ( - - Location -
- - Manage Users   - {maybeCountryName} - - -
- ) : null} - - About - - - {aboutText || } - - - - - - Groups - setGroupSectionExpanded(!groupSectionExpanded)} - groupMemberRelationships={groupsDetails} - /> - -
- {isProfileOwner && ( - - - - )} -
- {/* Modal */} - showEditProfileModal(false)} - onSave={() => { - refetch(); - }} - editModalData={getEditModalData} - /> - - ); -} diff --git a/datahub-web-react/src/app/entity/user/UserProfile.tsx b/datahub-web-react/src/app/entity/user/UserProfile.tsx deleted file mode 100644 index b25bb092cd0c61..00000000000000 --- a/datahub-web-react/src/app/entity/user/UserProfile.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import { Col, Row } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import NonExistentEntityPage from '@app/entity/shared/entity/NonExistentEntityPage'; -import { decodeUrn } from '@app/entity/shared/utils'; -import { UserAssets } from '@app/entity/user/UserAssets'; -import UserGroups from '@app/entity/user/UserGroups'; -import UserInfoSideBar from '@app/entity/user/UserInfoSideBar'; -import { RoutedTabs } from '@app/shared/RoutedTabs'; -import useUserParams from '@app/shared/entitySearch/routingUtils/useUserParams'; -import { ErrorSection } from '@app/shared/error/ErrorSection'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useGetUserQuery } from '@graphql/user.generated'; -import { EntityRelationship, EntityType } from '@types'; - -export interface Props { - onTabChange: (selectedTab: string) => void; -} - -export enum TabType { - Assets = 'Owner Of', - Groups = 'Groups', -} -const ENABLED_TAB_TYPES = [TabType.Assets, TabType.Groups]; - -const GROUP_PAGE_SIZE = 20; - -/** - * Styled Components - */ -const UserProfileWrapper = styled.div` - &&& .ant-tabs-nav { - margin: 0; - } -`; - -const Content = styled.div` - color: #262626; - height: calc(100vh - 60px); - - &&& .ant-tabs > .ant-tabs-nav .ant-tabs-nav-wrap { - padding-left: 15px; - } -`; - -export const EmptyValue = styled.div` - &:after { - content: 'None'; - color: #b7b7b7; - font-style: italic; - font-weight: 100; - } -`; - -/** - * Responsible for reading & writing users. - */ -export default function UserProfile() { - const { urn: encodedUrn } = useUserParams(); - const urn = decodeUrn(encodedUrn); - const entityRegistry = useEntityRegistry(); - - const { error, data, refetch } = useGetUserQuery({ variables: { urn, groupsCount: GROUP_PAGE_SIZE } }); - - const castedCorpUser = data?.corpUser as any; - - const userGroups: Array = - castedCorpUser?.groups?.relationships?.map((relationship) => relationship as EntityRelationship) || []; - const userRoles: Array = - castedCorpUser?.roles?.relationships?.map((relationship) => relationship as EntityRelationship) || []; - - // Routed Tabs Constants - const getTabs = () => { - return [ - { - name: TabType.Assets, - path: TabType.Assets.toLocaleLowerCase(), - content: , - display: { - enabled: () => true, - }, - }, - { - name: TabType.Groups, - path: TabType.Groups.toLocaleLowerCase(), - content: , - display: { - enabled: () => userGroups?.length > 0, - }, - }, - ].filter((tab) => ENABLED_TAB_TYPES.includes(tab.name)); - }; - const defaultTabPath = getTabs() && getTabs()?.length > 0 ? getTabs()[0].path : ''; - const onTabChange = () => null; - - // Side bar data - const sideBarData = { - photoUrl: data?.corpUser?.editableProperties?.pictureLink || undefined, - avatarName: - data?.corpUser?.editableProperties?.displayName || - data?.corpUser?.info?.displayName || - data?.corpUser?.info?.fullName || - data?.corpUser?.urn, - name: - data?.corpUser?.editableProperties?.displayName || - (data?.corpUser && entityRegistry.getDisplayName(EntityType.CorpUser, data?.corpUser)) || - undefined, - role: data?.corpUser?.editableProperties?.title || data?.corpUser?.info?.title || undefined, - team: data?.corpUser?.editableProperties?.teams?.join(',') || data?.corpUser?.info?.departmentName || undefined, - countryCode: data?.corpUser?.info?.countryCode || undefined, - email: data?.corpUser?.editableProperties?.email || data?.corpUser?.info?.email || undefined, - slack: data?.corpUser?.editableProperties?.slack || undefined, - phone: data?.corpUser?.editableProperties?.phone || undefined, - aboutText: data?.corpUser?.editableProperties?.aboutMe || undefined, - groupsDetails: userGroups, - dataHubRoles: userRoles, - urn, - username: data?.corpUser?.username, - }; - - if (data?.corpUser?.exists === false) { - return ; - } - - return ( - <> - {error && } - - -
- - - - - - - - - - - ); -} diff --git a/datahub-web-react/src/app/entity/user/preview/Preview.tsx b/datahub-web-react/src/app/entity/user/preview/Preview.tsx deleted file mode 100644 index 580cdedca8523c..00000000000000 --- a/datahub-web-react/src/app/entity/user/preview/Preview.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { Typography } from 'antd'; -import React from 'react'; -import { Link } from 'react-router-dom'; -import styled from 'styled-components'; - -import { IconStyleType } from '@app/entity/Entity'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import SearchTextHighlighter from '@app/search/matches/SearchTextHighlighter'; -import { CustomAvatar } from '@app/shared/avatar'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { EntityType } from '@types'; - -const PreviewContainer = styled.div` - display: flex; - width: 100%; - justify-content: space-between; - align-items: center; -`; - -const PlatformInfo = styled.div` - margin-bottom: 8px; - display: flex; - align-items: center; - height: 24px; -`; - -const TitleContainer = styled.div` - margin-bottom: 8px; -`; - -const PreviewImage = styled.div` - max-height: 18px; - width: auto; - object-fit: contain; - margin-right: 10px; - background-color: transparent; -`; - -const EntityTitle = styled(Typography.Text)` - &&& { - margin-bottom: 0; - font-size: 16px; - font-weight: 600; - vertical-align: middle; - } -`; - -const PlatformText = styled(Typography.Text)` - font-size: 12px; - line-height: 20px; - font-weight: 700; - color: ${ANTD_GRAY[7]}; -`; - -const AvatarContainer = styled.div` - margin-right: 60px; -`; - -export const Preview = ({ - urn, - name, - title, - photoUrl, -}: { - urn: string; - name: string; - photoUrl?: string | undefined; - title?: string | undefined; -}): JSX.Element => { - const entityRegistry = useEntityRegistry(); - const url = entityRegistry.getEntityUrl(EntityType.CorpUser, urn); - - return ( - -
- - - - - {entityRegistry.getIcon(EntityType.CorpUser, 20, IconStyleType.HIGHLIGHT)} - - {entityRegistry.getEntityName(EntityType.CorpUser)} - - - {name ? : urn} - - - - {title && ( - - - - )} -
- - - - - -
- ); -}; diff --git a/datahub-web-react/src/app/entity/view/ManageViews.tsx b/datahub-web-react/src/app/entity/view/ManageViews.tsx deleted file mode 100644 index 0304c6cef5bc01..00000000000000 --- a/datahub-web-react/src/app/entity/view/ManageViews.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { ViewsList } from '@app/entity/view/ViewsList'; - -const PageContainer = styled.div` - padding-top: 20px; - width: 100%; - display: flex; - flex-direction: column; - overflow: auto; -`; - -const PageHeaderContainer = styled.div` - && { - padding-left: 24px; - } -`; - -const PageTitle = styled(Typography.Title)` - && { - margin-bottom: 12px; - } -`; - -const ListContainer = styled.div` - display: flex; - flex-direction: column; - overflow: auto; -`; - -/** - * Component used for displaying the 'Manage Views' experience. - */ -export const ManageViews = () => { - return ( - - - Manage Views - - Create, edit, and remove your Views. Views allow you to save and share sets of filters for reuse - when browsing DataHub. - - - - - - - ); -}; diff --git a/datahub-web-react/src/app/entity/view/ViewsList.tsx b/datahub-web-react/src/app/entity/view/ViewsList.tsx deleted file mode 100644 index a548974ad3845e..00000000000000 --- a/datahub-web-react/src/app/entity/view/ViewsList.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import { PlusOutlined } from '@ant-design/icons'; -import { Button, Pagination, message } from 'antd'; -import * as QueryString from 'query-string'; -import React, { useEffect, useState } from 'react'; -import { useLocation } from 'react-router'; -import styled from 'styled-components'; - -import TabToolbar from '@app/entity/shared/components/styled/TabToolbar'; -import { ViewsTable } from '@app/entity/view/ViewsTable'; -import { ViewBuilder } from '@app/entity/view/builder/ViewBuilder'; -import { ViewBuilderMode } from '@app/entity/view/builder/types'; -import { DEFAULT_LIST_VIEWS_PAGE_SIZE, searchViews } from '@app/entity/view/utils'; -import { SearchBar } from '@app/search/SearchBar'; -import { Message } from '@app/shared/Message'; -import { scrollToTop } from '@app/shared/searchUtils'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useListMyViewsQuery } from '@graphql/view.generated'; - -const PaginationContainer = styled.div` - display: flex; - justify-content: center; -`; - -const StyledPagination = styled(Pagination)` - margin: 40px; -`; - -const searchBarStyle = { - maxWidth: 220, - padding: 0, -}; - -const searchBarInputStyle = { - height: 32, - fontSize: 12, -}; - -/** - * This component renders a paginated, searchable list of Views. - */ -export const ViewsList = () => { - /** - * Context - */ - const location = useLocation(); - const entityRegistry = useEntityRegistry(); - - /** - * Query Params - */ - const params = QueryString.parse(location.search, { arrayFormat: 'comma' }); - const paramsQuery = (params?.query as string) || undefined; - - /** - * State - */ - const [page, setPage] = useState(1); - const [selectedViewUrn, setSelectedViewUrn] = useState(undefined); - const [showViewBuilder, setShowViewBuilder] = useState(false); - const [query, setQuery] = useState(undefined); - useEffect(() => setQuery(paramsQuery), [paramsQuery]); - - /** - * Queries - */ - const pageSize = DEFAULT_LIST_VIEWS_PAGE_SIZE; - const start = (page - 1) * pageSize; - const { loading, error, data } = useListMyViewsQuery({ - variables: { - start, - count: pageSize, - }, - fetchPolicy: 'cache-first', - }); - - const onClickCreateView = () => { - setShowViewBuilder(true); - }; - - const onClickEditView = (urn: string) => { - setShowViewBuilder(true); - setSelectedViewUrn(urn); - }; - - const onCloseModal = () => { - setShowViewBuilder(false); - setSelectedViewUrn(undefined); - }; - - const onChangePage = (newPage: number) => { - scrollToTop(); - setPage(newPage); - }; - - /** - * Render variables. - */ - const totalViews = data?.listMyViews?.total || 0; - const views = searchViews(data?.listMyViews?.views || [], query); - const selectedView = (selectedViewUrn && views.find((view) => view.urn === selectedViewUrn)) || undefined; - - return ( - <> - {!data && loading && } - {error && message.error({ content: `Failed to load Views! An unexpected error occurred.`, duration: 3 })} - - - null} - onQueryChange={(q) => setQuery(q.length > 0 ? q : undefined)} - entityRegistry={entityRegistry} - /> - - - {totalViews >= pageSize && ( - - - - )} - {showViewBuilder && ( - - )} - - ); -}; diff --git a/datahub-web-react/src/app/entity/view/ViewsTable.tsx b/datahub-web-react/src/app/entity/view/ViewsTable.tsx deleted file mode 100644 index 2de13122be347b..00000000000000 --- a/datahub-web-react/src/app/entity/view/ViewsTable.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { Empty } from 'antd'; -import React from 'react'; - -import { StyledTable } from '@app/entity/shared/components/styled/StyledTable'; -import { - ActionsColumn, - DescriptionColumn, - NameColumn, - ViewTypeColumn, -} from '@app/entity/view/select/ViewsTableColumns'; - -import { DataHubView } from '@types'; - -type ViewsTableProps = { - views: DataHubView[]; - onEditView: (urn) => void; -}; - -/** - * This component renders a table of Views. - */ -export const ViewsTable = ({ views, onEditView }: ViewsTableProps) => { - const tableColumns = [ - { - title: 'Name', - dataIndex: 'name', - key: 'name', - render: (name, record) => , - }, - { - title: 'Description', - dataIndex: 'description', - key: 'description', - render: (description) => , - }, - { - title: 'Type', - dataIndex: 'viewType', - key: 'viewType', - render: (viewType) => , - }, - { - title: '', - dataIndex: '', - key: 'x', - render: (record) => , - }, - ]; - - /** - * The data for the Views List. - */ - const tableData = views.map((view) => ({ - ...view, - })); - - return ( - , - }} - pagination={false} - /> - ); -}; diff --git a/datahub-web-react/src/app/entity/view/builder/utils.ts b/datahub-web-react/src/app/entity/view/builder/utils.ts index 131d9bc81582ca..2a6f0c70d7400e 100644 --- a/datahub-web-react/src/app/entity/view/builder/utils.ts +++ b/datahub-web-react/src/app/entity/view/builder/utils.ts @@ -57,7 +57,7 @@ export function convertNestedSubTypeFilter(filters: Array) { * @param filters a list of Facet Filter Inputs representing the view filters. This can include the entity type filter. * @param operatorType a logical operator to be used when joining the filters into the View definition. */ -export const buildViewDefinition = (filters: Array, operatorType: LogicalOperator) => { +const buildViewDefinition = (filters: Array, operatorType: LogicalOperator) => { const convertedFilters = convertNestedSubTypeFilter(filters); const entityTypes = extractEntityTypesFilterValues(convertedFilters); const filteredFilters = convertedFilters.filter((filter) => filter.field !== ENTITY_FILTER_NAME); diff --git a/datahub-web-react/src/app/entity/view/select/ViewsTableColumns.tsx b/datahub-web-react/src/app/entity/view/select/ViewsTableColumns.tsx deleted file mode 100644 index 62324082eb3882..00000000000000 --- a/datahub-web-react/src/app/entity/view/select/ViewsTableColumns.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { Button, Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { useUserContext } from '@app/context/useUserContext'; -import { ANTD_GRAY } from '@app/entity/shared/constants'; -import { ViewTypeLabel } from '@app/entity/view/ViewTypeLabel'; -import { ViewDropdownMenu } from '@app/entity/view/menu/ViewDropdownMenu'; -import { GlobalDefaultViewIcon } from '@app/entity/view/shared/GlobalDefaultViewIcon'; -import { UserDefaultViewIcon } from '@app/entity/view/shared/UserDefaultViewIcon'; - -import { DataHubViewType } from '@types'; - -const StyledDescription = styled.div` - max-width: 300px; -`; - -const ActionButtonsContainer = styled.div` - display: flex; - justify-content: center; - align-items: center; - padding-right: 8px; -`; - -const NameContainer = styled.span` - display: flex; - align-items: center; - justify-content: left; -`; - -const IconPlaceholder = styled.span` - display: flex; - align-items: center; - justify-content: center; -`; - -type NameColumnProps = { - name: string; - record: any; - onEditView: (urn) => void; -}; - -export function NameColumn({ name, record, onEditView }: NameColumnProps) { - const userContext = useUserContext(); - const maybePersonalDefaultViewUrn = userContext.state?.views?.personalDefaultViewUrn; - const maybeGlobalDefaultViewUrn = userContext.state?.views?.globalDefaultViewUrn; - - const isUserDefault = record.urn === maybePersonalDefaultViewUrn; - const isGlobalDefault = record.urn === maybeGlobalDefaultViewUrn; - - return ( - - - {isUserDefault && } - {isGlobalDefault && } - - - - ); -} - -type DescriptionColumnProps = { - description: string; -}; - -export function DescriptionColumn({ description }: DescriptionColumnProps) { - return ( - - {description || No description} - - ); -} - -type ViewTypeColumnProps = { - viewType: DataHubViewType; -}; - -export function ViewTypeColumn({ viewType }: ViewTypeColumnProps) { - return ; -} - -type ActionColumnProps = { - record: any; -}; - -export function ActionsColumn({ record }: ActionColumnProps) { - return ( - - - - ); -} diff --git a/datahub-web-react/src/app/entity/view/select/styledComponents.tsx b/datahub-web-react/src/app/entity/view/select/styledComponents.tsx index a2ba05a83e9e5b..fc06d0f1d9ae86 100644 --- a/datahub-web-react/src/app/entity/view/select/styledComponents.tsx +++ b/datahub-web-react/src/app/entity/view/select/styledComponents.tsx @@ -10,7 +10,7 @@ export const NoMarginButton = styled(Button)` } `; -export const StyledRightOutlined = styled(RightOutlined)` +const StyledRightOutlined = styled(RightOutlined)` && { font-size: 8px; color: ${ANTD_GRAY[7]}; diff --git a/datahub-web-react/src/app/entity/view/utils.ts b/datahub-web-react/src/app/entity/view/utils.ts index 589780e3858c4a..b7b35e65f9a5d8 100644 --- a/datahub-web-react/src/app/entity/view/utils.ts +++ b/datahub-web-react/src/app/entity/view/utils.ts @@ -46,7 +46,7 @@ export const convertStateToUpdateInput = (state: ViewBuilderState) => { * @param urn urn of the View * @param state state of the View */ -export const convertStateToView = (urn: string, state: ViewBuilderState): DataHubView => { +const convertStateToView = (urn: string, state: ViewBuilderState): DataHubView => { return { urn, type: EntityType.DatahubView, @@ -75,7 +75,7 @@ export const convertStateToView = (urn: string, state: ViewBuilderState): DataHu * @param views: A list of DataHub View objects. * @param q: An optional search query. */ -export const searchViews = (views: Array, q?: string) => { +const searchViews = (views: Array, q?: string) => { if (q && q.length > 0) { const qLower = q.toLowerCase(); return views.filter((view) => view.name.toLowerCase().includes(qLower) || view.description?.includes(qLower)); diff --git a/datahub-web-react/src/app/entityV2/application/AssetsSections.tsx b/datahub-web-react/src/app/entityV2/application/AssetsSections.tsx index 2ad0f4dd056e2f..950f7b1ce63029 100644 --- a/datahub-web-react/src/app/entityV2/application/AssetsSections.tsx +++ b/datahub-web-react/src/app/entityV2/application/AssetsSections.tsx @@ -25,7 +25,7 @@ const AssetsSectionWrapper = styled.div` min-width: 100px; `; -export const StyledHeaderWrapper = styled(SummaryTabHeaderWrapper)` +const StyledHeaderWrapper = styled(SummaryTabHeaderWrapper)` margin-bottom: 8px; `; diff --git a/datahub-web-react/src/app/entityV2/businessAttribute/profile/BusinessAttributeDataTypeSection.tsx b/datahub-web-react/src/app/entityV2/businessAttribute/profile/BusinessAttributeDataTypeSection.tsx index 1ee9d902570a16..3e4773cacd4b91 100644 --- a/datahub-web-react/src/app/entityV2/businessAttribute/profile/BusinessAttributeDataTypeSection.tsx +++ b/datahub-web-react/src/app/entityV2/businessAttribute/profile/BusinessAttributeDataTypeSection.tsx @@ -97,4 +97,3 @@ export const BusinessAttributeDataTypeSection = ({ readOnly }: Props) => { ); }; -export default BusinessAttributeDataTypeSection; diff --git a/datahub-web-react/src/app/entityV2/dataProduct/AddOutputPortCard.tsx b/datahub-web-react/src/app/entityV2/dataProduct/AddOutputPortCard.tsx deleted file mode 100644 index d84ad7c7e39bc9..00000000000000 --- a/datahub-web-react/src/app/entityV2/dataProduct/AddOutputPortCard.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { PlusOutlined } from '@ant-design/icons'; -import React from 'react'; -import styled from 'styled-components'; - -import { REDESIGN_COLORS } from '@app/entityV2/shared/constants'; -import { Card } from '@app/sharedV2/cards/components'; - -const DataProductTitle = styled.div` - font-size: 16px; - font-weight: 400; - color: ${REDESIGN_COLORS.BLUE}; - padding: 10px 14px; -`; - -export default function AddOutputPortCard() { - return ( - - - - Add Output Port - - - ); -} diff --git a/datahub-web-react/src/app/entityV2/dataset/profile/Lineage.tsx b/datahub-web-react/src/app/entityV2/dataset/profile/Lineage.tsx index 558f48b760a6cd..776e2afa66660e 100644 --- a/datahub-web-react/src/app/entityV2/dataset/profile/Lineage.tsx +++ b/datahub-web-react/src/app/entityV2/dataset/profile/Lineage.tsx @@ -9,7 +9,7 @@ import { useEntityRegistry } from '@app/useEntityRegistry'; import { DownstreamEntityRelationships, EntityType, UpstreamEntityRelationships } from '@types'; -export type Props = { +type Props = { upstreamLineage?: UpstreamEntityRelationships | null; downstreamLineage?: DownstreamEntityRelationships | null; }; diff --git a/datahub-web-react/src/app/entityV2/dataset/profile/UsageFacepile.tsx b/datahub-web-react/src/app/entityV2/dataset/profile/UsageFacepile.tsx index bba44711ba1dba..061125b01d197e 100644 --- a/datahub-web-react/src/app/entityV2/dataset/profile/UsageFacepile.tsx +++ b/datahub-web-react/src/app/entityV2/dataset/profile/UsageFacepile.tsx @@ -7,7 +7,7 @@ import { useEntityRegistry } from '@app/useEntityRegistry'; import { EntityType, UserUsageCounts } from '@types'; -export type Props = { +type Props = { users?: (UserUsageCounts | null)[] | null; maxNumberDisplayed?: number; }; diff --git a/datahub-web-react/src/app/entityV2/dataset/profile/schema/components/CustomPagination.tsx b/datahub-web-react/src/app/entityV2/dataset/profile/schema/components/CustomPagination.tsx deleted file mode 100644 index a9a98b7d506ec2..00000000000000 --- a/datahub-web-react/src/app/entityV2/dataset/profile/schema/components/CustomPagination.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import { LeftOutlined, RightOutlined } from '@ant-design/icons'; -import { Button, Dropdown, Menu, Typography } from 'antd'; -import React, { useState } from 'react'; -import styled from 'styled-components'; - -const CustomPaginationContainer = styled.div` - display: flex; - flex-direction: row; - height: 32px; -`; -const NavButton = styled(Button)` - margin: 4px 6px; - cursor: pointer; -`; -const DescriptionText = styled(Typography.Text)` - line-height: 32px; -`; -const VersionText = styled(Typography.Text)` - padding: 0 4px; - line-height: 32px; - cursor: pointer; -`; -const VersionRightText = styled(Typography.Text)` - padding-left: 4px; - line-height: 32px; - cursor: pointer; -`; - -type Props = { - onChange: (version1: number, version2: number) => void; - maxVersion: number; -}; - -export default function CustomPagination({ onChange, maxVersion }: Props) { - const [version1, setVersion1] = useState(maxVersion || 1); // current version - first dropdown selected - const [version2, setVersion2] = useState(maxVersion ? maxVersion - 1 : 0); // past version comparing with current - second dropdown - - const onNextClick = () => { - setVersion1((v) => v - 1); - setVersion2(version1 - 2); - onChange(version1 - 1, version1 - 2); - }; - const onPrevClick = () => { - setVersion1((v) => v + 1); - setVersion2(version1); - onChange(version1 + 1, version1); - }; - const onVersion1Click = ({ key }) => { - const newVersion1 = parseInt(key, 10); - setVersion1(newVersion1); - if (version2 >= newVersion1) { - setVersion2(newVersion1 - 1); - onChange(newVersion1, newVersion1 - 1); - return; - } - onChange(newVersion1, version2); - }; - const onVersion2Click = ({ key }) => { - setVersion2(parseInt(key, 10)); - onChange(version1, parseInt(key, 10)); - }; - - const menu1 = ( - - {[...Array(maxVersion)].map((_, i) => ( - // eslint-disable-next-line react/no-array-index-key - - {i === 0 ? 'latest' : `version ${maxVersion + 1 - i}`} - - ))} - - ); - - const menu2 = ( - - {[...Array(version1)].map((_, i) => ( - // eslint-disable-next-line react/no-array-index-key - - {`version ${version1 - i}`} - - ))} - - ); - - return ( - - } - onClick={onPrevClick} - disabled={version1 >= maxVersion} - /> - Comparing - - - {version1 === maxVersion ? 'latest' : `version ${version1 + 1}`} - - - to - - {`version ${version2 + 1}`} - - } - onClick={onNextClick} - disabled={version1 <= 1} - /> - - ); -} diff --git a/datahub-web-react/src/app/entityV2/dataset/profile/schema/components/SchemaVersionSummary.tsx b/datahub-web-react/src/app/entityV2/dataset/profile/schema/components/SchemaVersionSummary.tsx index 2a27a41a8cf387..ade15ec68d255f 100644 --- a/datahub-web-react/src/app/entityV2/dataset/profile/schema/components/SchemaVersionSummary.tsx +++ b/datahub-web-react/src/app/entityV2/dataset/profile/schema/components/SchemaVersionSummary.tsx @@ -21,7 +21,7 @@ type Props = { diffSummary: SchemaDiffSummary; }; -export default function SchemaVersionSummary({ diffSummary }: Props) { +function SchemaVersionSummary({ diffSummary }: Props) { return (
    diff --git a/datahub-web-react/src/app/entityV2/dataset/profile/schema/components/TypeIcon.tsx b/datahub-web-react/src/app/entityV2/dataset/profile/schema/components/TypeIcon.tsx deleted file mode 100644 index 8324ce90309a91..00000000000000 --- a/datahub-web-react/src/app/entityV2/dataset/profile/schema/components/TypeIcon.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { - CalendarOutlined, - FieldBinaryOutlined, - FieldTimeOutlined, - NumberOutlined, - QuestionCircleOutlined, - UnderlineOutlined, - UnorderedListOutlined, -} from '@ant-design/icons'; -import { Tooltip } from '@components'; -import { Typography } from 'antd'; -import React, { FC } from 'react'; -import { VscFileBinary, VscSymbolString } from 'react-icons/vsc'; -import styled from 'styled-components'; - -import { capitalizeFirstLetter } from '@app/shared/textUtil'; - -import { SchemaFieldDataType } from '@types'; - -const TypeIconContainer = styled.div` - display: flex; - flex-direction: column; - justify-content: center; - text-align: center; - margin-top: 2.5px; - width: 40px; -`; - -const TypeSubtitle = styled(Typography.Text)<{ hasicon?: string }>` - font-size: 8px; - text-align: center; - ${(props) => (props.hasicon ? '' : 'margin-top: 4px;')} -`; - -const IconSpan = styled.span` - font-size: 18px; -`; - -const DATA_TYPE_ICON_MAP: Record | null; size: number; text: string }> = - { - [SchemaFieldDataType.Boolean]: { - icon: FieldBinaryOutlined, - size: 18, - text: 'Boolean', - }, - [SchemaFieldDataType.Fixed]: { icon: FieldBinaryOutlined, size: 18, text: 'Fixed' }, - [SchemaFieldDataType.String]: { - icon: () => ( - - - - ), - size: 20, - text: 'String', - }, - [SchemaFieldDataType.Bytes]: { - icon: () => ( - - - - ), - size: 18, - text: 'Bytes', - }, - [SchemaFieldDataType.Number]: { icon: NumberOutlined, size: 14, text: 'Number' }, - [SchemaFieldDataType.Date]: { icon: CalendarOutlined, size: 18, text: 'Date' }, - [SchemaFieldDataType.Time]: { icon: FieldTimeOutlined, size: 18, text: 'Time' }, - [SchemaFieldDataType.Enum]: { icon: UnorderedListOutlined, size: 18, text: 'Enum' }, - [SchemaFieldDataType.Null]: { icon: QuestionCircleOutlined, size: 16, text: '' }, - [SchemaFieldDataType.Map]: { icon: null, size: 0, text: 'Map' }, - [SchemaFieldDataType.Array]: { icon: UnorderedListOutlined, size: 14, text: 'Array' }, - [SchemaFieldDataType.Union]: { icon: UnderlineOutlined, size: 14, text: 'Union' }, - [SchemaFieldDataType.Struct]: { icon: null, size: 0, text: 'Struct' }, - }; - -const truncate = (length: number, input?: string | null) => { - if (!input) return ''; - if (input.length > length) { - return `${input.substring(0, length)}...`; - } - return input; -}; - -type Props = { - type: SchemaFieldDataType; - nativeDataType: string | null | undefined; -}; - -export default function TypeIcon({ type, nativeDataType }: Props) { - const { icon: Icon, size, text } = DATA_TYPE_ICON_MAP[type]; - - // if unable to match type to DataHub, display native type info by default - const nativeFallback = type === SchemaFieldDataType.Null; - - // eslint-disable-next-line react/prop-types - const NativeDataTypeTooltip = ({ children }) => - nativeDataType ? ( - - {children} - - ) : ( - <>{children} - ); - - return ( - - - {Icon && } - - {nativeFallback ? truncate(250, nativeDataType) : text} - - - - ); -} diff --git a/datahub-web-react/src/app/entityV2/dataset/profile/schema/components/VersionSelector.tsx b/datahub-web-react/src/app/entityV2/dataset/profile/schema/components/VersionSelector.tsx index 6e44c27f748ce8..d8007c19f9180b 100644 --- a/datahub-web-react/src/app/entityV2/dataset/profile/schema/components/VersionSelector.tsx +++ b/datahub-web-react/src/app/entityV2/dataset/profile/schema/components/VersionSelector.tsx @@ -13,7 +13,7 @@ import navigateToUrl from '@app/utils/navigateToUrl'; import { DataPlatform, SemanticVersionStruct } from '@types'; export const SEMANTIC_VERSION_PARAM = 'semantic_version'; -export const SIBLING_VERSION_PARAM = 'secondary_version'; // Note: Currently unused +const SIBLING_VERSION_PARAM = 'secondary_version'; // Note: Currently unused const Wrapper = styled.div` display: flex; diff --git a/datahub-web-react/src/app/entityV2/dataset/profile/schema/utils/types.ts b/datahub-web-react/src/app/entityV2/dataset/profile/schema/utils/types.ts index 0b43ef2f113ea7..78281d9b9e0238 100644 --- a/datahub-web-react/src/app/entityV2/dataset/profile/schema/utils/types.ts +++ b/datahub-web-react/src/app/entityV2/dataset/profile/schema/utils/types.ts @@ -10,7 +10,7 @@ export interface ExtendedSchemaFields extends SchemaField { parent?: ExtendedSchemaFields; } -export enum SchemaViewType { +enum SchemaViewType { NORMAL, BLAME, } diff --git a/datahub-web-react/src/app/entityV2/dataset/profile/schema/utils/utils.ts b/datahub-web-react/src/app/entityV2/dataset/profile/schema/utils/utils.ts index ff3e2e53c8d929..14e31dc3bb11f1 100644 --- a/datahub-web-react/src/app/entityV2/dataset/profile/schema/utils/utils.ts +++ b/datahub-web-react/src/app/entityV2/dataset/profile/schema/utils/utils.ts @@ -14,7 +14,7 @@ import { SchemaField, } from '@types'; -export function convertEditableSchemaMeta( +function convertEditableSchemaMeta( editableSchemaMeta?: Array, fields?: Array, ): Array { @@ -34,7 +34,7 @@ export function convertEditableSchemaMeta( return updatedFields; } -export function convertEditableSchemaMetadataForUpdate( +function convertEditableSchemaMetadataForUpdate( editableSchemaMetadata: EditableSchemaMetadata | null | undefined, ): EditableSchemaMetadataUpdate { return { @@ -151,7 +151,7 @@ export function groupByFieldPath( return outputRows; } -export function diffMarkdown(oldStr: string, newStr: string) { +function diffMarkdown(oldStr: string, newStr: string) { const diffArray = diff.diffChars(oldStr || '', newStr || ''); return diffArray .map((diffOne) => { @@ -207,7 +207,7 @@ export function getRawSchema(schema: PlatformSchema | undefined | null, showKeyS } // Get diff summary between two versions and prepare to visualize description diff changes -export function getDiffSummary( +function getDiffSummary( currentVersionRows?: Array, previousVersionRows?: Array, options: { showKeySchema: boolean } = { showKeySchema: false }, diff --git a/datahub-web-react/src/app/entityV2/dataset/profile/stats/Stats.tsx b/datahub-web-react/src/app/entityV2/dataset/profile/stats/Stats.tsx deleted file mode 100644 index 1385f6df5aa25e..00000000000000 --- a/datahub-web-react/src/app/entityV2/dataset/profile/stats/Stats.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { Radio } from 'antd'; -import React, { useState } from 'react'; - -import HistoricalStatsView from '@app/entityV2/dataset/profile/stats/historical/HistoricalStatsView'; -import LatestStatsView from '@app/entityV2/dataset/profile/stats/snapshot/LatestStatsView'; - -import { DatasetProfile } from '@types'; - -export type Props = { - urn: string; - profile: DatasetProfile; -}; - -enum ViewType { - LATEST, - HISTORICAL, -} - -export default function Stats({ urn, profile }: Props) { - /** - * Determines which view should be visible: latest or historical. - */ - const [view, setView] = useState(ViewType.LATEST); - - const onChangeView = (e) => { - setView(e.target.value); - }; - - const toggleView = ( - - Latest - Historical - - ); - - return ( - <> - {view === ViewType.LATEST && } - {view === ViewType.HISTORICAL && } - - ); -} diff --git a/datahub-web-react/src/app/entityV2/dataset/profile/stats/StatsSection.tsx b/datahub-web-react/src/app/entityV2/dataset/profile/stats/StatsSection.tsx index 32244ee67cc374..b5855f29524e93 100644 --- a/datahub-web-react/src/app/entityV2/dataset/profile/stats/StatsSection.tsx +++ b/datahub-web-react/src/app/entityV2/dataset/profile/stats/StatsSection.tsx @@ -14,7 +14,7 @@ const ThinDivider = styled(Divider)` margin-bottom: 8px; `; -export type Props = { +type Props = { children: React.ReactNode; title: string; rightFloatView?: React.ReactNode; diff --git a/datahub-web-react/src/app/entityV2/dataset/profile/stats/historical/HistoricalStatsView.tsx b/datahub-web-react/src/app/entityV2/dataset/profile/stats/historical/HistoricalStatsView.tsx deleted file mode 100644 index 421d9474d075b5..00000000000000 --- a/datahub-web-react/src/app/entityV2/dataset/profile/stats/historical/HistoricalStatsView.tsx +++ /dev/null @@ -1,230 +0,0 @@ -import { Affix, Row, Select, Typography } from 'antd'; -import React, { ReactNode, useEffect, useState } from 'react'; -import styled from 'styled-components'; - -import StatsSection from '@app/entityV2/dataset/profile/stats/StatsSection'; -import ProfilingRunsChart from '@app/entityV2/dataset/profile/stats/historical/charts/ProfilingRunsChart'; -import StatChart from '@app/entityV2/dataset/profile/stats/historical/charts/StatChart'; -import { - computeAllFieldPaths, - computeChartTickInterval, - extractChartValuesFromFieldProfiles, - extractChartValuesFromTableProfiles, -} from '@app/entityV2/shared/utils'; -import { Message } from '@app/shared/Message'; -import { getFixedLookbackWindow } from '@app/shared/time/timeUtils'; - -import { useGetDataProfilesLazyQuery } from '@graphql/dataset.generated'; -import { DateInterval } from '@types'; - -const HeaderRow = styled(Row)` - padding-top: 24px; - padding-bottom: 28px; - background-color: white; -`; - -const SubHeaderText = styled(Typography.Text)` - color: gray; - font-size: 16px; -`; - -const EmbeddedSelect = styled(Select)` - padding-left: 8px; -`; - -/** - * Change this to add or modify the lookback windows that are selectable via the UI. - */ -const LOOKBACK_WINDOWS = [ - { text: '1 day', windowSize: { interval: DateInterval.Day, count: 1 } }, - { text: '1 week', windowSize: { interval: DateInterval.Week, count: 1 } }, - { text: '1 month', windowSize: { interval: DateInterval.Month, count: 1 } }, - { text: '3 months', windowSize: { interval: DateInterval.Month, count: 3 } }, - { text: '1 year', windowSize: { interval: DateInterval.Year, count: 1 } }, -]; - -const DEFAULT_LOOKBACK_WINDOW = '3 months'; - -const getLookbackWindowSize = (text: string) => { - for (let i = 0; i < LOOKBACK_WINDOWS.length; i++) { - const window = LOOKBACK_WINDOWS[i]; - if (window.text === text) { - return window.windowSize; - } - } - throw new Error(`Unrecognized lookback window size ${text} provided`); -}; - -export type Props = { - urn: string; - toggleView: ReactNode; -}; - -export default function HistoricalStatsView({ urn, toggleView }: Props) { - const [getDataProfiles, { data: profilesData, loading: profilesLoading }] = useGetDataProfilesLazyQuery({ - fetchPolicy: 'cache-first', - }); - - /** - * Perform initial fetch of default lookback window stats. - */ - useEffect(() => { - getDataProfiles({ - variables: { urn, ...getFixedLookbackWindow(getLookbackWindowSize(DEFAULT_LOOKBACK_WINDOW)) }, - }); - }, [urn, getDataProfiles]); - - /** - * Determines which fixed lookback window is used to display historical statistics. See above for valid options. - */ - const [selectedLookbackWindow, setSelectedLookbackWindow] = useState(DEFAULT_LOOKBACK_WINDOW); - const selectedWindowSize = getLookbackWindowSize(selectedLookbackWindow); - const selectedWindow = getFixedLookbackWindow(selectedWindowSize); - - /** - * Determines which field path is highlighted in column stats. Defaults to none. - */ - const [selectedFieldPath, setSelectedFieldPath] = useState(''); - - /** - * Change handlers. - */ - const onChangeSelectedLookbackWindow = (text) => { - const newWindowSize = getLookbackWindowSize(text); - const newTimeWindow = getFixedLookbackWindow(newWindowSize); - getDataProfiles({ - variables: { urn, ...newTimeWindow }, - }); - setSelectedLookbackWindow(text); - }; - - const onChangeSelectedFieldPath = (value) => { - setSelectedFieldPath(value); - }; - - const graphTickInterval = computeChartTickInterval(selectedWindowSize); - const graphDateRange = { - start: selectedWindow.startTime.toString(), - end: selectedWindow.endTime.toString(), - }; - - const profiles = profilesData?.dataset?.datasetProfiles || []; - const allFieldPaths = Array.from(computeAllFieldPaths(profiles)); - - if (selectedFieldPath === '' && allFieldPaths.length > 0) { - // Set initially selected field path. - setSelectedFieldPath(allFieldPaths[0]); - } - - const columnSelectView = ( - - Viewing stats for column - - {allFieldPaths.map((fieldPath) => ( - {fieldPath} - ))} - - - ); - - /** - * Compute Table Stat chart data. - */ - const rowCountChartValues = extractChartValuesFromTableProfiles(profiles, 'rowCount'); - const columnCountChartValues = extractChartValuesFromTableProfiles(profiles, 'columnCount'); - - /** - * Compute Column Stat chart data. - */ - const nullCountChartValues: Array = extractChartValuesFromFieldProfiles( - profiles, - selectedFieldPath, - 'nullCount', - ); - const nullPercentageChartValues: Array = extractChartValuesFromFieldProfiles( - profiles, - selectedFieldPath, - 'nullProportion', - ); - const distinctCountChartValues: Array = extractChartValuesFromFieldProfiles( - profiles, - selectedFieldPath, - 'uniqueCount', - ); - const distinctPercentageChartValues: Array = extractChartValuesFromFieldProfiles( - profiles, - selectedFieldPath, - 'uniqueProportion', - ); - - return ( - <> - {profilesLoading && } - - -
    - Profiling History - - Viewing profiling history for the past - - {LOOKBACK_WINDOWS.map((lookbackWindow) => ( - {lookbackWindow.text} - ))} - - -
    - {toggleView} -
    -
    - - - - - - - - - - - - - - - - - - - - - ); -} diff --git a/datahub-web-react/src/app/entityV2/dataset/profile/stats/historical/charts/ProfilingRunsChart.tsx b/datahub-web-react/src/app/entityV2/dataset/profile/stats/historical/charts/ProfilingRunsChart.tsx deleted file mode 100644 index 4d1cbeeafe4f00..00000000000000 --- a/datahub-web-react/src/app/entityV2/dataset/profile/stats/historical/charts/ProfilingRunsChart.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { Button, Col, Modal, Table, Typography } from 'antd'; -import React, { useState } from 'react'; -import styled from 'styled-components'; - -import DataProfileView from '@app/entityV2/dataset/profile/stats/snapshot/SnapshotStatsView'; - -import { DatasetProfile } from '@types'; - -export const ChartTable = styled(Table)` - margin: 12px; - box-shadow: ${(props) => props.theme.styles['box-shadow']}; -`; - -export type Props = { - profiles: Array; -}; - -export default function ProfilingRunsChart({ profiles }: Props) { - const [showModal, setShowModal] = useState(false); - const [selectedProfileIndex, setSelectedProfileIndex] = useState(-1); - - const showProfileModal = (index: number) => { - setSelectedProfileIndex(index); - setShowModal(true); - }; - - const onClose = () => { - setShowModal(false); - setSelectedProfileIndex(-1); - }; - - const tableData = profiles.map((profile) => { - const profileDate = new Date(profile.timestampMillis); - return { - timestamp: `${profileDate.toLocaleDateString()} at ${profileDate.toLocaleTimeString()}`, - rowCount: profile.rowCount?.toString() || 'unknown', - columnCount: profile.columnCount?.toString() || 'unknown', - }; - }); - - const tableColumns = [ - { - title: 'Recent Profiles', - key: 'Recent Profiles', - dataIndex: 'timestamp', - render: (title, record, index) => { - return ( - - ); - }, - }, - { - title: 'Row Count', - key: 'Row Count', - dataIndex: 'rowCount', - }, - { - title: 'Column Count', - key: 'Column Count', - dataIndex: 'columnCount', - }, - ]; - - const selectedProfile = (selectedProfileIndex >= 0 && profiles[selectedProfileIndex]) || undefined; - const profileModalTitle = - selectedProfile && - `Showing profile from ${new Date(selectedProfile?.timestampMillis).toLocaleDateString()} at ${new Date( - selectedProfile?.timestampMillis, - ).toLocaleTimeString()}`; - - return ( - <> - {selectedProfile && ( - - - - )} -
- - - - ); -} diff --git a/datahub-web-react/src/app/entityV2/dataset/profile/stats/historical/charts/StatChart.tsx b/datahub-web-react/src/app/entityV2/dataset/profile/stats/historical/charts/StatChart.tsx deleted file mode 100644 index 3a8866ad62d651..00000000000000 --- a/datahub-web-react/src/app/entityV2/dataset/profile/stats/historical/charts/StatChart.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { Col, Divider, Typography } from 'antd'; -import React, { useMemo } from 'react'; -import styled from 'styled-components'; - -import { ChartCard } from '@app/analyticsDashboard/components/ChartCard'; -import { ChartContainer } from '@app/analyticsDashboard/components/ChartContainer'; -import { TimeSeriesChart } from '@app/analyticsDashboard/components/TimeSeriesChart'; - -import { DateInterval, DateRange } from '@types'; - -const ChartTitle = styled(Typography.Title)` - && { - margin-bottom: 20px; - text-align: left; - width: 100%; - } -`; - -const ThinDivider = styled(Divider)` - margin: 0px; - padding: 0px; -`; - -type Point = { - timeMs: number; - value: number; -}; - -export type Props = { - title: string; - values: Array; - tickInterval: DateInterval; - dateRange: DateRange; -}; - -/** - * Change these to change the chart axis & line colors - * TODO: Add this to the theme config. - */ -const DEFAULT_LINE_COLOR = '#20d3bd'; -const DEFAULT_AXIS_COLOR = '#D8D8D8'; -const DEFAULT_AXIS_WIDTH = 2; - -/** - * Time Series Chart with a single line. - */ -export default function StatChart({ title, values, tickInterval: interval, dateRange }: Props) { - const timeSeriesData = useMemo( - () => - values - .sort((a, b) => a.timeMs - b.timeMs) - .map((value) => { - const dateStr = new Date(value.timeMs).toISOString(); - return { - x: dateStr, - y: value.value, - }; - }), - [values], - ); - - const chartData = { - title, - lines: [ - { - name: 'line_1', - data: timeSeriesData, - }, - ], - interval, - dateRange, - }; - - return ( - <> - - - - {chartData.title} - - - - - - - ); -} diff --git a/datahub-web-react/src/app/entityV2/dataset/profile/stats/snapshot/LatestStatsView.tsx b/datahub-web-react/src/app/entityV2/dataset/profile/stats/snapshot/LatestStatsView.tsx deleted file mode 100644 index b253ce627fc44f..00000000000000 --- a/datahub-web-react/src/app/entityV2/dataset/profile/stats/snapshot/LatestStatsView.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { Affix, Row, Typography } from 'antd'; -import React, { ReactNode } from 'react'; -import styled from 'styled-components'; - -import DataProfileView from '@app/entityV2/dataset/profile/stats/snapshot/SnapshotStatsView'; - -import { DatasetProfile } from '@types'; - -const HeaderRow = styled(Row)` - padding-top: 24px; - padding-bottom: 28px; - background-color: white; -`; - -export type Props = { - profile: DatasetProfile; - toggleView: ReactNode; -}; - -export default function LatestStatsView({ profile, toggleView }: Props) { - const reportedAtDate = new Date(profile.timestampMillis); - return ( - <> - - -
- Latest Stats - - Reported on {reportedAtDate.toLocaleDateString()} at {reportedAtDate.toLocaleTimeString()} - -
- {toggleView} -
-
- - - ); -} diff --git a/datahub-web-react/src/app/entityV2/dataset/profile/stats/snapshot/SnapshotStatsView.tsx b/datahub-web-react/src/app/entityV2/dataset/profile/stats/snapshot/SnapshotStatsView.tsx index 279f52e12a0ec7..419c391b15efc5 100644 --- a/datahub-web-react/src/app/entityV2/dataset/profile/stats/snapshot/SnapshotStatsView.tsx +++ b/datahub-web-react/src/app/entityV2/dataset/profile/stats/snapshot/SnapshotStatsView.tsx @@ -20,7 +20,7 @@ const decimalToPercentStr = (decimal: number, precision: number): string => { return `${(decimal * 100).toFixed(precision)}%`; }; -export type Props = { +type Props = { profile: DatasetProfile; }; diff --git a/datahub-web-react/src/app/entityV2/dataset/profile/stories/documentation.ts b/datahub-web-react/src/app/entityV2/dataset/profile/stories/documentation.ts deleted file mode 100644 index 345d33faddfec0..00000000000000 --- a/datahub-web-react/src/app/entityV2/dataset/profile/stories/documentation.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { EntityType } from '@types'; - -export const sampleDocs = [ - { - url: 'https://www.google.com', - description: 'This doc spans the internet web', - author: { urn: 'urn:li:corpuser:1', username: '1', type: EntityType.CorpUser }, - created: { - time: 0, - actor: 'urn:li:corpuser:1', - }, - }, -]; diff --git a/datahub-web-react/src/app/entityV2/dataset/profile/stories/lineageEntities.ts b/datahub-web-react/src/app/entityV2/dataset/profile/stories/lineageEntities.ts index 3583ca1a8e2dc0..a44be98c3dc0a6 100644 --- a/datahub-web-react/src/app/entityV2/dataset/profile/stories/lineageEntities.ts +++ b/datahub-web-react/src/app/entityV2/dataset/profile/stories/lineageEntities.ts @@ -1,6 +1,6 @@ import { EntityType, FabricType, PlatformNativeType } from '@types'; -export const sampleUpstreamEntities = [ +const sampleUpstreamEntities = [ { name: 'Upstream HiveDataset', type: EntityType.Dataset, @@ -43,7 +43,7 @@ export const sampleUpstreamEntities = [ }, ]; -export const sampleDownstreamEntities = [ +const sampleDownstreamEntities = [ { name: 'Downstream HiveDataset', type: EntityType.Dataset, diff --git a/datahub-web-react/src/app/entityV2/dataset/profile/stories/sampleSchema.ts b/datahub-web-react/src/app/entityV2/dataset/profile/stories/sampleSchema.ts index 9ce31ac0469f91..41166a5da7c9eb 100644 --- a/datahub-web-react/src/app/entityV2/dataset/profile/stories/sampleSchema.ts +++ b/datahub-web-react/src/app/entityV2/dataset/profile/stories/sampleSchema.ts @@ -3,11 +3,11 @@ import { dataset3 } from '@src/Mocks'; import { EntityType, Schema, SchemaField, SchemaFieldDataType, SchemaMetadata } from '@types'; // Extending the schema type with an option for tags -export type TaggedSchemaField = { +type TaggedSchemaField = { tags: Tag[]; } & SchemaField; -export type Tag = { +type Tag = { name: string; value?: string; color: string; diff --git a/datahub-web-react/src/app/entityV2/dataset/shared/FormattedBytesStat.tsx b/datahub-web-react/src/app/entityV2/dataset/shared/FormattedBytesStat.tsx deleted file mode 100644 index 188fa2b21b18b4..00000000000000 --- a/datahub-web-react/src/app/entityV2/dataset/shared/FormattedBytesStat.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { Tooltip } from '@components'; -import React from 'react'; - -import { formatBytes, formatNumberWithoutAbbreviation } from '@app/shared/formatNumber'; - -export const FormattedBytesStat = ({ bytes }: { bytes: number }) => { - const formattedBytes = formatBytes(bytes); - return ( - - {formattedBytes.number} {formattedBytes.unit} - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/domain/DataProductsTab/DataProductsTab.tsx b/datahub-web-react/src/app/entityV2/domain/DataProductsTab/DataProductsTab.tsx index 1d7bb40c1d988e..36f035a1c45e6d 100644 --- a/datahub-web-react/src/app/entityV2/domain/DataProductsTab/DataProductsTab.tsx +++ b/datahub-web-react/src/app/entityV2/domain/DataProductsTab/DataProductsTab.tsx @@ -5,7 +5,7 @@ import React, { useState } from 'react'; import { useLocation } from 'react-router'; import styled from 'styled-components'; -import { DomainsPaginationContainer } from '@app/domain/DomainsList'; +import { DomainsPaginationContainer } from '@app/domainV2/DomainsList'; import { useEntityContext, useEntityData } from '@app/entity/shared/EntityContext'; import CreateDataProductModal from '@app/entityV2/domain/DataProductsTab/CreateDataProductModal'; import DataProductResult from '@app/entityV2/domain/DataProductsTab/DataProductResult'; diff --git a/datahub-web-react/src/app/entityV2/domain/summary/DocumentationSection.tsx b/datahub-web-react/src/app/entityV2/domain/summary/DocumentationSection.tsx deleted file mode 100644 index 0b9dc3931bf797..00000000000000 --- a/datahub-web-react/src/app/entityV2/domain/summary/DocumentationSection.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import { EditOutlined, ExpandAltOutlined, FileOutlined } from '@ant-design/icons'; -import { Divider, Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { useEntityData, useRefetch, useRouteToTab } from '@app/entity/shared/EntityContext'; -import { AddLinkModal } from '@app/entityV2/shared/components/styled/AddLinkModal'; -import { EmptyTab } from '@app/entityV2/shared/components/styled/EmptyTab'; -import { ANTD_GRAY } from '@app/entityV2/shared/constants'; -import { LinkList } from '@app/entityV2/shared/tabs/Documentation/components/LinkList'; -import { Button, Editor } from '@src/alchemy-components'; - -const Header = styled.div` - display: flex; - align-items: start; - justify-content: space-between; - padding: 16px 4px; -`; - -const Title = styled(Typography.Title)` - && { - color: ${ANTD_GRAY[9]}; - padding: 0px; - margin: 0px; - display: flex; - align-items: center; - } -`; - -const ThinDivider = styled(Divider)` - && { - padding-top: 0px; - padding-bottom: 0px; - margin-top: 0px; - margin-bottom: 20px; - } -`; - -const Documentation = styled.div` - .remirror-editor.ProseMirror { - padding: 0px 8px; - } -`; - -const StyledFileOutlined = styled(FileOutlined)` - && { - font-size: 16px; - margin-right: 8px; - } -`; - -export const DocumentationSection = () => { - // The summary tab consists of modules - const { entityData } = useEntityData(); - const refetch = useRefetch(); - const routeToTab = useRouteToTab(); - - const description = entityData?.editableProperties?.description || entityData?.properties?.description || ''; - const hasDescription = description || description !== ''; - - return ( - <> -
- - <StyledFileOutlined /> - About - - {hasDescription && ( - - )} -
- - - {(hasDescription && ) || ( - - - - - )} - - - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/glossaryNode/useGlossaryChildren.ts b/datahub-web-react/src/app/entityV2/glossaryNode/useGlossaryChildren.ts index 951d369e7d7fe9..fd4af0abbf5e03 100644 --- a/datahub-web-react/src/app/entityV2/glossaryNode/useGlossaryChildren.ts +++ b/datahub-web-react/src/app/entityV2/glossaryNode/useGlossaryChildren.ts @@ -9,7 +9,7 @@ import { ENTITY_NAME_FIELD } from '@src/app/searchV2/context/constants'; import { useGetAutoCompleteMultipleResultsQuery, useScrollAcrossEntitiesQuery } from '@src/graphql/search.generated'; import { Entity, EntityType, SortOrder } from '@src/types.generated'; -export const GLOSSARY_CHILDREN_COUNT = 50; +const GLOSSARY_CHILDREN_COUNT = 50; function getGlossaryChildrenScrollInput(urn: string, scrollId: string | null) { return { diff --git a/datahub-web-react/src/app/entityV2/glossaryTerm/profile/GlossaryRelatedTermsResult.tsx b/datahub-web-react/src/app/entityV2/glossaryTerm/profile/GlossaryRelatedTermsResult.tsx index a86dd1d358bc8a..3932d6f84d547a 100644 --- a/datahub-web-react/src/app/entityV2/glossaryTerm/profile/GlossaryRelatedTermsResult.tsx +++ b/datahub-web-react/src/app/entityV2/glossaryTerm/profile/GlossaryRelatedTermsResult.tsx @@ -19,7 +19,7 @@ export enum RelatedTermTypes { isAChildren = 'Inherited by', } -export type Props = { +type Props = { glossaryRelatedTermType: string; glossaryRelatedTermResult: Array; }; diff --git a/datahub-web-react/src/app/entityV2/glossaryTerm/profile/GlossarySidebarAboutSection.tsx b/datahub-web-react/src/app/entityV2/glossaryTerm/profile/GlossarySidebarAboutSection.tsx deleted file mode 100644 index 7b9653f2bab5fb..00000000000000 --- a/datahub-web-react/src/app/entityV2/glossaryTerm/profile/GlossarySidebarAboutSection.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { useEntityData, useRouteToTab } from '@app/entity/shared/EntityContext'; -import StripMarkdownText from '@app/entityV2/shared/components/styled/StripMarkdownText'; -import { SidebarHeader } from '@app/entityV2/shared/containers/profile/sidebar/SidebarHeader'; - -const DescriptionTypography = styled(Typography.Paragraph)` - max-width: 65ch; -`; - -export default function GlossarySidebarAboutSection() { - const { entityData }: any = useEntityData(); - const description = entityData?.glossaryTermInfo?.definition; - const source = entityData?.glossaryTermInfo?.sourceRef; - const sourceUrl = entityData?.glossaryTermInfo?.sourceUrl; - const routeToTab = useRouteToTab(); - - return ( -
- - {description && ( - - routeToTab({ tabName: 'Documentation' })}> - Read More - - } - > - {description} - - - )} - - - {source && ( - - {sourceUrl ? ( - - {source} - - ) : ( - { - source, - } - )} - - )} -
- ); -} diff --git a/datahub-web-react/src/app/entityV2/glossaryTerm/profile/SchemaView.tsx b/datahub-web-react/src/app/entityV2/glossaryTerm/profile/SchemaView.tsx deleted file mode 100644 index e004c9d1c597a3..00000000000000 --- a/datahub-web-react/src/app/entityV2/glossaryTerm/profile/SchemaView.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { Empty, Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -export type Props = { - rawSchema: string | null; -}; - -const Content = styled.div` - margin-left: 32px; - flex-grow: 1; -`; - -export default function SchemaView({ rawSchema }: Props) { - return ( - <> - {rawSchema && rawSchema.length > 0 ? ( - -
-                        {rawSchema}
-                    
-
- ) : ( - - - - )} - - ); -} diff --git a/datahub-web-react/src/app/entityV2/group/GroupEditModal.tsx b/datahub-web-react/src/app/entityV2/group/GroupEditModal.tsx index 97b47d9b1dca96..b988f1d31b8374 100644 --- a/datahub-web-react/src/app/entityV2/group/GroupEditModal.tsx +++ b/datahub-web-react/src/app/entityV2/group/GroupEditModal.tsx @@ -20,7 +20,7 @@ type Props = { updateName?: (name: string) => void; // TODO: Add name to the update mutation for groups to avoid 2 calls. }; /** Regex Validations */ -export const USER_NAME_REGEX = new RegExp('^[a-zA-Z ]*$'); +const USER_NAME_REGEX = new RegExp('^[a-zA-Z ]*$'); export default function GroupEditModal({ canEditGroupName, diff --git a/datahub-web-react/src/app/entityV2/shared/EntityDropdown/DomainParentSelect.tsx b/datahub-web-react/src/app/entityV2/shared/EntityDropdown/DomainParentSelect.tsx index c467a47102631a..a48acd56080fc5 100644 --- a/datahub-web-react/src/app/entityV2/shared/EntityDropdown/DomainParentSelect.tsx +++ b/datahub-web-react/src/app/entityV2/shared/EntityDropdown/DomainParentSelect.tsx @@ -14,7 +14,7 @@ import { useDomainsContext } from '@src/app/domainV2/DomainsContext'; import { Domain, EntityType } from '@types'; // filter out entity itself and its children -export function filterResultsForMove(entity: Domain, entityUrn: string) { +function filterResultsForMove(entity: Domain, entityUrn: string) { return ( entity.urn !== entityUrn && entity.__typename === 'Domain' && diff --git a/datahub-web-react/src/app/entityV2/shared/EntityDropdown/EntityMenuActions.tsx b/datahub-web-react/src/app/entityV2/shared/EntityDropdown/EntityMenuActions.tsx index b6e868ac8d172c..e2e4c92ac95d21 100644 --- a/datahub-web-react/src/app/entityV2/shared/EntityDropdown/EntityMenuActions.tsx +++ b/datahub-web-react/src/app/entityV2/shared/EntityDropdown/EntityMenuActions.tsx @@ -46,7 +46,7 @@ const MenuItems = styled.div<{ $shouldFillAllAvailableSpace?: boolean }>` const MoreOptionsContainer = styled.div``; -export interface Options { +interface Options { hideDeleteMessage?: boolean; skipDeleteWait?: boolean; } diff --git a/datahub-web-react/src/app/entityV2/shared/EntityDropdown/index.tsx b/datahub-web-react/src/app/entityV2/shared/EntityDropdown/index.tsx deleted file mode 100644 index c048ca17aa97b0..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/EntityDropdown/index.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import EntityMenuActions from '@app/entityV2/shared/EntityDropdown/EntityMenuActions'; - -export default EntityMenuActions; diff --git a/datahub-web-react/src/app/entityV2/shared/EntityDropdown/useDeleteGlossaryEntity.tsx b/datahub-web-react/src/app/entityV2/shared/EntityDropdown/useDeleteGlossaryEntity.tsx deleted file mode 100644 index 8edca65fe0250f..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/EntityDropdown/useDeleteGlossaryEntity.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { Modal, message } from 'antd'; -import { useState } from 'react'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useDeleteGlossaryEntityMutation } from '@graphql/glossary.generated'; - -function useDeleteGlossaryEntity() { - const [hasBeenDeleted, setHasBeenDeleted] = useState(false); - const { entityData, urn: entityDataUrn, entityType } = useEntityData(); - const entityRegistry = useEntityRegistry(); - - const [deleteGlossaryEntity] = useDeleteGlossaryEntityMutation(); - - function handleDeleteGlossaryEntity() { - deleteGlossaryEntity({ - variables: { - urn: entityDataUrn, - }, - fetchPolicy: 'cache-first', - }) - .catch((e) => { - message.destroy(); - message.error({ content: `Failed to delete: \n ${e.message || ''}`, duration: 3 }); - }) - .finally(() => { - message.loading({ - content: 'Deleting...', - duration: 2, - }); - setHasBeenDeleted(true); - message.success({ - content: `Deleted ${entityRegistry.getEntityName(entityType)}!`, - duration: 2, - }); - }); - } - - function onDeleteEntity() { - Modal.confirm({ - title: `Delete ${entityRegistry.getDisplayName(entityType, entityData)}`, - content: `Are you sure you want to remove this ${entityRegistry.getEntityName(entityType)}?`, - onOk() { - handleDeleteGlossaryEntity(); - }, - onCancel() {}, - okText: 'Yes', - maskClosable: true, - closable: true, - }); - } - - return { onDeleteEntity, hasBeenDeleted }; -} - -export default useDeleteGlossaryEntity; diff --git a/datahub-web-react/src/app/entityV2/shared/EntityGroups.tsx b/datahub-web-react/src/app/entityV2/shared/EntityGroups.tsx deleted file mode 100644 index 944d7c498ab6dd..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/EntityGroups.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { Tag } from 'antd'; -import React from 'react'; -import { Link } from 'react-router-dom'; - -import { EmptyValue, GroupsSeeMoreText, Tags, TagsSection } from '@app/entityV2/shared/SidebarStyledComponents'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { EntityRelationship, EntityType } from '@types'; - -type Props = { - readMore: boolean; - setReadMore: (readMore: boolean) => void; - groupMemberRelationships: Array; -}; - -/** - * EntityGroups- to display the groups category in sidebar section - */ -export default function EntityGroups({ readMore, setReadMore, groupMemberRelationships }: Props) { - const entityRegistry = useEntityRegistry(); - - return ( - - {groupMemberRelationships?.length === 0 && } - {!readMore && - groupMemberRelationships?.slice(0, 2).map((item) => { - if (!item?.entity?.urn) return null; - const entityUrn = entityRegistry.getEntityUrl(EntityType.CorpGroup, item?.entity?.urn); - return ( - - - {entityRegistry.getDisplayName(EntityType.CorpGroup, item.entity)} - - - ); - })} - {readMore && - groupMemberRelationships?.length > 2 && - groupMemberRelationships?.map((item) => { - if (!item?.entity?.urn) return null; - const entityUrn = entityRegistry.getEntityUrl(EntityType.CorpGroup, item.entity.urn); - return ( - - - {entityRegistry.getDisplayName(EntityType.CorpGroup, item.entity)} - - - ); - })} - {!readMore && groupMemberRelationships?.length > 2 && ( - setReadMore(!readMore)}> - {`+${groupMemberRelationships?.length - 2} more`} - - )} - - ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/EntitySearchInput/EntitySearchInput.tsx b/datahub-web-react/src/app/entityV2/shared/EntitySearchInput/EntitySearchInput.tsx deleted file mode 100644 index 4451d8d2a35449..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/EntitySearchInput/EntitySearchInput.tsx +++ /dev/null @@ -1,181 +0,0 @@ -import { Tooltip } from '@components'; -import { Select, Tag } from 'antd'; -import React, { useEffect, useState } from 'react'; - -import EntitySearchInputResultV2 from '@app/entityV2/shared/EntitySearchInput/EntitySearchInputResultV2'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useGetEntitiesLazyQuery } from '@graphql/entity.generated'; -import { useGetSearchResultsForMultipleLazyQuery } from '@graphql/search.generated'; -import { Entity, EntityType } from '@types'; - -type Props = { - selectedUrns: string[]; - entityTypes: EntityType[]; - placeholder?: string; - mode?: 'multiple' | 'single'; - style?: any; - tagStyle?: React.CSSProperties; - optionStyle?: React.CSSProperties; - onChangeSelectedUrns: (newUrns: string[]) => void; -}; - -const addToCache = (cache: Map, entity: Entity) => { - cache.set(entity.urn, entity); - return cache; -}; - -const buildCache = (entities: Entity[]) => { - const cache = new Map(); - entities.forEach((entity) => cache.set(entity.urn, entity)); - return cache; -}; - -const isResolutionRequired = (urns: string[], cache: Map) => { - const uncachedUrns = urns.filter((urn) => !cache.has(urn)); - return uncachedUrns.length > 0; -}; - -/** - * This component allows you to search and select entities. It will handle everything, including - * resolving the entities to their display name when required. - * - * TODO: Ideally an initial entity cache could be injected into the component when it's created. - */ -export const EntitySearchInput = ({ - selectedUrns, - entityTypes, - placeholder, - style, - tagStyle, - optionStyle, - mode, - onChangeSelectedUrns, -}: Props) => { - const entityRegistry = useEntityRegistry(); - const [entityCache, setEntityCache] = useState>(new Map()); - - /** - * Bootstrap by resolving all URNs that are not in the cache yet. - */ - const [getEntities, { data: resolvedEntitiesData }] = useGetEntitiesLazyQuery(); - useEffect(() => { - if (isResolutionRequired(selectedUrns, entityCache)) { - // Resolve urns to their full entities - getEntities({ variables: { urns: selectedUrns } }); - } - }, [selectedUrns, entityCache, getEntities]); - - /** - * If some entities need to be resolved, simply build the cache from them. - * This should only happen once at component bootstrap. Typically - * all URNs will be missing from the cache. - */ - useEffect(() => { - if (resolvedEntitiesData && resolvedEntitiesData.entities?.length) { - const entities: Entity[] = (resolvedEntitiesData?.entities as Entity[]) || []; - setEntityCache(buildCache(entities)); - } - }, [resolvedEntitiesData]); - - /** - * Response to user typing with search. - */ - const [searchResources, { data: resourcesSearchData }] = useGetSearchResultsForMultipleLazyQuery(); - const searchResults = resourcesSearchData?.searchAcrossEntities?.searchResults || []; - const searchResultEntities = searchResults.map((result) => result.entity) as Entity[]; - const urnToSearchResultEntity = new Map(); - searchResults.forEach((result) => { - urnToSearchResultEntity[result.entity.urn] = { - urn: result.entity.urn, - type: result.entity.type, - displayName: entityRegistry.getDisplayName(result.entity.type, result.entity), - }; - }); - - const onSelect = (newUrn) => { - const newEntity = searchResultEntities.find((entity) => entity.urn === newUrn); - if (newEntity) { - setEntityCache(addToCache(entityCache, newEntity)); - if (mode === 'single') { - onChangeSelectedUrns([newUrn]); - } else { - const newUrns = [...selectedUrns, newUrn]; - onChangeSelectedUrns(newUrns); - } - } - }; - - const onDeselect = (urn) => { - if (mode === 'single') { - onChangeSelectedUrns([]); - } else { - onChangeSelectedUrns(selectedUrns.filter((u) => u !== urn)); - } - }; - - const onSearch = (text: string) => { - searchResources({ - variables: { - input: { - types: entityTypes, - query: text, - start: 0, - count: 10, - }, - }, - }); - }; - - /** - * Issue a star search on component mount to provide a default set of results. - */ - useEffect(() => { - searchResources({ - variables: { - input: { - types: entityTypes, - query: '*', - start: 0, - count: 10, - }, - }, - }); - }, [entityTypes, searchResources]); - - return ( - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/EntitySearchInput/EntitySearchInputResult.tsx b/datahub-web-react/src/app/entityV2/shared/EntitySearchInput/EntitySearchInputResult.tsx deleted file mode 100644 index d95864cded9a23..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/EntitySearchInput/EntitySearchInputResult.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import { IconStyleType } from '@app/entityV2/Entity'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -type Props = { - entity: any; -}; - -const Container = styled.div` - display: flex; - justify-content: left; - align-items: center; - padding: 12px; -`; - -const IconContainer = styled.div` - margin-right: 8px; -`; - -export const EntitySearchInputResult = ({ entity }: Props) => { - const entityRegistry = useEntityRegistry(); - return ( - - {entityRegistry.getIcon(entity.type, 12, IconStyleType.ACCENT)} - {entityRegistry.getDisplayName(entity.type, entity)} - - ); -}; - -export default EntitySearchInputResult; diff --git a/datahub-web-react/src/app/entityV2/shared/EntitySearchSelect/EntitySearchSelect.tsx b/datahub-web-react/src/app/entityV2/shared/EntitySearchSelect/EntitySearchSelect.tsx deleted file mode 100644 index 4c1a798bbae973..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/EntitySearchSelect/EntitySearchSelect.tsx +++ /dev/null @@ -1,342 +0,0 @@ -import { LoadingOutlined } from '@ant-design/icons'; -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import styled from 'styled-components'; - -import Dropdown from '@components/components/Dropdown/Dropdown'; -import { Input } from '@components/components/Input/Input'; -import { - Container, - DropdownContainer, - LabelContainer, - OptionContainer, - OptionLabel, - OptionList, - SelectBase, - SelectLabel, - SelectLabelContainer, - StyledCheckbox, - StyledIcon, -} from '@components/components/Select/components'; -import SelectActionButtons from '@components/components/Select/private/SelectActionButtons'; -import SelectLabelRenderer from '@components/components/Select/private/SelectLabelRenderer/SelectLabelRenderer'; -import useSelectDropdown from '@components/components/Select/private/hooks/useSelectDropdown'; -import { SelectOption, SelectSizeOptions } from '@components/components/Select/types'; - -import EntitySearchInputResultV2 from '@app/entityV2/shared/EntitySearchInput/EntitySearchInputResultV2'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useGetEntitiesLazyQuery } from '@graphql/entity.generated'; -import { useGetSearchResultsForMultipleLazyQuery } from '@graphql/search.generated'; -import { Entity, EntityType } from '@types'; - -const EmptyState = styled.div` - padding: 16px 12px; - text-align: center; - color: #8c8c8c; - font-style: italic; -`; - -const LoadingState = styled.div` - padding: 16px 12px; - text-align: center; - color: #8c8c8c; - display: flex; - align-items: center; - justify-content: center; - gap: 8px; -`; - -const SearchInputContainer = styled.div` - padding: 8px 12px; - border-bottom: 1px solid #f0f0f0; -`; - -const EntityOptionContainer = styled.div` - width: 100%; -`; - -export interface EntitySearchSelectProps { - selectedUrns?: string[]; - entityTypes: EntityType[]; - placeholder?: string; - size?: SelectSizeOptions; - isMultiSelect?: boolean; - isDisabled?: boolean; - isReadOnly?: boolean; - label?: string; - width?: number | 'full' | 'fit-content'; - onUpdate?: (selectedUrns: string[]) => void; - showClear?: boolean; - isRequired?: boolean; - icon?: any; -} - -interface EntityOption extends SelectOption { - entity: Entity; -} - -const addToCache = (cache: Map, entity: Entity) => { - cache.set(entity.urn, entity); - return cache; -}; - -const buildCache = (entities: Entity[]) => { - const cache = new Map(); - entities.forEach((entity) => cache.set(entity.urn, entity)); - return cache; -}; - -const isResolutionRequired = (urns: string[], cache: Map) => { - const uncachedUrns = urns.filter((urn) => !cache.has(urn)); - return uncachedUrns.length > 0; -}; - -/** - * A standardized entity search and selection component that allows users to search - * for DataHub entities and select one or multiple entities. Built on top of the - * Select component library infrastructure for consistency. - */ -export const EntitySearchSelect: React.FC = ({ - selectedUrns = [], - entityTypes, - placeholder = 'Search for entities...', - size = 'md', - isMultiSelect = false, - isDisabled = false, - isReadOnly = false, - label, - width = 255, - onUpdate, - showClear = true, - isRequired = false, - icon, -}) => { - const entityRegistry = useEntityRegistry(); - const [entityCache, setEntityCache] = useState>(new Map()); - const [searchQuery, setSearchQuery] = useState(''); - const selectRef = useRef(null); - const dropdownRef = useRef(null); - - const { - isOpen, - isVisible, - close: closeDropdown, - toggle: toggleDropdown, - } = useSelectDropdown(false, selectRef, dropdownRef); - - /** - * Bootstrap by resolving all URNs that are not in the cache yet. - */ - const [getEntities, { data: resolvedEntitiesData, loading: entitiesLoading }] = useGetEntitiesLazyQuery(); - useEffect(() => { - if (isResolutionRequired(selectedUrns, entityCache)) { - getEntities({ variables: { urns: selectedUrns } }); - } - }, [selectedUrns, entityCache, getEntities]); - - /** - * Build cache from resolved entities - */ - useEffect(() => { - if (resolvedEntitiesData && resolvedEntitiesData.entities?.length) { - const entities: Entity[] = (resolvedEntitiesData?.entities as Entity[]) || []; - setEntityCache(buildCache(entities)); - } - }, [resolvedEntitiesData]); - - /** - * Search functionality - */ - const [searchResources, { data: resourcesSearchData, loading: searchLoading }] = - useGetSearchResultsForMultipleLazyQuery(); - - const entityOptions: EntityOption[] = useMemo(() => { - const results = resourcesSearchData?.searchAcrossEntities?.searchResults || []; - return results.map((result) => ({ - label: entityRegistry.getDisplayName(result.entity.type, result.entity), - value: result.entity.urn, - entity: result.entity as Entity, - })); - }, [resourcesSearchData, entityRegistry]); - - const handleSelectClick = useCallback(() => { - if (!isDisabled && !isReadOnly) { - toggleDropdown(); - } - }, [toggleDropdown, isDisabled, isReadOnly]); - - const handleOptionClick = useCallback( - (option: EntityOption) => { - // Add entity to cache - setEntityCache(addToCache(entityCache, option.entity)); - - let newUrns: string[]; - if (isMultiSelect) { - newUrns = selectedUrns.includes(option.value) - ? selectedUrns.filter((urn) => urn !== option.value) - : [...selectedUrns, option.value]; - } else { - newUrns = [option.value]; - closeDropdown(); - } - - onUpdate?.(newUrns); - }, - [selectedUrns, isMultiSelect, onUpdate, closeDropdown, entityCache], - ); - - const handleSearchChange = useCallback( - (value: string) => { - setSearchQuery(value); - searchResources({ - variables: { - input: { - types: entityTypes, - query: value || '*', - start: 0, - count: 10, - }, - }, - }); - }, - [entityTypes, searchResources], - ); - - const handleClearSelection = useCallback(() => { - onUpdate?.([]); - }, [onUpdate]); - - const removeOption = useCallback( - (option: SelectOption) => { - const newUrns = selectedUrns.filter((urn) => urn !== option.value); - onUpdate?.(newUrns); - }, - [selectedUrns, onUpdate], - ); - - /** - * Issue a default search on component mount - */ - useEffect(() => { - searchResources({ - variables: { - input: { - types: entityTypes, - query: '*', - start: 0, - count: 10, - }, - }, - }); - }, [entityTypes, searchResources]); - - // Create options for selected values from cache - const selectedOptions: SelectOption[] = useMemo(() => { - return selectedUrns.map((urn) => { - const entity = entityCache.get(urn); - return { - label: entity ? entityRegistry.getDisplayName(entity.type, entity) : urn, - value: urn, - }; - }); - }, [selectedUrns, entityCache, entityRegistry]); - - const isLoading = entitiesLoading || searchLoading; - - return ( - - {label && {label}} - {isVisible && ( - ( - - - { - const newValue = typeof value === 'function' ? value(searchQuery) : value; - handleSearchChange(newValue); - }} - placeholder="Search..." - icon={{ icon: 'Search' }} - data-testid="entity-search-select-input" - /> - - - {isLoading && ( - - - - )} - {!isLoading && entityOptions.length === 0 && No entities found} - {!isLoading && - entityOptions.map((option) => ( - !isMultiSelect && handleOptionClick(option)} - isSelected={selectedUrns.includes(option.value)} - isMultiSelect={isMultiSelect} - data-testid={`entity-search-option-${option.entity.urn.split(':').pop()}`} - > - {isMultiSelect ? ( - - - - - handleOptionClick(option)} - checked={selectedUrns.includes(option.value)} - /> - - ) : ( - - - - )} - - ))} - - - )} - > - - - {icon && } - - - 0} - isOpen={isOpen} - isDisabled={!!isDisabled} - isReadOnly={!!isReadOnly} - handleClearSelection={handleClearSelection} - fontSize={size} - showClear={!!showClear} - /> - - - )} - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/GlossaryEntityContext.tsx b/datahub-web-react/src/app/entityV2/shared/GlossaryEntityContext.tsx index 27a7e18b9f1acb..8b1c123bb5cb8e 100644 --- a/datahub-web-react/src/app/entityV2/shared/GlossaryEntityContext.tsx +++ b/datahub-web-react/src/app/entityV2/shared/GlossaryEntityContext.tsx @@ -3,7 +3,7 @@ import React, { useContext } from 'react'; import { GenericEntityProperties } from '@app/entity/shared/types'; import { Entity } from '@src/types.generated'; -export interface GlossaryEntityContextType { +interface GlossaryEntityContextType { isInGlossaryContext: boolean; entityData: GenericEntityProperties | null; setEntityData: (entityData: GenericEntityProperties | null) => void; diff --git a/datahub-web-react/src/app/entityV2/shared/SidebarStyledComponents.tsx b/datahub-web-react/src/app/entityV2/shared/SidebarStyledComponents.tsx index d0fbdaaf4578cb..d20ef404ce8d37 100644 --- a/datahub-web-react/src/app/entityV2/shared/SidebarStyledComponents.tsx +++ b/datahub-web-react/src/app/entityV2/shared/SidebarStyledComponents.tsx @@ -33,7 +33,7 @@ export const SideBar = styled.div` } `; -export const SideBarSubSection = styled.div` +const SideBarSubSection = styled.div` height: calc(100vh - 135px); overflow: auto; padding-right: 18px; @@ -105,7 +105,7 @@ export const RoleName = styled.div` } `; -export const Team = styled.div` +const Team = styled.div` font-size: 12px; line-height: 20px; color: #8c8c8c; @@ -130,7 +130,7 @@ export const SocialDetails = styled.div` } `; -export const EditButton = styled.div` +const EditButton = styled.div` bottom: 24px; position: absolute; right: 27px; @@ -187,17 +187,17 @@ export const TagsSection = styled.div` align-self: start; `; -export const NoDataFound = styled.span` +const NoDataFound = styled.span` font-size: 12px; color: #262626; font-weight: 100; `; -export const Tags = styled.div` +const Tags = styled.div` margin-top: 5px; `; -export const GroupsSeeMoreText = styled.span` +const GroupsSeeMoreText = styled.span` font-weight: 500; font-size: 12px; line-height: 20px; @@ -205,7 +205,7 @@ export const GroupsSeeMoreText = styled.span` cursor: pointer; `; -export const DisplayCount = styled.span` +const DisplayCount = styled.span` font-family: Mulish; font-style: normal; font-weight: 500; @@ -214,11 +214,11 @@ export const DisplayCount = styled.span` color: #8c8c8c; `; -export const GroupSectionTitle = styled.span` +const GroupSectionTitle = styled.span` margin-right: 8px; `; -export const GroupSectionHeader = styled.div` +const GroupSectionHeader = styled.div` padding-bottom: 12px; `; @@ -343,7 +343,7 @@ export const DraftsOutlinedIconStyle = styled(DraftsOutlinedIcon)` font-size: 12px !important; `; -export const SubscriptionContainer = styled(Row)` +const SubscriptionContainer = styled(Row)` display: flex; gap: 0.5rem; `; @@ -353,7 +353,7 @@ export const OwnershipContainer = styled(Row)` gap: 0.5rem; `; -export const DisplayNameText = styled.span` +const DisplayNameText = styled.span` color: ${ANTD_GRAY_V2[12]}; font-family: Mulish; font-size: 12px; diff --git a/datahub-web-react/src/app/entityV2/shared/components/legacy/Properties.tsx b/datahub-web-react/src/app/entityV2/shared/components/legacy/Properties.tsx index 075c458e0a49c9..78e37c2de082af 100644 --- a/datahub-web-react/src/app/entityV2/shared/components/legacy/Properties.tsx +++ b/datahub-web-react/src/app/entityV2/shared/components/legacy/Properties.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { StringMapEntry } from '@types'; -export type Props = { +type Props = { properties: StringMapEntry[]; }; diff --git a/datahub-web-react/src/app/entityV2/shared/components/styled/DemoButton.tsx b/datahub-web-react/src/app/entityV2/shared/components/styled/DemoButton.tsx deleted file mode 100644 index 63a9ff061dc782..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/components/styled/DemoButton.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { Button } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -const StyledButton = styled(Button)` - padding: 8px; - font-size: 14px; - margin-left: 18px; -`; - -export default function DemoButton() { - return ( - - Schedule a Demo - - ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/components/styled/ExpandedOwner/OwnerContent.tsx b/datahub-web-react/src/app/entityV2/shared/components/styled/ExpandedOwner/OwnerContent.tsx deleted file mode 100644 index da921695060bcc..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/components/styled/ExpandedOwner/OwnerContent.tsx +++ /dev/null @@ -1,148 +0,0 @@ -import { Popover } from '@components'; -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components/macro'; - -import { REDESIGN_COLORS } from '@app/entityV2/shared/constants'; -import { - getDescriptionFromType, - getNameFromType, -} from '@app/entityV2/shared/containers/profile/sidebar/Ownership/ownershipUtils'; -import { CustomAvatar } from '@app/shared/avatar'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { Owner } from '@types'; - -const TextWrapper = styled.span<{ fontSize?: number }>` - ${(props) => props.fontSize && `font-size: ${props.fontSize}px;`} - color: ${REDESIGN_COLORS.DARK_GREY}; - - max-width: 150px; - text-overflow: ellipsis; - overflow: hidden; -`; - -const ContentWrapper = styled.span` - display: flex; - align-items: center; - gap: 4px; - - max-width: inherit; -`; - -const AvatarWrapper = styled.div` - min-width: 24px; -`; - -const OwnerPopoverTitleContainer = styled.div` - display: flex; - flex-direction: row; - align-items: center; - justify-content: flex-start; - gap: 6px; -`; - -const OwnerEntityTypeText = styled(Typography.Text)` - font-family: 'Mulish', sans-serif; - font-weight: 500; - font-size: 14px; - line-height: 19px; -`; - -const OwnerPopoverContentContainer = styled.div` - display: flex; - flex-direction: column; - align-items: flex-start; - - text-overflow: ellipsis; - overflow: hidden; -`; - -const OwnerNameText = styled(Typography.Text)` - font-family: 'Mulish', sans-serif; - font-weight: 700; - font-size: 12px; - line-height: 16px; - margin-bottom: 4px; -`; - -const OwnershipTypeText = styled(Typography.Text)` - font-family: 'Mulish', sans-serif; - font-weight: 700; - font-size: 10px; - line-height: 14px; -`; - -const OwnwershipTypeDescriptionText = styled(Typography.Text)` - font-family: 'Mulish', sans-serif; - font-weight: 500; - font-size: 10px; - line-height: 14px; -`; - -interface Props { - name: string; - owner: Owner; - hidePopOver?: boolean; - pictureLink?: string; - fontSize?: number; -} - -export default function OwnerContent({ name, owner, hidePopOver, pictureLink, fontSize }: Props) { - const entityRegistry = useEntityRegistry(); - const ownerEntity = owner.owner; - const ownerEntityType = owner.owner.type; - const ownerEntityTypeDisplayName = entityRegistry.getEntityName(ownerEntityType); - const ownerDisplayName = entityRegistry.getDisplayName(ownerEntityType, ownerEntity); - let ownershipTypeName; - let ownershipTypeDescription; - if (owner.ownershipType && owner.ownershipType.info) { - ownershipTypeName = owner.ownershipType.info.name; - ownershipTypeDescription = owner.ownershipType.info.description; - } else if (owner.type) { - ownershipTypeName = getNameFromType(owner.type); - ownershipTypeDescription = getDescriptionFromType(owner.type); - } - - const avatar: React.ReactNode = ( - - ); - - /* TODO: We probably do not want render if ownership type has been soft deleted */ - - return ( - - {avatar} - {hidePopOver ? ( - {name} - ) : ( - - {avatar} - {ownerEntityTypeDisplayName} - - } - content={ - - {ownerDisplayName} - {ownershipTypeName} - {ownershipTypeDescription} - - } - > - {name} - - )} - - ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/components/styled/MarkAsDeprecatedButton.tsx b/datahub-web-react/src/app/entityV2/shared/components/styled/MarkAsDeprecatedButton.tsx index c350c682fb8f0c..dffe2816037177 100644 --- a/datahub-web-react/src/app/entityV2/shared/components/styled/MarkAsDeprecatedButton.tsx +++ b/datahub-web-react/src/app/entityV2/shared/components/styled/MarkAsDeprecatedButton.tsx @@ -35,7 +35,7 @@ type MarkAsDeprecatedButtonContentsProps = { internalText?: string; }; -export const MarkAsDeprecatedButtonContents = ({ internalText }: MarkAsDeprecatedButtonContentsProps) => { +const MarkAsDeprecatedButtonContents = ({ internalText }: MarkAsDeprecatedButtonContentsProps) => { return ( diff --git a/datahub-web-react/src/app/entityV2/shared/components/styled/SeeMore.tsx b/datahub-web-react/src/app/entityV2/shared/components/styled/SeeMore.tsx deleted file mode 100644 index fa7b726c63d18b..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/components/styled/SeeMore.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { Button } from 'antd'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entityV2/shared/constants'; - -export const SeeMore = styled(Button)` - margin-top: -20px; - background-color: ${ANTD_GRAY[4]}; - padding: 8px; - border: none; - line-height: 8px; - height: 20px; -`; diff --git a/datahub-web-react/src/app/entityV2/shared/components/styled/StripMarkdownText.tsx b/datahub-web-react/src/app/entityV2/shared/components/styled/StripMarkdownText.tsx index 370e1c547786a0..b7ffc7f564940e 100644 --- a/datahub-web-react/src/app/entityV2/shared/components/styled/StripMarkdownText.tsx +++ b/datahub-web-react/src/app/entityV2/shared/components/styled/StripMarkdownText.tsx @@ -10,7 +10,7 @@ const RemoveMarkdownContainer = styled.div<{ shouldWrap: boolean }>` text-overflow: ellipsis; `; -export type Props = { +type Props = { children: string | undefined | null; readMore?: JSX.Element; suffix?: JSX.Element; diff --git a/datahub-web-react/src/app/entityV2/shared/components/styled/StyledButton.tsx b/datahub-web-react/src/app/entityV2/shared/components/styled/StyledButton.tsx deleted file mode 100644 index b3e744a5aac728..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/components/styled/StyledButton.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { Button } from 'antd'; -import styled from 'styled-components'; - -export default styled(Button)` - padding-top: 5px; - padding-bottom: 5px; - padding-right: 16px; - padding-left: 16px; - box-shadow: 0px 0px 4px 0px #0000001a; - border: 1px solid #d9d9d9; - - font-size: 12px; - font-weight: 500; - line-height: 20px; - vertical-align: top; - border-radius: 5px; -`; diff --git a/datahub-web-react/src/app/entityV2/shared/components/styled/StyledMDEditor.tsx b/datahub-web-react/src/app/entityV2/shared/components/styled/StyledMDEditor.tsx deleted file mode 100644 index d0453ec8539420..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/components/styled/StyledMDEditor.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import MDEditor from '@uiw/react-md-editor'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entityV2/shared/constants'; - -export default styled(MDEditor)` - height: calc(100% - 46px) !important; - z-index: 0; - box-shadow: none; - border-radius: 0; - font-weight: 400; - .w-md-editor-toolbar { - border-color: ${ANTD_GRAY[4]}; - background: white; - padding: 0 20px; - height: 46px !important; - li { - button { - height: 100%; - margin: 0 5px; - } - svg { - width: 16px; - height: 16px; - } - &.active > button { - color: ${(props) => props.theme.styles['primary-color']}; - background-color: ${ANTD_GRAY[3]}; - } - } - } - .w-md-editor-preview { - box-shadow: inset 1px 0 0 0 ${ANTD_GRAY[4]}; - } - .w-md-editor-content { - height: calc(100% - 46px) !important; - } -`; diff --git a/datahub-web-react/src/app/entityV2/shared/components/styled/StyledTable.tsx b/datahub-web-react/src/app/entityV2/shared/components/styled/StyledTable.tsx index 5ea962bcdd5e72..175f0fc9c7e6d6 100644 --- a/datahub-web-react/src/app/entityV2/shared/components/styled/StyledTable.tsx +++ b/datahub-web-react/src/app/entityV2/shared/components/styled/StyledTable.tsx @@ -39,7 +39,7 @@ export const StyledTable = styled(Table)` ` as typeof Table; // this above line preserves the Table component's generic-ness -export const CompactStyledTable = styled(Table)` +const CompactStyledTable = styled(Table)` overflow: inherit; height: inherit; diff --git a/datahub-web-react/src/app/entityV2/shared/components/styled/search/EmbeddedListSearch.tsx b/datahub-web-react/src/app/entityV2/shared/components/styled/search/EmbeddedListSearch.tsx index f032a56ba4d2a0..884361245eb87f 100644 --- a/datahub-web-react/src/app/entityV2/shared/components/styled/search/EmbeddedListSearch.tsx +++ b/datahub-web-react/src/app/entityV2/shared/components/styled/search/EmbeddedListSearch.tsx @@ -61,7 +61,7 @@ function useWrappedSearchResults(params: GetSearchResultsParams) { } // the addFixedQuery checks and generate the query as per params pass to embeddedListSearch -export const addFixedQuery = (baseQuery: string, fixedQuery: string, emptyQuery: string) => { +const addFixedQuery = (baseQuery: string, fixedQuery: string, emptyQuery: string) => { let finalQuery = ``; if (baseQuery && fixedQuery) { finalQuery = baseQuery.includes(fixedQuery) ? `${baseQuery}` : `(*${baseQuery}*) AND (${fixedQuery})`; @@ -77,7 +77,7 @@ export const addFixedQuery = (baseQuery: string, fixedQuery: string, emptyQuery: // Simply remove the fields that were marked as fixed from the facets that the server // responds. -export const removeFixedFiltersFromFacets = (fixedFilters: FilterSet, facets: FacetMetadata[]) => { +const removeFixedFiltersFromFacets = (fixedFilters: FilterSet, facets: FacetMetadata[]) => { const fixedFields = fixedFilters.filters.map((filter) => filter.field); return facets.filter((facet) => !fixedFields.includes(facet.field)); }; diff --git a/datahub-web-react/src/app/entityV2/shared/components/styled/search/EntitySearchResults.tsx b/datahub-web-react/src/app/entityV2/shared/components/styled/search/EntitySearchResults.tsx index bc584d910ff94f..c7171de6bc5101 100644 --- a/datahub-web-react/src/app/entityV2/shared/components/styled/search/EntitySearchResults.tsx +++ b/datahub-web-react/src/app/entityV2/shared/components/styled/search/EntitySearchResults.tsx @@ -11,7 +11,7 @@ import { useEntityRegistry } from '@app/useEntityRegistry'; import { Entity, EntityPath, EntityType, SearchResult } from '@types'; -export const StyledList = styled(List)` +const StyledList = styled(List)` height: 100%; flex: 1; overflow: auto; @@ -37,7 +37,7 @@ const StyledCheckbox = styled(Checkbox)` margin-right: 12px; `; -export const ListItem = styled.div<{ isSelectMode: boolean; areMatchesExpanded; compactUserSearchCardStyle: boolean }>` +const ListItem = styled.div<{ isSelectMode: boolean; areMatchesExpanded; compactUserSearchCardStyle: boolean }>` padding: 20px; display: flex; align-items: center; diff --git a/datahub-web-react/src/app/entityV2/shared/components/styled/search/action/ActionDropdown.tsx b/datahub-web-react/src/app/entityV2/shared/components/styled/search/action/ActionDropdown.tsx index 5b826f8059d132..53651109c316f9 100644 --- a/datahub-web-react/src/app/entityV2/shared/components/styled/search/action/ActionDropdown.tsx +++ b/datahub-web-react/src/app/entityV2/shared/components/styled/search/action/ActionDropdown.tsx @@ -37,7 +37,7 @@ const DropdownWrapper = styled.div<{ margin-right: 12px; `; -export type Action = { +type Action = { title: React.ReactNode; onClick: () => void; }; diff --git a/datahub-web-react/src/app/entityV2/shared/components/subtypes.tsx b/datahub-web-react/src/app/entityV2/shared/components/subtypes.tsx index 461bb3e5cc1282..d21c767e0f2170 100644 --- a/datahub-web-react/src/app/entityV2/shared/components/subtypes.tsx +++ b/datahub-web-react/src/app/entityV2/shared/components/subtypes.tsx @@ -18,12 +18,10 @@ export enum SubType { Dataset = 'Dataset', Project = 'Project', View = 'View', - Table = 'Table', TableauWorksheet = 'Worksheet', TableauWorkbook = 'Workbook', TableauPublishedDataSource = 'Published Data Source', TableauEmbeddedDataSource = 'Embedded Data Source', - LookerExplore = 'Explore', Looker = 'Look', DbtSource = 'Source', VertexAIPipelineTask = 'Pipeline Task', diff --git a/datahub-web-react/src/app/entityV2/shared/constants.ts b/datahub-web-react/src/app/entityV2/shared/constants.ts index 64c13cfd0eeb8a..a35f617f6423f5 100644 --- a/datahub-web-react/src/app/entityV2/shared/constants.ts +++ b/datahub-web-react/src/app/entityV2/shared/constants.ts @@ -198,9 +198,9 @@ export const EMPTY_MESSAGES = { }, }; -export const ELASTIC_MAX_COUNT = 10000; +const ELASTIC_MAX_COUNT = 10000; -export const getElasticCappedTotalValueText = (count: number) => { +const getElasticCappedTotalValueText = (count: number) => { if (count === ELASTIC_MAX_COUNT) { return `${ELASTIC_MAX_COUNT}+`; } @@ -217,7 +217,7 @@ export const ENTITY_TYPES_WITH_MANUAL_LINEAGE = new Set([ export const GLOSSARY_ENTITY_TYPES = [EntityType.GlossaryTerm, EntityType.GlossaryNode]; -export const DEFAULT_SYSTEM_ACTOR_URNS = ['urn:li:corpuser:__datahub_system', 'urn:li:corpuser:unknown']; +const DEFAULT_SYSTEM_ACTOR_URNS = ['urn:li:corpuser:__datahub_system', 'urn:li:corpuser:unknown']; export const VIEW_ENTITY_PAGE = 'VIEW_ENTITY_PAGE'; @@ -233,7 +233,7 @@ export const EDITING_DOCUMENTATION_URL_PARAM = 'editing'; export const UNKNOWN_DATA_PLATFORM = 'urn:li:dataPlatform:unknown'; -export const SMART_ASSERTION_STALE_IN_DAYS = 3; +const SMART_ASSERTION_STALE_IN_DAYS = 3; export const TITLE_CASE_EXCEPTION_WORDS = ['of', 'the', 'in', 'on', 'and', 'a', 'an', 'to', 'for', 'at', 'by']; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/DefaultEntityHeader.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/header/DefaultEntityHeader.tsx index 9315026f119107..e27dd94ff40f6f 100644 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/DefaultEntityHeader.tsx +++ b/datahub-web-react/src/app/entityV2/shared/containers/profile/header/DefaultEntityHeader.tsx @@ -23,7 +23,7 @@ import { useEntityRegistry } from '@app/useEntityRegistry'; import { DataPlatform, DisplayProperties, Domain, EntityType, Post } from '@types'; -export const TitleWrapper = styled.div` +const TitleWrapper = styled.div` max-width: 100%; display: flex; @@ -55,7 +55,7 @@ const TitleRow = styled(HeaderRow)` font-size: 16px; `; -export const Row = styled.div` +const Row = styled.div` padding: 18px; display: flex; flex-direction: row; @@ -65,7 +65,7 @@ export const Row = styled.div` overflow: hidden; `; -export const LeftColumn = styled.div` +const LeftColumn = styled.div` min-width: 0; display: flex; @@ -73,7 +73,7 @@ export const LeftColumn = styled.div` align-items: center; `; -export const RightColumn = styled.div` +const RightColumn = styled.div` flex-shrink: 0; display: flex; flex-direction: column; @@ -83,7 +83,7 @@ export const RightColumn = styled.div` padding-left: 8px; `; -export const TopButtonsWrapper = styled.div` +const TopButtonsWrapper = styled.div` display: flex; justify-content: flex-end; gap: 8px; @@ -95,7 +95,7 @@ const HeaderIconsWrapper = styled.span` margin-right: 8px; `; -export type Props = { +type Props = { urn: string; entityType: EntityType; entityUrl: string; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/EntityCount.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/header/EntityCount.tsx index 451cbf05926ad7..a394be680181a0 100644 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/EntityCount.tsx +++ b/datahub-web-react/src/app/entityV2/shared/containers/profile/header/EntityCount.tsx @@ -4,7 +4,7 @@ import styled from 'styled-components'; import { ANTD_GRAY } from '@app/entityV2/shared/constants'; -export const EntityCountText = styled(Typography.Text)` +const EntityCountText = styled(Typography.Text)` display: inline-block; font-size: 12px; line-height: 20px; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/EntityHealthPopover.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/header/EntityHealthPopover.tsx deleted file mode 100644 index a3020322626596..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/EntityHealthPopover.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { Popover } from '@components'; -import { Divider } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entityV2/shared/constants'; -import { EntityHealthStatus } from '@app/entityV2/shared/containers/profile/header/EntityHealthStatus'; -import { HealthSummaryIconType, getHealthSummaryIcon, getHealthSummaryMessage } from '@app/shared/health/healthUtils'; - -import { Health } from '@types'; - -const Header = styled.span` - display: flex; - align-items: center; - justify-content: left; -`; - -const Icon = styled.span` - margin-right: 8px; - display: flex; - align-items: center; -`; - -const Title = styled.span` - font-weight: bold; - color: ${ANTD_GRAY[1]}; - padding-top: 4px; - padding-bottom: 4px; - font-size: 14px; -`; - -const StatusContainer = styled.div` - margin-bottom: 8px; -`; - -const StyledDivider = styled(Divider)` - &&& { - margin: 0px; - padding: 0px; - padding-right: 8px; - padding-left: 8px; - margin-top: 8px; - margin-bottom: 8px; - border-color: ${ANTD_GRAY[5]}; - } -`; - -type Props = { - health: Health[]; - baseUrl: string; - children: React.ReactNode; - fontSize?: number; - placement?: any; -}; - -export const EntityHealthPopover = ({ health, baseUrl, children, fontSize, placement = 'right' }: Props) => { - return ( - -
- {getHealthSummaryIcon(health, HealthSummaryIconType.OUTLINED, fontSize)}{' '} - {getHealthSummaryMessage(health)} -
- - {health.map((h) => ( - - - - ))} - - } - color="#262626" - placement={placement} - zIndex={10000000} - > - {children} -
- ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/EntityHealthStatus.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/header/EntityHealthStatus.tsx deleted file mode 100644 index 8c500caba4405b..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/EntityHealthStatus.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import React from 'react'; -import { Link } from 'react-router-dom'; -import styled from 'styled-components'; - -import { ANTD_GRAY, REDESIGN_COLORS } from '@app/entityV2/shared/constants'; -import { getHealthRedirectPath, getHealthTypeName } from '@app/shared/health/healthUtils'; - -import { HealthStatusType } from '@types'; - -const StatusContainer = styled.div` - display: flex; - justify-content: left; - align-items: center; - color: ${ANTD_GRAY[1]}; - font-size: 14px; -`; - -const Title = styled.span` - display: flex; - align-items: center; - font-weight: bold; - margin-right: 8px; - width: 72px; -`; - -const RedirectLink = styled(Link)` - margin-left: 4px; - color: ${REDESIGN_COLORS.BLUE}; -`; - -type Props = { - type: HealthStatusType; - message?: string | undefined; - baseUrl: string; -}; - -export const EntityHealthStatus = ({ type, message, baseUrl }: Props) => { - const title = getHealthTypeName(type); - const redirectPath = getHealthRedirectPath(type); - const fullPath = `${baseUrl}/${redirectPath}`; - return ( - - {title} {message} - {redirectPath && ( - - details - - )} - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/EntityPlatformLoadingSection.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/header/EntityPlatformLoadingSection.tsx deleted file mode 100644 index 8a8aae53be1ebb..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/EntityPlatformLoadingSection.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Skeleton, Space } from 'antd'; -import * as React from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entityV2/shared/constants'; - -const ContextSkeleton = styled(Skeleton.Input)` - && { - width: 320px; - border-radius: 4px; - background-color: ${ANTD_GRAY[3]}; - } -`; - -export default function EntityPlatformLoadingSection() { - return ( - - - - ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/GlossaryPreviewCardDecoration.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/header/GlossaryPreviewCardDecoration.tsx index 5340458a0160bc..463f7309bfb696 100644 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/GlossaryPreviewCardDecoration.tsx +++ b/datahub-web-react/src/app/entityV2/shared/containers/profile/header/GlossaryPreviewCardDecoration.tsx @@ -16,7 +16,7 @@ interface GlossaryItemRibbonProps { color: string; } -export const GLOSSARY_RIBBON_SIZE = 8; +const GLOSSARY_RIBBON_SIZE = 8; const GlossaryItemRibbon = styled.span` position: absolute; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/PlatformContent/ParentNodesView.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/header/PlatformContent/ParentNodesView.tsx index 404c235fd520e7..e006f0d85a8c52 100644 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/PlatformContent/ParentNodesView.tsx +++ b/datahub-web-react/src/app/entityV2/shared/containers/profile/header/PlatformContent/ParentNodesView.tsx @@ -10,7 +10,7 @@ import { useEntityRegistry } from '@app/useEntityRegistry'; import { EntityType, GlossaryNode } from '@types'; -export const StyledRightOutlined = styled(RightOutlined)` +const StyledRightOutlined = styled(RightOutlined)` color: ${ANTD_GRAY[7]}; font-size: 8px; margin: 0 4px; @@ -59,7 +59,7 @@ interface Props { parentNodes?: GlossaryNode[] | null; } -export default function ParentNodesView({ parentNodes }: Props) { +function ParentNodesView({ parentNodes }: Props) { const entityRegistry = useEntityRegistry(); const { contentRef, isContentTruncated } = useContentTruncation(parentNodes); diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/PlatformContent/ParentNodesViewForSearchRedesign.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/header/PlatformContent/ParentNodesViewForSearchRedesign.tsx deleted file mode 100644 index 56b0414b6e3907..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/PlatformContent/ParentNodesViewForSearchRedesign.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import { FolderOutlined, RightOutlined } from '@ant-design/icons'; -import { Tooltip } from '@components'; -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entityV2/shared/constants'; -import useContentTruncation from '@app/shared/useContentTruncation'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { EntityType, GlossaryNode } from '@types'; - -export const StyledRightOutlined = styled(RightOutlined)` - color: ${ANTD_GRAY[7]}; - font-size: 8px; - margin: 0 4px; -`; - -// must display content in reverse to have ellipses at the beginning of content -export const ParentNodesWrapper = styled.div` - align-items: center; - white-space: nowrap; - text-overflow: ellipsis; - flex-direction: row-reverse; - display: flex; -`; - -export const Ellipsis = styled.span` - color: ${ANTD_GRAY[7]}; - margin-right: 2px; -`; - -export const StyledTooltip = styled(Tooltip)` - display: flex; - white-space: nowrap; - overflow: hidden; -`; - -const GlossaryNodeText = styled(Typography.Text)<{ color: string }>` - color: #56668e; - - font-family: Mulish; - font-size: 10px; - font-style: normal; - font-weight: 500; - line-height: normal; -`; - -const GlossaryNodeIcon = styled(FolderOutlined)<{ color: string }>` - color: ${(props) => props.color}; - - &&& { - font-size: 12px; - margin-right: 4px; - } -`; - -interface Props { - parentNodes?: GlossaryNode[] | null; -} - -export default function ParentNodesView({ parentNodes }: Props) { - const entityRegistry = useEntityRegistry(); - const { contentRef, isContentTruncated } = useContentTruncation(parentNodes); - - return ( - - {[...(parentNodes || [])]?.reverse()?.map((parentNode, idx) => ( - <> - - - {entityRegistry.getDisplayName(EntityType.GlossaryNode, parentNode)} - - {idx + 1 !== parentNodes?.length && } - - ))} - - } - overlayStyle={isContentTruncated ? {} : { display: 'none' }} - > - {isContentTruncated && ...} - - {[...(parentNodes || [])]?.map((parentNode, idx) => ( - <> - hihihihi - - {entityRegistry.getDisplayName(EntityType.GlossaryNode, parentNode)} - - - {idx + 1 !== parentNodes?.length && } - - ))} - - - ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/PlatformContent/PlatformContentContainer.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/header/PlatformContent/PlatformContentContainer.tsx deleted file mode 100644 index e0aaab988113f9..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/PlatformContent/PlatformContentContainer.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import React from 'react'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { IconStyleType } from '@app/entityV2/Entity'; -import ContainerIcon from '@app/entityV2/shared/containers/profile/header/PlatformContent/ContainerIcon'; -import PlatformContentView from '@app/entityV2/shared/containers/profile/header/PlatformContent/PlatformContentView'; -import { getDisplayedEntityType } from '@app/entityV2/shared/containers/profile/header/utils'; -import { getPlatformNameFromEntityData } from '@app/entityV2/shared/utils'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; -import useContentTruncation from '@app/shared/useContentTruncation'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { Container, EntityType } from '@types'; - -function PlatformContentContainer() { - const { entityType, entityData } = useEntityData(); - const entityRegistry = useEntityRegistry(); - const platformName = getPlatformNameFromEntityData(entityData); - const platformLogoUrl = entityData?.platform?.properties?.logoUrl; - const entityLogoComponent = entityRegistry.getIcon(entityType, 12, IconStyleType.ACCENT); - const typeIcon = - entityType === EntityType.Container ? ( - - ) : ( - entityRegistry.getIcon(entityType, 12, IconStyleType.ACCENT) - ); - const displayedEntityType = getDisplayedEntityType(entityData, entityRegistry, entityType); - const instanceId = entityData?.dataPlatformInstance?.instanceId; - - const { contentRef, isContentTruncated } = useContentTruncation(entityData); - - return ( - platform.properties?.displayName || capitalizeFirstLetterOnly(platform.name), - )} - platformLogoUrls={entityData?.siblingPlatforms?.map((platform) => platform.properties?.logoUrl)} - entityLogoComponent={entityLogoComponent} - instanceId={instanceId} - typeIcon={typeIcon} - entityType={displayedEntityType} - parentContainers={entityData?.parentContainers?.containers} - parentContainersRef={contentRef} - areContainersTruncated={isContentTruncated} - parentEntities={entityData?.parentDomains?.domains} - /> - ); -} - -export default PlatformContentContainer; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/PlatformContent/constants.ts b/datahub-web-react/src/app/entityV2/shared/containers/profile/header/PlatformContent/constants.ts deleted file mode 100644 index e69de29bb2d1d6..00000000000000 diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/PlatformContent/index.ts b/datahub-web-react/src/app/entityV2/shared/containers/profile/header/PlatformContent/index.ts deleted file mode 100644 index c55502225183f0..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/PlatformContent/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import PlatformContentContainer from '@app/entityV2/shared/containers/profile/header/PlatformContent/PlatformContentContainer'; - -export default PlatformContentContainer; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/StructuredPropertyBadge.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/header/StructuredPropertyBadge.tsx index a35a15b4d0c0d2..6dc65c393df01d 100644 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/header/StructuredPropertyBadge.tsx +++ b/datahub-web-react/src/app/entityV2/shared/containers/profile/header/StructuredPropertyBadge.tsx @@ -9,7 +9,7 @@ import { getStructuredPropertyValue } from '@src/app/entity/shared/utils'; import { getDisplayName } from '@src/app/govern/structuredProperties/utils'; import { StructuredProperties } from '@src/types.generated'; -export const MAX_PROP_BADGE_WIDTH = 150; +const MAX_PROP_BADGE_WIDTH = 150; const StyledTooltip = styled(Tooltip)` .ant-tooltip-inner { diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/AboutSection/EmptyContentSection.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/AboutSection/EmptyContentSection.tsx deleted file mode 100644 index 97d8cf479fbdeb..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/AboutSection/EmptyContentSection.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { PlusOutlined } from '@ant-design/icons'; -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { useRouteToTab } from '@app/entity/shared/EntityContext'; -import { EMPTY_MESSAGES } from '@app/entityV2/shared/constants'; - -const EmptyContentWrapper = styled.div` - font-size: 12px; - display: flex; - justify-content: start; - align-items: start; -`; - -const EmptyContentMessage = styled(Typography.Text)` - font-size: 12px; -`; - -const AddButton = styled.div` - margin: 0px; - padding: 0px; - margin-left: 12px; - :hover { - cursor: pointer; - } -`; - -interface Props { - readOnly?: boolean; -} - -export default function EmptyContentSection({ readOnly }: Props) { - const routeToTab = useRouteToTab(); - - return ( - - {EMPTY_MESSAGES.documentation.title} - {!readOnly && ( - routeToTab({ tabName: 'Documentation', tabParams: { editing: true } })}> - Add docs - - )} - - ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection.tsx index 95123fadf20ceb..2fc97e70b7f55f 100644 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection.tsx +++ b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection.tsx @@ -116,4 +116,3 @@ export const SidebarAboutSection = ({ properties, readOnly }: Props) => { ); }; -export default SidebarAboutSection; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Chart/Header/utils.ts b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Chart/Header/utils.ts deleted file mode 100644 index bb00fa32517c50..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Chart/Header/utils.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { ChartProperties } from '@types'; - -// This util is used for Charts and Dashboards who get last updated differently than others -export function getLastUpdatedMs( - properties: Pick | null | undefined, -): number | undefined { - return properties?.lastRefreshed || properties?.lastModified?.time || undefined; -} diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Container/ContainerSelectModal.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Container/ContainerSelectModal.tsx deleted file mode 100644 index 15af098bb9b767..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Container/ContainerSelectModal.tsx +++ /dev/null @@ -1,192 +0,0 @@ -import { Tooltip } from '@components'; -import { Button, Form, Modal, Select, Tag } from 'antd'; -import React, { ReactNode, useRef, useState } from 'react'; -import styled from 'styled-components/macro'; - -import { useEnterKeyListener } from '@app/shared/useEnterKeyListener'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useGetSearchResultsLazyQuery } from '@graphql/search.generated'; -import { Container, Entity, EntityType } from '@types'; - -type Props = { - onCloseModal: () => void; - defaultValues?: { urn: string; entity?: Entity | null }[]; - onOkOverride?: (result: string[]) => void; - titleOverride?: string; -}; - -type SelectedContainer = { - entity?: Entity | null; - urn: string; -}; - -const StyleTag = styled(Tag)` - padding: 0px 7px; - margin-right: 3px; - display: flex; - justify-content: start; - align-items: center; -`; - -const PreviewImage = styled.img` - max-height: 18px; - width: auto; - object-fit: contain; - background-color: transparent; - margin-right: 4px; -`; - -export const ContainerSelectModal = ({ onCloseModal, defaultValues, onOkOverride, titleOverride }: Props) => { - const [containerSearch, { data: platforSearchData }] = useGetSearchResultsLazyQuery(); - const entityRegistry = useEntityRegistry(); - - const containerSearchResults = - platforSearchData?.search?.searchResults?.map((searchResult) => searchResult.entity) || []; - - const [selectedContainers, setSelectedContainers] = useState(defaultValues || []); - - const inputEl = useRef(null); - - const onModalClose = () => { - onCloseModal(); - }; - - const handleSearch = (text: string) => { - containerSearch({ - variables: { - input: { - type: EntityType.Container, - query: text, - start: 0, - count: 5, - }, - }, - }); - }; - - // Renders a search result in the select dropdown. - const renderSearchResult = (entity: Container) => { - const displayName = entityRegistry.getDisplayName(EntityType.Container, entity); - - const truncatedDisplayName = displayName.length > 25 ? `${displayName.slice(0, 25)}...` : displayName; - return ( - - - {truncatedDisplayName} - - ); - }; - - const containerSearchOptions = containerSearchResults?.map((result) => { - return ( - - {renderSearchResult(result as Container)} - - ); - }); - - const onSelectContainer = (newValue: { value: string; label: ReactNode }) => { - const newUrn = newValue.value; - - if (inputEl && inputEl.current) { - (inputEl.current as any).blur(); - } - - const filteredContainer = containerSearchResults?.find((entity) => entity.urn === newUrn); - - if (filteredContainer) { - const container = filteredContainer as Container; - setSelectedContainers([ - ...(selectedContainers || []), - { - entity: container, - urn: newUrn, - }, - ]); - } - }; - - const onDeselectContainer = (val) => { - setSelectedContainers(selectedContainers?.filter((container) => container.urn !== val.value)); - }; - - const onOk = () => { - if (!selectedContainers) { - return; - } - - if (onOkOverride) { - onOkOverride(selectedContainers?.map((container) => container.urn)); - } - }; - - // Handle the Enter press - useEnterKeyListener({ - querySelectorToExecuteClick: '#setContainerButton', - }); - - const tagRender = (props) => { - // eslint-disable-next-line react/prop-types - const { label, closable, onClose } = props; - const onPreventMouseDown = (event) => { - event.preventDefault(); - event.stopPropagation(); - }; - return ( - - {label} - - ); - }; - - return ( - - - - - } - > -
- - - - -
- ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Container/utils.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Container/utils.tsx index 29b11988eb8dd2..c2d81693b11668 100644 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Container/utils.tsx +++ b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Container/utils.tsx @@ -13,13 +13,13 @@ const SummaryText = styled.span` color: ${ANTD_GRAY[7]}; `; -export type ContentTypeSummary = { +type ContentTypeSummary = { type: string; count: number; isEntityType: boolean; // If false, this represents a sub-type. }; -export type ContentsSummary = { +type ContentsSummary = { total: number; types: ContentTypeSummary[]; }; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Domain/SidebarDataProductsSection.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Domain/SidebarDataProductsSection.tsx deleted file mode 100644 index 43bf91432b4f29..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Domain/SidebarDataProductsSection.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import React from 'react'; -import { useHistory } from 'react-router'; -import styled from 'styled-components/macro'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { REDESIGN_COLORS } from '@app/entityV2/shared/constants'; -import { navigateToDomainDataProducts } from '@app/entityV2/shared/containers/profile/sidebar/Domain/utils'; -import EmptySectionText from '@app/entityV2/shared/containers/profile/sidebar/EmptySectionText'; -import { SidebarSection } from '@app/entityV2/shared/containers/profile/sidebar/SidebarSection'; -import { pluralize } from '@app/shared/textUtil'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -const Section = styled.div` - display: flex; - align-items: start; - justify-content: start; - flex-wrap: wrap; - text-wrap: wrap; -`; - -const SummaryText = styled.div``; - -const ViewAllButton = styled.div` - display: flex; - align-items: center; - font-weight: bold; - padding: 0px 2px; - margin-left: 8px; - color: ${REDESIGN_COLORS.DARK_GREY}; - :hover { - cursor: pointer; - } -`; - -const SidebarDataProductsSection = () => { - const { urn, entityType, entityData } = useEntityData(); - const entityRegistry = useEntityRegistry(); - const history = useHistory(); - - const domain = entityData as any; - const productsCount = domain?.dataProducts?.total || 0; - const hasProducts = productsCount > 0; - - if (!hasProducts) { - return null; - } - - return ( - - {(hasProducts && ( - <> -
- - {productsCount} - {pluralize(productsCount, 'data product')} - - - navigateToDomainDataProducts(urn, entityType, history, entityRegistry) - } - > - View all - -
- - )) || } - - } - /> - ); -}; - -export default SidebarDataProductsSection; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Domain/utils.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Domain/utils.tsx index 8f1fea31cca888..f58d557de2c939 100644 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Domain/utils.tsx +++ b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Domain/utils.tsx @@ -15,13 +15,13 @@ const SummaryText = styled.span` color: ${ANTD_GRAY[7]}; `; -export type ContentTypeSummary = { +type ContentTypeSummary = { entityType: EntityType; type?: string; count: number; }; -export type ContentsSummary = { +type ContentsSummary = { total: number; types: ContentTypeSummary[]; }; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/EntityInfo/EntityInfo.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/EntityInfo/EntityInfo.tsx deleted file mode 100644 index a4dbce6eb9471b..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/EntityInfo/EntityInfo.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import Link from 'antd/lib/typography/Link'; -import React from 'react'; -import styled from 'styled-components'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { DatasetStatsSummarySubHeader } from '@app/entityV2/dataset/profile/stats/stats/DatasetStatsSummarySubHeader'; -import PlatformContent from '@app/entityV2/shared/containers/profile/header/PlatformContent'; -import FormInfo from '@app/entityV2/shared/containers/profile/sidebar/FormInfo/FormInfo'; -import { StyledDivider } from '@app/entityV2/shared/containers/profile/sidebar/FormInfo/components'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import LinkOut from '@images/link-out.svg?react'; - -const EntityName = styled.div` - font-size: 16px; - font-weight: 700; - line-height: 24px; - margin-bottom: 8px; -`; - -const EntityInfoWrapper = styled.div` - padding-top: 20px; -`; - -const StyledLink = styled(Link)` - font-size: 14px; - line-height: 18px; - display: inline-flex; - align-items: center; - - svg { - height: 14px; - width: 14px; - } -`; - -const FormInfoWrapper = styled.div` - margin-top: 12px; -`; - -interface Props { - formUrn: string; -} - -export default function EntityInfo({ formUrn }: Props) { - const entityRegistry = useEntityRegistry(); - const { entityType, entityData } = useEntityData(); - const entityName = entityData ? entityRegistry.getDisplayName(entityType, entityData) : ''; - - return ( - - - {entityName} - - View Profile - - - - - - - - ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/EntityProfileSidebarSearchHeader.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/EntityProfileSidebarSearchHeader.tsx deleted file mode 100644 index 52b07a9b40c7c0..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/EntityProfileSidebarSearchHeader.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { Button } from 'antd'; -import React, { useContext } from 'react'; -import styled from 'styled-components'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import EntitySidebarContext from '@app/sharedV2/EntitySidebarContext'; -import { useEntityRegistry } from '@app/useEntityRegistry'; -import { useCustomTheme } from '@src/customThemeContext'; - -import SidebarBackArrow from '@images/sidebarBackArrow.svg?react'; - -const Container = styled.div` - display: flex; - flex-direction: horizontal; - justify-content: space-between; - padding-left: 20px; - padding-right: 20px; - padding-top: 12px; - padding-bottom: 4px; - align-items: center; -`; - -const StyledSidebarBackArrow = styled(SidebarBackArrow)` - cursor: pointer; -`; - -type Props = { - showViewDetails?: boolean; -}; - -export default function EntityProfileSidebarSearchHeader({ showViewDetails = true }: Props) { - const { theme } = useCustomTheme(); - const entitySidebarContext = useContext(EntitySidebarContext); - const entityRegistry = useEntityRegistry(); - const { urn, entityType } = useEntityData(); - - return ( - - { - entitySidebarContext.setSidebarClosed(true); - }} - /> - {showViewDetails && ( - - )} - - ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/EntitySidebarSectionsTab.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/EntitySidebarSectionsTab.tsx index f6e11ce9cdf569..8c7f6d7f7947f8 100644 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/EntitySidebarSectionsTab.tsx +++ b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/EntitySidebarSectionsTab.tsx @@ -22,7 +22,7 @@ interface Props { renderType: TabRenderType; } -export const contextsWithoutLastSynchronized = [ +const contextsWithoutLastSynchronized = [ TabContextType.CHROME_SIDEBAR, TabContextType.SEARCH_SIDEBAR, TabContextType.LINEAGE_SIDEBAR, diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/FormInfo/components.ts b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/FormInfo/components.ts index 7985c2ac5d9f45..40ff0328cc82c6 100644 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/FormInfo/components.ts +++ b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/FormInfo/components.ts @@ -9,13 +9,13 @@ export const FlexWrapper = styled.div` line-height: 18px; `; -export const StyledIcon = styled(Icon)<{ addLineHeight?: boolean }>` +const StyledIcon = styled(Icon)<{ addLineHeight?: boolean }>` font-size: 18px; margin-right: 8px; ${(props) => props.addLineHeight && `line-height: 24px;`} `; -export const SubTitle = styled.div<{ addMargin?: boolean }>` +const SubTitle = styled.div<{ addMargin?: boolean }>` font-weight: 600; margin-bottom: 4px; ${(props) => props.addMargin && `margin-top: 8px;`} @@ -29,7 +29,7 @@ export const Title = styled.div` align-items: center; `; -export const StyledDivider = styled(Divider)` +const StyledDivider = styled(Divider)` margin: 12px 0 0 0; `; @@ -42,7 +42,7 @@ export const StyledReadOutlined = styled(ReadOutlined)<{ color?: string; addLine ${(props) => props.color && `color: ${props.color};`} `; -export const StyledReadFilled = styled(ReadFilled)<{ color: string; addLineHeight?: boolean }>` +const StyledReadFilled = styled(ReadFilled)<{ color: string; addLineHeight?: boolean }>` margin-right: 8px; height: 18px; width: 18px; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/HeaderAndTabs.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/HeaderAndTabs.tsx deleted file mode 100644 index e1fa4129c2df1e..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/HeaderAndTabs.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import React, { useCallback, useState } from 'react'; -import styled from 'styled-components'; - -let isResizing = false; - -export type Props = { - children: React.ReactNode; -}; - -const ResizableDiv = styled.div<{ width }>` - width: ${(props) => props.width}px; - min-width: 440px; - display: flex; - justify-content: space-between; -`; - -const HeaderAndTabs = ({ children }: Props) => { - const initialWidth = 70 / (100 / document.documentElement.clientWidth); - - const [sidebarWidth, setSidebarWidth] = useState(initialWidth); - - const cbHandleMouseMove = useCallback((e) => { - const offsetRight = e.clientX - document.body.offsetLeft; - - const minWidthVw = 70; - const minWidthPx = minWidthVw / (100 / document.documentElement.clientWidth); - - const maxWidthVw = 98; - const maxWidthPx = maxWidthVw / (100 / document.documentElement.clientWidth); - - if (offsetRight > minWidthPx && offsetRight < maxWidthPx) { - setSidebarWidth(offsetRight); - } - }, []); - - const cbHandleMouseUp = useCallback( - (_) => { - if (!isResizing) { - return; - } - isResizing = false; - document.removeEventListener('mousemove', cbHandleMouseMove); - document.removeEventListener('mouseup', cbHandleMouseUp); - }, - [cbHandleMouseMove], - ); - - function handleMousedown(e) { - e.stopPropagation(); - e.preventDefault(); - // we will only add listeners when needed, and remove them afterward - document.addEventListener('mousemove', cbHandleMouseMove); - document.addEventListener('mouseup', cbHandleMouseUp); - isResizing = true; - } - - return ( - - {children} - {/* eslint-disable jsx-a11y/no-static-element-interactions */} -
- header -
-
- ); -}; - -export default HeaderAndTabs; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/LastIngested.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/LastIngested.tsx index 4301fb0d88046b..11370335297dda 100644 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/LastIngested.tsx +++ b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/LastIngested.tsx @@ -179,4 +179,3 @@ function LastIngested({ lastIngested }: Props) { ); } -export default LastIngested; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Lineage/utils.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Lineage/utils.tsx index f13b0878e0ef5c..0d96dad2772a1b 100644 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Lineage/utils.tsx +++ b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Lineage/utils.tsx @@ -12,13 +12,13 @@ const SummaryText = styled.span` font-weight: bold; `; -export type LineageDirectionTypeSummary = { +type LineageDirectionTypeSummary = { type: string; count: number; isEntityType: boolean; // If false, this represents a sub-type. }; -export type LineageDirectionSummary = { +type LineageDirectionSummary = { total: number; types: LineageDirectionTypeSummary[]; }; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Ownership/LdapFormItem.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Ownership/LdapFormItem.tsx deleted file mode 100644 index c0c1ed4f1653dd..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Ownership/LdapFormItem.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { AutoComplete, Form } from 'antd'; -import { FormInstance } from 'antd/es/form/Form'; -import React, { useState } from 'react'; - -import { useGetAutoCompleteResultsLazyQuery } from '@graphql/search.generated'; -import { EntityType } from '@types'; - -const OWNER_SEARCH_PLACEHOLDER = 'Search an LDAP'; - -type Props = { - form: FormInstance; -}; - -export const LdapFormItem = ({ form }: Props) => { - const [getOwnerAutoCompleteResults, { data: searchOwnerSuggestionsData }] = useGetAutoCompleteResultsLazyQuery(); - const [ownerQuery, setOwnerQuery] = useState(''); - - const onSelectSuggestion = (ldap: string) => { - setOwnerQuery(ldap); - }; - - const onChangeOwnerQuery = async (query: string) => { - const row = await form.validateFields(); - - if (query && query.trim() !== '') { - getOwnerAutoCompleteResults({ - variables: { - input: { - type: row.type, - query, - field: row.type === EntityType.CorpUser ? 'ldap' : 'name', - }, - }, - }); - } - setOwnerQuery(query); - }; - - return ( - - ({ - value: suggestion, - }))) || - [] - } - value={ownerQuery} - onSelect={onSelectSuggestion} - onSearch={onChangeOwnerQuery} - placeholder={OWNER_SEARCH_PLACEHOLDER} - /> - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Ownership/ownershipUtils.ts b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Ownership/ownershipUtils.ts index 77eb6e37cf7e57..b4def9bd9ccaca 100644 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Ownership/ownershipUtils.ts +++ b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Ownership/ownershipUtils.ts @@ -6,7 +6,7 @@ import { OwnershipType, OwnershipTypeEntity } from '@types'; * A mapping from OwnershipType to it's display name & description. In the future, * we intend to make this configurable. */ -export const OWNERSHIP_DISPLAY_TYPES = [ +const OWNERSHIP_DISPLAY_TYPES = [ { type: OwnershipType.TechnicalOwner, name: 'Technical Owner', @@ -38,7 +38,7 @@ export const getNameFromType = (type: OwnershipType) => { return ownershipTypeToDetails.get(type)?.name || type; }; -export const getDescriptionFromType = (type: OwnershipType) => { +const getDescriptionFromType = (type: OwnershipType) => { return ownershipTypeToDetails.get(type)?.description || 'No description'; }; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Platform/SelectPlatformModal.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Platform/SelectPlatformModal.tsx deleted file mode 100644 index f5e2a5241a0504..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Platform/SelectPlatformModal.tsx +++ /dev/null @@ -1,189 +0,0 @@ -import { Tooltip } from '@components'; -import { Button, Form, Modal, Select, Tag } from 'antd'; -import React, { ReactNode, useRef, useState } from 'react'; -import styled from 'styled-components/macro'; - -import { useEnterKeyListener } from '@app/shared/useEnterKeyListener'; - -import { useGetSearchResultsLazyQuery } from '@graphql/search.generated'; -import { DataPlatform, Entity, EntityType } from '@types'; - -type Props = { - onCloseModal: () => void; - defaultValues?: { urn: string; entity?: Entity | null }[]; - onOk?: (result: string[]) => void; - titleOverride?: string; -}; - -type SelectedPlatform = { - entity?: Entity | null; - urn: string; -}; - -const StyleTag = styled(Tag)` - padding: 0px 7px; - margin-right: 3px; - display: flex; - justify-content: start; - align-items: center; -`; - -const PreviewImage = styled.img` - max-height: 18px; - width: auto; - object-fit: contain; - background-color: transparent; - margin-right: 4px; -`; - -export const SelectPlatformModal = ({ onCloseModal, defaultValues, onOk, titleOverride }: Props) => { - const [platformSearch, { data: platforSearchData }] = useGetSearchResultsLazyQuery(); - const platformSearchResults = - platforSearchData?.search?.searchResults?.map((searchResult) => searchResult.entity) || []; - - const [selectedPlatforms, setSelectedPlatforms] = useState(defaultValues); - - const inputEl = useRef(null); - - const onModalClose = () => { - onCloseModal(); - }; - - const handleSearch = (text: string) => { - platformSearch({ - variables: { - input: { - type: EntityType.DataPlatform, - query: text, - start: 0, - count: 5, - }, - }, - }); - }; - - // Renders a search result in the select dropdown. - const renderSearchResult = (entity: DataPlatform) => { - const displayName = entity.properties?.displayName || entity.name; - const truncatedDisplayName = displayName.length > 25 ? `${displayName.slice(0, 25)}...` : displayName; - return ( - - {!!entity.properties?.logoUrl && } - {truncatedDisplayName} - - ); - }; - - const platformSearchOptions = platformSearchResults?.map((result) => { - return ( - - {renderSearchResult(result as DataPlatform)} - - ); - }); - - const onSelectPlatform = (newValue: { value: string; label: ReactNode }) => { - const newUrn = newValue.value; - - if (inputEl && inputEl.current) { - (inputEl.current as any).blur(); - } - - const filteredPlatforms = - platformSearchResults?.filter((entity) => entity.urn === newUrn).map((entity) => entity) || []; - - if (filteredPlatforms.length) { - const platform = filteredPlatforms[0] as DataPlatform; - setSelectedPlatforms([ - ...(selectedPlatforms || []), - { - entity: platform, - urn: newUrn, - }, - ]); - } - }; - - const onDeselectPlatform = (val) => { - setSelectedPlatforms(selectedPlatforms?.filter((platform) => platform.urn !== val.value)); - }; - - const handleOk = () => { - if (!selectedPlatforms) { - return; - } - - if (onOk) { - onOk(selectedPlatforms?.map((platform) => platform.urn)); - } - }; - - // Handle the Enter press - useEnterKeyListener({ - querySelectorToExecuteClick: '#setPlatformButton', - }); - - const tagRender = (props) => { - // eslint-disable-next-line react/prop-types - const { label, closable, onClose } = props; - const onPreventMouseDown = (event) => { - event.preventDefault(); - event.stopPropagation(); - }; - return ( - - {label} - - ); - }; - - return ( - - - - - } - > -
- - - - -
- ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Query/SidebarQueryCreatedAtSection.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Query/SidebarQueryCreatedAtSection.tsx deleted file mode 100644 index 7a691599fc085f..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Query/SidebarQueryCreatedAtSection.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; - -// import styled from 'styled-components/macro'; - -import { useBaseEntity } from '@app/entity/shared/EntityContext'; -import { SidebarSection } from '@app/entityV2/shared/containers/profile/sidebar/SidebarSection'; -import { toRelativeTimeString } from '@app/shared/time/timeUtils'; - -import { QueryEntity } from '@types'; - -export default function SidebarQueryUpdatedAtSection() { - const baseEntity = useBaseEntity<{ entity: QueryEntity }>(); - - return ( - {toRelativeTimeString(baseEntity?.entity?.properties?.created?.time || 0)}} - /> - ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Recommendations/SidebarEntityRecommendations.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Recommendations/SidebarEntityRecommendations.tsx deleted file mode 100644 index 697eaaf7f12a90..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Recommendations/SidebarEntityRecommendations.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import { SidebarHeader } from '@app/entityV2/shared/containers/profile/sidebar/SidebarHeader'; -import { RecommendationModule } from '@app/recommendations/RecommendationModule'; -import { RecommendationDisplayType } from '@app/recommendations/types'; - -import { useListRecommendationsQuery } from '@graphql/recommendations.generated'; -import { EntityType, RecommendationModule as RecommendationModuleType, ScenarioType } from '@types'; - -const RecommendationsContainer = styled.div``; - -const RecommendationContainer = styled.div` - margin-bottom: 20px; -`; - -export const SidebarEntityRecommendations = ({ - userUrn, - entityUrn, - entityType, -}: { - userUrn: string; - entityUrn: string; - entityType: EntityType; -}) => { - const scenario = ScenarioType.EntityProfile; - const { data } = useListRecommendationsQuery({ - variables: { - input: { - userUrn, - requestContext: { - scenario, - entityRequestContext: { - urn: entityUrn, - type: entityType, - }, - }, - limit: 3, - }, - }, - }); - const recommendationModules = data?.listRecommendations?.modules; - return ( - - {recommendationModules && - recommendationModules.map((module) => ( - - - - - ))} - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Recommendations/SidebarRecommendationsSection.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Recommendations/SidebarRecommendationsSection.tsx deleted file mode 100644 index 20b551065817fa..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/Recommendations/SidebarRecommendationsSection.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import { useUserContext } from '@app/context/useUserContext'; -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { SidebarEntityRecommendations } from '@app/entityV2/shared/containers/profile/sidebar/Recommendations/SidebarEntityRecommendations'; - -const RecommendationsContainer = styled.div``; - -export const SidebarRecommendationsSection = () => { - const { urn, entityType } = useEntityData(); - const authenticatedUserUrn = useUserContext()?.user?.urn; - return ( - - {authenticatedUserUrn && ( - - )} - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/SidebarCollapseIcon.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/SidebarCollapseIcon.tsx deleted file mode 100644 index 6a6afa71692fe4..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/SidebarCollapseIcon.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { Tooltip } from '@components'; -import { ArrowLeft, ArrowRight } from '@phosphor-icons/react'; -import React, { useContext } from 'react'; -import styled from 'styled-components'; - -import { REDESIGN_COLORS } from '@app/entityV2/shared/constants'; -import EntitySidebarContext from '@app/sharedV2/EntitySidebarContext'; -import { getColor } from '@src/alchemy-components/theme/utils'; - -const Container = styled.div` - display: flex; - align-items: center; - justify-content: center; - height: 56px; - padding: 8px; -`; - -const IconWrapper = styled.div<{ direction: 'left' | 'right' }>` - display: flex; - align-items: center; - justify-content: center; -`; - -const CloseButton = styled.div<{ $isClosed: boolean }>` - cursor: pointer; - margin: 0px; - padding: 2px 6px; - display: flex; - align-items: center; - height: 40px; - width: 40px; - border-radius: 6px; - justify-content: center; - color: ${(p) => p.theme.styles['primary-color']}; - ${(props) => - props.$isClosed && - ` - background-color: ${getColor('primary', 600, props.theme)}; - color: ${REDESIGN_COLORS.WHITE}; - `} - :hover { - background-color: ${(p) => getColor('primary', 600, p.theme)}; - color: ${REDESIGN_COLORS.WHITE}; - } -`; - -export default function SidebarCollapseIcon() { - const { isClosed, setSidebarClosed } = useContext(EntitySidebarContext); - - return ( - - - setSidebarClosed(!isClosed)} - data-testid="toggleSidebar" - > - - {isClosed ? : } - - - - - ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/SidebarCompactSchemaSection.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/SidebarCompactSchemaSection.tsx deleted file mode 100644 index 2e8e423b3a67d1..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/SidebarCompactSchemaSection.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; - -import { SidebarSection } from '@app/entityV2/shared/containers/profile/sidebar/SidebarSection'; -import { SchemaTab } from '@app/entityV2/shared/tabs/Dataset/Schema/SchemaTab'; -import { TabRenderType } from '@app/entityV2/shared/types'; -import { ENTITY_PROFILE_SCHEMA_ID } from '@app/onboarding/config/EntityProfileOnboardingConfig'; - -export const SidebarCompactSchemaSection = () => { - return ( -
- } /> -
- ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/SidebarLogicSection.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/SidebarLogicSection.tsx index 6a37418238f7b4..31b757aa634f96 100644 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/SidebarLogicSection.tsx +++ b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/SidebarLogicSection.tsx @@ -87,7 +87,7 @@ interface HelperProps { } // exported for testing only -export function SidebarLogicSection({ title, statement, highlightedStrings, externalUrl }: HelperProps) { +function SidebarLogicSection({ title, statement, highlightedStrings, externalUrl }: HelperProps) { const [showFullContentModal, setShowFullContentModal] = useState(false); const isEmbeddedProfile = useIsEmbeddedProfile(); diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/StatusSection.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/StatusSection.tsx index 60d4de0045638c..e6e3bee134500e 100644 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/StatusSection.tsx +++ b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/StatusSection.tsx @@ -20,7 +20,7 @@ const SyncedAssetContainer = styled.div` flex-direction: column; `; -export const StyledCollapse = styled(Collapse)` +const StyledCollapse = styled(Collapse)` text-wrap: wrap; .ant-collapse-header { padding: 0px 0px !important; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/TopUsersFacepile.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/TopUsersFacepile.tsx index a178e2900d1a56..2f507086baceb2 100644 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/TopUsersFacepile.tsx +++ b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/TopUsersFacepile.tsx @@ -8,7 +8,7 @@ import { useEntityRegistry } from '@app/useEntityRegistry'; import { CorpUser, EntityType } from '@types'; -export type Props = { +type Props = { users: Array; max?: number; checkExistence?: boolean; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/popularity/PopularityIcon.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/popularity/PopularityIcon.tsx deleted file mode 100644 index 67653f4b23679c..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/popularity/PopularityIcon.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Group } from '@visx/group'; -import React from 'react'; - -import PopularityIconBar from '@app/entityV2/shared/containers/profile/sidebar/shared/popularity/PopularityIconBar'; -import { PopularityTier } from '@app/entityV2/shared/containers/profile/sidebar/shared/utils'; - -type Props = { - tier: PopularityTier; - width?: number; - height?: number; -}; - -const PopularityIcon = ({ tier, width = 38, height = 32 }: Props) => { - return ( - - - - - - - - ); -}; - -export default PopularityIcon; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/popularity/PopularityIconBar.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/popularity/PopularityIconBar.tsx deleted file mode 100644 index 99eb5fa97ed60f..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/popularity/PopularityIconBar.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { Bar } from '@visx/shape'; -import React from 'react'; - -import { ANTD_GRAY } from '@app/entityV2/shared/constants'; - -const ACTIVE_COLOR = '#3F54D1'; -const INACTIVE_COLOR = ANTD_GRAY[5]; - -type Props = { - index: number; - active: boolean; - opacity: number; -}; - -const PopularityIconBar = ({ index, active, opacity }: Props) => { - return ( - - ); -}; - -export default PopularityIconBar; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/styledComponents.ts b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/styledComponents.ts index 9ac394234db709..1ec02f12352d52 100644 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/styledComponents.ts +++ b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/styledComponents.ts @@ -24,7 +24,7 @@ export const LabelText = styled(Typography.Text)` color: ${REDESIGN_COLORS.BODY_TEXT}; `; -export const InstanceIcon = styled.div` +const InstanceIcon = styled.div` height: 22px; width: 22px; background-color: #c9fff2; @@ -39,7 +39,7 @@ export const InstanceIcon = styled.div` } `; -export const StyledLabel = styled.span` +const StyledLabel = styled.span` font-size: 16px; font-weight: 400; color: ${REDESIGN_COLORS.BODY_TEXT}; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/utils.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/utils.tsx index dcd8d734709584..1c58efef177749 100644 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/utils.tsx +++ b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/shared/utils.tsx @@ -14,7 +14,7 @@ export enum PopularityTier { TIER_4, // Least Popular } -export const ACRYL_PLATFORM = 'DataHub Core'; +const ACRYL_PLATFORM = 'DataHub Core'; export enum ActionType { SHARE, diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/tagRenderer.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/tagRenderer.tsx deleted file mode 100644 index ed8dd44d155bfb..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/sidebar/tagRenderer.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Tag } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -const StyleTag = styled(Tag)` - padding: 0px 7px; - margin-right: 3px; - display: flex; - justify-content: start; - align-items: center; -`; - -export const tagRender = (props) => { - // eslint-disable-next-line react/prop-types - const { label, closable, onClose } = props; - const onPreventMouseDown = (event) => { - event.preventDefault(); - event.stopPropagation(); - }; - return ( - - {label} - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/containers/profile/utils.tsx b/datahub-web-react/src/app/entityV2/shared/containers/profile/utils.tsx index dea4055abe8b18..a8dc24b52da3ee 100644 --- a/datahub-web-react/src/app/entityV2/shared/containers/profile/utils.tsx +++ b/datahub-web-react/src/app/entityV2/shared/containers/profile/utils.tsx @@ -135,7 +135,7 @@ export function getEntityPath( }${tabParamsString}`; } -export function useEntityPath(entityType: EntityType, urn: string, tabName?: string, tabParams?: Record) { +function useEntityPath(entityType: EntityType, urn: string, tabName?: string, tabParams?: Record) { const isLineageMode = useIsLineageMode(); const isHideSiblingMode = useIsSeparateSiblingsMode(); const entityRegistry = useEntityRegistry(); @@ -156,7 +156,7 @@ export function useRoutedTab(tabs: EntityTab[]): EntityTab | undefined { return undefined; } -export function useIsOnTab(tabName: string): boolean { +function useIsOnTab(tabName: string): boolean { const { pathname } = useLocation(); const trimmedPathName = pathname.endsWith('/') ? pathname.slice(0, pathname.length - 1) : pathname; // Match against the regex diff --git a/datahub-web-react/src/app/entityV2/shared/embed/EmbeddedHeader.tsx b/datahub-web-react/src/app/entityV2/shared/embed/EmbeddedHeader.tsx deleted file mode 100644 index b08b798f6d6890..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/embed/EmbeddedHeader.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import { ArrowRightOutlined } from '@ant-design/icons'; -import { Image, Typography } from 'antd'; -import Link from 'antd/lib/typography/Link'; -import React from 'react'; -import styled, { useTheme } from 'styled-components/macro'; - -import { EventType } from '@app/analytics'; -import analytics from '@app/analytics/analytics'; -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { IconStyleType } from '@app/entityV2/Entity'; -import { ANTD_GRAY } from '@app/entityV2/shared/constants'; -import { getDisplayedEntityType } from '@app/entityV2/shared/containers/profile/header/utils'; -import { useAppConfig } from '@app/useAppConfig'; -import { useEntityRegistry } from '@app/useEntityRegistry'; -import { DEFAULT_APP_CONFIG } from '@src/appConfigContext'; - -const HeaderWrapper = styled.div` - display: flex; -`; - -const LogoImage = styled(Image)` - display: inline-block; - height: 40px; - width: auto; -`; - -const EntityContent = styled.div` - margin-left: 16px; - display: flex; - flex-direction: column; - justify-content: space-between; -`; - -const EntityTypeWrapper = styled.div` - font-size: 12px; - color: ${ANTD_GRAY[8]}; -`; - -const TypeIcon = styled.span` - margin-right: 5px; -`; - -const EntityName = styled(Typography.Text)` - font-size: 16px; - font-weight: 700; - line-height: 24px; -`; - -const StyledLink = styled(Link)` - font-size: 10px; - font-weight: 700; - line-height: 22px; - margin-left: 8px; -`; - -const EntityNameWrapper = styled.div` - display: flex; - align-items: baseline; -`; - -export default function EmbeddedHeader() { - const entityRegistry = useEntityRegistry(); - const { entityData, entityType } = useEntityData(); - const appConfig = useAppConfig(); - const themeConfig = useTheme(); - - function trackClickViewInDataHub() { - analytics.event({ - type: EventType.EmbedProfileViewInDataHubEvent, - entityType, - entityUrn: entityData?.urn || '', - }); - } - - const typeIcon = entityRegistry.getIcon(entityType, 12, IconStyleType.ACCENT, ANTD_GRAY[8]); - const displayedEntityType = getDisplayedEntityType(entityData, entityRegistry, entityType); - const entityName = entityRegistry.getDisplayName(entityType, entityData); - const entityTypePathName = entityRegistry.getPathName(entityType); - const logoUrl = - appConfig.config !== DEFAULT_APP_CONFIG - ? appConfig.config.visualConfig.logoUrl || themeConfig.assets.logoUrl - : undefined; - - return ( - - - - - {typeIcon} - {displayedEntityType} - - - - {entityName} - - - view in DataHub - - - - - ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/embed/EmbeddedHealthIcon.tsx b/datahub-web-react/src/app/entityV2/shared/embed/EmbeddedHealthIcon.tsx deleted file mode 100644 index f612a16629d13d..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/embed/EmbeddedHealthIcon.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import { orange } from '@ant-design/colors'; -import { WarningFilled } from '@ant-design/icons'; -import { Tooltip } from '@components'; -import React from 'react'; -import { useParams } from 'react-router'; -import styled from 'styled-components'; - -import { generateQueryVariables } from '@app/entityV2/shared/embed/UpstreamHealth/utils'; -import { decodeUrn } from '@app/entityV2/shared/utils'; -import { useGetDefaultLineageStartTimeMillis } from '@app/lineage/utils/useGetLineageTimeParams'; -import { getEntityTypeFromEntityUrn } from '@app/lineageV3/utils/lineageUtils'; -import { HAS_ACTIVE_INCIDENTS_FILTER_NAME, HAS_FAILING_ASSERTIONS_FILTER_NAME } from '@app/search/utils/constants'; -import { useUrlQueryParam } from '@app/shared/useUrlQueryParam'; -import { useAppConfig } from '@app/useAppConfig'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useSearchAcrossLineageQuery } from '@graphql/search.generated'; - -// Do not update unless you update the reference to this ID in our Chrome extension code -const ICON_ID = 'embedded-datahub-health-icon'; - -// Default size for the warning icon in pixels -const DEFAULT_ICON_SIZE = 16; - -const StyledWarning = styled(WarningFilled)<{ size: number }>` - color: ${orange[5]}; - font-size: ${({ size }) => size}px; -`; - -interface RouteParams { - urn: string; -} - -// Used by our Chrome Extension to show a warning health icon if there are unhealthy upstreams -export default function EmbeddedHealthIcon() { - const entityRegistry = useEntityRegistry(); - const { urn: encodedUrn } = useParams(); - const { value: showTooltipParam } = useUrlQueryParam('show-tooltip', 'false'); - const { value: sizeParam } = useUrlQueryParam('size', DEFAULT_ICON_SIZE.toString()); - const showTooltip = showTooltipParam === 'true'; - const iconSize = parseInt(sizeParam || DEFAULT_ICON_SIZE.toString(), 10); - const urn = decodeUrn(encodedUrn); - const entityType = getEntityTypeFromEntityUrn(urn, entityRegistry); - const [, , entityTypeFallback] = urn.split(':'); - - const appConfig = useAppConfig(); - const lineageEnabled: boolean = appConfig?.config?.chromeExtensionConfig?.lineageEnabled || false; - const startTimeMillis = useGetDefaultLineageStartTimeMillis(); - - const { data: incidentsData } = useSearchAcrossLineageQuery( - generateQueryVariables({ - urn, - startTimeMillis, - filterField: HAS_ACTIVE_INCIDENTS_FILTER_NAME, - start: 0, - includeAssertions: false, - includeIncidents: true, - skip: !lineageEnabled, - count: 0, - }), - ); - - const { data: assertionsData } = useSearchAcrossLineageQuery( - generateQueryVariables({ - urn, - startTimeMillis, - filterField: HAS_FAILING_ASSERTIONS_FILTER_NAME, - start: 0, - includeAssertions: true, - includeIncidents: false, - skip: !lineageEnabled, - count: 0, - }), - ); - - if (incidentsData?.searchAcrossLineage?.total || assertionsData?.searchAcrossLineage?.total) { - const warningIcon = ; - - if (showTooltip) { - const title = - "Some upstream entities are unhealthy, which may impact this entity. Expand the DataHub browser extension's side panel for more details."; - return ( - - - {warningIcon} - - - ); - } - - return warningIcon; - } - - return null; -} diff --git a/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/ActiveIncidents.tsx b/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/ActiveIncidents.tsx deleted file mode 100644 index 191fdae207dbef..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/ActiveIncidents.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { LoadingOutlined } from '@ant-design/icons'; -import React from 'react'; - -import { - FailingDataWrapper, - FailingSectionWrapper, - LoadMoreButton, - LoadingWrapper, -} from '@app/entityV2/shared/embed/UpstreamHealth/FailingAssertions'; -import FailingEntity from '@app/entityV2/shared/embed/UpstreamHealth/FailingEntity'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { Dataset } from '@types'; - -interface Props { - datasetsWithActiveIncidents: Dataset[]; - totalDatasetsWithActiveIncidents: number; - fetchMoreIncidentsData: () => void; - isLoadingIncidents: boolean; -} - -export default function ActiveIncidents({ - datasetsWithActiveIncidents, - totalDatasetsWithActiveIncidents, - fetchMoreIncidentsData, - isLoadingIncidents, -}: Props) { - const entityRegistry = useEntityRegistry(); - - return ( - - {totalDatasetsWithActiveIncidents} data source{totalDatasetsWithActiveIncidents > 1 && 's'} with active - incidents - - {datasetsWithActiveIncidents.map((dataset) => { - const numActiveIncidents = (dataset as any).activeIncidents.total; - - return ( - 1 ? 's' : ''}`} - /> - ); - })} - {totalDatasetsWithActiveIncidents > datasetsWithActiveIncidents.length && ( - <> - {isLoadingIncidents && ( - - - - )} - {!isLoadingIncidents && ( - + Load more - )} - - )} - - - ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/FailingAssertions.tsx b/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/FailingAssertions.tsx deleted file mode 100644 index 01331b780d8bc3..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/FailingAssertions.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { LoadingOutlined } from '@ant-design/icons'; -import { Button } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import FailingEntity from '@app/entityV2/shared/embed/UpstreamHealth/FailingEntity'; -import { getNumAssertionsFailing } from '@app/entityV2/shared/embed/UpstreamHealth/utils'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { Dataset } from '@types'; - -export const FailingSectionWrapper = styled.div` - margin: 8px 0 0 34px; - font-size: 14px; - color: black; -`; - -export const FailingDataWrapper = styled.div` - margin-left: 20px; -`; - -export const LoadMoreButton = styled(Button)` - border: none; - padding: 0; - box-shadow: none; -`; - -export const LoadingWrapper = styled.div` - // set width and height to what our load more button is - width: 68px; - height: 32px; - display: flex; - justify-content: center; - align-items: center; -`; - -interface Props { - datasetsWithFailingAssertions: Dataset[]; - totalDatasetsWithFailingAssertions: number; - fetchMoreAssertionsData: () => void; - isLoadingAssertions: boolean; -} - -export default function FailingAssertions({ - datasetsWithFailingAssertions, - totalDatasetsWithFailingAssertions, - fetchMoreAssertionsData, - isLoadingAssertions, -}: Props) { - const entityRegistry = useEntityRegistry(); - - return ( - - {totalDatasetsWithFailingAssertions} data source{totalDatasetsWithFailingAssertions > 1 && 's'} with failing - assertions - - {datasetsWithFailingAssertions.map((dataset) => { - const totalNumAssertions = dataset.assertions?.assertions?.length; - const numAssertionsFailing = getNumAssertionsFailing(dataset); - - return ( - - ); - })} - {totalDatasetsWithFailingAssertions > datasetsWithFailingAssertions.length && ( - <> - {isLoadingAssertions && ( - - - - )} - {!isLoadingAssertions && ( - + Load more - )} - - )} - - - ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/FailingEntity.tsx b/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/FailingEntity.tsx deleted file mode 100644 index 9615ad90be46f0..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/FailingEntity.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { red } from '@ant-design/colors'; -import Icon from '@ant-design/icons/lib/components/Icon'; -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import ExternalLink from '@images/link-out.svg?react'; - -const DatasetWrapper = styled.div` - display: flex; - align-items: center; - margin-top: 8px; - overflow: hidden; - justify-content: space-between; -`; - -const AssertionsSummaryWrapper = styled.span` - font-size: 10px; - font-weight: 700; - line-height: 13px; - color: ${red[7]}; - background-color: ${red[0]}; - border-radius: 8px; - margin-left: 5px; - padding: 2px 4px; - letter-spacing: 0.2px; - white-space: nowrap; -`; - -const StyledLink = styled(Typography.Link)` - align-items: center; - display: flex; - overflow: hidden; - img { - margin-right: 3px; - } -`; - -const StyledIcon = styled(Icon)` - margin-right: 3px; -`; - -interface Props { - link: string; - displayName: string; - contentText: string; -} - -export default function FailingEntity({ link, displayName, contentText }: Props) { - return ( - - - - - {displayName} - - - {contentText} - - ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/FailingInputs.tsx b/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/FailingInputs.tsx deleted file mode 100644 index fed026c1253664..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/FailingInputs.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import { orange } from '@ant-design/colors'; -import { DownOutlined, WarningFilled } from '@ant-design/icons'; -import { Typography } from 'antd'; -import React, { useState } from 'react'; -import styled from 'styled-components'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { ANTD_GRAY } from '@app/entityV2/shared/constants'; -import { getDisplayedEntityType } from '@app/entityV2/shared/containers/profile/header/utils'; -import ActiveIncidents from '@app/entityV2/shared/embed/UpstreamHealth/ActiveIncidents'; -import FailingAssertions from '@app/entityV2/shared/embed/UpstreamHealth/FailingAssertions'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { Dataset } from '@types'; - -const FailingEntityTitle = styled(Typography.Text)` - font-size: 16px; - line-height: 24px; - margin-left: 6px; -`; - -const StyledWarning = styled(WarningFilled)` - color: ${orange[5]}; - font-size: 14px; -`; - -const FailingDetailsWrapper = styled.span` - font-size: 14px; - color: ${ANTD_GRAY[8]}; - margin-left: 6px; - white-space: nowrap; - &:hover { - cursor: pointer; - color: ${(props) => props.theme.styles['primary-color']}; - } -`; - -const FailingInputsHeader = styled.div` - display: flex; - align-items: center; -`; - -const StyledArrow = styled(DownOutlined)<{ isOpen: boolean }>` - font-size: 12px; - margin-left: 3px; - ${(props) => - props.isOpen && - ` - transform: rotate(180deg); - padding-top: 1px; - `} -`; - -interface Props { - datasetsWithActiveIncidents: Dataset[]; - totalDatasetsWithActiveIncidents: number; - fetchMoreIncidentsData: () => void; - isLoadingIncidents: boolean; - datasetsWithFailingAssertions: Dataset[]; - totalDatasetsWithFailingAssertions: number; - fetchMoreAssertionsData: () => void; - isLoadingAssertions: boolean; -} - -export default function FailingInputs({ - datasetsWithActiveIncidents, - totalDatasetsWithActiveIncidents, - fetchMoreIncidentsData, - isLoadingIncidents, - datasetsWithFailingAssertions, - totalDatasetsWithFailingAssertions, - fetchMoreAssertionsData, - isLoadingAssertions, -}: Props) { - const [areFailingDetailsVisible, setAreFailingDetailsVisible] = useState(false); - const entityRegistry = useEntityRegistry(); - const { entityData, entityType } = useEntityData(); - const displayedEntityType = getDisplayedEntityType(entityData, entityRegistry, entityType); - - return ( -
- - - - Data quality issues impacting this {displayedEntityType} - - setAreFailingDetailsVisible(!areFailingDetailsVisible)}> - details - - - {areFailingDetailsVisible && ( - <> - {datasetsWithActiveIncidents.length > 0 && ( - - )} - {datasetsWithFailingAssertions.length > 0 && ( - - )} - - )} -
- ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/UpstreamHealth.tsx b/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/UpstreamHealth.tsx index 7b097461dfd146..40a36b10d012c6 100644 --- a/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/UpstreamHealth.tsx +++ b/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/UpstreamHealth.tsx @@ -21,7 +21,7 @@ import { useEntityRegistry } from '@src/app/useEntityRegistry'; import { useSearchAcrossLineageQuery } from '@graphql/search.generated'; import { FilterOperator, LineageDirection } from '@types'; -export const StyledDivider = styled(Divider)` +const StyledDivider = styled(Divider)` margin: 16px 0; `; diff --git a/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/utils.ts b/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/utils.ts index 99d69463784993..38a9c964f1c726 100644 --- a/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/utils.ts +++ b/datahub-web-react/src/app/entityV2/shared/embed/UpstreamHealth/utils.ts @@ -25,7 +25,7 @@ interface Arguments { count?: number; } -export function generateQueryVariables({ +function generateQueryVariables({ urn, startTimeMillis, filterField, diff --git a/datahub-web-react/src/app/entityV2/shared/links/DataProductMiniPreviewAddDataProduct.tsx b/datahub-web-react/src/app/entityV2/shared/links/DataProductMiniPreviewAddDataProduct.tsx deleted file mode 100644 index 0aeb2eda021330..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/links/DataProductMiniPreviewAddDataProduct.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { PlusOutlined } from '@ant-design/icons'; -import React from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY, ANTD_GRAY_V2, REDESIGN_COLORS } from '@app/entity/shared/constants'; - -const DomainInfoContainer = styled.div` - display: flex; - flex-direction: column; -`; - -const DataProductDescription = styled.div` - font-size: 14px; - font-weight: 400; - color: ${ANTD_GRAY[7]}; - font-family: Mulish; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - max-width: 200px; -`; - -const DataProductTitle = styled.div` - font-size: 16px; - font-weight: 400; - color: ${REDESIGN_COLORS.BLUE}; - font-family: Mulish; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - max-width: 200px; -`; - -const Card = styled.div` - align-self: stretch; - align-items: center; - background-color: ${ANTD_GRAY[1]}; - border: 1.5px solid ${ANTD_GRAY_V2[5]}; - border-radius: 10px; - display: flex; - justify-content: start; - min-width: 160px; - padding: 16px; - height: 100%; - :hover { - border: 1.5px solid ${REDESIGN_COLORS.BLUE}; - cursor: pointer; - } -`; - -export const DataProductMiniPreviewAddDataProduct = ({ onAdd }: { onAdd: () => void }): JSX.Element => { - return ( - - - - - Add Data Product - - Share your knowledge - - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/links/EntityExternalLink.tsx b/datahub-web-react/src/app/entityV2/shared/links/EntityExternalLink.tsx deleted file mode 100644 index defdf717eb7e4f..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/links/EntityExternalLink.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React, { ReactNode } from 'react'; - -interface Props { - url: string | null | undefined; - children: ReactNode; -} - -const EntityExternalLink: React.FC = ({ url, children }) => ( - - {children} - -); - -export default EntityExternalLink; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/AccessManagement/AccessButtonHelpers.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/AccessManagement/AccessButtonHelpers.tsx index 6511b9ea10e55f..0f94f0947d6a27 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/AccessManagement/AccessButtonHelpers.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/AccessManagement/AccessButtonHelpers.tsx @@ -7,13 +7,13 @@ import { ANTD_GRAY, REDESIGN_COLORS } from '@app/entityV2/shared/constants'; /** * Tooltip message for when user already has access */ -export const ACCESS_GRANTED_TOOLTIP = 'You already have access to this role'; +const ACCESS_GRANTED_TOOLTIP = 'You already have access to this role'; /** * Styled button component for access management actions. * Supports both enabled (request) and disabled (granted) states. */ -export const AccessButton = styled(Button)` +const AccessButton = styled(Button)` background-color: ${REDESIGN_COLORS.BLUE}; color: ${REDESIGN_COLORS.WHITE}; width: 80px; @@ -56,7 +56,7 @@ export interface RoleAccessData { * Handles the click event for access request buttons. * Only opens the URL if the user doesn't already have access. */ -export const handleAccessButtonClick = (hasAccess: boolean, url?: string) => (e: React.MouseEvent) => { +const handleAccessButtonClick = (hasAccess: boolean, url?: string) => (e: React.MouseEvent) => { if (!hasAccess && url) { e.preventDefault(); window.open(url); @@ -98,9 +98,9 @@ export const renderAccessButton = (roleData: RoleAccessData): React.ReactElement /** * Determines the button text based on access status */ -export const getAccessButtonText = (hasAccess: boolean): string => (hasAccess ? 'Granted' : 'Request'); +const getAccessButtonText = (hasAccess: boolean): string => (hasAccess ? 'Granted' : 'Request'); /** * Determines if the button should be disabled */ -export const isAccessButtonDisabled = (hasAccess: boolean): boolean => hasAccess; +const isAccessButtonDisabled = (hasAccess: boolean): boolean => hasAccess; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/AccessManagement/AccessManagerDescription.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/AccessManagement/AccessManagerDescription.tsx index 06b55b67c6ee79..527a97ce5ef41c 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/AccessManagement/AccessManagerDescription.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/AccessManagement/AccessManagerDescription.tsx @@ -2,7 +2,7 @@ import { Typography } from 'antd'; import React, { useState } from 'react'; import styled from 'styled-components'; -export type Props = { +type Props = { description: any; }; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Governance/TestResults.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Governance/TestResults.tsx deleted file mode 100644 index 7b4fc7fd273fcb..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Governance/TestResults.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; - -import { TestResultsList } from '@app/entityV2/shared/tabs/Dataset/Governance/TestResultsList'; -import { TestResultsSummary } from '@app/entityV2/shared/tabs/Dataset/Governance/TestResultsSummary'; - -import { TestResult } from '@types'; - -type Props = { - passing: Array; - failing: Array; -}; - -export const TestResults = ({ passing, failing }: Props) => { - const filteredPassing = passing.filter((testResult) => testResult.test !== null); - const filteredFailing = failing.filter((testResult) => testResult.test !== null); - const totalTests = filteredPassing.length + filteredFailing.length; - - return ( - <> - - {totalTests > 0 && ( - - )} - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Governance/TestResultsList.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Governance/TestResultsList.tsx deleted file mode 100644 index 841f7681b1bfb7..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Governance/TestResultsList.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import { CopyOutlined, StopOutlined } from '@ant-design/icons'; -import { Button, Tooltip } from '@components'; -import { Divider, Empty, Tag, Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { StyledTable } from '@app/entityV2/shared/components/styled/StyledTable'; -import { getResultColor, getResultIcon, getResultText } from '@app/entityV2/shared/tabs/Dataset/Governance/testUtils'; - -import { TestResult } from '@types'; - -const ResultContainer = styled.div` - display: flex; - align-items: center; - justify-content: left; -`; - -const TestResultsContainer = styled.div` - padding: 20px; -`; - -const TestName = styled(Typography.Title)` - margin: 0px; - padding: 0px; - - && { - margin-bottom: 4px; - } -`; - -const TestCategory = styled(Typography.Text)` - margin: 0px; - padding: 0px; -`; - -const ResultTypeText = styled(Typography.Text)` - margin-left: 8px; -`; - -const CopyButton = styled(Button)` - padding: 0px 8px 0px 8px; - margin: 0px; - height: 32px; -`; - -type Props = { - title: string; - results: Array; -}; - -export const TestResultsList = ({ title, results }: Props) => { - const resultsTableData = results.map((result) => ({ - urn: result.test?.urn, - name: result?.test?.name, - category: result?.test?.category, - description: result?.test?.description, - resultType: result.type, - })); - - const resultsTableCols = [ - { - title: '', - dataIndex: '', - key: '', - render: (_, record: any) => { - const resultColor = (record.resultType && getResultColor(record.resultType)) || 'default'; - const resultText = (record.resultType && getResultText(record.resultType)) || 'No Evaluations'; - const resultIcon = (record.resultType && getResultIcon(record.resultType)) || ; - return ( - -
- - {resultIcon} - {resultText} - -
-
-
-
- {record.name} - {record.category} - - - {record.description || 'No description'} - -
-
- {navigator.clipboard && ( - - { - navigator.clipboard.writeText(record.urn); - }} - > - - - - )} -
-
- ); - }, - }, - ]; - - return ( - - {title} - , - }} - showHeader={false} - pagination={false} - /> - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Governance/TestResultsSummary.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Governance/TestResultsSummary.tsx deleted file mode 100644 index 301cee4362656a..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Governance/TestResultsSummary.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import { CheckCircleFilled, CloseCircleFilled, StopOutlined } from '@ant-design/icons'; -import { Tooltip } from '@components'; -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { FAILURE_COLOR_HEX, SUCCESS_COLOR_HEX } from '@components/theme/foundations/colors'; - -import { ANTD_GRAY } from '@app/entityV2/shared/constants'; - -const SummaryHeader = styled.div` - width: 100%; - padding-left: 40px; - padding-top: 20px; - padding-bottom: 20px; - display: flex; - align-items: center; - border-bottom: 1px solid ${ANTD_GRAY[4.5]}; -`; - -const SummaryContainer = styled.div``; - -const SummaryMessage = styled.div` - display: inline-block; - margin-left: 20px; -`; - -const SummaryTitle = styled(Typography.Title)` - && { - padding-bottom: 0px; - margin-bottom: 0px; - } -`; - -export type TestsSummary = { - failing: number; - passing: number; - total: number; -}; - -type Props = { - summary: TestsSummary; -}; - -const getSummaryIcon = (summary: TestsSummary) => { - if (summary.total === 0) { - return ; - } - if (summary.passing === summary.total) { - return ; - } - return ; -}; - -const getSummaryMessage = (summary: TestsSummary) => { - if (summary.total === 0) { - return 'No tests have run'; - } - if (summary.passing === summary.total) { - return 'All tests are passing'; - } - if (summary.failing === summary.total) { - return 'All tests are failing'; - } - return 'Some tests are failing'; -}; - -export const TestResultsSummary = ({ summary }: Props) => { - const summaryIcon = getSummaryIcon(summary); - const summaryMessage = getSummaryMessage(summary); - const subtitleMessage = `${summary.passing} passing tests, ${summary.failing} failing tests`; - return ( - - - -
- {summaryIcon} - - {summaryMessage} - {subtitleMessage} - -
-
-
-
- ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Governance/testUtils.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Governance/testUtils.tsx deleted file mode 100644 index 04f60877ab17b6..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Governance/testUtils.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons'; -import React from 'react'; - -import { FAILURE_COLOR_HEX, SUCCESS_COLOR_HEX } from '@components/theme/foundations/colors'; - -import { TestResultType } from '@types'; - -/** - * Returns the display text assoociated with an Test Result Type - */ -export const getResultText = (result: TestResultType) => { - switch (result) { - case TestResultType.Success: - return 'Passing'; - case TestResultType.Failure: - return 'Failing'; - default: - throw new Error(`Unsupported Test Result Type ${result} provided.`); - } -}; - -/** - * Returns the display color assoociated with an TestResultType - */ - -export const getResultColor = (result: TestResultType) => { - switch (result) { - case TestResultType.Success: - return SUCCESS_COLOR_HEX; - case TestResultType.Failure: - return FAILURE_COLOR_HEX; - default: - throw new Error(`Unsupported Test Result Type ${result} provided.`); - } -}; - -/** - * Returns the display icon assoociated with an TestResultType - */ -export const getResultIcon = (result: TestResultType) => { - const resultColor = getResultColor(result); - switch (result) { - case TestResultType.Success: - return ; - case TestResultType.Failure: - return ; - default: - throw new Error(`Unsupported Test Result Type ${result} provided.`); - } -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/CopyQuery.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/CopyQuery.tsx index 890d3b027803ae..51589eb1deba82 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/CopyQuery.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/CopyQuery.tsx @@ -3,7 +3,7 @@ import { Tooltip } from '@components'; import { Button } from 'antd'; import React, { useState } from 'react'; -export type Props = { +type Props = { query: string; showCopyText?: boolean; style?: any; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/Query.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/Query.tsx index 700588554f8562..f034a8cb8786d9 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/Query.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/Query.tsx @@ -4,7 +4,7 @@ import QueryBuilderModal from '@app/entityV2/shared/tabs/Dataset/Queries/QueryBu import QueryCard from '@app/entityV2/shared/tabs/Dataset/Queries/QueryCard'; import QueryModal from '@app/entityV2/shared/tabs/Dataset/Queries/QueryModal'; -export type Props = { +type Props = { urn?: string; query: string; title?: string; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCard.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCard.tsx index 89b4fcb258fd3f..e5df2272aaeaaa 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCard.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCard.tsx @@ -16,7 +16,7 @@ const Card = styled.div<{ isCompact?: boolean }>` ${(props) => props.isCompact && `max-width: 650px;`} `; -export type Props = { +type Props = { urn?: string; query: string; title?: string; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardDetails.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardDetails.tsx index cca46cc1ff0fc7..e5ed47069faba9 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardDetails.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardDetails.tsx @@ -68,7 +68,7 @@ const EmptyText = styled.div` } `; -export type Props = { +type Props = { urn?: string; title?: string; description?: string; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardDetailsMenu.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardDetailsMenu.tsx index 8ca40ca1492ece..6f8d2dbd8a1a7d 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardDetailsMenu.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardDetailsMenu.tsx @@ -9,7 +9,7 @@ const StyledMoreOutlined = styled(MoreOutlined)` font-size: 14px; `; -export type Props = { +type Props = { urn: string; onDeleted?: (urn: string) => void; index?: number; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardEditButton.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardEditButton.tsx index 79451ec9ebf064..9ef76bbb4587af 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardEditButton.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardEditButton.tsx @@ -10,7 +10,7 @@ const EditQueryActionButton = styled(Button)` } `; -export type Props = { +type Props = { onClickEdit?: () => void; index?: number; }; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardHeader.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardHeader.tsx index dd0ddb6edf5ee4..b6216e6f5bcde7 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardHeader.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardHeader.tsx @@ -22,7 +22,7 @@ const ExpandButton = styled(Button)` margin-left: 8px; `; -export type Props = { +type Props = { query: string; focused: boolean; onClickExpand?: (newQuery) => void; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardQuery.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardQuery.tsx index e681e2fa4cbbc0..6d067fcac1c353 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardQuery.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/QueryCardQuery.tsx @@ -40,7 +40,7 @@ const NestedSyntax = styled(StyledSyntaxHighlighter)<{ isCompact?: boolean }>` `} `; -export type Props = { +type Props = { query: string; showDetails: boolean; onClickExpand?: (newQuery) => void; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/utils/constants.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/utils/constants.ts index fd3b8fbe062317..dd06c494a9a24b 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/utils/constants.ts +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/utils/constants.ts @@ -9,7 +9,7 @@ export const DEFAULT_PAGE_SIZE = 5; /** * The Max number of "Recent Queries" to surface. */ -export const DEFAULT_MAX_RECENT_QUERIES = 9; +const DEFAULT_MAX_RECENT_QUERIES = 9; /** * Searching Queries diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/utils/getCurrentPage.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/utils/getCurrentPage.ts deleted file mode 100644 index 2931de97e69aca..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Queries/utils/getCurrentPage.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Returns the queries for the current page - */ -export const getQueriesForPage = (queries: any, page: number, pageSize: number) => { - const start = (page - 1) * pageSize; - const end = start + pageSize; - return queries.length >= end ? queries.slice(start, end) : queries.slice(start, queries.length); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/CompactSchemaTable.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/CompactSchemaTable.tsx index bf592655333906..73fd8c2060262b 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/CompactSchemaTable.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/CompactSchemaTable.tsx @@ -21,7 +21,7 @@ import { resolveRuntimePath } from '@utils/runtimeBasePath'; import { EditableSchemaMetadata, EntityType, SchemaField, SchemaMetadata, UsageQueryResult } from '@types'; -export type Props = { +type Props = { rows: Array; schemaMetadata: SchemaMetadata | undefined | null; editableSchemaMetadata?: EditableSchemaMetadata | null; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/SchemaTable.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/SchemaTable.tsx index 45eb4168a6a917..23b2e482bf88a3 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/SchemaTable.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/SchemaTable.tsx @@ -142,7 +142,7 @@ const TableContainer = styled.div<{ isSearchActive: boolean; hasRowWithDepth: bo } `; -export type Props = { +type Props = { rows: Array; schemaMetadata: SchemaMetadata | undefined | null; editableSchemaMetadata?: EditableSchemaMetadata | null; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/components/MenuColumn.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/components/MenuColumn.tsx index 5ac4d969922453..cad69e831211f9 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/components/MenuColumn.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/components/MenuColumn.tsx @@ -15,7 +15,7 @@ export const ImpactAnalysisIcon = styled(VscGraphLeft)` font-size: 18px; `; -export const CopyOutlinedIcon = styled(CopyOutlined)` +const CopyOutlinedIcon = styled(CopyOutlined)` transform: scaleX(-1); font-size: 16px; `; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/components/NestedRowIcon.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/components/NestedRowIcon.tsx deleted file mode 100644 index c9d1e3f804a15e..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/components/NestedRowIcon.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { REDESIGN_COLORS } from '@app/entityV2/shared/constants'; - -import RowIcon from '@images/row-icon.svg?react'; - -const RowIconContainer = styled.div` - position: relative; - display: flex; - align-items: center; -`; -const DepthContainer = styled.div` - height: 13px; - width: 13px; - border-radius: 50%; - background: ${REDESIGN_COLORS.WHITE}; - margin-left: -7px; - margin-top: -12px; - display: flex; - align-items: center; -`; - -const DepthNumber = styled(Typography.Text)` - margin-left: 4px; - background: transparent; - color: ${REDESIGN_COLORS.PRIMARY_PURPLE}; - font-size: 10px; - font-weight: 400; -`; - -type Props = { - depth: number; -}; - -export default function NestedRowIcon({ depth }: Props) { - return ( - - - - {depth} - - - ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/components/SchemaFieldDrawer/FieldTitle.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/components/SchemaFieldDrawer/FieldTitle.tsx deleted file mode 100644 index c1c55f766e1b52..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/components/SchemaFieldDrawer/FieldTitle.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { REDESIGN_COLORS } from '@app/entityV2/shared/constants'; - -const FieldName = styled(Typography.Text)` - color: ${REDESIGN_COLORS.WHITE_WIRE}; - font-size: 16px; - font-weight: 700; - line-height: 24px; - overflow: hidden; - display: block; - cursor: pointer; - :hover { - font-weight: bold; - } -`; - -interface Props { - displayName: string; -} - -export default function FieldTitle({ displayName }: Props) { - const name = displayName.split('.').pop(); - return {name}; -} diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/components/SchemaFieldDrawer/FieldUsageStats.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/components/SchemaFieldDrawer/FieldUsageStats.tsx deleted file mode 100644 index 32ae7e2f4e6c81..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/components/SchemaFieldDrawer/FieldUsageStats.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import React, { useMemo } from 'react'; -import styled from 'styled-components'; - -import { useBaseEntity } from '@app/entity/shared/EntityContext'; -import { pathMatchesNewPath } from '@app/entityV2/dataset/profile/schema/utils/utils'; -import { ANTD_GRAY_V2 } from '@app/entityV2/shared/constants'; -import { SectionHeader } from '@app/entityV2/shared/tabs/Dataset/Schema/components/SchemaFieldDrawer/components'; -import { UsageBar } from '@app/entityV2/shared/tabs/Dataset/Schema/utils/useUsageStatsRenderer'; -import { formatNumberWithoutAbbreviation } from '@app/shared/formatNumber'; - -import { GetDatasetQuery } from '@graphql/dataset.generated'; -import { SchemaField } from '@types'; - -const USAGE_BAR_MAX_WIDTH = 100; - -const UsageBarWrapper = styled.div` - display: flex; - align-items: center; -`; - -const UsageBarBackground = styled.div` - background-color: ${ANTD_GRAY_V2[3]}; - border-radius: 2px; - height: 4px; - width: ${USAGE_BAR_MAX_WIDTH}px; -`; - -const UsageTextWrapper = styled.span` - margin-left: 8px; -`; - -const UsageSection = styled.div` - margin-bottom: 24px; -`; - -interface Props { - expandedField: SchemaField; -} - -export default function FieldUsageStats({ expandedField }: Props) { - const baseEntity = useBaseEntity(); - const usageStats = baseEntity?.dataset?.usageStats; - const hasUsageStats = useMemo(() => (usageStats?.aggregations?.fields?.length || 0) > 0, [usageStats]); - const maxFieldUsageCount = useMemo( - () => Math.max(...(usageStats?.aggregations?.fields?.map((field) => field?.count || 0) || [])), - [usageStats], - ); - const relevantUsageStats = usageStats?.aggregations?.fields?.find((fieldStats) => - pathMatchesNewPath(fieldStats?.fieldName, expandedField.fieldPath), - ); - - if (!hasUsageStats || !relevantUsageStats) return null; - - return ( - - Usage - - - - - - {formatNumberWithoutAbbreviation(relevantUsageStats.count || 0)} queries / month - - - - ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/components/SchemaFieldDrawer/components.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/components/SchemaFieldDrawer/components.ts index 9195eab6d450cf..853044750e034f 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/components/SchemaFieldDrawer/components.ts +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/components/SchemaFieldDrawer/components.ts @@ -4,7 +4,7 @@ import styled from 'styled-components'; import { REDESIGN_COLORS } from '@app/entityV2/shared/constants'; import { colors } from '@src/alchemy-components'; -export const SectionHeader = styled.div` +const SectionHeader = styled.div` margin-bottom: 8px; color: ${REDESIGN_COLORS.DARK_GREY}; font-size: 14px; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/utils/useTagsAndTermsRendererFeatureTable.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/utils/useTagsAndTermsRendererFeatureTable.tsx deleted file mode 100644 index 3a3ab7a62d6fbb..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/utils/useTagsAndTermsRendererFeatureTable.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import React from 'react'; - -import { useEntityData, useRefetch } from '@app/entity/shared/EntityContext'; -import { pathMatchesExact } from '@app/entityV2/dataset/profile/schema/utils/utils'; -import TagTermGroup from '@app/sharedV2/tags/TagTermGroup'; - -import { EditableSchemaMetadata, EntityType, GlobalTags, SchemaField } from '@types'; - -export default function useTagsAndTermsRendererFeatureTable( - editableSchemaMetadata: EditableSchemaMetadata | null | undefined, - tagHoveredIndex: string | undefined, - setTagHoveredIndex: (index: string | undefined) => void, - options: { showTags: boolean; showTerms: boolean }, -) { - const { urn } = useEntityData(); - const refetch = useRefetch(); - - const tagAndTermRender = (tags: GlobalTags, record: SchemaField, rowIndex: number | undefined) => { - const relevantEditableFieldInfo = editableSchemaMetadata?.editableSchemaFieldInfo?.find( - (candidateEditableFieldInfo) => pathMatchesExact(candidateEditableFieldInfo.fieldPath, record.fieldPath), - ); - - return ( -
- setTagHoveredIndex(undefined)} - entityUrn={urn} - entityType={EntityType.Dataset} - entitySubresource={record.fieldPath} - refetch={refetch} - /> -
- ); - }; - return tagAndTermRender; -} diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/utils/useUsageStatsRenderer.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/utils/useUsageStatsRenderer.tsx index e9f6f05aea6f0d..71f3fa91d7dc93 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/utils/useUsageStatsRenderer.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Schema/utils/useUsageStatsRenderer.tsx @@ -10,7 +10,7 @@ import { useBaseEntity } from '@src/app/entity/shared/EntityContext'; import { GetDatasetQuery } from '@graphql/dataset.generated'; import { UsageQueryResult } from '@types'; -export const UsageBar = styled.div<{ width: number }>` +const UsageBar = styled.div<{ width: number }>` width: ${(props) => props.width}px; height: 4px; background-color: ${geekblue[3]}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/StatsSection.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/StatsSection.tsx deleted file mode 100644 index 32244ee67cc374..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/StatsSection.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Divider, Row, Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -const Section = styled.div` - padding-top: 24px; - padding-bottom: 40px; - margin-bottom: 20px; - width: 100%; -`; - -const ThinDivider = styled(Divider)` - margin-top: 8px; - margin-bottom: 8px; -`; - -export type Props = { - children: React.ReactNode; - title: string; - rightFloatView?: React.ReactNode; -}; - -export default function StatsSection({ children, title, rightFloatView }: Props) { - return ( -
- - {title} - {rightFloatView || } - - - {children} -
- ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/StatsTabV2/graphs/ChangeHistoryGraph/constants.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/StatsTabV2/graphs/ChangeHistoryGraph/constants.ts index b083b132c0c2ae..b0f643af0c5e08 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/StatsTabV2/graphs/ChangeHistoryGraph/constants.ts +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/StatsTabV2/graphs/ChangeHistoryGraph/constants.ts @@ -1,7 +1,7 @@ import { AggregationGroup } from '@app/entityV2/shared/tabs/Dataset/Stats/StatsTabV2/graphs/ChangeHistoryGraph/types'; import { OperationType } from '@src/types.generated'; -export const AVAILABLE_OPERATION_TYPES = [ +const AVAILABLE_OPERATION_TYPES = [ OperationType.Insert, OperationType.Update, OperationType.Delete, diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/StatsTabV2/graphs/utils.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/StatsTabV2/graphs/utils.ts index 8bdcd476b1f135..a29fec8e35f333 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/StatsTabV2/graphs/utils.ts +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/StatsTabV2/graphs/utils.ts @@ -7,7 +7,7 @@ import { DateInterval, TimeRange } from '@src/types.generated'; dayjs.extend(utc); -export type TimeSeriesDatum = { +type TimeSeriesDatum = { time: number; value: number; }; @@ -15,8 +15,8 @@ export type TimeSeriesDatum = { export type AggregationFunction = (values: number[]) => number | undefined; export const MAX_VALUE_AGGREGATION: AggregationFunction = (values) => Math.max(...values); -export const MIN_VALUE_AGGREGATION: AggregationFunction = (values) => Math.min(...values); -export const LATEST_VALUE_AGGREGATION: AggregationFunction = (values) => values.at(-1); +const MIN_VALUE_AGGREGATION: AggregationFunction = (values) => Math.min(...values); +const LATEST_VALUE_AGGREGATION: AggregationFunction = (values) => values.at(-1); export const SUM_VALUES_AGGREGATION: AggregationFunction = (values) => values.reduce((sum, val) => sum + val, 0); /** diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/StatsTabV2/highlights/styledComponents.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/StatsTabV2/highlights/styledComponents.ts index f4ba2593d282ff..2396a6bd92d88d 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/StatsTabV2/highlights/styledComponents.ts +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/StatsTabV2/highlights/styledComponents.ts @@ -8,7 +8,7 @@ const NUM_CARDS_LATEST_STATS = 2; const NUM_CARDS_LAST_MONTH_STATS = 3; const LATEST_STATS_MAX_WIDTH = 470; -export const highlightsSectionStyles = css` +const highlightsSectionStyles = css` display: flex; flex-direction: column; gap: 8px; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/historical/HistoricalStats.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/historical/HistoricalStats.tsx index 32eee24009dadf..b5c189fc17b470 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/historical/HistoricalStats.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/historical/HistoricalStats.tsx @@ -49,7 +49,7 @@ const getLookbackWindowSize = (window: LookbackWindow) => { return window.windowSize; }; -export type Props = { +type Props = { urn: string; lookbackWindow: LookbackWindow; }; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/historical/charts/ProfilingRunsChart.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/historical/charts/ProfilingRunsChart.tsx index 45ce5add432b53..2ae74ff5c89057 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/historical/charts/ProfilingRunsChart.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/historical/charts/ProfilingRunsChart.tsx @@ -9,11 +9,11 @@ import { formatBytes, formatNumberWithoutAbbreviation } from '@app/shared/format import { DatasetProfile } from '@types'; -export const ChartTable = styled(Table)` +const ChartTable = styled(Table)` margin-top: 16px; `; -export type Props = { +type Props = { profiles: Array; areAllProfilesPartitioned: boolean; }; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/historical/charts/StatChart.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/historical/charts/StatChart.tsx index e6f8b1381bc044..1e7bbe7347e1e6 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/historical/charts/StatChart.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Stats/historical/charts/StatChart.tsx @@ -34,7 +34,7 @@ type AxisConfig = { formatter: (tick: number) => string; }; -export type Props = { +type Props = { title: string; values: Array; tickInterval: DateInterval; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AcrylAssertionDetails.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AcrylAssertionDetails.tsx deleted file mode 100644 index 52da589febf2fb..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AcrylAssertionDetails.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import { AcrylAssertionDetailsHeader } from '@app/entityV2/shared/tabs/Dataset/Validations/AcrylAssertionDetailsHeader'; -import { AcrylAssertionResultsChart } from '@app/entityV2/shared/tabs/Dataset/Validations/AcrylAssertionResultsChart'; - -import { CronSchedule } from '@types'; - -const Container = styled.div` - width: 100%; - padding-left: 52px; -`; - -type Props = { - urn: string; - schedule?: CronSchedule; - lastEvaluatedAtMillis?: number | undefined; - nextEvaluatedAtMillis?: number | undefined; - isStopped?: boolean; -}; - -export const AcrylAssertionDetails = ({ - urn, - schedule, - lastEvaluatedAtMillis, - nextEvaluatedAtMillis, - isStopped = false, -}: Props) => { - return ( - - - - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AcrylAssertionDetailsHeader.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AcrylAssertionDetailsHeader.tsx deleted file mode 100644 index 87be3a8dee9742..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AcrylAssertionDetailsHeader.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import { ClockCircleOutlined } from '@ant-design/icons'; -import { Tooltip } from '@components'; -import { Divider, Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entityV2/shared/constants'; -import { getCronAsText } from '@app/entityV2/shared/tabs/Dataset/Validations/acrylUtils'; -import { TruncatedTextWithTooltip } from '@app/shared/TruncatedTextWithTooltip'; -import { getLocaleTimezone } from '@app/shared/time/timeUtils'; - -import { CronSchedule } from '@types'; - -const TimeLabel = styled.div` - max-width: 280px; - padding: 0; - margin: 0; - display: flex; - align-items: center; - color: ${ANTD_GRAY[7]}; -`; - -const Schedule = styled.span` - display: flex; - align-items: center; - justify-content: left; -`; - -const StyledTruncatedText = styled(TruncatedTextWithTooltip)` - color: ${ANTD_GRAY[7]}; -`; - -const StyledClockCircleOutlined = styled(ClockCircleOutlined)` - margin-right: 8px; -`; - -type Props = { - schedule?: CronSchedule; - lastEvaluatedAtMillis?: number | undefined; - nextEvaluatedAtMillis?: number | undefined; - isStopped?: boolean; -}; - -/** - * Renders the header of the Assertion Details card, which displays the run schedule for the assertion. - */ -export const AcrylAssertionDetailsHeader = ({ - schedule, - lastEvaluatedAtMillis, - nextEvaluatedAtMillis, - isStopped = false, -}: Props) => { - const localeTimezone = getLocaleTimezone(); - - /** - * Last evaluated timestamp - */ - const lastEvaluatedAt = lastEvaluatedAtMillis && new Date(lastEvaluatedAtMillis); - const lastEvaluatedTimeLocal = lastEvaluatedAt - ? `Last evaluated on ${lastEvaluatedAt.toLocaleDateString()} at ${lastEvaluatedAt.toLocaleTimeString()} (${localeTimezone})` - : null; - const lastEvaluatedTimeGMT = lastEvaluatedAt ? lastEvaluatedAt.toUTCString() : null; - - /** - * Next evaluated timestamp - */ - const nextEvaluatedAt = nextEvaluatedAtMillis && new Date(nextEvaluatedAtMillis); - const nextEvaluatedTimeLocal = nextEvaluatedAt - ? `Next evaluation at ${nextEvaluatedAt.toLocaleDateString()} at ${nextEvaluatedAt.toLocaleTimeString()} (${localeTimezone})` - : null; - const nextEvaluatedTimeGMT = nextEvaluatedAt ? nextEvaluatedAt.toUTCString() : null; - - /** - * Cron String - This will not be present for external assertions. - */ - const interval = schedule?.cron?.replaceAll(', ', ''); - const timezone = schedule?.timezone || Intl.DateTimeFormat().resolvedOptions().timeZone; - const cronAsText = interval && getCronAsText(interval); - const scheduleText = schedule && cronAsText && !cronAsText.error && cronAsText.text; - - return ( -
- Evaluations - {(!isStopped && ( - - {scheduleText && ( - - - - {lastEvaluatedTimeLocal && } - - )} - - - {lastEvaluatedTimeLocal} {nextEvaluatedAtMillis ? : true} - - - - {nextEvaluatedTimeLocal && {nextEvaluatedTimeLocal}} - - - )) || This assertion is not actively running.} -
- ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AcrylAssertionResultsChart.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AcrylAssertionResultsChart.tsx deleted file mode 100644 index 5c57e2159e9a0e..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AcrylAssertionResultsChart.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import styled from 'styled-components'; - -import { LOOKBACK_WINDOWS } from '@app/entityV2/shared/tabs/Dataset/Stats/lookbackWindows'; -import { AcrylAssertionResultsChartHeader } from '@app/entityV2/shared/tabs/Dataset/Validations/AcrylAssertionResultsChartHeader'; -import { AcrylAssertionResultsChartTimeline } from '@app/entityV2/shared/tabs/Dataset/Validations/AcrylAssertionResultsChartTimeline'; -import { getFixedLookbackWindow } from '@app/shared/time/timeUtils'; - -import { useGetAssertionRunsLazyQuery } from '@graphql/assertion.generated'; - -const RESULT_CHART_WIDTH_PX = 800; - -const Container = styled.div` - width: ${RESULT_CHART_WIDTH_PX}px; - padding-top: 12px; -`; - -type Props = { - urn: string; -}; - -export const AcrylAssertionResultsChart = ({ urn }: Props) => { - /** - * Retrieve a specific assertion's evaluations between a particular start and end time. - */ - const [getAssertionRuns, { data }] = useGetAssertionRunsLazyQuery({ fetchPolicy: 'cache-first' }); - - /** - * Set default window for fetching assertion history. - */ - const [lookbackWindow, setLookbackWindow] = useState(LOOKBACK_WINDOWS.WEEK); - - /** - * Whenever the selected lookback window changes (via user selection), then - * refetch the runs for the assertion. - */ - useEffect(() => { - getAssertionRuns({ - variables: { assertionUrn: urn, ...getFixedLookbackWindow(lookbackWindow.windowSize) }, - }); - }, [urn, lookbackWindow, getAssertionRuns]); - - const selectedWindow = getFixedLookbackWindow(lookbackWindow.windowSize); - const selectedWindowTimeRange = { - startMs: selectedWindow.startTime, - endMs: selectedWindow.endTime, - }; - - return ( - - - - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AcrylAssertionResultsChartHeader.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AcrylAssertionResultsChartHeader.tsx deleted file mode 100644 index a09cd8a8a88b0b..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AcrylAssertionResultsChartHeader.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { Typography } from 'antd'; -import { SelectValue } from 'antd/lib/select'; -import React from 'react'; -import styled from 'styled-components'; - -import PrefixedSelect from '@app/entityV2/shared/tabs/Dataset/Stats/historical/shared/PrefixedSelect'; -import { LOOKBACK_WINDOWS, LookbackWindow } from '@app/entityV2/shared/tabs/Dataset/Stats/lookbackWindows'; -import { TimeRange } from '@app/entityV2/shared/tabs/Dataset/Validations/AssertionResultTimeline'; -import { getResultColor } from '@app/entityV2/shared/tabs/Dataset/Validations/assertionUtils'; -import { formatNumber } from '@app/shared/formatNumber'; - -import { AssertionResultType, AssertionRunEventsResult } from '@types'; - -const Header = styled.div` - display: flex; - justify-content: space-between; -`; - -const EvaluationsSummary = styled.div` - width: 300px; - display: flex; - align-items: center; - justify-content: left; -`; - -const EvaluationDateRange = styled(Typography.Text)` - margin-right: 20px; -`; - -const EvaluationResults = styled.div``; - -const ResultTypeCount = styled.span` - margin-right: 12px; -`; - -const ErrorEvaluationsCount = styled(Typography.Text)` - font-weight: 600; - color: ${getResultColor(AssertionResultType.Error)}; -`; - -type Props = { - timeRange: TimeRange; - results?: AssertionRunEventsResult | null; - lookbackWindow: LookbackWindow; - setLookbackWindow: (newWindow: LookbackWindow) => void; -}; - -export const AcrylAssertionResultsChartHeader = ({ timeRange, lookbackWindow, setLookbackWindow, results }: Props) => { - /** - * Start and end dates being observed in the chart. - */ - const startDate = new Date(timeRange.startMs).toLocaleDateString('en-us', { - month: 'short', - day: 'numeric', - }); - const endDate = new Date(timeRange.endMs).toLocaleDateString('en-us', { - month: 'short', - day: 'numeric', - }); - - /** - * Success / Failure summary - */ - const succeededCount = results?.succeeded; - const failedCount = results?.failed; - const errorCount = results?.errored; - - /** - * Invoked when user selects new lookback window (e.g. 1 year) - */ - const onChangeLookbackWindow = (value: SelectValue) => { - const newLookbackWindow = Object.values(LOOKBACK_WINDOWS).filter((window) => window.text === value?.valueOf()); - setLookbackWindow(newLookbackWindow[0]); - }; - - return ( -
- - - {startDate} - {endDate} - - - - - {formatNumber(succeededCount)} - {' '} - passed - - - - {formatNumber(failedCount)} - {' '} - failed - - {errorCount ? ( - - {formatNumber(errorCount)} error - {errorCount > 1 ? 's' : ''} - - ) : null} - - - window.text)} - value={lookbackWindow.text} - setValue={onChangeLookbackWindow} - /> -
- ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AcrylAssertionResultsChartTimeline.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AcrylAssertionResultsChartTimeline.tsx deleted file mode 100644 index 66bace47cfd2af..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AcrylAssertionResultsChartTimeline.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import { ArrowRightOutlined } from '@ant-design/icons'; -import { Tooltip } from '@components'; -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { - AssertionResultTimeline, - TimeRange, -} from '@app/entityV2/shared/tabs/Dataset/Validations/AssertionResultTimeline'; -import { DatasetAssertionResultDetails } from '@app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionResultDetails'; -import { - getResultErrorMessage, - getResultIcon, - getResultText, -} from '@app/entityV2/shared/tabs/Dataset/Validations/assertionUtils'; -import { LinkWrapper } from '@app/shared/LinkWrapper'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { AssertionResultType, AssertionRunEventsResult, AssertionRunStatus, DataPlatform, EntityType } from '@types'; - -const RESULT_CHART_WIDTH_PX = 800; - -const AssertionResultIcon = styled.span` - margin-right: 8px; -`; - -const AssertionResultDetailsContainer = styled.div` - margin-bottom: 4px; -`; - -const AssertionResultErrorMessage = styled.div` - max-width: 250px; - margin-bottom: 4px; -`; - -const AssertionResultInitializingMessage = styled.div` - max-width: 250px; - margin-bottom: 4px; -`; - -type Props = { - timeRange: TimeRange; - results?: AssertionRunEventsResult | null; - platform?: DataPlatform | null; -}; - -export const AcrylAssertionResultsChartTimeline = ({ results, platform, timeRange }: Props) => { - const entityRegistry = useEntityRegistry(); - const completedRuns = - results?.runEvents?.filter((runEvent) => runEvent.status === AssertionRunStatus.Complete) || []; - - /** - * Data for the timeline of assertion results. - */ - const timelineData = - completedRuns - .filter((runEvent) => !!runEvent.result) - .map((runEvent) => { - const { result } = runEvent; - - if (!result) throw new Error('Completed assertion run event does not have a result.'); - - const resultTime = new Date(runEvent.timestampMillis); - const localTime = resultTime.toLocaleString(); - const gmtTime = resultTime.toUTCString(); - const resultUrl = result.externalUrl; - const isInitializing = result.type === AssertionResultType.Init; - const errorMessage = getResultErrorMessage(result); - const platformName = - (platform && entityRegistry.getDisplayName(EntityType.DataPlatform, platform)) || undefined; - - /** - * Create a "result" to render in the timeline chart. - */ - return { - time: runEvent.timestampMillis, - result: { - type: result.type, - resultUrl, - title: ( - <> - {getResultIcon(result.type)} - {getResultText(result.type)} - - ), - content: ( - <> - - - - {isInitializing && ( - - Collecting the information required to evaluate this assertion. - - )} - {errorMessage && ( - {errorMessage} - )} -
- - {localTime} - -
- {resultUrl && ( - - {platformName ? `View in ${platformName}` : 'View results'}{' '} - - - )} - - ), - }, - }; - }) || []; - - return ; -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionGroupHeader.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionGroupHeader.tsx deleted file mode 100644 index 81b4ef8462405f..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionGroupHeader.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { AssertionGroup } from '@app/entityV2/shared/tabs/Dataset/Validations/acrylTypes'; -import { getAssertionGroupSummaryIcon } from '@app/entityV2/shared/tabs/Dataset/Validations/acrylUtils'; - -const Container = styled.div` - display: flex; - align-items: center; - padding: 4px 0px; - &:hover { - cursor: pointer; - } -`; - -const TextContainer = styled.div` - display: flex; - align-items: center; - justify-content: left; - font-size: 14px; -`; - -const Title = styled(Typography.Text)` - && { - padding-bottom: 0px; - margin-bottom: 0px; - } -`; - -const Message = styled(Typography.Text)` - && { - font-size: 12px; - margin-left: 8px; - } -`; - -const SummaryIcon = styled.div` - margin-right: 16px; -`; - -type Props = { - group: AssertionGroup; -}; - -export const AssertionGroupHeader = ({ group }: Props) => { - const { summary } = group; - const summaryIcon = getAssertionGroupSummaryIcon(summary); - const inactiveCount = summary.totalAssertions - summary.total; - const summaryMessage = `${summary.passing} passing, ${summary.failing} failing${ - summary.erroring ? `, ${summary.erroring} errors` : '' - }${inactiveCount ? `, ${inactiveCount} inactive` : ''}`; - return ( - - {summaryIcon && {summaryIcon}} - - {group.icon} - {group.name} - {summaryMessage} - - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/AcryAssertionTypeSelect.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/AcryAssertionTypeSelect.tsx deleted file mode 100644 index 9f387c7fd77195..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/AcryAssertionTypeSelect.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react'; - -import { SimpleSelect } from '@src/alchemy-components'; - -type Option = { - label: string; - value: string; -}; - -type Props = { - options: Option[]; - selectedValue: string | undefined; - onSelect: (value: string) => void; -}; - -export function AcryAssertionTypeSelect({ options, selectedValue, onSelect }: Props) { - const selectedOption = options.find((option) => option.value === selectedValue) || { label: undefined }; - - const displayValue = selectedOption.label ? `Group ${selectedOption.label}` : 'Group'; - - return ( - { - if (value.length) { - onSelect(value[0]); - } else { - onSelect(''); - } - }} - placeholder={displayValue} - size="md" - showClear={false} - optionSwitchable - width={50} - /> - ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/GroupByTable.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/GroupByTable.tsx deleted file mode 100644 index 05a7774f6ad977..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/GroupByTable.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import { AssertionListTableRow } from '@app/entityV2/shared/tabs/Dataset/Validations/AssertionList/types'; -import { ANTD_GRAY } from '@src/app/entityV2/shared/constants'; - -const GroupContainer = styled.div` - background: #fafafa; - &&& .acryl-selected-assertions-table-row { - background-color: ${ANTD_GRAY[4]}; - } -`; - -const Row = styled.div` - display: flex; - width: 100%; - border-bottom: 1px solid #f0f0f0; - padding: 16px; -`; - -const Cell = styled.div<{ width?: string; minWidth?: string | null; paddingRight?: string | number }>` - width: ${(props) => props.width || 'auto'}; - min-width: ${(props) => props.minWidth || null}; - padding-right: ${(props) => props.paddingRight || '20px'}; - text-overflow: ellipsis; - overflow-wrap: break-word; -`; - -type AcrylAssertionGroupByComponentProps = { - groupData: AssertionListTableRow[]; - columns: any[]; - onRow: (record: any) => { - onClick: (_: any) => void; - }; - focusUrn?: string; - entityType: string; -}; - -export const GroupByTable = ({ - groupData, - columns, - onRow, - focusUrn, - entityType, -}: AcrylAssertionGroupByComponentProps) => { - return ( - - {groupData?.map((item) => ( - { - onRow(item)?.onClick(event); - }} - className={ - focusUrn === item.urn - ? `acryl-selected-${entityType}s-table-row` - : `acryl-${entityType}s-table-row` - } - > - {columns.map((column) => { - const isNameColumn = column?.key === 'name'; - const isActionColumn = column?.key === 'actions'; - const minWidth = isNameColumn ? 'min-content' : null; - return ( - column?.width && - column?.key && ( - - {column.render - ? column.render(item[column.dataIndex], item) - : item[column.dataIndex]} - - ) - ); - })} - - ))} - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/StyledComponents.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/StyledComponents.tsx deleted file mode 100644 index fee7afaa05de0c..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/StyledComponents.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@src/app/entityV2/shared/constants'; - -export const StyledTableContainer = styled.div` - table tr.acryl-selected-table-row { - background-color: ${ANTD_GRAY[4]}; - } - margin: 0px 12px 12px 12px; -`; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/constant.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/constant.ts index c8812129eb3402..06fadb30d963f2 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/constant.ts +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/constant.ts @@ -14,7 +14,7 @@ export const ASSERTION_DEFAULT_FILTERS = { }, }; -export const ASSERTION_GROUP_BY_FILTER_OPTIONS = [ +const ASSERTION_GROUP_BY_FILTER_OPTIONS = [ { label: 'Type', value: 'type' }, { label: 'Status', value: 'status' }, ]; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/hooks.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/hooks.tsx index 69cea262aff84c..8af894dc2e8dfa 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/hooks.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/hooks.tsx @@ -166,7 +166,7 @@ export const useAssertionsTableColumns = ({ contract, refetch }) => { }, [renderAssertionName, renderCategory, renderLastRun, renderTags, renderActions]); }; -export const usePinnedAssertionTableHeaderProps = () => { +const usePinnedAssertionTableHeaderProps = () => { // Dynamic height calculation const tableContainerRef = useRef(null); const [scrollY, setScrollY] = useState(0); diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/types.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/types.ts index 8b11bd39a730e4..06cdaca843502e 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/types.ts +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/types.ts @@ -12,7 +12,7 @@ import { TagAssociation, } from '@src/types.generated'; -export type EntityStagedForAssertion = { +type EntityStagedForAssertion = { urn: string; platform: DataPlatform; entityType: EntityType; @@ -54,7 +54,7 @@ export type AssertionListTableRow = { name?: string; }; -export type AssertionGroupExtended = Omit & { +type AssertionGroupExtended = Omit & { assertions: AssertionListTableRow[]; groupName?: JSX.Element; }; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/utils.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/utils.tsx index a7f7a15ec09e0a..165cc0d1ee5e1d 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/utils.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionList/utils.tsx @@ -117,7 +117,7 @@ const getGroupNameBySummary = (record) => { * @param entityType * @returns {AssertionBuilderSiblingOptions[]} */ -export const useSiblingOptionsForAssertionBuilder = ( +const useSiblingOptionsForAssertionBuilder = ( entityData: GenericEntityProperties | null, urn: string, entityType: EntityType, diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionMenu.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionMenu.tsx deleted file mode 100644 index e526176c0b7acb..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionMenu.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { Menu } from 'antd'; -import React from 'react'; - -import CopyUrnMenuItem from '@app/shared/share/items/CopyUrnMenuItem'; - -interface AssertionMenuProps { - urn: string; -} - -export default function AssertionMenu({ urn }: AssertionMenuProps) { - return ( - - - - ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionResultTimeline.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionResultTimeline.tsx deleted file mode 100644 index f2d6de3169130a..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/AssertionResultTimeline.tsx +++ /dev/null @@ -1,134 +0,0 @@ -import { Popover } from '@components'; -import { AxisBottom } from '@visx/axis'; -import { Group } from '@visx/group'; -import { scaleUtc } from '@visx/scale'; -import { Bar } from '@visx/shape'; -import { Maybe } from 'graphql/jsutils/Maybe'; -import React, { useMemo } from 'react'; - -import { ERROR_COLOR_HEX, FAILURE_COLOR_HEX, SUCCESS_COLOR_HEX } from '@components/theme/foundations/colors'; - -import { ANTD_GRAY } from '@app/entityV2/shared/constants'; -import { LinkWrapper } from '@app/shared/LinkWrapper'; - -import { AssertionResultType } from '@types'; - -export type AssertionResult = { - type: AssertionResultType; - title: React.ReactNode; - content: React.ReactNode; - resultUrl?: Maybe; -}; - -export type AssertionDataPoint = { - time: number; - result: AssertionResult; -}; - -export type TimeRange = { - startMs: number; - endMs: number; -}; - -type Props = { - data: Array; - timeRange: TimeRange; - width: number; -}; - -const INIT_COLOR_HEX = '#8C8C8C'; - -const getFillColor = (type: AssertionResultType) => { - switch (type) { - case AssertionResultType.Success: - return SUCCESS_COLOR_HEX; - case AssertionResultType.Failure: - return FAILURE_COLOR_HEX; - case AssertionResultType.Error: - return ERROR_COLOR_HEX; - case AssertionResultType.Init: - return INIT_COLOR_HEX; - default: - throw new Error(`Unsupported Assertion Result Type ${type} provided.`); - } -}; - -/** - * Assertion run results displayed on a horizontal timeline. - */ -export const AssertionResultTimeline = ({ data, timeRange, width }: Props) => { - const yMax = 60; - const left = 0; - - const xScale = useMemo( - () => - scaleUtc({ - domain: [new Date(timeRange.startMs), new Date(timeRange.endMs + 600000)], - range: [0, width], - }), - [timeRange, width], - ); - - const transformedData = data.map((result, i) => { - return { - index: i, - title: result.result.title, - content: result.result.content, - type: result.result.type, - time: result.time, - url: result.result.resultUrl, - }; - }); - - return ( - <> - - - {transformedData.map((d) => { - const barWidth = 8; - const barHeight = 18; - const barX = xScale(new Date(d.time)); - const barY = yMax - barHeight; - const fillColor = getFillColor(d.type); - return ( - - - - - - ); - })} - - v.toLocaleDateString('en-us', { month: 'short', day: 'numeric' })} - tickLabelProps={(_) => ({ - fontSize: 11, - angle: 0, - textAnchor: 'middle', - })} - /> - - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/Assertions.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/Assertions.tsx deleted file mode 100644 index a96c426c151f6f..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/Assertions.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import React, { useState } from 'react'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import { combineEntityDataWithSiblings } from '@app/entity/shared/siblingUtils'; -import { DatasetAssertionsList } from '@app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionsList'; -import { DatasetAssertionsSummary } from '@app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionsSummary'; -import { sortAssertions } from '@app/entityV2/shared/tabs/Dataset/Validations/assertionUtils'; -import { useIsSeparateSiblingsMode } from '@app/entityV2/shared/useIsSeparateSiblingsMode'; - -import { useGetDatasetAssertionsQuery } from '@graphql/dataset.generated'; -import { Assertion, AssertionResultType } from '@types'; - -/** - * Returns a status summary for the assertions associated with a Dataset. - */ -const getAssertionsStatusSummary = (assertions: Array) => { - const summary = { - failedRuns: 0, - succeededRuns: 0, - erroredRuns: 0, - totalRuns: 0, - totalAssertions: assertions.length, - }; - assertions.forEach((assertion) => { - if ((assertion.runEvents?.runEvents?.length || 0) > 0) { - const mostRecentRun = assertion.runEvents?.runEvents?.[0]; - const resultType = mostRecentRun?.result?.type; - if (AssertionResultType.Success === resultType) { - summary.succeededRuns++; - } - if (AssertionResultType.Failure === resultType) { - summary.failedRuns++; - } - if (AssertionResultType.Error === resultType) { - summary.erroredRuns++; - } - if (AssertionResultType.Init !== resultType) { - summary.totalRuns++; // only count assertions for which there is one completed run event, ignoring INIT statuses! - } - } - }); - return summary; -}; - -/** - * Component used for rendering the Validations Tab on the Dataset Page. - * - * TODO: Note that only the legacy DATASET assertions are supported for viewing as of today. - */ -// CAN DELETE -export const Assertions = () => { - const { urn, entityData } = useEntityData(); - const { data, refetch } = useGetDatasetAssertionsQuery({ variables: { urn }, fetchPolicy: 'cache-first' }); - const isHideSiblingMode = useIsSeparateSiblingsMode(); - - const combinedData = isHideSiblingMode ? data : combineEntityDataWithSiblings(data); - const [removedUrns, setRemovedUrns] = useState([]); - - const assertions = - (combinedData && combinedData.dataset?.assertions?.assertions?.map((assertion) => assertion as Assertion)) || - []; - const filteredAssertions = assertions.filter( - (assertion) => !removedUrns.includes(assertion.urn) && !!assertion.info?.datasetAssertion, - ); - - // Pre-sort the list of assertions based on which has been most recently executed. - assertions.sort(sortAssertions); - - return ( - <> - - {entityData && ( - { - // Hack to deal with eventual consistency. - setRemovedUrns([...removedUrns, assertionUrn]); - setTimeout(() => refetch(), 3000); - }} - /> - )} - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/BooleanTimeline.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/BooleanTimeline.tsx deleted file mode 100644 index 4718bd5dadd26f..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/BooleanTimeline.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import { Popover } from '@components'; -import { AxisBottom } from '@visx/axis'; -import { Group } from '@visx/group'; -import { scaleUtc } from '@visx/scale'; -import { Bar } from '@visx/shape'; -import React, { useMemo } from 'react'; - -import { FAILURE_COLOR_HEX, SUCCESS_COLOR_HEX } from '@components/theme/foundations/colors'; - -import { ANTD_GRAY } from '@app/entityV2/shared/constants'; - -export type BooleanResult = { - isSuccess: boolean; - title: React.ReactNode; - content: React.ReactNode; - resultUrl?: string; -}; - -export type BooleanDataPoint = { - time: number; - result: BooleanResult; -}; - -export type TimeRange = { - startMs: number; - endMs: number; -}; - -type Props = { - data: Array; - timeRange: TimeRange; - width: number; -}; - -/** - * True / false results displayed on a horizontal timeline. - */ -export const BooleanTimeline = ({ data, timeRange, width }: Props) => { - const yMax = 60; - const left = 0; - - const xScale = useMemo( - () => - scaleUtc({ - domain: [new Date(timeRange.startMs), new Date(timeRange.endMs + 600000)], - range: [0, width], - }), - [timeRange, width], - ); - - const transformedData = data.map((result, i) => { - return { - index: i, - title: result.result.title, - content: result.result.content, - isSuccess: result.result.isSuccess, - time: result.time, - }; - }); - - return ( - <> - - - {transformedData.map((d) => { - const barWidth = 8; - const barHeight = 18; - const barX = xScale(new Date(d.time)); - const barY = yMax - barHeight; - const fillColor = d.isSuccess ? SUCCESS_COLOR_HEX : FAILURE_COLOR_HEX; - return ( - - - - ); - })} - - v.toLocaleDateString('en-us', { month: 'short', day: 'numeric' })} - tickLabelProps={(_) => ({ - fontSize: 11, - angle: 0, - textAnchor: 'middle', - })} - /> - - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionDetails.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionDetails.tsx deleted file mode 100644 index a47696623f7917..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionDetails.tsx +++ /dev/null @@ -1,266 +0,0 @@ -import { ArrowRightOutlined } from '@ant-design/icons'; -import { Tooltip } from '@components'; -import { Typography } from 'antd'; -import { SelectValue } from 'antd/lib/select'; -import React, { useEffect, useState } from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entityV2/shared/constants'; -import PrefixedSelect from '@app/entityV2/shared/tabs/Dataset/Stats/historical/shared/PrefixedSelect'; -import { LOOKBACK_WINDOWS } from '@app/entityV2/shared/tabs/Dataset/Stats/lookbackWindows'; -import { BooleanDataPoint, BooleanTimeline } from '@app/entityV2/shared/tabs/Dataset/Validations/BooleanTimeline'; -import { DatasetAssertionResultDetails } from '@app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionResultDetails'; -import { - getResultColor, - getResultErrorMessage, - getResultIcon, - getResultText, -} from '@app/entityV2/shared/tabs/Dataset/Validations/assertionUtils'; -import { LinkWrapper } from '@app/shared/LinkWrapper'; -import { formatNumber } from '@app/shared/formatNumber'; -import { getFixedLookbackWindow, getLocaleTimezone } from '@app/shared/time/timeUtils'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useGetAssertionRunsLazyQuery } from '@graphql/assertion.generated'; -import { AssertionResultType, AssertionRunStatus, EntityType } from '@types'; - -const RESULT_CHART_WIDTH_PX = 800; - -const LastEvaluatedAtLabel = styled.div` - padding: 0; - margin: 0; - display: flex; - align-items: center; - color: ${ANTD_GRAY[7]}; -`; - -const AssertionResultIcon = styled.span` - margin-right: 8px; -`; - -const AssertionResultDetailsContainer = styled.div` - margin-bottom: 4px; -`; - -const AssertionResultErrorMessage = styled.div` - max-width: 250px; - margin-bottom: 4px; -`; - -const AssertionResultInitializingMessage = styled.div` - max-width: 250px; - margin-bottom: 4px; -`; - -const ContentContainer = styled.div` - width: 100%; - padding-left: 52px; -`; - -const EvaluationsDetails = styled.div` - width: ${RESULT_CHART_WIDTH_PX}px; - padding-top: 12px; -`; - -const EvaluationsHeader = styled.div` - display: flex; - justify-content: space-between; -`; - -const EvaluationsSummary = styled.div` - width: 300px; - display: flex; - align-items: center; - justify-content: left; -`; - -const EvaluationDateRange = styled(Typography.Text)` - margin-right: 20px; -`; - -const SucceededEvaluationsCount = styled.span` - margin-right: 12px; -`; - -const FailedEvaluationsCount = styled.span` - margin-right: 12px; -`; - -type Props = { - urn: string; - lastEvaluatedAtMillis?: number | undefined; -}; - -export const DatasetAssertionDetails = ({ urn, lastEvaluatedAtMillis }: Props) => { - const [getAssertionRuns, { data }] = useGetAssertionRunsLazyQuery({ fetchPolicy: 'cache-first' }); - const entityRegistry = useEntityRegistry(); - - /** - * Set default window for fetching assertion history. - */ - const [lookbackWindow, setLookbackWindow] = useState(LOOKBACK_WINDOWS.WEEK); - useEffect(() => { - getAssertionRuns({ - variables: { assertionUrn: urn, ...getFixedLookbackWindow(lookbackWindow.windowSize) }, - }); - }, [urn, lookbackWindow, getAssertionRuns]); - - /** - * Invoked when user selects new lookback window (e.g. 1 year) - */ - const onChangeLookbackWindow = (value: SelectValue) => { - const newLookbackWindow = Object.values(LOOKBACK_WINDOWS).filter((window) => window.text === value?.valueOf()); - setLookbackWindow(newLookbackWindow[0]); - }; - const selectedWindow = getFixedLookbackWindow(lookbackWindow.windowSize); - const selectedWindowTimeRange = { - startMs: selectedWindow.startTime, - endMs: selectedWindow.endTime, - }; - - const completeAssertionRunEvents = - data?.assertion?.runEvents?.runEvents?.filter( - (runEvent) => runEvent.status === AssertionRunStatus.Complete && runEvent.result, - ) || []; - - /** - * Last evaluated timestamp - */ - const lastEvaluatedAt = lastEvaluatedAtMillis - ? new Date(lastEvaluatedAtMillis) - : completeAssertionRunEvents.length > 0 && new Date(completeAssertionRunEvents[0].timestampMillis); - const localeTimezone = getLocaleTimezone(); - const lastEvaluatedTimeLocal = - (lastEvaluatedAt && - `Last evaluated on ${lastEvaluatedAt.toLocaleDateString()} at ${lastEvaluatedAt.toLocaleTimeString()} (${localeTimezone})`) || - 'No evaluations found'; - const lastEvaluatedTimeGMT = lastEvaluatedAt && lastEvaluatedAt.toUTCString(); - - /** - * Start and end date bounds for Chart - */ - const startDate = new Date(selectedWindowTimeRange.startMs).toLocaleDateString('en-us', { - month: 'short', - day: 'numeric', - }); - const endDate = new Date(selectedWindowTimeRange.endMs).toLocaleDateString('en-us', { - month: 'short', - day: 'numeric', - }); - - /** - * Success / Failure summary - */ - const succeededCount = data?.assertion?.runEvents?.succeeded; - const failedCount = data?.assertion?.runEvents?.failed; - - /** - * Data for the chart of assertion results. - */ - const assertionResultsChartData: BooleanDataPoint[] = - completeAssertionRunEvents.map((runEvent) => { - const { result } = runEvent; - - if (!result) throw new Error('Completed assertion run event does not have a result.'); - - const resultTime = new Date(runEvent.timestampMillis); - const localTime = resultTime.toLocaleString(); - const gmtTime = resultTime.toUTCString(); - const resultUrl: string | undefined = result.externalUrl?.valueOf(); - const isInitializing = result.type === AssertionResultType.Init; - const errorMessage = getResultErrorMessage(result); - const platformName = data?.assertion?.platform - ? entityRegistry.getDisplayName(EntityType.DataPlatform, data?.assertion?.platform) - : undefined; - - /** - * Create a "result" to render in the timeline chart. - */ - return { - time: runEvent.timestampMillis, - result: { - type: result.type, - isSuccess: result.type === AssertionResultType.Success, - resultUrl, - title: ( - <> - {getResultIcon(result.type)} - {getResultText(result.type)} - - ), - content: ( - <> - - - - {isInitializing && ( - - Collecting the information required to evaluate this assertion. - - )} - {errorMessage && {errorMessage}} -
- - {localTime} - -
- {resultUrl && ( - - {platformName ? `View in ${platformName}` : 'View results'} - - )} - - ), - }, - }; - }) || []; - - return ( - -
- Evaluations - - {lastEvaluatedTimeLocal} - - - - - - {startDate} - {endDate} - -
- - - {formatNumber(succeededCount)} - {' '} - passed - - - - {formatNumber(failedCount)} - {' '} - failed - -
-
- window.text)} - value={lookbackWindow.text} - setValue={onChangeLookbackWindow} - /> -
- -
-
-
- ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionLogicModal.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionLogicModal.tsx index 68d71d0b6891d6..d2551c29943665 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionLogicModal.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionLogicModal.tsx @@ -3,7 +3,7 @@ import React from 'react'; import Query from '@app/entityV2/shared/tabs/Dataset/Queries/Query'; -export type AssertionsSummary = { +type AssertionsSummary = { totalAssertions: number; totalRuns: number; failedRuns: number; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionResultDetails.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionResultDetails.tsx deleted file mode 100644 index 1edde5647f9d2f..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionResultDetails.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Typography } from 'antd'; -import React from 'react'; - -import { AssertionResult } from '@types'; - -type Props = { - result: AssertionResult; -}; - -export const DatasetAssertionResultDetails = ({ result }: Props) => { - const maybeActualValue = result.actualAggValue; - const maybeUnexpectedCount = result.unexpectedCount; - const maybeRowCount = result.rowCount; - const maybeNativeResults = result.nativeResults; - return ( - <> - {maybeActualValue !== null && maybeActualValue !== undefined && ( -
- Actual: {maybeActualValue} -
- )} - {maybeUnexpectedCount !== null && maybeUnexpectedCount !== undefined && ( -
- Invalid Count: {maybeUnexpectedCount} -
- )} - {maybeRowCount !== null && maybeRowCount !== undefined && ( -
- Row Count: {maybeRowCount} -
- )} - {maybeNativeResults && ( -
- {maybeNativeResults.map((entry) => ( -
- {entry.key}: {entry.value} -
- ))} -
- )} - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionsList.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionsList.tsx deleted file mode 100644 index 305562eaf8b1e4..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionsList.tsx +++ /dev/null @@ -1,197 +0,0 @@ -import { DeleteOutlined, DownOutlined, MoreOutlined, RightOutlined, StopOutlined } from '@ant-design/icons'; -import { Tooltip } from '@components'; -import { Button, Dropdown, Empty, Image, Modal, Tag, Typography, message } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { StyledTable } from '@app/entityV2/shared/components/styled/StyledTable'; -import AssertionMenu from '@app/entityV2/shared/tabs/Dataset/Validations/AssertionMenu'; -import { DatasetAssertionDescription } from '@app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionDescription'; -import { DatasetAssertionDetails } from '@app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionDetails'; -import { - getResultColor, - getResultIcon, - getResultText, -} from '@app/entityV2/shared/tabs/Dataset/Validations/assertionUtils'; -import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; - -import { useDeleteAssertionMutation } from '@graphql/assertion.generated'; -import { Assertion, AssertionRunStatus } from '@types'; - -const ResultContainer = styled.div` - display: flex; - align-items: center; - justify-content: left; -`; - -const ResultTypeText = styled(Typography.Text)` - margin-left: 8px; -`; - -const ActionButtonContainer = styled.div` - display: flex; - justify-content: right; - align-items: center; -`; - -const PlatformContainer = styled.div` - margin-right: 8px; -`; - -const StyledMoreOutlined = styled(MoreOutlined)` - font-size: 18px; -`; - -type Props = { - assertions: Array; - onDelete?: (urn: string) => void; -}; - -/** - * A list of assertions displaying their most recent run status, their human-readable - * description, and platform. - * - * Currently this component supports rendering Dataset Assertions only. - */ -export const DatasetAssertionsList = ({ assertions, onDelete }: Props) => { - const [deleteAssertionMutation] = useDeleteAssertionMutation(); - - const deleteAssertion = async (urn: string) => { - try { - await deleteAssertionMutation({ - variables: { urn }, - }); - message.success({ content: 'Removed assertion.', duration: 2 }); - } catch (e: unknown) { - message.destroy(); - if (e instanceof Error) { - message.error({ content: `Failed to remove assertion: \n ${e.message || ''}`, duration: 3 }); - } - } - onDelete?.(urn); - }; - - const onDeleteAssertion = (urn: string) => { - Modal.confirm({ - title: `Confirm Assertion Removal`, - content: `Are you sure you want to remove this assertion from the dataset?`, - onOk() { - deleteAssertion(urn); - }, - onCancel() {}, - okText: 'Yes', - maskClosable: true, - closable: true, - }); - }; - - const assertionsTableData = assertions.map((assertion) => ({ - urn: assertion.urn, - type: assertion.info?.type, - platform: assertion.platform, - datasetAssertionInfo: assertion.info?.datasetAssertion, - description: assertion.info?.description, - lastExecTime: assertion.runEvents?.runEvents?.length && assertion.runEvents.runEvents[0].timestampMillis, - lastExecResult: - assertion.runEvents?.runEvents?.length && - assertion.runEvents.runEvents[0].status === AssertionRunStatus.Complete && - assertion.runEvents.runEvents[0].result?.type, - })); - - const assertionsTableCols = [ - { - title: '', - dataIndex: '', - key: '', - render: (_, record: any) => { - const executionDate = record.lastExecTime && new Date(record.lastExecTime); - const localTime = executionDate && `${executionDate.toLocaleDateString()}`; - const resultColor = (record.lastExecResult && getResultColor(record.lastExecResult)) || 'default'; - const resultText = (record.lastExecResult && getResultText(record.lastExecResult)) || 'No Evaluations'; - const resultIcon = (record.lastExecResult && getResultIcon(record.lastExecResult)) || ; - const { description } = record; - return ( - -
- - - {resultIcon} - {resultText} - - -
- -
- ); - }, - }, - { - title: '', - dataIndex: '', - key: '', - render: (_, record: any) => ( - - - - {(record.platform.properties?.logoUrl && ( - - )) || ( - - {record.platform.properties?.displayName || - capitalizeFirstLetterOnly(record.platform.name)} - - )} - - - - } trigger={['click']}> - - - - ), - }, - ]; - - return ( - <> - , - }} - expandable={{ - defaultExpandAllRows: false, - expandRowByClick: true, - expandedRowRender: (record) => { - return ; - }, - expandIcon: ({ expanded, onExpand, record }: any) => - expanded ? ( - onExpand(record, e)} /> - ) : ( - onExpand(record, e)} /> - ), - }} - showHeader={false} - pagination={false} - /> - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionsSummary.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionsSummary.tsx deleted file mode 100644 index 3ef24da77bbb42..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/DatasetAssertionsSummary.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import { CheckCircleFilled, CloseCircleFilled, ExclamationCircleFilled, StopOutlined } from '@ant-design/icons'; -import { Tooltip } from '@components'; -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { ERROR_COLOR_HEX, FAILURE_COLOR_HEX, SUCCESS_COLOR_HEX } from '@components/theme/foundations/colors'; - -import { ANTD_GRAY } from '@app/entityV2/shared/constants'; - -const SummaryHeader = styled.div` - width: 100%; - padding-left: 40px; - padding-top: 20px; - padding-bottom: 20px; - display: flex; - align-items: center; - border-bottom: 1px solid ${ANTD_GRAY[4.5]}; -`; - -const SummaryContainer = styled.div``; - -const SummaryMessage = styled.div` - display: inline-block; - margin-left: 20px; -`; - -const SummaryTitle = styled(Typography.Title)` - && { - padding-bottom: 0px; - margin-bottom: 0px; - } -`; - -export type AssertionsSummary = { - totalAssertions: number; - totalRuns: number; - failedRuns: number; - succeededRuns: number; - erroredRuns: number; -}; - -type Props = { - summary: AssertionsSummary; -}; - -const getSummaryIcon = (summary: AssertionsSummary) => { - if (summary.totalRuns === 0) { - return ; - } - if (summary.succeededRuns === summary.totalRuns) { - return ; - } - if (summary.erroredRuns > 0) { - return ; - } - return ; -}; - -const getSummaryMessage = (summary: AssertionsSummary) => { - if (summary.totalRuns === 0) { - return 'No assertions have run'; - } - if (summary.succeededRuns === summary.totalRuns) { - return 'All assertions are passing'; - } - if (summary.erroredRuns > 0) { - return 'An error is preventing some assertions from running'; - } - if (summary.failedRuns === summary.totalRuns) { - return 'All assertions are failing'; - } - return 'Some assertions are failing'; -}; - -export const DatasetAssertionsSummary = ({ summary }: Props) => { - const summaryIcon = getSummaryIcon(summary); - const summaryMessage = getSummaryMessage(summary); - const errorMessage = summary.erroredRuns - ? `, ${summary.erroredRuns} error${summary.erroredRuns > 1 ? 's' : ''}` - : ''; - const inactiveAssertionsCount = summary.totalAssertions - summary.totalRuns; - const inactiveAssertionsMessage = inactiveAssertionsCount ? `, ${inactiveAssertionsCount} inactive.` : '.'; - const subtitleMessage = `${summary.succeededRuns} successful assertions, ${summary.failedRuns} failed assertions`; - return ( - - - -
- {summaryIcon} - - {summaryMessage} - - {subtitleMessage} - {errorMessage} - {inactiveAssertionsMessage} - - -
-
-
-
- ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/FreshnessAssertionDescription.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/FreshnessAssertionDescription.tsx index 8b5bf837259e1c..fa4eee45d08539 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/FreshnessAssertionDescription.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/FreshnessAssertionDescription.tsx @@ -16,7 +16,7 @@ type Props = { monitorSchedule?: Maybe; }; -export const getCronAsLabel = (cronSchedule: CronSchedule) => { +const getCronAsLabel = (cronSchedule: CronSchedule) => { const { cron, timezone } = cronSchedule; if (!cron) { return ''; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/ValidationsTab.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/ValidationsTab.tsx deleted file mode 100644 index 23579643231e1a..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/ValidationsTab.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import { FileDoneOutlined, FileProtectOutlined } from '@ant-design/icons'; -import { Button } from 'antd'; -import React, { useEffect } from 'react'; -import { useHistory, useLocation } from 'react-router'; -import styled from 'styled-components'; - -import { useEntityData } from '@app/entity/shared/EntityContext'; -import TabToolbar from '@app/entityV2/shared/components/styled/TabToolbar'; -import { ANTD_GRAY } from '@app/entityV2/shared/constants'; -import { TestResults } from '@app/entityV2/shared/tabs/Dataset/Governance/TestResults'; -import { Assertions } from '@app/entityV2/shared/tabs/Dataset/Validations/Assertions'; -import { useGetValidationsTab } from '@app/entityV2/shared/tabs/Dataset/Validations/useGetValidationsTab'; - -const TabTitle = styled.span` - margin-left: 4px; -`; - -const TabButton = styled(Button)<{ selected: boolean }>` - background-color: ${(props) => (props.selected && ANTD_GRAY[3]) || 'none'}; - margin-left: 4px; -`; - -enum TabPaths { - ASSERTIONS = 'Assertions', - TESTS = 'Tests', -} - -const DEFAULT_TAB = TabPaths.ASSERTIONS; - -/** - * Component used for rendering the Entity Validations Tab. - */ - -// CAN DELETE -export const ValidationsTab = () => { - const { entityData } = useEntityData(); - const history = useHistory(); - const { pathname } = useLocation(); - - const totalAssertions = (entityData as any)?.assertions?.total; - const passingTests = (entityData as any)?.testResults?.passing || []; - const maybeFailingTests = (entityData as any)?.testResults?.failing || []; - const totalTests = maybeFailingTests.length + passingTests.length; - - const { selectedTab, basePath } = useGetValidationsTab(pathname, Object.values(TabPaths)); - - // If no tab was selected, select a default tab. - useEffect(() => { - if (!selectedTab) { - // Route to the default tab. - history.replace(`${basePath}/${DEFAULT_TAB}`); - } - }, [selectedTab, basePath, history]); - - /** - * The top-level Toolbar tabs to display. - */ - const tabs = [ - { - title: ( - <> - - Assertions ({totalAssertions}) - - ), - path: TabPaths.ASSERTIONS, - disabled: false, - content: , - }, - { - title: ( - <> - - Tests ({totalTests}) - - ), - path: TabPaths.TESTS, - disabled: totalTests === 0, - content: , - }, - ]; - - return ( - <> - -
- {tabs.map((tab) => ( - history.replace(`${basePath}/${tab.path}`)} - > - {tab.title} - - ))} -
-
- {tabs.filter((tab) => tab.path === selectedTab).map((tab) => tab.content)} - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/acrylUtils.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/acrylUtils.tsx index 047bfd5f15c783..e7289d31929c2e 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/acrylUtils.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/acrylUtils.tsx @@ -137,7 +137,7 @@ export const getAssertionGroupName = (type: string): string => { return ASSERTION_TYPE_TO_INFO.has(type) ? ASSERTION_TYPE_TO_INFO.get(type).name : type; }; -export const getAssertionGroupTypeIcon = (type: string) => { +const getAssertionGroupTypeIcon = (type: string) => { return ASSERTION_TYPE_TO_INFO.has(type) ? ASSERTION_TYPE_TO_INFO.get(type).icon : ; }; @@ -187,7 +187,7 @@ export const getAssertionsSummary = (assertions: Assertion[]): AssertionStatusSu * TODO: We will remove this mapping code once we replace the OSS legacy assertions summary with the new * format. */ -export const getLegacyAssertionsSummary = (assertions: Assertion[]) => { +const getLegacyAssertionsSummary = (assertions: Assertion[]) => { const newSummary = getAssertionsSummary(assertions); return { failedRuns: newSummary.failing, @@ -241,7 +241,7 @@ export const createAssertionGroups = (assertions: Array): AssertionGr }; // TODO: Make this the default inside DatasetAssertionsSummary.tsx. -export const getAssertionGroupSummaryIcon = (summary: AssertionStatusSummary) => { +const getAssertionGroupSummaryIcon = (summary: AssertionStatusSummary) => { if (summary.total === 0) { return null; } @@ -255,7 +255,7 @@ export const getAssertionGroupSummaryIcon = (summary: AssertionStatusSummary) => }; // TODO: Make this the default inside DatasetAssertionsSummary.tsx. -export const getAssertionGroupSummaryMessage = (summary: AssertionStatusSummary) => { +const getAssertionGroupSummaryMessage = (summary: AssertionStatusSummary) => { if (summary.total === 0) { return 'No assertions have run'; } @@ -276,7 +276,7 @@ export const getAssertionGroupSummaryMessage = (summary: AssertionStatusSummary) * * @param schedule a cron schedule */ -export const getNextScheduleEvaluationTimeMs = (schedule: CronSchedule) => { +const getNextScheduleEvaluationTimeMs = (schedule: CronSchedule) => { try { const interval = cronParser.parseExpression(schedule.cron, { tz: schedule.timezone }); const nextDate = interval.next().toDate(); // Get next date as JavaScript Date object @@ -295,7 +295,7 @@ export const getNextScheduleEvaluationTimeMs = (schedule: CronSchedule) => { * @param schedule a cron schedule * @param maybeFromDateTS */ -export const getPreviousScheduleEvaluationTimeMs = (schedule: CronSchedule, maybeFromDateTS?: number) => { +const getPreviousScheduleEvaluationTimeMs = (schedule: CronSchedule, maybeFromDateTS?: number) => { try { const interval = cronParser.parseExpression(schedule.cron, { tz: schedule.timezone }); if (typeof maybeFromDateTS !== 'undefined') { @@ -310,7 +310,7 @@ export const getPreviousScheduleEvaluationTimeMs = (schedule: CronSchedule, mayb return undefined; } }; -export const getAssertionTypesForEntityType = (entityType: EntityType, monitorsConnectionForEntityExists: boolean) => { +const getAssertionTypesForEntityType = (entityType: EntityType, monitorsConnectionForEntityExists: boolean) => { return ASSERTION_INFO.filter((type) => type.entityTypes.includes(entityType)).map((type) => ({ ...type, enabled: type.enabled && (!type.requiresConnectionSupportedByMonitors || monitorsConnectionForEntityExists), diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/builder/hooks.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/builder/hooks.ts index 5f6553c692920b..61aa3650b1bfcd 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/builder/hooks.ts +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/builder/hooks.ts @@ -69,7 +69,7 @@ const OPEN_ASSERTION_BUILDER_QUERY_PARAM = 'open_assertion_builder'; * @param {Function} onOpenAssertionBuilder - Function to open assertion builder. * @returns {Object} Object containing the 'open_assertion_builder' from the URL. */ -export const useOpenAssertionBuilder = (onOpenAssertionBuilder: () => void) => { +const useOpenAssertionBuilder = (onOpenAssertionBuilder: () => void) => { const location = useLocation(); const history = useHistory(); const openBuilderParam = getQueryParams(OPEN_ASSERTION_BUILDER_QUERY_PARAM, location); @@ -106,7 +106,7 @@ export const useOpenAssertionBuilder = (onOpenAssertionBuilder: () => void) => { * - expandedRowKeys: Array of currently expanded row keys. * - setExpandedRowKeys: Function to manually set the expanded row keys. */ -export const useExpandedRowKeys = (groups, { isGroupBy }: { isGroupBy: boolean }) => { +const useExpandedRowKeys = (groups, { isGroupBy }: { isGroupBy: boolean }) => { const location = useLocation(); const assertionUrnParam = new URLSearchParams(location.search).get('assertion_urn'); const [expandedRowKeys, setExpandedRowKeys] = useState([]); diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/actions/styledComponents.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/actions/styledComponents.tsx deleted file mode 100644 index 5316a8f0c00d77..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/actions/styledComponents.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import styled from 'styled-components'; - -// Helper functions to simplify logic -const getBackgroundColor = ({ isExpandedView, primary }: { isExpandedView?: boolean; primary?: boolean }) => { - if (isExpandedView) return 'inherit'; - return primary ? '#5280e8' : '#ffffff'; -}; - -const getColor = ({ isExpandedView, primary }: { isExpandedView?: boolean; primary?: boolean }) => { - if (primary) return '#fff'; - return isExpandedView ? '#000' : '#5280e8'; -}; - -const getBorder = ({ isExpandedView, primary }: { isExpandedView?: boolean; primary?: boolean }) => { - if (isExpandedView) return 'none'; - return primary ? '1px solid #5280e8' : '1px solid #f0f0f0'; -}; - -export const ActionItemButton = styled.button<{ disabled?: boolean; primary?: boolean; isExpandedView?: boolean }>` - border-radius: ${(props) => (props.isExpandedView ? `0px` : `20px`)}; - width: 28px; - height: 28px; - margin: ${(props) => (props.isExpandedView ? `0px` : `0px 4px`)}; - padding: 0px; - display: flex; - align-items: center; - justify-content: center; - overflow: hidden; - background-color: ${(props) => getBackgroundColor(props)}; - color: ${(props) => getColor(props)}; - box-shadow: none; - cursor: ${(props) => (props.disabled ? 'not-allowed' : 'pointer')}; - &&:hover { - ${(props) => !props.disabled && 'opacity: 0.8;'} - } - ${(props) => props.disabled && 'opacity: 0.5'}; - border: ${(props) => getBorder(props)}; -`; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/popoverUtils.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/popoverUtils.ts deleted file mode 100644 index e69de29bb2d1d6..00000000000000 diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/ColumnMetricAssertionsResultsGraph.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/ColumnMetricAssertionsResultsGraph.tsx deleted file mode 100644 index e69de29bb2d1d6..00000000000000 diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/ColumnValueAssertionsResultsGraph.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/ColumnValueAssertionsResultsGraph.tsx deleted file mode 100644 index e69de29bb2d1d6..00000000000000 diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/CustomSqlAssertionsResultsGraph.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/CustomSqlAssertionsResultsGraph.tsx deleted file mode 100644 index e69de29bb2d1d6..00000000000000 diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/FreshnessAssertionsResultsGraph.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/FreshnessAssertionsResultsGraph.tsx deleted file mode 100644 index e69de29bb2d1d6..00000000000000 diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/VolumeAssertionResultsGraph.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/VolumeAssertionResultsGraph.tsx deleted file mode 100644 index e69de29bb2d1d6..00000000000000 diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/charts/types.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/charts/types.ts index 62814249ba71e3..77d6d6e05ff619 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/charts/types.ts +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/charts/types.ts @@ -2,7 +2,7 @@ import { Maybe } from 'graphql/jsutils/Maybe'; import { Assertion, AssertionResultType, AssertionRunEvent } from '@types'; -export type AssertionResult = { +type AssertionResult = { type: AssertionResultType; resultUrl?: Maybe; yValue?: number; // for checks with varying y-values diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/charts/utils.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/charts/utils.ts index 639d73309609df..46366b6fc5bc68 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/charts/utils.ts +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/charts/utils.ts @@ -8,12 +8,12 @@ import { import { AssertionInfo, AssertionResultType, AssertionType, Maybe } from '@types'; export const ACCENT_COLOR_HEX = '#222222'; -export const EXTRA_HIGHLIGHT_COLOR_HEX = '#4050E7'; -export const SUCCESS_COLOR_HEX = '#52C41A'; -export const FAILURE_COLOR_HEX = '#F5222D'; -export const ERROR_COLOR_HEX = '#FAAD14'; -export const INIT_COLOR_HEX = '#8C8C8C'; -export const EXPECTED_RANGE_SHADE_COLOR = '#11d469'; +const EXTRA_HIGHLIGHT_COLOR_HEX = '#4050E7'; +const SUCCESS_COLOR_HEX = '#52C41A'; +const FAILURE_COLOR_HEX = '#F5222D'; +const ERROR_COLOR_HEX = '#FAAD14'; +const INIT_COLOR_HEX = '#8C8C8C'; +const EXPECTED_RANGE_SHADE_COLOR = '#11d469'; export const getFillColor = (type: AssertionResultType) => { switch (type) { @@ -36,7 +36,7 @@ export const getFillColor = (type: AssertionResultType) => { * @param maxY * @returns {number[]} */ -export function generateYScaleTickValues(minY: number, maxY: number): number[] { +function generateYScaleTickValues(minY: number, maxY: number): number[] { return [minY, maxY]; } @@ -109,7 +109,7 @@ export function getCustomTimeScaleTickValue(v, timeRange) { return v.toLocaleDateString('en-us', { month: 'short', day: 'numeric' }); } -export const getBestChartTypeForAssertion = ( +const getBestChartTypeForAssertion = ( assertionInfo?: AssertionInfo | Maybe, ): AssertionChartType => { switch (assertionInfo?.type) { @@ -134,7 +134,7 @@ export const getBestChartTypeForAssertion = ( * @param timestampMillisModifiers * @returns {AssertionDataPoint[]} */ -export const duplicateDataPointsAcrossBufferedTimeRange = ( +const duplicateDataPointsAcrossBufferedTimeRange = ( dataPoint: AssertionDataPoint, timestampMillisBuffer: number, ): AssertionDataPoint[] => { diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/transformers.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/transformers.ts index f0ded496291551..7c007160301920 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/transformers.ts +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/transformers.ts @@ -21,7 +21,7 @@ import { * @param runEvent * @returns {number | undefined} */ -export const tryGetYValueForChartFromAssertionRunEvent = (): number | undefined => { +const tryGetYValueForChartFromAssertionRunEvent = (): number | undefined => { return tryGetPrimaryMetricValueFromAssertionRunEvent(); }; @@ -30,7 +30,7 @@ export const tryGetYValueForChartFromAssertionRunEvent = (): number | undefined * @param runEvents * @returns {AssertionDataPoint[]} */ -export const getAssertionDataPointsFromRunEvents = (runEvents: AssertionRunEvent[]): AssertionDataPoint[] => { +const getAssertionDataPointsFromRunEvents = (runEvents: AssertionRunEvent[]): AssertionDataPoint[] => { return ( runEvents .filter((runEvent) => !!runEvent.result) @@ -62,7 +62,7 @@ export const getAssertionDataPointsFromRunEvents = (runEvents: AssertionRunEvent * @param assertionInfo * @returns {number | undefined} */ -export const tryGetYAxisLabelForChartFromAssertionInfo = ( +const tryGetYAxisLabelForChartFromAssertionInfo = ( assertionInfo?: AssertionInfo | Maybe, ): string | undefined => { let label: string | undefined; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/utils.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/utils.ts index 1c8471f56e9199..8ef72581138ce7 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/utils.ts +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/result/timeline/utils.ts @@ -6,15 +6,15 @@ const ONE_HOUR_IN_MS = 60 * 60 * 1000; // Milliseconds in one hour const ONE_DAY_IN_MS = 24 * ONE_HOUR_IN_MS; // Milliseconds in one day const ONE_WEEK_IN_MS = 7 * ONE_DAY_IN_MS; // Milliseconds in one week -export function isLessThanOneDay(timeRange) { +function isLessThanOneDay(timeRange) { return timeRange.endMs - timeRange.startMs <= ONE_DAY_IN_MS; } -export function isLessThanOneHour(timeRange) { +function isLessThanOneHour(timeRange) { return timeRange.endMs - timeRange.startMs <= ONE_HOUR_IN_MS; } -export function isGreaterThanOneYear(timeRange) { +function isGreaterThanOneYear(timeRange) { return timeRange.endMs - timeRange.startMs >= 365 * ONE_DAY_IN_MS; } diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/shared/DetailedErrorMessage.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/shared/DetailedErrorMessage.tsx deleted file mode 100644 index d95b5c75050fef..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/shared/DetailedErrorMessage.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entityV2/shared/constants'; -import { getDetailedErrorMessage } from '@app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/shared/resultMessageUtils'; - -import { AssertionRunEvent } from '@types'; - -const Container = styled.div` - padding: 4px; -`; - -const Row = styled.div` - display: flex; - align-items: start; - justify-content: start; - padding: 4px 8px; -`; - -const Title = styled.div` - font-weight: bold; - margin-right: 8px; - font-size: 16px; -`; - -const Message = styled.div` - color: ${ANTD_GRAY[8]}; -`; - -type Props = { - run: AssertionRunEvent; -}; - -export const DetailedErrorMessage = ({ run }: Props) => { - const type = run?.result?.error?.type; - const message = getDetailedErrorMessage(run); - return ( - - - {type} - - {message && ( - - {message} - - )} - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/shared/DetailedErrorMessageTooltip.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/shared/DetailedErrorMessageTooltip.tsx deleted file mode 100644 index bc150f1b3844d5..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/shared/DetailedErrorMessageTooltip.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { InfoCircleOutlined } from '@ant-design/icons'; -import { Popover } from '@components'; -import { TooltipPlacement } from 'antd/lib/tooltip'; -import React from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entityV2/shared/constants'; -import { DetailedErrorMessage } from '@app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/shared/DetailedErrorMessage'; - -import { AssertionRunEvent } from '@types'; - -const StyledInfoCircleOutlined = styled(InfoCircleOutlined)` - margin-left: 8px; - font-size: 12px; - color: ${ANTD_GRAY[7]}; -`; - -type Props = { - run: AssertionRunEvent; - placement?: TooltipPlacement; -}; - -export const DetailedErrorMessageTooltip = ({ run, placement = 'bottom' }: Props) => { - return ( - } - > - - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/shared/assertionUtils.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/shared/assertionUtils.ts deleted file mode 100644 index 4d92f119be5bcb..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/shared/assertionUtils.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { Assertion, AssertionSourceType, AssertionType } from '@types'; - -export enum AssertionEditabilityScopeType { - FULL = 'FULL', - ACTIONS_AND_DESCRIPTION = 'ACTIONS_AND_DESCRIPTION', - ACTIONS_ONLY = 'ACTIONS_ONLY', - NONE = 'NONE', -} - -// ------- NOTE: we take the lowest permission of the union of (AssertType, AssertionSourceType) from the maps below ------- // -const ASSERTION_TYPE_TO_EDITING_SCOPE: { [type in AssertionType]: AssertionEditabilityScopeType } = { - [AssertionType.Custom]: AssertionEditabilityScopeType.FULL, - [AssertionType.Field]: AssertionEditabilityScopeType.FULL, - [AssertionType.Freshness]: AssertionEditabilityScopeType.FULL, - [AssertionType.Sql]: AssertionEditabilityScopeType.FULL, - [AssertionType.Volume]: AssertionEditabilityScopeType.FULL, - [AssertionType.DataSchema]: AssertionEditabilityScopeType.FULL, - [AssertionType.Dataset]: AssertionEditabilityScopeType.ACTIONS_AND_DESCRIPTION, - [AssertionType.Custom]: AssertionEditabilityScopeType.ACTIONS_AND_DESCRIPTION, -}; -const SOURCE_TYPE_TO_EDITING_SCOPE: { [type in AssertionSourceType]: AssertionEditabilityScopeType } = { - [AssertionSourceType.Native]: AssertionEditabilityScopeType.FULL, - [AssertionSourceType.External]: AssertionEditabilityScopeType.ACTIONS_AND_DESCRIPTION, - [AssertionSourceType.Inferred]: AssertionEditabilityScopeType.ACTIONS_ONLY, -}; - -// Scope types that unlock the certain editing abilities (broadest to narrowest) -const TIERED_SCOPE_TYPES_MAP = { - FULL: [AssertionEditabilityScopeType.FULL], - ACTIONS_AND_DESCRIPTION: [ - AssertionEditabilityScopeType.ACTIONS_AND_DESCRIPTION, - AssertionEditabilityScopeType.FULL, - ], - ACTIONS_ONLY: [ - AssertionEditabilityScopeType.ACTIONS_ONLY, - AssertionEditabilityScopeType.ACTIONS_AND_DESCRIPTION, - AssertionEditabilityScopeType.FULL, - ], -}; - -/** - * Gets the edabilityType of an asseriton - * @param assertion - * @returns {AssertionEditabilityScopeType} - */ -export const getAssertionEditabilityType = (assertion: Assertion): AssertionEditabilityScopeType => { - const assertionType = assertion.info?.type; - const assertionSourceType = assertion.info?.source?.type ?? AssertionSourceType.External; // NOTE: null==External since some of our integration connectors actually do not and historically have not produced this field - if (!assertionType) { - return AssertionEditabilityScopeType.NONE; - } - - // 1. Full editing - const isSourceTypeValidForFullEditing = TIERED_SCOPE_TYPES_MAP.FULL.includes( - SOURCE_TYPE_TO_EDITING_SCOPE[assertionSourceType], - ); - const isAssertionTypeValidForFullEditing = TIERED_SCOPE_TYPES_MAP.FULL.includes( - ASSERTION_TYPE_TO_EDITING_SCOPE[assertionType], - ); - if (isSourceTypeValidForFullEditing && isAssertionTypeValidForFullEditing) { - return AssertionEditabilityScopeType.FULL; - } - - // 2. Actions and description editing - const isSourceTypeValidForActionAndDescriptionEditing = TIERED_SCOPE_TYPES_MAP.ACTIONS_AND_DESCRIPTION.includes( - SOURCE_TYPE_TO_EDITING_SCOPE[assertionSourceType], - ); - const isAssertionTypeValidForActionAndDescriptionEditing = TIERED_SCOPE_TYPES_MAP.ACTIONS_AND_DESCRIPTION.includes( - ASSERTION_TYPE_TO_EDITING_SCOPE[assertionType], - ); - if (isSourceTypeValidForActionAndDescriptionEditing && isAssertionTypeValidForActionAndDescriptionEditing) { - return AssertionEditabilityScopeType.ACTIONS_AND_DESCRIPTION; - } - - // 3. Actions only editing - const isSourceTypeValidForActionOnlyEditing = TIERED_SCOPE_TYPES_MAP.ACTIONS_ONLY.includes( - SOURCE_TYPE_TO_EDITING_SCOPE[assertionSourceType], - ); - const isAssertionTypeValidForActionOnlyEditing = TIERED_SCOPE_TYPES_MAP.ACTIONS_ONLY.includes( - ASSERTION_TYPE_TO_EDITING_SCOPE[assertionType], - ); - if (isSourceTypeValidForActionOnlyEditing && isAssertionTypeValidForActionOnlyEditing) { - return AssertionEditabilityScopeType.ACTIONS_ONLY; - } - - return AssertionEditabilityScopeType.NONE; -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/shared/constants.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/shared/constants.ts index b8884a7e6e35b4..5d5ac1cf6471bb 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/shared/constants.ts +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/shared/constants.ts @@ -33,7 +33,7 @@ export const ASSERTION_NATIVE_RESULTS_KEYS_BY_ASSERTION_TYPE = { }, }; -export const ASSERTION_OPERATOR_DESCRIPTIONS_REQUIRING_SUFFIX = [ +const ASSERTION_OPERATOR_DESCRIPTIONS_REQUIRING_SUFFIX = [ AssertionStdOperator.EqualTo, AssertionStdOperator.NotEqualTo, AssertionStdOperator.Contain, diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/shared/resultExtractionUtils.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/shared/resultExtractionUtils.ts index 93b2933234aa93..80ede6d45a9315 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/shared/resultExtractionUtils.ts +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/shared/resultExtractionUtils.ts @@ -54,7 +54,7 @@ const calculateExpectedNumericalValueWithPreviousNumericalValue = ( * @param key * @returns {number | undefined} */ -export function tryExtractNumericalValueFromNativeResults( +function tryExtractNumericalValueFromNativeResults( nativeResults: Maybe | undefined, key: string, ): number | undefined { @@ -68,7 +68,7 @@ export function tryExtractNumericalValueFromNativeResults( * @param key * @returns {number | undefined} */ -export function tryExtractArrayValueFromNativeResults( +function tryExtractArrayValueFromNativeResults( nativeResults: Maybe | undefined, key: string, ): any[] | undefined { @@ -76,7 +76,7 @@ export function tryExtractArrayValueFromNativeResults( return parseJsonArrayOrDefault(maybeValue, undefined); } -export function tryExtractNumericalValueFromAssertionStdParameter( +function tryExtractNumericalValueFromAssertionStdParameter( param?: Maybe, ): number | undefined { let maybeNumber: undefined | number; @@ -87,13 +87,13 @@ export function tryExtractNumericalValueFromAssertionStdParameter( return maybeNumber; } -export const tryGetFieldMetricAssertionNumericalResult = (result?: Maybe): number | undefined => { +const tryGetFieldMetricAssertionNumericalResult = (result?: Maybe): number | undefined => { return tryExtractNumericalValueFromNativeResults( result?.nativeResults, ASSERTION_NATIVE_RESULTS_KEYS_BY_ASSERTION_TYPE.FIELD_ASSERTIONS.METRIC_VALUES.Y_VALUE_KEY_NAME, ); }; -export const tryGetFieldValueAssertionNumericalResult = (result?: Maybe) => { +const tryGetFieldValueAssertionNumericalResult = (result?: Maybe) => { if (result?.type === AssertionResultType.Init) return 0; return tryExtractNumericalValueFromNativeResults( result?.nativeResults, @@ -101,32 +101,32 @@ export const tryGetFieldValueAssertionNumericalResult = (result?: Maybe) => { +const tryGetSqlAssertionNumericalResult = (result?: Maybe) => { return tryExtractNumericalValueFromNativeResults( result?.nativeResults, ASSERTION_NATIVE_RESULTS_KEYS_BY_ASSERTION_TYPE.SQL_ASSERTIONS.Y_VALUE_KEY_NAME, ); }; -export const tryGetPreviousSqlAssertionNumericalResult = (result?: Maybe) => { +const tryGetPreviousSqlAssertionNumericalResult = (result?: Maybe) => { return tryExtractNumericalValueFromNativeResults( result?.nativeResults, ASSERTION_NATIVE_RESULTS_KEYS_BY_ASSERTION_TYPE.SQL_ASSERTIONS.PREVIOUS_Y_VALUE_KEY_NAME, ); }; -export const tryGetAbsoluteVolumeAssertionNumericalResult = (result?: Maybe) => { +const tryGetAbsoluteVolumeAssertionNumericalResult = (result?: Maybe) => { const rowCount = result?.rowCount; return rowCount || undefined; }; -export const tryGetPreviousVolumeAssertionNumericalResult = (result?: Maybe) => { +const tryGetPreviousVolumeAssertionNumericalResult = (result?: Maybe) => { return tryExtractNumericalValueFromNativeResults( result?.nativeResults, ASSERTION_NATIVE_RESULTS_KEYS_BY_ASSERTION_TYPE.VOLUME_ASSERTIONS.PREVIOUS_Y_VALUE_KEY_NAME, ); }; -export const tryGetActualUpdatedTimestampFromAssertionResult = (result?: Maybe) => { +const tryGetActualUpdatedTimestampFromAssertionResult = (result?: Maybe) => { const eventsArrString = result?.nativeResults?.find((pair) => pair.key === 'events')?.value; const eventsArr = eventsArrString ? JSON.parse(eventsArrString) : []; const timestamps = eventsArr.map((event) => event.time); @@ -135,21 +135,21 @@ export const tryGetActualUpdatedTimestampFromAssertionResult = (result?: Maybe { +const tryGetExtraFieldsInActual = (result?: AssertionResult | null) => { return tryExtractArrayValueFromNativeResults( result?.nativeResults, ASSERTION_NATIVE_RESULTS_KEYS_BY_ASSERTION_TYPE.SCHEMA_ASSERTIONS.EXTRA_FIELDS_IN_ACTUAL_KEY_NAME, ); }; -export const tryGetExtraFieldsInExpected = (result?: AssertionResult | null) => { +const tryGetExtraFieldsInExpected = (result?: AssertionResult | null) => { return tryExtractArrayValueFromNativeResults( result?.nativeResults, ASSERTION_NATIVE_RESULTS_KEYS_BY_ASSERTION_TYPE.SCHEMA_ASSERTIONS.EXTRA_FIELDS_IN_EXPECTED_KEY_NAME, ); }; -export const tryGetMismatchedTypeFields = (result?: AssertionResult | null) => { +const tryGetMismatchedTypeFields = (result?: AssertionResult | null) => { return tryExtractArrayValueFromNativeResults( result?.nativeResults, ASSERTION_NATIVE_RESULTS_KEYS_BY_ASSERTION_TYPE.SCHEMA_ASSERTIONS.MISMATCHED_TYPE_FIELDS_KEY_NAME, @@ -166,8 +166,8 @@ export const tryGetPrimaryMetricValueFromAssertionRunEvent = (): number | undefi }; // This captures context around the expected range of values -export type AssertionRangeEndType = 'inclusive' | 'exclusive'; -export type AssertionExpectedRange = { +type AssertionRangeEndType = 'inclusive' | 'exclusive'; +type AssertionExpectedRange = { // These are the actual values we expect (ie. actual row count) high?: number; low?: number; @@ -190,7 +190,7 @@ export type AssertionExpectedRange = { * @param totals * @returns */ -export function tryGetExpectedRangeFromAssertionAgainstAbsoluteValues( +function tryGetExpectedRangeFromAssertionAgainstAbsoluteValues( totals?: | Maybe | Maybe @@ -248,7 +248,7 @@ export function tryGetExpectedRangeFromAssertionAgainstAbsoluteValues( * @param previousCount * @returns {AssertionExpectedRange} */ -export function tryGetExpectedRangeFromAssertionAgainstRelativeValues( +function tryGetExpectedRangeFromAssertionAgainstRelativeValues( changingInfo?: Maybe, changeType?: Maybe, previousCount?: Maybe, @@ -340,7 +340,7 @@ export function tryGetExpectedRangeFromAssertionAgainstRelativeValues( }; } -export function tryGetExpectedRangeFromFailThreshold( +function tryGetExpectedRangeFromFailThreshold( fieldValuesAssertion?: Maybe, ): AssertionExpectedRange { const highType: AssertionRangeEndType = 'inclusive'; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/utils.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/utils.tsx index 4b32087f80f38a..fa908aa59d29e9 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/utils.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertion/profile/summary/utils.tsx @@ -61,7 +61,7 @@ import { useGetUserQuery } from '@graphql/user.generated'; * @link getOperatorText * Returns the Plain Text to render for the operator portion of the Assertion Description */ -export const getOperatorPlainText = ( +const getOperatorPlainText = ( op: AssertionStdOperator, parameters: AssertionStdParameters | undefined, nativeType: string | undefined, @@ -130,7 +130,7 @@ export const getOperatorPlainText = ( * * Schema assertions require an aggregation. */ -export const getSchemaAggregationPlainText = ( +const getSchemaAggregationPlainText = ( aggregation: AssertionStdAggregation | undefined | null, fields: Array | undefined | null, ) => { @@ -156,7 +156,7 @@ export const getSchemaAggregationPlainText = ( * * Row assertions require an aggregation. */ -export const getRowsAggregationPlainText = (aggregation: AssertionStdAggregation | undefined | null) => { +const getRowsAggregationPlainText = (aggregation: AssertionStdAggregation | undefined | null) => { switch (aggregation) { case AssertionStdAggregation.RowCount: return 'Dataset row count is'; @@ -176,7 +176,7 @@ export const getRowsAggregationPlainText = (aggregation: AssertionStdAggregation * Returns the Plain Text to render for the aggregation portion of the Assertion Description * for Assertions on Dataset Columns */ -export const getColumnAggregationPlainText = ( +const getColumnAggregationPlainText = ( aggregation: AssertionStdAggregation | undefined | null, field: SchemaFieldRef | undefined, ) => { @@ -230,7 +230,7 @@ export const getColumnAggregationPlainText = ( * @link getAggregationText * Returns the Plain Text to render for the aggregation portion of the Assertion Description */ -export const getAggregationPlainText = ( +const getAggregationPlainText = ( scope: DatasetAssertionScope, aggregation: AssertionStdAggregation | undefined | null, fields: Array | undefined | null, @@ -254,7 +254,7 @@ export const getAggregationPlainText = ( * A human-readable Plain Text description of a Dataset Assertion. */ -export const getDatasetAssertionPlainTextDescription = (datasetAssertion: DatasetAssertionInfo): string => { +const getDatasetAssertionPlainTextDescription = (datasetAssertion: DatasetAssertionInfo): string => { const { scope, aggregation, fields, operator, parameters, nativeType } = datasetAssertion; const aggregationPlainText = getAggregationPlainText(scope, aggregation, fields); const operatorPlainText = getOperatorPlainText(operator, parameters || undefined, nativeType || undefined); @@ -266,7 +266,7 @@ export const getDatasetAssertionPlainTextDescription = (datasetAssertion: Datase * @link getAggregationText * A human-readable Plain Text description of a Volume Assertion. */ -export const getVolumeAssertionPlainTextDescription = (assertionInfo: VolumeAssertionInfo): string => { +const getVolumeAssertionPlainTextDescription = (assertionInfo: VolumeAssertionInfo): string => { const volumeType = assertionInfo.type; const volumeTypeInfo = getVolumeTypeInfo(assertionInfo); const volumeTypeDescription = getVolumeTypeDescription(volumeType); @@ -284,7 +284,7 @@ export const getVolumeAssertionPlainTextDescription = (assertionInfo: VolumeAsse * @link getAggregationText * A human-readable Plain Text description of a Field Assertion. */ -export const getFieldAssertionPlainTextDescription = (assertionInfo: FieldAssertionInfo) => { +const getFieldAssertionPlainTextDescription = (assertionInfo: FieldAssertionInfo) => { const field = getFieldDescription(assertionInfo); const transform = getFieldTransformDescription(assertionInfo); // Do not pluralize if this is a metric assertion since you're checking one metric, not multiple values @@ -300,7 +300,7 @@ export const getFieldAssertionPlainTextDescription = (assertionInfo: FieldAssert * @link getAggregationText * A human-readable Plain Text description of a Schema Assertion. */ -export const getSchemaAssertionPlainTextDescription = (assertionInfo: SchemaAssertionInfo) => { +const getSchemaAssertionPlainTextDescription = (assertionInfo: SchemaAssertionInfo) => { const { compatibility } = assertionInfo; const matchText = compatibility === SchemaAssertionCompatibility.ExactMatch ? 'exactly match' : 'include'; const expectedColumnCount = assertionInfo?.fields?.length || 0; @@ -312,7 +312,7 @@ export const getSchemaAssertionPlainTextDescription = (assertionInfo: SchemaAsse /** * A human-readable Plain Text description of an Freshness Assertion. */ -export const getFreshnessAssertionPlainTextDescription = ( +const getFreshnessAssertionPlainTextDescription = ( assertionInfo: FreshnessAssertionInfo, monitorSchedule: CronSchedule, ) => { diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertionUtils.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertionUtils.tsx index e4e2a938c214c3..7999d917a68013 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertionUtils.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/assertionUtils.tsx @@ -42,7 +42,7 @@ export const sortAssertions = (a, b) => { /** * Returns the display text assoociated with an AssertionResultType */ -export const getResultText = (result: AssertionResultType) => { +const getResultText = (result: AssertionResultType) => { switch (result) { case AssertionResultType.Success: return 'Passed'; @@ -84,7 +84,7 @@ export const getResultColor = (result?: AssertionResultType) => { /** * Returns the display icon associated with an AssertionResultType */ -export const getResultIcon = (result: AssertionResultType, color?: string) => { +const getResultIcon = (result: AssertionResultType, color?: string) => { const resultColor = color || getResultColor(result); switch (result) { case AssertionResultType.Success: @@ -103,7 +103,7 @@ export const getResultIcon = (result: AssertionResultType, color?: string) => { /** * Convert an array of StringMapEntry into a map, for easy retrieval. */ -export const convertNativeParametersArrayToMap = (nativeParameters: Maybe> | undefined) => { +const convertNativeParametersArrayToMap = (nativeParameters: Maybe> | undefined) => { if (nativeParameters) { const map = new Map(); nativeParameters.forEach((parameter) => { @@ -166,7 +166,7 @@ export const getFormattedParameterValue = (parameter: AssertionStdParameter | un /** * Throws if an assertion has no input fields */ -export const validateAssertionsHasInputFields = (info: DatasetAssertionInfo) => { +const validateAssertionsHasInputFields = (info: DatasetAssertionInfo) => { if (info.fields && info.fields.length === 1) { return info.fields[0].path; } diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/contract/builder/utils.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/contract/builder/utils.ts index 7f0277bd32528a..e500cbcd818965 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/contract/builder/utils.ts +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/contract/builder/utils.ts @@ -8,7 +8,7 @@ import { DataContract } from '@types'; /** * Creates a builder state instance from a Data Contract object. */ -export const createBuilderState = (contract?: DataContract | null): DataContractBuilderState | undefined => { +const createBuilderState = (contract?: DataContract | null): DataContractBuilderState | undefined => { if (contract) { return { schema: diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/useGetValidationsTab.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/useGetValidationsTab.ts index 164e8e489e3465..7fcfd2f82aed27 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/useGetValidationsTab.ts +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/useGetValidationsTab.ts @@ -5,7 +5,7 @@ */ const VALIDATION_TAB_NAME_REGEX_PATTERN = '^/[^/]+/[^/]+/[^/]+/([^/]+).*'; -export type SelectedTab = { +type SelectedTab = { basePath: string; selectedTab: string | undefined; }; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/utils.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/utils.tsx index 683ba69cfef478..064ee5db5eb0e9 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/utils.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Dataset/Validations/utils.tsx @@ -72,7 +72,7 @@ type VolumeTypeField = | 'incrementingSegmentRowCountTotal' | 'incrementingSegmentRowCountChange'; -export const getPropertyFromVolumeType = (type: VolumeAssertionType) => { +const getPropertyFromVolumeType = (type: VolumeAssertionType) => { switch (type) { case VolumeAssertionType.RowCountTotal: return 'rowCountTotal' as VolumeTypeField; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Documentation/components/CompactMarkdownViewer.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Documentation/components/CompactMarkdownViewer.tsx index 01c81d3247ba4e..3b2b88bd78fa60 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Documentation/components/CompactMarkdownViewer.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Documentation/components/CompactMarkdownViewer.tsx @@ -95,7 +95,7 @@ const MoreIndicator = styled.span` break-word: normal; `; -export type Props = { +type Props = { content: string; lineLimit?: number | null; fixedLineHeight?: boolean; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Documentation/components/DiscardDescriptionModal.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Documentation/components/DiscardDescriptionModal.tsx deleted file mode 100644 index 8b11f02c9e6ac7..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Documentation/components/DiscardDescriptionModal.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { Button, Modal } from 'antd'; -import React from 'react'; - -type Props = { - cancelModalVisible?: boolean; - onDiscard?: () => void; - onCancel?: () => void; -}; - -export const DiscardDescriptionModal = ({ cancelModalVisible, onDiscard, onCancel }: Props) => { - return ( - <> - - Cancel - , - , - ]} - > -

Are you sure you want to close the documentation editor? Any unsaved changes will be lost.

-
- - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Documentation/components/ShortMarkdownViewer.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Documentation/components/ShortMarkdownViewer.tsx index 3938acc4210f18..cf8ac9822897ae 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Documentation/components/ShortMarkdownViewer.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Documentation/components/ShortMarkdownViewer.tsx @@ -11,7 +11,7 @@ const StyledText = styled(Text)` width: 100%; `; -export type Props = { +type Props = { content: string; clearMarkdown?: boolean; }; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/hooks/useIncidentHandler.ts b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/hooks/useIncidentHandler.ts index fc06db2fa272a3..e2f02eb12a9777 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/hooks/useIncidentHandler.ts +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/hooks/useIncidentHandler.ts @@ -13,7 +13,7 @@ import { EntityType, IncidentSourceType, IncidentState } from '@src/types.genera import { IncidentResultFieldsFragment } from '@graphql/incident.generated'; -export const getCacheIncident = ({ +const getCacheIncident = ({ values, responseData, user, diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/styledComponents.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/styledComponents.tsx index d3b7a2643e9113..19a5e3c8d0ba93 100644 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/styledComponents.tsx +++ b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/AcrylComponents/styledComponents.tsx @@ -4,7 +4,7 @@ import styled, { keyframes } from 'styled-components'; import { Button, colors } from '@src/alchemy-components'; import { ANTD_GRAY, REDESIGN_COLORS } from '@src/app/entityV2/shared/constants'; -export const IncidentListStyledTable = styled(Table)` +const IncidentListStyledTable = styled(Table)` max-width: none; &&& .ant-table-thead .ant-table-cell { font-weight: 600; @@ -154,7 +154,7 @@ export const Header = styled.div` margin-bottom: 1rem; `; -export const ToggleIcon = styled.span` +const ToggleIcon = styled.span` color: #666; `; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/components/IncidentListItem.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/components/IncidentListItem.tsx deleted file mode 100644 index 406fef456057f9..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/components/IncidentListItem.tsx +++ /dev/null @@ -1,338 +0,0 @@ -import { CheckCircleFilled, CheckOutlined, MoreOutlined, WarningFilled } from '@ant-design/icons'; -import { Popover, Tooltip } from '@components'; -import { Button, Dropdown, List, Menu, Tag, Typography, message } from 'antd'; -import React, { useState } from 'react'; -import { Link } from 'react-router-dom'; -import styled from 'styled-components'; - -import analytics, { EntityActionType, EventType } from '@app/analytics'; -import { useEntityData, useRefetch } from '@app/entity/shared/EntityContext'; -import CompactMarkdownViewer from '@app/entityV2/shared/tabs/Documentation/components/CompactMarkdownViewer'; -import { ResolveIncidentModal } from '@app/entityV2/shared/tabs/Incident/components/ResolveIncidentModal'; -import { - FAILURE_COLOR_HEX, - SUCCESS_COLOR_HEX, - getNameFromType, -} from '@app/entityV2/shared/tabs/Incident/incidentUtils'; -import handleGraphQLError from '@app/shared/handleGraphQLError'; -import { toLocalDateTimeString, toRelativeTimeString } from '@app/shared/time/timeUtils'; -import { useEntityRegistry } from '@app/useEntityRegistry'; - -import { useUpdateIncidentStatusMutation } from '@graphql/mutations.generated'; -import { useGetUserQuery } from '@graphql/user.generated'; -import { EntityType, Incident, IncidentState, IncidentType } from '@types'; - -type Props = { - incident: Incident; - refetch?: () => Promise; -}; - -const IncidentListContainer = styled(List.Item)` - padding-top: 20px; - padding-bottom: 20px; -`; - -const IncidentItemContainer = styled.div` - display: flex; - justify-content: space-between; - padding-left: 8px; - padding-right: 8px; - width: 100%; -`; - -const IncidentHeaderContainer = styled.div` - display: flex; - justify-content: left; - align-items: center; -`; - -const DescriptionContainer = styled.div` - margin-top: 8px; -`; - -const TitleContainer = styled.div` - display: flex; - align-items: center; -`; - -const IncidentTitle = styled(Typography.Text)` - font-size: 14px; - font-weight: 700; - margin-right: 16px; - color: #000000; - line-height: 22px; - text-align: justify; - max-width: 500px; -`; - -const IncidentTypeTag = styled(Tag)` - width: auto; - height: 26px; - text-align: center; - font-weight: 500; - font-size: 12px; - line-height: 20px; - color: #262626; - padding: 2px 15px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - max-width: 500px; -`; - -const IncidentDescriptionText = styled(Typography.Text)` - max-width: 500px; - font-weight: 500; - font-size: 12px; - line-height: 20px; - color: #262626; - display: block; - word-wrap: break-word; - white-space: normal; - text-align: justify; -`; - -const IncidentDescriptionLabel = styled(Typography.Text)` - margin-top: 4px; - font-weight: 400; - font-size: 10px; - color: #8c8c8c; - display: block; - word-wrap: break-word; - white-space: normal; - text-align: justify; -`; - -const IncidentCreatedTime = styled(Typography.Text)` - font-weight: 500; - font-size: 10px; - line-height: 20px; - color: #8c8c8c; -`; - -const IncidentResolvedText = styled(Typography.Text)` - font-weight: 500; - font-size: 12px; - line-height: 20px; - color: #8c8c8c; -`; - -const IncidentResolvedTextContainer = styled.div` - display: flex; - align-items: center; -`; - -const IncidentResolvedContainer = styled.div` - display: flex; - align-items: center; - margin-right: 30px; -`; - -const IncidentResolvedButton = styled(Button)` - background: #ffffff; - border: 1px solid #d9d9d9; - box-sizing: border-box; - box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.1); - border-radius: 5px; - color: #262626; - font-weight: 500; - font-size: 12px; - line-height: 20px; -`; - -const MenuIcon = styled(MoreOutlined)` - display: flex; - justify-content: center; - align-items: center; - font-size: 25px; - height: 28px; - margin-left: 5px; -`; - -const MenuItem = styled.div` - font-size: 12px; - padding-left: 12px; - padding-right: 12px; - color: rgba(0, 0, 0, 0.85); -`; - -export default function IncidentListItem({ incident, refetch }: Props) { - const { entityType } = useEntityData(); - const refetchEntity = useRefetch(); - const entityRegistry = useEntityRegistry(); - const [updateIncidentStatusMutation] = useUpdateIncidentStatusMutation(); - const [isResolvedModalVisible, setIsResolvedModalVisible] = useState(false); - - // Fetching the most recent actor's data. - const { data: createdActor } = useGetUserQuery({ - variables: { urn: incident.created.actor || '', groupsCount: 0 }, - fetchPolicy: 'cache-first', - }); - const { data: lastUpdatedActor } = useGetUserQuery({ - variables: { urn: incident.incidentStatus?.lastUpdated.actor || '', groupsCount: 0 }, - fetchPolicy: 'cache-first', - }); - - // Converting the created time into UTC - const createdDate = new Date(incident.created.time).getTime(); - const lastModifiedDate = new Date(incident.incidentStatus?.lastUpdated.time || incident.created.time).getTime(); - - // Updating the incident status on button click - const updateIncidentStatus = (state: IncidentState, resolvedMessage: string) => { - message.loading({ content: 'Updating...' }); - updateIncidentStatusMutation({ - variables: { urn: incident.urn, input: { state, message: resolvedMessage } }, - }) - .then(() => { - message.destroy(); - analytics.event({ - type: EventType.EntityActionEvent, - entityType, - entityUrn: incident.urn, - actionType: EntityActionType.ResolvedIncident, - }); - message.success({ content: 'Incident updated!', duration: 2 }); - setTimeout(() => { - refetchEntity?.(); - }, 3000); - refetch?.(); - setIsResolvedModalVisible(false); - }) - .catch((error) => { - handleGraphQLError({ - error, - defaultMessage: 'Failed to update incident! An unexpected error occurred', - permissionMessage: - 'Unauthorized to update incident for this asset. Please contact your DataHub administrator.', - }); - }); - }; - - // Handle the Resolved Modal visibility - const handleResolved = () => { - setIsResolvedModalVisible(!isResolvedModalVisible); - }; - - const menu = ( - - - updateIncidentStatus(IncidentState.Active, '')} data-testid="reopen-incident"> - Reopen incident - - - - ); - - return ( - <> - - - -
- - {incident.title} - - {incident.incidentType === IncidentType.Custom - ? incident.customType - : getNameFromType(incident.incidentType)} - - - - Description - - {incident.incidentStatus?.state === IncidentState.Resolved ? ( - <> - Resolution Note - - {incident?.incidentStatus?.message || 'No additional details'} - - - ) : null} - - - - - Created {toRelativeTimeString(createdDate)} by{' '} - - - {createdActor?.corpUser && ( - - {entityRegistry.getDisplayName(EntityType.CorpUser, createdActor?.corpUser)} - - )} - -
-
- {incident.incidentStatus?.state === IncidentState.Resolved ? ( - - Note} - content={ - incident?.incidentStatus?.message === null ? ( - No additional details - ) : ( - - {incident?.incidentStatus?.message} - - ) - } - > - - {incident?.incidentStatus?.lastUpdated && ( - - Resolved {toRelativeTimeString(lastModifiedDate)} by{' '} - - )} - {lastUpdatedActor?.corpUser && ( - - {entityRegistry.getDisplayName( - EntityType.CorpUser, - lastUpdatedActor?.corpUser, - )} - - )} - - - - - - - - ) : ( - - } - onClick={() => handleResolved()} - data-testid="resolve-incident" - > - Resolve - - - - )} -
-
- {isResolvedModalVisible && ( - - )} - - ); -} diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/components/IncidentSummary.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/components/IncidentSummary.tsx deleted file mode 100644 index ea8e0fa47903a1..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/components/IncidentSummary.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import { CheckCircleFilled, StopOutlined, WarningFilled } from '@ant-design/icons'; -import { Typography } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -import { ANTD_GRAY } from '@app/entityV2/shared/constants'; -import { FAILURE_COLOR_HEX, SUCCESS_COLOR_HEX } from '@app/entityV2/shared/tabs/Incident/incidentUtils'; - -const SummaryHeader = styled.div` - width: 100%; - height: 80px; - padding-left: 40px; - padding-top: 0px; - display: flex; - align-items: center; - padding-top: 20px; - padding-bottom: 20px; -`; - -const SummaryContainer = styled.div``; - -const SummaryMessage = styled.div` - display: inline-block; - margin-left: 20px; -`; - -const SummaryTitle = styled(Typography.Title)` - && { - padding-bottom: 0px; - margin-bottom: 0px; - } -`; - -export type IncidentsSummary = { - totalIncident: number; - resolvedIncident: number; - activeIncident: number; -}; - -type Props = { - summary: IncidentsSummary; -}; - -const getSummaryIcon = (summary: IncidentsSummary) => { - if (summary.totalIncident === 0) { - return ; - } - if (summary.resolvedIncident === summary.totalIncident) { - return ; - } - return ; -}; - -const getSummaryMessage = (summary: IncidentsSummary) => { - if (summary.totalIncident === 0) { - return 'No incidents have been raised'; - } - if (summary.resolvedIncident === summary.totalIncident) { - return 'There are no active incidents'; - } - if (summary.activeIncident === 1) { - return `There is ${summary.activeIncident} active incident`; - } - if (summary.activeIncident > 1) { - return `There are ${summary.activeIncident} active incidents`; - } - return null; -}; - -export const IncidentSummary = ({ summary }: Props) => { - const summaryIcon = getSummaryIcon(summary); - const summaryMessage = getSummaryMessage(summary); - const subtitleMessage = `${summary.activeIncident} active incidents, ${summary.resolvedIncident} resolved incidents`; - return ( - - -
- {summaryIcon} - - {summaryMessage} - {subtitleMessage} - -
-
-
- ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/components/IncidentsLoadingSection.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/components/IncidentsLoadingSection.tsx deleted file mode 100644 index e0d51502ed277b..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/components/IncidentsLoadingSection.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Divider, Skeleton } from 'antd'; -import React from 'react'; -import styled from 'styled-components'; - -const Container = styled.div` - display: flex; - flex-direction: column; - justify-content: start; - gap: 12px; - margin-top: 20px; -`; - -const CardWrapper = styled.div` - padding: 0px 40px; -`; - -const CardSkeleton = styled(Skeleton.Input)` - && { - padding: 0px 20px 20px 0px; - height: 100px; - border-radius: 8px; - width: 100%; - } -`; - -export const IncidentsLoadingSection = () => { - return ( - - - - - - - - - - - - - - - ); -}; diff --git a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/components/ResolveIncidentModal.tsx b/datahub-web-react/src/app/entityV2/shared/tabs/Incident/components/ResolveIncidentModal.tsx deleted file mode 100644 index 36da4d1458d3bf..00000000000000 --- a/datahub-web-react/src/app/entityV2/shared/tabs/Incident/components/ResolveIncidentModal.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { Button, Form, Input, Modal } from 'antd'; -import React from 'react'; - -import { IncidentState } from '@types'; - -const { TextArea } = Input; - -type AddIncidentProps = { - handleResolved: () => void; - isResolvedModalVisible: boolean; - updateIncidentStatus: (state: IncidentState, resolvedMessage: string) => void; -}; - -export const ResolveIncidentModal = ({ - handleResolved, - isResolvedModalVisible, - updateIncidentStatus, -}: AddIncidentProps) => { - const [form] = Form.useForm(); - - const handleClose = () => { - form.resetFields(); - handleResolved(); - }; - - const onResolvedIncident = (formData: any) => { - updateIncidentStatus(IncidentState.Resolved, formData.message); - handleClose(); - }; - - return ( - <> - - Cancel - , - , - ]} - > -
- -