Fixed: UI inconsistency as per feedback #4192 (#4840)

This commit is contained in:
Shailesh Parmar 2022-05-11 15:04:27 +05:30 committed by GitHub
parent 0acf88e1ba
commit 4395cae6b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 738 additions and 697 deletions

View File

@ -467,235 +467,241 @@ const DashboardDetails = ({
tabs={tabs} tabs={tabs}
/> />
<div className="tw-bg-white tw-flex-grow tw--mx-6 tw-px-7 tw-py-4"> <div className="tw-flex-grow tw-flex tw-flex-col tw--mx-6 tw-px-7 tw-py-4">
{activeTab === 1 && ( <div className="tw-bg-white tw-flex-grow tw-p-4 tw-shadow tw-rounded-md">
<> {activeTab === 1 && (
<div className="tw-grid tw-grid-cols-4 tw-gap-4 tw-w-full"> <>
<div className="tw-col-span-full"> <div className="tw-grid tw-grid-cols-4 tw-gap-4 tw-w-full">
<Description <div className="tw-col-span-full tw--ml-5">
description={description} <Description
entityFieldThreads={getEntityFieldThreadCounts( description={description}
'description', entityFieldThreads={getEntityFieldThreadCounts(
entityFieldThreadCount 'description',
)} entityFieldThreadCount
entityFqn={dashboardFQN} )}
entityName={entityName} entityFqn={dashboardFQN}
entityType={EntityType.DASHBOARD} entityName={entityName}
hasEditAccess={hasEditAccess()} entityType={EntityType.DASHBOARD}
isEdit={isEdit} hasEditAccess={hasEditAccess()}
isReadOnly={deleted} isEdit={isEdit}
owner={owner} isReadOnly={deleted}
onCancel={onCancel} owner={owner}
onDescriptionEdit={onDescriptionEdit} onCancel={onCancel}
onDescriptionUpdate={onDescriptionUpdate} onDescriptionEdit={onDescriptionEdit}
onEntityFieldSelect={onEntityFieldSelect} onDescriptionUpdate={onDescriptionUpdate}
onThreadLinkSelect={onThreadLinkSelect} onEntityFieldSelect={onEntityFieldSelect}
/> onThreadLinkSelect={onThreadLinkSelect}
/>
</div>
</div> </div>
</div> <div className="tw-table-responsive tw-my-6">
<div className="tw-table-responsive tw-my-6"> <table className="tw-w-full" data-testid="charts-table">
<table className="tw-w-full" data-testid="charts-table"> <thead>
<thead> <tr className="tableHead-row">
<tr className="tableHead-row"> <th className="tableHead-cell">Chart Name</th>
<th className="tableHead-cell">Chart Name</th> <th className="tableHead-cell">Chart Type</th>
<th className="tableHead-cell">Chart Type</th> <th className="tableHead-cell">Description</th>
<th className="tableHead-cell">Description</th> <th className="tableHead-cell tw-w-60">Tags</th>
<th className="tableHead-cell tw-w-60">Tags</th> </tr>
</tr> </thead>
</thead> <tbody className="tableBody">
<tbody className="tableBody"> {charts.map((chart, index) => (
{charts.map((chart, index) => ( <tr
<tr className={classNames(
className={classNames( 'tableBody-row',
'tableBody-row', !isEven(index + 1) ? 'odd-row' : null
!isEven(index + 1) ? 'odd-row' : null )}
)} key={index}>
key={index}> <td className="tableBody-cell">
<td className="tableBody-cell"> <Link
<Link target="_blank"
target="_blank" to={{ pathname: chart.chartUrl }}>
to={{ pathname: chart.chartUrl }}> <span className="tw-flex">
<span className="tw-flex"> <span className="tw-mr-1">
<span className="tw-mr-1"> {chart.displayName}
{chart.displayName} </span>
<SVGIcons
alt="external-link"
className="tw-align-middle"
icon="external-link"
width="12px"
/>
</span> </span>
<SVGIcons </Link>
alt="external-link" </td>
className="tw-align-middle" <td className="tableBody-cell">
icon="external-link" {chart.chartType}
width="12px" </td>
/> <td className="tw-group tableBody-cell tw-relative">
</span> <div className="tw-inline-block">
</Link> <div
</td> className="tw-cursor-pointer tw-flex"
<td className="tableBody-cell">{chart.chartType}</td> data-testid="description">
<td className="tw-group tableBody-cell tw-relative"> <div>
<div className="tw-inline-block"> {chart.description ? (
<div <RichTextEditorPreviewer
className="tw-cursor-pointer tw-flex" markdown={chart.description}
data-testid="description"> />
<div> ) : (
{chart.description ? ( <span className="tw-no-description">
<RichTextEditorPreviewer No description
markdown={chart.description} </span>
/> )}
) : ( </div>
<span className="tw-no-description"> {!deleted && (
No description <NonAdminAction
</span> html={getHtmlForNonAdminAction(
Boolean(owner)
)}
isOwner={hasEditAccess()}
permission={Operation.UpdateDescription}
position="top">
<button
className="tw-self-start tw-w-8 tw-h-auto tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 focus:tw-outline-none"
onClick={() =>
handleUpdateChart(chart, index)
}>
<SVGIcons
alt="edit"
icon="icon-edit"
title="Edit"
width="10px"
/>
</button>
</NonAdminAction>
)} )}
</div> </div>
{!deleted && (
<NonAdminAction
html={getHtmlForNonAdminAction(
Boolean(owner)
)}
isOwner={hasEditAccess()}
permission={Operation.UpdateDescription}
position="top">
<button
className="tw-self-start tw-w-8 tw-h-auto tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 focus:tw-outline-none"
onClick={() =>
handleUpdateChart(chart, index)
}>
<SVGIcons
alt="edit"
icon="icon-edit"
title="Edit"
width="10px"
/>
</button>
</NonAdminAction>
)}
</div> </div>
</div> </td>
</td> <td
<td className="tw-group tw-relative tableBody-cell"
className="tw-group tw-relative tableBody-cell" onClick={() => {
onClick={() => { if (!editChartTags) {
if (!editChartTags) { // Fetch tags and terms only once
// Fetch tags and terms only once if (tagList.length === 0 || tagFetchFailed) {
if (tagList.length === 0 || tagFetchFailed) { fetchTagsAndGlossaryTerms();
fetchTagsAndGlossaryTerms();
}
handleEditChartTag(chart, index);
}
}}>
{deleted ? (
<div className="tw-flex tw-flex-wrap">
<TagsViewer
sizeCap={-1}
tags={chart.tags || []}
/>
</div>
) : (
<NonAdminAction
html={getHtmlForNonAdminAction(Boolean(owner))}
isOwner={hasEditAccess()}
permission={Operation.UpdateTags}
position="left"
trigger="click">
<TagsContainer
editable={editChartTags?.index === index}
isLoading={
isTagLoading &&
editChartTags?.index === index
} }
selectedTags={chart.tags as EntityTags[]} handleEditChartTag(chart, index);
size="small" }
tagList={tagList} }}>
type="label" {deleted ? (
onCancel={() => { <div className="tw-flex tw-flex-wrap">
handleChartTagSelection(); <TagsViewer
}} sizeCap={-1}
onSelectionChange={(tags) => { tags={chart.tags || []}
handleChartTagSelection(tags); />
}}> </div>
{chart.tags?.length ? ( ) : (
<button <NonAdminAction
className="tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 focus:tw-outline-none" html={getHtmlForNonAdminAction(
data-testid="edit-tags"> Boolean(owner)
<SVGIcons
alt="edit"
icon="icon-edit"
title="Edit"
width="10px"
/>
</button>
) : (
<span className="tw-opacity-60 group-hover:tw-opacity-100 tw-text-grey-muted group-hover:tw-text-primary">
<Tags
startWith="+ "
tag="Add tag"
type="outlined"
/>
</span>
)} )}
</TagsContainer> isOwner={hasEditAccess()}
</NonAdminAction> permission={Operation.UpdateTags}
)} position="left"
</td> trigger="click">
</tr> <TagsContainer
))} editable={editChartTags?.index === index}
</tbody> isLoading={
</table> isTagLoading &&
editChartTags?.index === index
}
selectedTags={chart.tags as EntityTags[]}
size="small"
tagList={tagList}
type="label"
onCancel={() => {
handleChartTagSelection();
}}
onSelectionChange={(tags) => {
handleChartTagSelection(tags);
}}>
{chart.tags?.length ? (
<button
className="tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 focus:tw-outline-none"
data-testid="edit-tags">
<SVGIcons
alt="edit"
icon="icon-edit"
title="Edit"
width="10px"
/>
</button>
) : (
<span className="tw-opacity-60 group-hover:tw-opacity-100 tw-text-grey-muted group-hover:tw-text-primary">
<Tags
startWith="+ "
tag="Add tag"
type="outlined"
/>
</span>
)}
</TagsContainer>
</NonAdminAction>
)}
</td>
</tr>
))}
</tbody>
</table>
</div>
</>
)}
{activeTab === 2 && (
<div
className="tw-py-4 tw-px-7 tw-grid tw-grid-cols-3 entity-feed-list tw--mx-7 tw--my-4"
id="activityfeed">
<div />
<ActivityFeedList
isEntityFeed
withSidePanel
className=""
deletePostHandler={deletePostHandler}
entityName={entityName}
feedList={entityThread}
postFeedHandler={postFeedHandler}
/>
<div />
</div> </div>
</> )}
)} {activeTab === 3 && (
{activeTab === 2 && ( <div className="tw-h-full tw-px-3">
<Entitylineage
addLineageHandler={addLineageHandler}
deleted={deleted}
entityLineage={entityLineage}
entityLineageHandler={entityLineageHandler}
isLoading={isLineageLoading}
isNodeLoading={isNodeLoading}
isOwner={hasEditAccess()}
lineageLeafNodes={lineageLeafNodes}
loadNodeHandler={loadNodeHandler}
removeLineageHandler={removeLineageHandler}
/>
</div>
)}
{activeTab === 4 && !deleted && (
<div>
<ManageTabComponent
allowDelete
currentTier={tier?.tagFQN}
currentUser={owner}
deletEntityMessage={getDeleteEntityMessage()}
entityId={dashboardDetails.id}
entityName={dashboardDetails.name}
entityType={EntityType.DASHBOARD}
hasEditAccess={hasEditAccess()}
manageSectionType={EntityType.DASHBOARD}
onSave={onSettingsUpdate}
/>
</div>
)}
<div <div
className="tw-py-4 tw-px-7 tw-grid tw-grid-cols-3 entity-feed-list tw--mx-7 tw--my-4" data-testid="observer-element"
id="activityfeed"> id="observer-element"
<div /> ref={elementRef as RefObject<HTMLDivElement>}>
<ActivityFeedList {getLoader()}
isEntityFeed
withSidePanel
className=""
deletePostHandler={deletePostHandler}
entityName={entityName}
feedList={entityThread}
postFeedHandler={postFeedHandler}
/>
<div />
</div> </div>
)}
{activeTab === 3 && (
<div className="tw-h-full">
<Entitylineage
addLineageHandler={addLineageHandler}
deleted={deleted}
entityLineage={entityLineage}
entityLineageHandler={entityLineageHandler}
isLoading={isLineageLoading}
isNodeLoading={isNodeLoading}
isOwner={hasEditAccess()}
lineageLeafNodes={lineageLeafNodes}
loadNodeHandler={loadNodeHandler}
removeLineageHandler={removeLineageHandler}
/>
</div>
)}
{activeTab === 4 && !deleted && (
<div>
<ManageTabComponent
allowDelete
currentTier={tier?.tagFQN}
currentUser={owner}
deletEntityMessage={getDeleteEntityMessage()}
entityId={dashboardDetails.id}
entityName={dashboardDetails.name}
entityType={EntityType.DASHBOARD}
hasEditAccess={hasEditAccess()}
manageSectionType={EntityType.DASHBOARD}
onSave={onSettingsUpdate}
/>
</div>
)}
<div
data-testid="observer-element"
id="observer-element"
ref={elementRef as RefObject<HTMLDivElement>}>
{getLoader()}
</div> </div>
</div> </div>
</div> </div>

View File

@ -579,187 +579,189 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
setActiveTab={setActiveTabHandler} setActiveTab={setActiveTabHandler}
tabs={tabs} tabs={tabs}
/> />
<div className="tw-flex-grow tw-flex tw-flex-col tw--mx-6 tw-px-7 tw-py-4">
<div className="tw-bg-white tw-flex-grow tw--mx-6 tw-px-7 tw-py-4"> <div className="tw-bg-white tw-flex-grow tw-p-4 tw-shadow tw-rounded-md">
{activeTab === 1 && ( {activeTab === 1 && (
<div <div
className="tw-grid tw-grid-cols-4 tw-gap-4 tw-w-full" className="tw-grid tw-grid-cols-4 tw-gap-4 tw-w-full"
id="schemaDetails"> id="schemaDetails">
<div className="tw-col-span-3"> <div className="tw-col-span-3 tw--ml-5">
<Description <Description
description={description} description={description}
entityFieldThreads={getEntityFieldThreadCounts( entityFieldThreads={getEntityFieldThreadCounts(
'description', 'description',
entityFieldThreadCount entityFieldThreadCount
)} )}
entityFqn={datasetFQN} entityFqn={datasetFQN}
entityName={entityName}
entityType={EntityType.TABLE}
hasEditAccess={hasEditAccess()}
isEdit={isEdit}
isReadOnly={deleted}
owner={owner}
onCancel={onCancel}
onDescriptionEdit={onDescriptionEdit}
onDescriptionUpdate={onDescriptionUpdate}
onEntityFieldSelect={onEntityFieldSelect}
onThreadLinkSelect={onThreadLinkSelect}
/>
</div>
<div className="tw-col-span-1 tw-border tw-border-main tw-rounded-md">
<FrequentlyJoinedTables
header="Frequently Joined Tables"
tableList={getFrequentlyJoinedWithTables()}
/>
</div>
<div className="tw-col-span-full">
<SchemaTab
columnName={getPartialNameFromTableFQN(
datasetFQN,
[FqnPart['Column']],
FQN_SEPARATOR_CHAR
)}
columns={columns}
entityFieldThreads={getEntityFieldThreadCounts(
'columns',
entityFieldThreadCount
)}
entityFqn={datasetFQN}
hasEditAccess={hasEditAccess()}
isReadOnly={deleted}
joins={tableJoinData.columnJoins as ColumnJoins[]}
owner={owner}
sampleData={sampleData}
onEntityFieldSelect={onEntityFieldSelect}
onThreadLinkSelect={onThreadLinkSelect}
onUpdate={onColumnsUpdate}
/>
</div>
</div>
)}
{activeTab === 2 && (
<div
className="tw-py-4 tw-px-7 tw-grid tw-grid-cols-3 entity-feed-list tw--mx-7 tw--my-4"
id="activityfeed">
<div />
<ActivityFeedList
isEntityFeed
withSidePanel
className=""
deletePostHandler={deletePostHandler}
entityName={entityName} entityName={entityName}
feedList={entityThread}
postFeedHandler={postFeedHandler}
/>
<div />
</div>
)}
{activeTab === 3 && (
<div id="sampleDataDetails">
<SampleDataTable
isLoading={isSampleDataLoading}
sampleData={getSampleDataWithType()}
/>
</div>
)}
{activeTab === 4 && (
<div
className="tw-py-4 tw-px-7 tw-grid tw-grid-cols-3 entity-feed-list"
id="tablequeries">
<div />
<TableQueries
isLoading={isQueriesLoading}
queries={tableQueries}
/>
<div />
</div>
)}
{activeTab === 5 && (
<div>
<TableProfiler
columns={columns.map((col) => ({
constraint: col.constraint as string,
colName: col.name,
colType: col.dataTypeDisplay as string,
dataType: col.dataType as string,
colTests: col.columnTests,
}))}
isTableDeleted={deleted}
qualityTestFormHandler={qualityTestFormHandler}
tableProfiles={tableProfile}
/>
</div>
)}
{activeTab === 6 && (
<DataQualityTab
columnOptions={columns}
handleAddColumnTestCase={handleAddColumnTestCase}
handleAddTableTestCase={handleAddTableTestCase}
handleRemoveColumnTest={handleRemoveColumnTest}
handleRemoveTableTest={handleRemoveTableTest}
handleSelectedColumn={handleSelectedColumn}
handleShowTestForm={handleShowTestForm}
handleTestModeChange={handleTestModeChange}
isTableDeleted={deleted}
selectedColumn={selectedColumn}
showTestForm={showTestForm}
tableTestCase={tableTestCase}
testMode={testMode}
/>
)}
{activeTab === 7 && (
<div
className={classNames(
'tw-px-2',
location.pathname.includes(ROUTES.TOUR)
? 'tw-h-70vh'
: 'tw-h-full'
)}
id="lineageDetails">
<Entitylineage
addLineageHandler={addLineageHandler}
deleted={deleted}
entityLineage={entityLineage}
entityLineageHandler={entityLineageHandler}
isLoading={isLineageLoading}
isNodeLoading={isNodeLoading}
isOwner={hasEditAccess()}
lineageLeafNodes={lineageLeafNodes}
loadNodeHandler={loadNodeHandler}
removeLineageHandler={removeLineageHandler}
/>
</div>
)}
{activeTab === 8 && Boolean(dataModel?.sql) && (
<div className="tw-border tw-border-main tw-rounded-md tw-py-4 tw-h-full cm-h-full">
<SchemaEditor
className="tw-h-full"
mode={{ name: CSMode.SQL }}
value={dataModel?.sql || ''}
/>
</div>
)}
{activeTab === 9 && !deleted && (
<div>
<ManageTab
allowDelete
currentTier={tier?.tagFQN}
currentUser={owner}
entityId={tableDetails.id}
entityName={tableDetails.name}
entityType={EntityType.TABLE} entityType={EntityType.TABLE}
hasEditAccess={hasEditAccess()} hasEditAccess={hasEditAccess()}
isEdit={isEdit} manageSectionType={EntityType.TABLE}
isReadOnly={deleted} onSave={onSettingsUpdate}
owner={owner}
onCancel={onCancel}
onDescriptionEdit={onDescriptionEdit}
onDescriptionUpdate={onDescriptionUpdate}
onEntityFieldSelect={onEntityFieldSelect}
onThreadLinkSelect={onThreadLinkSelect}
/> />
</div> </div>
<div className="tw-col-span-1 tw-border tw-border-main tw-rounded-md"> )}
<FrequentlyJoinedTables
header="Frequently Joined Tables"
tableList={getFrequentlyJoinedWithTables()}
/>
</div>
<div className="tw-col-span-full">
<SchemaTab
columnName={getPartialNameFromTableFQN(
datasetFQN,
[FqnPart['Column']],
FQN_SEPARATOR_CHAR
)}
columns={columns}
entityFieldThreads={getEntityFieldThreadCounts(
'columns',
entityFieldThreadCount
)}
entityFqn={datasetFQN}
hasEditAccess={hasEditAccess()}
isReadOnly={deleted}
joins={tableJoinData.columnJoins as ColumnJoins[]}
owner={owner}
sampleData={sampleData}
onEntityFieldSelect={onEntityFieldSelect}
onThreadLinkSelect={onThreadLinkSelect}
onUpdate={onColumnsUpdate}
/>
</div>
</div>
)}
{activeTab === 2 && (
<div <div
className="tw-py-4 tw-px-7 tw-grid tw-grid-cols-3 entity-feed-list tw--mx-7 tw--my-4" data-testid="observer-element"
id="activityfeed"> id="observer-element"
<div /> ref={elementRef as RefObject<HTMLDivElement>}>
<ActivityFeedList {getLoader()}
isEntityFeed
withSidePanel
className=""
deletePostHandler={deletePostHandler}
entityName={entityName}
feedList={entityThread}
postFeedHandler={postFeedHandler}
/>
<div />
</div> </div>
)}
{activeTab === 3 && (
<div id="sampleDataDetails">
<SampleDataTable
isLoading={isSampleDataLoading}
sampleData={getSampleDataWithType()}
/>
</div>
)}
{activeTab === 4 && (
<div
className="tw-py-4 tw-px-7 tw-grid tw-grid-cols-3 entity-feed-list"
id="tablequeries">
<div />
<TableQueries
isLoading={isQueriesLoading}
queries={tableQueries}
/>
<div />
</div>
)}
{activeTab === 5 && (
<div>
<TableProfiler
columns={columns.map((col) => ({
constraint: col.constraint as string,
colName: col.name,
colType: col.dataTypeDisplay as string,
dataType: col.dataType as string,
colTests: col.columnTests,
}))}
isTableDeleted={deleted}
qualityTestFormHandler={qualityTestFormHandler}
tableProfiles={tableProfile}
/>
</div>
)}
{activeTab === 6 && (
<DataQualityTab
columnOptions={columns}
handleAddColumnTestCase={handleAddColumnTestCase}
handleAddTableTestCase={handleAddTableTestCase}
handleRemoveColumnTest={handleRemoveColumnTest}
handleRemoveTableTest={handleRemoveTableTest}
handleSelectedColumn={handleSelectedColumn}
handleShowTestForm={handleShowTestForm}
handleTestModeChange={handleTestModeChange}
isTableDeleted={deleted}
selectedColumn={selectedColumn}
showTestForm={showTestForm}
tableTestCase={tableTestCase}
testMode={testMode}
/>
)}
{activeTab === 7 && (
<div
className={classNames(
location.pathname.includes(ROUTES.TOUR)
? 'tw-h-70vh'
: 'tw-h-full'
)}
id="lineageDetails">
<Entitylineage
addLineageHandler={addLineageHandler}
deleted={deleted}
entityLineage={entityLineage}
entityLineageHandler={entityLineageHandler}
isLoading={isLineageLoading}
isNodeLoading={isNodeLoading}
isOwner={hasEditAccess()}
lineageLeafNodes={lineageLeafNodes}
loadNodeHandler={loadNodeHandler}
removeLineageHandler={removeLineageHandler}
/>
</div>
)}
{activeTab === 8 && Boolean(dataModel?.sql) && (
<div className="tw-border tw-border-main tw-rounded-md tw-py-4 tw-h-full cm-h-full">
<SchemaEditor
className="tw-h-full"
mode={{ name: CSMode.SQL }}
value={dataModel?.sql || ''}
/>
</div>
)}
{activeTab === 9 && !deleted && (
<div>
<ManageTab
allowDelete
currentTier={tier?.tagFQN}
currentUser={owner}
entityId={tableDetails.id}
entityName={tableDetails.name}
entityType={EntityType.TABLE}
hasEditAccess={hasEditAccess()}
manageSectionType={EntityType.TABLE}
onSave={onSettingsUpdate}
/>
</div>
)}
<div
data-testid="observer-element"
id="observer-element"
ref={elementRef as RefObject<HTMLDivElement>}>
{getLoader()}
</div> </div>
</div> </div>
{threadLink ? ( {threadLink ? (

View File

@ -393,226 +393,230 @@ const PipelineDetails = ({
tabs={tabs} tabs={tabs}
/> />
<div className="tw-bg-white tw-flex-grow tw--mx-6 tw-px-7 tw-py-4"> <div className="tw-flex-grow tw-flex tw-flex-col tw--mx-6 tw-px-7 tw-py-4">
{activeTab === 1 && ( <div className="tw-bg-white tw-flex-grow tw-p-4 tw-shadow tw-rounded-md">
<> {activeTab === 1 && (
<div className="tw-grid tw-grid-cols-4 tw-gap-4 tw-w-full"> <>
<div className="tw-col-span-full"> <div className="tw-grid tw-grid-cols-4 tw-gap-4 tw-w-full">
<Description <div className="tw-col-span-full tw--ml-5">
description={description} <Description
entityFieldThreads={getEntityFieldThreadCounts( description={description}
'description', entityFieldThreads={getEntityFieldThreadCounts(
entityFieldThreadCount 'description',
)} entityFieldThreadCount
entityFqn={pipelineFQN} )}
entityName={entityName} entityFqn={pipelineFQN}
entityType={EntityType.PIPELINE} entityName={entityName}
hasEditAccess={hasEditAccess()} entityType={EntityType.PIPELINE}
isEdit={isEdit} hasEditAccess={hasEditAccess()}
isReadOnly={deleted} isEdit={isEdit}
owner={owner} isReadOnly={deleted}
onCancel={onCancel} owner={owner}
onDescriptionEdit={onDescriptionEdit} onCancel={onCancel}
onDescriptionUpdate={onDescriptionUpdate} onDescriptionEdit={onDescriptionEdit}
onEntityFieldSelect={onEntityFieldSelect} onDescriptionUpdate={onDescriptionUpdate}
onThreadLinkSelect={onThreadLinkSelect} onEntityFieldSelect={onEntityFieldSelect}
/> onThreadLinkSelect={onThreadLinkSelect}
/>
</div>
</div> </div>
</div> <div className="tw-table-responsive tw-my-6">
<div className="tw-table-responsive tw-my-6"> {tasks ? (
{tasks ? ( <table className="tw-w-full" data-testid="tasks-table">
<table className="tw-w-full" data-testid="tasks-table"> <thead>
<thead> <tr className="tableHead-row">
<tr className="tableHead-row"> <th className="tableHead-cell">Task Name</th>
<th className="tableHead-cell">Task Name</th> <th className="tableHead-cell">Description</th>
<th className="tableHead-cell">Description</th> <th className="tableHead-cell">Task Type</th>
<th className="tableHead-cell">Task Type</th> </tr>
</tr> </thead>
</thead> <tbody className="tableBody">
<tbody className="tableBody"> {tasks?.map((task, index) => (
{tasks?.map((task, index) => ( <tr
<tr className={classNames(
className={classNames( 'tableBody-row',
'tableBody-row', !isEven(index + 1) ? 'odd-row' : null
!isEven(index + 1) ? 'odd-row' : null )}
)} key={index}>
key={index}> <td className="tableBody-cell">
<td className="tableBody-cell"> <Link
<Link target="_blank"
target="_blank" to={{ pathname: task.taskUrl }}>
to={{ pathname: task.taskUrl }}> <span className="tw-flex">
<span className="tw-flex"> <span className="tw-mr-1">
<span className="tw-mr-1"> {task.displayName}
{task.displayName}
</span>
<SVGIcons
alt="external-link"
className="tw-align-middle"
icon="external-link"
width="12px"
/>
</span>
</Link>
</td>
<td className="tw-group tableBody-cell tw-relative">
<div
className="tw-cursor-pointer tw-flex"
data-testid="description">
<div>
{task.description ? (
<RichTextEditorPreviewer
markdown={task.description}
/>
) : (
<span className="tw-no-description">
No description{' '}
</span> </span>
)} <SVGIcons
</div> alt="external-link"
{!deleted && ( className="tw-align-middle"
<Fragment> icon="external-link"
<NonAdminAction width="12px"
html={getHtmlForNonAdminAction( />
Boolean(owner) </span>
)} </Link>
isOwner={hasEditAccess()} </td>
permission={Operation.UpdateDescription} <td className="tw-group tableBody-cell tw-relative">
position="top"> <div
<button className="tw-cursor-pointer tw-flex"
className="tw-self-start tw-w-8 tw-h-auto tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 focus:tw-outline-none" data-testid="description">
onClick={() => <div>
handleUpdateTask(task, index) {task.description ? (
}> <RichTextEditorPreviewer
<SVGIcons markdown={task.description}
alt="edit" />
icon="icon-edit" ) : (
title="Edit" <span className="tw-no-description">
width="12px" No description{' '}
/> </span>
</button> )}
</NonAdminAction> </div>
{!isNil( {!deleted && (
getFieldThreadElement( <Fragment>
<NonAdminAction
html={getHtmlForNonAdminAction(
Boolean(owner)
)}
isOwner={hasEditAccess()}
permission={Operation.UpdateDescription}
position="top">
<button
className="tw-self-start tw-w-8 tw-h-auto tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 focus:tw-outline-none"
onClick={() =>
handleUpdateTask(task, index)
}>
<SVGIcons
alt="edit"
icon="icon-edit"
title="Edit"
width="12px"
/>
</button>
</NonAdminAction>
{!isNil(
getFieldThreadElement(
task.name,
'description',
getEntityFieldThreadCounts(
'tasks',
entityFieldThreadCount
) as EntityFieldThreads[],
onThreadLinkSelect
)
) &&
onEntityFieldSelect &&
!task.description ? (
<button
className="focus:tw-outline-none tw-ml-1 tw-opacity-0 group-hover:tw-opacity-100 tw--mt-2"
data-testid="request-description"
onClick={() =>
onEntityFieldSelect?.(
`tasks/${task.name}/description`
)
}>
<PopOver
position="top"
title="Request description"
trigger="mouseenter">
<SVGIcons
alt="request-description"
className="tw-mt-2.5"
icon={Icons.REQUEST}
/>
</PopOver>
</button>
) : null}
{getFieldThreadElement(
task.name, task.name,
'description', 'description',
getEntityFieldThreadCounts( getEntityFieldThreadCounts(
'tasks', 'tasks',
entityFieldThreadCount entityFieldThreadCount
) as EntityFieldThreads[], ) as EntityFieldThreads[],
onThreadLinkSelect onThreadLinkSelect,
) EntityType.PIPELINE,
) && pipelineFQN,
onEntityFieldSelect && `tasks/${task.name}/description`,
!task.description ? ( Boolean(task.description)
<button )}
className="focus:tw-outline-none tw-ml-1 tw-opacity-0 group-hover:tw-opacity-100 tw--mt-2" </Fragment>
data-testid="request-description" )}
onClick={() => </div>
onEntityFieldSelect?.( </td>
`tasks/${task.name}/description` <td className="tableBody-cell">
) {task.taskType}
}> </td>
<PopOver </tr>
position="top" ))}
title="Request description" </tbody>
trigger="mouseenter"> </table>
<SVGIcons ) : (
alt="request-description" <div className="tw-mt-4 tw-ml-4 tw-flex tw-justify-center tw-font-medium tw-items-center tw-border tw-border-main tw-rounded-md tw-p-8">
className="tw-mt-2.5" <span>No task data is available</span>
icon={Icons.REQUEST} </div>
/> )}
</PopOver> </div>
</button> </>
) : null} )}
{getFieldThreadElement( {activeTab === 2 && (
task.name, <div
'description', className="tw-py-4 tw-px-7 tw-grid tw-grid-cols-3 entity-feed-list tw--mx-7 tw--my-4"
getEntityFieldThreadCounts( id="activityfeed">
'tasks', <div />
entityFieldThreadCount <ActivityFeedList
) as EntityFieldThreads[], isEntityFeed
onThreadLinkSelect, withSidePanel
EntityType.PIPELINE, className=""
pipelineFQN, deletePostHandler={deletePostHandler}
`tasks/${task.name}/description`, entityName={entityName}
Boolean(task.description) feedList={entityThread}
)} postFeedHandler={postFeedHandler}
</Fragment> />
)} <div />
</div>
</td>
<td className="tableBody-cell">{task.taskType}</td>
</tr>
))}
</tbody>
</table>
) : (
<div className="tw-mt-4 tw-ml-4 tw-flex tw-justify-center tw-font-medium tw-items-center tw-border tw-border-main tw-rounded-md tw-p-8">
<span>No task data is available</span>
</div>
)}
</div> </div>
</> )}
)} {activeTab === 3 && (
{activeTab === 2 && ( <PipelineStatusList
isLoading={isPipelineStatusLoading}
pipelineStatus={pipelineStatus}
/>
)}
{activeTab === 4 && (
<div className="tw-h-full tw-px-3">
<Entitylineage
addLineageHandler={addLineageHandler}
deleted={deleted}
entityLineage={entityLineage}
entityLineageHandler={entityLineageHandler}
isLoading={isLineageLoading}
isNodeLoading={isNodeLoading}
isOwner={hasEditAccess()}
lineageLeafNodes={lineageLeafNodes}
loadNodeHandler={loadNodeHandler}
removeLineageHandler={removeLineageHandler}
/>
</div>
)}
{activeTab === 5 && !deleted && (
<div>
<ManageTabComponent
allowDelete
currentTier={tier?.tagFQN}
currentUser={owner}
entityId={pipelineDetails.id}
entityName={pipelineDetails.name}
entityType={EntityType.PIPELINE}
hasEditAccess={hasEditAccess()}
manageSectionType={EntityType.PIPELINE}
onSave={onSettingsUpdate}
/>
</div>
)}
<div <div
className="tw-py-4 tw-px-7 tw-grid tw-grid-cols-3 entity-feed-list tw--mx-7 tw--my-4" data-testid="observer-element"
id="activityfeed"> id="observer-element"
<div /> ref={elementRef as RefObject<HTMLDivElement>}>
<ActivityFeedList {getLoader()}
isEntityFeed
withSidePanel
className=""
deletePostHandler={deletePostHandler}
entityName={entityName}
feedList={entityThread}
postFeedHandler={postFeedHandler}
/>
<div />
</div> </div>
)}
{activeTab === 3 && (
<PipelineStatusList
isLoading={isPipelineStatusLoading}
pipelineStatus={pipelineStatus}
/>
)}
{activeTab === 4 && (
<div className="tw-h-full">
<Entitylineage
addLineageHandler={addLineageHandler}
deleted={deleted}
entityLineage={entityLineage}
entityLineageHandler={entityLineageHandler}
isLoading={isLineageLoading}
isNodeLoading={isNodeLoading}
isOwner={hasEditAccess()}
lineageLeafNodes={lineageLeafNodes}
loadNodeHandler={loadNodeHandler}
removeLineageHandler={removeLineageHandler}
/>
</div>
)}
{activeTab === 5 && !deleted && (
<div>
<ManageTabComponent
allowDelete
currentTier={tier?.tagFQN}
currentUser={owner}
entityId={pipelineDetails.id}
entityName={pipelineDetails.name}
entityType={EntityType.PIPELINE}
hasEditAccess={hasEditAccess()}
manageSectionType={EntityType.PIPELINE}
onSave={onSettingsUpdate}
/>
</div>
)}
<div
data-testid="observer-element"
id="observer-element"
ref={elementRef as RefObject<HTMLDivElement>}>
{getLoader()}
</div> </div>
</div> </div>
</div> </div>

View File

@ -387,99 +387,100 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
setActiveTab={setActiveTabHandler} setActiveTab={setActiveTabHandler}
tabs={tabs} tabs={tabs}
/> />
<div className="tw-flex-grow tw-flex tw-flex-col tw--mx-6 tw-px-7 tw-py-4">
<div className="tw-bg-white tw-flex-grow tw--mx-6 tw-px-7 tw-py-4"> <div className="tw-bg-white tw-flex-grow tw-p-4 tw-shadow tw-rounded-md">
{activeTab === 1 && ( {activeTab === 1 && (
<> <>
<div className="tw-grid tw-grid-cols-4 tw-gap-4 tw-w-full"> <div className="tw-grid tw-grid-cols-4 tw-gap-4 tw-w-full">
<div className="tw-col-span-full"> <div className="tw-col-span-full tw--ml-5">
<Description <Description
description={description} description={description}
entityFieldThreads={getEntityFieldThreadCounts( entityFieldThreads={getEntityFieldThreadCounts(
'description', 'description',
entityFieldThreadCount entityFieldThreadCount
)} )}
entityFqn={topicFQN} entityFqn={topicFQN}
entityName={entityName} entityName={entityName}
entityType={EntityType.TOPIC} entityType={EntityType.TOPIC}
hasEditAccess={hasEditAccess()} hasEditAccess={hasEditAccess()}
isEdit={isEdit} isEdit={isEdit}
isReadOnly={deleted} isReadOnly={deleted}
owner={owner} owner={owner}
onCancel={onCancel} onCancel={onCancel}
onDescriptionEdit={onDescriptionEdit} onDescriptionEdit={onDescriptionEdit}
onDescriptionUpdate={onDescriptionUpdate} onDescriptionUpdate={onDescriptionUpdate}
onEntityFieldSelect={onEntityFieldSelect} onEntityFieldSelect={onEntityFieldSelect}
onThreadLinkSelect={onThreadLinkSelect} onThreadLinkSelect={onThreadLinkSelect}
/> />
</div>
</div>
{schemaText ? (
<Fragment>
{getInfoBadge([{ key: 'Schema', value: schemaType }])}
<div
className="tw-my-4 tw-border tw-border-main tw-rounded-md tw-py-4"
data-testid="schema">
<SchemaEditor value={schemaText} />
</div> </div>
</Fragment>
) : (
<div className="tw-flex tw-justify-center tw-font-medium tw-items-center tw-border tw-border-main tw-rounded-md tw-p-8">
No schema data available
</div> </div>
)} {schemaText ? (
</> <Fragment>
)} {getInfoBadge([{ key: 'Schema', value: schemaType }])}
{activeTab === 2 && ( <div
className="tw-my-4 tw-border tw-border-main tw-rounded-md tw-py-4"
data-testid="schema">
<SchemaEditor value={schemaText} />
</div>
</Fragment>
) : (
<div className="tw-flex tw-justify-center tw-font-medium tw-items-center tw-border tw-border-main tw-rounded-md tw-p-8">
No schema data available
</div>
)}
</>
)}
{activeTab === 2 && (
<div
className="tw-py-4 tw-px-7 tw-grid tw-grid-cols-3 entity-feed-list tw--mx-7 tw--my-4 "
id="activityfeed">
<div />
<ActivityFeedList
isEntityFeed
withSidePanel
className=""
deletePostHandler={deletePostHandler}
entityName={entityName}
feedList={entityThread}
postFeedHandler={postFeedHandler}
/>
<div />
</div>
)}
{activeTab === 3 && (
<div data-testid="sample-data">
<SampleDataTopic
isLoading={isSampleDataLoading}
sampleData={sampleData}
/>
</div>
)}
{activeTab === 4 && (
<div data-testid="config">
<SchemaEditor value={JSON.stringify(getConfigObject())} />
</div>
)}
{activeTab === 5 && !deleted && (
<div>
<ManageTabComponent
allowDelete
currentTier={tier?.tagFQN}
currentUser={owner}
entityId={topicDetails.id}
entityName={topicDetails.name}
entityType={EntityType.TOPIC}
hasEditAccess={hasEditAccess()}
manageSectionType={EntityType.TOPIC}
onSave={onSettingsUpdate}
/>
</div>
)}
<div <div
className="tw-py-4 tw-px-7 tw-grid tw-grid-cols-3 entity-feed-list tw--mx-7 tw--my-4 " data-testid="observer-element"
id="activityfeed"> id="observer-element"
<div /> ref={elementRef as RefObject<HTMLDivElement>}>
<ActivityFeedList {getLoader()}
isEntityFeed
withSidePanel
className=""
deletePostHandler={deletePostHandler}
entityName={entityName}
feedList={entityThread}
postFeedHandler={postFeedHandler}
/>
<div />
</div> </div>
)}
{activeTab === 3 && (
<div data-testid="sample-data">
<SampleDataTopic
isLoading={isSampleDataLoading}
sampleData={sampleData}
/>
</div>
)}
{activeTab === 4 && (
<div data-testid="config">
<SchemaEditor value={JSON.stringify(getConfigObject())} />
</div>
)}
{activeTab === 5 && !deleted && (
<div>
<ManageTabComponent
allowDelete
currentTier={tier?.tagFQN}
currentUser={owner}
entityId={topicDetails.id}
entityName={topicDetails.name}
entityType={EntityType.TOPIC}
hasEditAccess={hasEditAccess()}
manageSectionType={EntityType.TOPIC}
onSave={onSettingsUpdate}
/>
</div>
)}
<div
data-testid="observer-element"
id="observer-element"
ref={elementRef as RefObject<HTMLDivElement>}>
{getLoader()}
</div> </div>
</div> </div>
{threadLink ? ( {threadLink ? (

View File

@ -25,7 +25,7 @@ type Item = {
email: string; email: string;
isActiveUser?: boolean; isActiveUser?: boolean;
profilePhoto?: string; profilePhoto?: string;
teamCount?: string; teamCount?: string | JSX.Element;
}; };
type Props = { type Props = {
@ -73,7 +73,7 @@ const UserDataCard = ({ item, onClick, onDelete, showTeams = true }: Props) => {
)} )}
</div> </div>
<p className="tw-truncate">{item.email}</p> <p className="tw-truncate">{item.email}</p>
{showTeams && <p>Teams: {item.teamCount}</p>} {showTeams && <div>Teams: {item.teamCount}</div>}
</div> </div>
</div> </div>
{!isNil(onDelete) && ( {!isNil(onDelete) && (

View File

@ -18,6 +18,7 @@ import { getUserPath } from '../../constants/constants';
import { EntityReference, User } from '../../generated/entity/teams/user'; import { EntityReference, User } from '../../generated/entity/teams/user';
import { getEntityName } from '../../utils/CommonUtils'; import { getEntityName } from '../../utils/CommonUtils';
import ErrorPlaceHolder from '../common/error-with-placeholder/ErrorPlaceHolder'; import ErrorPlaceHolder from '../common/error-with-placeholder/ErrorPlaceHolder';
import PopOver from '../common/popover/PopOver';
import Searchbar from '../common/searchbar/Searchbar'; import Searchbar from '../common/searchbar/Searchbar';
import Loader from '../Loader/Loader'; import Loader from '../Loader/Loader';
import ConfirmationModal from '../Modals/ConfirmationModal/ConfirmationModal'; import ConfirmationModal from '../Modals/ConfirmationModal/ConfirmationModal';
@ -66,6 +67,35 @@ const UserDetails = ({
setDeletingUser(undefined); setDeletingUser(undefined);
}; };
const getTeamsText = (teams: EntityReference[]) => {
return teams.length > 1 ? (
<span>
{getEntityName(teams[0])}, &{' '}
<PopOver
html={
<span>
{teams.map((t, i) => {
return i >= 1 ? (
<span className="tw-block tw-text-left" key={i}>
{getEntityName(t)}
</span>
) : null;
})}
</span>
}
position="bottom"
theme="light"
trigger="mouseenter">
<span className="tw-underline tw-cursor-pointer">
{teams.length - 1} more
</span>
</PopOver>
</span>
) : (
`${getEntityName(teams[0])}`
);
};
const getUserCards = () => { const getUserCards = () => {
return isUsersLoading ? ( return isUsersLoading ? (
<Loader /> <Loader />
@ -84,10 +114,8 @@ const UserDetails = ({
isActiveUser: !user.deleted, isActiveUser: !user.deleted,
profilePhoto: user.profile?.images?.image || '', profilePhoto: user.profile?.images?.image || '',
teamCount: teamCount:
user.teams && user.teams?.length user.teams && user.teams.length
? user.teams ? getTeamsText(user.teams)
?.map((team) => team.displayName ?? team.name)
?.join(', ')
: 'No teams', : 'No teams',
}; };