Fixed #695 Owner field in dataset page should be clickable to get more info. (#715)

This commit is contained in:
Sachin Chaurasiya 2021-10-08 22:23:53 +05:30 committed by GitHub
parent 37984f2822
commit d311fbf849
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 124 additions and 39 deletions

View File

@ -21,6 +21,7 @@ type ExtraInfo = {
value: string | number; value: string | number;
isLink?: boolean; isLink?: boolean;
placeholderText?: string; placeholderText?: string;
openInNewTab?: boolean;
}; };
type Props = { type Props = {
@ -184,17 +185,19 @@ const EntityPageInfo = ({
className="link-text" className="link-text"
href={info.value as string} href={info.value as string}
rel="noopener noreferrer" rel="noopener noreferrer"
target="_blank"> target={info.openInNewTab ? '_blank' : '_self'}>
<> <>
<span className="tw-mr-1"> <span className="tw-mr-1">
{info.placeholderText || info.value} {info.placeholderText || info.value}
</span> </span>
<SVGIcons {info.openInNewTab && (
alt="external-link" <SVGIcons
className="tw-align-middle" alt="external-link"
icon="external-link" className="tw-align-middle"
width="12px" icon="external-link"
/> width="12px"
/>
)}
</> </>
</a> </a>
) : ( ) : (

View File

@ -43,6 +43,7 @@ const PLACEHOLDER_ROUTE_SERVICE_FQN = ':serviceFQN';
const PLACEHOLDER_ROUTE_SERVICE_TYPE = ':serviceType'; const PLACEHOLDER_ROUTE_SERVICE_TYPE = ':serviceType';
const PLACEHOLDER_ROUTE_SEARCHQUERY = ':searchQuery'; const PLACEHOLDER_ROUTE_SEARCHQUERY = ':searchQuery';
const PLACEHOLDER_ROUTE_TAB = ':tab'; const PLACEHOLDER_ROUTE_TAB = ':tab';
const PLACEHOLDER_ROUTE_TEAM = ':team';
export const pagingObject = { after: '', before: '' }; export const pagingObject = { after: '', before: '' };
@ -106,6 +107,7 @@ export const ROUTES = {
WORKFLOWS: '/workflows', WORKFLOWS: '/workflows',
SQL_BUILDER: '/sql-builder', SQL_BUILDER: '/sql-builder',
TEAMS: '/teams', TEAMS: '/teams',
TEAM_DETAILS: `/teams/${PLACEHOLDER_ROUTE_TEAM}`,
SETTINGS: '/settings', SETTINGS: '/settings',
STORE: '/store', STORE: '/store',
FEEDS: '/feeds', FEEDS: '/feeds',
@ -186,6 +188,12 @@ export const getPipelineDetailsPath = (pipelineFQN: string) => {
return path; return path;
}; };
export const getTeamDetailsPath = (teamName: string) => {
let path = ROUTES.TEAM_DETAILS;
path = path.replace(PLACEHOLDER_ROUTE_TEAM, teamName);
return path;
};
export const LIST_TYPES = ['numbered-list', 'bulleted-list']; export const LIST_TYPES = ['numbered-list', 'bulleted-list'];

View File

@ -130,6 +130,7 @@ declare module 'Models' {
name?: string; name?: string;
id: string; id: string;
type: 'user' | 'team'; type: 'user' | 'team';
displayName?: string;
}; };
tags: Array<ColumnTags>; tags: Array<ColumnTags>;
usageSummary: UsageSummary; usageSummary: UsageSummary;

View File

@ -25,7 +25,10 @@ import { ModalWithMarkdownEditor } from '../../components/Modals/ModalWithMarkdo
import ManageTab from '../../components/my-data-details/ManageTab'; import ManageTab from '../../components/my-data-details/ManageTab';
import TagsContainer from '../../components/tags-container/tags-container'; import TagsContainer from '../../components/tags-container/tags-container';
import Tags from '../../components/tags/tags'; import Tags from '../../components/tags/tags';
import { getServiceDetailsPath } from '../../constants/constants'; import {
getServiceDetailsPath,
getTeamDetailsPath,
} from '../../constants/constants';
import { EntityType } from '../../enums/entity.enum'; import { EntityType } from '../../enums/entity.enum';
import { Pipeline } from '../../generated/entity/data/pipeline'; import { Pipeline } from '../../generated/entity/data/pipeline';
import { Task } from '../../generated/entity/data/task'; import { Task } from '../../generated/entity/data/task';
@ -120,13 +123,23 @@ const MyPipelinePage = () => {
]; ];
const extraInfo = [ const extraInfo = [
{ key: 'Owner', value: owner?.name || '' }, {
key: 'Owner',
value:
owner?.type === 'team'
? getTeamDetailsPath(owner?.name || '')
: owner?.name || '',
placeholderText: owner?.displayName || '',
isLink: owner?.type === 'team',
openInNewTab: false,
},
{ key: 'Tier', value: tier ? tier.split('.')[1] : '' }, { key: 'Tier', value: tier ? tier.split('.')[1] : '' },
{ {
key: `${serviceType} Url`, key: `${serviceType} Url`,
value: pipelineUrl, value: pipelineUrl,
placeholderText: displayName, placeholderText: displayName,
isLink: true, isLink: true,
openInNewTab: true,
}, },
// { key: 'Usage', value: usage }, // { key: 'Usage', value: usage },
// { key: 'Queries', value: `${weeklyUsageCount} past week` }, // { key: 'Queries', value: `${weeklyUsageCount} past week` },

View File

@ -25,7 +25,10 @@ import { ModalWithMarkdownEditor } from '../../components/Modals/ModalWithMarkdo
import ManageTab from '../../components/my-data-details/ManageTab'; import ManageTab from '../../components/my-data-details/ManageTab';
import TagsContainer from '../../components/tags-container/tags-container'; import TagsContainer from '../../components/tags-container/tags-container';
import Tags from '../../components/tags/tags'; import Tags from '../../components/tags/tags';
import { getServiceDetailsPath } from '../../constants/constants'; import {
getServiceDetailsPath,
getTeamDetailsPath,
} from '../../constants/constants';
import { EntityType } from '../../enums/entity.enum'; import { EntityType } from '../../enums/entity.enum';
import { Chart } from '../../generated/entity/data/chart'; import { Chart } from '../../generated/entity/data/chart';
import { Dashboard, TagLabel } from '../../generated/entity/data/dashboard'; import { Dashboard, TagLabel } from '../../generated/entity/data/dashboard';
@ -121,13 +124,23 @@ const MyDashBoardPage = () => {
]; ];
const extraInfo = [ const extraInfo = [
{ key: 'Owner', value: owner?.name || '' }, {
key: 'Owner',
value:
owner?.type === 'team'
? getTeamDetailsPath(owner?.name || '')
: owner?.name || '',
placeholderText: owner?.displayName || '',
isLink: owner?.type === 'team',
openInNewTab: false,
},
{ key: 'Tier', value: tier ? tier.split('.')[1] : '' }, { key: 'Tier', value: tier ? tier.split('.')[1] : '' },
{ {
key: `${serviceType} Url`, key: `${serviceType} Url`,
value: dashboardUrl, value: dashboardUrl,
placeholderText: displayName, placeholderText: displayName,
isLink: true, isLink: true,
openInNewTab: true,
}, },
// { key: 'Usage', value: usage }, // { key: 'Usage', value: usage },
// { key: 'Queries', value: `${weeklyUsageCount} past week` }, // { key: 'Queries', value: `${weeklyUsageCount} past week` },

View File

@ -44,6 +44,7 @@ import SchemaTab from '../../components/my-data-details/SchemaTab';
import { import {
getDatabaseDetailsPath, getDatabaseDetailsPath,
getServiceDetailsPath, getServiceDetailsPath,
getTeamDetailsPath,
} from '../../constants/constants'; } from '../../constants/constants';
import { EntityType } from '../../enums/entity.enum'; import { EntityType } from '../../enums/entity.enum';
import { import {
@ -118,7 +119,9 @@ const MyDataDetailsPage = () => {
}); });
const [tableTags, setTableTags] = useState<Array<ColumnTags>>([]); const [tableTags, setTableTags] = useState<Array<ColumnTags>>([]);
const [isEdit, setIsEdit] = useState(false); const [isEdit, setIsEdit] = useState(false);
const [owner, setOwner] = useState<Table['owner']>(); const [owner, setOwner] = useState<
Table['owner'] & { displayName?: string }
>();
const [tableJoinData, setTableJoinData] = useState<TableJoins>({ const [tableJoinData, setTableJoinData] = useState<TableJoins>({
startDate: new Date(), startDate: new Date(),
dayCount: 0, dayCount: 0,
@ -178,8 +181,20 @@ const MyDataDetailsPage = () => {
const extraInfo: Array<{ const extraInfo: Array<{
key?: string; key?: string;
value: string | number; value: string | number;
isLink?: boolean;
placeholderText?: string;
openInNewTab?: boolean;
}> = [ }> = [
{ key: 'Owner', value: owner?.name || '' }, {
key: 'Owner',
value:
owner?.type === 'team'
? getTeamDetailsPath(owner?.name || '')
: owner?.name || '',
placeholderText: owner?.displayName || '',
isLink: owner?.type === 'team',
openInNewTab: false,
},
{ key: 'Tier', value: tier ? tier.split('.')[1] : '' }, { key: 'Tier', value: tier ? tier.split('.')[1] : '' },
{ key: 'Usage', value: usage }, { key: 'Usage', value: usage },
{ key: 'Queries', value: `${weeklyUsageCount} past week` }, { key: 'Queries', value: `${weeklyUsageCount} past week` },

View File

@ -16,6 +16,7 @@
*/ */
import { AxiosError, AxiosResponse } from 'axios'; import { AxiosError, AxiosResponse } from 'axios';
import classNames from 'classnames';
import { isNull } from 'lodash'; import { isNull } from 'lodash';
import { ServiceCollection, ServiceData, ServiceTypes } from 'Models'; import { ServiceCollection, ServiceData, ServiceTypes } from 'Models';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
@ -55,6 +56,7 @@ import {
import { DatabaseService } from '../../generated/entity/services/databaseService'; import { DatabaseService } from '../../generated/entity/services/databaseService';
import { MessagingService } from '../../generated/entity/services/messagingService'; import { MessagingService } from '../../generated/entity/services/messagingService';
import { PipelineService } from '../../generated/entity/services/pipelineService'; import { PipelineService } from '../../generated/entity/services/pipelineService';
import { useAuth } from '../../hooks/authHooks';
import useToastContext from '../../hooks/useToastContext'; import useToastContext from '../../hooks/useToastContext';
import { getCountBadge, getTabClasses } from '../../utils/CommonUtils'; import { getCountBadge, getTabClasses } from '../../utils/CommonUtils';
import { getFrequencyTime, serviceTypeLogo } from '../../utils/ServiceUtils'; import { getFrequencyTime, serviceTypeLogo } from '../../utils/ServiceUtils';
@ -79,7 +81,7 @@ export type ApiData = {
const ServicesPage = () => { const ServicesPage = () => {
const showToast = useToastContext(); const showToast = useToastContext();
const { isAdminUser } = useAuth();
const [isModalOpen, setIsModalOpen] = useState(false); const [isModalOpen, setIsModalOpen] = useState(false);
const [serviceName, setServiceName] = const [serviceName, setServiceName] =
useState<ServiceTypes>('databaseServices'); useState<ServiceTypes>('databaseServices');
@ -462,7 +464,11 @@ const ServicesPage = () => {
className="tw-card" className="tw-card"
position="right" position="right"
title={TITLE_FOR_NON_ADMIN_ACTION}> title={TITLE_FOR_NON_ADMIN_ACTION}>
<div className="tw-inline-block" style={{ width: '100%' }}> <div
className={classNames('tw-inline-block', {
'tw-opacity-40': !isAdminUser,
})}
style={{ width: '100%' }}>
<div <div
className="tw-cursor-pointer tw-flex tw-flex-col tw-justify-center tw-items-center tw-py-6" className="tw-cursor-pointer tw-flex tw-flex-col tw-justify-center tw-items-center tw-py-6"
data-testid="add-services" data-testid="add-services"

View File

@ -19,7 +19,7 @@ import { AxiosError, AxiosResponse } from 'axios';
import { compare } from 'fast-json-patch'; import { compare } from 'fast-json-patch';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Link } from 'react-router-dom'; import { Link, useHistory, useParams } from 'react-router-dom';
import AppState from '../../AppState'; import AppState from '../../AppState';
import { import {
createTeam, createTeam,
@ -37,6 +37,7 @@ import FormModal from '../../components/Modals/FormModal';
import { ModalWithMarkdownEditor } from '../../components/Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor'; import { ModalWithMarkdownEditor } from '../../components/Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
import { import {
ERROR404, ERROR404,
getTeamDetailsPath,
TITLE_FOR_NON_ADMIN_ACTION, TITLE_FOR_NON_ADMIN_ACTION,
} from '../../constants/constants'; } from '../../constants/constants';
import { Team } from '../../generated/entity/teams/team'; import { Team } from '../../generated/entity/teams/team';
@ -49,6 +50,8 @@ import Form from './Form';
import UserCard from './UserCard'; import UserCard from './UserCard';
const TeamsPage = () => { const TeamsPage = () => {
const { team } = useParams() as Record<string, string>;
const history = useHistory();
const [teams, setTeams] = useState<Array<Team>>([]); const [teams, setTeams] = useState<Array<Team>>([]);
const [currentTeam, setCurrentTeam] = useState<Team>(); const [currentTeam, setCurrentTeam] = useState<Team>();
const [error, setError] = useState<string>(''); const [error, setError] = useState<string>('');
@ -58,22 +61,6 @@ const TeamsPage = () => {
const [isAddingTeam, setIsAddingTeam] = useState<boolean>(false); const [isAddingTeam, setIsAddingTeam] = useState<boolean>(false);
const [isAddingUsers, setIsAddingUsers] = useState<boolean>(false); const [isAddingUsers, setIsAddingUsers] = useState<boolean>(false);
const [userList, setUserList] = useState<Array<User>>([]); const [userList, setUserList] = useState<Array<User>>([]);
const fetchTeams = () => {
setIsLoading(true);
getTeams(['users', 'owns'])
.then((res: AxiosResponse) => {
setTeams(res.data.data);
setCurrentTeam(res.data.data[0]);
setIsLoading(false);
})
.catch((err: AxiosError) => {
if (err?.response?.data.code) {
setError(ERROR404);
}
setIsLoading(false);
});
};
const fetchCurrentTeam = (name: string, update = false) => { const fetchCurrentTeam = (name: string, update = false) => {
if (currentTeam?.name !== name || update) { if (currentTeam?.name !== name || update) {
setIsLoading(true); setIsLoading(true);
@ -91,6 +78,24 @@ const TeamsPage = () => {
} }
}; };
const fetchTeams = () => {
setIsLoading(true);
getTeams(['users', 'owns'])
.then((res: AxiosResponse) => {
if (!team) {
setCurrentTeam(res.data.data[0]);
}
setTeams(res.data.data);
setIsLoading(false);
})
.catch((err: AxiosError) => {
if (err?.response?.data.code) {
setError(ERROR404);
}
setIsLoading(false);
});
};
const createNewTeam = (data: Team) => { const createNewTeam = (data: Team) => {
createTeam(data) createTeam(data)
.then((res: AxiosResponse) => { .then((res: AxiosResponse) => {
@ -147,6 +152,9 @@ const TeamsPage = () => {
const getActiveTabClass = (tab: number) => { const getActiveTabClass = (tab: number) => {
return tab === currentTab ? 'active' : ''; return tab === currentTab ? 'active' : '';
}; };
const changeCurrentTeam = (name: string) => {
history.push(getTeamDetailsPath(name));
};
const getTabs = () => { const getTabs = () => {
return ( return (
@ -200,7 +208,7 @@ const TeamsPage = () => {
return ( return (
<> <>
<div <div
className="tw-grid xl:tw-grid-cols-4 md:tw-grid-cols-2 tw-gap-4" className="tw-grid xl:tw-grid-cols-4 md:tw-grid-cols-3 tw-gap-4"
data-testid="user-card-container"> data-testid="user-card-container">
{currentTeam?.users?.map((user, index) => { {currentTeam?.users?.map((user, index) => {
const User = { const User = {
@ -245,7 +253,7 @@ const TeamsPage = () => {
return ( return (
<> <>
<div <div
className="tw-grid xl:tw-grid-cols-4 md:tw-grid-cols-2 tw-gap-4" className="tw-grid xl:tw-grid-cols-4 md:tw-grid-cols-3 tw-gap-4"
data-testid="dataset-card"> data-testid="dataset-card">
{' '} {' '}
{currentTeam?.owns?.map((dataset, index) => { {currentTeam?.owns?.map((dataset, index) => {
@ -287,8 +295,7 @@ const TeamsPage = () => {
)}`} )}`}
key={team.name} key={team.name}
onClick={() => { onClick={() => {
fetchCurrentTeam(team.name); changeCurrentTeam(team.name);
setCurrentTab(1);
}}> }}>
<p className="tw-text-center tag-category tw-self-center"> <p className="tw-text-center tag-category tw-self-center">
{team.displayName} {team.displayName}
@ -351,6 +358,11 @@ const TeamsPage = () => {
setUserList(AppState.users); setUserList(AppState.users);
}, [AppState.users]); }, [AppState.users]);
useEffect(() => {
fetchCurrentTeam(team);
setCurrentTab(1);
}, [team]);
return ( return (
<> <>
{error ? ( {error ? (

View File

@ -19,7 +19,10 @@ import PageContainer from '../../components/containers/PageContainer';
import Loader from '../../components/Loader/Loader'; import Loader from '../../components/Loader/Loader';
import ManageTab from '../../components/my-data-details/ManageTab'; import ManageTab from '../../components/my-data-details/ManageTab';
import SchemaEditor from '../../components/schema-editor/SchemaEditor'; import SchemaEditor from '../../components/schema-editor/SchemaEditor';
import { getServiceDetailsPath } from '../../constants/constants'; import {
getServiceDetailsPath,
getTeamDetailsPath,
} from '../../constants/constants';
import { EntityType } from '../../enums/entity.enum'; import { EntityType } from '../../enums/entity.enum';
import { User } from '../../generated/entity/teams/user'; import { User } from '../../generated/entity/teams/user';
import { useAuth } from '../../hooks/authHooks'; import { useAuth } from '../../hooks/authHooks';
@ -351,7 +354,16 @@ const MyTopicDetailPage = () => {
isTagEditable isTagEditable
entityName={name} entityName={name}
extraInfo={[ extraInfo={[
{ key: 'Owner', value: owner?.name || '' }, {
key: 'Owner',
value:
owner?.type === 'team'
? getTeamDetailsPath(owner?.name || '')
: owner?.name || '',
placeholderText: owner?.displayName || '',
isLink: owner?.type === 'team',
openInNewTab: false,
},
{ key: 'Tier', value: tier ? tier.split('.')[1] : '' }, { key: 'Tier', value: tier ? tier.split('.')[1] : '' },
...getConfigDetails(), ...getConfigDetails(),
]} ]}

View File

@ -52,6 +52,7 @@ const AuthenticatedAppRouter: FunctionComponent = () => {
<Route exact component={WorkflowsPage} path={ROUTES.WORKFLOWS} /> <Route exact component={WorkflowsPage} path={ROUTES.WORKFLOWS} />
<Route exact component={SQLBuilderPage} path={ROUTES.SQL_BUILDER} /> <Route exact component={SQLBuilderPage} path={ROUTES.SQL_BUILDER} />
<Route exact component={TeamsPage} path={ROUTES.TEAMS} /> <Route exact component={TeamsPage} path={ROUTES.TEAMS} />
<Route exact component={TeamsPage} path={ROUTES.TEAM_DETAILS} />
<Route exact component={SettingsPage} path={ROUTES.SETTINGS} /> <Route exact component={SettingsPage} path={ROUTES.SETTINGS} />
<Route exact component={StorePage} path={ROUTES.STORE} /> <Route exact component={StorePage} path={ROUTES.STORE} />
{/* <Route exact component={FeedsPage} path={ROUTES.FEEDS} /> */} {/* <Route exact component={FeedsPage} path={ROUTES.FEEDS} /> */}

View File

@ -100,7 +100,8 @@ export const getOwnerFromId = (
const team = AppState.userTeams.find((item) => item.id === id); const team = AppState.userTeams.find((item) => item.id === id);
if (team) { if (team) {
retVal = { retVal = {
name: team.displayName || team.name, name: team.name,
displayName: team.displayName || team.name,
id: team.id, id: team.id,
type: 'team', type: 'team',
}; };